Ren'Py newbie question regarding textbutton

rainshigure

Newbie
May 14, 2018
43
6
hello everyone

I'm trying to make some kind of cheat menu to change game variable.
to do this I'm using textbutton , and I would like to pass the variables into the so called cheat UI where there is button to increase/decrease the variable value.

currently I'm trying to make it like this
You don't have permission to view the spoiler content. Log in or register now.

but I got the following error in the traceback file
You don't have permission to view the spoiler content. Log in or register now.

I don't know if it's not possible to call label with parameter from textbutton, or is it that I did something wrong.

If someone could help to explain this or give suggestion if there is a better way to do this is appreactiated, thanks in advance
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
You can't include the argument as part of the name of the label. You need to pass that in afterwards as part of the "args".



It should be: action Call("show_change_aff_screen", mary_aff)

Also you don't pass the mary_aff variable into the new screen, but beyond that you can call screens from inside screens so jumping to the label is pointless.
 
Last edited:
  • Like
Reactions: The Rogue Trader

rainshigure

Newbie
May 14, 2018
43
6
You can't include the argument as part of the name of the label. You need to pass that in afterwards as part of the "args".



It should be: action Call("show_change_aff_screen", mary_aff)

Also you don't pass the mary_aff variable into the new screen, but beyond that you can call screens from inside screens so jumping to the label is pointless.
hello, thanks for the suggestion

I manage to make it work by changing some things, but then I got another issue, when I tried to change the variable value inside the new screen it said the variable doesn't exist.

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

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

is this related to what you said, "Also you don't pass the mary_aff variable into the new screen". is it not possible to pass the variable into different screen?
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
Ren'py is a fucking nightmare to use because all its parts have totally different syntax rules. I think string interpolation is only usable inside Ren'py code. For screen language, you need to use Python string concatentation. So it would be text "Aff: " + str(char_aff) For SetVariable, you just use the variable name without any quotes or brackets.

It is possible to pass the variable into different screens. I'm saying, you did not do that in your first example. You use show screen change_char_aff but you don't actually pass the variable to it.
 

rainshigure

Newbie
May 14, 2018
43
6
Ren'py is a fucking nightmare to use because all its parts have totally different syntax rules. I think string interpolation is only usable inside Ren'py code. For screen language, you need to use Python string concatentation. So it would be text "Aff: " + str(char_aff) For SetVariable, you just use the variable name without any quotes or brackets.

It is possible to pass the variable into different screens. I'm saying, you did not do that in your first example. You use show screen change_char_aff but you don't actually pass the variable to it.
hello again, sorry to keep asking, but I still got an error after following your advice on the setVariable function

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

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

not sure what went wrong here, I don't even use the split function
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
Python relies on indentation, and if you don't indent your example properly it's hard for me to help you, sorry.

The error means somewhere you passed a variable to a function you thought was a string, but is actually an integer. I can't see the rest of your code, but it may be this line: Call(exit_label). You need quotes around exit_label.
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
After looking at the files in your trackback, I realized was wrong. You do need to use quotation marks when passing the variable name into SetVariable(), because it's actually fetching the integer from the store by name. I had that confused with SetField(), which takes an object reference as its first parameter.

Like I said, the syntax for this fucking program is all over the place.

Also, some tips:

Always put a return statement at the end of your labels. Iirc Ren'py will fallthrough and continue executing after a label ends. That's how it knows to include local labels inside global labels. So even though Python is based around indentation, Ren'py just ignores it and keeps going past the indentation. I'm not sure how "smart" Ren'py is at knowing not to execute screen language, but I wouldn't bet on it. Always better to explicitly return. And following from that, don't mix in screen declarations with your scripting. Always put screens/styles/transforms etc. either in a separate file or at the top of a file. Don't pepper them all through your code like that.
 
Last edited:

CheerMaster

Newbie
Dec 27, 2018
31
257
I'm not trying to be an asshole or anything, but are you doing it out of "necessity" as to avoid the need of to edit every single save of the games you play or are you doing this cheat menu for the fun of it?
If it's for the fun of it, please do ignore this and keep it up, but if not, there's URM, that allows you to do variable editing, among other bunch of things.
Again, I just wanted to mention it, not trying to disparage your work.
 

