Ren'Py How to change main menu screen according to player's choice through the game?

ZaWarudo

Newbie
Apr 5, 2021
69
212
So basically i am planning to highlight characters on the main menu according to their love , hate, slave or whatever meters. Let's say if the love is above 5 for a certain character after a certain event their picture on the main menu screen should change to a different one. How can i achieve this? Thanks.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,374
15,286
So basically i am planning to highlight characters on the main menu according to their love , hate, slave or whatever meters. Let's say if the love is above 5 for a certain character after a certain event their picture on the main menu screen should change to a different one. How can i achieve this? Thanks.
Wow... Short answer: you just can't.

Think about it, you want to adapt an image shown only before the game start, accordingly to what happen once the game is started... This is just as impossible than reaching your destination before you started to move.

Of course, some can answer "use a persistent value".
They wouldn't be wrong, since persistent values are known before the game effectively starts. But this is only viable if you are sure at 100000000% that not a single player will have two parallels plays. Else, at best you'll have a value that isn't accurate (you only update the persistent when a save happen), or at worse you'll just break your game (you use the persistent value in game).


This being said, if you don't talk about the main menu image, but the system menu background (the image you see as background when you load, save, and all), then it's different.
You need to edit the "game_menu" screen, in order to change the way it deal with this background:
Code:
screen game_menu(title, scroll=None):

    style_prefix "game_menu"

    if main_menu:
        add gui.main_menu_background
    else:
        add gui.game_menu_background

    frame:
        style "game_menu_outer_frame"
[...]
It's the part after the add gui.game_menu_background that need to be changed.
And here there's many way to do.

The easiest one if probably to rely a displayable of sprites.
Code:
image girl1InBackground = ConditionSwitch(
         "love > 5", "images/background/girl1/whatever1.png",
         "love > 10", "images/background/girl1/whatever2.png",
         "True", "images/background/girl1/whatever.png" )

image girl2InBackground = ConditionSwitch(
         "love > 5", "images/background/girl2/whatever1.png",
         "love > 10", "images/background/girl2/whatever2.png",
         "True", "images/background/girl2/whatever.png" )

image systemBackground = Composite(
         ( 1920, 1080 ),
         ( 0, 0 ), "girl1InBackgdound",
         ( 0 , 200), "girl2InBackground" )

screen game_menu(title, scroll=None):

    style_prefix "game_menu"

    if main_menu:
        add gui.main_menu_background
    else:
        add "systemBackground"

    frame:
        style "game_menu_outer_frame"
[...]
You can probably even go deeper:
Code:
image girl1InBackgroundLove = ConditionSwitch(
         "love > 5", "images/background/girl1/whateverLove1.png",
         "love > 10", "images/background/girl1/whateverLove2.png",
         "True", "images/background/girl1/whateverLove.png" )

image girl1InBackgroundLust = ConditionSwitch(
         "lust > 5", "images/background/girl1/whateverLust1.png",
         "lust > 10", "images/background/girl1/whateverLust2.png",
         "True", "images/background/girl1/whateverLust.png" )

image girl1InBackground = ConditionSwitch(
         "love > Lust", "girl1InBackgroundLove",
         "love < Lust", "girl1InBackgroundLust",
         "True", "images/background/girl1/whateverDefault.png" )
 
Last edited:

LightmanP

Well-Known Member
Modder
Game Developer
Oct 5, 2020
1,672
15,510
They wouldn't be wrong, since persistent values are known before the game effectively starts. But this is only viable if you are sure at 100000000% that not a single player will have two parallels plays. Else, at best you'll have a value that isn't accurate (you only update the persistent when a save happen), or at worse you'll just break your game (you use the persistent value in game).
They could reset those persistent variables at some point after the start of the game for a new playthrough, but yeah, this obviously wouldn't be perfect.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,374
15,286
They could reset those persistent variables at some point after the start of the game for a new playthrough, but yeah, this obviously wouldn't be perfect.
The reset would works only in case of restart. But in case of parallel play you are doomed.

There's a game like that, that use a persistent value for the nickname gave to some of the girls.
By itself the idea could be interesting since you can restart the game and have the previously used nickname come as default option ; well, the game messed since it reset the value before asking for your input, but it's a detail.
The problem is that you can be dominant, lover or submissive, and obviously the nickname you'll use during the dominant play are more like "slut", "dirty whore" and things like that. Then you save your progression, load the submissive play, and... well, "fuck meat" don't fit well as nickname for your mistress...

And nowadays games tend to have at least two possible routes, what mean for many players two parallels playthrough.
You'll start following the corruption route, reaching 10 corruptions points, save and starts the lover route. It's good, the value is reset, you start with 0 corruption points, and save at the end of the update, with 10 love points.
The next update come, you load your save for the corruption route and... discover that you've 0 corruption points and 10 love points. You think you messed your save, an restart this route. At the end of the update you save when you've 20 corruption points, and load your lover route, that will have 20 corruption points and 0 love points... This time you're sure, the game is a mess and use persistent values.
 

