Ren'Py A conditional question

seamanq

Well-Known Member
Game Developer
Aug 28, 2018
1,896
2,876
I have a parameter that I have set as a Boolean here in the code:

Code:
python:
    shaneage = renpy.input("Shane is ___ years old? (Default: 18)")
    shaneage = shaneage.strip()

    if not shaneage:
         shaneage = 18
Later on I want to evaluate that variable to see if it is under a certain number:

Code:
if sandiage <= 17:
In my code I have confirmed that the variable is setting correctly as entered:

Code:
"Shane is [shaneage] and attends [shaneschool]."
However, when I set the age under 18, confirmed by the above line, when I try to run the test condition above, it fails, and does not do what it is supposed to do. According to the Ren'py Python documentation, this should be working properly. No error is thrown, it just ignores what I ask it to do if the age is under 18. Is there something in the input shangeage.strip() that I need to do to tell it that the input is Boolean? Suggestions?
 

Epadder

Programmer
Game Developer
Oct 25, 2016
568
1,064
You're checking the condition of 'sandiage' not 'shaneage', at least in the code you've supplied.
 

seamanq

Well-Known Member
Game Developer
Aug 28, 2018
1,896
2,876
Both are defined in the same way at the beginning of the code. And neither are working when called.

Code:
if shaneage <= 17:
    pn "And then, there are a few other minor issues, like your age."
I think I know the problem, and the problem is that the input is automatically defaulting to text string. In looking some more at problems people were having entering integers, I found the solution. This code works and stores the variable as an integer.

Code:
python:
    shaneage = int(renpy.input("Shane is ___ years old? (Default: 18)"))

    if not shaneage:
         shaneage = int(18)
When it hits the logical evaluation (the if statement), if the age is under 18, it triggers the appropriate response now.
 

Dogeek

Summertime Saga
Game Developer
Apr 20, 2018
74
510
input(), in python 3 (at least) returns a string and it's up to you to parse it. If you want an int, you have to manually cast it.

It can fail though, and this should be inside a try/except block to catch the exception if it does.

Python:
def int_input(string=""):
    while True:
        x = input(string)
        try:
            return int(x)
        except ValueError as e:
            print(e)
            continue
 

seamanq

Well-Known Member
Game Developer
Aug 28, 2018
1,896
2,876
Doesn't enclosing it in the int() container get around that? Or are you saying that the approach is not foolproof, and further precautions are needed?
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
Doesn't enclosing it in the int() container get around that? Or are you saying that the approach is not foolproof, and further precautions are needed?
It would if you could be sure your player actually entered a number.
But what if they typed "eighteen" or "0.347747" or anything else for that matter.
The first time your assume your player will do what you want them to is the first time your game will crash.

Rather than ask the player their age... You might want to do a simple "menu" choice to say "I meet my country's legal age for playing this game" and "No, I am not old enough to play your game". Or a simple "Are you old enough (Yes/No)" or "I agree to the games age restriction" would work too.

Keep in mind, not all countries have 18 as their legal requirement for this type of game. Some countries it could be 21. I'm guessing 16 might be true somewhere too (though I don't know of any).

Keep things simple. Which means if you can avoid using numbers... don't use numbers.
 

seamanq

Well-Known Member
Game Developer
Aug 28, 2018
1,896
2,876
You missed the point of the variable completely. The variable is for the player to enter the name of particular characters in the game to an age of their choosing. Since I don't know the laws of every country, I am not qualified to even set a range for this, so I leave it to the user. I will, however, add a note that the value entered must be a number. That is definitely a good idea.
 

seamanq

Well-Known Member
Game Developer
Aug 28, 2018
1,896
2,876
input(), in python 3 (at least) returns a string and it's up to you to parse it. If you want an int, you have to manually cast it.

It can fail though, and this should be inside a try/except block to catch the exception if it does.

Python:
def int_input(string=""):
    while True:
        x = input(string)
        try:
            return int(x)
        except ValueError as e:
            print(e)
            continue
After considering the input from 79flavors, your approach seems to be more practical, as if the player of the game decides to put something that is not a legitimate integer, it would crash the game entirely. Your way, at least, there is a graceful way to return an error code, rather than shutting things down entirely.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
In which case, you could return zero as an age if the player enters an invalid number. (by using "return 0" instead of "print e"/"continue".)

