Pokemon project

Hi,

for the pokemon project, I wanted to randomly select from a list the attacking pokemon vs. the defending pokemon, and then calculate the caused damage and current health after the damge occured.

However, the following code gives me an “UnboundLocalError: local variable ‘damage’ referenced before assignment”, but I can’t find the bug here.

Can anyone give advise?

Much appreciated! Thanks!

import random

class Pokemon:
  def __init__(self, name, level, pok_type, max_health, current_health, knocked):
    self.name = name
    self.level = level
    self.pok_type = pok_type
    self.max_health = max_health
    self.current_health = current_health
    self.knocked = knocked

    
  def attack(self, defending):
    if self.level > defending.level:
      damage = (2*self.level)
    elif self.level < defending.level:
      damage = (0.5*self.level)
    print(f"{self.name} attacked {defending.name} and caused a damage of {damage}.")
    return damage
    
  def lose_health(self, caused_damage):
    self.current_health = self.current_health - caused_damage
    print(f'After attack {self.name} has a current health score of {self.current_health}')
    return self.current_health
  
#individual pokemons: fire, water and grass

fire_pok = Pokemon("Pokemon fire", 2, 'fire', 100, 80, False)

water_pok = Pokemon("Pokemon water", 3, 'water', 100, 100, False)

grass_pok = Pokemon("Pokemon grass", 1, 'grass', 100, 60, False)


while True:
  attacking_pok = random.choice([fire_pok, water_pok, grass_pok])
  defending_pok = random.choice([fire_pok, water_pok, grass_pok])
                           
  caused_damage = attacking_pok.attack(defending_pok)
  health_status = defending_pok.lose_health(caused_damage)
  
  if defending_pok.current_health <=0:
    break

I did a little testing, and it seems pokemon can target themselves to attack, and if one does that, then your attack function never assigns anything to your damage variable, because you’re checking for a higher or lower level, but not same level.

2 Likes

Thank you for your help, this was spot-on!!

1 Like

Hi,

I advanced a bit in the pokemon project and encountered another bug that is hard for me to fix. In the code below, the while loop should exit when two pokemons got knocked out. But somehow the loop will is infinite, it seems that code never gets to the point where the second pokemon got knocked out. I think it has be be related to the if conditions where I specify that already knocked out Pokemons can not attack or sustain damage anymore.

Sorry, the code is perhaps a little too long to post here, but I will give it a try. If anyone has an idear I would be very grateful.
Thanks!

import random

class Pokemon:
  def __init__(self, name, level, pok_type, max_health, current_health, knocked):
    self.name = name
    self.level = level
    self.pok_type = pok_type
    self.max_health = max_health
    self.current_health = current_health
    self.knocked = knocked
  """   
  def __repr__(self):
    print(f'Pokemon name: {self.name}\nLevel: {self.level}\nType: {self.pok_type}\nMax health: {self.max_health}\nCurrent health: {self.current_health}\nKnocked out: {self.knocked}')
    
  """
  count = 0 
  def attack(self, defending):
    if Pokemon.count == 20 and self.level != defending.level:
      self.level += 1
      print(f'{self.name} ascended one level up!!!')
      print('\n')
    if self.level > defending.level:
      damage = (2*self.level)
      Pokemon.count += 1
    elif self.level < defending.level:
      damage = (0.5*self.level)
      Pokemon.count += 1
    elif self.level == defending.level:
      damage = (0*self.level)
      Pokemon.count += 0
    print(f"{self.name} attacked {defending.name} and caused a damage of {damage}. {self.name} now has {Pokemon.count} attacks.")
    return damage
   
  def lose_health(self, caused_damage):
    self.current_health = (self.current_health - caused_damage)
    print(f'After attack {self.name} has a current health score of {self.current_health}')
    return self.current_health
  
  def regain_health(self, healed_pok):
    healed_pok.current_health = (healed_pok.current_health + (self.current_health*0.05))
    if healed_pok.current_health > healed_pok.max_health:
      healed_pok.current_health = healed_pok.max_health
    print(f'{self.name} healt {healed_pok.name}. {healed_pok.name} has now a current health of {healed_pok.current_health}.')
  
  def knock_out(self, current_health):
    if self.current_health <= 0:
      self.knocked = True
      print(f'{self.name} got knocked out!!!')
    return self.knocked
    