ZaWarudo

Newbie
Apr 5, 2021
69
212
This being said, if you don't talk about the main menu image, but the system menu background (the image you see as background when you load, save, and all), then it's different.
You need to edit the "game_menu" screen, in order to change the way it deal with this background:

It's the part after the add gui.game_menu_background that need to be changed.
And here there's many way to do.

The easiest one if probably to rely a displayable of sprites.
To be perfectly honest, i didn't understand what you meant in the first place but after reading the second part, i can say that i was actually talking about here. So i guess i was talking about game menu screen. I am terribly sorry, i am still new to terminology. here.png

So after reading your comment, i guess i can still do it. I am still not sure what you meant but after trying the values you talked about i'll update here. Thanks!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,582
2,220
To be perfectly honest, i didn't understand what you meant [...]

Your main problem is that all the variables that would keep track of how the player is doing are not available at the point the main main is shown. (There are two similar menus "main_menu" and "game_menu"... game menu is the one you see when you're in the middle of a game, the main menu is the one you see before you start).

There is something called variables. They exist outside of the main game-play loop. They are not part of the save game files... they are entirely separate. Think of them as "per game" group of variables rather than a "per play through" group of variables. They "persist" through pretty much anything the player does.

So imagine you have a two variables "var_a" (normal) and "var_b" (persistent). When you start a game for the first time, let's say they both start as 0. The player plays for a bit and both var_a and var_b end up being 6.
The player (for whatever reason) starts a new game. While var_a is reset back to 0, var_b is still 6.

This behavior is great for certain things. The game's volume for one example.

And it might work for what you have planned. Have the values stored in persistent variables and use those persistent variables on the main menu to change the pictures you wish to show.

One solution is to reset the persistent variables you want to use for the main menu each time you start a new game too. But...

The problem Anne wants to highlight is when a player is playing two (or more) routes through the game simultaneously.

The player starts the game for the first time with a character called "Bob".
"Bob" plays for a while and var_b ends up being 4.

The player then restarts the game with a new character "Bob2".
Because you've coded it that way... var_b is reset to zero for BOTH "Bob2" and "Bob". Probably not what you had planned.

Now let's imagine var_b is tracking something common like "lust".
The player continues to alternate playing between "Bob" and "Bob2". Bob gains 10 lust points and Bob2 gain 12. var_b is now 22. Also, probably not what you had in mind.

If your game is focused on lifestyle, perhaps you have "Dominant" and "Submissive" variables... v_dom and v_sub. Imagine if your game stored these as persistent variables and game does "+1 dom and -1 sub" for a specific choice and "-1 dom and +1 sub" for the opposite choice. If a player were playing BOTH routes, alternating between saved games with each route... the values could all end up cancelling each other out and the values all being zero, because a choice made on one path reverses the choice made on the other path.


I think persistent is still the way to solve this. Though you need to plan ahead for crap like this.

One solution is to keep all the variable "normal" and each time you alter these variables... copy the value to a persistent variable of a similar name. Then use the persistent variable on the main menu.
It will mean that the menu will show pictures based on the value of the latest playthrough - and for a lot of players, who only play a game once, this would be fine.
You'll also need to update "all" the persistent variables, even if you only change 1.. because otherwise you might end up with a really odd mix of values if the player is switching between two very different play-throughs.

Maybe something like:

Python:
default mc_love = 0
default mc_lust = 0
default e_love = 0
default e_lust = 0

default persistent.mc_love = 0
default persistent.mc_lust = 0
default persistent.e_love = 0
default persistent.e_lust = 0

init python:

    def update_persistent_variables():

        persistent.mc_love = store.mc_love
        persistent.mc_lust = store.mc_lust
        persistent.e_love = store.e_love
        persistent.e_lust = store.e_lust
        # etc, etc.

label start:

    "*** START ***"

    # later during the game...

    $ mc_lust += 1
    $ update_persistent_variables()

    # later....

    $ e_love += 1
    $ update_persistent_variables()

    # maybe even...

    $ mc_lust += 1
    $ e_love += 1
    $ update_persistent_variables()

    # and so on....

    "*** THE END ***"
    return

Then you just check the persistent variables when doing anything with main menu images.
btw. The store is just me being extra careful. "Normal" variables are kept in a store namespace.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,374
15,286
As usual, for precise and understandable explanation, wait for 79flavors ;)

You'll also need to update "all" the persistent variables, even if you only change 1.. because otherwise you might end up with a really odd mix of values if the player is switching between two very different play-throughs.
I present an alternative, .
Technically those callbacks are here to let the game, or a mod, add information to the JSON data that will be available before a saved file will be load. But what interest us here is that it will be called each time the player save the game. What mean that you don't need to update the persistent variables in real time, you can do it right before a save.
There's an issue it the player rely on the "save on quit" feature, but I'm not sure there's many people who know that it's a possibility. Anyway, in this case the value will just be a little out dated, since I presume that the player will still save time to time during his play.

