Equality Comparisons in Ren’Py

Equality Comparisons in Ren’Py

Now that you know how to write conditional statements using if/elif/else with booleans (see Conditional Statements in Ren’Py) and several basic variable types (see Simple Variable Types in Ren’Py), let’s look into the different things you can compare so that you can write complex branching paths in your game.

There is also a quiz to test your knowledge of comparisons, with additional questions combining the information in this tutorial and the earlier parts on conditionals and simple variables to check your understanding of these concepts.

Difficulty Level: Beginner

As this tutorial builds off of information in the previous ones, it’s recommended you take a look at those before tackling this one. 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 the section on Menus, Labels, and Jumps in the Ren’Py quickstart.

Comparisons

What are Comparisons?

comparison  is a way of comparing two or more values in a game. Typically at least one of the values you’re comparing is a variable, so you can use the result of this comparison to do things like change dialogue or branch off in an entirely new direction.

Informally, in your program you might want to do things like:

  1. If the player has at least 8 affection points with Xia, she’ll ask them on a date
  2. If the player has 10 or more bad end points, they get the bad end. If they have less than 10 bad end points but more than 0, they get the normal end. Otherwise, they get the good end.
  3. If the player bought Ashwin a digital camera and they’re on a date in the park, show a line of dialogue where they take a picture of the fountain.
  4. If the player is carrying a life jacket or they made it to the top of the ship in time to get in a life boat, they survive.
  5. If the player gave Zoran the book Pride & Prejudice and has at least 5 trust points with Zoran, Zoran will share a story from his childhood.
  6. If the player has enough money, they can buy a flower.

You can see the if/else-style structure to these sorts of statements like we covered in Conditional Statements in Ren’Py, but the comparisons have more things to check than just one value which is True/False (for example, needing to check more than one value in 3, 4, and 5, or comparing numbers in 1, 2, and 6).

Checking if two values are the same

Sometimes, you might want to check something like “if the player bought Ashwin a digital camera”. If you recall from the last tutorial on simple variables, we had a section of code that looked like:

default gift = None
label start():
    "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"
    "Later that day, you were able to give them the [gift] you bought earlier."
    "They liked it a lot."

In this case, gift is equal to one of “bath bomb”, “self-help book”, or “digital camera”. This isn’t a boolean, so if we want to know specifically if the player bought Ashwin the digital camera, we can’t do if gift: because that just checks if gift has some not-false value (this is explained further in the section on Truthy/Falsey values).

So, informally, we want to know: is the value of gift equal to "digital camera"?

In Ren’Py (and in most programming languages), the way to check this is with two equals signs like ==:

if gift == "digital camera":
    "Ashwin took out the camera you gave them earlier to take a picture of the fountain."

It’s very important to note that it’s two == and not just one = for comparison. A single = is only for setting a variable, like with $ gift = "digital camera" where you are giving the variable gift a value of “digital camera”. Two == let you compare variables, like checking if gift currently has the value “digital camera”. Comparison does not change the current value of the variable.

As you might recall from the guide to simple variables, you generally should NOT do this kind of exact comparison for  floats  aka numbers with decimal points. So while the following code won’t cause an error, it may not perform as you expect:

$ money = 10.00
if money == 10.00: # Bad; floats aren't exact
    jump go_to_market

Instead, you’ll use numerical comparisons for floats, described in Numerical Comparisons and Combinations in Ren’Py.

However, it’s fine to use == to compare between values like integers and strings, such as:

default num_cookies = 1
label start:
    menu:
        "Give Zoran a cookie.":
            $ num_cookies -= 1
        "Don't give Zoran a cookie.":
            "You declined to give Zoran a cookie."
    if num_cookies == 1:
        "You decided to eat a cookie yourself."
    else:
        "You wished you had something to eat."

or as seen above, if gift == "digital camera":.

