Welcome to the sponsor-exclusive content for the Ren'Py Patreon. Sponsors like you ensure this page exists. Thank you.

_images/wiki-burr.png

In-Game Wiki-Like Glossary or Codex link

One of the Ren’Py customizations I’ve been asked about more than a few times is something called a glossary or codex. This is an area of the game, usually part of the main menu or game menu, where the player can go to see definitions of terms used in the story - everything from the 1920s slang in The Blind Griffin to the various forms of Kravte magic in the Fault series.

Working on Ren’Py 6.99.13, I made a few changes to how hyperlinks work, and I realized that these changes now make it possible to create a Wiki-like glossary or codex. This means one with hyperlinks between screens that take the player from topic to topic.

These examples require Ren’Py 6.99.13, which is still under development, to work. You can try them on a nightly build (from https://nightly.renpy.org/), or wait for the final release.

Our First Screen link

Our example wiki uses Ren’Py’s screen system, with one screen per topic. It’s meant to use the new GUI, which is the default in 6.99.13. We use multiple screens so we can add elements on a screen-by-screen basis.

Here’s our first screen.

screen wiki_weehawken():

    tag menu

    use game_menu(_("Weehawken, New Jersey")):

        text _p("""
            Among other things, Weehawken was the side of the Weehawken dueling grounds,
            where duels were fought from the 1700s to the 1840s. For example, this is where
            {a=showmenu:wiki_burr}Aaron Burr{/a} shot {a=showmenu:wiki_hamilton}Alexander Hamilton{/a}.

            {a=showmenu:wiki_index}Back to Index{/a}
            """)

This can go in any .rpy file you choose. If you only have a small number of wiki entries, it can go at the end of screens.rpy. Otherwise, it might make sense to create a wiki.rpy file.

The first line gives the name of the screen, wiki_weehawken, and indicates that it does not take any parameters. The tag menu tells Ren’Py that this screen is part of the main or game menus, and should replace any other screen in those menus when it is called up.

The use game_menu(_("Weehawken, New Jersey")): line is also part of the main or game menus. It displays the navigation and title, and sets up the content area where the rest of the text can go. It takes as an argument the title, enclosed inside the _() function that marks it as a string that can be translated.

The text line is where all the real action is, as it has three concepts some creators might not be familiar with.

Working from the inside out, we have the newly improved a text tag, which is of the form {a=protocol:value}text{/a}. We call the part of the link before the value the protocol, since until recently it was almost always http or https to take the player to a website. In Ren’Py 6.99.12, new protocols have been introduced. The jump and call protocols jump to and call labels, while the show and showmenu protocols show screens. It’s also possible to define custom protocols for your own use.

In our example, we use the showmenu protocol. It’s equivalent to the ShowMenu() function, which is used to show a screen on the main or game menus. This means that when a link is clicked, Ren’Py will show the named screen. Since both screens are part of the main or game menus, the current screen is hidden.

The second concept is triple-quoted strings, which are strings that start and end with three quotes (“””). These are a part of Python that can be used in Ren’Py init blocks, screens, and other places where Python is accepted. The advantage of a triple-quoted string is that it can span multiple lines, and contain single quotes.

Finally, we have the new _p function. This function might have a small name, but it’s a big deal. It takes the text in triple quotes and reformats it into a sensible paragraph. It does this by removing whitespace at the start and end, and the start and end of every line. The text is broken up into paragraphs on empty lines. The {p} text tag introduces a line break, and otherwise lines are separated by spaces.

The result of this is, I think, a fairly straightforward wiki entry with minimal boilerplate.

More Wiki Screens link

Of course, a single screen won’t do us much good - it will cause an error when clicking a link, as there’s no place to go to. So here are the rest of the screens in our little wiki:

define config.hyperlink_protocol = "showmenu"

screen wiki_hamilton():

    tag menu

    use game_menu(_("Alexander Hamilton")):

        text _p("""
            Alexander Hamilton was a Patriot and the first treasury secretary of
            the United States. He was killed in a duel with {a=wiki_burr}Aaron Burr{/a}
            in {a=wiki_weehawken}Weehawken, New Jersey{/a}.

            {a=wiki_index}Back to Index{/a}
            """)


screen wiki_burr():

    tag menu

    use game_menu(_("Aaron Burr")):

        text _p("""
            Aaron Burr was the third Vice President of the United States. But all anyone
            remembers him for nowadays is shooting {a=wiki_hamilton}Alexander Hamilton{/a}.

            {a=wiki_index}Back to Index{/a}
            """)

screen wiki_index():

    tag menu

    use game_menu(_("Wiki Index")):

        vbox:
            text _p("""
            • {a=wiki_burr}Burr, Aaron{/a}{p}
            • {a=wiki_hamilton}Hamilton, Alexander{/a}{p}
            • {a=wiki_weehawken}Weehawken, New Jersey{/a}{p}
            """)

Defining config.hyperlink_protocol saves us a little bit of typing, as it tells Ren’Py which protocol to use when no protocol is given. Other than that, these screens are all short and very similar to the first one.

Accessing the Wiki link

One way of accessing the wiki is to make it available through the navigation screen in screens.rpy. Here’s the navigation screen with the new line added:

screen navigation():

    vbox:
        style_prefix "navigation"

        xpos gui.navigation_xpos
        yalign 0.5

        spacing gui.navigation_spacing

        if main_menu:

            textbutton _("Start") action Start()

        else:

            textbutton _("History") action ShowMenu("history")

            textbutton _("Save") action ShowMenu("save")

        textbutton _("Load") action ShowMenu("load")

        textbutton _("Preferences") action ShowMenu("preferences")

        if _in_replay:

            textbutton _("End Replay") action EndReplay(confirm=True)

        elif not main_menu:

            textbutton _("Main Menu") action MainMenu()

        textbutton _("Wiki") action ShowMenu("wiki_index")

        textbutton _("About") action ShowMenu("about")

        if renpy.variant("pc"):

            ## Help isn't necessary or relevant to mobile devices.
            textbutton _("Help") action ShowMenu("help")

            ## The quit button is banned on iOS and unnecessary on Android.
            textbutton _("Quit") action Quit(confirm=not main_menu)

The new line is the one mentioning the wiki. It’s also possible to access the wiki from a link inside the game:

l "That {a=wiki_hamilton}Alexander Hamilton{/a} is a swell guy. I hope he becomes President one day."

show lucy mad

l "Why are you looking at me like that?!"

Locking Articles link

Of course, it’s possible for some articles in your game’s wiki to contain spoilers that you don’t want players to read until after a certain point. In this case, we can define our own hyperlink protocol that checks to see if an article is locked. Defining a new protocol has to be done in Python. Here’s how it’s done:

default persistent.wiki_unlocked = { "wiki_index" }

init python:

    def locked_handler(target):
        renpy.run(ShowMenu(target))

    def locked_sensitive(target):
        return target in persistent.wiki_unlocked

    config.hyperlink_handlers["locked"] = locked_handler
    config.hyperlink_sensitive["locked"] = locked_sensitive

define config.hyperlink_protocol = "locked"
define gui.hyperlink_text_insensitive_color = gui.insensitive_color

The default line creates the set of unlocked articles, stored in the game’s persistent, so that an article unlocked once will be unlocked in future playthroughs. Since we’ll want the index to always be available, it’s unlocked by default.

The locked_handler function defines what happens when a link beginning with locked: is clicked. In this case, it opens a screen, just like showmenu: links did above.

The locked_sensitive function determines when a locked: link is clickable. In this case, it’s only clickable when the screen is categorized in persistent.wiki_unlocked.

The next two lines update the dictionaries that associate the functions with the locked protocol.

Finally, the two define lines at the end change the default protocol to be “locked”, and set the color of insensitive links to be the same as that of insensitive buttons.

To unlock an article, add it to the set by placing a line like this in the appropriate part of your story script:

$ persistent.wiki_unlocked.add("wiki_hamilton")

Once it’s added, all links to the article will become clickable the next time they are shown.