Requesting Assistance with Python OOP and a premade code that uses many Global Variables (2024)

This is going to be a lengthy post as I want to make sure that all information pertaining to the issue I am currently having is available. As well as what I am trying to achieve. Also what is going wrong, and the paths I have already taken to try to solve the issue on my own before coming here. So that maybe someone will see that I am at my wits end and be willing to assist me.

I am currently creating a new VN, I have created a KN before and understand the basic and slightly advanced form of coding. So I decided I would truly test myself with this new game and try to make it the best I possibly could. I watched over 60 hours of tutorials, literally 62 videos, from various series on youtube. If you have a tutorial on youtube I probably watched it. I was very interested in OOP as it seems to me at least to be the most advanced thing you can do with RenPy and combining RenPys screen language with OOP you can essentially do anything.

So I sat down and decided what I wanted to create. I decided on a game that would be essentially a sandbox. I wanted image buttons to move around the home, and the city as a whole. None of that teleporting around stuff. I wanted an Inventory System with drag and drop items, that works with NPC Venders. I want a scaling battle system. With missions that have scaling rewards and scaling enemies based on the difficulty the player chooses. Rank E missions being the lowest and Rank S the highest. I also wanted the player to have a dynamic party. So if you befriended someone in the game they could join your party. Also those joinable members to have unique skills to add a fun spice to it all.

I was able to get everything working how I wanted it to except for the 2 things that I simply had no clue how to make. The Battle System and Inventory. So I brought up a guide. Followed it to the letter and got it working. The issue was it did not scale well, which the uploader said it wouldn't in the video. Also they did not cover OOP and classes very well in the video so while I was able to get an idea of how it worked I was unable to truly understand it.

I then went and asked on a couple of different websites and even got desperate enough that I went and spent 3 days trying to get something working from chatgpt. When I finally got a response on a forum all I got was. "That's the easiest thing in the word, Look up for loops." To which I sent the code I had, which had for loops already in it. I told them that after going to chatgpt it only made things worse. The only other reply I got was "Thats you fault for going to chatgpt for python code."
After that I just typed what I was looking for into google and saw a reply to a 5 year old post. Where the reply was "Why don't you go to the lemma soft forums, they have a lot of people that can help you, and after a quick search I found 3 battle systems in the RenPy Cookbook section which is prebuilt ready to use code.
I saw that and was extremely excited. So I came right over. Went through the cookbook trying to find something I could edit to work the way I was trying to get it to work. I found 2 and apparently one was based on the other one. The RPG Battle System/Other Misc Features and Animated RPG Battle Engine 1.2

After looking through all the code I thought I had a good enough grasp on it to understand it, well I found it 4 days ago and it still isnt working the way I think it should.

So since the code has a section for a fixed battle I figured I could just copy that and make a new instance of it for each of the "Ranks". Add an unlocked variable to have a character show up as a possible team mate. Add some more monsters, skills, and even code in some actual animations and it would be good to go. Well that is not how it is turning out.

Currently the I have the E and D Rank battles set up. I have it so that the player needs to beat the E Rank battles "4 Giant Bats" 25 times to unlock the D Rank battles "2 Icefall Treants" that part works. Well unlocked the button works, and facing the bats works. But as soon as I beat battle number 25 and move over to the D Rank missions it is still 4 Giant Bats. The Icefall Treants do not work. But if I stay in the E rank until battle 27 then go to D Rank, I get 1 battle Vs the 4 bats then everything after that there is nothing. Like the Treants are "There" they can hit the player. But their images are not there, and they are not in a battle slot so the player can not hit them back.

