Building off of the information in the previous tutorial on variables, this guide will walk you through using conditional statements in your game. You will be able to do things like change dialogue, customize menu choices, and branch the game down different paths. There is also a quiz to test your knowledge of conditionals.
I recommend you start with A Quick Primer on Variables in Ren’Py to learn about variables first. This guide also assumes you have a basic idea of how to write choice menus. If you need a quick refresher, you can check out Menus, Labels, and Jumps in the Ren’Py quickstart.
Conditionals
What’s a Conditional?
A conditional, or a conditional statement, is code that tells the computer whether to do something based on the outcome of a particular expression.
In simpler terms, sometimes in your day-to-day life you need to make decisions like “if it’s raining outside, then I’ll bring my umbrella” (and if it isn’t raining outside, then you won’t bring an umbrella). We call this if/then-style of decision making a conditional.
In code, a conditional allows you to change what code is executed (run by the computer, so it shows in-game) based on some kind of condition (like “if it’s raining outside”). The condition itself (“if it’s raining outside”) is known as an expression, which is evaluated, or checked, to determine if it’s True or False. If the expression evaluates to True
, then the code associated with it will run. If it evaluates to False
, then it is skipped.
For example, the process of evaluating the expression “if it’s raining outside” would involve going outside or looking to see if it is indeed raining. If so, then the expression is True, as in, yes, it is True that it is raining outside. As a result, you should bring your umbrella with you (since “if it’s raining outside” (True) “then I’ll bring my umbrella”).
Term list
The if
Statement
The if
statement is the most basic way of writing conditionals in Ren’Py. In its simplest form, it looks like the following:
if <expression>:
<result>
An in-game example of this might look like:
if went_to_store:
"You didn't buy anything, though."
You might recognize this from the previous tutorial on variables. went_to_store
is a boolean, that is, it is either True
or False
. If it is True
, then the line below it should run. If it’s False
, then this line should be skipped over so the player doesn’t see it.
In Ren’Py and Python, spacing is crucial to tell the computer what code belongs together. You might notice that in the above example, the line underneath if went_to_store:
is four spaces to the right. This is called indentation. By default, Ren’Py uses four spaces for each level of indentation. So, the line “You didn’t buy anything, though.” is indented one level to the right, because it is 4 spaces (one level) to the right of the line above it.
This indentation tells Ren’Py that the line “You didn’t buy anything, though.” belongs to the line before it, if went_to_store:
. Anything that is indented underneath if went_to_store:
will only be seen in the case that went_to_store
is True
.
This is important because it forms something known as a block, which is what we call a chunk of code indented under a line with a colon. So, for example, all of these lines are part of the same block:
if watched_tv:
"You turned on the TV and browsed through some shows."
"You found one that seemed interesting and watched the first episode."
"Then you went to sleep."
jump went_to_sleep
This is because they are all indented one level to the right underneath the if watched_tv:
line.
If the player didn’t watch TV, they won’t see any of these lines, nor will they jump to the label went_to_sleep
, because all those lines are indented under the if watched_tv:
statement, and the player did not watch TV.
If we wanted both players who watched TV and those who didn’t to eventually end up at the same went_to_sleep
label, we could do something like:
if watched_tv:
"You turned on the TV and browsed through some shows."
"You found one that seemed interesting and watched the first episode."
"Then you went to sleep."
jump went_to_sleep
In this case, the last line jump went_to_sleep
is not part of the previous block, because it is no longer indented underneath it. So, a player who chose to watch TV will see all three lines of dialogue and then jump to the label went_to_sleep
, but a player who doesn’t watch TV will immediately jump to the label went_to_sleep
, since jump went_to_sleep
isn’t part of the if watched_tv:
condition block, and watched_tv
is False, so the lines indented after if watched_tv:
will be skipped.
You’ve actually already seen blocks before if you’ve been using menus. This is because menus look like:
"At the mall, you decided you wanted to buy Ashwin something."
menu:
"Buy them a bath bomb.":
$ gift = "bath bomb"
"Buy them a self-help book.":
$ gift = "self-help book"
"Buy them a digital camera.":
$ gift = "digital camera"
Everything is indented at least one level underneath the menu:
line to indicate that the next lines are part of a particular choice menu. Then, each choice ends with a :
and has its own block as well to indicate what should happen if the player chooses that choice. So, you should indent the things that should happen if the player makes a particular choice one level further underneath the choice itself.
Term list
else
and elif
else
When making a decision, sometimes there are several options. For example, consider the following situation:
You’re deciding what to wear today. If it’s warm outside, you’ll wear a t-shirt. Otherwise, you’ll wear a sweater.
In this case, something happens regardless of whether the condition (it’s warm outside) is true or not. If it’s not warm outside, you still need to wear something. It doesn’t matter if it’s just cool outside or if it’s freezing cold, just that it isn’t warm enough to wear a t-shirt.
This is where we can use the else
clause of the if
statement which was explained earlier. else
can be translated to “if nothing else in this statement was true, then do this”. In practice, it looks like this:
if warm_outside:
"You put on a t-shirt before leaving the house."
else:
"You put on a sweater before leaving the house."
In this case, if the boolean variable warm_outside
is True
, then the dialogue will read “You put on a t-shirt before leaving the house.”.
If it’s not warm_outside
(warm_outside
is False
), then the dialogue will read “You put on a sweater before leaving the house.”.
else
doesn’t take any more specific expressions, so there’s no such thing as
# Incorrect 1
if warm_outside:
"You put on a t-shirt before leaving the house."
else cold_outside: # Wrong! Will cause an error.
"You put on a sweater before leaving the house."
else
is just a catch-all for anything that didn’t evaluate to True in the previous checks. Which leads into the next point – that you can check for several different situations before you get to an else
clause.
elif
Consider the following:
You’re deciding what to eat for supper. If the local Thai restaurant is open, you want to buy food from there. If it’s not, you’ll try the pizza place next door. But if neither of those options work out, then you’ll just make yourself a grilled cheese sandwich.
There are a few things that should happen here. First, we have to check if the Thai restaurant is open. Assuming the status of the Thai restaurant is stored in a True/False boolean like thai_restaurant_open = False
, then we could start by making a statement like:
default thai_restaurant_open = False
label start:
if thai_restaurant_open:
"You ate some Thai food for dinner."
If the Thai restaurant isn’t open, though, we then need to check if the pizza place is open. Let’s say that whether the pizza place is open or not is stored in the variable pizza_place_open = False
.
Now, using the building blocks we know about so far, you might try something like this:
if thai_restaurant_open:
"You ate some Thai food for dinner."
else:
# We'll put something here?
This is on the right track! The else
will happen whenever thai_restaurant_open
is False
. In fact, you can nest conditional statements inside of each other like
default thai_restaurant_open = False
default pizza_place_open = False
label start:
if thai_restaurant_open:
"You ate some Thai food for dinner."
else:
if pizza_place_open:
"You ate some pizza for dinner."
Now if the Thai restaurant isn’t open, we go to the else
clause. There, we have another conditional, if pizza_place_open:
. If that’s True, the dialogue says “You ate some pizza for dinner.”
So in the current code, if thai_restaurant_open
is True
, then the player eats Thai food and the game will skip the code that’s indented under else
since our initial condition, if thai_restaurant_open
, is True
. So, the player will see the dialogue “You ate some Thai food for dinner.”
Otherwise, if thai_restaurant_open
is False
(the restaurant isn’t open), then we’ll go to the else
line. There, we have a new check for if pizza_place_open:
. If the pizza place is open, then the player will see the dialogue “You ate some pizza for dinner.”
We’re not done yet, though – currently if neither the Thai restaurant nor the pizza place are open, we want to say that you ate grilled cheese. That can go in the else
clause after the if pizza_place_open:
condition:
# Solution 1
if thai_restaurant_open:
"You ate some Thai food for dinner."
else:
if pizza_place_open:
"You ate some pizza for dinner."
else:
"You ate some grilled cheese for dinner."
There! Now we have a conditional statement which does what we’d outlined above – if the Thai restaurant is open, you eat Thai food. If it’s not open, but the pizza place is open, then you eat pizza. If the Thai restaurant is closed and the pizza place is closed, then you eat grilled cheese.
Note also that if the Thai restaurant is open, it doesn’t matter whether the pizza place is open or not. Since else
translates to “do this only if nothing else before this check is True”, when the Thai restaurant is open, Ren’Py doesn’t even bother to look at the code under the else
clause, since the first expression was True.
The else
is also important to make sure this conditional flows properly. For example, consider the following:
# Incorrect 2
if thai_restaurant_open:
"You ate some Thai food for dinner."
if pizza_place_open:
"You ate some pizza for dinner."
else:
"You ate some grilled cheese for dinner."
At first glance, this seems all right – if the Thai restaurant and the pizza place aren’t open, you eat grilled cheese. If the Thai place isn’t open but the pizza place is, then you eat pizza.
However, it’s important to notice that this example has two separate conditional statements. The first one is if thai_restaurant_open:
, and the second is if pizza_place_open:
. Since they are independent of one another, Ren’Py will check both regardless of the outcome of any previous checks.
The reason why this doesn’t happen in our earlier Solution 1 is because the second conditional statement, if pizza_place_open:
, is nested inside the else
clause of the if thai_restaurant_open
. If the first expression is True
– that is, if thai_restaurant_open
– then Ren’Py doesn’t execute any code in the else
clause, including our second if pizza_place_open
check, because it’s inside of the else
clause. So, the whole if pizza_place_open
code is just skipped.
Meanwhile, in Incorrect 2, if pizza_place_open
is a separate conditional statement, and it isn’t inside the else
clause of the conditional with if thai_restaurant_open
. Ren’Py will check it regardless of the outcome of if thai_restaurant_open
. Thus, when the Thai restaurant is open, you’ll see dialogue that you ate Thai food. However, since these are two separate conditional statements, the game will also check whether pizza_place_open
is True. If it is, then it will also show the line “You ate some pizza for dinner”. If it isn’t, it will also show the line “You ate some grilled cheese for dinner”. But if the Thai restaurant is open, we don’t want to eat pizza or grilled cheese! If we got Thai food, it shouldn’t matter whether the pizza place is open or not, which is why you need to make it part of the same conditional via else
OR elif
, which is a short form for else if
that we’ll discuss below.
So our actual solution, which didn’t have the problem earlier with the pizza place being open at the same time as the Thai restaurant, looks like this:
# Solution 1
if thai_restaurant_open:
"You ate some Thai food for dinner."
else:
if pizza_place_open:
"You ate some pizza for dinner."
else:
"You ate some grilled cheese for dinner."
But of course, let’s say we had more conditions – like “if the pizza place isn’t open, then get ice cream from the ice cream stand. And if that’s not open either, then try the sushi place”. This could quickly turn into something long and ugly like:
# Temporary Solution 1
if thai_restaurant_open:
"You ate some Thai food for dinner."
else:
if pizza_place_open:
"You ate some pizza for dinner."
else:
if ice_cream_stand_open:
"You ate some ice cream for dinner."
else:
if sushi_place_open:
"You ate some sushi for dinner."
else:
"You ate some grilled cheese for dinner."
Obviously having so many if/else
conditions nested inside each other is a bit hard to follow. Luckily, there’s a special clause to simplify this, known as elif
. As mentioned before, it’s short for else if
, and will simplify the above conditional into:
# Solution 2
if thai_restaurant_open:
"You ate some Thai food for dinner."
elif pizza_place_open:
"You ate some pizza for dinner."
elif ice_cream_stand_open:
"You ate some ice cream for dinner."
elif sushi_place_open:
"You ate some sushi for dinner."
else:
"You ate some grilled cheese for dinner."
Much cleaner! This also does not suffer from the problem earlier with the two separate if
statements in the Incorrect 2
example, because the elif
clauses are all part of the same conditional. An elif
clause will only run if nothing before it evaluated to True, and like an else
clause, it must come after an if
statement and can’t exist on its own.
The logic is as follows:
- If the Thai restaurant is open, show the line “You ate some Thai food for dinner.” We found one condition in the entire conditional statement that’s True already, so we skip all of the
elif
s and theelse
and proceed with the rest of the game. - Otherwise, if the Thai restaurant isn’t open, check if the pizza place is open. If it is, show “You ate some pizza for dinner.” and skip all the rest of the
elif
/else
clauses. - Otherwise, if both the previous two places weren’t open, check if the ice cream stand is open. If it is, show “You ate some ice cream for dinner.” and skip the rest of the
elif
/else
clauses. - Otherwise, if none of the previous three places were open, check if the sushi place is open. If it is, show “You ate some sushi for dinner.” and skip the
else
. - Finally, if everything we previously checked was
False
(all the restaurants were closed), show the line “You ate some grilled cheese for dinner.”
Similarly, the more succinct version of our original Solution 1
is:
# Improved Solution 1
if thai_restaurant_open:
$ dinner = "Thai food"
elif pizza_place_open:
$ dinner = "pizza"
else:
$ dinner = "grilled cheese"
Summary
All conditional statements will take one of the following forms:
if
statement only, no other checks:
if <expression>:
<result>
e.g.
"You decided to go to the park."
if owns_dog:
"You took your dog with you on a leash."
"On such a nice day, the birds were singing brightly."
In this case, only a player who has a dog (owns_dog
is True) will see the line “You took your dog with you on a leash.” Players who don’t will simply move on to the next line, “On such a nice day…”
if
accompanied by one or more elif
clauses
if <expression>:
<result>
elif <expression>:
<result>
# can add more elif clauses
e.g.
"You started to feel hungry."
if made_soup:
"The soup you made earlier sounded tasty."
elif ordered_takeout:
"You thought you might have some leftovers from yesterday's takeout."
"You walked over to your fridge to peek inside."
In this case, the choices are more-or-less flavour text; if the player didn’t make soup or order takeout, then they’ll still go to the fridge and look inside. There’s no else
clause here, so if neither of the expressions are True (they didn’t make soup or order takeout), they just go to the fridge. This if
/elif
structure also prevents both lines of dialogue from playing one after the other; while it’s possible the player both made_soup
and ordered_takeout
, we only want one of the flavour text variations to display, and it would sound unusual if the player saw both “The soup you made earlier sounded tasty” and “You thought you might have some leftovers from yesterday’s takeout” back-to-back.
if
accompanied by an else
clause
if <expression>:
<result>
else:
<result>
e.g.
if got_food_poisoning:
"You shook your head, unable to go anywhere while your insides felt like the center of a volcano."
jump stay_at_home
else:
"Fireworks sounded really fun! You nodded enthusiastically."
jump go_to_fireworks
In this case, two very separate things should happen if the player did or didn’t get food poisoning – either they have to stay at home, or they’ll go out to watch some fireworks. The else
clause takes care of anything that wasn’t covered by the if
statement, so in this case, in the case that the player didn’t get food poisoning, they can go to the fireworks.
if
accompanied by some elif
clauses and an else
if <expression>:
<result>
elif <expression>:
<result>
# Can add more elif clauses
else:
<result>
e.g.
"It was a good summer, all things considered."
if shared_ice_cream:
"You" "Remember how I let you try some of my ice cream?"
elif went_boating:
"You" "You almost fell overboard when we were out on the lake and saw a swan."
elif had_sleepover:
"You" "I was so tired the day after our sleepover."
else:
"You" "We sure made some good memories."
"Ash" "I wish summer didn't have to end."
Note that you can have as many elif
clauses as you like – one, two, zero, seventy-four (though at that point you might want to consider restructuring how you’re handling so many situations!), or however many you need. There’s only ever one if
, at the start, and one else
, optionally, at the end.
In this example, the player might have done several activities over their summer vacation, and in the wrap-up, they can reminisce about one of the memories. They shouldn’t be able to mention every memory that happened all in a row, just the most important one that the player completed. These events aren’t mutually exclusive – all of them might have happened, or none of them – so an if
/elif
/else
structure lets us organize which event is the most important to mention.
Next Steps
Now that you know how to use conditionals to direct the flow of the game, in the next part (Simple Variable Types in Ren’Py) we’ll look into some more types of variables so you can begin to keep track of more complex information. Before that, though, you can test your understanding of conditional statements with a short quiz: Conditionals Quiz.