Ren'Py Restarting Dialogue

ZLZK

Member
Modder
Jul 2, 2017
295
794
I'm modding a Ren'Py game.
I have added button to game menu that changes a variable.

For example:
There is displayed dialogue with a variable.​
I enter game menu and click added button to change that variable.​
But when I leave game menu variable in dialogue isn't updated.​

This thing is beginning to drive me nuts.

How can I force dialogue to repeat itself?
And how can I make it happen when leaving game menu?
  • Rollback
    • Rollback is erasing changes in variables, pass.
  • raise renpy.game.RestartTopContext()
    • Works, but makes quick_menu disappear.
The effect I want to use is possible and it's even in the engine, but I'm unable to recreate it.
I mean entering and leaving console does what I need.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
This doesn't actually answer your question...

But on a purely practical level... can't you just see the dialogue -> rollback a line or two -> enter the game menu -> change the value of the variable -> return back to the game and then continue one or two lines to the original dialogue (but now with the updated value)?

Less of a solution and more of a work-around.

Dialogue is just screen say(): and from memory... actually, nvm. I'm not sure of the answer I was about to type and so until I have time to sit down and do a bit of testing, better I don't say anything that might mislead you right now.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
How can I force dialogue to repeat itself?
It is repeated automatically when you return to the game.

What happen is not that the dialog line is not updated, but that you are changing the value from, and therefore in, an upper context. Then, once you return to the main context, the value return to what it is expected to be.

So the question is: Why do you need to go back to the main menu in order to change this value ?


Just define a screen with your button, then show it or add it to . The change will be performed from the main context, and therefore apply immediately.
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
I need it to be in game_menu, because button changes settings.
And I want to see right away effects of changed settings.

The variable does change.
I mean Ren'Py isn't redrawing screens after returning from game menu.
How to force it to redraw displayed screens?
And how to do it when I return back from game_menu?

Game reloading, loading saves, dialogue advancing.
All works, but I want changes to be displayed right after returning from game_menu.

The tricky part is that game_menu isn't top context.
Just define a screen with your button, then show it or add it to . The change will be performed from the main context, and therefore apply immediately.
No they are not. I have screen for modding and to see changes-
I still have to use raise renpy.game.RestartTopContext() to see the changes.
 
Last edited:

ZLZK

Member
Modder
Jul 2, 2017
295
794
I'm also doing another mod where I'm changing text of menu choices.
And it's same issue all over again.
I need some other solution than raise renpy.game.RestartTopContext().
What function should I use to see changes right away in a attached file?
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
I need it to be in game_menu, because button changes settings.
Except that you absolutely don't need to be in the main menu to change a setting. In fact, passing by the main menu is the most complicated way to change a setting, precisely because of the context issue.


I mean Ren'Py isn't redrawing screens after returning from game menu.
How to force it to redraw displayed screens?
And how to do it when I return back from game_menu?
As I already said, you don't need to force Ren'Py to redraw the screen when returning from the game menu, because it do it automatically, period.


[...] in a attached file?
[Mode "I swear, I don't need vacations... but some days it's hard, really hard": ON]

Ok, so:
  • There's a function designed to see if a given screen is actually displayed or not, it's ;
  • there's a callback designed to change the text of a menu choices, it's ;
  • If you want to change the behavior of a menu, either edit the "choice" screen, define your own "choice" screen that you'll put in a file proceeded after "screen.rpy", or use , coupled to renpy.get_menu_args() (undocumented), to force the value of the "screen" . Be noted that from store.menu you can also change the menu choices ;
  • If you want to address a variable from a function, using the store. prefix is enough ;
  • The RestartTopContext exception do not do what you think. It will abruptly quit all context until it reach the main one, then reset the game by proceeding again the default statements, and finally continue with the next entry in the context without having a single moment proceeded again the actual entry ;
  • When you need to really force Ren'Py to restart what he just did, it's that is designed for this.

[mode: OFF by now I need some...]
 
  • Like
Reactions: ZLZK

ZLZK

Member
Modder
Jul 2, 2017
295
794
Except that you absolutely don't need to be in the main menu to change a setting. In fact, passing by the main menu is the most complicated way to change a setting, precisely because of the context issue.
Even if not I would still prefer to.

As I already said, you don't need to force Ren'Py to redraw the screen when returning from the game menu, because it do it automatically, period.
It does not or it's redrawing with old values.

  • There's a function designed to see if a given screen is actually displayed or not, it's ;
