0

I'm making a small text game for fun. I want to use a function which is located in a function file that I made called functionala.

The function in question, attack(), does not work and the program crashes with the error:

Traceback (most recent call last):
  File "C:\Users\seanm\Desktop\Programming\The mists of Alandria\Mists_of_alandria.py", line 22, in <module>
    functionala2.attack()
  File "C:\Users\seanm\Desktop\Programming\The mists of Alandria\functionala2.py", line 27, in attack
    variablestamina += 2
UnboundLocalError: local variable 'variablestamina' referenced before assignment

The new and improved version of the functionala file is what seems to be causing the problem:

variablestamina = 20
variablehealth = 40
variablemonsterhealth = 30
variableattacktype1 = ("Lightattack")
variableattacktype2 = ("Mediumattack")
variableattacktype3 = ("Heavyattack")

def attack():
     variableattackquery = input("You can execute three types of attacks. Lightattack does 2 damage and takes no stamina. Mediumattack does 4 damage and takes 2 stamina. Heavyattack does 7 damage and takes 5 stamina. You can only do one per turn: ")
     if variableattackquery == variableattacktype1:
        variablemonsterhealth -= 2
        variablestamina -= 2
     if variableattackquery == variableattacktype2:
        variablemonsterhealth -= 4
        variablestamina -= 4
     if variableattackquery == variableattacktype3:
        variablemonsterhealth -= 7
        variablestamina -= 7 
     variablestamina += 2
     variablestamina = min(20, variablestamina)
     print ("The "+monster+" has "+str(variablemonsterhealth)+" health left")
     print ("You have "+str(variablestamina)+" stamina left")
     monsterattack = random.randrange(4,6)
     variablehealth -= monsterattack
     print ("The "+monster+" attacks you for "+str(monsterattack))
     print ("You have "+str(variablehealth)+" health left")
     print()
zondo
  • 19,901
  • 8
  • 44
  • 83
  • Is the indentation as shown in this question the same as in your code? Your first snippet has excessive indentation for the first line and too little for one print statement. Your second snippet has excess for all lines. Indentation is important in Python! – Rory Daulton Apr 05 '17 at 18:52
  • 4
    So you have two files, and each file imports the other file? While this is not strictly forbidden by Python, it can often lead to confusing error messages or surprising behavior, which seems to be the case here. Try to redesign your code so no circular imports occur. – Kevin Apr 05 '17 at 18:52
  • @Rory Daulton no, my indentation is wrong in this and it isn't the same in the files. sorry, couldn't find a way to import the code in its original format – Dominic Morgan Apr 05 '17 at 18:54
  • Possible duplicate of [Python circular importing?](http://stackoverflow.com/questions/22187279/python-circular-importing) – Peter Wood Apr 05 '17 at 18:57
  • @Kevin alright, I have redesigned my code by removing the import in "functionala". unfortunately, it now says that my variablemonsterhealth is referenced before assignment, even though the variable is assigned before the actual function. – Dominic Morgan Apr 05 '17 at 19:02
  • Well, since the chance of the error message being at fault is close to minimum, chances are more likely that there might be a misunderstanding on your part as to the order in which your code is being executed.. Since there seems to be a lot of 'noise' in the posted code snippet, could you by any chance upload a [Minimal, Complete, and Verifiable example](https://www.wired.com/wp-content/uploads/images_blogs/design/2013/09/tumblr_inline_mjx5ioXh8l1qz4rgp.gif) so we might help you out? – Montmons Apr 05 '17 at 19:13

1 Answers1

0

This seems a cleaner way of doing it, all in a single file. you may want to look at using classes.

From console, call game() to start the game, that's it. The game will end when either monster or you have health <= 0.

Code:

from random import randrange

def game():
    stamina = 20
    health = 40
    monsterhealth = 30
    monster = 'orc'
    attacks = {'light':(-2,0),'medium':(-4,-2),'heavy':(-7,-4)}
    while True:
        a = input('you can execute 3 types of attacks, light, medium or heavy... pick one.')
        a = a.lower().strip()
        if a in attacks:
            stamina, health, monsterhealth = attack(stamina, health, monsterhealth, monster, attacks[a])
            if stamina <= 0:
                print 'you have died...'
                break
            elif monsterhealth <= 0:
                print 'the {} has died...'.format(monster)
                break
        else:
            break

def attack(stamina, health, monsterhealth, monster, att):
    monsterhealth += att[0]
    stamina += att[1]
    stamina = min(20, stamina)
    print('the {} has {} health remaining'.format(monster,monsterhealth))
    print('you have {} stamina remaining'.format(stamina))
    ma = randrange(4,6)
    health -= ma
    print('the {} attacks you for {}'.format(monster,ma))
    print('you have {} health left'.format(health))
    return stamina, health, monsterhealth

NB: Even doing this in a single file, you need to scope the variables to the "main" procedure (game), and pass them to the attack function. Otherwise, referring to these names will raise the same error, and you can reproduce this like so:

m = 1
def foo():
   m += 1  '## m doesn't exist within scope of foo, so it will raise the same error

HOWEVER, and this may be confusing, the following will not raise an error:

m = 1
def foo():
   print m

Nor will this:

m = 1
def foo():
   a = m
   print a

But both of those seem kind of hack-y and it's usually better to pass values from the main procedure to called functions/methods/etc and return appropriate values to the caller.

David Zemens
  • 53,033
  • 11
  • 81
  • 130