Book of Lore#

Since we know how to point and click in Ren’Py, why don’t we apply that knowledge to making a Book of Lore?

(All the scripts and pictures of this chapter can be downloaded here. Hyperlinks will not work! To get them working, see the next tutorial!)

We’ll manage data structures (the system of articles) and we’ll create browsing navigation, including history with Back and Forward buttons and tooltips:

Lore Dictionary#

First we’ll need data, such as articles for our lorepedia. I put them in a separate file (articles.rpy) to manage future expansion easily, though it’s not a requirement:

default articles = {
    "Anarchs":
        """
        Anarchs are {a}vampires{/a} who reject the status quo
        of {a}Cainite{/a} society.

        They especially resent the privileged status held
        by {a}elders{/a} within the {a}Camarilla{/a} and other vampire
        sects.
        """,
    "Brujah":
        """
        The Brujah are one of the thirteen {a}clans{/a} of
        {a}Kindred{/a}.

        Prominent members of Brujah belonged to the
        {a}Camarilla{/a}, the {a}Sabbat{/a}, and the {a}Anarchs{/a}.
        """,
    "Camarilla":
        """
        The Camarilla is the most organized of the
        vampiric {a}sects{/a}, an elite club that favours
        tradition and control of the mortal populace
        from behind the scenes.

        Due to recent events many of Camarilla {a}elders{/a}
        don't let {a}Anarchs{/a}, {a}Caitiff{/a}, or {a}thin-blooded{/a}
        vampires settle in their Domains.
        """,
    "":
        """
        {i}Unknown term.{/i}

        I need to learn more about this topic.

        {a}Back{/a}
        """,
    }

We have the data as a dictionary (Python dict), where article titles serve as keys and article texts as values. There is also an article with the empty title. It will serve as placeholder for terms that player doesn’t know yet.

Lore Function#

We’ll have a set viewed to store titles that player have seen, so that we could highlight titles with new information.

(More on that in the next part of the tutorial.)

To navigate with back and forward buttons, we’ll have a list lore_history, initially empty, to append the titles of visited articles to that list.

Variable lore_hist_n will be the index of currently shown title in that list. Usually it will be -1, which means “first from the end”, i.e. the last item in the list. But when we click “Back” button, we’ll move to the previously visited article, and lore_hist_n will become -2.

This way we could always know which article is “previous” in the navigation history and which is “next”.

To show an article from Book of Lore, we’ll call function lore::

default viewed = set()
default lore_history = [ ]
default lore_hist_n = -1

init python:
    def lore(topic, history=0):
        if history:
            store.lore_hist_n += history
            topic = store.lore_history[store.lore_hist_n]
        elif topic:
            store.viewed.add(topic)
            if store.lore_hist_n < -1:
                del store.lore_history[store.lore_hist_n+1:]
                store.lore_hist_n = -1
            if not store.lore_history or store.lore_history[-1] != topic:
                store.lore_history.append(topic)
                store.lore_hist_n = -1

        if renpy.get_screen("lorepedia"):
            renpy.hide_screen("lorepedia")
            renpy.show_screen("lorepedia", topic)
        else:
            renpy.call_screen("lorepedia", topic)

This function can be called in two ways:

  • If parameter history is not zero, then it’s an integer commanding to jump back or forward in navigation history. E.g. if it’s -1, it means “show the previous article in the navigation history”. And if it’s 1, likewise, it means “show the next article”.

  • If parameter history is zero, then parameter topic will be used, to show the article with that title. We’ll add that title to the set viewed, and manage the navigation history:

    • If there are items in “Forward” history, we’ll delete them.

    • We’ll add the current title as the newest navigated item.

After all the data has been managed, function lore calls screen “lorepedia” with the title of the article to show as the parameter.

Lore Screen#

Screen “lorepedia” has two main areas:

  • A scrollable Viewport on the left, with “history navigation” imagemap and buttons for every article.

  • An article area on the right, to display the contents of the current article.

The viewport is made thusly:

screen lorepedia(titel):
    add "bg_lorepedia"
    viewport:
        area (0, 0, 340, 1080)
        scrollbars "vertical"
        mousewheel True
        draggable True
        style_prefix "lore"
        vbox:
            imagemap auto "btn_lore_%s.webp":
                xysize (300, 90)
                hotspot (0, 0, 100, 90):
                    action Function(lore, None, -1)
                    sensitive (len(lore_history)+lore_hist_n > 0)
                    if len(lore_history)+lore_hist_n > 0:
                        tooltip lore_history[lore_hist_n-1]
                hotspot (100, 0, 100, 90):
                    action Return()
                hotspot (200, 0, 100, 90):
                    action Function(lore, None, 1)
                    sensitive (lore_hist_n < -1)
                    if lore_hist_n < -1:
                        tooltip lore_history[lore_hist_n+1]

            for a in articles:
                if a:
                    button:
                        xysize (300, 90)
                        if len(a) > 15:
                            text a size 24
                        elif len(a) > 11:
                            text a size 28
                        else:
                            text a
                        action Function(lore, a)

First, look how the navigation imagemap works:

_images/btn_lore_hover.webp

The hotspot in the middle (“exit”) just returns from the screen:

hotspot (100, 0, 100, 90):
    action Return()

The hotspot on the left (“Back”, or “Previous”), is sensitive only when there are articles visited before the current one:

hotspot (0, 0, 100, 90):
    action Function(lore, None, -1)
    sensitive (len(lore_history)+lore_hist_n > 0)
    if len(lore_history)+lore_hist_n > 0:
        tooltip lore_history[lore_hist_n-1]

The tooltip shows the title of that “previous” article.

Likewise, the hotspot on the right (“Forward”), is sensitive only when we returned back in navigation history, so that there are articles “forward”:

hotspot (200, 0, 100, 90):
    action Function(lore, None, 1)
    sensitive (lore_hist_n < -1)
    if lore_hist_n < -1:
        tooltip lore_history[lore_hist_n+1]

The rest of the viewport contents is simple: just article titles from dict articles, shown on buttons. (If the length of the title is large, it’s shown with reduced font sizes.)


The rightmost area of the screen “lorepedia” shows the article’s contents:

frame:
    area (360, 0, 1520, 1080)
    padding (40, 4)
    background "#0008"

    if renpy.can_show(titel.lower()):
        add titel.lower() xalign 1. ypos 60

    text titel style "lore_title" at gradient_v

    if titel in articles:
        text articles[titel] style "lore_article"
    else:
        text articles[""] style "lore_article"

Here with function renpy.can_show() we check if there is an image named as the article’s title, converted to lowercase. In that case the image is shown in the top-right corner. For example, if article is named “Camarilla”, an image “camarilla” will be shown, if exists.

Finally, if requested article does not exist in dict articles, then the placeholder text will be shown for that title.

_images/unknown_term.webp

The screen also shows tooltips (see Example):

$ tooltip = GetTooltip()

if tooltip:

    nearrect:
        focus "tooltip"
        prefer_top False

        frame:
            background "#904"
            xalign 0.5
            text tooltip style "tooltip"

Conclusion#

Here’s the last part of the main script, showing the usage of the Book of Lore:

label start:
    $ _confirm_quit = False
    "What do you know about {a}Caitiff{/a}?"
    window hide
    $ lore("Caitiff")
    "So, nothing?.. Well, let me tell you a story that happened—"
    return

# Credits:
# Frame https://mollycat2020.picmix.com
# Blood Splatter https://www.freeiconspng.com/img/44472
# Lore Pictures: Vampire The Masquerade, fair use (educational)

Apart from these scripts, I created separate files styles.rpy with styles and hyperlink.rpy (which we’ll develop more later, in chapter Hyperlinks). All the files of this tutorial can be downloaded, placed in a new Ren’Py 8 project (overwriting the original contents) and run. (Hyperlinks will not work! To get them working, see the next tutorial.)

Have fun!