I have read about this function in doc already many times.

  • there's a callback designed to change the text of a menu choices, it's ;
I didn't know about it, but I don't want to compare text in every menu, I just want to edit certain menus.

  • If you want to change the behavior of a menu, either edit the "choice" screen, define your own "choice" screen that you'll put in a file proceeded after "screen.rpy", or use , coupled to renpy.get_menu_args() (undocumented), to force the value of the "screen" . Be noted that from store.menu you can also change the menu choices ;
Actually I have recently edited menu function for it to be able to display information about hidden choices.
Combined with config.menu_include_disabled hidden choices now display its condition too.
I would like too see how others accomplished it.

  • If you want to address a variable from a function, using the store. prefix is enough ;
I just wanted to be safe.

  • The RestartTopContext exception do not do what you think. It will abruptly quit all context until it reach the main one, then reset the game by proceeding again the default statements, and finally continue with the next entry in the context without having a single moment proceeded again the actual entry ;
I know what it does, I just can't extract the part I want from it.
Same with closing console, I can't find what causes an update.

  • When you need to really force Ren'Py to restart what he just did, it's that is designed for this.
I don't think it works for screens that aren't itself.
I need something like RestartStatement().
But this is just Rollback and RollForward, which means it erases changes.
And it doesn't even seems to work. I didn't used it corectly...
So this works great for variables that aren't affected by Rollback.
And it even supports game_menu, because it's Deferred Rollback.


So like the doc has said it, I would like to have a function that:
"re-run the current statement"
But the one that doesn't rely on rollback.
 
Last edited:

ZLZK

Member
Modder
Jul 2, 2017
295
794
But on a purely practical level... can't you just see the dialogue -> rollback a line or two -> enter the game menu -> change the value of the variable -> return back to the game and then continue one or two lines to the original dialogue (but now with the updated value)?
RestartStatement() does opposite of it.
I tried doing it some time ago,
but I didn't manage to make working function that RollForward into unseen content.


So for menus RestartStatement() does the trick.
I forgot about this solution, because it didn't work for variables.


I will just come clean what I'm doing, because there might be already solution to it.
My button in game_menu changes Player name, but when returning from game_menu,
Statement Say still displays old Player name.
Maybe this doesn't bother you, but I can't leave it alone.
Even more so when changing Player name in console doesn't have this issue.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
It does not or it's redrawing with old values.
I can assure you that it do it.
The problem do not lie on what Ren'Py is doing, but on what you want it to do, and they are two different things. Your problem can not be solved by a redrawing of the screen, because it's not where it lie.


I have read about this function in doc already many times.
Then why using an over complex procedure that offer absolutely no guaranty of constancy in time, and will possibly make you miss some menus ?


I didn't know about it, but I don't want to compare text in every menu, I just want to edit certain menus.
Yet the code you shown proceed every menu, and could perfectly be embedded in the "choice" screen ; "choice" screen that, like I said, can perfectly be redefined without editing the original code.

This said, there's ways to fix this problem ; from config.label_callback (to know in what label you are) to renpy.get_filename_line() (to know where you are in the code), passing by config.label_overrides (to enable/disable the replacement). There's even many threads here explaining all this.


I know what it does, I just can't extract the part I want from it.
execution.py:run_context()
Code:
    while True:
        try:
            [...]
        except renpy.game.RestartContext as e:
            renpy.exports.execute_default_statement(False)
            continue

        except renpy.game.RestartTopContext as e:
            if top:
                renpy.exports.execute_default_statement(False)
                continue
            else:
                raise
It's the only place where the exception is used, and not only there's clearly nothing to extract from the exception, but it also clearly do the exact opposite of what you want to achieve, since it pass to the next statement.
Are you really sure that you know what the RestartTopContext exception is doing ?


Same with closing console, I can't find what causes an update.
I said it, the context. The console operate in the same context than the game, while the main menu operate two context above it. This have an impact in the interaction since its own context have changed.


So like the doc has said it, I would like to have a function that:
"re-run the current statement"
But the one that doesn't rely on rollback.
I'll give you a hint: the answer is in your screen... No, really, you have the answer right in front of your eyes since the starts.


