Passing variable value from new "context" back to main game? [SOLVED]

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
I am trying to implement allowing the player to turn off some sounds in my game through a screen accessed by pressing a particular keystroke ("b" here).
For this I use the following init block:

Python:
init python:

    def show_mccumsound_menu():
        renpy.call("Mccumsound")
    config.keymap["open_mccumsound_menu"] = ["b"]

    # When key is pressed at anytime, open custom screen.
    config.underlay.append(renpy.Keymap(open_mccumsound_menu=show_mccumsound_menu))
which therefore calls the following label which is a screen with just two images to press to turn on or off these sounds, leading to the variable cumsoundon being True or False:

Python:
label Mccumsound:
call screen mcchoosesound
screen mcchoosesound:
    modal True
    imagebutton:
        focus_mask True
        idle "v07/mcsoundon.png"
        hover "v07/mcsoundon.png"
        action [SetVariable("cumsoundon", True), Hide("mcchoosesound"), Return]
    imagebutton:
        focus_mask True
        idle "v07/mcsoundoff.png"
        hover "v07/mcsoundoff.png"
        action [SetVariable("cumsoundon", False), Hide("mcchoosesound"), Return]
It works, but my issue is that it moves down one stack at the end on "Return", because it is not a call to a new "context".

But if, instead I use:

Python:
init python:
    def show_mccumsound_menu():
        renpy.call_in_new_context("Mccumsound")
    config.keymap["open_mccumsound_menu"] = ["b"]
The setting of the variable "cumsoundon" to True or False is not passed back to the game. Therefore, I am in a bit of a conundrum and was wondering if there was a way around this if anyone knows?
 

sillyrobot

Engaged Member
Apr 22, 2019
2,041
1,809
I'm becoming slightly interested in ren'py but am by no means passable let alone an expert.

In your first example, should the screen be inside the label?

Shouldn't it be more like

Code:
screen screenname:
    <screen def>


label labelname:
    call screen screenname
    return (which AFIAIK is optional)
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
I'm becoming slightly interested in ren'py but am by no means passable let alone an expert.

In your first example, should the screen be inside the label?

Shouldn't it be more like

Code:
screen screenname:
    <screen def>


label labelname:
    call screen screenname
    return (which AFIAIK is optional)
Hi there, I don' t think this is the issue here, everything works, and there is no "bug". It's just that I want to be able to call that label in a new context while retaining the value re-assigned to a variable within that context when returning back to the main game context and I have failed to find out how to do that so far.
But maybe I'm wrong of course...
PS: also, to clarify, the return is not optional because the player has to press on of either two buttons, and both have a return call.
 

sillyrobot

Engaged Member
Apr 22, 2019
2,041
1,809
Hi there, I don' t think this is the issue here, everything works, and there is no "bug". It's just that I want to be able to call that label in a new context while retaining the value re-assigned to a variable within that context when returning back to the main game context and I have failed to find out how to do that so far.
But maybe I'm wrong of course...
You can always find the variable in the store. From what I recall, screens are one of the few areas where variables are localised. But something like

$store.variablename = newValue

should work.


I think it'll cause other problems though. Screens get "run" multiple times.
 

sillyrobot

Engaged Member
Apr 22, 2019
2,041
1,809
Glancing at the docs, "action SetVariable()" attached to a control is what you are looking for.
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Glancing at the docs, "action SetVariable()" attached to a control is what you are looking for.
Ok, thanks, what exactly do you mean by "attached to a control" please? I suck at Ren'py...
 

sillyrobot

Engaged Member
Apr 22, 2019
2,041
1,809
Ok, thanks, what exactly do you mean by "attached to a control" please? I suck at Ren'py...
Looking at your screen code, you are already using it in your imagebutton control. It suggest changing "SetVariable("cumsoundon", True)" to ""SetVariable("store.cumsoundon", True). That should skip contexts and get back to the main data store.

