• To improve security, we will soon start forcing password resets for any account that uses a weak password on the next login. If you have a weak password or a defunct email, please update it now to prevent future disruption.

Ren'Py Replay and setting variables before starting game.

SnubbLR

Newbie
Game Developer
Sep 13, 2017
77
544
So I am making a replay/gallery function for my game. I've spent more than 6 hours on this small issue and finally had to cave in and ask for help.

I want the player to be able to toggle between scat and bestiality on and off before selecting a scene in the replay screen.

I managed to get bestiality toggle-able perfectly with this:

Python:
init python:
    gallery  = Gallery()

    gallery.button("black")
    gallery.image("black")


screen gal:
    tag menu


    textbutton _("Scat On") action ToggleVariable("scat", true_value=1, false_value=0):
        pos (700, 10)
    textbutton _("Scat Off") action ToggleVariable("scat", true_value=0, false_value=1):
        pos (700, 55)

    if persistent.patch_installed:
        textbutton _("Bestiality On") action [SetField(persistent, "patch_enabled", True), SelectedIf(persistent.patch_enabled)]:
            pos (960,10)
        textbutton _("Bestiality Off") action [SetField(persistent, "patch_enabled", False), SelectedIf(not persistent.patch_enabled)]:
            pos (960,55)

    vbox pos (153, 220):
        imagebutton:
            action Replay("alleyintro")
            idle Transform("alley/alley026.jpg", zoom=0.175)
            hover Transform("alley/alley026.jpg", zoom=0.2)
The scat portion does not work, and I know why. When Replay() kicks in, the default values are being used. In my case, scat is being controlled by a value (1 or 0, should have used True/False, sigh ), that is declared before my start label as scat = 0. Bestiality is being controlled by the patch and it works great for once.

I need to either toggle the default value to 1 somehow in my gallery screen, or I need to change persistent value to 1. I've tried so many things but keep getting errors.

I've tried defining scat like this
Python:
init python:
    gallery  = Gallery()

    gallery.button("black")
    gallery.image("black")

    if persistent.scat is None:
        persistent.scat = 0
and then
Python:
screen gal:
    tag menu

    textbutton _("Scat On") action ToggleField(persistent, 'scat', 1, 0):
        pos (1200,10)
And many other combinations, pretty much always ending up in some syntax errors or crashes.

Is there anyone who could help me figure out how to make scat toggled just like bestiality up above?

Also, if someone has an easy fix to make the player name transferable to the replays, that would be great too... That's next on my list and will probably also take another 6 hours...

I am extremely bad at coding... Thank you for your time . You guys are awesome
 

SnubbLR

Newbie
Game Developer
Sep 13, 2017
77
544
Ok so I got some help from Wildman in the F95 discord server. It get's the job done, but it will require me to do a lot of extra typing in all my scenes. But anyway, this is what I got so far. I use my original toggle switch


Python:
textbutton _("Scat On") action ToggleVariable("scat", true_value=1, false_value=0):
        pos (700, 10)
    textbutton _("Scat Off") action ToggleVariable("scat", true_value=0, false_value=1):
        pos (700, 55)
To set the variable on the Gallery screen. Then I use Scope

Code:
vbox pos (578, 650):
        imagebutton:
            if scat == 1:
                action Replay("store7", scope={"scat": 1})
            else:
                action Replay("store7")
            if scat == 0:
                idle Transform("store/st141.png", zoom=0.175)
                hover Transform("store/st141.png", zoom=0.2)
            else:
                idle Transform("store/st154.png", zoom=0.175)
                hover Transform("store/st154.png", zoom=0.2)
to start the replay either with scat on or off.

It would be nicer to have just the switch do the setting for me and then not have to add any extra code on each gallery button, but unless someone has a better idea, this is what I'll go with :)

Now I'll just figure out the name issue... I need to figure out how to save the name as a persistent.

