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
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_board
label 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_board
label 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_board
label 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_board
label 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_board
label 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_board
label quest_board():
scene questboard with dissolve
call screen quest_board
return
screen 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
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_tooltip
label 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_tooltip
label 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_tooltip
label 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_tooltip
label 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
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
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
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
Code: Select all
default srankset = None
default arankset = None
default brankset = None
default crankset = None
default drankset = None
default erankset = None
default fixedset = None
default tt_timer = False
default damage = 0
default m_damage = 0
default dropitem = None
default atk_sfx = None
default mp_lost = 0
default hp_lost = 0
default players = 1
default monsters_total = 0
default monsters_dead = 0
default 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)
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])
return
init 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
* I edited the Subject as I felt it may not have been clear enough.