0

The code runs the button/label itself, but inside a for loop it seems like the variables don't update in the function until the whole thing ends. I do realize the amount of global variables I'm using is messed up but I don't know what else to do.

I've tried putting the tkinter parts in a different function, and running that inside the original function. I've also tried using

while choice==0:
    time.sleep(1)

to make sure that the tkinter parts were running only after the whole function was created. Even when I click on a choice, the program itself is still waiting for the choice variable to update.

Here is my code:


import random
import time
from tkinter import *
from tkinter import ttk





playercommands = ["info","stats","inventory","inv","help","hand","end","dictionary","dic"] #list of commands the player can run at any time
choice = 0

playerstats = {"level": 1, "hp": 50,"dmg": "1","skills": ""} #player's stats
explvl = 0 #amount of experience points player has
kills = 0 #number of zombies player has killed
weapondmg = 0
zombielvl = 0 #level of zombie player is fighting

lastlvl = 1 #level before update

starttime = 0

#zombies' stats by levels
zombielvlone = {"hp": 2, "dmg": 0.5, "exp": 10}
zombielvltwo = {"hp": 4, "dmg": 1, "exp": 20}
zombielvlthree = {"hp": 5, "dmg": 2, "exp": 30}
zombielvlfour = {"hp": 7, "dmg": 3, "exp": 40}
zombielvlfive = {"hp": 10, "dmg": 5,"exp": 50}
zombielvlsix = {} #placeholder
zombielvlseven = {}
zombielvleight = {"hp": 50, "dmg": 10, "exp": 200}
zombielvlnine = {}
zombielvlten = {"hp": 100, "dmg": 20, "exp": 500}

zombiestats = [zombielvlone, zombielvltwo, zombielvlthree, zombielvlfour, zombielvlfive, zombielvlsix, zombielvlseven, zombielvleight, zombielvlnine, zombielvlten] #list of zombie stats
killed = "" #the stats of zombie that was killed



#operation functions
def lvlcheck(): #checks player's exp, levels them accordingly
    global playerstats
    global explvl
    global lastlvl
    currenthp = playerstats.get("hp") #hp before updating to make sure it isn't reset

    
    if explvl < 50: #level 1
        playerstats = {"level": 1, "hp": currenthp,"dmg": "1","skills": ""}
        if playerstats.get("level") > lastlvl: #if player has leveled up
            levelup()
    elif explvl < 100: #level 2 ...
        playerstats = {"level": 2, "hp": currenthp,"dmg": "1","skills": ""}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 150:
        playerstats = {"level": 3, "hp": currenthp,"dmg": "1.25","skills": ""}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 200:
        playerstats = {"level": 4, "hp": currenthp,"dmg": "1.25","skills": ""}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 250:
        playerstats = {"level": 5, "hp": currenthp,"dmg": "1.5","skills": ""}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 300:
        playerstats = {"level": 6, "hp": currenthp,"dmg": "1.5","skills": "AOE"}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 350:
        playerstats = {"level": 7, "hp": currenthp,"dmg": "1.5","skills": "AOE, Regen"}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 400:
        playerstats = {"level": 8, "hp": currenthp,"dmg": "1.75","skills": "AOE, Regen"}
        if playerstats.get("level") > lastlvl:
            levelup()
    elif explvl < 450:
        updatedhp = 50-50-(currenthp)
        playerstats = {"level": 9, "hp": currenthp,"dmg": "1.76","skills": "AOE, Regen, DOT"}
        if playerstats.get("level") > lastlvl:
            levelup()
    else:
        playerstats = {"level": 10, "hp": currenthp,"dmg": "2","skills": "AOE, Regen, DOT"}
        if playerstats.get("level") > lastlvl:
            levelup()

def levelup():
    global playerstats
    global lastlvl
    hpbonus = 0 #How much hp the user needs added
    for i in range(lastlvl, playerstats.get("level")):
        if i+1 <= 6: #levels 1-6: gets 10 more hp every level
            hpbonus += 10
        elif i+1 == 9: #level 9: gets 100 more hp
            hpbonus += 100
        else: #level 7, 8, 10 and +: no hp bonus, only skill and dmg bonuses
            hpbonus += 0
    playerstats["hp"] = playerstats.get("hp")+hpbonus
    lastlvl = playerstats.get("level")
    print("\nCongratulations, you leveled up! You are now level "+str(playerstats.get("level"))+". Use the command \'stats\' to check your level's perks!\n")




def killreward():
    #rewards for killing zombies
    global explvl
    global killed
    global kills
    explvl += int(killed.get('exp'))
    lvlcheck()