Right now, this is the code I have in my game for naming oneself in the intro
Code:
$ y = renpy.input("Who am I? (if nothing is entered, I am Sebastian)")
    $ y = y.strip()
    if y == "":
        $ y = "Sebastian"
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,560
2,179
Another option to consider is using scope={} for .

It's not an obvious thing in the documentation, but scope={} allows you to pass a list of variables and their values into the replay. You essentially say "start the replay, with these variables set to these values".

You only need to include the variables used within the replay, so it shouldn't be too long a list.
It'll look something like : action Replay("day4_visit_the_museum", scope={"affection":1, "trust":300}.

While this example only passes strings, those same values could be persistent variables or config/preference stuff too.
action Replay("day4_visit_the_museum", scope={"affection":1, "trust":persistent.saved_trust}.

If you had a screen which triggered the replay, and on that screen you had a few textbuttons configured as Radio Buttons (see the standard preferences screen for examples) to pick the options - it might be a viable solution.

You can also use config.replay_scope which presets a list of variables to be used by any Replay(). Though obviously that has only limited use where you need differing values passed along.

As for the name issue, I might offer up the following example:

Python:
default persistent.latest_mcname = "Waldo"
default mc_name = "Unknown"

define mc = Character("[mc_name]", color="#FFFFFF", what_prefix='"', what_suffix='"')
define mc_t = Character("[mc_name]", what_prefix='{i}(', what_suffix='){/i}', what_color="#AAAAAA")

define narrator = Character('', what_color='#FFFF66')

label start:

    scene black with fade

    "Welcome to [config.name]."

    $ mc_name = renpy.input("What is your name? {i}(Press ENTER for [persistent.latest_mcname]){/i}", exclude="[]{}")
    $ mc_name = mc_name or [persistent.latest_mcname]
    $ persistent.latest_mcname = mc_name

    if _in_replay:
        $ mc_name = persistent.latest_mcname

    mc "Hi, my name is [mc]."
    mc_t "Your character is thinking."

    $ renpy.end_replay()

    return

Each time the player starts a new game, the name they pick is stored as a persistent variable. Next time they start a game, they are offered the same name as the default. The persistent value can also be used in the replay. The only time it gets a little odd is if you pick specific names when playing different "personas". Instead, you'll just get the latest name that was used instead of the right persona for the right combination of character traits.

Building upon the config.replay_scope, you could probably do away with the if _in_replay code by coding...
config.replay_scope = {"mc_name": persistent.latest_mcname}.

I don't think my examples fit exactly what you are aiming for, but they should give you enough to think about solve your own problems.
 
Last edited:
  • Like
Reactions: anne O'nymous

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,198
14,931
Python:
    textbutton _("Scat On") action ToggleVariable("scat", true_value=1, false_value=0):
        pos (700, 10)
    textbutton _("Scat Off") action ToggleVariable("scat", true_value=0, false_value=1):
        pos (700, 55)

    if persistent.patch_installed:
        textbutton _("Bestiality On") action [SetField(persistent, "patch_enabled", True), SelectedIf(persistent.patch_enabled)]:
            pos (960,10)
        textbutton _("Bestiality Off") action [SetField(persistent, "patch_enabled", False), SelectedIf(not persistent.patch_enabled)]:
            pos (960,55)
Wow, there's many things to say here:

Firstly, having two buttons that both toggle the same variable isn't right at all. If scat is off, clicking on the "scat off" button would turn it on.

Secondly, why are you using "1" and "0" as value for scat, and not just a boolean like for bestiality ?

Thirdly, why are you using a persistent value for the bestiality content, and not for the scat content ?
Side note: Due to the difference in context, there's 90% chance that it's the reason why the scat part don't works.

Fourthly, never ever use a persistent value to define if a patch is installed or not. The player can change his mind and remove the patch, or he can forget to install it with the new update. Then he would have absolutely no way to turn the flag off, what would then break the game.

Fifthly, the use of SelectedIf(persistent.patch_enabled) is outdated, there's now a selected property for the buttons.

Sixthly, the use of SelectedIf(persistent.patch_enabled) is useless in this context. Ren'Py know perfectly well how to define if a button is selected of not, depending on its action field.

Seventhly, screen declaration should always include a parameter declaration, even if it's an empty one. This lead to a better optimization for the screens and therefore better performances for the player.


So, in the end, it should be:

Python:
init python:

    # Do not break the game for the players that have used the patch in the past.
    if persistent.patch_installed:
        # If the patch isn't present...
        if not renpy.os.path.exist( NAME OF THE PATCH FILE ):
            # disable it for that play session...
            patch_installed = False
            # and disable its content for the session.
            #  The use of a persistent value here is due to the need to switch the value
            # from a menu screen *and* to limits the change in the existing code.
            persistent.patch_enabled = False
        else:
            # Else enable the patch...
            patch_installed = True
            # and use the persistent preference for the session...
            persistent.patch_enabled = persistent.patch_preference

[...]

screen gal():

    [...]

    textbutton _("Scat"):
        style "switchButton"
        action ToggleField( persistent, "scat")
        #selected persistent.scat   # If really you are paranoid, but /ToggleField/ should do the same.
        pos (700, 10)

    if patch_installed:
        textbutton _("Bestiality"):
            style "switchButton"
            # Switch both the session and global preference.
            action [ ToggleField( persistent, "patch_enabled"), ToggleField( persistent, "patch_preference") ]
            #selected persistent.patch_enabled   # If really you are paranoid, but /ToggleField/ should do the same.
            pos (960,10)

style switchButton is button
#  Buttons will be in green and bold when selected, and in red when not selected.
# This is explicit enough, but you can use whatever style you want, including a visual indicator.
style switchButton_text is button_text:
    color "#F00"      # red
    selected_color "#0F0"    # green
    selected_bold True
Then in your code you just have to change if scat into if persistent.scat, and it should works as you want it to works.
 
  • Like
Reactions: Nicke

osanaiko

Engaged Member
Modder
Jul 4, 2017
2,149
3,501
Sixthly, the use of SelectedIf(persistent.patch_enabled) is useless in this context. Ren'Py know perfectly well how to define if a button is selected of not, depending on its action field.
I don't want to derail this dev-help-thread... but I found the documentation around this feature to be near useless:

Quoting from the docs for "button":
action
The action to run when the button is activated. A button is activated when it is clicked, or when the player selects it and hits enter on the keyboard. This also controls if the button is sensitive if sensitive is not provided or None, and if the button is selected if selected is not provided or None.
Then on the "Screen Actions, Values, and Functions" page of the docs:
A list of actions can usually be provided in lieu of a single action, in which case the actions in the list are run in order. A list of actions is sensitive if all of the actions are sensitive, and selected if any of them are ; that unless or , respectively, is part of the list.
It doesn't explain (anywhere that I could find) HOW the selected/sensitive state is determined by the action. Is it some AND/OR operation on the values of the parameters that are supplied to the actions?

edit: after digging into the source code it seems that the defaults of the base Action class are "selected is false" and "sensitive is true", and then some specific Actions override the get_sen/get_sel methods. So unless one reads the source code, there is no way to know... :poop:
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,198
14,931
It doesn't explain (anywhere that I could find) HOW the selected/sensitive state is determined by the action. Is it some AND/OR operation on the values of the parameters that are supplied to the actions?

edit: after digging into the source code it seems that the defaults of the base Action class are "selected is false" and "sensitive is true", and then some specific Actions override the get_sen/get_sel methods. So unless one reads the source code, there is no way to know... :poop:
Your reading is mostly correct.

Basically (because it's always a bit more complex) Ren'Py ask every action if they think that the button is selected, and do a AND on what they are saying. But not all action will return a True or False value, some have a purely undefined one.

By example, if you have action SetVariable( "whatever", 42 ), it's easy. Either the value is 42, and so it's True that the button is selected, or the value isn't 42 and it's False.
But when you have action If( whatever > 50, SetVariable( "whatever", whatever + 1), NullAction(), there's no True or False possible answer. It become a None answer, that will looks like a False.

There's also cases where a button can trigger more than one state for some reason. To stay a bit on topic it could be the case for a multi content patch:
Python:
hbox:
    text "patch"
    textbutton "enabled":
        action [ SetVariable( "patch", True ), SetVariable( "watersport", True ), SetVariable( "incest", True ) ]
    textbutton "disabled":
        action [ SetVariable( "patch", False ), SetVariable( "watersport", False ), SetVariable( "incest", False ) ]
if patch:
    textbutton "Watersport enabled":
        action ToggleVariable( "watersport" )
    textbutton "Incest enabled":
        action ToggleVariable( "incest" )
If you enable the patch, but disable watersport, the "enabled" button will be seen as being not selected.

It's where the selected property is helpful. It permit you to define more precisely when a button is selected or not.
Here, it would be selected patch for the "enabled" button, and selected not patch for the "disabled" one. Be noted that like you can't turn a variable at True when the patch is disabled, the selected part isn't necessary.
 
  • Like
Reactions: osanaiko

osanaiko

Engaged Member
Modder
Jul 4, 2017
2,149
3,501
Yes, I can see that now, thanks for the explanation.

It's a complex topic, and seems like a missing part of the documentation. Well, I guess it is open source so maybe I could try to make a PR...
 

SnubbLR

Newbie
Game Developer
Sep 13, 2017
77
544
Wow, there's many things to say here:

Firstly, having two buttons that both toggle the same variable isn't right at all. If scat is off, clicking on the "scat off" button would turn it on.

Secondly, why are you using "1" and "0" as value for scat, and not just a boolean like for bestiality ?

Thirdly, why are you using a persistent value for the bestiality content, and not for the scat content ?
Side note: Due to the difference in context, there's 90% chance that it's the reason why the scat part don't works.

Fourthly, never ever use a persistent value to define if a patch is installed or not. The player can change his mind and remove the patch, or he can forget to install it with the new update. Then he would have absolutely no way to turn the flag off, what would then break the game.

Fifthly, the use of SelectedIf(persistent.patch_enabled) is outdated, there's now a selected property for the buttons.

Sixthly, the use of SelectedIf(persistent.patch_enabled) is useless in this context. Ren'Py know perfectly well how to define if a button is selected of not, depending on its action field.

Seventhly, screen declaration should always include a parameter declaration, even if it's an empty one. This lead to a better optimization for the screens and therefore better performances for the player.


So, in the end, it should be:

Python:
init python:

    # Do not break the game for the players that have used the patch in the past.
    if persistent.patch_installed:
        # If the patch isn't present...
        if not renpy.os.path.exist( NAME OF THE PATCH FILE ):
            # disable it for that play session...
            patch_installed = False
            # and disable its content for the session.
            #  The use of a persistent value here is due to the need to switch the value
            # from a menu screen *and* to limits the change in the existing code.
            persistent.patch_enabled = False
        else:
            # Else enable the patch...
            patch_installed = True
            # and use the persistent preference for the session...
            persistent.patch_enabled = persistent.patch_preference

[...]

screen gal():

    [...]

    textbutton _("Scat"):
        style "switchButton"
        action ToggleField( persistent, "scat")
        #selected persistent.scat   # If really you are paranoid, but /ToggleField/ should do the same.
        pos (700, 10)

    if patch_installed:
        textbutton _("Bestiality"):
            style "switchButton"
            # Switch both the session and global preference.
            action [ ToggleField( persistent, "patch_enabled"), ToggleField( persistent, "patch_preference") ]
            #selected persistent.patch_enabled   # If really you are paranoid, but /ToggleField/ should do the same.
            pos (960,10)

style switchButton is button
#  Buttons will be in green and bold when selected, and in red when not selected.
# This is explicit enough, but you can use whatever style you want, including a visual indicator.
style switchButton_text is button_text:
    color "#F00"      # red
    selected_color "#0F0"    # green
    selected_bold True
Then in your code you just have to change if scat into if persistent.scat, and it should works as you want it to works.
So about the persistent.bestiality patch... Originally it was intended to be a patch, but I ended up not having an actual patch in the game. I just use the code "
if persistent.patch_enabled:
jump beast1" as a regular code to differentiate between bestiality content and non-bestiality content (The patch is always installed). I know it must look completely dumb, but I don't fuck with it if it works. And I'm almost sure the patch stuff has no effect on my scat problems. Amazingly, thanks to me going this dumb route, it gave me no problems when working on the gallery since everything regarding bestiality was already set as persistent.

I tried your code, and I couldn't get it to work. No matter what I did, the scat value wouldn't change as a variable. Someone in my discord suggested using ChatGPT, so that's where I went. After another 7 hours hanging out with AI, I got nowhere (though I had some amusing results, this for example
Code:
def ToggleScat():
        global scat
        persistent.scat = 1 - scat
        scat_button_selected = scat == 1
, made scat toggle on and off every time I clicked shift+D to check my variables?). Then I revisited your message, and realized I read this very very important part wrong:
Then in your code you just have to change if scat into if persistent.scat, and it should works as you want it to works.
You meant changing every single scat variable in my whole game to persistent.scat, not just in the code snippet you gave me... So I did. I used "replace in project" and it was terrifying. But I think it freaking worked! No bugs so far, and the replay function seem to work the way I want it to.

One small problem I am having though with the button...

Python:
style switchButton is button

style switchButton_text is button_text:
    color "#0F0"      # red
    selected_color "#0F0"    # green
    selected_bold True
This one doesn't turn red. It's just always green, the only thing that changes is that it turns Bold when activated. Never mind, I'm an idiot again It's the same hex color, sigh. No big deal for me at this point though. It might have to do with me apparently using an older version of renpy (Something ChatGPT was happy to point out whenever it had a chance. But I'm terrified of changing to a never version. If it works, don't fuck with it.

Anyway,
AI - 0
anne O'nymous - 1.

Thank you so much <3


Now the next step is to figure out the name issue. Currently, this is what I have in my game in the intro

Python:
$ y = renpy.input("Who am I? (if nothing is entered, I am Sebastian)")
    $ y = y.strip()
    if y == "":
        $ y = "Sebastian"
    y "{i}That's right.. My name is{/i} [y]"
Now I got to figure out how to make that persistent too.


Also, another problem that is looming on the horizon... I want my gallery to be completely unlocked from the get-go, rather than the player having to see the label in the game before being able to see the scene in the gallery. I need to figure out how to do that. A problem here might be that a new player goes direct to the Gallery, rather than playing the intro, and therefore doesn't get so set a player name. I can see this causing bugs in the future.

Anyway, Google and F95 posts will probably be helpful with these future problems. Thanks again guys. You're awesome
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,198
14,931
I tried your code, and I couldn't get it to work. [...] and realized I read this very very important part wrong:
Sorry about that. I have the chance to be able to post from works, what I was doing that time. But sometimes it also mean less time to ensure that I'm clear enough.


Never mind, I'm an idiot again It's the same hex color, sigh.
No, you are not an idiot.
Even nowadays with my decades of experience, I sometimes make errors as basic as this one. And anyway, it's through our errors that we learn and progress.


Thank you so much <3
You're welcome.



Now the next step is to figure out the name issue. Currently, this is what I have in my game in the intro

Python:
$ y = renpy.input("Who am I? (if nothing is entered, I am Sebastian)")
    $ y = y.strip()
    if y == "":
        $ y = "Sebastian"
    y "{i}That's right.. My name is{/i} [y]"
Now I got to figure out how to make that persistent too.

It's not too difficult. Strictly speaking, you just need to have a $ persistent.name = y.

But There's an issue here, you are using the same variable for the sayer and to store the name.
Ren'Py is strong and can deal with this, but for once it's a strength that hide a terrible fate, and a broken state that can be really hard to debug when you don't know about it. The first thread where it appeared, years ago, was a long journey to the solution.

So, I propose you this:
Python:
#  Give a default name to your MC.
default yName = "Sebastian"

#  Define the /sayer/, and tell Ren'Py that the "yName" variable
# is where the character name is stored.
define y = Character( name="[yName]" )

label whatever:
    [...]

    #  If there's already a persistent name, because the player restarted
    # the game, use it as default name.
    if persistent.yName:
        $ yName = persistent.yName

    #  Use the default name, or the previously chosen one, as default
    # value. That way, if it please the player, he just have to validate.
    $ yName = renpy.input("Who am I?", default=yName ).strip()
   
    #  A security net. If the name is empty, fallback to you default name.
    # An empty string is seen as a False value, so here you can have a basic
    # condition for the /if/.
    if not yName:
        $ yName = "Sebastian"

    # Then finally store the name, or new name, as persistent value
    $ persistent.yName = yName

Also, another problem that is looming on the horizon... I want my gallery to be completely unlocked from the get-go, rather than the player having to see the label in the game before being able to see the scene in the gallery. I need to figure out how to do that.
For this, 79flavors or Rich are more adapted than me.


A problem here might be that a new player goes direct to the Gallery, rather than playing the intro, and therefore doesn't get so set a player name. I can see this causing bugs in the future.
Well, with the way I presented above, it would then have the default value gave to "yName", so there will be no bugs.
But you're right that it would have led to some issue the way you initially did it.

So, a good practice, always declare your variable before use.
For this, I recommend you the reading of this thread. What directly interest you is more the second and third posts, but the whole thread have high value content, especially its opening post. And, while you're at reading, you should probably also take a look at (here, reading the opening post is enough).
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,198
14,931
this might be because 79flavors made this mistake in his post.
It's not a mistake.

Character objects* have a special behavior, and when expressed as text, like in mc "my name is [mc]", Ren'Py will return the name gave to that character. So here there's only one variable.
But in the same time I agree that for anyone who don't know about that particularity, it looks like the name is directly stored into the variable named "mc".


*: Strictly speaking it's in fact an ADVCharacter object. But it's created through Character(), so it's less confusing to name it that way.
 
  • Like
Reactions: 79flavors

peterppp

Member
Mar 5, 2020
469
879
It's not a mistake.

Character objects* have a special behavior, and when expressed as text, like in mc "my name is [mc]", Ren'Py will return the name gave to that character. So here there's only one variable.
But in the same time I agree that for anyone who don't know about that particularity, it looks like the name is directly stored into the variable named "mc".


*: Strictly speaking it's in fact an ADVCharacter object. But it's created through Character(), so it's less confusing to name it that way.
someone made a mistake, but it turns out it was me! apologies to 79flavors then, it fooled a newbie like me
 
  • Like
Reactions: 79flavors

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,560
2,179
this might be because 79flavors made this mistake in his post. as you said, anyone can make simple mistakes
Python:
    mc "Hi, my name is [mc]."

It's not a mistake. It's a deliberate choice on my part. Though I understand why it might cause confusion.

I use the example as it is, because it works for all characters - even the ones that don't have variables for the name of the specific character.
The path of least resistance is when you have a Character() identified as mc and has a variable used for it's name like mc_name... you put [mc_name] in any spoken dialogue.
But when you have something like define k = Character("Karen"), there isn't an equivalent [k_name] (or whatever you call the variable).

However for a reason I'll detail below, [mc] and [k] would both still work to print the character's name. I code it that way in my recent examples, because it means that if at some later point in your game development you want to be able to change Karen's name, you can - without rewriting all the dialogue that mentions her name. Basically, it adds a bit of flexibility that I think is useful.

The downside is when someone mistakenly does something like $ k = renpy.input("Enter a name for you friend"). And suddenly you've changed your Character() object k into a string object k. Worse, k is now part of the save file.
So yes, I understand the confusion and some of the risks in laying out my examples as I do.

The reason using the Character() object as the character's name, say rather than [k.name] is the often overlooked function. It basically says that if you use an object somewhere the script is expecting a string (like dialogue), it will instead return the .name property as that string rather than the object itself.
 

SnubbLR

Newbie
Game Developer
Sep 13, 2017
77
544
Sorry about that. I have the chance to be able to post from works, what I was doing that time. But sometimes it also mean less time to ensure that I'm clear enough.




No, you are not an idiot.
Even nowadays with my decades of experience, I sometimes make errors as basic as this one. And anyway, it's through our errors that we learn and progress.




You're welcome.






It's not too difficult. Strictly speaking, you just need to have a $ persistent.name = y.

But There's an issue here, you are using the same variable for the sayer and to store the name.
Ren'Py is strong and can deal with this, but for once it's a strength that hide a terrible fate, and a broken state that can be really hard to debug when you don't know about it. The first thread where it appeared, years ago, was a long journey to the solution.

So, I propose you this:
Python:
#  Give a default name to your MC.
default yName = "Sebastian"

#  Define the /sayer/, and tell Ren'Py that the "yName" variable
# is where the character name is stored.
define y = Character( name="[yName]" )

label whatever:
    [...]

    #  If there's already a persistent name, because the player restarted
    # the game, use it as default name.
    if persistent.yName:
        $ yName = persistent.yName

    #  Use the default name, or the previously chosen one, as default
    # value. That way, if it please the player, he just have to validate.
    $ yName = renpy.input("Who am I?", default=yName ).strip()
  
    #  A security net. If the name is empty, fallback to you default name.
    # An empty string is seen as a False value, so here you can have a basic
    # condition for the /if/.
    if not yName:
        $ yName = "Sebastian"

    # Then finally store the name, or new name, as persistent value
    $ persistent.yName = yName



For this, 79flavors or Rich are more adapted than me.




Well, with the way I presented above, it would then have the default value gave to "yName", so there will be no bugs.
But you're right that it would have led to some issue the way you initially did it.

So, a good practice, always declare your variable before use.
For this, I recommend you the reading of this thread. What directly interest you is more the second and third posts, but the whole thread have high value content, especially its opening post. And, while you're at reading, you should probably also take a look at (here, reading the opening post is enough).
Well, this worked pretty well for me, so thank you so much! Really!

The only small problem is that for returning players who had played the game and named themselves using the old way has some inconsistencies when using old saves. But once they start a new game and make their name persistent, it seems to work somewhat.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,198
14,931
The only small problem is that for returning players who had played the game and named themselves using the old way has some inconsistencies when using old saves.
Oh, there's way to deal with this without the need to restart the game.

Among it's , Ren'Py have one named after_load that, if it exist, will be called every time the player load a save file, right after the said save file have been loaded. So, you can do the transition from one method to another by yourself:

Python:
label after_load:

    # For regular variables:
    if not hasattr( store, "newVariableName" ):
        newVariableName = oldVariableName

    # For persistent values:
    if not persistent.newVariableName:
        persistent.newVariableName = oldVariableName

    return
Like the value is assigned only if the new variable don't exist yet, you can leave that code forever. It will only be triggered once by save file, while doing nothing for players who started the game after you made the change.

For more, you can take a look at my . It cover that kind of issue and way more.
 
  • Like
Reactions: osanaiko