Note that comparing strings is  case-sensitive, that is, "digital camera" is NOT the same as "Digital Camera" which is NOT the same as "DIGITAL CAMERA". Spacing also matters – if you have a stray space at the end of a string, for example, it won’t match a string without that space e.g. "Xia " is NOT the same as "Xia" without the extra space. There are string utility functions to help with this, such as strip() and lower(), so you can make more accurate comparisons. We’ll talk about those in a later tutorial on strings. For now, just keep in mind that capital letters in your strings are important, as two strings with different capitalizations are not the same.

You typically should not use == when comparing with booleans like True or False e.g. if ate_apple == True. For more on that, see the section on “Truthy” versus “Falsey”.

Places where you should use ==

  • When comparing against an integer e.g. if num_game_wins == 2
  • When comparing against a string e.g. if xia_job == "book store"

Places where you shouldn’t use ==

  • When comparing against a float e.g. if grade == 0.9 (Bad! Don’t use exact comparisons with floats, since decimal numbers may have slight rounding errors)
  • When comparing against a boolean value e.g. if went_home == True or if owns_cat == False (poor style and may not be what you want; see Truthy vs Falsey)
  • If you’re trying to set a variable (setting uses one = e.g. $ xia_job = "doctor" or default ash_gift = "bath bomb")

Checking if two values are different

Besides ==, you might also want to know if two values are not equal. There are two primary ways of checking for this, depending on what kind of value you’re comparing against.

The first way is with !=, which stands for “not equal”. In many programming languages, ! means “not”, so in this case, ! (not) = (equal) -> !=

As with ==, this is a good comparison to use for strings and integers, but not for floats or booleans. So, you could do something like:

default mood = "neutral"
label start():
    "Now, at the end of a long day, you were feeling..."
    menu:
        "Happy":
            $ mood = "happy"
        "Exhausted":
            $ mood = "tired"
        "Sad":
            $ mood = "sad"
        "Just okay":
            $ mood = "neutral"
    if mood != "happy":
        "Ash" "Hey, are you feeling all right?"
        "Ash" "I know it was a pretty long day."

If the player isn’t feeling good at the end of the day, Ashwin should check up on them. But there are multiple different “negative” feelings they might have – they might be sad, or maybe just tired or even neutral. Instead of having a check for each possible feeling that leads to this dialogue, we can just check if the player isn’t happy with if mood != "happy".

You can use this comparison for integers as well, such as:

default mistakes = 0
default xia_job = "doctor"
label start():
    "Xia" "So what's my favourite colour, then?"
    menu:
        "Yellow.":
            pass
        "Blue.":
            $ mistakes += 1
    "Xia" "And my job?"
    menu:
        "Doctor.":
            if xia_job != "doctor":
                $ mistakes += 1
        "Librarian":
            if xia_job != "librarian":
                $ mistakes += 1
    if mistakes != 0:
        "Xia" "Looks like you don't know me as well as you think you do!"
    else:
        "Xia" "Hmm, probably made the questions too easy..."

We have a few instances of comparisons here. In the choice menu about Xia’s job, we check to see what her job actually is before adding points to the mistakes variable. If the player says “Doctor” when xia_job is not "doctor", then they answered wrong so the number of mistakes increases, and the same goes for Xia being a librarian.

Then, at the end, if the player made a mistake (so mistakes is not equal to 0), Xia tells them they don’t know her as well as they think. Otherwise, she wonders if her questions were too easy.

Another way to write this last conditional statement is:

if mistakes == 0:
    "Xia" "Hmm, probably made the questions too easy..."
else:
    "Xia" "Looks like you don't know me as well as you think you do!"

As with ==, the use cases for != are very similar:

Places where you should use !=

  • When comparing against an integer e.g. if remaining_cookies != 1
  • When comparing against a string e.g. if ash_gift != "digital camera"

