Setting _game_menu_screen dynamically

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
User avatar
plaster
Regular
Posts: 89
Joined: Thu Jul 11, 2013 1:03 am
Tumblr: plasterbrain
Soundcloud: plasterbrain
Location: Chicago
Contact:

Setting _game_menu_screen dynamically

#1 Post by plaster »

My game menu has four screens, which we'll call foo, bar, and baz. By default, _game_menu_screen is set to "foo", so hitting the menu key, X, or right-clicking will open foo.

If a player goes to any one of the other screens and then closes the menu from there, I would like to be change _game_menu_screen to the last screen they accessed. For example, if someone goes to bar, and then closes out of the in-game menu, the next time they press X, I would like to open bar instead of foo.

Doing this:

Code: Select all

screen foo():
    on "show" action SetVariable("_game_menu_screen", "foo")
    text "[_game_menu_screen]"
shows "foo" on the screen. But if config._game_menu_screen was set to "bar," _invoke_game_menu will open bar. If I set _game_menu_screen to "baz" within the actual game, the game menu will become baz, but foo will still show "foo" !

The difficulty is that the in-game menu is a different context than the game itself, right? I don't really understand contexts, call stacks, or store variables. I am hack-and-slashing my way through OOP tbh. pls help tho I'm out of ideas :[

User avatar
PyTom
Ren'Py Creator
Posts: 16093
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Setting _game_menu_screen dynamically

#2 Post by PyTom »

So, _game_menu_screen is, for a bunch of reasons, treated specially. Ren'Py makes it a dynamic variable when entering the the menus, and hence resets it to its own value when leaving.

To avoid it, avoid using _game_menu_screen entirely. Instead, intercept it at config.game_menu_action. My version is this, with a little bit of setup.

Code: Select all

default game_menu_screen = "save"

init python:

    class InvokeGameMenu(Action):

        def __call__(self):
            return renpy.run(ShowMenu(game_menu_screen))

    config.game_menu_action = InvokeGameMenu()
And then code like this in every screen.

Code: Select all

    on "show" action SetVariable("game_menu_screen", "save")
    on "replace" action SetVariable("game_menu_screen", "save")

You probably want to run on replace as well as show, so you get it triggered when changing screens. There's nothing special about the name game_menu_show, it just happens to be similar to _game_menu_show.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

User avatar
komehara
Regular
Posts: 36
Joined: Fri Jan 31, 2020 10:08 pm
Projects: Spirit Link
Tumblr: hsandt
Deviantart: hsandt
Github: hsandt
itch: komehara
Contact:

Re: Setting _game_menu_screen dynamically

#3 Post by komehara »

Interesting, I found a very similar code in an old game project but written differently, I can't remember if it was inspired by this thread of if I had found a similar solution on my own, which would explain the subtle differences in code. Anyway, the big difference is that I made it a Preference. In addition, today I copied the code to a new Renpy 8.1.3 project, it still works, and to make it work with the "Menu" button of the quick menu on touch device too, I had to change an extra line.

Equivalent of tom's code to define the custom action, but using a simple function:

Code: Select all

# options.rpy, e.g. after `default preferences.afm_time = 15`

# This is an alternative to "Setting _game_menu_screen dynamically"
# https://lemmasoft.renai.us/forums/viewtopic.php?t=44154
# which is a bit more lightweight in code

## Define a custom preference to decide which screen to show first in game menu,
## as _game_menu_screen cannot be reliably changed in the menu,
## This can be tweaked in the Preferences screen.
default preferences.game_menu_screen = "save_screen"

## Define a custom action to open game menu set in Preferences.
## To make sure we evaluate preferences.game_menu_screen at runtime, we use a function
## instead of creating an action on init. We still use ShowMenu's __call__
## for convenience (but we don't need predict, get_selected, get_sensitive for this quick action)
init -110 python:
    def show_pref_game_menu():
        ShowMenu(preferences.game_menu_screen)()

define config.game_menu_action = show_pref_game_menu
Preference to change the custom action behaviour:

Code: Select all

# screens.rpy
screen preferences():
    # ...
                ## Additional vboxes of type "radio_pref" or "check_pref" can be
                ## added here, to add additional creator-defined preferences.

                vbox:
                    style_prefix "radio"
                    label _("Default menu")
                    textbutton _("Save") action SetField(preferences, "game_menu_screen", "save_screen")
                    textbutton _("Preferences") action SetField(preferences, "game_menu_screen", "preferences_screen")

# and add this to make it work on touch devices
screen quick_menu():
    variant "touch"
    
    # ...
    
    if quick_menu:

        hbox:
            # ...
            
            # just add preferences.game_menu_screen argument here
            textbutton _("Menu") action ShowMenu(preferences.game_menu_screen)

Post Reply

Who is online

Users browsing this forum: AWizardWithWords, Bing [Bot], decocloud, piinkpuddiin, Semrush [Bot]