My button in game_menu changes Player name,
What absolutely don't have its place in the main menu since it regard the current playthrough and not the global state of the game.
But let's say it does have its place in the main menu:
/!\ Wrote on the fly and it's way past midnight here /!\
Python:
init python:
    if persistent.mcName is None:
        persistent.mcName = "default"

    config.label_overrides["start"] = "myStart"
    config.label_overrides["realStart"] = "start"
    config.label_overrides["after_load"] = "myAfterLoad"
    config.label_overrides["realAfterLoad"] = "after_load"

label myStart:
    $ mc.name = "[persistent.mcName]"
    jump realStart

label myAfterLoad:
    if mc.name != "[persistent.mcName]":
        $ mc.name = "[persistent.mcName]"
    jump realAfterLoad

screen game_menu():
    [...]
    textbutton "change MC name":
        action Show( "mcName" )
    [...]

screen mcName():
    modal True
    input value  FieldInputValue( persistent, "mcName")

    textbutton "cancel" action Hide( "mcName" )
    textbutton "validate" action RestartStatement()
Yeah, I know, not long ago I said that persistent values for this... And it still stand, but well...
 
Last edited:

ZLZK

Member
Modder
Jul 2, 2017
295
794
Then why using an over complex procedure that offer absolutely no guaranty of constancy in time, and will possibly make you miss some menus ?
[...]
Yet the code you shown proceed every menu, and could perfectly be embedded in the "choice" screen ; "choice" screen that, like I said, can perfectly be redefined without editing the original code.
This was just example, to try out menus from game in gui.
It only applies to current menu.
It had to be done this way, because my tool operates on nodes too.
I'm thinking of making gui version of my tool.
I mean editing current menus and generating file with changes for not gui version.

It's the only place where the exception is used, and not only there's clearly nothing to extract from the exception, but it also clearly do the exact opposite of what you want to achieve, since it pass to the next statement.
Are you really sure that you know what the RestartTopContext exception is doing ?
It doesn't go to the next statement, it reenters current one.

I said it, the context. The console operate in the same context than the game, while the main menu operate two context above it. This have an impact in the interaction since its own context have changed.
It does not. renpy.call_in_new_context("_console")

What absolutely don't have its place in the main menu since it regard the current playthrough and not the global state of the game.
I have it in my gallery unlocker, seems to fits its place.


Since my current project(another mod) operates on persistent variables.
Action RestartStatement() is good enough for now.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
It does not. renpy.call_in_new_context("_console")
It does, type renpy.context_nesting_level() from the console...
Yeah, Ren'Py is a bit more complex to understand than it looks.
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
It does, type renpy.context_nesting_level() from the console...
Yeah, Ren'Py is a bit more complex to understand than it looks.
Actually this is what is giving me troubles.
Because main context becomes console, and you can't access main context anymore.
That's why I did this code $ node = renpy.game.script.namemap.get(renpy.game.context().current, None)
in screen, because I couldn't get it to work from console.
But even in screen it gives me troubles.
Because variable is set in next node instead of current one.

I just wanted to access nodes on screen from console to try things out in game instead of files.
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
I figured out how console does that.
For example we are in statement B.
When we open console it's actually Rollbacking to statement A.
And when we close console return statement calls next node which is ours statement B.
That's why I was confused that it does updating.

So what I want is to be able to Rollback TopContext from SubContext.
Because RestartStatement() does Rollbacking after changes,
causing changes to be lost if they weren't persistent.
So I need to rollback before changes.
I'm almost there. :D
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
Today I have again tried to make it happen.
After hours without any progress I almost given up.
But then after reading for an nth time description of Rollback,
I knew then that that's what I was looking for.

Solution is really simple. I'm surprised that no one helped me with a right direction.
I was only able to make it because I didn't ignore console behavior and learned from it.
So now I was able to recreate it.

You don't have permission to view the spoiler content. Log in or register now.

So thanks, but no thanks.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
Solution is really simple. I'm surprised that no one helped me with a right direction.
I told you that the solution was right under your nose, and you finally found one of them... Because yes, there's others solutions. Like by example doing exactly what you asked for at first, forcing the current statement to play again: renpy.game.script.namemap.get(renpy.game.context().current, None)()

You past your time discarding what was said because you're stubborn and absolutely want it done your way ; while saying yourself that it's a half working way with some issues. Don't be surprised that people don't put more efforts in their answers. Especially since what you asked for was a fix for an issue that you shouldn't have had in the first place.