Places where you shouldn’t use !=

  • When comparing against a float e.g. if grade != 1.0 (Bad! Don’t use exact comparisons with floats)
  • When comparing against a boolean value e.g. if went_home != True or if owns_cat != False (poor style and may not be what you want; see Truthy vs Falsey)

Not

You might remember that when we’ve been using booleans (True/False), to check if they’re True we just do

if thai_restaurant_open:

What if you want to check if it’s False instead (as in, the restaurant is NOT open)? Luckily, there’s a very special key word called not which can be used like:

if not thai_restaurant_open:

In more plain language, you can read it like “if the Thai restaurant is not open” or “if the expression “the Thai restaurant is open” is not true”. The expression if not thai_restaurant_open will evaluate to True if thai_restaurant_open is False – it’s kind of like a double-negative. If something is not False, then it must be True.

So, you could do something like:

default thai_restaurant_open = False
default pizza_place_open = False
label start:
    if thai_restaurant_open:
        "You ate some Thai food for dinner."
    elif pizza_place_open:
        "You ate some pizza for dinner."
    else:
        "You ate some grilled cheese for dinner."

    if not thai_restaurant_open:
        "It was too bad the Thai restaurant was closed, though."
        "You had definitely been hungry for Thai food."
    "Now that you were full, it was time for bed."

The player will see the extra lines of dialogue under if not thai_restaurant_open only if the Thai restaurant was not open (so, $ thai_restaurant_open = False somewhere in the script earlier).

Truthy versus Falsey

So this whole time I’ve been saying that it’s better to just write if pizza_place_open and if not pizza_place_open when checking boolean values. But a boolean isn’t inexact like a float is, so why is it better not to use ==, as in, if thai_restaurant_open == True?

The most important reason is that if went_to_park and if went_to_park == True are not the same thing! Explaining why involves two concepts called “Truthy” and “Falsey”.

Hopefully you’re feeling more comfortable now with the idea of True and False, and how to check for them with conditional statements like if not pizza_place_open and if player_ate_apple. You’ve also seen several variable types now, like integers, strings, and floats, besides just booleans.

Every variable type has a particular value which is considered “False” if you use it in a conditional statement as if it were a boolean. This is called a “Falsey” value, since it may not be exactly equal to the specific value False, but it still isn’t “True”. Anything that isn’t “Falsey” is “Truthy” instead, and will evaluate to True in a conditional statement.

  • For booleans, False is Falsey, and True is Truthy (as you would expect)
  • For integers, the number 0 is Falsey. Negative numbers like -1 are Truthy, not Falsey. 0 is the only number which is Falsey, and everything else is Truthy.
  • For floats, same thing: 0.0 (or 0 with arbitrary decimal points e.g. 0.000000000) is Falsey. Any other number, no matter how large, small, or negative, is Truthy.
  • For strings, the empty string (a string with nothing in it, not even a space i.e. "" or '') is Falsey. A string with anything in it, one character or many, is Truthy, even if it’s something like "False" or "0" because it’s a string which has a word in it so it isn’t empty.
  • The special value None is Falsey.

So what does it even mean if something is “Falsey” or “Truthy”? Well, it explains how those values will be evaluated in a conditional statement like if not x or if x.

So, let’s look at the following example:

# Example 1
default gift = ""
label start:
    if gift:
        "You gave Zoran a [gift]."
    else:
        "You hadn't bought anything, so you just waved at Zoran."

Here, gift starts with a default value of "", which is the empty string because it doesn’t have anything in it (inside the quotes). We can then check it as if it was a boolean, with if gift:. This checks if gift is a “Truthy” value, and in this case because gift is a string, it checks if the string is empty or not.

The behaviour of the conditional would also be the same if we had done:

# Example 1b (Not as good)
default gift = False
label start:
    if gift:
        "You gave Zoran a [gift]."
    else:
        "You hadn't bought anything, so you just waved at Zoran."

