AttributeError: 'Charmander' object has no attribute 'attack'

class Pokemon:

    

  def __init__(self, name, types, level = 5):

    self.name = name

    self.level = level

    self.health = level * 5

    self.max_health = level * 5

    self.types = types

    self.is_knocked_out = False

  def __repr__(self):

    return f"Pokemon info: {self.name}, Type: {self.types}, Current Health: {self.health}, Max Health: {self.max_health}"

  def revive(self):

    self.is_knocked_out = False

    if self.health == 0:

       self.health = 1

    print(f"{self.name} was revived!")

  def knock_out(self):

    self.is_knocked_out = True

    if self.health != 0:

      self.health = 0

    print(f"{self.name} has been knocked out")

    def lose_health(self, life):

      self.health -= life

      if self.health <= 0:

        self.health = 0

        self.knock_out()

      else:

        print(f"{self.name} now has {self.health} health.")

    def gain_health(self, heal):

      if self.health == 0:

        self.revive()

        self.health +=heal

      print(f"{self.name} now has {self.health} health")

    def attack (self, other_pokemon):

      if self.is_knocked_out == True:

        print(f"You can't attack. {self.name} has been knocked out.")

      return

      if (self.types == "Grass" and other_pokemon.types == "Fire") or (self.types == "Fire" and other_pokemon.types == "Water") or (self.types == "Water" and other_pokemon.types == "Grass"):

        damage = self.level * 0.5

        print("It's not an effective attack!")

        other_pokemon.loose_health(round(damage))

      if (self.types == other_pokemon.types):

        print("Both used same power")

        other_pokemon.loose_health(self.level)

      if (self.types == "Fire" and other_pokemon.types == "Grass") or (self.types == "Grass" and other_pokemon.types == "Water") or (self.types == "Water" and other_pokemon.types == "Fire"):

        damage = self.level * 2

        print("It's an effective attack!")

        other_pokemon.loose_health((damage))

class Charmander(Pokemon):

    def __init__(self, level = 5):

        super().__init__("Charmander", "Fire", level)

class Squirtle(Pokemon):

    def __init__(self, level = 5):

        super().__init__("Squirtle", "Water", level)

class Bulbasaur(Pokemon):

    def __init__(self, level = 5):

        super().__init__("Bulbasaur", "Grass", level)

class Trainer:

    

  def __init__(self, pokemon_list, num_potions, name):

        self.pokemons = pokemon_list

        self.potions = num_potions

        self.current_pokemon = 0

        self.name = name

  def __repr__(self):

      

        print(f"The trainer {name} has the following pokemon".format(name = self.name))

        for pokemon in self.pokemons:

            print(pokemon)

        return "The current active pokemon is {name}".format(name = self.pokemons[self.current_pokemon].name)

        

  def switch_active_pokemon(self, new_active):

     

        if new_active < len(self.pokemons) and new_active >= 0:

            # You can't switch to a pokemon that is knocked out

            if self.pokemons[new_active].is_knocked_out:

                print("{name} is knocked out. You can't make it your active pokemon".format(name = self.pokemons[new_active].name))

            # You can't switch to your current pokemon

            elif new_active == self.current_pokemon:

                print("{name} is already your active pokemon".format(name = self.pokemons[new_active].name))

            # Switches the pokemon

            else:

                self.current_pokemon = new_active

                print("Go {name}, it's your turn!".format(name = self.pokemons[self.current_pokemon].name))

  def use_potion(self):

       if self.potions > 0:

            print("You used a potion on {name}.".format(name = self.pokemons[self.current_pokemon].name))

           

            self.pokemons[self.current_pokemon].gain_health(20)

            self.potions -= 1

       else:

            print("You don't have any more potions")

  def attack_other_trainer(self, other_trainer):

        # Your current pokemon attacks the other trainer's current pokemon

        my_pokemon = self.pokemons[self.current_pokemon]

        their_pokemon = other_trainer.pokemons[other_trainer.current_pokemon]

        my_pokemon.attack(their_pokemon)

a = Charmander(7)

b = Squirtle()

c = Squirtle(1)

d = Bulbasaur(10)

trainer_one = Trainer([a,b,c], 3, "Alex")

trainer_two = Trainer([d], 5, "Billa")

print(trainer_one)

print(trainer_two)

trainer_one.attack_other_trainer(trainer_two)

trainer_two.attack_other_trainer(trainer_one)

trainer_two.use_potion()

trainer_one.attack_other_trainer(trainer_two)

trainer_two.switch_active_pokemon(0)

trainer_two.switch_active_pokemon(1)

I first had to fix this line:

print(f"The trainer {name} has the following pokemon".format(name = self.name))

which uses both f-string and format. Pretty weird, use one or the other (preferable f-string), but certainly not both.

looking at the available methods:

        print(dir(my_pokemon))
        my_pokemon.attack(their_pokemon)

I don’t see attack. And numerous other methods/attributes seem to be missing at well. Given I can see the methods on the code, what comes to mind are scope and nesting. And sure enough, you nested attack and other methods within your knock_out method

please follow pep-8 style guidelines and use 4 spaces indent. Makes it so much easier to spot this kind of mistake.

1 Like

Ok… I will try to solve the mistakes.

see:

  def knock_out(self):

    self.is_knocked_out = True

    if self.health != 0:

      self.health = 0

    print(f"{self.name} has been knocked out")

    def lose_health(self, life):

do you see the nesting?

yes the if statement

That too, but that is fine. But you nested your lose_health method inside your knock_out method, hold on, let me show you:

__def knock_out(self):

    self.is_knocked_out = True

    if self.health != 0:

      self.health = 0

    print(f"{self.name} has been knocked out")

____def lose_health(self, life):

I replaced the spaces with underscores, do you see it now? And its not only lose_health method, all the methods after lose_health as well. Due to this nesting, the class doesn’t have the methods/attribute it should have.

for your own sake, please read about pep-8 and follow the style guide recommendation to make life easier for yourself :slight_smile:

1 Like

oh I got it…thank you
I will check the pep-8 aswell

1 Like