Problem with text adventure, global and local variables

Viewed 54
from random import randint
from time import sleep

pminatk = 0
pmaxatk = 4
playerhp = 15

def atk(minatk, maxatk):
    return randint(minatk, maxatk)

def playerAtk(monsterhp):
    dmg = atk(pminatk, pmaxatk)
    monsterhp -= dmg
    print ("Du gjorde %i skade. Monsteret har nå %i liv igjen" % (dmg, monsterhp))
    sleep(1)
    return monsterhp

def monsterAtk(mminatk, mmaxatk):
    global playerhp
    dmg = atk(mminatk, mmaxatk)
    playerhp -= dmg
    print ("Monsteret gjorde %i skade. Du har nå %i liv igjen" % (dmg, playerhp))
    sleep(1)

def fight(monsterhp, mminatk, mmaxatk):
    global playerhp
    while monsterhp > 0 and playerhp > 0:
        playerAtk(monsterhp)
        if monsterhp > 0:
            monsterAtk(mminatk, mmaxatk)
    if playerhp > 0:
        print ("Gratulerer! Du beseiret monsteret!")
    else:
        print ("Du døde!")

fight(5, 1, 2)
fight(6, 0, 2)

This is supposed to be a simple battle system in a text based adventure. Now my problem is that monsterhp always goes back to its original valye after playerAtk is executed. If I choose to have monsterhp as a global variable it will remain 0 after fight() is finished, leaving the hp of all OTHER monster equal to zero as well. Now i could have more than one variable to assign different hp-values to different monster, but is there any way I can do this using parameters to the fight() function?

1 Answers

Your immediate problem is in your while loop when you call playerAtk(), you return monsterhp from it, but do not actually use it in that loop and that is why you see monster's health points to go back up to the original value. Line 28 needs to read:

monsterhp = playerAtk(monsterhp)

instead of:

playerAtk(monsterhp)

As it was suggested in a comment though, It's worth looking into defining your custom classes. I've thrown together following example based on your code to whet your appetite:

from random import randint
from time import sleep

PLAYERNAME = "Player1"
PLAYERHP = 15
PMINATK = 0
PMAXATK = 4


class CharacterDied(Exception):
    def __init__(self, msg):
        self.msg = msg


class Character:
    def __init__(self, name, initial_hp, minatk, maxatk):
        self.name = name
        self.hp = initial_hp
        self.minatk = minatk
        self.maxatk = maxatk

    def take_damage(self, damage_hp):
        self.hp -= damage_hp
        msg = "{} takes {:d}HP damage and has {:d} left."
        print(msg.format(self.name, damage_hp, self.hp))
        if self.hp < 0:
            msg = "{} died."
            raise CharacterDied(msg.format(self.name))

    def attack(self, other):
        dmg = randint(self.minatk, self.maxatk)
        sleep(1)
        other.take_damage(dmg)


def fight(char1, char2):
    try:
        while True:
            char1.attack(char2)
            char2.attack(char1)
    except CharacterDied as death_exception:
        print(death_exception.msg)


if __name__ == "__main__":
    player = Character(PLAYERNAME, PLAYERHP, PMINATK, PMAXATK)
    fight(player, Character("Monster1", 5, 1, 2))
    if player.hp > 0:
        fight(player, Character("Monster2", 6, 0, 2))

There are many ways to do this. For simplicity, I've written just one generic Character class we can use for player and monsters, but even if we started customizing them with subclasses, for instance the fight is now a bit more generic and we can also have a monster attack the player as it just became function of two fighting characters.

To your original question though the benefit sought after here is that attributes are kept and persistent with their instance objects which is generally much easier to follow than to try to deal with and track global variables.

Related