Hi everyone! I’ve been working on a save system that would allow the player to save and load at any time from the stat screen, similar to something that you would see in regular games, visual novels and the like.
Today, on another thread, I saw that other people might be working on something similar and thought it might be nice to have a place for everyone to pool their knowledge on this topic.
Below I wrote a guide on how to implement my approach to such a save system, I have implicit_control_flow set to true for my code so you might need to change some things if you don’t use it.
I also have a small example demo that contains everything described below.
Persistent checkpoints
So, the first issue we run into when trying to do this with checkpoints is that reloading old checkpoints deletes new ones. Say I have a checkpoint both at the end of Chapter 1 and Chapter 2 of a story. If we rewind to the end of Chapter 1, the checkpoint in Chapter 2 will no longer exist.
Fortunately, we can avoid this by using checkpoint_exclusions. Exclusions can be declared in the startup file to keep certain variables the same, even if we reload checkpoints. We can also add entire checkpoints to this, keeping them persistent even after reloading.
But you are only able to add checkpoints to the exclusion list if they already exist during startup, so we will need to create saves for all of our checkpoints at the end of the startup file, like this:
*create checkpoint_exclusions "checkpoint_one checkpoint_two checkpoint_three"
*save_checkpoint one
*save_checkpoint two
*save_checkpoint three
This also means that we have 3 checkpoints saved right at the start of our story, we will need to keep this in mind to avoid errors during loading.
Later, during saving and loading, we will also use some additional variables, that allow us to name our checkpoints and prevent some errors. Add them to the startup file and the exclusion list.
*create checkUsed1 0
*create checkUsed2 0
*create checkUsed3 0
*create checkName1 "Empty"
*create checkName2 "Empty"
*create checkName3 "Empty"
*create checkpoint_exclusions "checkpoint_one checkpoint_two checkpoint_three"
Loading checkpoints
Now we can really get started! The chapter on saving checkpoints uses a lot of stuff from the loading part, so we will first take a look at loading checkpoints.
The first lesson on trying to do any complicated changes in the stat screen is that you really don’t want to do any complicated changes in the stat screen, because it can lead to a bunch of really annoying bugs.
To avoid this we use the *redirect_scene command to move us from the stat screen to a seperate file, where we will load our checkpoints.
Put something like this somewhere in your statscreen file:
*label statscreen_loading
*choice
*selectable_if (checkUsed1 = 1) #Load 1: ${checkName1}
*redirect_scene save_manager loading1
*selectable_if (checkUsed2 = 1) #Load 2: ${checkName2}
*redirect_scene save_manager loading2
*selectable_if (checkUsed3 = 1) #Load 3: ${checkName3}
*redirect_scene save_manager loading3
#Cancel
*goto other_stats_stuff
You can also see that we have used our other variables here.checkUsed will only be set to 1 once the player has saved in that slot by themselves atleast once, preventing them from loading our saves in the startup file. checkName helps the player keep track of what checkpoint leads to what part of the story.
Now for *redirect_scene to work we will also need a seperate file here named save_manager.txt, where we will load our checkpoints. It looks like this, for now:
*label loading1
*restore_checkpoint one
*label loading2
*restore_checkpoint two
*label loading3
*restore_checkpoint three
*label loadingauto
*restore_checkpoint auto
You might have also noticed the auto checkpoint at the end there, we will use it in the next part.
Saving checkpoints
Now we are finally ready to create saves.
Except you are actually just straight up not allowed to create any saves inside the stat screen, so we will need to do a little workaround:
*label other_stats_stuff
This is the stat screen test123
*choice
#save
*redirect_scene save_manager loadingAuto
#load
*goto statscreen_loading
Our “save” button actually just loads an autosave. We will create this autosave after every choice, page break etc. using a subroutine and then use this autosave to create our proper saves.
We will expand our save_manager.txt to work as our subroutine. It now looks like this:
*label save
*save_checkpoint auto
*if choice_just_restored_checkpoint
Please select a save slot
*choice
# 1: ${checkName1}
*set checkUsed1 1
*set checkName1 chaptername
*save_checkpoint one
# 2: ${checkName2}
*set checkUsed2 1
*set checkName2 chaptername
*save_checkpoint two
# 3: ${checkName3}
*set checkUsed3 1
*set checkName3 chaptername
*save_checkpoint three
*return
*return
*label loading1
*restore_checkpoint one
*label loading2
*restore_checkpoint two
*label loading3
*restore_checkpoint three
*label loadingauto
*restore_checkpoint auto
Let’s go through this step by step.
The most annoying and error prone part of this whole thing is that you will now need to place *gosub_scene save_manager save all over your story whenever you want the player to be able to save. For a true save at any point system this would mean after every page_break, choice etc. You can check the small demo above for an example.
Once the story reaches one of these gosubs an auto save is created and the code skips to the return with nothing else happening for now. The main saving part in our routine is blocked off by the *if choice_just_restored_checkpoint, this should only activate if we load our autosave using our save button in the stat screen.
After that the player can choose a save slot, which is then marked as used and given a name.
I use an additional variable for naming the save that changes during the story depending on the chapter number, but you could probably figure out some better way to name this or just let the player pick their own name.
And with that you’re done!
I hope this can be helpful or at least interesting to you! If you noticed some errors/issues or have other ideas or improvements I would be happy to hear about them.
