Ren'Py Return from Call_screen [SOLVED]

JohnDupont

Active Member
Modder
May 26, 2017
792
2,655
Hello,

I'm modding a game. A screen is called: it shows multiple elements and hides went clicked.
Python:
call screen "screen"

screen "screen":
    "multiple elements"
    button action Return()
I want to modify the screen so it doesn't appear when in a replay like:
Python:
screen "screen":
    if _in_replay:
        "RETURN"
    else:
        "multiple elements"
        button action Return()
I'm not sure to understand how call_screen works and I can't find the solution.
I'm currently using a workaround with timer 0.1 action Return().
 

TearStar

Developer of Lesbian/Futa Games
Game Developer
Mar 12, 2018
511
1,064
If you scrollback it will always calls back the screen.

You can just easily see that is not possible (I know a workaround) since if you open console and do some cheats when you scroll back it will open the console again (reverting your cheats).

I guess it's got to do with it's assembly. There is a line of commands that is done. What python does is going to a sequential code like any other program do. But when you revert it's assembly (going backwards) it will see that you opened the console.

What you can do is actually BLOCK rollback. Looks like this.


Python:
default backToOrigin = False

screen something:
    "This is your screen"

label call_something:
    call something
    if backToOrigin: #_return == "prev" was in my code but I don't where it came from
        $ backToOrigin = False
        $ renpy.block_rollback()
        return

screen button_to_call_something():
    textbutton "Something" action [SetVariable("backToOrigin", True), Call("call_something")]
    #if it's not a textbutton you can just call call_something
I hope I get your meaning.

