How to make conditional statements based on a numerical value

ChaosOpen

Well-Known Member
Game Developer
Sep 26, 2019
1,013
2,133
Basically I'd like to create an info character which you can ask about a girl and they will give you one of several responses based on a hidden affection number. So, for example if it's between 1-5 she says one thing, 6-10 another, and 11-15 she says yet another. I want this to be prompted automaticall when you talk to her, for example if you're making progress with a girl she will comment on it. The point is to make it sound natural but still be vague as to what the exact value is, emulating you giving the user a feeling that simply watching a digit slowly climb. However, there are 8 girls, so you can see how writing an if-else chain for each possible response for each level can stack up quickly, so if I can, I'd like to avoid writing 100+ lines worth of if-else statements.

But any attempt to write it will throw it back this error:
Untitled.jpg

Here is the code it gave me, the top one works, which is a conditional statement to have an option for an event disappear once they have seen it. Basically each adds 1 point at the end of the event, so at the end it says "$ karen_love += 1" then jumps them back to the question. At which point the option for that event diappears, they then check out all of the options until only one is left "I'm done for the day" which takes them to the next chapter in the story. That seems to work.

However the last line is what is giving me trouble, having her say a statement on her own if certain conditions are met doesn't seem to be working:
m "test script" if karen_love ==1
dfefedffc.jpg
 

moskyx