I'm unsure why you want a new context -- it seems meant to support calling one interactive screen while in another to prevent actions taken in the second from affecting the first.
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Looking at your screen code, you are already using it in your imagebutton control. It suggest changing "SetVariable("cumsoundon", True)" to ""SetVariable("store.cumsoundon", True). That should skip contexts and get back to the main data store.

I'm unsure why you want a new context -- it seems meant to support calling one interactive screen while in another to prevent actions taken in the second from affecting the first.
Thanks, I'll try that and let you know.
I want to call a new context because I noticed that otherwise it moves down one line of script upon return. If the player is in the middle of a choice menu, that could be a nuisance...
EDIT: I tried and I'm sorry to report that it didn't work. Still would not pass that variable's value to the main game upon return...
RE-EDIT: does that variable also need to be defined in a particular way now? Right now it's just default cumsoundon = True for example.
 

sillyrobot

Engaged Member
Apr 22, 2019
2,041
1,809
Thanks, I'll try that and let you know.
I want to call a new context because I noticed that otherwise it moves down one line of script upon return. If the player is in the middle of a choice menu, that could be a nuisance...
EDIT: I tried and I'm sorry to report that it didn't work. Still would not pass that variable's value to the main game upon return...
RE-EDIT: does that variable also need to be defined in a particular way now? Right now it's just default cumsoundon = True for example.
Default should be fine. I don't think I grok 'down one line of script' though.

You may have to wait from someone who actually codes in ren'py for help, I'm afraid.
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Default should be fine. I don't think I grok 'down one line of script' though.
Well it does, I can assure you. At least in the Ren'py version I'm using (7.2.0) which, granted, isn't the latest version at all...
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,294
Python:
init python:
    def show_mccumsound_menu():
        renpy.call("Mccumsound")
Replace renpy.call("Mccumsound"), by , and get ride of the Mccumsound label.
 
  • Like
Reactions: EpicLust

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Replace renpy.call("Mccumsound"), by , and get ride of the Mccumsound label.
Thanks but then I'm running into an issue if I press "b" during a choice dialogue menu:

Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/newaliens.rpy", line 108, in script
    menu:
  File "game/script.rpy", line 18, in show_mccumsound_menu
    renpy.call_screen("mcchoosesound")
Exception: Cannot start an interaction in the middle of an interaction, without creating a new context.
EDIT; actually, I'm getting this error message all the time as soon as I press "b" actually, not just during a choice menu...
Re-edit, and if I change these lines, which I thought I had forgotten to change, the same thing happens.
Python:
init python:
    def show_mcchoosesound_menu():
        renpy.call_screen("mcchoosesound")
    config.keymap["open_mcchoosesound_menu"] = ["b"]

    # When key is pressed at anytime, open custom screen.
    config.underlay.append(renpy.Keymap(open_mcchoosesound_menu=show_mcchoosesound_menu))
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,294
Code:
Exception: Cannot start an interaction in the middle of an interaction, without creating a new context.
Try to put a renpy.restart_interaction() before you call the screen.

Or you can threat the screen as a menu through renpy.run( store.ShowMenu( "mcchoosesound" ) ) but it should fallback on the context problem.

Or just offer this choice directly in the "preferences" screen.

Or use a screen to trigger the opening of your menu:
Code:
screen UI:
    key "K_b" action Show( "mcchoosesound" )

label whatever:
    show screen UI
[/icode]
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Try to put a renpy.restart_interaction() before you call the screen.

Or you can threat the screen as a menu through renpy.run( store.ShowMenu( "mcchoosesound" ) ) but it should fallback on the context problem.

Or just offer this choice directly in the "preferences" screen.

Or use a screen to trigger the opening of your menu:
Code:
screen UI:
    key "K_b" action Show( "mcchoosesound" )

label whatever:
    show screen UI