This way your assembly sequence will have a block_rollback(so you can't rollback before the CALL SOMETHING) this way.
If you want to COMPLETELY be able to rollback you can do this without showing this again is much-much harder.

You need to set up a 'flag' to jump backwards. But this isn't what Von Neumann architecture is designed for.

Question is: Do you want to be able rollback before you called that screen?


I help you figure out. But it's not designed for.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
9,949
14,548
I'm not sure to understand how call_screen works and I can't find the solution.
The problem isn't how called screen works, but how screen actions works and how a button handle the actions. In short, you can force a screen action to be played, but it will not solve the problem here, because the Return screen action is in fact just a Python return statement.

So, basically :

I'm currently using a workaround with timer 0.1 action Return().
It's the only effective works around for the way you want to do it. But as you probably discovered, it will flash the screen.
Code:
default inReplay = False

screen myCalled:
    use inReplay

    textbutton "Click me to continue":
        action Return()


screen inReplay():
    if inReplay is True:
        timer 0.001 action Return()

label start:

    call screen myCalled

    "All right, now let's say that we are in a replayed scene."
    $ inReplay = True

    call screen myCalled
    "You immediatly returned."
    return
The other solution is to condition the call of the screen :
Code:
default inReplay = False

screen myCalled:
    textbutton "Click me to continue":
        action Return()

label start:

    call screen myCalled

    "All right, now let's say that we are in a replayed scene."
    $ inReplay = True

    if inReplay is False:
        call screen myCalled
    "The screen wasn't even called."
    return

Now that all this is said, I have a question for you :
If the screen is displayed and the player asked to click somewhere, there's a reason. Why do you want to remove this from the replayed scene, and how will you know what the player want to see as action in the replayed scene ?
 
  • Like
Reactions: JohnDupont

JohnDupont

Active Member
Modder
May 26, 2017
792
2,655
The problem isn't how called screen works, but how screen actions works and how a button handle the actions. In short, you can force a screen action to be played, but it will not solve the problem here, because the Return screen action is in fact just a Python return statement.

So, basically :



It's the only effective works around for the way you want to do it. But as you probably discovered, it will flash the screen.
Code:
default inReplay = False

screen myCalled:
    use inReplay

    textbutton "Click me to continue":
        action Return()


screen inReplay():
    if inReplay is True:
        timer 0.001 action Return()

label start:

    call screen myCalled

    "All right, now let's say that we are in a replayed scene."
    $ inReplay = True

    call screen myCalled
    "You immediatly returned."
    return
The other solution is to condition the call of the screen :
Code:
default inReplay = False

screen myCalled:
    textbutton "Click me to continue":
        action Return()

label start:

    call screen myCalled

    "All right, now let's say that we are in a replayed scene."
    $ inReplay = True

    if inReplay is False:
        call screen myCalled
    "The screen wasn't even called."
    return

Now that all this is said, I have a question for you :
If the screen is displayed and the player asked to click somewhere, there's a reason. Why do you want to remove this from the replayed scene, and how will you know what the player want to see as action in the replayed scene ?
Thanks.

I still don't get how called screen works. I'm not certain to have a perfect understanding of what Ren'Py means by interaction or when call_screen is better than show_screen.
renpy.call_screen(_screen_name, *args, **kwargs)
The programmatic equivalent of the call screen statement.​

This shows _screen_name as a screen, then causes an interaction to occur. The screen is hidden at the end of the interaction, and the result of the interaction is returned.
Keyword arguments not beginning with _ are passed to the scope of the screen.​
If the keyword argument _with_none is false, "with None" is not run at the end of end of the interaction.​

But I guess that my workaround is the best solution in the end. The screen doesn't flash for the player because the visible elements aren't part of the if _in_replay condition.

As I said, I'm modding the game. Modifying the screen is much simpler than modifying all the call screen.

The why is this screen displays a stat change, which is useless in a replay.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
9,949
14,548
I still don't get how called screen works. I'm not certain to have a perfect understanding of what Ren'Py means by interaction or when call_screen is better than show_screen.
It's, relatively speaking, simple. If the game need to wait for an action coming from the player, then the screen must be called. And if the game don't need to wait, then it must be shown.
As for "interaction", it's way more complex since it's not even something constant. But basically, take it as the definition of the word itself. So, is an interaction every thing that need the player to do something ; take in count that he need to click to show the next dialog line.
 
  • Like
Reactions: JohnDupont

TearStar

Developer of Lesbian/Futa Games
Game Developer
Mar 12, 2018
511
1,064
I still don't get how called screen works. I'm not certain to have a perfect understanding of what Ren'Py means by interaction or when call_screen is better than show_screen.
CALL -> call means it has a return point.
JUMP -> if you jump somewhere there is no return point (address) so it exits instead.

Show is different in this case. Show is just "show an image". If you don't set modal screen you can click through the screen.
 
  • Like
Reactions: JohnDupont

JohnDupont

Active Member
Modder
May 26, 2017
792
2,655
If you scrollback it will always calls back the screen.

You can just easily see that is not possible (I know a workaround) since if you open console and do some cheats when you scroll back it will open the console again (reverting your cheats).

I guess it's got to do with it's assembly. There is a line of commands that is done. What python does is going to a sequential code like any other program do. But when you revert it's assembly (going backwards) it will see that you opened the console.

What you can do is actually BLOCK rollback. Looks like this.


Python:
default backToOrigin = False

screen something:
    "This is your screen"

label call_something:
    call something
    if backToOrigin: #_return == "prev" was in my code but I don't where it came from
        $ backToOrigin = False
        $ renpy.block_rollback()
        return

screen button_to_call_something():
    textbutton "Something" action [SetVariable("backToOrigin", True), Call("call_something")]
    #if it's not a textbutton you can just call call_something
I hope I get your meaning.

This way your assembly sequence will have a block_rollback(so you can't rollback before the CALL SOMETHING) this way.
If you want to COMPLETELY be able to rollback you can do this without showing this again is much-much harder.

You need to set up a 'flag' to jump backwards. But this isn't what Von Neumann architecture is designed for.

Question is: Do you want to be able rollback before you called that screen?

I help you figure out. But it's not designed for.
Sorry @TearStar, I didn't see your first post.
I'll test to see if the workaround cause a problem with rollback but since I don't want to modify the label, only the screen, so I'm quite limited in terms of solutions.

It's, relatively speaking, simple. If the game need to wait for an action coming from the player, then the screen must be called. And if the game don't need to wait, then it must be shown.
As for "interaction", it's way more complex since it's not even something constant. But basically, take it as the definition of the word itself. So, is an interaction every thing that need the player to do something ; take in count that he need to click to show the next dialog line.
CALL -> call means it has a return point.
JUMP -> if you jump somewhere there is no return point (address) so it exits instead.

Show is different in this case. Show is just "show an image". If you don't set modal screen you can click through the screen.
I tried as a solution and it would return to the last called label. So I assumed that the Call and Return function didn't work the same way for screens and labels.
I also tried but I didn't get what I could expect from reading the "definition" of Call_screen: end the interaction, therefore hide the called screen then return to the label. I'm not sure I understand what this function does or what interaction means in the definition of Call_screen.

Anyway, my understanding was:
Call_screen allows you to stop in the middle of a label and jump back to where you were after you're done with the screen. It's usefull for in-game menus. You can leave the screen with Jump, Call (I'm assuming, I don't think I ever tried) or Return.
Show_screen allows to show a displayable and still keep going with the label. You can hide the screen with Hide.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
9,949
14,548
CALL -> call means it has a return point.
JUMP -> if you jump somewhere there is no return point (address) so it exits instead.

Show is different in this case. Show is just "show an image". If you don't set modal screen you can click through the screen.
Sorry but, while you're right in your definition for "call" and "jump" as control flow statement, these definition do not apply to screen ; not even the one for "call".

As I said, the difference is that a called screen will wait for the player ; or more precisely wait for a Return screen action to be triggered. This will a shown screen will return immediately.
But at no time a return point exist, because at no time the code goes out of its flow ; this unless you explicitly goes out of the flow, either with a "Jump" or a "Call" screen action.

It can be easily demonstrated :
Code:
screen ctrl:
    $ d = renpy.call_stack_depth()
    text "Number of return point(s) [d]"

screen myCalled:
    textbutton "click me" xalign 0.5 yalign 0.5 action Return()

label start:

    show screen ctrl

    "You start with no return point, logical."
    call myCalled
    'You "used" this return point.'
    "But, look at the value when you call a screen."
    call screen myCalled
    "See, no return point was created."
    return

label myCalled:
    "You added a return point in the stack."
    return

So I assumed that the Call and Return function didn't work the same way for screens and labels.
You assumed correctly. The statement is named "call screen" because the screen is intended to return a value, not because the statement itself will sent you out of the code's flow.

I also tried
Didn't thought about this. Here's the code to use it :

Code:
init python:
     # Create a custom displayable
     class InReplayReturn(renpy.Displayable):

        # Automatically called by Ren'py to render the displayable
        def render(self, width, height, st, at):
            # If it's in replay, end the interaction, that will force the return.
            # Else, return a 0 sized empty zone to not alter the screen.
            return renpy.end_interaction( True ) if store.inReplay is True else renpy.Render(0, 0)

default inReplay = False

screen myCalled:
    add InReplayReturn()

    textbutton "click me" xalign 0.5 yalign 0.5 action Return()

label start:
    "Regular use."
    call screen myCalled

    $ inReplay = True
    "In Replay use."
    call screen myCalled
    "It returned immediatly."
    return