Forum Fanatic
Jun 17, 2019
4,005
12,961
Not sure if there's a way to avoid the 100+ if statements you want to avoid but I'm certain that way of coding only works in menu choices.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,376
15,289
However the last line is what is giving me trouble, having her say a statement on her own if certain conditions are met doesn't seem to be working:
m "test script" if karen_love ==1
Because you are confusing menu choice (what works) with dialog line (what don't works).

As for the answer to the main question, even if Python or Ren'py had a switch statement, you'll still would need many lines.

Among the many methods to do it, there's this one :
Python:
init python:
    def theRelation( girl ):
        # get the love value for this girl
        stat = getattr( store, girl + "_love" )
        if    stat <=5: return "Unaware of your existence"
        elif stat <= 10: return "Not interested"
        [...]
        else: return "Madly in love"

label whatever:
    # Retrieve the relation value to display
    $ rel = theRelation( "karen" )
    # Then display it while making it translation ready
    "Karen is [rel!t]."
But using a statistic screen in place of a dialog would still be the way that lead to the smallest number of lines.
By example :
Python:
# String for each level of relation
define girlRelation = [ ( 5, "Unaware of your existence" ),
                                 ( 10, "Not interested" ),
                                 [...],
                                 ( 99999, "Madly in love" ) ]
# List of all the girls
define girlsName = [ "karen", "girl1", "girl2", [...] ]
# Actual statistic page
default statPage = 0


screen girlStats( girl ):
     vbox:
        # get the love value for this girl
         $ stat = getattr( store, girl + "_love" )
         $ rel = ""
         # process all the step
         for i in range( 0, girlRelation ):
             # If the step is higher than the actual value, stop.  
             if stat > girlRelation[i][0]: break
             # Else it's at least this step.
             rel = girlRelation[i][1]

         hbox:
             # Display the capitalized name of the girl, translation ready
             text _( "{} : ".format( girl.capitalize() ) )
             # Then the description of the girl, translation ready
             text _( "{}".format( rel ) )

screen stats():
    vbox:
        # Include the stat page for the actual girl
        use girlStat( girlsName[statPage] )

    hbox:
        # Show the button for the previous girl page, if not the first girl.
        showif statPage > 0:
            textbutton _( "Previous" ) action SetVariable( "statPage", statPage - 1 )
        # Show the button for the next girl page, if not the last girl.
        showif statPage < len( girlsName ):
            textbutton _( "Next" ) action SetVariable( "statPage", statPage + 1 )
 

scrumbles

Engaged Member
Jan 12, 2019
2,330
2,421
Alternatively you can define a list of answers:
Code:
define answers = (
    "Do I know you?",   # index: 0; love: zero
    "Oh, it's you...",  # index: 1; love: 1-5
    "Hi! How's going?", # index: 2; love: 6-10
    "Hello, honey!",    # index: 3; love: 11-15
)
and, assuming that the answer changes every 5 love points, you can use the '/' operator to retrieve the index of the right answer:
Code:
$ karen_answer_index = (karen_love+4) / 5
$ karen_answer = answers[karen_answer_index]
m "[karen_answer]"
These three lines can be condensed like that:
Code:
$ m(answers[(karen_love+4) / 5])
Edit: the '/' operator works as intended if both numbers are integer, otherwise it returns a floating-point number.
 
Last edited:

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,223
To repeat a point from above, conditional menu choices and conditional dialogue are coded with the if: in different places.

Python:
label day_one_choice:
    scene day_1_choice with longfade
    menu:
        "I still need to speak with Emily" if emily_love == 0:
            jump emily_event_one
        "I still need to speak with Karen" if karen_love == 0:
            jump karen_event_one
        "I still need to speak with Claire" if claire_love == 0:
            jump claire_event_one
-vs-
Python:
    if emily_love == 0:
        e "I barely know you."
Personally, I'm still at the newbie stage of not really using functions or lists/arrays.

I might be tempted to do something like:

Python:
label day_one_choice:
    scene day_1_choice with longfade
    menu:
        "I still need to speak with Emily" if emily_love == 0:
            jump emily_event_one
        "I still need to speak with Karen" if karen_love == 0:
            jump karen_event_one
        "I still need to speak with Claire" if claire_love == 0:
            jump claire_event_one

    "I've already spoken to all the girls I can."
    jump day_1_some_other_label

label emily_event_one:

    call emily_greeting
    e "more dialogue"
    jump day_two_choice


label emily_greeting:

    if emily_love <= 0:
        e "I'm sorry. Who are you?"
    elif emily_love <= 5:
        e "Oh hey, [mc]."
    elif emily_love <= 10:
        e "Hi [mc]. How's it going?"
    elif emily_love <= 15:
        e "Hello sweetie."
    else:
        e "*** emily_love is higher than I planned ([emily_love]) ***"

    return
Where anytime Emily wanted to introduce herself to me, I do call emily_greeting instead of coding the same thing over and over in different places within the code. The RenPy build process with add a from emily_greeting_1 to the end of each call line. Leave them alone. Never touch them.

Yes, it's still a dozen lines of code per character, totalling lots of if/elif's.

You could make it more generic by doing something like:

Python:
define mc = Character ("[player_name]")
define e = Character("Emily", color="#04B486")
define k = Character("Karen", color="#04B486")
define c = Character("Claire", color="#04B486")

default player_name = "Unknown"

default emily_score = 0
default karen_score = 0
default claire_score = 0


label start:

    scene black with fade
    "Start:.... "

    $ emily_score = 0
    $ karen_score = 5
    $ claire_score = 11

    call female_greeting(e, emily_score)
    call female_greeting(k, karen_score)
    call female_greeting(c, claire_score)

    "*** THE END ***"

    return


label female_greeting(char_id, char_score):
    if char_score <= 0:
        char_id.name "I'm sorry. Who are you?"
    elif char_score <= 5:
        char_id.name "Oh hey, [mc]."
    elif char_score <= 10:
        char_id.name "Hi [mc]. How's it going?"
    elif char_score <= 15:
        char_id.name "Hello sweetie."
    else:
        "*** female_greeting() score is higher than I planned ([char_score]) ***"

    return
But that would assume all characters give the same greeting, depending on their scores.

Edit: A quick note that <= works here with elif: because the numbers are being checked from lowest to highest. If you coded something using "greater than or equal to" (>=), you'd need to reverse the order the numbers are checked in, highest first to lowest last or code each range explicitly (like elif char_score > 0 and char_score <= 5:).

RenPy can be as simple or as complex as you want it to be. Just pick a solution you understand right now, and as you get more experienced... pick another solution.

Generally speaking anne O'nymous 's answer will be the "best" ones, mine will be the simpler solutions.
 
Last edited:

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,223
and, assuming that the answer changes every 5 love points, you can use the % operator to retrieve the index of the right
Sooooo clooosssseee.....

% is modulus.
It's the remainder after the first number is divided by the second.

1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1

It's great for things like calendars or time-of-day. But not this.


I think what you wanted was int(), which is the whole number value, without any decimal places.

Python:
    $ karen_answer_index = int((karen_love+4) / 5)
    $ karen_answer = answers[karen_answer_index]
    m "[karen_answer]"
0 + 4 = 4 ... int(4 / 5) = 0
1 + 4 = 5 ... int(5 / 5) = 1
2 + 4 = 6 ... int(6 / 5) = 1
3 + 4 = 7 ... int(7 / 5) = 1
4 + 4 = 8 ... int(8 / 5) = 1
5 + 4 = 9 ... int(9 / 5) = 1
6 + 4 = 10 ... int(10 / 5) = 2
etc.
 
  • Like
Reactions: anne O'nymous

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,376
15,289
RenPy can be as simple or as complex as you want it to be. Just pick a solution you understand right now, and as you get more experienced... pick another solution.
Totally this.
Ren'py generally offer a ton of possible solutions. Some are clean, some are dirty. Some are short, some are verbose. Some are complex, some are simple. Some need Python, some are pure Ren'py. But there isn't one that is "the solution" ; I've seen clean solutions that were totally broke, as well as simple solutions that amazed me by their inventiveness.
The two things that really matters are the understanding of the solution and it solidity face to possible bugs. And if it effectively works then it's never silly.


Generally speaking anne O'nymous 's answer will be the "best" ones, mine will be the simpler solutions.
I answered the literal question, you answered to the practical one ;)
But you forgot to say something : The number of line in fact don't matter here.