rainshigure

Newbie
May 14, 2018
43
6
After looking at the files in your trackback, I realized was wrong. You do need to use quotation marks when passing the variable name into SetVariable(), because it's actually fetching the integer from the store by name. I had that confused with SetField(), which takes an object reference as its first parameter.

Like I said, the syntax for this fucking program is all over the place.

Also, some tips:

Always put a return statement at the end of your labels. Iirc Ren'py will fallthrough and continue executing after a label ends. That's how it knows to include local labels inside global labels. So even though Python is based around indentation, Ren'py just ignores it and keeps going past the indentation. I'm not sure how "smart" Ren'py is at knowing not to execute screen language, but I wouldn't bet on it. Always better to explicitly return. And following from that, don't mix in screen declarations with your scripting. Always put screens/styles/transforms etc. either in a separate file or at the top of a file. Don't pepper them all through your code like that.
unfortunately even after put quote at the char_aff it still doesn't work
You don't have permission to view the spoiler content. Log in or register now.
You don't have permission to view the spoiler content. Log in or register now.
lolz, I think I will give up on making this separate cheat screen, instead I will just put the textbutton in the previous screen instead,

thank you very much for all the help
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
This should work.

"char_aff" is an argument to the screen so it's not in the store. Instead we need to pass the name of the variable we do want to change ("mary_aff") as a string to the screen so it can be used with SetVariable().

Code:
screen change_char_aff(affection_value, affection_name):
    hbox xalign 0.8 yalign 0.1 spacing 15:
        text " Aff: " + str(affection_value) style "Char_text"
        textbutton " +" style "Char_text" action SetVariable (affection_name, affection_value+1)
        textbutton " -" style "Char_text" action SetVariable (affection_name, affection_value-1)

screen cheat_screen():
    imagebutton xalign 0.97 yalign 0.015:
        idle "images/phone/exit.png"
        action Hide("cheat_screen"), Call("exit_label")

    imagebutton xalign 0.97 yalign 0.9:
        idle "images/phone/back.png"
        action Hide("cheat_screen"), Call("main_phone_screen")

    vbox xalign 0.1 yalign 0.1 spacing 15:
        textbutton "Mary" style "Char_text" action Show("change_char_aff", None, mary_aff, "mary_aff")

#######################################################

default mary_aff = 0

label cheat_menu:

    show screen cheat_screen

    $ _skipping = False
    $ quick_menu = False #removes that buttons on bottom so you cannot press auto
    $ preferences.afm_enable = False
    $ renpy.pause(hard=True)
    
    return
 
  • Like
Reactions: rainshigure

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
It should be: action Call("show_change_aff_screen", mary_aff)
Yeah, passing the value instead of the variable will really help...


Ren'py is a fucking nightmare to use because all its parts have totally different syntax rules.
Not really.


I think string interpolation is only usable inside Ren'py code.
Totally wrong.


It is possible to pass the variable into different screens.
Of course.



To OP, what you want is something that looks like this:
Python:
# Ensure that the cheat menu will always be available.
define config.overlay_screens.append( "cheatOpener" )

# List of cheat - ( name, value ).
define cheats = [ ( "Mary affection", "mary_aff" ), 
             ( "Sarah affection", "sarah_aff" ), 
             # Continue with the other cheats.
             ]

# Button to access the cheat menu.
screen cheatOpener():
    textbutton "cheat":
        # Change those to to position the button where you want.
        xalign 0.0
        yalign 0.0
        # Display the cheat menu on click.
        action Show( "cheatMenu" )

