Ren'Py Should I reset the call stack? If so, how?

RandyTyr

Active Member
Game Developer
Apr 30, 2021
779
1,827
I've been using both "jump" and "call"-commands in different parts of my Renpy-project, depending on what control flow makes more sense to me in the respective part. I'm now moving from Chapter 3 to Chapter 4, and I want to do the switchover in a label that is a few "call"s deep, with a "jump" to the start of Chapter 4.

Should I be concerned about what's on the call-stack at the moment of jumping over? It's a one-time thing, so no risk of piling hundreds of labels in there. But maybe I ought to reset the stack anyway? And if so, how do I do that?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,191
I've been using both "jump" and "call"-commands in different parts of my Renpy-project, depending on what control flow makes more sense to me in the respective part.
Hmm, it's not supposed to be done depending on what make sense for you, but depending on what make sense in regard of the game flow. You jump by default, and only call when you need to come back to this exact point after you've finished with what is behind the called label.


I'm now moving from Chapter 3 to Chapter 4, and I want to do the switchover in a label that is a few "call"s deep, with a "jump" to the start of Chapter 4.
What mean that the player will be forced to replay everything starting this said "few 'call's deep" label you want to jump to. Then unless your jump is conditioned, repeat this loop endlessly.


Should I be concerned about what's on the call-stack at the moment of jumping over?
You always need to be concerned, since the call stack store the point where the player will be sent back once Ren'Py encounter the return statement that end your called label/sequence.


But maybe I ought to reset the stack anyway?
If resetting the call stack do not break the game, then its flow is initially broken.


And if so, how do I do that?
By calling until return 0.
 
  • Like
Reactions: gojira667

RandyTyr

Active Member
Game Developer
Apr 30, 2021
779
1,827
What mean that the player will be forced to replay everything starting this said "few 'call's deep" label you want to jump to. Then unless your jump is conditioned, repeat this loop endlessly.
I don't understand - and I suspect that my explanation of the structure wasn't clear.

The basic idea is as follows:

In Chapter 3, the MC explores 100 rooms. The "main" label of the chapter calls a label that loads the information about the current room, and that label then might call another label to handle interactions inside the room. The "main" label doesn't care what room the MC is in, all the details are handled elsewhere.

In Room 99, there is an interaction possible that ends Chapter 3. The "room interaction"-label is where this is handled, by jumping to the start label of Chapter 4.

How would this induce any weird loops?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,191
In Room 99, there is an interaction possible that ends Chapter 3. The "room interaction"-label is where this is handled, by jumping to the start label of Chapter 4.

How would this induce any weird loops?
This way, yes, it will not induce a loop.


But then why jump from this room ? It would be better (because you'll not have to care about the call stack) to rely on a flag raised when the interaction ending chapter 3 is triggered.
Then in the main label that let the player choose the room, test if this flag is raised, and jump to the chapter 4 from there.

Something like:
Python:
default chapter4Ready = False

label mainLabel:
    [call rooms...]
    if chapter4Ready:
        jump startChapter4

label room99:
    [...]
    menu:
        "something":
            [...]
        "the ending interaction":
            $ chapter4Ready = True
            [...]

    return
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
The most common mistake with jump and call is what Anne described... using call in situations where (like now) you decide that you want to exit the code you've "called into" without using return. The reality is that those call statements should probably have been jump statements. Or at the very least, there should have been some sort of "hub" label that was always returned to and the decision to jump elsewhere should be made after the script logic has returned from the called block (like Anne's most recent reply).

Or put another way, only ever use call when you're 100% sure you'll be using return to come back.

But you are where you are... and this is RenPy... so we can afford to throw out some of the commercial programming rules.

If you jump to Chapter4... that's fine*.
* Okay, it's not fine - but it's not terrible either.

What will happen is that you'll leave a few labels on the call stack, but as long as you never use a return beyond this point without a corresponding call - it will behave (due to it's "Last on, First off" nature)... up to a point. If you keep repeating this sort of coding, the amount of labels left on the stack will keep increasing. That's bad in purely technical terms (since you're not managing your code correctly), but RenPy won't care. A couple of hundred labels on a stack is perfectly normal in python, as long as things are coded correctly. Relatively speaking, it's a tiny amount of memory.

The "up to a point" is when the program ends.
RenPy scripts tend to end with a final return statement (it effectively returns to the main menu).
Except your script will still have labels on the stack and the script will "return" there instead. Suddenly your player will be wondering why at the end of the game, they're back in the middle of some content they finished ages ago (because you called it and didn't return out of it).
Since this is RenPy... there's a way around it. Instead of ending the game with return, instead use $ MainMenu(confirm=false), which will effectively go "sod, it... back to the main menu... I don't care what else is happening". It's a kludge, but it's a kludge that will ignore the remaining items on the stack.

Alternatively, you could use Anne's other suggestion of a loop using and .
will remove the newest entry on the call stack. One at a time.
will tell you how many items are currently on the stack.
If you loop around the "pop" until the "stack_depth" is zero, the stack will be empty and then you can jump to Chapter4. Again, a bit of kludge - but it solves the problem you've built for yourself.