Loops (Ren'Py)

Ren'Py script has a single looping construct: the while loop. It executes the body of the loop until the condition is False. It is typically used in the following way:
Note: Python itself has a much more complete set.


    while thereIsStuffToDo:
        call doSomeStuff()

For the loop to end, whatever is in doSomeStuff() has to eventually cause the condition thereIsStuffToDo is to become False.

Here's an example where there's a menu inside the while loop. It allows the player to search a room for clues until they've had enough:


default keyFound = False
default pageFound = False

label study:
    $ renpy.dynamic('done')
    "You respectfully enter your grandfather's study. The room still
    smells the same as it always did."
    $ done = False
    while not done:
        menu:
            "{alt}Menu. {/alt}Where do you want to look?"
            "Search desk":
                if pageFound:
                    "You carefully search the desk again but don't find
                    anything else that's interesting."
                else:
                    "You carefully search the desk and under the blotter
                    you find a curious page of parchment covered in symbols."
                    $ pageFound = True
            "Check under rug":
                if keyFound:
                    "You look under the old rug again but don't find
                    anything else."
                else:
                    "You lift to corner of the old rug and find a small
                    brass key."
                    $ keyFound = True
            "Leave":
                $ done = True
    "You leave the study and close the door behind you."
    return

The done is local to this subroutine, and initially set to False allowing the loop to run (if it had been True to begin with the whole menu would have been skipped). Making it local means that study can be called from inside another loop using a variable with the same name. The only way done can be set to True is if the player chooses the "Leave" menu option.

The variables keyFound and pageFound are global to the story. Presumably they have some relevance elsewhere: a box that can now be opened or a conversation with an NPC. If the player returns to this room they can search more, and possibly find items they didn't look for the first time.

This raises some questions:

These are really questions about game design rather than coding. In classic parser-based Interactive Fiction there is no menu so the player isn't prompted to necessarily search scenery objects like the desk or the rug. A visual novel's menus make this more obvious and removes this particular challenge. Arguably this is better design for a more modern age. The search could be replaced by a "hidden-object" puzzle game if you wanted to restore some difficulty.

Another way

It is possible to do the same with just jumps, but it's not nearly as clean, and I wouldn't recommend it:


default keyFound = False
default pageFound = False

label study:
    "You respectfully enter your grandfather's study. The room still
    smells the same as it always did."
label .loop:
    menu:
        "{alt}Menu. {/alt}Where do you want to look?"
        "Search desk":
            if pageFound:
                "You carefully search the desk again but don't find
                anything else that's interesting."
            else:
                "You carefully search the desk and under the blotter
                you find a curious page of parchment covered in symbols."
                $ pageFound = True
        "Check under rug":
            if keyFound:
                "You look under the old rug again but don't find
                anything else."
            else:
                "You lift to corner of the old rug and find a small
                brass key."
                $ keyFound = True
        "Leave":
            jump .leave
    jump .loop
label .leave:
    "You leave the study and close the door behind you."
    return