So now with the backstory all out of the way. I have tried rewritting sections of the code, moving bits around, I noticed if I use the command call load_monsters in the dev console it will give me 1 more random battle with the bats. Which had me thinking about persistent variables. Mainly because I also noticed if I change the monsters names and stats in the script after a save game is made the changes never take effect. But if I create a new game the changes are there. The only explanation I can come up with for that behavior is persistent variables....right? I mean I am not under any false impression that I am amazing at coding. I would classify myself as just barely above a novice. But that makes sense to me? I also noticed in the code that it is calling and defining globals a lot. After many hours of research I came across a post saying that global variables are not persistent for the save, but they are saved until the application is closed? So that made me even more confused.

So what is following is the changes I made to the code and everything that pertains to the E and D Rank battles. I tried to follow the way the original author Habitacle did. Any help that anyone can give, even so much as just pointing me in the right direction for where I can solve this and getting it working the way I want it to would be so very appreciated.

Load Setup area where I added e-sranksets following the fixedset example put in place already.

Code: Select all

label load_setup: if not name: $ name = "Player" $ a.name = name $ magicheal.addSkill(a) # add new skills $ defenseup.addSkill(c) $ magicswap.addSkill(y) call load_monsters call load_items $ party_list = [a,y,c,f,r] # initial party list, including main character $ fixedset = "set 1" $ erankset = "set 2" $ drankset = "set 3" $ crankset = "set 4" $ brankset = "set 5" $ arankset = "set 6" $ srankset = "set 7" $ wild_monsters = [mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11] $ restorehp() $ restoremp() return

Load Setup is being called right after label start.
label start:
call load_setup

This section of code covers the Labels and runs a check to make sure it is not too late.

Code: Select all

label erank(): if timeOfDay >= 5: rudy "It is too late I need to sleep" jump quest_board else: call battleE $ erankset = "set 2" $ restorehp() $ restoremp() jump quest_boardlabel drank(): if timeOfDay >= 5: rudy "It is too late I need to sleep" jump quest_board else: call battleD $ drankset = "set 3" $ restorehp() $ restoremp() jump quest_boardlabel crank(): if timeOfDay >= 5: rudy "It is too late I need to sleep" jump quest_board else: call battleC $ crankset = "set 4" $ restorehp() $ restoremp() jump quest_boardlabel brank(): if timeOfDay >= 5: rudy "It is too late I need to sleep" jump quest_board else: call battleB $ brankset = "set 5" $ restorehp() $ restoremp() jump quest_boardlabel arank(): if timeOfDay >= 5: rudy "It is too late I need to sleep" jump quest_board else: call battleA $ arankset = "set 6" $ restorehp() $ restoremp() jump quest_boardlabel srank(): if timeOfDay >= 5: rudy "It is too late I need to sleep" jump quest_board else: call battleS $ srankset = "set 7" $ restorehp() $ restoremp() jump quest_boardlabel quest_board(): scene questboard with dissolve call screen quest_board returnscreen quest_board(): use topBar if erank_unlocked == True: imagebutton auto "erankjob_%s": focus_mask True tooltip "E-Ranked Mission" action Call('erank') if drank_unlocked == True: imagebutton auto "drankjob_%s": focus_mask True tooltip "D-Ranked Mission" action Call('drank') if crank_unlocked == True: imagebutton auto "crankjob_%s": focus_mask True tooltip "C-Ranked Mission" action Call('crank') if brank_unlocked == True: imagebutton auto "brankjob_%s": focus_mask True tooltip "B-Ranked Mission" action Call('brank') if arank_unlocked == True: imagebutton auto "arankjob_%s": focus_mask True tooltip "A-Ranked Mission" action Call('arank') if srank_unlocked == True: imagebutton auto "srankjob_%s": focus_mask True tooltip "S-Ranked Mission" action Call('srank')$ tooltip = GetTooltip()if tooltip: text "[tooltip]" return

Labels that cover which battle scenario should be called.

Code: Select all