# The cheat menu.
screen cheatMenu():

    #  The screen catch all the clicks.
    modal True

    frame:
        # Full black background.
        background Solid( "#000" )
        # Center the screen.
        xalign 0.5
        yalign 0.5
        # Enforce the size of the screen.
        xsize config.screen_width - 100
        ysize config.screen_height - 100
        # Do not stick the content to the border.
        padding ( 50, 50 )

        #  Grid that will contain the buttons.
        #  The first value is the number of columns, the second is
        # the number of rows. Therefore adjust depending of the
        # number of cheats you need.
        #  The result of columns * rows MUST be bigger than the
        # number of cheats.
        grid 1 10:
            #  Needs Ren'Py 7.5.0 or more.
            allow_underfull True

            # Iterate through all the cheats.
            for t, v in cheats:
                # Make the buttons appear on one line.
                hbox:
                    # Name of the cheat.
                    text "[t]"
                    # Aerate a bit.
                    null width 5
                    # Increase the value
                    textbutton "+" action SetVariable( v, getattr( store, v ) + 1 )
                    # Aerate a bit.
                    null width 5
                    # Decrease the value
                    textbutton "-" action SetVariable( v, getattr( store, v ) - 1 )

    # Finally add a button to close the cheat menu.
    textbutton "Close":
        xpos 55
        ypos 55
        action Hide( "cheatMenu" )
 
  • Like
Reactions: rainshigure

MidnightArrow

Active Member
Aug 22, 2021
500
452
Yeah, passing the value instead of the variable will really help...
Python doesn't have datatypes and the OP didn't assign it anywhere, so there's no way to tell in the first post what it's meant to be. Besides, everything in Python is an object, so logically it should always pass by reference. There should be no such thing as passing by value, right?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
Python doesn't have datatypes and the OP didn't assign it anywhere, so there's no way to tell in the first post what it's meant to be.
Really ? Not even his "to increase/decrease the variable value" ?


Besides, everything in Python is an object, so logically it should always pass by reference. There should be no such thing as passing by value, right?
You should really starts to think a bit before you write, because it starts to be really tiring to read you.
As you said yourself, in Python everything is an object. And, as any programmer who have graduated after the early 90's know, the value of an object is its reference. Therefore in Python the notion of "passage by reference" and "passage by value" mean nothing at all.
Inb4: Whatever if you graduated or not. You pass a big part of your time saying that Python is a shitty language, therefore it's expected that you know at least the basis.

What I was pointing isn't the way the arguments are proceeded since, like I just said, it would be nonsensical.
No, I was referring to the fact that in Python every variables are immutable. What mean that when you're changing the value of a variable, you're in fact deleting the previous variable and creating one with the same name.
Therefore, while having the reference to a variable give you a "read access", when the variable is a scalar-like (string, number, boolean), it also don't give you more than if you only had its value. The reference by itself is totally useless when what you need is a "write access" ; what you need in this case is the name of the variable.
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
Really ? Not even his "to increase/decrease the variable value" ?
OP didn't specify what the variable value they were trying to increase was, because there was no variable arithmetic in their first post.

You should really starts to think a bit before you write, because it starts to be really tiring to read you.
...
Inb4: Whatever if you graduated or not. You pass a big part of your time saying that Python is a shitty language, therefore it's expected that you know at least the basis.
People should think a bit before they implement this shitty scripting language into their programs, because it's really tiring to use it.

I want to use Ren'py, and Ren'py doesn't support anything else (afaik).

No, I was referring to the fact that in Python every variables are immutable. What mean that when you're changing the value of a variable, you're in fact deleting the previous variable and creating one with the same name.
Therefore, while having the reference to a variable give you a "read access", when the variable is a scalar-like (string, number, boolean), it also don't give you more than if you only had its value. The reference by itself is totally useless when what you need is a "write access" ; what you need in this case is the name of the variable.
So basically all variable names are keys in a dictionary (the store, presumably), and when you reassign the variable you're really changing the data associated with the key. Okay, fine. So why does Python pride itself on "There's only one way to do it", but then pretend it has objects and namespaces ("stores") that are really dictionaries under the hood? Why not just use dictionary syntax for everything, rather than this convoluted indirection to try and support features it doesn't actually support?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,236
OP didn't specify what the variable value they were trying to increase was, because there was no variable arithmetic in their first post.
And what you expect them to be ? Strings ?


