Ren'Py Getting Old Save Files to work in future updates!

despiteful

COED Conquest Dev
Game Developer
Jun 12, 2020
330
625
Hey!

I'm the developer of the renpy sandbox game COED Conquest!

When I started the project as a complete noob 1,5 years ago, I didn't spend any thought on compatability of my save files.

All my variables are defined inside a label at the beginning of a new game, therefore if I add something like a new heroine or an event (both classes in my game) they won't be in a save file from an older version!

Since the game has quite a lot of variables split into multiple files making changes is a lot of work, and therefore I would like to discuss the solution I thought of here first before I spend hours trying something that won't work.

My idea would be to turn all my old labels into 'init python' blocks with priorities according to the current variable declaration regime.
This should add any newly defined variable to the old save files correct?

If that would work I have the problem that variables like for example 'Events' are appended to an 'Eventlist' in the initialization, so every new event would not end up in the 'Eventlist' of old save files, since they already have said list saved in their save, correct?

If I'm correct so far, I could add a label that checks if an element is inside the list and adds it if it is not, would that work? If yes, can I make it so that it only is called when loading, or starting a new game? EDIT: Just found the after_load label, that should work for me in that regard at least!

Thanks in advance for your input!
 
Last edited:

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,500
8,035
Variables do not need to be anywhere, not inside a label or inside a init python.
They can exist inside a simple .rpy file and that works just fine, at least for me.
 

despiteful

COED Conquest Dev
Game Developer
Jun 12, 2020
330
625
Variables do not need to be anywhere, not inside a label or inside a init python.
They can exist inside a simple .rpy file and that works just fine, at least for me.
Interesting, but I can't define an order in which they are created then right?
For example need to create all the locations before I can add them to an event ect. Adding them into the same rpy file in the right order isn't really an option for me, so I thought that init python could be useful sinds you can give each block a priority in which it is loaded
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,500
8,035
You can create them and call them when they are needed. No need to make variables on the spot.
 

despiteful

COED Conquest Dev
Game Developer
Jun 12, 2020
330
625
You can create them and call them when they are needed. No need to make variables on the spot.
That wouldn't really work for me, if I add a new heroine, or a new location, they need to be presented from the first loading of the game and they also need to be in their respective lists or the search algorythms won't find where they are at what time ect.

The problem I still see is that of the lists, since if I add the elements to the list at initialization, and a player loads his save he will load the old version of the list and he won't have access to said heroine or location or event ect.

I just found the after_load label which should be able to solve my troubles even if it will be a lot of work I suppose..
 

despiteful

COED Conquest Dev
Game Developer
Jun 12, 2020
330
625
Did you try, tho?
I use arrays and I can add new elements without any issue.
I have not, I will give it a shot!
Just to clarify:
You have an array with 3 elements, a player saves his game, you make a new version of the game and add a 4th element, the player will be able to load his game and have all 4 elements in his array?
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,500
8,035
Thanks, one hopfefully last question:

Is the array (and your other variables) defined with 'define' or 'default'?
Default, if they change throughout the game.
Define if they are meant to stay the way you initialized them.
 

despiteful

COED Conquest Dev
Game Developer
Jun 12, 2020
330
625
Oh my god! Thank you so much! The whole thing will be a lot less work than I thought!
And on top of it I can do it in pieces without breaking anything!

every variable in my game will be changed to
if not hasattr( store, "myNewVariable" ):
$ myNewVariable = "Its default value"

Since I already have the list in the same place in my code I can immedeatly go like this:

if not hasattr( store, "myList" ):
$ myList = []

if not hasattr( store, "myNewVariable" ):
$ myNewVariable = "Its default value"
$ myList.append(myNewVariable )

This is just perfect!
 
  • Like
Reactions: darlic

AdventAnyx

Active Member
Game Developer
Feb 2, 2020
740
2,920
Yeah, I started the same way: wrote all my variables like:
$ some_var1 = 0
Then tracked what labels they start to appear in before I do something to them.

All I had to do later was to change that to:
default some_var1 = 0
You can place it anywhere.
Still can't figure out (from reading) what's the difference between "default" and "define" is. I write mine as "default" though. All good.