class Trainer(Pokemon):
  def __init__(self, name, potion, pokemon, act_pok):
    self.name = name
    self.potion = potion
    self.pokemon = pokemon
    self.act_pok = act_pok
    
  def trainer_attacking(self, defending):
    if self.potion == 'healing':
      if self.pokemon[self.act_pok].current_health >= 0 and defending.pokemon[defending.act_pok].current_health >= 0:
        self.pokemon[self.act_pok].current_health += 10
      if self.pokemon[self.act_pok].current_health > self.pokemon[self.act_pok].max_health:
        self.pokemon[self.act_pok].current_health = self.pokemon[self.act_pok].max_health
      print(f'{self.pokemon[self.act_pok].name} got healed by trainer {self.name}. {self.pokemon[self.act_pok].name} current health is now {self.pokemon[self.act_pok].current_health}.')
    return self.pokemon[self.act_pok].current_health
  
    if self.potion == 'reviving':
      if self.pokemon[self.act_pok].current_health >= 0 and defending.pokemon[defending.act_pok].current_health >= 0:
        self.pokemon[self.act_pok].current_health = (self.pokemon[self.act_pok].max_health * 0.20)
      print(f'{self.pokemon[self.act_pok].name} got revived by trainer {self.name}. {self.pokemon[self.act_pok].name} current health is now {self.pokemon[self.act_pok].current_health}.')
    return self.pokemon[self.act_pok].current_health
      
    if self.potion == 'damaging':
      if defending.pokemon[defending.act_pok].current_health >= 0 and self.pokemon[self.act_pok].current_health >= 0:
        defending.pokemon[defending.act_pok].current_health = defending.pokemon[self.act_pok].current_health - 10
        print(f'{defending.pokemon[defending.act_pok].name} got damaged by trainer {self.name}. {defending.pokemon[defending.act_pok].name} current health is now {defending.pokemon[defending.act_pok].current_health}.')
    return defending.pokemon[defending.act_pok].current_health

  
# individual pokemons: fire, water and grass

fire_pok = Pokemon("Pokemon fire", 2, 'fire', 100, 50, False)

water_pok = Pokemon("Pokemon water", 3, 'water', 100, 45, False)

grass_pok = Pokemon("Pokemon grass", 1, 'grass', 100, 40, False)


trainer_yoda = Trainer("Yoda", "healing", [fire_pok, water_pok, grass_pok], 1)

trainer_luke = Trainer("Luke", "reviving", [fire_pok, water_pok, grass_pok], 2)

trainer_obivan = Trainer("Obivan", "damaging", [fire_pok, water_pok, grass_pok], 0)




num = 0
while num <=2:
  attacking_pok = random.sample([fire_pok, water_pok, grass_pok],1)
  pok_att = attacking_pok[0]

  defending_pok = random.sample([fire_pok, water_pok, grass_pok],1)
  pok_def = defending_pok[0]
  
 
  if pok_att.name != pok_def.name and pok_att.knocked !=True and pok_def.knocked != True:
    caused_damage = pok_att.attack(pok_def)
    health_status = pok_def.lose_health(caused_damage)
    if pok_def.knock_out(health_status) == True:
      num += 1
    print('\n')
    
  if pok_att.name == pok_def.name and pok_att.knocked !=True and pok_def.knocked != True:
    pok_att.regain_health(pok_def)
    print('\n')
 
  num_list = list(range(1, 11))
  random_list = random.sample((num_list),1)
  
  for i in random_list:
    if i == 2 or i == 8:
      attacking_trainer = random.sample([trainer_yoda, trainer_luke, trainer_obivan],1)
      train_att = attacking_trainer[0]
      defending_trainer = random.sample([trainer_yoda, trainer_luke, trainer_obivan],1)
      trainer_def = defending_trainer[0]
      
      train_att.trainer_attacking(trainer_def) 
      
    else:
      pass