People should think a bit before they implement this shitty scripting language into their programs, because it's really tiring to use it.
Yet, due to it's simplicity, and it being largely fool proof, while relatively obvious and easily readable by a human, it's one of the main language taught in universities' computer courses all around the world.
I don't like this language, it goes against all the freedom, and habits, I acquired during decades of use of C and (my beloved) Perl. But this doesn't prevent me to recognize that, despite its rigidity, and the oddity of it's immutability and duck typing approach, it's a language easy to learn and to use.
It's a language as easy as lua, while being more powerful than it. Therefore it's the perfect choice when you need an embedded script language that will possibly be used by total novices ; this even when, in the case of Ren'Py, "embedded" is misused.


So basically all variable names are keys in a dictionary (the store, presumably), [...]
What the fucking fuck is "the store" ?
Hint: you're talking about Python here...


So why does Python pride itself on "There's only one way to do it", [...]
OMFG... There's still peoples stuck with this now 22 years old promotional geek joke ?
Before using it as argument to justify your hate of Python, you should have took few times to search what hide behind those few words. Just to be sure that there's at least a bit of truth behind the meaning you give them.
TL;DR: There isn't a single bit of truth, you totally misunderstood what it was intended for and what it mean.

No, Python do not pride itself with this. As I said, it was a promotional geek joke, that happened during the 2000.
At this time, Perl was at its top. It was the most used script language, present by default in all Linux distributions and *nix OSes, even being use by the core of the said distribution and OSes. This while Python was still at its prime, and rarely used. Due to its oddity, it was too often seen as marginal, and, worse for geeks, it was heretic ; it was the first language intended to be mainstream that killed the father and abandoned the C syntax ({ and } to marks the blocks, ; to end a line, and few others idioms).
At the OSCON 2000, the Python team decided to distribute shirts with printed on them a sentence that was the exact opposite of Perl's motto (" "). What was their effective thoughts behind this, only them know. But it's difficult to imagine that they weren't aware that, by distributing those shirts to pure computer geeks that would immediately get the reference, they were presenting their language as being "everything that Perl isn't".
And since Perl is a "what the fucking fuck" language (yet it's my favorite ; yes I'm also a cat guy), it presented Python as an "easy to use, easy to understand" language. One sentence, eight words, and the whole philosophy being Python is summarized. But this never was, and will never be, the Python's motto.

At no time the Python team believed that their language was, and even less should be, this rigid. It's not even what they had in mind, and therefore even less what they intended to do.
Yes, they designed Python to be easy to use and as obvious as possible. But they are no fools, they know that, to paraphrase Jurassic Park because it fit perfectly, "coders will not be contained. Coders breaks free, they expands to new territories and crashes through barriers, painfully, maybe even dangerously". Said otherwise, they know that there will always be more than one way to do it.

They know it so well that it's said explicitly in the ; the text describing the philosophy that should be applied when writing Python code. This is yet another geek reference, and yet another way (with the "killed father" thing) to show the real intent behind the language: putting the past behind and starting a new era.
At this time coders, especially C ones, had 's , generally shortened as "TAOCP" ; what led to a bunch of "The Art Of", and with them to the "TAO" expression. In response to this, Python decided to have it's "Zen".
I'll not start an explanation regarding Chinese philosophies, so in short, "Python take the best of TAOCP, and make it simple and practicable". There was the TAO generation, and it was now time to make place to the Zen generation.

Back to the topic, in the Zen of Python you found those two lines:
"There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
"
What is far to the rigidity you attribute to Python.
Firstly, there's the "should". Therefore it's not an obligation ("must"), but a recommendation.
Secondly, it's weighted by the following "preferably". Therefore it's "as much as possible".
Thirdly, there's the "obvious". Therefore, this do not exclude the existence of more obscures, when not or even purely , possibilities.
And finally, there's the second line. This one can be less easy to understand, but in short it's a self-mockery. They recognize themselves that if you don't share their own views regarding how a programming language should be designed, then it will perhaps not be always "this obvious".

