How to show the quick menu with an animation when you click a button

# Events

We have several activities planned for this week!

• First community event of the year, happening on Friday! The event takes place in Discord, and more information will be released throughout the week in #events. Just know that the activity will be a collaborative artwork created over the course of 24 hours!
• Saturday @ 0730PST/1030EST we have our weekly dev stream
• Saturday @ 1700PST/2000EST we will have a game stream. We’ll be posting a list of games to play, and you can cast votes for what order to play them in.

The YDD glossary code was initially an ugly hack that used different screens for when you clicked on a word from the dialogue and when you looked it up in the glossary. While it worked, it was not pretty.

It was especially bad when we went to get YDD translated. To get that working, we had to append _language to every screen, make sure the translator knows how to add the _language to the translations, and duplicate the screen. If the translator wanted to add or remove words, then that would require adding extra conditionals to the sidebar with the list of words to ensure the wrong words in the wrong languages didn’t get all mixed up. The end result was 2 large glossary files per language that was difficult to debug for typos or strange behavior.

With the most recent language update, we decided to redo the glossary code to make it easier for future translations and just generally adding entries to a glossary (DMR’s glossary will be updated too). The glossary data is all stored in an external csv-like file, and then at the start of the game, we read the file and dynaimcally generate the glossary. For each language, we create a glossary.csv file. It has columns: language, key, entry, and definition. Language is unnecessary now, but it was originally created to have all the glossaries for every language combined into a single file. The key is for programming purposes; spaces are one of the greatest evils for coding, so we need a version of the word without any spaces (e.g. kid_gloves for “Kid gloves”). The key is also used to determine the order of the entries in-game. The word list is alphabetically ordered, so if there is a particular order that another language wants their words in, they can easily adjust that. The entry is the word to look up in the glossary, and the definition is the word’s (or phrase’s) meaning.

The code for reading in the glossary:

init 5 python:
# define a dictionary for each language to hold all the glossary entries for each language
glossary_dict = {"french":{},"english":{},"russian":{},"chinese_simp":{}}

# create a glossary entry class just for data management.
# not necessary if you just want to use anonymous tuples
# but we enjoy objects
class GlossaryEntry():
def __init__(self, entry, definition):
self.entry = entry
self.definition = definition

# when you click a word in dialogue to look it up in the dictionary,
# open the glossary and show the word and its entry
def set_glossary_entry_on_show(entry_key):
store.active_entry=entry_key

# if you are keeping track of whether the player has seen the word before
# persistent.__dict__[entry_key]= True

renpy.transition(dissolve)
renpy.restart_interaction()
return

# for every language, open the appropriate glossary_language file
for l in glossary_dict.keys():
f = renpy.file("glossaries/glossary_"+l+".csv")
lines = lines[1:]
col = 0
# for every line in the file
for line in lines:
# split the line by the delimiter. Usually in a csv we use
# a comma (csv = comma separated values),
# but we use commas in normal text, so we have to use
# some other delimiter. Choosing | is an arbitrary decision.
# You can use any other delimiter as long as it doesn't interfere
# with splitting the file up into different columns
cols = line.split('|')

lang = cols[0]
key = cols[1]

# Get rid of the extra \ when reading the file so that you
# can have separate paragraphs in the word definition.
# Decode utf-8 characters so you can read non-ascii characters
# like Chinese and Russian
entry = cols[2].replace("\\n","\n").decode('utf-8')
definition = cols[3].strip("\r\n").replace("\\n","\n").decode('utf-8')

# Create a new glossary entry object to hold the data
ge = GlossaryEntry(entry,definition)
# game's glossary for accessing later
store.glossary_dict[lang][key] = ge

read_glossary()

The Ren’Py screen code for actually accessing the glossary in-game

screen glossary():
# This is the glossary that is accessible via the side menu
zorder 199
modal True

# this is the definition of the word once selected
use glossary_single
# this is the navigation containing all the words that you can open
# set the glossary scrollbar so that when you switch between words, the scrollbar
# resets to the top of the definition

screen glossary_single():
# the screen with the info after someone clicks a word to show the definition
imagebutton:
idle "gui/clickoff.png"
hover "gui/clickoff.png"
xpos 0
ypos 0
modal False

# if the glossary has just been opened, then we don't want to display an entry's information
if store.entry_data is None:
$store.entry_data = "" if store.entry_definition is None:$ store.entry_definition = ""
zorder 200
style_prefix "entry"
vbox:
ysize 320
# the entry that was clicked on
label store.entry_data  xpos 610  ypos 140 xalign 0.0 xsize 300
viewport id "entry_vp":
mousewheel True
draggable True
xpos 610
ypos 159
xsize 300
# the definition of the entry that was clicked
text store.entry_definition
vbar value YScrollValue("entry_vp") xpos 922 ypos 131 ymaximum 361 base_bar "gui/scrollbar/vertical_idle_bar.png" thumb "gui/scrollbar/vertical_idle_thumb.png" thumb_offset 21  top_gutter 25  bottom_gutter 15 right_gutter 20 left_gutter 10 xsize 42

zorder 205
# when we first open up the glossary, we don't want an entry to already be showing
$store.active_entry = None # make sure we open the english dictionary entries if we are in english if _preferences.language is None:$ entry_lang = "english"
else:
$entry_lang = _preferences.language # if the player has selected an entry, then we should update the screen # to display the information for the selected entry if store.active_entry is not None:$ store.entry_data = glossary_dict[entry_lang][store.active_entry].entry
$store.entry_definition = glossary_dict[entry_lang][store.active_entry].definition$ glossary_keys_sorted = sorted(glossary_dict[entry_lang].keys())
$lang_dict = glossary_dict[entry_lang] vbox: xpos 318 ypos 140 xsize 210 ysize 346 spacing 23 viewport id "g_list": mousewheel True draggable True vbox: style "list_text" spacing 13 # dynamically create the list of words in the glossary for k in glossary_keys_sorted:$ v = lang_dict[k]
textbutton v.entry action [SetVariable("store.active_entry",k),\
SetVariable("store.entry_definition",v.definition),\
SetVariable("store.entry_data",v.entry),\
Function(glosssary_scroll_value.change,0)] text_color "#262118" text_size 24 text_hover_underline True text_selected_idle_underline True text_idle_underline False
# textbutton glossary_dict[key].name action [SetVariable("store.active_entry",key),SetScreenVariable("entry_definition",glossary_dict[key].name),SetScreenVariable("entry_data",glossary_dict[key].entry)] text_idle_color "#1d1818" text_selected_idle_color "#818181" text_hover_color "#818181"