Yes, using a pure if/else structure will need more lines, but that will be wrote just once. So, let say that he'll need 30 minutes to write them (which is a really large guess)... Well, it will anyway be faster than the hour (which is a low guess) needed to find a solution that would need less lines, then to test it to ensure that it will be bug free.
 

scrumbles

Engaged Member
Jan 12, 2019
2,330
2,421
Sooooo clooosssseee.....

% is modulus.
It's the remainder after the first number is divided by the second.
You didn't refresh the page, I fixed the typo a few minutes after posting the solution. :p

I'm surprised instead that nobody said "It's a tuple, you doofus, not a list!" :rolleyes:
 
  • Like
Reactions: 79flavors

ChaosOpen

Well-Known Member
Game Developer
Sep 26, 2019
1,013
2,133
To repeat a point from above, conditional menu choices and conditional dialogue are coded with the if: in different places.

Python:
label day_one_choice:
    scene day_1_choice with longfade
    menu:
        "I still need to speak with Emily" if emily_love == 0:
            jump emily_event_one
        "I still need to speak with Karen" if karen_love == 0:
            jump karen_event_one
        "I still need to speak with Claire" if claire_love == 0:
            jump claire_event_one
-vs-
Python:
    if emily_love == 0:
        e "I barely know you."
Personally, I'm still at the newbie stage of not really using functions or lists/arrays.

I might be tempted to do something like:


Where anytime Emily wanted to introduce herself to me, I do call emily_greeting instead of coding the same thing over and over in different places within the code. The RenPy build process with add a from emily_greeting_1 to the end of each call line. Leave them alone. Never touch them.

Yes, it's still a dozen lines of code per character, totalling lots of if/elif's.

You could make it more generic by doing something like:


But that would assume all characters give the same greeting, depending on their scores.

Edit: A quick note that <= works here with elif: because the numbers are being checked from lowest to highest. If you coded something using "greater than or equal to" (>=), you'd need to reverse the order the numbers are checked in, highest first to lowest last or code each range explicitly (like elif char_score > 0 and char_score <= 5:).

RenPy can be as simple or as complex as you want it to be. Just pick a solution you understand right now, and as you get more experienced... pick another solution.

Generally speaking anne O'nymous 's answer will be the "best" ones, mine will be the simpler solutions.
*Eyes glaze over in complete lack of understanding.*

I'm really on the bottom rung of understanding, to give you an idea many of the explanations given are still going over my head. For example I just learned that there is something called "elif" in this thread, but I'm not quite sure yet what the rules are for its use.

I tried to come up with something basic that allows me to show memories which will take you back to the computer if you're reviewing the memory or adds +1 to the value if you are seeing it for the first time. It might work, it seems to be anyway.

Python:
    if molly_sex >= 2:
        jump bedroom_computer_day_one
    else:
        $ molly_sex +=1
As an aside, speaking of ugly methods, is there any way to make it display the affection of the girls during game? I don't need it to look good I simply want to use it for bug testing. So, even if it takes up half the screen, I just need a short python string to enable it to show the values.

Here are the initial values:
Python:
init: 
    $ chelsey_love = 0
    $ claire_love = 0
    $ karen_love = 0
    $ emily_love = 0
    $ lauren_love = 0
    $ rachel_love = 0
    $ shiro_love = 0
    $ kendal_love = 0
    $ sarah_love = 0
    $ molly_sex = 0
And the characters.

Python:
define ch = Character("Chelsey", color="#e473e7")
define cl = Character("Claire", color="#00cc00")
define ka = Character("Karen",color="#ffff00")
define e = Character("Emily",color="#33cc99")
define l = Character("Lauren",color="#0099cc")
define s = Character("Sarah",color="#ff3399")
define m = Character("Molly",color="#cc9933")
define sh = Character("Shiro",color="#ffffff")
define ke = Character("Kendal",color="#a52a2a")
define p = Character("p",color="##ff0000")
 
Last edited:

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,223
For example I just learned that there is something called "elif" in this thread, but I'm not quite sure yet what the rules are for its use.
elif: is basically else + if: in one statement.

It's partly "typing shortcut" and partly "avoiding silly levels of indentation".

Imagine something similar to what I wrote above...
Python:
   if emily_love <= 0:
        e "I'm sorry. Who are you?"
    elif emily_love <= 5:
        e "Oh hey, [mc]."
    elif emily_love <= 10:
        e "Hi [mc]. How's it going?"
    elif emily_love <= 15:
        e "Hello sweetie."
    else:
        e "*** emily_love is higher than I planned ([emily_love]) ***"
... and now, I'll avoid using elif:...

