Problems with chapter select

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
trailsiderice
Regular
Posts: 69
Joined: Fri Sep 29, 2023 4:02 pm
Contact:

Problems with chapter select

#1 Post by trailsiderice »

Edit:
Adding a TL;DR since this is kind of long and probably a little confusing. Basically, I'm having a ton of problems getting a chapter select to work the way I want it to. If you think you have an idea for how to get this working, you don't need to read the entirety of the rest of this thread, although I would appreciate at least a skim so you can see whether or not I've tried your suggestion already.
How I want it to function: (stuff that I can't seem to get working right will have a red asterisk)
  • From the main menu, the player can either choose to enter each route directly where they left off or go to chapter select for that route*
  • From the chapter select menu, the player can select any chapter to play, but only if they are not currently inside a chapter already (if the leave the game in the middle of a chapter, all other chapters are greyed out except the one they are on until they finish the one they are on)
  • Players can leave the chapter at any time during a chapter and come back to the chapter in around the same spot they were before in that chapter without having to restart the chapter entirely*
  • When finished with one chapter, players can choose to either continue to the next chapter or exit back to the chapter select menu*
  • If the player chooses to exit the chapter, they can go back and replay any of the previous chapters they've already unlocked, and this will overwrite any variables they've modified, without getting rid of their progress*
  • Variables modified in one chapter should continue to have that modified value in following chapters*
  • Players have only one save per route. There is no save slot menu, saves are handled automatically.*
  • All these things should be true at the same time, without any of them causing problems with any of the others************
This feels like it should not be difficult. However it is, evidently, an endless struggle.
Below is a documentation of my struggles: (i.e. tl;dr is now over)

Hi!
I've mentioned this in some other posts I've made, but my game has a particular set up where players select a route on the main menu, and each route has a "start/continue" button and a "chapter select" menu button.

The Start/Continue button checks to see if an autosave with the character's name as a prefix exist (for example, "[charactername]-auto-1". To make this work, I have an autosave prefix callback that changes the autosave prefix depending on which character route you're playing, and I have the maximum number of autosaves set to 1.)

The Chapter Select button, meanwhile, checks to see if a save file exists with the name "[charactername]menu" (where charactername depends on which route you're trying to view the menu for), and if it exists, loads that save file, and if it doesn't, jumps to a label that shows the menu screen for that character. The Menu save file is saved right before the player exits out of the chapter select menu to go to the main menu.

The reason I have the character menu screen shown inside a label rather than as a screen on the main menu is because I need to make it so that players can exit out of a chapter at the end of it, and start the next chapter from the chapter select menu without needing to store variables from the previous chapter as persistent data. I set it up this way on the suggestion of another user here, you can see that topic here to get a better idea of what my end goal with this setup is.

Here is the code for my start/continue and chapter select buttons:

Code: Select all

# variables that detect if either respective save file exists
default menufileexists = FileLoadable(char + "menu",slot=True)
default gamefileexists = FileLoadable(char + "-auto-1",slot=True)

## Start/Continue button
# if there's no menu file (which there should be if the player has made any game progress) the button should say "start" and start from the route beginning
if not menufileexists:
    textbutton ("START"):
        style "routestartbutton"
        text_style "startbtntxt"
        action Start(char + "_chap1part1")
else: # if not, the button should say continue and load the game file
    textbutton ("CONTINUE"):
        style "routestartbutton"
        text_style "startbtntxt"
        action FileLoad(char + "-auto-1",confirm=False,slot=True))
        
## Chapter Select button
# checks if a menu file exists, and if it doesn't starts the game from the appropriate menu label
textbutton ("CHAPTER SELECT"):
    style "routemenubutton"
    text_style "routemenubuttontxt"
    action If(menufileexists,FileLoad(char + "menu",confirm=False,slot=True),Start(char + "_menu"))
    xalign 0.5

and the code for the button that exits the chapter select to go to the main menu:

Code: Select all