And also take a look at the special label called "after_load". You can fix your shit for people playing from their prev. save.
I recommend having some unique variable for each build for this.
I have something like:
default cheat_pass = "codeword123"
I use this to let people use cheat-buttons, but now it's also useful for things like this:
Code:
label after_load:
    if cheat_pass != "newpass123":
        $ cheat_pass = "newpass123"
        $ old_var = 15
        $ another_var = False
    return
So, basically, if the cheat password in older save is wrong, you can fix it and assume that some variables can be fixed along the line (if needed).
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,500
8,035
Yeah, I started the same way: wrote all my variables like:
$ some_var1 = 0
Then tracked what labels they start to appear in before I do something to them.

All I had to do later was to change that to:
default some_var1 = 0
You can place it anywhere.
Still can't figure out (from reading) what's the difference between "default" and "define" is. I write mine as "default" though. All good.

And also take a look at the special label called "after_load". You can fix your shit for people playing from their prev. save.
I recommend having some unique variable for each build for this.
I have something like:
default cheat_pass = "codeword123"
I use this to let people use cheat-buttons, but now it's also useful for things like this:
Code:
label after_load: 
    if cheat_pass != "newpass123":
        $ cheat_pass = "newpass123"
        $ old_var = 15
        $ another_var = False
So, basically, if the cheat password in older save is wrong, you can fix it and assume that some variables can be fixed along the line (if needed).

Define is a constant, Default is a variable.
It is the easiest way to remember it.

It is not the correct definition, but if you need a variable to change state during the gameplay, you use default.
If you need to define something (Such as a character or the amount of elements an array has), you use define.
 

AdventAnyx

Active Member
Game Developer
Feb 2, 2020
740
2,920
Define is a constant, Default is a variable.
It is the easiest way to remember it.

It is not the correct definition, but if you need a variable to change state during the gameplay, you use default.
If you need to define something (Such as a character or the amount of elements an array has), you use define.
I'm a noob, so it might be something to do with this, but I used default for everything before I had to deal with the main-menu (probably because the game is technically not started yet).
Then I had to use "define" for a variable that is supposed to show different backgrounds in the main menu. I also have buttons in the main menu that change said variable and show different backgrounds. That's why I can't wrap my head around the "it's constant" vs "it's variable". I can change both of them but only the "defined" one works in the main menu.
 

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
5,500
8,035
I'm a noob, so it might be something to do with this, but I used default for everything before I had to deal with the main-menu (probably because the game is technically not started yet).
Then I had to use "define" for a variable that is supposed to show different backgrounds in the main menu. I also have buttons in the main menu that change said variable and show different backgrounds. That's why I can't wrap my head around the "it's constant" vs "it's variable". I can change both of them but only the "defined" one works in the main menu.
You can change defined stuff yes, but the changed variables will not behave like a default one would.
If I remember correctly, back when I was learning Ren'Py, I made the mistake of using define instead of default and whenever I would pick a choice, that would change for all the other saves as well. Really messy.

As a rule of thumb, you use define for stuff that never changes.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,966
16,214
You can change defined stuff yes, but the changed variables will not behave like a default one would.
It's not exactly that, partly because your constant/variable opposition is a little too reducing. Something like that is probably better :
  • default, the variable will be saved by default.
  • define, the variable will be saved only if redefined.

We should probably totally get ride of this "is changed" approach, because it's precisely the trap set by define.

myDict["blabla"] = "blibli" is changing a value, but myDict is still the dictionary X, as initially defined.
myObject.count = 2 is changing a value, but myObject is still the same than.

Then come :
myDict = { "blabla": "blibli" } you redefined myDict into a new dictionary, that will now be saved.
myObject = MyClass( count=2 ) you redefined myObject to be a new one, and it will be now saved.
myString = "bloblo" you redefined myString, that is now a new text and that will be saved.

What left only one execption (against the many for the "changed" approach), numbers.
myInt += 1 feel less like a redefinition than all the other example. Yet it is one.
 
  • Like
Reactions: Winterfire