Python:
    if emily_love <= 0:
        e "I'm sorry. Who are you?"
    else:
        if emily_love <= 5:
            e "Oh hey, [mc]."
        else:
            if emily_love <= 10:
                e "Hi [mc]. How's it going?"
            else:
                if emily_love <= 15:
                    e "Hello sweetie."
                else:
                    e "*** emily_love is higher than I planned ([emily_love]) ***"
As you can imagine, it wouldn't take long before the indentation becomes unmanageable, especially where the "responses" aren't just a single line of dialogue, but something more indepth.

... and all that is just a way of avoiding the "long hand" way of doing it... like this...

Python:
    if emily_love <= 0:
        e "I'm sorry. Who are you?"

    if emily_love > 0 and emily_love <= 5:
        e "Oh hey, [mc]."

    if emily_love > 5 and emily_love <= 10:
        e "Hi [mc]. How's it going?"

    if emily_love > 10 and emily_love <= 15:
        e "Hello sweetie."

    if emily_love > 15
        e "*** emily_love is higher than I planned ([emily_love]) ***"
But again, as I wrote in a previous post... pick whichever solution makes sense to you. Any one of those three will do exactly the same. It's just more typing for some than others. What matters is that you understand it, not that someone else would write it the same way.

[...] is there any way to make it display the affection of the girls during game? I don't need it to look good I simply want to use it for bug testing. So, even if it takes up half the screen, I just need a short python string to enable it to show the values.
Yes.

There is something called the developer console. It's usually disabled for games that have been built and distributed... but as long as you're still in development mode (using the RenPy launcher), it's available.

Launch your game from the RenPy launcher and once it's running, press <SHIFT+O>.
... it'll open the developer console.

Code:
  Press <esc> to exit console. Type help for help.
  Ren'Py script enabled.
>

From there, you can issue RenPy/Python command directly... in this case, you want the watch command.

Python:
watch chelsey_love
watch claire_love
# etc.
The variable and it's value will be displayed in a box overlaying the screen in the top right corner of your UI.

If you want to remove a variable that you are keeping track of... use unwatch.

Python:
unwatch chelsey_love

When you've finished typing console commands, just press <ESC> to return to the game.


If you ever do get to a stage where you want to show a version that "looks good", then you want to add your own screen:, which will usually be a frame: used to hold a vbox:, which in turn holds a list of text: lines, one for each character.

A frame: is just a box that contains other boxes. A vbox: is a "vertical box", where elements shown inside it are stacked vertically (as opposed to a hbox: where things are shown side to side).

I don't think you are there yet, but I mention it only so you know the sort of things you are looking for when you do decide that you'd like to add something like that.


Some other points... and sorry for the the wall of text...

Python:
init:
    $ chelsey_love = 0
    $ claire_love = 0
    $ karen_love = 0
    $ emily_love = 0
    $ lauren_love = 0
    $ rachel_love = 0
    $ shiro_love = 0
    $ kendal_love = 0
    $ sarah_love = 0
    $ molly_sex = 0
Is the way RenPy used to do things a lot of years ago. It'll still work now, but there are reasons why the newer way is better...
Given your previous comments... I'll just go with "trust me on this"...

Python:
default chelsey_love = 0
default claire_love = 0
default karen_love = 0
default emily_love = 0
default lauren_love = 0
default rachel_love = 0
default shiro_love = 0
default kendal_love = 0
default sarah_love = 0
default molly_sex = 0
No init: required (at least for variable creation).


And finally... something I'm guessing at (because I see it all the time)...

Python:
define p = Character("p",color="##ff0000")
I'm guessing that p is your player character, and that somewhere further down the code you have something like...

Python:
    $ p = renpy.input("What is your name? {i}(Press ENTER for 'Sam'){/i}")
    $ p = p.strip()
    if p == "":
        $ p = "Sam"
IF you have done this... it'll sort of work... but it's wrong.
I bet you're wondering why you player character's name isn't red.

It's a common mistake and basically what's happening is that you use define to create a Character(): object called p. That character has a name, it has colors, it can be customized a lot with various parameters.

Then the code does a renpy.input() which completely destroys the original character variable and replaces it with a string of text. That string doesn't have any of the attributes that the Character(): had, and any customization you've tried to do will be lost.

