0

I am currently developing a short text-based adventure so I can learn how to use Classes within Python. As part of this, I am trying to create a combat system where the player could choose an NPC to attack.

The aim is that the player can enter the name of the NPC and the weapon they want to use. A method in the target's class will then be called, to lose health based on the damage of the weapon.

My current code is below:

class npc:
    def __init__(self, name, alliance):
        self.name = name
        self.alliance = alliance
    def loseHealth(self, health, dmg):
        self.dmg = dmg
        self.health = self.health - dmg
    def usePotion(self, health, pType):
        if pType == "great":
            self.health = min(self.health + 50,self.maxHealth)
        elif pType == "normal":
            self.health = min(self.health + 25,self.maxHealth)
        else:
            pass
    def attack(self, target, weaponDmg):
        if target in npcList:
            target.loseHealth(self.health, weaponDmg)

class human(npc):
    maxHealth = 100
    health = 100
    def __init__(self, name, alliance):
        super().__init__(name, alliance)

class orc(npc):
    maxHealth = 200
    health = 200
    def __init(self, name, alliance):
        super().__init__(name, alliance)

weaponDmg = {'sword':10,'axe':20}
alice = human("alice","good")
bob = orc("bob","evil")
npcList = [alice, bob]
target = input("Enter Target:")
weapon = input("Enter weapon:")
for x in range(3):
    alice.attack(target,weaponDmg[weapon]) #using alice temporarily until I have a person class sorted
    print(target.health)
DavidG
  • 24,279
  • 14
  • 89
  • 82
nyep
  • 35
  • 7
  • 1
    How about using an npcDict, rather then a list. Would make it easier for you to access according to a name. – Rohi Mar 26 '18 at 14:26

2 Answers2

0

You can call a method on an instance by using getattr, here is an example:

>>> class Test:
...     def my_method(self, arg1, arg2):
...         print(arg1, arg2)
... 
>>> t = Test()
>>> getattr(t, 'my_method')('foo', 'bar')
foo bar
Andreas
  • 61
  • 3
0

The simple and pythonic answer is to use a dict of NPCs keyed by name, the same way you’re already doing it with weapons:

npcs = {‘alice’: alice, ‘bob’: bob}
target = input("Enter Target:")
weapon = input("Enter weapon:")
for x in range(3):
    alice.attack(npcs[target], weaponDmg[weapon])
    print(target.health)

And if you want to look up the attacking NPC by user-supplied name as well as the attackee, you can do the same thing there:

npcs[attacker].attack(npcs[target], weaponDmg[weapon])

If you really want to do this inside the attack method you can keep passing in target as a name (string) and do this:

   if target in npcs:
        npcs[target].loseHealth(self.health, weaponDmg)

... but that probably isn’t a very good design. It means you’re sharing a global variable, and your NPC objects all “know” about that global dict and all the NPCs in it, which doesn’t seem like part of their responsibility.


You can make this a little less repetitive by creating the dict with a comprehension:

npcs = {npc.name: npc for npc in (alice, bob)}

... or by just creating them directly in the dict instead of in variables that you’re probably never going to otherwise use:

npcs = {}
npcs[‘alice’] = human("alice","good")
npcs[‘bob’] = orc("bob","evil")
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Fantastic - you've helped a lot. Thank you. I have used a dictionary to store the npcs and have stripped out the sharing of global variabels in the attack method. – nyep Mar 27 '18 at 07:05