def choicemaker(userchoice):
    global choice
    choice = userchoice
    

def fightscene():
    global weapondmg
    global zombiestats
    global playerstats
    global choice
    
    killcount = 0
    zombiehp = "?"
    zombienum = "?"
    regen = 0
    

    #Fight statistics
    statwindow = Tk()
    statwindow.title("Fight Statistics")
    statfrm = ttk.Frame(statwindow, padding=10)
    statfrm.grid()
    
    #Statistics, column0, stat type
    ttk.Label(statfrm, text="Kills").grid(column=0, row=0)
    ttk.Label(statfrm, text="Current Zombie HP").grid(column=0, row=1)
    ttk.Label(statfrm, text="Zombies Left").grid(column=0, row=2)
    ttk.Label(statfrm, text="Player HP").grid(column=0, row=3)
    ttk.Label(statfrm, text="Regeneration").grid(column=0, row=4)

    #Statistics, column1, stat
    ttk.Label(statfrm, text=killcount).grid(column=1, row=0)
    ttk.Label(statfrm, text=zombiehp).grid(column=1, row=1)
    ttk.Label(statfrm, text=zombienum).grid(column=1, row=2)
    ttk.Label(statfrm, text=10).grid(column=1, row=3)#change to playerstats
    if regen == 0:
        ttk.Label(statfrm, text="No regen").grid(column=1, row=4)
    else:
        ttk.Label(statfrm, text=regen).grid(column=1, row=4)

    #Fight choice windows
    fightwindow = Tk()
    fightwindow.title("Fighting the undead...")
    fightfrm = ttk.Frame(fightwindow, padding=10)
    fightfrm.grid()

    if weapondmg == 0:
        ttk.Label(fightfrm, text="You do not have a weapon.").grid(column=0, row=0)
        ttk.Label(fightfrm, text="You died.").grid(column=0, row=1)
        return
    zombie = zombiestats[zombielvl-1]
    zombiehp = zombie.get("hp")
    if zombielvl <= 5:
        zombienum = random.randint(2,10)
        if "AOE" in playerstats.get("skills"):
            zombienum = (zombienum//2)+1
    else:
        zombienum = 1

    for i in range(zombienum):
        choice = 0 #resetting choice
        
        ttk.Label(fightfrm, text="Do you swing right or left?").grid(column=1, row=0)
        leftbutton = Button(fightfrm, text="Left", command=lambda *args: choicemaker(1)).grid(column=0, row=1) #manually fighting, swing left, choice = 1
        rightbutton = Button(fightfrm, text="Right", command=lambda *args: choicemaker(2)).grid(column=2, row=1)#manually fighting, swing right, choice = 2
        autofightbutton = Button(fightfrm, text="Autofight", command=lambda *args: choicemaker(3)).grid(column=1, row=1)#automatically fighting, choice = 3


        if choice == 1 or choice == 2:
            if playerstats.get("hp") <= 0:
                fightwindow.destroy() #clearing window
                #remaking window
                fightwindow = Tk()
                fightfrm.title("Fight Statistics")
                fightfrm = ttk.Frame(fightwindow, padding=10)
                fightfrm.grid()
                
                ttk.Label(fightfrm, text="You run out of HP.").grid(column=0, row=0)
                ttk.Label(fightfrm, text="You die.").grid(column=1, row=0)
                time.sleep(3)
                quit()
            else:
                hitreg = random.randint(0,1)
                if hitreg == 0: #if user misses zombie
                    ttk.Label(fightfrm, text="You take "+str(zombie.get("dmg"))+"HP of DMG.").grid(column=0, row=1)

                    #skill usage
                    if "Regen" in playerstats.get("skills"): #regeneration skill
                        regen = random.randint(1, 10)
                        playerstats["hp"] = playerstats.get("hp") + regen
                    else:
                        regen = 0
                    if "DOT" in playerstats.get("skills"): #DOT skill
                        zombiehp = zombiehp - random.randint(1, 2)
                        
                    if int(weapondmg*float(playerstats.get("dmg"))) < int(zombiehp):
                        zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                        ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                        ttk.Label(fightfrm, text="Your weapon does not deal enough damage.").grid(column=0, row=5)
                        ttk.Label(fightfrm, text="You attack the zombie again.").grid(column=0, row=7)
                        ttk.Label(fightfrm, text="The zombie is at "+str(zombiehp)+"HP!").grid(column=0, row=8)
                    else:
                        zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                        ttk.Label(fightfrm, text="").grid(column=0, row=7)
                        ttk.Label(fightfrm, text="").grid(column=0, row=8)
                        ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                        ttk.Label(fightfrm, text="The zombie dies.").grid(column=0, row=5)
                        killed = zombie
                        kills += 1
                        killcount += 1
                        killreward()
                        zombienum -= 1
                if hitreg == 1: #if user hits zombie
                    if "Regen" in playerstats.get("skills"): #regeneration skill
                        regen = random.randint(1, 10)
                        playerstats["hp"] = playerstats.get("hp") + regen
                    else:
                        regen = 0
                    if "DOT" in playerstats.get("skills"): #DOT skill
                        zombiehp = zombiehp - random.randint(1, 2)
                        
                    if int(weapondmg*float(playerstats.get("dmg"))) < int(zombiehp):
                        zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                        ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                        ttk.Label(fightfrm, text="Your weapon does not deal enough damage.").grid(column=0, row=5)
                        ttk.Label(fightfrm, text="You attack the zombie again.").grid(column=0, row=7)
                        ttk.Label(fightfrm, text="The zombie is at "+str(zombiehp)+"HP!").grid(column=0, row=8)
                    else:
                        zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                        ttk.Label(fightfrm, text="").grid(column=0, row=7)
                        ttk.Label(fightfrm, text="").grid(column=0, row=8)
                        ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                        ttk.Label(fightfrm, text="The zombie dies.").grid(column=0, row=5)
                        killed = zombie
                        kills += 1
                        killcount += 1
                        killreward()
                        zombienum -= 1

                #Statistics, column1, stat reset
                ttk.Label(statfrm, text="").grid(column=1, row=0)
                ttk.Label(statfrm, text="").grid(column=1, row=1)
                ttk.Label(statfrm, text="").grid(column=1, row=2)
                ttk.Label(statfrm, text="").grid(column=1, row=3)
                ttk.Label(statfrm, text="").grid(column=1, row=4)


                #Statistics, column1, stat
                ttk.Label(statfrm, text=killcount).grid(column=1, row=0)
                ttk.Label(statfrm, text=zombiehp).grid(column=1, row=1)
                ttk.Label(statfrm, text=zombiecount).grid(column=1, row=2)
                ttk.Label(statfrm, text=playerstats.get("hp")).grid(column=1, row=3)
                if regen == 0:
                    ttk.Label(statfrm, text="No regen").grid(column=1, row=4)
                else:
                    ttk.Label(statfrm, text=regen).grid(column=1, row=4)

                    
        elif choice == 3: #autofight
            for n in range(zombienum-i):
                if playerstats.get("hp") <= 0:
                    fightwindow.destroy() #clearing window
                    #remaking window
                    fightwindow = Tk()
                    fightfrm.title("Fight Statistics")
                    fightfrm = ttk.Frame(fightwindow, padding=10)
                    fightfrm.grid()
                    
                    ttk.Label(fightfrm, text="You run out of HP.").grid(column=0, row=0)
                    ttk.Label(fightfrm, text="You die.").grid(column=1, row=0)
                    time.sleep(3)
                    quit()
                else:
                    hitreg = random.randint(0,1)
                    if hitreg == 0: #if user misses zombie
                        ttk.Label(fightfrm, text="You take "+str(zombie.get("dmg"))+"HP of DMG.").grid(column=0, row=1)

                        #skill usage
                        if "Regen" in playerstats.get("skills"): #regeneration skill
                            regen = random.randint(1, 10)
                            playerstats["hp"] = playerstats.get("hp") + regen
                        else:
                            regen = 0
                        if "DOT" in playerstats.get("skills"): #DOT skill
                            zombiehp = zombiehp - random.randint(1, 2)
                            
                        if int(weapondmg*float(playerstats.get("dmg"))) < int(zombiehp):
                            zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                            ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                            ttk.Label(fightfrm, text="Your weapon does not deal enough damage.").grid(column=0, row=5)
                            ttk.Label(fightfrm, text="You attack the zombie again.").grid(column=0, row=7)
                            ttk.Label(fightfrm, text="The zombie is at "+str(zombiehp)+"HP!").grid(column=0, row=8)
                        else:
                            zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                            ttk.Label(fightfrm, text="").grid(column=0, row=7)
                            ttk.Label(fightfrm, text="").grid(column=0, row=8)
                            ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                            ttk.Label(fightfrm, text="The zombie dies.").grid(column=0, row=5)
                            killed = zombie
                            kills += 1
                            killcount += 1
                            killreward()
                            zombienum -= 1
                    if hitreg == 1: #if user hits zombie
                        if "Regen" in playerstats.get("skills"): #regeneration skill
                            regen = random.randint(1, 10)
                            playerstats["hp"] = playerstats.get("hp") + regen
                        else:
                            regen = 0
                        if "DOT" in playerstats.get("skills"): #DOT skill
                            zombiehp = zombiehp - random.randint(1, 2)
                            
                        if int(weapondmg*float(playerstats.get("dmg"))) < int(zombiehp):
                            zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                            ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                            ttk.Label(fightfrm, text="Your weapon does not deal enough damage.").grid(column=0, row=5)
                            ttk.Label(fightfrm, text="You attack the zombie again.").grid(column=0, row=7)
                            ttk.Label(fightfrm, text="The zombie is at "+str(zombiehp)+"HP!").grid(column=0, row=8)
                        else:
                            zombiehp = str(int(float(zombiehp)-float(playerstats.get("dmg"))))
                            ttk.Label(fightfrm, text="").grid(column=0, row=7)
                            ttk.Label(fightfrm, text="").grid(column=0, row=8)
                            ttk.Label(fightfrm, text="You deal "+str(weapondmg*float(playerstats.get("dmg")))+"HP of DMG!").grid(column=0, row=4)
                            ttk.Label(fightfrm, text="The zombie dies.").grid(column=0, row=5)
                            killed = zombie
                            kills += 1
                            killcount += 1
                            killreward()
                            zombienum -= 1
                #Statistics, column1, stat reset
                ttk.Label(statfrm, text="").grid(column=1, row=0)
                ttk.Label(statfrm, text="").grid(column=1, row=1)
                ttk.Label(statfrm, text="").grid(column=1, row=2)
                ttk.Label(statfrm, text="").grid(column=1, row=3)
                ttk.Label(statfrm, text="").grid(column=1, row=4)


                #Statistics, column1, stat
                ttk.Label(statfrm, text=killcount).grid(column=1, row=0)
                ttk.Label(statfrm, text=zombiehp).grid(column=1, row=1)
                ttk.Label(statfrm, text=zombiecount).grid(column=1, row=2)
                ttk.Label(statfrm, text=playerstats.get("hp")).grid(column=1, row=3)
                if regen == 0:
                    ttk.Label(statfrm, text="No regen").grid(column=1, row=4)
                else:
                    ttk.Label(statfrm, text=regen).grid(column=1, row=4)
                    
    if zombienum == 0:
        fightwindow = Tk()
        fightwindow.title("Fighting the undead...")
        fightfrm = ttk.Frame(fightwindow, padding=10)
        fightfrm.grid()
        ttk.Label(fightfrm, text="You killed all the zombies!").grid(column=0, row=0)
        proceedbutton = Button(fightfrm, text="Proceed", command=lambda:[fightwindow.destroy()]).grid(column=0, row=1)
        return
  • "it seems like the variables don't update" -- I don't understand what you mean. Which for loop? Which variables? Why do you think you don't update? I will say this -- remember that, when you tweak a GUI element, like `ttk.Label` nothing happens immediately. All that does is send some messages. Nothing actually gets drawn until your handler returns back to the main loop, where the messages are dispatched. – Tim Roberts May 17 '23 at 05:07
  • @TimRoberts When I check what is stored in `choice` after clicking the button, it shows that the variables have been changed but the `if choice==1 or choice==2` and `elif choice==3` parts don't run. The main problem is in `fightscene()`. The loop that isn't working is ``` for i in range(zombienum): choice = 0 #resetting choice ttk.Label(fightfrm, text="Do you swing right or left?").grid(column=1, row=0) leftbutton = Button(fightfrm, text="Left", command=lambda *args: choicemaker(1)).grid(column=0, row=1)``` – cyl4061 May 17 '23 at 05:18
  • 2
    RIght. You set `choice = 0`, then you create your buttons, which of course does not change `choice`, so when you get to the `if`, it's always going to be 0. You don't even get the chance to click buttons until after this function returns. If you need to take action on button clicks, then you have to DO the action during the `choicemaker` callback. You have to think "event driven", not linear. – Tim Roberts May 17 '23 at 06:35
  • 3
    Do not use `time.sleep` in a Tkinter program. Tk is an event oriented system. While you sleep you are not processing events. In particular a loop with sleep just blocks all events. Instead, ensure you create *one* `Tk()` window and run the mainloop to process events. For additional toplevel windows, use `Toplevel`. For a delayed event use the `after` method to post an event into the event queue that is processed after some interval eg: `mytoplevel.after(1000, do_some_function)`. – patthoyts May 17 '23 at 10:08

0 Answers0