IF (and as I say, I'm guessing)... if that is what you've done... this is what it should look like...

Python:
default player_name = "Unnamed"

define p = Character("[player_name]",color="##ff0000")

label start:

# maybe some intro first...

    $ player_name = renpy.input("What is your name? {i}(Press ENTER for 'Sam'){/i}")
    $ player_name = player_name.strip() or "Sam"

# the rest of your code...
This way you are separating the string which stores the name from the character object that uses it.
You can call the string variable anything you like... I just used player_name this time out of habit.

Sorry, I know that's a lot - but it's the only way I know how to explain stuff...
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,376
15,289
For example I just learned that there is something called "elif" in this thread, but I'm not quite sure yet what the rules are for its use.
Don't take it as a criticism, but you should perhaps stop working on your game for few weeks, and read Ren'py's documentation. It would really be a life changing thing and make your game easier to create.
I say that because, even if it don't goes deep in the details, the said documentation have a whole section dedicated to the structure.

You don't necessarily need to read the whole documentation, it's index is relatively explicit and you can see relatively easily what is important to read at first, and what can wait or while never be used by you. But really, reading it would be something helpful. And if there's something that you don't understand, or aren't sure to understand, you can still ask here.
 

ChaosOpen

Well-Known Member
Game Developer
Sep 26, 2019
1,013
2,133
stuff about variables
I didn't know that, I have watched the entire manual from start to finish and I do refer back to it every so often but that thing is dense with a lot of information, so it's hard to read it once and remember everything. Plus the examples they give don't always display exactly what I want to try. So, of it's like:
Lady- "If you type this, then this will happen?"
Me- "But what if I wanted to change it slightly for a similar albeit different effect?"
Lady- "Then don't, now sit down and shut up loser, you decided to be a history major in college rather than learning to code, you made your bed so lie in it."

So, instead I look at many of the other games people have made and when I see someone has implemented a feature I'd like to have in my game, I study it to try and apply it to my own. So, that's where my usage of dollar signs came from.

Either that or just fiddle with different things until I get the effect I want. For example, check out the sweet skills on my main menu:
Untitled.jpg

I'm still trying to come up with a solution for out-lining in-game text. What I'd like to do is get rid of the dialogue box entirely, as I think the dark rectangle is ugly as sin but lack the ability to do this:
external-content.duckduckgo.com.png

Seriously, that dialogue box looks like it smoothly fades from dark to white but after looking at it for hours and hours I can clearly see a line now my life has been a complete lie.

So, I figured I'd simply have text that is clearly visible on the screen would be a good alternative, I figured white text outlined in black would be a good solution, if the picture is too dark for black text they can read the white inside, if it is too bright for white text, they can see the black outline.

...but I can't figure out how to do that without also making it where it outlines the character names, which also uses the digital clock type font and looks hideous with a black outline.

Plus, I'm only 10% sure that would actually work.

stuff about names that was written by you but to save space lets just amend it.
I managed to create some weird hybrid bastardization.

Python:
$ p = renpy.input("I think I'll go with")
$ p = p.strip()
define p = Character(color="#00ff00")
I wasn't sure what was actually coloring p(protagonist) so I just left the define variable in there under the assumption. "It works now, lets not mess with it."

One thing I would like to mess with is getting rid of the affection altogether. Right now I'm using it as a stopgap for keeping track of which events the user has seen but that quick fix is quickly proving itself untenable. To understand how each works, the core plot is linear, while the girls are routes which you have the option of selecting at fixed points, which are limited, there are eight girls but you can only hang out with 1-3 girls per prompt, and I disabled the text log to 50 lines, which is more than enough if you're trying to reread something, but prevents the user from using the mouse wheel to roll all the way back to the decision. So, harsh decisions must be made.

So, I'd like to do four things:

-Make the option disappear after the user has seen it
-Limit it the number of choices they can see.(so, for example, they have 8 girls to choose from but can only see 2-3 events per day)
-As the story progresses narrow down the options so that you can only continue to advance their route if you've made it at least a specified amount of progress down the each girls story.
-Use true/false statements to keep track of the events rather than a hidden affection meter

In essence, I want it to be possible to lose the game. I don't want the wild and unpredictable choices you see in some novels, but if they try and play Don Juan and romance every girl choosing different girls every time the prompt comes up in the game they will lose as they will reach a point where they can't see any options.

The point is to do each girl in turn, focusing on one, then the next, then the next. Allowing you to romance several girls if you do it right, but with each girl having(a planned) 5 events and 2 H-scenes, then maybe some combo scenes if you select the right pair of girls.

Personality, I'd like to use true/false to let renpy know that the user has seen the previous event and would like to move on to the next.

I'd like to just put:
Code:
label hang_out
menu:
    "Who do you want to hang out with now?"
    "Emily":
        if emiliy_event_one == False:
            jump emily_event_one
        elif emiliy_event_one == True:
            jump emily_event_two
        elif emily_event_two == True:
            jump emily_event_three
        else:
            --something that will get rid of the option entirely--
So, basically, click the option and it takes them to the next event, if there are no more events, then the option disappears.

Problem I have, is I'm not quite sure how to inform renpy to keep track of whether the user has seen that label.

I'd like to say declaring at the beginning of the game:

default emily_event_one = False
default emily_event_two = False
default emily_event_three = False

then after each event I add:
$ emily_event_one = True

Problem is it seems to be temperamental, mostly due to my stupidity, as I don't understand it quite as well as I do menus or if statements.(Just because I didn't know that elif existed 24 hours ago doesn't mean I couldn't pump out a bangin' if/else statement) Plus, I don't know how to make the else statement to get rid of the choice once they have reached the maximum number of events, as I haven't attempted that before.

For example, I was getting rid of choices using this method. The first prompt gives you the ability to see all of the events, bringing all of the girls affection up to 1. So it looked like this:


Python:
menu:
    "I still need to talk to the other girls, who should I talk to?"

    "I'd like to speak with Emily" if emily_love == 0:
        jump emily_event_one
    "I'd like to speak with Karen" if karen_love == 0:
        jump karen_event_one
    "I'd like to speak with Claire" if claire_love == 0:
        jump claire_event_one
    "I'm done for the day":
        jump afternoon_continue
So, you can see how the option would disappear as each event is seen until all you're left with is "I'm done for the day."

Eventually, I'd like the choices to look more like this:

Python:
menu:
    "Who do you want to hang out with?"

    "Emily" if emily_event_two == True:
        if emily_event_three == False:
            jump emily_event_three
        elif emily_event_three == True:
            jump emily_event_four
        elif emily_event_four == True:
            jump emily_event_five
        else: ?

    "Claire" if claire_event_two == True:
        if claire_event_three == False:
            jump claire_event_three
        elif claire_event_three == True:
            jump claire_event_four
        elif claire_event_four == True:
            jump claire_event_five
        else: ?
I didn't want to extend that to the complete choice for all 8 girls, but you get the general idea.

It links them to the next choice no matter what progress they have made through but it doesn't display the choice unless they have seen event two. If they haven't, then the option never shows up.

But there are two things wrong with that:
a. There is no option to get rid of the choice once they have selected it and since all of the events would link back to the choice, a person could theoretically go through all 40 events in one sitting if they wanted to.
b. There is still no option to limit the number of choices.

c. In testing I tried changing the first choice to:
Python:
menu:
    "Who do you want to hang out with now?"
    "Emily": if emily_event_one == False
        jump emily_event_one
    "claire" if claire_event_one == False
        jump claire_event_one
    "Karen" if karen_event_one == False
        jump karen_event_one
    "I'm done for now."
        jump "continue_first_day"
and I got this:
qdcwsed.jpg
Is it possibly due to the events themselves being organized into a different file? For example, claire_event_one is located in claire_events.rpy while emily_event_one is located in emily_event.rpy while the main script is running in script.rpy

I've tried it several ways, I have cycled through all of the various definitions

default emily_event_one = False
define emily_event_one = False
$ emily_event_one = False
default emily_event_one == False
define emily_event_one == False
$ emily_event_one == False

all say "it is not defined."
 
Last edited:

moskyx

Forum Fanatic
Jun 17, 2019
4,005
12,961
Before someone else jumps here and gives you a comprehensive answer, I'll point out a couple of things.

If/elif/else order: ren'py will check the conditions from up to down. In this example you'll have another problem
Eventually, I'd like the choices to look more like this:

Python:
menu:
    "Who do you want to hang out with?"

    "Emily" if emily_event_two == True:
        if emily_event_three == False:
            jump emily_event_three
        elif emily_event_three == True:
            jump emily_event_four
        elif emily_event_four == True:
            jump emily_event_five
        else: ?

    "Claire" if claire_event_two == True:
        if claire_event_three == False:
            jump claire_event_three
        elif claire_event_three == True:
            jump claire_event_four
        elif claire_event_four == True:
            jump claire_event_five
        else: ?
Let's assume you can choose Emily because you went to event 2. Then Ren'py will check if you went to events 3 and 4. But if you went to both, Ren'py will redirect you to event 4 again because event 3 check is placed before event 4 check. So you should inverse the order, putting the last possible event in the first check. And you can get rid of the elifs and use just ifs. If Ren'py detects an elif, it checks the whole pile of conditional statements and then decide which one you'll follow. With simple ifs, Ren'py checks just one at a time, so if first is met it jumps to it and forgets about the rest.
Python:
menu:
    "Who do you want to hang out with?"

    "Emily" if emily_event_two == True:
        if emily_event_four == True:
            jump emily_event_five
        if emily_event_three == True:
            jump emily_event_four
        if emily_event_three == False:
            jump emily_event_three
      
       
    "Claire" if claire_event_two == True:
        if claire_event_four == True:
            jump claire_event_five
        if claire_event_three == True:
            jump claire_event_four
        if claire_event_three == False:
            jump claire_event_three

Also, you don't need to always add an else statement. Else is used for any other possible options you didn't check before. It's like the 'broom-wagon', if ren'py can't follow any previous "if" statement because conditions are not met, you'll get the "else". But if you have defined all possible options, you don't need the else.

Now, in order to get rid of a choice already selected, you can create another variable and do something like this:

Python:
default choose_Emily = False
default choose_Claire = False

menu:
    "Who do you want to hang out with?"

    "Emily" if emily_event_two == True and choose_Emily == False:
        $ choose_Emily = True
        if emily_event_four == True:
            jump emily_event_five
        if emily_event_three == True:
            jump emily_event_four
        if emily_event_three == False:
            jump emily_event_three
      
       
    "Claire" if claire_event_two == True and choose_Claire == False:
        $ choose_Claire = True
        if claire_event_four == True:
            jump claire_event_five
        if claire_event_three == True:
            jump claire_event_four
        if claire_event_three == False:
            jump claire_event_three
Note that the option(s) selected will have its flag set to true, so if you want to use this menu again later on, you'll have to set them back to False before calling the menu.
 

Saki_Sliz

Well-Known Member
May 3, 2018
1,403
1,005
Man, you guys are doing a lot of work and coding...

Time for me to give a not helpful answer! :D

Basically you guys are describing a system with multiple states, and multiple entry points (ie characters, character stats). With different dialog being made available, it is not an analog system, you guys are forced to be discrete, Hence why the butt-ton of if statements. A FSM or finite state machine is basically what you are working with (FSM is a graphical technic to map out this issue), but FSM are basically just a bunch of if statements and state tracker variables, so implementing one wouldn't solve the problem you are having.

The only solution that I know of is function pointers. I use them all the time and they're my favorite way of coding. From what I understand, Python tends to be a reference only language, handling data as pointers, but I don't know if it can point to functions, not to mention it looks like your guys's code is a hybrid between python and the renpy interpreter, so I don't even know if you would be able to handle things like pointer management.

A good example of function pointers are in C#, called delegates. Basically you have an variable that is also a function. This function can be the code for interacting with a character, but you can set this function variable to any other function, and by listing out multiple functions that represent different states of the relationship, you can just set the varible function to any of these other functions to be executed next time you interact with the character. If you have more function pointers inside of other functions being pointed at, the system becomes less discrete and more analog (aka small parts of the code are able to change and adapt without having to do a butt-ton of if statements). I'd give a good code example, but I actually need to leave now.
 
  • Like
Reactions: hiya02

ChaosOpen

Well-Known Member
Game Developer
Sep 26, 2019
1,013
2,133
Before someone else jumps here and gives you a comprehensive answer, I'll point out a couple of things.

If/elif/else order: ren'py will check the conditions from up to down. In this example you'll have another problem


Let's assume you can choose Emily because you went to event 2. Then Ren'py will check if you went to events 3 and 4. But if you went to both, Ren'py will redirect you to event 4 again because event 3 check is placed before event 4 check. So you should inverse the order, putting the last possible event in the first check. And you can get rid of the elifs and use just ifs. If Ren'py detects an elif, it checks the whole pile of conditional statements and then decide which one you'll follow. With simple ifs, Ren'py checks just one at a time, so if first is met it jumps to it and forgets about the rest.


Also, you don't need to always add an else statement. Else is used for any other possible options you didn't check before. It's like the 'broom-wagon', if ren'py can't follow any previous "if" statement because conditions are not met, you'll get the "else". But if you have defined all possible options, you don't need the else.

Now, in order to get rid of a choice already selected, you can create another variable and do something like this:

Note that the option(s) selected will have its flag set to true, so if you want to use this menu again later on, you'll have to set them back to False before calling the menu.
Is there going to be a problem with renpy keeping track of all of these viables? I've already got:
Python:
define chu = Character("Girl with Pink Highlights",color="#e473e7")
define clu = Character("Green haired girl",color="#00cc00")
define lu = Character("Long Haired Girl",color="#0099cc")
define su = Character("Pink Haired Girl",color="ff3399")
define mu = Character("Teacher",color="#cc9933")
define shu = Character("Girl",color="#ffffff")
define keu = Character("Dark Skinned Girl",color="#a52a2a")
define pu = Character("Myself",color="#ff0000")

define ch = Character("Chelsey", color="#e473e7")
define cl = Character("Claire", color="#00cc00")
define ka = Character("Karen",color="#ffff00")
define e = Character("Emily",color="#33cc99")
define l = Character("Lauren",color="#0099cc")
define s = Character("Sarah",color="#ff3399")
define m = Character("Molly",color="#cc9933")
define sh = Character("Shiro",color="#ffffff")
define ke = Character("Kendal",color="#a52a2a")
define na = Character ("Narration",color="#ff0000")

define et = Character("Emily's Thoughts",color="#33cc99")
define kat = Character("Karen's Thoughts",color="ffff00")
define mt = Character("Molly's Thoughts",color="#cc9933")

define ds = Dissolve(.6)
define dss = Dissolve(1.0)
define dsss = Dissolve(1.5)
define dssss = Dissolve(2.0)
define cumflash = Fade(0.2, 0.0, 0.2, color="#ffffff")
define longfade = Fade(1.0, 0.5, 1.0, color="#000000")
I'm stacking more and more and more crap seems like it's going to eventually begin to bog down the works.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,376
15,289
I'm still trying to come up with a solution for out-lining in-game text.
The style property.
Search the definition of the say_dialogue style in the screens.rpy file, and add :
Code:
    outlines [ ( 1, "#FF0000", 0, 0 ) ]
At the end of it. I use red as color for the example, use the one you want.


What I'd like to do is get rid of the dialogue box entirely, as I think the dark rectangle is ugly as sin but lack the ability to do this:
View attachment 751991
It's the say_window style. It's not explicitly defined, so you have to create it by yourself :
Code:
style say_window is window:
    background Solid( "#FF0000" )
Then you use whatever you want for the property. Once again I used red as example, but you are more looking for something like background Solid( "#00000050" )


Seriously, that dialogue box looks like it smoothly fades from dark to white but after looking at it for hours and hours I can clearly see a line now my life has been a complete lie.
Launch the game, start it, put the mouse cursor over the dialog box (but not over the text), then press SHIFT+i. You'll open the style inspector, that will give you the name of the style used, here "say_window" as I said. And if you click on the style name, you'll see its values and inheritance.


Python:
$ p = renpy.input("I think I'll go with")
$ p = p.strip()
define p = Character(color="#00ff00")
No, no, no. It works, but only because of a miracle.
What this code do is :
  • Create a variable named p that is a Character object.
  • Reassign a value to the variable named p that is now a string.
Or, said otherwise, it's like if you replaced a wheel of your car by a book. It will works most of the time because there's still 3 other wheel, but time to time, boom...
What you want is :
Code:
define p = Character( "[pName]", color="#00ff00")

label whatever:
    $ pName = renpy.input( "What's your name ?", default="Marc" ).strip().capitalize()
     [...]


-Make the option disappear after the user has seen it
It's the role of the .
Code:
define girlsMenuSet = set()

label whatever:
    menu:
        set girlsMenuSet
        "Karen":
            [...]
        "Girl 1":
            [...]

label nextDay:
    $ girlsMenuSet = set()

-Limit it the number of choices they can see.(so, for example, they have 8 girls to choose from but can only see 2-3 events per day)
Code:
define girlsMenuSet = set()
define girlsSeen = 0

label whatever:
    menu:
        set girlsMenuSet
        "Karen":
            [...]
        "Girl 1":
            [...]

    $ girlsSeen += 1
    if girlsSeen < 3:
        jump whatever
    jump somewhereElse

label nextDay:
    $ girlsMenuSet = set()
    $ girlsSeen = 0
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,223
Is there going to be a problem with renpy keeping track of all of these variables? I've already got:
<snip>
RenPy: Not even slightly.
You: Well, that kinda depends on you.

So far, what you've described is tiny.
If you're already already feeling a little overwhelmed, that might be a sign you need to think about making your game simpler, until such time as you're more confident.

RenPy would not have a problem with 100x the number of variables and definitions you've already got. 1000x even.
The only upper limit I've ever seen developers come up against is the overall size of their game when trying to create an android port. Even then, it's invariably about the number and size of the images, rather than the size or complexity of the code.

The only real bottleneck is the programmer. Even then, it's largely about experience rather than logical thinking. People simply try too hard and the fun gets sucked out of writing the game.

A dev might create a variable called visited_uncles_house, which is fine - until you need to track a 2nd visit to the uncle's house. An experienced dev might have realized before they started that you'd end up going there more than once and called the first variable visited_uncles_house_ch1 (chapter 1, if that makes sense) and so adding a visited_uncles_house_ch3 is easy. Whereas an inexperienced dev might not think ahead and just add a visited_uncles_house2. Both will work, but the 2nd example isn't exactly clear and so harder to keep track of in your head while you're writing chapter 9.

I realize a lot of devs want to include lots of features. They may even think them necessary to attract paying customers. But if it's all feeling a bit difficult... scale things back a bit and write a game you're likely to have fun writing. Even if that ends up being a kinetic novel (no player choices). Learn some stuff as you go along, then write your 2nd game using the stuff you've learned - including the stuff you dropped from the first game.

... I'm not saying all that applies to you. I'm just saying your replies so far trigger this train of thought in me.

I'm stacking more and more and more crap seems like it's going to eventually begin to bog down the works.
Maybe. But RenPy will be fine with it. The rest is on you.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,376
15,289
The only upper limit I've ever seen developers come up against is the overall size of their game when trying to create an android port. Even then, it's invariably about the number and size of the images, rather than the size or complexity of the code.
There's also few cases where the game reached the memory size limit for Python (2 GB for Ren'py). But it was with codes that stored way too much things and generally stored them literally ; things like $ choice1 = "Peek to your mother in the bathroom", in place of something like $ peekedMomBathroomDay1 = True that would have used less memory.
But it's really exceptional, and few games really need more than 100 KB for their variables.
 
  • Like
Reactions: 79flavors