## This is a header that is shown on both the chapter select screen and during gameplay. during gameplay, it collapses to be unintrusive, but a button in the corner can be clicked to slide it down and do things like exit, save, view game settings, etc
imagemap:
        ## this code determines whether the header is collapsed or not. Header cannot be collapsed unless the player is inside gameplay
        if ingame == False:
            auto "gui/mainmenu/header_%s.png"
        elif headerclosed == True:
            ground "gui/mainmenu/bx_header_story.png"
            hover "gui/mainmenu/bx_header_story.png"
            at slide_up
        else:
            auto "gui/mainmenu/header-story_%s.png"
            at slide_down
        
        ## this code determines what the header's exit button will do depending on if you are inside a chapter or on the chapter select screen
        hotspot (32,27,85,50):
            if ingame == True:
                ## if player is inside a chapter, the exit button takes the player to the chapter select menu
                action [SetVariable("ingame",False),Jump(savefilename + "_menu")] 
                sensitive headerclosed == False
            else:
            	## if the player is already on the chapter select menu, save the game to the "[charactername]menu" save slot and then exit to the main menu if successful
                action FileSave(savefilename + "menu", confirm=False, slot=True, action=MainMenu(confirm=False))
The buttons for each chapter on the chapter select menu also check if an autosave file exists and loads it if it does (or starts the chapter from the beginning if it doesnt) in the same way that the start/continue button does.

My problem:

Frequently I find that if I exit out of the game in the middle of a chapter, (particularly if I load an existing autosave for a chapter via the chapter select menu and then immediately exit) then exit out of the chapter select menu to the main menu, what happens is that if I click the "Chapter Select" button again, instead of loading the menu save and showing the chapter select menu, it will load the autosave, and take me directly back into the chapter I was just playing. (i.e. the Chapter Select button is performing the function of the Start/Continue button in these cases for some reason)

Most of the time, loading the chapter select works as intended, even when there is an autosave file. But sometimes it just decides to load the autosave instead of the menu file for whatever reason. I can't seem to figure out why.

I need to find a way to fix this. This "separate save for in-game and menu screens" set up is the only way I can think of to make my chapter select work the way I want it to without storing every single important in-game variable throughout the route as persistent data, but it's honestly getting so frustrating trying to get it to work that I'm considering just saying "fuck it", abandoning dealing with renpy saves, and doing it the persistent data way.