Keeping your example:
Python:
init python:
    def mySaveJSONcallback( JSON ):
        persistent.mc_love = mc_love
        persistent.mc_lust = mc_lust
        persistent.e_love = e_love
        persistent.e_lust = e_lust

    config.save_json_callbacks.append( mySaveJSONcallback )
And that's all what is needed since it will be called automatically when a save happen.


There's also an approach I thought about, using a list for the persistent variables and an id-like value by playthrough.
Python:
init python:
    # Create if they don't exist
    if persistent.persistentNextRank is None:
        persistent.persistentNextRank = 0
    if persistent.nicknames is None:
        persistent.nicknames = []

#  The value being /default/ed, it will be saved and so unique for this playthrough.
default persistentRank = 0

label start:
    # Rank for this game is next available rank for all playthrough.
    $ persistentRank = persistent.persistentNextRank
    # Increase the next available rank for all playthrough.
    $ persistent.persistentNextRank += 1
    [...]
    $ persistent.nicknames[persitentRank] = renpy.input( "What nickname do you want to give her ?" )
    [...]
So, with parallel routes, persistent.nicknames[0] will be the nickname you chose during your first playthrough, while persistent.nicknames[1] will be the one you chose during the second playthrough, and so on.

There's not much interest in this, since it defeat the interest of the persistent store (value unique for a playthrough in a store used to store the value common for all playthrough), but I thought about it, and it's possible, so I present it.

Be also noted that, if it can be used for what OP want, there's still a problem: which "persistentRank" used for the main menu ?
Technically speaking all represent where the player was when he quit the game, but in the same time some can represent abandoned playthrough.
 
  • Like
Reactions: gojira667

kotte

Member
Feb 11, 2018
182
318
The use case for "showing the game's characters according to their meters on the Main menu" is probably just to get a nice feeling of immersion. Each time I go back to the game and start it, I see each character they way I have shaped them.

In this case, just showing the last saved value using anne's suggested save_json_callback is probably fine.
Each time I start the game while on the corruption route, I'll be seeing my corrupted friends on the Main menu.
When I switch to the love route, the first time I will still see corrupt characters, but next time I will see my sweet little angels.

I also imagine all sort's of fun easter eggs in the image! Let's say that Lil' Sis has found the machine gun in one playthrough. Showing her holding it on the Main menu screen would be a cool feature, don't you think?

Just out of curiosity I wonder, what other ways are there than using persistent variables?
What happens if you use renpy.newest_slot() to get the latest save and the load it expicitly using renpy.load(), in the code for the Main menu? Is it even possible, since the game isn't started yet?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,374
15,286
Just out of curiosity I wonder, what other ways are there than using persistent variables?
What happens if you use renpy.newest_slot() to get the latest save and the load it expicitly using renpy.load(), in the code for the Main menu? Is it even possible, since the game isn't started yet?
Don't remember its name, but there's a function that permit you to load the JSON file of whatever save file.
Therefore, coupling config.save_json_callbacks with it, you can achieve that without the need for a persistent value.
But it will still not solve the parallel route problem.

After, you can also assume that each save page is dedicated to a particular route and look at the newest save file in each. Then, just slide the main menu, first the girls as in the save from the first page, then the girls as in the save from the second page, and so on.
 
  • Like
Reactions: kotte

monksims

Active Member
Mar 17, 2019
510
536
I haven't had as much experience with Renpy than experts above but I've done some programming since the 1990s with a long break of 19 years. But here's my two cents how I might tackle this feature by keeping it as simple as possible:

If the image in the game menu would be the one with the highest priority, a persistent valueset would control how the background image was showed. Each playthrough would have its own "persistent" valueset in the save that could be loaded and set in the after_load label. That would mean that the main menu would use the valueset from the latest playthrough session, if the main menu image should utilise persistent values.

If I would have a changing main menu showing different images from all different playthroughs, I'd have to identify each playthrough in the start and have multiple persistent valuesets stored by the playthroughID (similar to Anne's example). The main menu could then have a carousel of images based of those valuesets. Edit: Renpy might be able add the name of slot into the image if the image was made dynamically and the valueset included the latest saveslot for the playthrough.
 
Last edited:
  • Red Heart
Reactions: ZaWarudo
Apr 24, 2020
192
257
The game Lab Rats 1 changes its game menu depending on your progress. The models change based on whenever new milestones are reached, but there is an option to switch models based on your own preference.

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

Obviously there's always going to be an issue with a more dynamic menu if a player keeps switching files, but I don't see a reason to dismiss such a feature based on that.
 
  • Red Heart
Reactions: ZaWarudo