However, it’s better practice to do something like default gift = "" if gift will later be set to a string like "camera". This is because there are many places in coding where the type of the variable matters, particularly if you’re doing any kind of comparisons or calculations with them, and you could get an error or an unexpected result if you tried to compare between, say, a boolean and a string. In fact, in many coding languages other than Python, it’s impossible to mix-and-match variable types – if you declare a variable is a string, you can’t later set it to False.

Note, however, that the following is NOT the same as Example 1:

# Incorrect 1
default gift = ""
label start:
    if gift == True:
        "You gave Zoran a [gift]."
    else:
        "You hadn't bought anything, so you just waved at Zoran."

if gift == True is specifically checking if gift is equal to the programming value True. Similarly, if gift != False is specifically checking if gift is not equal to the programming value Falseif gift == True won’t be true for any string value of gift, not "cake" or "" or "True" (as a string), only True. We can see this if we substitute the actual value of gift into the statement – "cake" == True is False, "True" == True is False, "" == True is False, True == True is True.

If there was a menu earlier to decide on a gift, we can follow the flow of the conditional statement:

default gift = ""
label start:
    "You decided to buy Zoran..."
    menu:
        "A bouquet of daffodils.":
            $ gift = "bouquet of daffodils"
        "A hand-made apron.":
            $ gift = "hand-made apron"
        "Nothing.":
            $ gift = ""
    "Zoran spied you across the marketplace and jogged over."
    if gift:
        "You gave Zoran a [gift]."
    else:
        "You hadn't bought anything, so you just waved at Zoran."

Here, if the player buys Zoran a bouquet of daffodils or a hand-made apron, they will see the line where they give Zoran a gift. It doesn’t matter specifically what the gift was in order to show the line – a player who bought a bouquet of daffodils will see “You gave Zoran a bouquet of daffodils” and a player who bought a hand-made apron will see “You gave Zoran a hand-made apron”. Later, because we have the gift’s name stored inside gift, we can change the dialogue or story based on what specific gift he was given. Meanwhile, a player who didn’t buy a gift will see the line “You hadn’t bought anything, so you just waved at Zoran.”, because gift is the empty string "", which is Falsey, so they see the line under the else clause.

It’s also very important to remember that == True and == False aren’t the same as if x and if not x when it comes to checking things like persistent variables, which begin with the default value NoneNone is a “falsey” value, but it is not the exact value False, which leads to many common errors.

In summary, each variable type can be evaluated as if it were a boolean via if x or if not x-style conditional statements. If the variable would evaluate as if it was True, it is “Truthy”. If it would evaluate as if it was False, it is “Falsey”. Comparisons like if x == True are only correct/True if x is the exact boolean value True, but if x covers a wider range of situations and can be used to both shorten your code and make it more readable. It is considered good coding practice to use if x and if not x instead of == True or == False, even when working with booleans, and can help prevent unintentional errors.

Summary

Before the quiz, let’s go over the new comparison types we learned and how they’re used in-game:

Comparing if two values are the same

if x == y:
  • Note the two == (one = is only for setting a variable; two for comparing)
  • This is True only if x and y have the exact same value
  • Good for comparing integers and strings
  • Not good for comparing floats and booleans

Comparing if two values are different

if x != y:
  • ! means “not” as in “not equal” !=
  • This is True for every case unless x and y are the exact same value
  • Good for comparing integers and strings
  • Not good for comparing floats and booleans

not

if not x:
  • If x is a “truthy” value, if not x is False
    • e.g. if x is one of "hello"-45, or True, then not x is False
  • If x is a “falsey” value, if not x is True
    • e.g. if x is one of ""0, or False, then not x is True
  • Can be used for all variable types, but should especially be used for booleans

Next Steps

As usual, there is a quiz to test your knowledge of the topics covered in this tutorial: Equality Comparison Quiz. If you’d like a bit of bonus information on booleans and strings, you can take a look at Booleans vs Strings before moving on to Numerical Comparisons and Combinations in Ren’Py.

Leave a Reply