Since 0 will be lower than 18, your game can just do the same as if the player had entered 4 or 16 or whatever. (which I'm guessing will be either to re-prompt the player to reenter an age until the game is happy with it).
Of course, if you just want to gracefully exit... you could do that too.
 

Dogeek

Summertime Saga
Game Developer
Apr 20, 2018
74
510
In which case, you could return zero as an age if the player enters an invalid number. (by using "return 0" instead of "print e"/"continue".)
The code I provided just repeatedly ask the user to enter an age until it's an integer (or a floating point number, but it would be truncated by the integer casting).

With renpy though, there is another way to do such a thing if you want to go the extra mile. You can use the Input displayable and the allow keyword to only allow numbers in that input field.

add Input(size=16, color="#fefefe", default=persistent.autosave_frequency, changed=setAutosaveFrequency, length=4, xpos= 657, ypos = 270, allow = "0123456789") (it's from the summertime saga code, changed must point to a callback, and default to any variable, all those keywod arguments are optional, note the allow keyword)
 

seamanq

Well-Known Member
Game Developer
Aug 28, 2018
1,896
2,876
On beta testing, I found out that the code that I thought was working was actually broken. Here's the code:

Code:
python:
    shaneage = int(renpy.input("Shane is ___ years old? (Default: 18)"))

    if not shaneage:
         shaneage = int(18)
Whenever someone just hit return (selecting the default), the game threw an error. In the second conditional, removing the int() from around 18 (which was already an integer) got rid of the error.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,611
2,258
The code I provided just repeatedly ask the user to enter an age until it's an integer (or a floating point number, but it would be truncated by the integer casting).
Ah ha.
I did wonder about the "while True:"
But I've never done python, nevermind to the level you clearly have. I saw the potential loop, but not how "print e" or "continue" would remain within it. I suppose I could have tested it, but I wasn't invested enough in problem beyond a simple reply.

(it's from the summertime saga code, changed must point to a callback, and default to any variable, all those keyword arguments are optional, note the allow keyword)
I'm going to guess that if he's struggling with "convert string to integer", callbacks might be a slightly further along in the manual than he's read so far. It's certainly beyond me... so I'm simply going to put my head in my hands and slowly rock back and forth while mumbling for a while.
I have used "input={charlist}" as an parameter for renpy.input before. The rest is completely over my head.

On beta testing, I found out that the code that I thought was working was actually broken. Here's the code:

Python:
python:
    shaneage = int(renpy.input("Shane is ___ years old? (Default: 18)"))

    if not shaneage:
         shaneage = int(18)
Whenever someone just hit return (selecting the default), the game threw an error. In the second conditional, removing the int() from around 18 (which was already an integer) got rid of the error.
Okay. I suppose if it works... then it works. I would try entering something really odd, like "dog" instead of a number as a final test.

But the "try:" / "except:" construct in @Dogeek 's post is the answer to "what if it generates an error?".
What "try" does is say "do this command, but if you get an error... check the error against the list of errors defined by the "except" clause. (if you don't get an error, it just carries on anyway).

So in this case, he's saying "try to return the integer of the string you entered". Then "if you get an error while converting that string to an integer (the 'except ValueError')... then do these commands instead".
The "while True:"... and I'm guessing the "continue"... keep it within a loop, repeatedly asking the player to keep entering a number until a valid one is accepted.
On top of all that, he's defining the whole thing as a new function (the 'def int_input(string=""):').

So instead of:
Python:
python:
    shaneage = int(renpy.input("Shane is ___ years old? (Default: 18)"))

    if not shaneage:
         shaneage = int(18)
You'd define the new function somewhere in your code . If you're using a single "script.rpy", then convention says probably near the top. Then use the new function further down...

Something like:
Python:
def int_input(string=""):
    while True:
        x = input(string)
        try:
            return int(x)
        except ValueError as e:
            print(e)
            continue

# <<< loads of other code >>>

label start:

# <<< more code >>>

    shaneage = int_input("Shane is ___ years old? (Default: 18)")

# <<< even more code >>>
In this case, you don't need to do all the "not shaneage:" type tests, because it's already handled by the "try:" logic within the new function.

Again, I haven't tested this code... it may work, just as I've written it... but if not... it'll need some tweaking.