label battleS: $ stopEvent() if srankset: $ monstersSRank() $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8] $ srankset = None $ asignPos() $ row1btn = False $ row2btn = False $ missed_t = [] $ win = False $ battleEnd = False $ monsters_dead = 0 $ currentplayer = None show screen battle_tooltiplabel battleA: $ stopEvent() if arankset: $ monstersARank() $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8] $ arankset = None $ asignPos() $ row1btn = False $ row2btn = False $ missed_t = [] $ win = False $ battleEnd = False $ monsters_dead = 0 $ currentplayer = None show screen battle_tooltiplabel battleB: $ stopEvent() if brankset: $ monstersBRank() $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8] $ brankset = None $ asignPos() $ row1btn = False $ row2btn = False $ missed_t = [] $ win = False $ battleEnd = False $ monsters_dead = 0 $ currentplayer = None show screen battle_tooltiplabel battleC: $ stopEvent() if crankset: $ monstersCRank() $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8] $ crankset = None $ asignPos() $ row1btn = False $ row2btn = False $ missed_t = [] $ win = False $ battleEnd = False $ monsters_dead = 0 $ currentplayer = None show screen battle_tooltiplabel battleD: $ stopEvent() $ drankset call load_monsters $ monstersDRank() $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8] $ drankset = None $ asignPos() $ row1btn = False $ row2btn = False $ missed_t = [] $ win = False $ battleEnd = False $ monsters_dead = 0 $ currentplayer = None show screen battle_tooltip##label battleE: $ stopEvent() $ erankset call load_monsters $ monstersERank() $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8] $ erankset = None $ asignPos() $ row1btn = False $ row2btn = False $ missed_t = [] $ win = False $ battleEnd = False $ monsters_dead = 0 $ currentplayer = None show screen battle_tooltip

I Also tried doing the same thing but like this and it did not work so I commented it out.

Code: Select all

#label battle:# $ stopEvent()# if fixedset:# $ monstersFixed()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ fixedset = None# if erankset:# $ monstersERank()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ erankset = None# if drankset:# $ monstersDRank()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ drankset = None# if crankset:# $ monstersCRank()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ crankset = None# if brankset:# $ monstersBRank()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ brankset = None# if arankset:# $ monstersARank()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ arankset = None# if srankset:# $ monstersSRank()# $ monster_slot = [m1,m2,m3,m4,m5,m6,m7,m8]# $ srankset = None# $ asignPos()# $ row1btn = False# $ row2btn = False# $ missed_t = []# $ win = False# $ battleEnd = False# $ monsters_dead = 0# $ currentplayer = None# show screen battle_tooltip

This section covers what happens at the end of each battle.

Code: Select all

label end_battle: hide screen battle_overlay with dissolve if win: stop music play sound fanfare "You win!" stop sound $ expFormula() $ Energy -= 10 $ clean -= 10 $ food -=10 $ timeOfDay += 1 if erank_unlocked and erank_mission <= 26: $ erank_mission += 1 if erank_mission == 25: $ drank_unlocked = True $ renpy.notify("Promoted to D-Rank adventurer!") if drank_unlocked == True and drank_mission <= 26: $ drank_mission += 1 if drank_mission == 25: $ crank_unlocked = True $ renpy.notify("Promoted to C-Rank adventurer!") if crank_unlocked == True and crank_mission <= 26: $ crank_mission += 1 if crank_mission == 25: $ brank_unlocked = True $ renpy.notify("Promoted to B-Rank adventurer!") if brank_unlocked == True and brank_mission <= 26: $ brank_mission += 1 if brank_mission == 25: $ arank_unlocked = True $ renpy.notify("Promoted to A-Rank adventurer!") if arank_unlocked == True and arank_mission <= 26: $ arank_mission += 1 if arank_mission == 25: $ srank_unlocked = True $ renpy.notify("Promoted to S-Rank adventurer!") if srank_unlocked: $ srank_mission += 1

This section covers the defines for the battle section, with monster locations on screen, which monsters they should be, and all that.

Code: Select all