[/icode]
Thanks for your answer, but where should I put the renpy.restart_interaction() bit please? In the init block? And where compared to my code? Because I fail to see how it would be read if I just put it before the actual screen in the code (since I presume pressing b would jump directly to the screen)
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,294
Thanks for your answer, but where should I put the renpy.restart_interaction() bit please?
Code:
init python:
    def show_mcchoosesound_menu():
        renpy.restart_interaction()
        renpy.call_screen("mcchoosesound")
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Code:
init python:
    def show_mcchoosesound_menu():
        renpy.restart_interaction()
        renpy.call_screen("mcchoosesound")
Nope sorry, still getting the same error message "Exception: Cannot start an interaction in the middle of an interaction, without creating a new context." unfortunately...
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,294
Nope sorry, still getting the same error message "Exception: Cannot start an interaction in the middle of an interaction, without creating a new context." unfortunately...
Well, I gave you three others ways... all anyways better than the one you're trying to follow.
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
Well, I gave you three others ways... all anyways better than the one you're trying to follow.
Yes you did and I thank you for that but you overestimate my Ren'py coding abilities...
I don't want to go through the preference screen because I don't want the player to "exit" the game, the screen with the two buttons is a transparent png and I'd like to keep it that way so the background picture is still visible.
Your last suggestion is intriguing but I don't understand the "label whatever". It seems like the screen would only be called at a particular point in the game? I'd like it to be at any point in the game. Also, where would I put those lines, in the main script or an init block?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,294
I don't want to go through the preference screen because I don't want the player to "exit" the game, the screen with the two buttons is a transparent png and I'd like to keep it that way so the background picture is still visible.
So you don't want the player to ever save the game ? Because there's absolutely no difference between the save/load screen and the preferences one.



Your last suggestion is intriguing but I don't understand the "label whatever". It seems like the screen would only be called at a particular point in the game?
A shown screen is hidden only if you explicitly ask for it to be hidden, or if a screen with the same tag is opened. Therefore, just show the screen at the start of the game, and it will be always present. And the only purpose of this screen is to open your sound menu if the given key is pressed.
 

EpicLust

Dev of Cockham Superheroes
Game Developer
May 30, 2017
3,779
7,198
So you don't want the player to ever save the game ? Because there's absolutely no difference between the save/load screen and the preferences one.





A shown screen is hidden only if you explicitly ask for it to be hidden, or if a screen with the same tag is opened. Therefore, just show the screen at the start of the game, and it will be always present. And the only purpose of this screen is to open your sound menu if the given key is pressed.
Ah yes, got it now, thanks a lot! That is indeed the simplest way to do it and I actually do have these kinds of "show screens" already in my script, but I didn't know about the "key" tag in a screen.
EDIT: actually, no, I get an error if the player is in the middle of a choice menu and also it still goes down one line in the script for some reason, so I'm kinda back to square one...

I have:
Python:
    screen soundcum():
        key "K_b" action Show( "mcchoosesound" )

    screen mcchoosesound:   
        modal True
        imagebutton:
            focus_mask True
            idle "v07/mcsoundon.png"
            hover "v07/mcsoundon.png"
            action [SetVariable("cumsoundon", True), Hide("mcchoosesound"), Return]
        imagebutton:
            focus_mask True
            idle "v07/mcsoundoff.png"
            hover "v07/mcsoundoff.png"
            action [SetVariable("cumsoundon", False), Hide("mcchoosesound"), Return]
and the show screen soundcum at the beginning of the game.
EDIT: to be honest, when I started this thread, I was hoping to be able to call my label in a "new context" (ie: the last bit of the code I wrote in the OP) and that the solution to my issue of the variable's value not being passed back to the main script was in the way I coded the screen mcchoosesound in that called label, something like it should be "SetGlobalVariable" instead of "SetVariable" (it's not that, I tried). I have other screens that I call in a new context so the stack doesn't go down a line when going back to the game (which is essential I think) but never had the issue because they were just showing stuff and not actually aimed at changing any variables.
But it seems my conundrum is much harder to resolve than I thought!
 
Last edited: