Revamping the Your Dry Delight glossary code and community events planned for the weekend
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.
Your Dry Delight glossary
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.run(ShowMenu("glossary"))
renpy.restart_interaction()
return
# read the glossary.csv
def read_glossary():
# for every language, open the appropriate glossary_language file
for l in glossary_dict.keys():
f = renpy.file("glossaries/glossary_"+l+".csv")
lines = f.readlines()
# skip the header row
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)
# Add the glossary data that you just read into the
# game's glossary for accessing later
store.glossary_dict[lang][key] = ge
# run the read_glossary() function to read in the glossary data
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
tag menu
if main_menu:
add "gui/mainmenu.jpg"
# this is the definition of the word once selected
use glossary_single
# this is the navigation containing all the words that you can open
use glossary_menu
# set the glossary scrollbar so that when you switch between words, the scrollbar
# resets to the top of the definition
default glosssary_scroll_value = ui.adjustment()
screen glossary_single():
# the screen with the info after someone clicks a word to show the definition
add "gui/menu.png"
add "gui/glossary_title.png"
imagebutton:
idle "gui/clickoff.png"
hover "gui/clickoff.png"
action [Return(), Function(hide_nav), Hide("glossary_single"), Hide("glossary_menu"), Hide("glossary"),Hide("navigation"),Hide("menu")]
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 = ""
tag menu
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
yadjustment glosssary_scroll_value
# 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
use navigation
screen glossary_menu():
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"
Questions or Comments?
Feel free to send in any AG-related questions! Our Ask Box is always open.
Q: This may be too early to ask but for the potential new VN competition idea, would you all consider only people with experience and with a finished script or would it be open to people with a concept and at least an outline as well?
A: If you have a concept and an outline, and you can provide evidence that you are able to see the project through and complete the script, then you would be a good fit for applying to the competition. There will be more information on the specifics and details required from outlines, as well as general specs for designs (max number of characters, backgrounds, etc.)!
Thanks so much for all of your amazing support, and stay safe out there!