"There is nothing so useless as doing efficiently that which should not be done at all." –
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
I told you that the solution was right under your nose, and you finally found one of them... Because yes, there's others solutions. Like by example doing exactly what you asked for at first, forcing the current statement to play again: renpy.game.script.namemap.get(renpy.game.context().current, None)()
[...]renpy.game.script.namemap.get(renpy.game.contexts[0].current, None)()
TypeError: 'Say' object is not callable

You past your time discarding what was said because you're stubborn and absolutely want it done your way ; while saying yourself that it's a half working way with some issues. Don't be surprised that people don't put more efforts in their answers. Especially since what you asked for was a fix for an issue that you shouldn't have had in the first place.
Actually I don't like My Rollback solution.

Calling Rollback without .complete() doesn't erase changes.
But Ren'Py says that it must always be called before Rollback.

So raise renpy.game.RestartTopContext() is better and even Rollback uses it.
But when I use it all extra screens disappears.
I mean quick_menu and overlays.
Contrary to it Rollback doesn't hide overlays when I'm doing my function call.

action Call("label", from_current=True) does exactly what I want.
But doesn't work from game_menu.
Also renpy.call("_console_return, from_current=True) called after leaving game_menu works too.
But I don't know how to call it after closing game_menu.


So after all this I can say it's Ren'Py limitation.
And I should wait till they make it.

Because I don't have any idea how to correct any of my solutions.
I mean how to:

1. Show/Hide overlays.

2. Make exception in a main context not in a sub context.
Or how to to quit sub context and call function from main context.
(This seems to be impossible, because the moment you leave sub context-
rest of the function is not called or called before leaving.)

3. Make a callback after leaving game_menu.


Anyway I shouldn't even have to do it,
If Ren'Py would support any of it.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
[...]renpy.game.script.namemap.get(renpy.game.contexts[0].current, None)()
TypeError: 'Say' object is not callable
Think...
When it come to move so dirty, I give hints, not answers. If you've the knowledge to follow the lead, good for you. And if you don't, then it mean that you shouldn't even have tried.


So after all this I can say it's Ren'Py limitation.
No, it's your approach limitation. Ren'Py is as much as fault here than a car would be if it sink when someone try to drive it on the ocean.
Since years there's thousands of games and mods that do what you want to achieve. They are doing it following Ren'Py behavior and it works. You are trying to do it forcing Ren'Py behavior, and it don't works... I'm sure that there's some wisdom behind this difference.


Because I don't have any idea how to correct any of my solutions.
I mean how to:

1. Show/Hide overlays.
The suppress_overlay boolean.


Or how to to quit sub context and call function from main context.
(This seems to be impossible, because the moment you leave sub context-
rest of the function is not called or called before leaving.)
It's totally possible, config.periodic_callbacks list and either len( renpy.context ) or renpy.context_nesting_level().


3. Make a callback after leaving game_menu.
on screen statement, or dirtily config.label_overrides["_game_menu"].


Anyway I shouldn't even have to do it,
If Ren'Py would support any of it.
Or if you weren't so stubborn.
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
on screen statement,
It calls before leaving, so it's not main context yet.

I started this thread because I'm not knowledgeable enough.
What I'm stubborn with? I am just looking for any working solution.

Ren'Py Exceptions are there to be used, it is not dirty or forcible.

suppress_overlay enlightened me what was wrong.

So raise renpy.game.RestartTopContext() is valid approach.
I just didn't reverse changes made by opening game_menu.
From function _enter_menu().
I didn't even think that I have to close game_menu myself, before using it.
Anyway I cannot find out what changes are made when game_menu is closing.
Because it seems that it is reversed by Rollback.

Python:
try:
    renpy.store.suppress_overlay = False
    raise renpy.game.RestartTopContext()
finally:
    renpy.game_menu("screen_name")
This code looks promising now.
But what else should I change before Restart,
or what should I call before it?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
It calls before leaving, so it's not main context yet.
You asked for a way to have a callback when you quit a screen, it's the answer to this question.
As for the context related part, the answer was right above.


What I'm stubborn with? I am just looking for any working solution.
And not only you persist to search a solution that will fix the broken approach you refuse to quit, but you also persist in searching it where it don't lie.
Working solutions for what you want to do, you had more than one.But the fact is that they rely on something different than your approach, therefore you discard them. And this last post you wrote is the exact demonstration of this. To make a change coming from a upper context only apply when the player return to the main context, you need only two things, than I named in my previous answer. Yet you again wrote a whole monologue centered on the use of an exception that you have absolutely no reason to use.


Ren'Py Exceptions are there to be used, it is not dirty or forcible.
Ren'Py exceptions are part of the engine's core, and there's absolutely no reason to use them since the engine come with all the interface functions needed for that.
You can perfectly change a label by raising the JumpException exception, but why one would do this since there's a statement, a Python function and a screen action that do it, and more, for you ? And the same apply for the RestartTopContext exception.


suppress_overlay enlightened me what was wrong.
What the fuck are you talking about ?
You ask how to show/hide overlays, I give you the answer, period.


So raise renpy.game.RestartTopContext() is valid approach.
I just didn't reverse changes made by opening game_menu.
Is a valid approach that don't do what you want to do, and need many days of "tries and fail", effectively a valid approach ?
 

ZLZK

Member
Modder
Jul 2, 2017
295
794
You asked for a way to have a callback when you quit a screen, it's the answer to this question.
I meant after not before.
So I actually meant different thing.

As for the context related part, the answer was right above.
Do you think checking something 20 times per second that you may not even have a use for,
is a good way of doing things?

And not only you persist to search a solution that will fix the broken approach you refuse to quit, but you also persist in searching it where it don't lie.
Working solutions for what you want to do, you had more than one.But the fact is that they rely on something different than your approach, therefore you discard them. And this last post you wrote is the exact demonstration of this. To make a change coming from a upper context only apply when the player return to the main context, you need only two things, than I named in my previous answer. Yet you again wrote a whole monologue centered on the use of an exception that you have absolutely no reason to use.
What do I refuse to quit?
I researched every option, even stated results up there.
And now I end up nowhere.
Meaning I quit everything.
Because nothing works to the fullest.
And I don't know how to progress any further.

Ren'Py exceptions are part of the engine's core, and there's absolutely no reason to use them since the engine come with all the interface functions needed for that.
You can perfectly change a label by raising the JumpException exception, but why one would do this since there's a statement, a Python function and a screen action that do it, and more, for you ? And the same apply for the RestartTopContext exception.
Are you not aware?
Exception is direct way to change things.
Because everything mentioned up end up doing Exception anyway.
It's like me writing function or statement that would use Exception in it and then use it myself.
It's just a shortcut I can chose to take/do later on, for now I have no need for it.

What the fuck are you talking about ?
You ask how to show/hide overlays, I give you the answer, period.
I'm talking about game_menu. When you open it it sets suppress_overlay to True,
and when I raise Exception there is nothing that changes it back.

Is a valid approach that don't do what you want to do, and need many days of "tries and fail", effectively a valid approach ?
I just need to reverse changes from opening game_menu.
Or to learn how to properly rollback game_menu.

And since now that I know why overlays are displayed when I was using Rollback solution.
Because Rollback returns to main context and so overlays too.
So I just need to disable overlays for my function, and I would be fine.
And quitting game_menu is done by Rollback anyway.
And rollback is also using RestartTopContext.

The only difference between my approach and Ren'Py mechanics-
is that that I don't change crucial variables to the game at the right time.
Because I didn't even know that I have to change anything.

So I will later work on on my own invoke_in_new_context function,
that will meet my demands.
Because it is surprising to me that overlays aren't disabled in it.
I was confused that it was doing it, but it was the game_menu that was doing it.
So just like game_menu I just need to set up things before calling my function,
and then undo it or use rollback if possible.


But I may not even do it anyway, because I had enough of this.
For such trivial thing to move mountains and rivers and the result isn't even good.
I just don't feel like I need it anymore.
Now I can live without it without any regret.
It was small detail anyway, without much use.
Gonna take my time and use it on something useful that I didn't finish yet.

And anyway why should I be doing it in the first place when you said others did it already?
The reason of this thread was to get finished method of this.
No matter what I do, it will have bigger flaws, because I'm not experienced enough.
I'm not developing engine I'm using it.
It's like asking players to fix themselves the game they are playing.
If no one wants to share his solution to this it's fine.
I just won't be using mine when it can endanger the game.
Risks are absurd and benefits are almost none.
I wanted efficient way, no efficient way no way it is.