init python: def monstersFixed(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if fixedset == "set 1": m2 = copy.deepcopy(mon4) m3 = copy.deepcopy(mon5) m4 = copy.deepcopy(mon6) m5 = copy.deepcopy(mon7) m6 = copy.deepcopy(mon8) m7 = copy.deepcopy(mon3) battle_monsters = [m2,m3,m4,m5,m6,m7] else: m1 = copy.deepcopy(mon1) battle_monsters = [m1] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax def monstersERank(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if erankset == "set 2": m1 = copy.deepcopy(mon2) m2 = copy.deepcopy(mon2) m3 = copy.deepcopy(mon2) m4 = copy.deepcopy(mon2) battle_monsters = [m1,m2,m3,m4] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax def monstersDRank(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if drankset == "set 3": m5 = copy.deepcopy(mon3) m6 = copy.deepcopy(mon3) battle_monsters = [m5,m6] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax def monstersCRank(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if crankset == "set 4": m1 = copy.deepcopy(mon4) m2 = copy.deepcopy(mon4) m3 = copy.deepcopy(mon4) m4 = copy.deepcopy(mon4) m5 = copy.deepcopy(mon4) m6 = copy.deepcopy(mon4) m7 = copy.deepcopy(mon4) m8 = copy.deepcopy(mon4) battle_monsters = [m1,m2,m3,m4,m5,m6,m7,m8] else: m1 = copy.deepcopy(mon1) battle_monsters = [m1] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax def monstersBRank(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if brankset == "set 5": m1 = copy.deepcopy(mon5) m2 = copy.deepcopy(mon5) m3 = copy.deepcopy(mon5) m4 = copy.deepcopy(mon5) m5 = copy.deepcopy(mon5) m6 = copy.deepcopy(mon5) battle_monsters = [m1,m2,m3,m4,m5,m6] else: m1 = copy.deepcopy(mon1) battle_monsters = [m1] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax def monstersARank(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if arankset == "set 6": m1 = copy.deepcopy(mon6) m2 = copy.deepcopy(mon6) m3 = copy.deepcopy(mon6) m4 = copy.deepcopy(mon6) m5 = copy.deepcopy(mon6) battle_monsters = [m1,m2,m3,m4,m5] else: m1 = copy.deepcopy(mon1) battle_monsters = [m1] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax def monstersSRank(): global monsters_total global battle_monsters global m1 global m2 global m3 global m4 global m5 global m6 global m7 global m8 m1 = copy.deepcopy(empty) m2 = copy.deepcopy(empty) m3 = copy.deepcopy(empty) m4 = copy.deepcopy(empty) m5 = copy.deepcopy(empty) m6 = copy.deepcopy(empty) m7 = copy.deepcopy(empty) m8 = copy.deepcopy(empty) if srankset == "set 7": m1 = copy.deepcopy(mon7) m2 = copy.deepcopy(mon7) battle_monsters = [m1,m2] else: m1 = copy.deepcopy(mon1) battle_monsters = [m1] monsters_total = len(battle_monsters) for m in battle_monsters: if m.name: m._hp = m.hpmax

This section really only covers the defaults, I am mainly including it so anyone reading knows that I did give the additions I made defaults in the same place as what I was following.

Code: Select all

default srankset = Nonedefault arankset = Nonedefault brankset = Nonedefault crankset = Nonedefault drankset = Nonedefault erankset = Nonedefault fixedset = Nonedefault tt_timer = Falsedefault damage = 0default m_damage = 0default dropitem = Nonedefault atk_sfx = Nonedefault mp_lost = 0default hp_lost = 0default players = 1default monsters_total = 0default monsters_dead = 0default b_skill = "none"default message = "none"default target = "none"default picked_targs = []default party_list = []default wild_monsters = []default battle_players = []default alive_players = []default battle_monsters = []default misstext_list = ["MiSs!", "MisS!", "mISs!", "mIsS!"]default diss = Dissolve(.2)

And since the issue does in a way have to do with the monsters I figured I should add in the code that pertains to them as well

Code: Select all

label load_monsters: # var = Monster(name, hpmax, atk, dfn, exp, lvl, img, sfx_atk, anim, skills) $ empty = Monster(None, None, None, None, None, None, None, None, dead=True) $ mon1 = Monster("Treant", 20, 15, 1.0, 50, 3, "1", "water", anim=slow_sway, skills=[arrowhail]) $ mon2 = Monster("Giant Bat", 50, 20, 6.0, 50, 5, "2", "pound", anim=squeeze, skills=[lifedrain]) $ mon3 = Monster("Icefall Treant", 300, 40, 5.0, 75, 10, "3", "tackle", anim=idle_shake, skills=[lifedrain]) $ mon4 = Monster("Snow Buffalo", 250, 10, 10.0, 100, 20, "4", "water", anim=idle_y, skills=[deathmissile]) $ mon5 = Monster("Luster Grizzly", 450, 35, 10.0, 75, 30, "5", "thunder", anim=idle_xy, skills=[rockthrow]) $ mon6 = Monster("Snow Drake", 700, 75, 15.0, 100, 40, "6", "fire", anim=idle_x, skills=[swordofdeath]) $ mon7 = Monster("Snow Dragon", 1500, 100, 20.0, 500, 50, "7", "cut", anim=idle_shake, skills=[lavaburst]) $ mon8 = Monster("Elder Treant", 55, 25, 2.0, 50, 4, "8", "scratch", anim=idle_shake, skills=[mindburn]) $ mon9 = Monster("Earth Dragon", 60, 40, 3.0, 50, 6, "9", "leaf", anim=idle_xy, skills=[lavaburst]) $ mon10 = Monster("Charizard", 90, 95, 4.0, 50, 8, "10", "fire", anim=idle_shake, skills=[deathmissile]) $ mon11 = Monster("Sea Dragon", 85, 85, 5.0, 50, 5, "11", "water", anim=idle_x, skills=[thunderbolt]) returninit python: class Monster(object): def __init__(self, name, hpmax, atk, dfn, exp, lvl, img, sfx_atk, anim=idle_shake, skills=[], state=None, dead=False, finaldmg=0, slot=1, sprite_pos=0, dmg_pos=(0,0)): self.name = name self.hpmax = hpmax self._hp = 0 self._mp = 0 self.atk = atk self.dfn = dfn #self.vel = vel self.state = state self.lvl = lvl self.exp = exp self.dead = dead self.skills = skills self.img = img self.sfx_atk = sfx_atk #self.sfx_cry = sfx_cry #self.sfx_die = sfx_die self.finaldmg = finaldmg self.slot = slot self.anim = anim self.sprite_pos = sprite_pos self.dmg_pos = dmg_pos #self.rarity = rarity @property def hp(self): value = self._hp if not ( 0 <= value <= self.hpmax ): value = max( 0, min( self.hpmax, value ) ) self._hp = value return self._hp

Ok that should just about cover everything, If anyone is willing to help again I am truly thankful, if I did not provide enough of the code I am more than happy to just send all of it, but as these are the values I adjusted I am assuming that I made a mistake somewhere, so I hope this is enough.

* I edited the Subject as I felt it may not have been clear enough.

Requesting Assistance with Python OOP and a premade code that uses many Global Variables (2024)
Top Articles
Latest Posts
Article information

Author: Arielle Torp

Last Updated:

Views: 6147

Rating: 4 / 5 (61 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Arielle Torp

Birthday: 1997-09-20

Address: 87313 Erdman Vista, North Dustinborough, WA 37563

Phone: +97216742823598

Job: Central Technology Officer

Hobby: Taekwondo, Macrame, Foreign language learning, Kite flying, Cooking, Skiing, Computer programming

Introduction: My name is Arielle Torp, I am a comfortable, kind, zealous, lovely, jolly, colorful, adventurous person who loves writing and wants to share my knowledge and understanding with you.