All this is also enforced by two other important lines, that appear early in the Zen of Python:
"Simple is better than complex.
Complex is better than complicated."
By themselves, those three lines recognize that there's at least "three ways to do it" ; the simple way, the complex way, and the complicated one.


but then pretend it has objects and namespaces ("stores") that are really dictionaries under the hood?
I already debunked this bullshit of yours.
And by the way, once again, what the fucking fuck is this "store" ?
hint: you are still talking about Python.


Why not just use dictionary syntax for everything, rather than this convoluted indirection to try and support features it doesn't actually support?
Why ? Well... Since I lost my patience I'll say it bluntly, and whatever if I'm harsh: Because you are an ignorant idiot who don't have the starts of a clue regarding what he is talking about.

You decided that you hate Ren'Py and Python, and that you should preach against them as often as you can, good for you. But the more you talk, the more it is obvious, at least for people knowing a bit the subject, that you hate them for no reasons. Or, said more precisely, that you hate them for purely personal reasons that are, in no way, linked to the reality. All your arguments against Ren'Py and Python as pure nonsense and are based on nothing more than your own wrong assumptions.

Take your two references to "store" by example. You're applying this to Python, pretending that it represent the way Python manage its namespaces. But the truth is that it's a Ren'Py thing. There no "store" in Python, Python do not manage its namespaces in that way.
And in Ren'Py they aren't namespaces. They are a mimic of namespaces, intended to mark a separation between the different variables, accordingly to their intent. This in order to limit the user confusion, the risk of name conflict, and therefore to hardened the language.
Anyone with a bit of experience in the field would quickly understand that it's the easiest approach when you have to design your own language. It's not necessarily the best approach, and depending of the language it can be an approach to avoid for many reasons. But in the case of Ren'Py, those reasons don't make much sense. The language isn't intended to run code allowing a remote access, nor to proceed third party code wrote in the same language and operated at the same level. Therefore there's no need for an enforced security layer. In the same time, code wrote with this language are intended to have frequent pauses (the time past reading the dialog), therefore speed efficiency is not a mandatory requirement.

Then, once you starts to think about it a bit more, this approach make even more sense, due to Ren'Py rollback feature. By storing the variables relative to the game (and to the game only) on an object, you then have the simplest possible design to manage the rollback feature. It suffice to make a (shallow) copy of the "store" objects, to have a full copy of the game context at a given time. And since this copy is made after each interaction, here speed efficiency matter. This while space efficiency is also a main criteria, since there will be a copy of dozen contexts.
No need to browse all the defined namespaces. No need to manage a list of variables then address them one by one. No need to maintain, and also keep a copy of, the name/type/value couple. You copy a bunch of objects, and it's done. This whatever how many variables the game have, and whatever how complex or deep they can be, and whatever at what moment the variables are created or deleted.
You also don't need to design extra code, just relying on the behavior of Python object is enough for all this to be automatically performed for you.

Finally, no, unlike what you claim, Ren'Py "stores" aren't dictionaries, like I said they are pure custom objects.
And, of course, also no, the "__dict__" dictionary is not how Python handle the attributes of an object. It's one, and only one, of the abstract used as interface between the core of the interpreter and the user.
Accordingly to the simplicity and obviousness approach behind the language design, Python team created this interface to offer an easy access to the attributes. One that permit to build the attribute name in real time ; something that would be way more complicated to do without this abstract.

That you hate Python, well, it's your problem, good for you if you want, who care. But when you spread your bullshit beliefs through stupid preaches full of nonsense, then it become everyone problem.
 

MidnightArrow

Active Member
Aug 22, 2021
500
452
And what you expect them to be ? Strings ?
I expected them to be objects. Which is why I passed them in by reference (or whatever the Python semantics are).

Everything else you said, that it's an eyesore to people who know C, that the motto is a pisstake on Perl, Chinese philosophy, I know all that already. You can say all you want about the "philosophy" behind it, it's still an ugly language with an awful class syntax, type safety and scoping flaws, "object-methods-but-not-really", etc. no matter how "simple" and "easy to use" it is.

But fine, let's drop the issue then.
 
  • Haha
Reactions: anne O'nymous