1

I am trying to build a turn based battle game but I am encountering a problem with damage infliction.

roomMonsters is a list like: [['A Zombie' , 2 , 2 , 3],['A Zombie , 2 , 2, 3]]

def heroAttack(roomMonsters , heroes):
    target = int(input('Which monster shall you attack? ')) #Which monster to attack
    attacker = int(input('Which hero shall you attack with? ')) #Which hero to attack with
    damage = int(random.randint(int(heroes[attacker][2]) , heroes[attacker][2])*2)    #Calculates damage
    for number in range(0,damage):
        while roomMonsters[target][1] > 0:
            roomMonsters[target][1] = roomMonsters[target][1]-1
            #print('Debug, inflicting pain')

    print('Your' , heroes[attacker][0] , 'attacked' , roomMonsters[target][0] , 'for' , damage , 'damage.') #Prints the result
    checkForMonsterDeath(heroes,roomMonsters,attacker,target)
    return roomMonsters

I expect the result to inflict damage to one list entry and then stop, so it inflicts damage to the zombie which is attacked.

However, it inflicts the damage to all zombies.I think it may be because the checkForMonsterDeath removes a monster from the list but I cannot see how that leads to the damage being inflicted to all the monsters of the same type.

Gameplay looks like this accordingly:

You enter the room and monsters lie ahead of you...  
You can see:  
0 A Zombie with 2 HP.
1 A Spider with 5 HP.
2 A Zombie with 2 HP.
Which monster shall you attack? 0
Which hero shall you attack with? 1
Your Wielder of Zzzzap attacked A Zombie for 14 damage.
A Zombie exploded in a fiery ball of gloop.
You enter the room and monsters lie ahead of you...  
You can see:  
0 A Spider with 5 HP.
1 A Zombie with 0 HP.

As you can see the damage is inflicted to all the zombies, not just the one who was attacked.

Apologies for any bad formatting, this is my first time here and thanks for your help.

j08691
  • 204,283
  • 31
  • 260
  • 272
  • You probably need to change `while roomMonsters[target][1] > 0` to `if roomMonsters[target][1] > 0` – jadsq Dec 07 '17 at 08:28
  • Instead of using the for and while loop, you can do `roomMonsters[target][1]=max(0,roomMonsters[target][1]-damage)` – T C Molenaar Dec 07 '17 at 08:34

1 Answers1

-1

The issue looks like it is one of the usual caveat that exists with list duplication. (Similar issue : List of lists changes reflected across sublists unexpectedly)

The problem is the following : the mutiple lists you have for each zombies are actually one and the same, which means that if you try to modify one element in one of the copies then the changes happens in all the copies (because they are the same object). So to have your several zombies with each a list of their own you will have to make independant copies of the original list (.copy() will suffice here). See that example :

zombieList = ['A Zombie' , 2 , 2 , 3]
badCopyRoomMonsters = [zombieList,zombieList]
#trying to deal damage to only the first zombie
badCopyRoomMonsters[0][1] = 0
print(badCopyRoomMonsters)
print(zombieList) #even the original list got modified because they are all references to the same object

zombieList = ['A Zombie' , 2 , 2 , 3]
goodCopyRoomMonsters =[zombieList.copy(),zombieList.copy()]
#trying to deal damage to only the first zombie
goodCopyRoomMonsters[0][1] = 0
print(goodCopyRoomMonsters)
print(zombieList) #now it's all behaving as expected
jadsq
  • 3,033
  • 3
  • 20
  • 32
  • So the issue is with my ```roomMonsters``` definition, I have tried to use the method you suggested but to no avail. Here is my code: ```roomMonsters.insert(0,currentMonster) #Adds the randomly selected monster to the list of monsters for this room``` ```currentMonster``` is a list like the zombie and I have tried doing ```insert(0, currentMonster.copy)``` Thanks, – Angry Apple Dec 08 '17 at 08:28
  • @AngryApple Did you mean `insert(0,currentMonster.copy())` ? – jadsq Dec 08 '17 at 08:36
  • Ah yes!Wow, many thanks, its amazing how something so simple can be so much of a pain to spot. :) – Angry Apple Dec 08 '17 at 10:18