(As a sidenote, I see a lot of experienced Ren'Py users on here complain about more inexperienced users relying too heavily on persistent data, but it's things like this that really makes me sympathize with those inexperienced users. The Ren'Py save system is designed in such a limiting, difficult to use way that expects your game to conform to it's own idea of what a visual novel's save system should look like, and if you want to deviate from that mold even a little bit, it's so difficult that it's honestly easier to just abuse persistent data)
Last edited by trailsiderice on Sun Jan 28, 2024 8:12 pm, edited 9 times in total.

trailsiderice
Regular
Posts: 69
Joined: Fri Sep 29, 2023 4:02 pm
Contact:

Re: Buttons load the wrong save

#2 Post by trailsiderice »

I'm not sure if this provides any sort of clue to what may be happening here, but I tried adding

Code: Select all

on "show" action FileSave(char + "menu",confirm=False,slot=True)
to the chapter select screen, and while it still sometimes loads the autosave, on some occasions what i seem to get instead is the following exception:

Code: Select all

  File "renpy/common/000statements.rpy", line 670, in execute_call_screen
    store._return = renpy.call_screen(name, *args, **kwargs)
Exception: Cannot start an interaction in the middle of an interaction, without creating a new context.
Currently looking through the documentation to try and wrap my head around this, but if anyone can help me figure out what's going on and maybe how to fix it, I'd appreciate it.

trailsiderice
Regular
Posts: 69
Joined: Fri Sep 29, 2023 4:02 pm
Contact:

Re: Buttons load the wrong save

#3 Post by trailsiderice »

I thought maybe I might try replacing Jump(savefilename + "_menu") in the header screen code with:

Code: Select all

Function(CallRouteMenu,char)
and then in an init python block, i defined the following function:

Code: Select all

def CallRouteMenu(route):
        menulabel = route + "_menu"
        renpy.call_in_new_context(menulabel)
And while I'm not getting the "cannot start interaction in the middle of an interaction" error anymore... it still sometimes loads the autosave instead of the menu save. So I'm stumped. Help would be appreciated.

trailsiderice
Regular
Posts: 69
Joined: Fri Sep 29, 2023 4:02 pm
Contact:

Re: Buttons load the wrong save

#4 Post by trailsiderice »

Ok, I think I've...sort of fixed it. I can already predict a few problems, so I'm probably still going to need some help with this.

What I've done for now is get rid of the "menu" save entirely. The reason I had two separate saves to begin with was because, at the end of each chapter, I have a screen that asks the player if they want to continue on to the next chapter or exit to the chapter select. Unfortunately even if I made the "go to chapter select" button save the game, I had a problem where, if the player exited the game from this menu, came back, and then loaded the next chapter from the chapter select, it would end up starting the player at the last autosave within the previous chapter, instead of starting the new chapter. And the way I had worked around this was by making it so that if the player exits from this menu, it simply deletes the autosave entirely, and saves the game on the chapter select menu. This made it so that variables would persist between chapters, but you wouldn't have weird glitches like that. But unfortunately that created the new glitch that prompted this thread in the first place.

What I've done to change this is, instead of saving on the chapter select menu, I make both the 'Continue' and 'Go to Chapter Select' buttons call the following label:

Code: Select all

label exit_label:
    $ renpy.force_autosave()
    if ingame == False:
        $ renpy.call_in_new_context(char + "_menu")
    else:
        return
The 'go to chapter select' button also changes that ingame variable to false before calling this label.

The problem with this set up:
While this works if the player plays the game in order, each chapter one by one, without ever going back, it does not work if the player decides to go back and play a previous chapter at any point. Since the chapter menu buttons load the autosave, it simply loads the last autosave instead of letting the player replay that chapter. Unfortunately I don't know how on earth I'm going to get around this issue with this set up while also preserving variable values.

I'm going to rename this thread to something more fitting, since the problem is pretty solidly not about buttons loading the wrong save at this point. Honestly, at this point I'm just looking for suggestions on a better way to set up my chapter select. I have no idea what a good way to set this up would be. It seems like no matter what I try, either the variables don't persist between chapters, or I have some nonsense where I can't control what buttons do what, or I lose the ability for players to go back and replay chapters without finishing the whole game first.

Someone please give me some input here.

trailsiderice
Regular
Posts: 69
Joined: Fri Sep 29, 2023 4:02 pm
Contact:

Re: Problems with chapter select [still need help]

#5 Post by trailsiderice »

Still need help with this.

I really would prefer to avoid abusing persistent data if I can, but I'm starting to think that abusing persistent data may be my only recourse here.

If anyone knows any way I could get this working in order to avoid abusing persistent data, I'd love to hear your suggestions.

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2407
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: Problems with chapter select [still need help]

#6 Post by Ocelot »

I didn't read all that, since it looks like a pretty complex system and I prefer not to debug complex systems bt looking at partial code snippets from random places, but I noticed that you are trying to avoid persistent data as if it was goto.

As long as you understand how persistent data works and what are implications of its use, it is perfectly fine to use it.
The main feature of persistent data is: if you set some value in save A, then it will be accessible in save B, and if save B changes it, it will be retroactively changed for save A.
So things like relationship levels (which should be different for different playthroughs) should not be stored in persistent data, but all-time max values (for determining, which scenes are avaliable for replay in main menu, for example) could.

That said I have a question:
If the player chooses to exit the chapter, they can go back and replay any of the previous chapters they've already unlocked, and this will overwrite any variables they've modified, without getting rid of their progress*

Variables modified in one chapter should continue to have that modified value in following chapters
I have some trouble understanding how exactly you wnat this to work.

Imagine it he first chapter you are asked to choose between black and red. You choose red.
In second chapter, because you chose red, you are given choice between hearts ♥ and diamonds ♦. You choose hearts ♥ and end the chapter.
Then you reply chapter one and choose black.
Then you get to chapter 3 and it check your choices for color and suit. What should happen here?
Option 1: It should respect current values and give you black hearts ♥. Then a simple use of persistent variables is enough. Chapter select can live in menu context instead of game context, everything is fine.
Option 2: It should remember choices from the very beginning and give you red hearts ♥. If you want black something, you will have to replay chapter 2 too and make a choice here. A slightly more complex approach, but still relatively easy. Chapter select can still live in menu context instead of game context.
< < insert Rick Cook quote here > >

trailsiderice
Regular
Posts: 69
Joined: Fri Sep 29, 2023 4:02 pm
Contact:

Re: Problems with chapter select [still need help]

#7 Post by trailsiderice »

Ocelot wrote: Sun Jan 28, 2024 4:31 am As long as you understand how persistent data works and what are implications of its use, it is perfectly fine to use it.
The main feature of persistent data is: if you set some value in save A, then it will be accessible in save B, and if save B changes it, it will be retroactively changed for save A.
So things like relationship levels (which should be different for different playthroughs) should not be stored in persistent data, but all-time max values (for determining, which scenes are avaliable for replay in main menu, for example) could.
That's fair. I think the thing that may be causing me trouble here is that I'm always seeing people say things like "do not ever put story related variables in persistent, it's bad practice/an abuse of persistents", and because i want to avoid bad practice, i try to listen to that and make it work in a different way. but for this particular game, I want my save system to be more of a "one playthrough per route per machine, unless the player chooses to completely reset the whole game" type of deal. Such that in my case, putting relationship values in persistent does actually make sense even though it would be bad practice for some other game that doesn't have this kind of mechanic. which I realize is unconventional, and it's not usually something I would do, but I have specific reasons for setting it up this way that are important mechanically.

But because this kind of system is unconventional, most people aren't really imagining this type of system when saying things like "it's an abuse of persistent data to put story related variables in persistent" so this may be a case of me trying to apply advice to my game that doesn't fit with the type of mechanic I'm going for. a sort of "if you understand the rule and have a good reason for breaking it, you should break it" kind of situation.
Ocelot wrote: Sun Jan 28, 2024 4:31 am Imagine it he first chapter you are asked to choose between black and red. You choose red.
In second chapter, because you chose red, you are given choice between hearts ♥ and diamonds ♦. You choose hearts ♥ and end the chapter.
Then you reply chapter one and choose black.
Then you get to chapter 3 and it check your choices for color and suit. What should happen here?
Option 1: It should respect current values and give you black hearts ♥. Then a simple use of persistent variables is enough. Chapter select can live in menu context instead of game context, everything is fine.
Option 2: It should remember choices from the very beginning and give you red hearts ♥. If you want black something, you will have to replay chapter 2 too and make a choice here. A slightly more complex approach, but still relatively easy. Chapter select can still live in menu context instead of game context.
Yeah, option 1 is kind of what I'm going for.
The idea is that the player can play through the whole route, unlock one ending, and then if they want to unlock a different ending, they don't have to play through the whole game again all the way to the end if they don't want to. if they do replay the whole game they get rewarded with changed dialogue or extra scenes in some chapters, but if they don't care about that and just want to unlock the ending only, they don't need to play all the chapters again—instead they can just selectively replay enough chapters with important choices in them to unlock the other ending.

So say for example during the player's first playthrough, they somehow managed to get 100% choices towards ending B. If they wanted to then unlock ending A, instead of replaying the whole game, they could just replay a little more than half of the chapters and select ending A choices during those chapters. then the total number of points towards the B ending would be less than the total number of points towards the A ending, and ending A would unlock. And now they have access to both ending A and ending B from the chapter select menu, if that makes sense.

Thanks for your help by the way. I think I will probably go back to using persistent data for the variables that are important across multiple chapters, since I think in my particular case it is probably justified.

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2407
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: Problems with chapter select

#8 Post by Ocelot »

In your case using persistent data seems acceptable. Just make sure that there are no intermediate dependencies that will set your game in strange states, like in black hearts example. Normally you could not get this by playing the game, only by some clever replaying of earlier chaptesr. Or actually anticipate this! Maybe some secret dialogue on normally-impossible combination of variables!
< < insert Rick Cook quote here > >

Post Reply

Who is online

Users browsing this forum: No registered users