[renpy] 01/04: New upstream version 6.99.14.3+dfsg

Markus Koschany apo at moszumanska.debian.org
Thu Apr 12 23:14:15 UTC 2018


This is an automated email from the git hooks/post-receive script.

apo pushed a commit to branch master
in repository renpy.

commit fab6c79689bc0eb762101d7c348dd38cf82a570c
Author: Markus Koschany <apo at debian.org>
Date:   Fri Apr 13 00:57:25 2018 +0200

    New upstream version 6.99.14.3+dfsg
---
 atom/Atom.edit.py                              |  85 +++
 gui/game/gui.rpy                               |   2 +
 gui/game/screens.rpy                           |   2 +
 launcher/game/editor.rpy                       |  78 ++-
 launcher/game/front_page.rpy                   |   5 +-
 launcher/game/gui7.rpy                         |   7 +-
 launcher/game/itch.rpy                         |   4 +-
 launcher/game/navigation.rpy                   |   2 +
 launcher/game/options.rpy                      |  27 +-
 launcher/game/package_formats.rpy              |   2 +-
 launcher/game/project.rpy                      |   4 +
 launcher/game/tl/piglatin/common.rpy           | 268 ++++++-
 launcher/game/tl/piglatin/developer.rpy        |  10 +-
 launcher/game/tl/piglatin/launcher.rpy         | 184 ++---
 launcher/game/tl/piglatin/screens.rpy          | 234 +++----
 launcher/game/tl/russian/common.rpy            | 278 +++++++-
 launcher/game/tl/russian/developer.rpy         |  10 +-
 launcher/game/tl/russian/error.rpy             |  78 +--
 launcher/game/tl/russian/launcher.rpy          | 178 ++---
 launcher/game/tl/russian/obsolete.rpy          |  27 +
 launcher/game/tl/russian/screens.rpy           | 232 +++---
 launcher/game/translations.rpy                 |   1 -
 renpy/__init__.py                              |   2 +-
 renpy/ast.py                                   |  58 +-
 renpy/atl.py                                   |  17 +-
 renpy/audio/music.py                           |   3 +
 renpy/character.py                             |   3 +
 renpy/common/000statements.rpy                 |  60 +-
 renpy/common/000window.rpy                     |  13 +-
 renpy/common/00action_file.rpy                 |  22 +-
 renpy/common/00action_other.rpy                |   7 +-
 renpy/common/00build.rpy                       |   1 +
 renpy/common/00gui.rpy                         |   6 +-
 renpy/common/00library.rpy                     |  83 ++-
 renpy/common/00nvl_mode.rpy                    |  44 +-
 renpy/common/00preferences.rpy                 |  95 ++-
 renpy/common/00start.rpy                       |   4 +
 renpy/common/00updater.rpy                     |   7 +-
 renpy/common/00voice.rpy                       |  11 +-
 renpy/common/_developer/developer.rpym         |   7 +-
 renpy/config.py                                |   6 +
 renpy/defaultstore.py                          |   1 +
 renpy/display/behavior.py                      |  68 +-
 renpy/display/core.py                          |  26 +-
 renpy/display/im.py                            |   8 +-
 renpy/display/image.py                         |  16 +-
 renpy/display/layout.py                        |  53 +-
 renpy/display/screen.py                        |  25 +-
 renpy/display/swdraw.py                        |   3 +
 renpy/display/video.py                         |  48 +-
 renpy/dump.py                                  |   9 +-
 renpy/editor.py                                |  10 +-
 renpy/execution.py                             |  17 +-
 renpy/exports.py                               |  32 +-
 renpy/main.py                                  |  18 +-
 renpy/persistent.py                            |   2 +-
 renpy/python.py                                | 136 +++-
 renpy/screenlang.py                            |  19 +-
 renpy/script.py                                |   2 +
 renpy/sl2/slast.py                             | 140 ++--
 renpy/sl2/slparser.py                          |  15 +-
 renpy/statements.py                            |  12 +-
 renpy/text/font.py                             |  23 +-
 renpy/translation/__init__.py                  |  59 +-
 renpy/translation/generation.py                |   4 +
 renpy/ui.py                                    |   4 +-
 renpy/vc_version.py                            |   2 +-
 renpy/warp.py                                  |  69 +-
 sphinx/game/doc.py                             | 191 +++--
 sphinx/source/changelog.rst                    | 139 ++++
 sphinx/source/credits.rst                      |   3 +
 sphinx/source/displayables.rst                 |  32 +-
 sphinx/source/gui.rst                          |   4 +
 sphinx/source/incompatible.rst                 |   6 +-
 sphinx/source/keywords.py                      |   6 +-
 sphinx/source/movie.rst                        |  21 +-
 sphinx/source/multiple.rst                     |  16 +-
 sphinx/source/nvl_mode.rst                     |   5 +
 sphinx/source/sponsors.html                    | 206 +++---
 sphinx/source/text.rst                         |   2 +-
 templates/portuguese/game/options.rpy          | 355 ++++------
 the_question/game/screens.rpy                  |   2 +
 the_question/game/tl/russian/common.rpy        | 805 ++++++++++++++++-----
 the_question/game/tl/russian/options.rpy       |   3 +-
 the_question/game/tl/russian/screens.rpy       | 172 ++---
 the_question/game/tl/russian/script.rpy        |  34 +-
 tutorial/game/01example.rpy                    |  17 +
 tutorial/game/indepth_minigame.rpy             |   2 +-
 tutorial/game/keywords.py                      |   6 +-
 tutorial/game/screens.rpy                      |   3 +
 tutorial/game/script.rpy                       |   3 +
 tutorial/game/tl/piglatin/common.rpy           | 276 +++++++-
 tutorial/game/tl/piglatin/indepth_minigame.rpy |   6 +-
 tutorial/game/tl/piglatin/screens.rpy          | 130 ++--
 tutorial/game/tl/piglatin/script.rpy           |  12 +-
 tutorial/game/tl/russian/01example.rpy         |   4 +-
 tutorial/game/tl/russian/common.rpy            | 929 +++++++++++++++++--------
 tutorial/game/tl/russian/indepth_minigame.rpy  |   4 +-
 tutorial/game/tl/russian/screens.rpy           | 130 ++--
 tutorial/game/tl/russian/script.rpy            |  12 +-
 100 files changed, 4487 insertions(+), 2037 deletions(-)

diff --git a/atom/Atom.edit.py b/atom/Atom.edit.py
new file mode 100644
index 0000000..e0ecacb
--- /dev/null
+++ b/atom/Atom.edit.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# The path to a copy of Atom that's been installed globally, if one exists.
+# This is overidden by RENPY_ATOM, if set. If either is given, that is used
+# and no special handing of the .atom directory is performed.
+ATOM = None
+
+import sys
+import os
+import subprocess
+import platform
+import shutil
+
+import renpy
+
+
+class Editor(renpy.editor.Editor):
+
+    has_projects = True
+
+    def get_atom(self):
+        """
+        Returns the path to the atom executable, if None. Also takes care
+        of setting up the .atom directory if it's not available.
+        """
+
+        atom = os.environ.get("RENPY_ATOM", ATOM)
+
+        if atom is not None:
+            return atom
+
+        DIR = os.path.abspath(os.path.dirname(__file__))
+
+        if renpy.windows:
+            atom = os.path.join(DIR, "atom-windows", "atom.exe")
+        elif renpy.macintosh:
+            atom = os.path.join(DIR, "Atom.app", "Contents", "Resources", "app", "atom.sh")
+        else:
+            atom = os.path.join(DIR, "atom-linux-" + platform.machine(), "atom")
+
+        default_dot_atom = os.path.join(DIR, "default-dot-atom")
+        dot_atom = os.path.join(DIR, ".atom")
+
+        if not os.path.exists(dot_atom) and os.path.exists(default_dot_atom):
+            shutil.copytree(default_dot_atom, dot_atom)
+
+        return atom
+
+    def begin(self, new_window=False, **kwargs):
+        self.args = [ ]
+
+    def open(self, filename, line=None, **kwargs):
+
+        if line:
+            filename = "{}:{}".format(filename, line)
+
+        self.args.append(filename)
+
+    def open_project(self, project):
+        self.args.append(project)
+
+    def end(self, **kwargs):
+
+        atom = self.get_atom()
+
+        self.args.reverse()
+
+        args = [ atom ] + self.args
+        args = [ renpy.exports.fsencode(i) for i in args ]
+
+        subprocess.Popen(args)
+
+
+def main():
+    e = Editor()
+    e.begin()
+
+    for i in sys.argv[1:]:
+        e.open(i)
+
+    e.end()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/gui/game/gui.rpy b/gui/game/gui.rpy
index d891277..8c00e0f 100644
--- a/gui/game/gui.rpy
+++ b/gui/game/gui.rpy
@@ -227,6 +227,8 @@ define gui.slot_button_borders = Borders(gui.scale(10), gui.scale(10), gui.scale
 define gui.slot_button_text_size = gui.scale(14)
 define gui.slot_button_text_xalign = 0.5
 define gui.slot_button_text_idle_color = gui.idle_small_color
+define gui.slot_button_text_selected_idle_color = gui.selected_color
+define gui.slot_button_text_selected_hover_color = gui.hover_color
 
 ## The width and height of thumbnails used by the save slots.
 define config.thumbnail_width = gui.scale(256)
diff --git a/gui/game/screens.rpy b/gui/game/screens.rpy
index 34e9ed7..9ef3b26 100644
--- a/gui/game/screens.rpy
+++ b/gui/game/screens.rpy
@@ -442,6 +442,7 @@ screen game_menu(title, scroll=None, yinitial=0.0):
                         scrollbars "vertical"
                         mousewheel True
                         draggable True
+                        pagekeys True
 
                         side_yfill True
 
@@ -457,6 +458,7 @@ screen game_menu(title, scroll=None, yinitial=0.0):
                         scrollbars "vertical"
                         mousewheel True
                         draggable True
+                        pagekeys True
 
                         side_yfill True
 
diff --git a/launcher/game/editor.rpy b/launcher/game/editor.rpy
index df2256e..0fbcd41 100644
--- a/launcher/game/editor.rpy
+++ b/launcher/game/editor.rpy
@@ -140,19 +140,47 @@ init 1 python in editor:
         Creates the list of FancyEditorInfo objects.
         """
 
+        import platform
+
         global fancy_editors
 
         scan_all()
 
         fei = fancy_editors = [ ]
 
+        # Atom.
+        AD = _("(Recommended) A modern and approachable text editor.")
+
+        if renpy.windows:
+            dlc = "atom-windows"
+            installed = os.path.exists(os.path.join(config.basedir, "atom/atom-windows"))
+        elif renpy.macintosh:
+            dlc = "atom-mac"
+            installed = os.path.exists(os.path.join(config.basedir, "atom/Atom.app"))
+        else:
+            dlc = "atom-linux"
+            installed = os.path.exists(os.path.join(config.basedir, "atom/atom-linux-" + platform.machine()))
+
+        e = FancyEditorInfo(
+            0,
+            "Atom",
+            AD,
+            dlc,
+            _("Up to 150 MB download required."),
+            None)
+
+        e.installed = e.installed and installed
+
+        fei.append(e)
+
+
         # Editra.
-        ED  = _("{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input.")
-        EDL  = _("{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython.")
+        ED  = _("A mature editor. Editra lacks the IME support required for Chinese, Japanese, and Korean text input.")
+        EDL  = _("A mature editor. Editra lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython.")
 
         if renpy.windows:
             dlc = "editra-windows"
-            installed = os.path.exists(os.path.join(config.basedir, "editra/Editra-win32"))
+            installed = os.path.exists(os.path.join(config.basedir, "editra/editra.exe"))
             description = ED
             error_message = None
         elif renpy.macintosh:
@@ -174,7 +202,7 @@ init 1 python in editor:
             _("Up to 22 MB download required."),
             error_message)
 
-        e.installed = e.installed or installed
+        e.installed = e.installed and installed
 
         fei.append(e)
 
@@ -195,7 +223,7 @@ init 1 python in editor:
             None))
 
         for k in editors:
-            if k in [ "Editra", "jEdit", "System Editor", "None" ]:
+            if k in [ "Atom", "Editra", "jEdit", "System Editor", "None" ]:
                 continue
 
             fei.append(FancyEditorInfo(
@@ -307,7 +335,7 @@ init 1 python in editor:
 
 
     class Edit(Action):
-        alt = "Edit [text]."
+        alt = _("Edit [text].")
 
         def __init__(self, filename, line=None, check=False):
             """
@@ -410,8 +438,6 @@ init 1 python in editor:
         Opens all scripts that are part of the current project in a web browser.
         """
 
-        alt = "Edit [text]."
-
         def __init__(self):
             return
 
@@ -444,6 +470,42 @@ init 1 python in editor:
                 exception = traceback.format_exception_only(type(e), e)[-1][:-1]
                 renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
 
+
+    class EditProject(Action):
+        """
+        Opens the project's base directory in an editor.
+        """
+
+        def __call__(self):
+
+            if not check_editor():
+                return
+
+            try:
+
+                e = renpy.editor.editor
+
+                e.begin()
+                e.open_project(project.current.path)
+                e.end()
+
+            except Exception, e:
+                exception = traceback.format_exception_only(type(e), e)[-1][:-1]
+                renpy.invoke_in_new_context(interface.error, _("An exception occured while launching the text editor:\n[exception!q]"), error_message, exception=exception)
+
+
+    def CanEditProject():
+        """
+        Returns True if EditProject can be used.
+        """
+
+        try:
+            e = renpy.editor.editor
+            return e.has_projects
+        except:
+            return False
+
+
 screen editor:
 
     frame:
diff --git a/launcher/game/front_page.rpy b/launcher/game/front_page.rpy
index 72fa1eb..230fb68 100644
--- a/launcher/game/front_page.rpy
+++ b/launcher/game/front_page.rpy
@@ -211,7 +211,10 @@ screen front_page_project:
                         textbutton "gui.rpy" action editor.Edit("game/gui.rpy", check=True)
                         textbutton "screens.rpy" action editor.Edit("game/screens.rpy", check=True)
 
-                        textbutton _("All script files") action editor.EditAll()
+                        if editor.CanEditProject():
+                            textbutton _("Open project") action editor.EditProject()
+                        else:
+                            textbutton _("All script files") action editor.EditAll()
 
         add SPACER
 
diff --git a/launcher/game/gui7.rpy b/launcher/game/gui7.rpy
index 5bc7c83..487df65 100644
--- a/launcher/game/gui7.rpy
+++ b/launcher/game/gui7.rpy
@@ -290,6 +290,7 @@ screen choose_gui_color():
 
     if gui_color:
         textbutton _("Continue") action Return(True) style "l_right_button"
+        key "input_enter" action Return(True)
 
 
 label change_gui:
@@ -442,7 +443,7 @@ label gui_project_common:
         python hide:
             if gui.project_system_font:
                 with open(os.path.join(project.current.gamedir, "tl/None/common.rpym"), "ab") as f:
-                    f.write("define gui.system_font = {!r}\r\n".format(gui.project_system_font))
+                    f.write("define gui.system_font = {!r}\r\n".format(gui.project_system_font).encode("utf-8"))
 
 
 label gui_generate_images:
@@ -450,7 +451,7 @@ label gui_generate_images:
     python:
 
         interface.processing(_("Updating the project..."))
-        project.current.launch([ 'gui_images' ], env={ "RENPY_VARIANT" : "small phone" } )
-        project.current.launch([ 'gui_images' ])
+        project.current.launch([ 'gui_images' ], env={ "RENPY_VARIANT" : "small phone" }, wait=True)
+        project.current.launch([ 'gui_images' ], wait=True)
 
     jump front_page
diff --git a/launcher/game/itch.rpy b/launcher/game/itch.rpy
index e23c14b..2b9bd49 100644
--- a/launcher/game/itch.rpy
+++ b/launcher/game/itch.rpy
@@ -126,7 +126,9 @@ label itch:
                 butler,
                 "push",
                 filename,
-                itch_project + ":" + build["version"] + "-" + channel,
+                itch_project + ":" + channel,
+                "--userversion",
+                build["version"],
                 )
 
         cc.run()
diff --git a/launcher/game/navigation.rpy b/launcher/game/navigation.rpy
index 773d031..32b25d3 100644
--- a/launcher/game/navigation.rpy
+++ b/launcher/game/navigation.rpy
@@ -166,6 +166,7 @@ screen navigation:
             frame style "l_label":
                 has hbox xfill True
                 text _("Navigate: [project.current.display_name!q]") style "l_label_text"
+                alt _("Navigate Script")
 
                 frame:
                     style "l_alternate"
@@ -192,6 +193,7 @@ screen navigation:
                 hbox:
                     spacing HALF_INDENT
                     text _("Category:")
+                    alt ""
 
                     textbutton _("files") action navigation.ChangeKind("file")
                     textbutton _("labels") action navigation.ChangeKind("label")
diff --git a/launcher/game/options.rpy b/launcher/game/options.rpy
index f754a10..0be1c3d 100644
--- a/launcher/game/options.rpy
+++ b/launcher/game/options.rpy
@@ -269,6 +269,22 @@ init python:
     build.classify_renpy("**/thumbs.db", None)
     build.classify_renpy("**/.*", None)
 
+    # Atom rules. These have to be very early, since Atom uses names like
+    # tmp for packages.
+    build.classify_renpy("atom/", "atom-all source_only")
+    build.classify_renpy("atom/Atom.edit.py", "atom-all source_only")
+    build.classify_renpy("atom/default-dot-atom/**", "atom-all")
+    build.classify_renpy("atom/atom-windows/**", "atom-windows")
+    build.classify_renpy("atom/Atom.app/**", "atom-mac")
+    build.classify_renpy("atom/atom-linux**", "atom-linux")
+
+    try:
+        with open(os.path.join(config.renpy_base, "atom", "executable.txt")) as f:
+            for l in f:
+                build.executable(l.strip())
+    except:
+        pass
+
     build.classify_renpy("rapt/**", "rapt")
 
     build.classify_renpy("renios/prototype/base/", None)
@@ -292,6 +308,7 @@ init python:
     build.classify_renpy("**/tmp/", None)
     build.classify_renpy("**/.Editra", None)
 
+
     # main source.
 
     def source_and_binary(pattern, source="source", binary="binary"):
@@ -373,11 +390,9 @@ init python:
     build.classify_renpy("editra/Editra-mac.app/**", "editra-mac")
     build.classify_renpy("editra/lib/**", "editra-windows")
     build.classify_renpy("editra/editra.exe", "editra-windows")
-
-
-    # Executable rules.
     build.executable("editra/Editra/Editra")
 
+
     # Packages.
     build.packages = [ ]
 
@@ -386,9 +401,15 @@ init python:
     build.package("raspi", "tar.bz2", "raspi", dlc=True, update=False)
 
     build.package("jedit", "zip", "jedit", dlc=True)
+
     build.package("editra-linux", "tar.bz2", "editra-all editra-linux", dlc=True)
     build.package("editra-mac", "zip", "editra-all editra-mac", dlc=True)
     build.package("editra-windows", "zip", "editra-all editra-windows", dlc=True)
+
+    build.package("atom-linux", "tar.bz2", "atom-all atom-linux", dlc=True)
+    build.package("atom-mac", "zip", "atom-all atom-mac", dlc=True)
+    build.package("atom-windows", "zip", "atom-all atom-windows", dlc=True)
+
     build.package("rapt", "zip", "rapt", dlc=True)
     build.package("renios", "zip", "renios", dlc=True)
 
diff --git a/launcher/game/package_formats.rpy b/launcher/game/package_formats.rpy
index cfdbbbb..92f650b 100644
--- a/launcher/game/package_formats.rpy
+++ b/launcher/game/package_formats.rpy
@@ -32,7 +32,7 @@ init python in distribute:
 
     from zipfile import crc32
 
-    zlib.Z_DEFAULT_COMPRESSION = 9
+    zlib.Z_DEFAULT_COMPRESSION = 5
 
     class ZipFile(zipfile.ZipFile):
 
diff --git a/launcher/game/project.rpy b/launcher/game/project.rpy
index e9821a0..916c3ae 100644
--- a/launcher/game/project.rpy
+++ b/launcher/game/project.rpy
@@ -95,6 +95,10 @@ init python in project:
             self.dump_mtime = 0
 
         def get_dump_filename(self):
+
+            if os.path.exists(os.path.join(self.gamedir, "saves")):
+                return os.path.join(self.gamedir, "saves", "navigation.json")
+
             self.make_tmp()
             return os.path.join(self.tmp, "navigation.json")
 
diff --git a/launcher/game/tl/piglatin/common.rpy b/launcher/game/tl/piglatin/common.rpy
index a38a65e..2ce277a 100644
--- a/launcher/game/tl/piglatin/common.rpy
+++ b/launcher/game/tl/piglatin/common.rpy
@@ -157,10 +157,54 @@ translate piglatin strings:
     old "%b %d, %H:%M"
     new "%bay %day, %Hay:%May"
 
-    # 00action_file.rpy:852
+    # 00action_file.rpy:344
+    old "Save slot %s: [text]"
+    new "Avesay otslay %say: [text]"
+
+    # 00action_file.rpy:417
+    old "Load slot %s: [text]"
+    new "Oadlay otslay %say: [text]"
+
+    # 00action_file.rpy:459
+    old "Delete slot [text]"
+    new "Eleteday otslay [text]"
+
+    # 00action_file.rpy:539
+    old "File page auto"
+    new "Ilefay agepay autoay"
+
+    # 00action_file.rpy:541
+    old "File page quick"
+    new "Ilefay agepay uickqay"
+
+    # 00action_file.rpy:543
+    old "File page [text]"
+    new "Ilefay agepay [text]"
+
+    # 00action_file.rpy:733
+    old "Next file page."
+    new "Extnay ilefay agepay."
+
+    # 00action_file.rpy:797
+    old "Previous file page."
+    new "Reviouspay ilefay agepay."
+
+    # 00action_file.rpy:858
     old "Quick save complete."
     new "Uickqay avesay ompletecay."
 
+    # 00action_file.rpy:876
+    old "Quick save."
+    new "Uickqay avesay."
+
+    # 00action_file.rpy:895
+    old "Quick load."
+    new "Uickqay oadlay."
+
+    # 00action_other.rpy:344
+    old "Language [text]"
+    new "Anguagelay [text]"
+
     # 00director.rpy:703
     old "The interactive director is not enabled here."
     new "Hetay interactiveay irectorday isay otnay enableday erehay."
@@ -305,23 +349,203 @@ translate piglatin strings:
     old "Self-voicing enabled. "
     new "Elfsay-oicingvay enableday. "
 
-    # 00library.rpy:183
+    # 00library.rpy:150
+    old "bar"
+    new "arbay"
+
+    # 00library.rpy:151
+    old "selected"
+    new "electedsay"
+
+    # 00library.rpy:152
+    old "viewport"
+    new "iewportvay"
+
+    # 00library.rpy:153
+    old "horizontal scroll"
+    new "orizontalhay crollsay"
+
+    # 00library.rpy:154
+    old "vertical scroll"
+    new "erticalvay crollsay"
+
+    # 00library.rpy:155
+    old "activate"
+    new "activateay"
+
+    # 00library.rpy:156
+    old "deactivate"
+    new "eactivateday"
+
+    # 00library.rpy:157
+    old "increase"
+    new "increaseay"
+
+    # 00library.rpy:158
+    old "decrease"
+    new "ecreaseday"
+
+    # 00library.rpy:193
     old "Skip Mode"
     new "Kipsay Odemay"
 
-    # 00library.rpy:269
+    # 00library.rpy:279
     old "This program contains free software under a number of licenses, including the MIT License and GNU Lesser General Public License. A complete list of software, including links to full source code, can be found {a=https://www.renpy.org/l/license}here{/a}."
     new "Histay rogrampay ontainscay eefray oftwaresay underay aay umbernay ofay icenseslay, includingay hetay Itmay Icenselay anday Nugay Esserlay Eneralgay Ublicpay Icenselay. Aay ompletecay istlay ofay oftwaresay, includingay inkslay otay ullfay ourcesay odecay, ancay ebay oundfay {a=https://www.renpy.org/l/license}erehay{/a}."
 
-    # 00preferences.rpy:475
+    # 00preferences.rpy:207
+    old "display"
+    new "isplayday"
+
+    # 00preferences.rpy:219
+    old "transitions"
+    new "ansitionstray"
+
+    # 00preferences.rpy:228
+    old "skip transitions"
+    new "kipsay ansitionstray"
+
+    # 00preferences.rpy:230
+    old "video sprites"
+    new "ideovay pritessay"
+
+    # 00preferences.rpy:239
+    old "show empty window"
+    new "owshay emptyay indowway"
+
+    # 00preferences.rpy:248
+    old "text speed"
+    new "exttay peedsay"
+
+    # 00preferences.rpy:256
+    old "joystick"
+    new "oystickjay"
+
+    # 00preferences.rpy:256
+    old "joystick..."
+    new "oystickjay..."
+
+    # 00preferences.rpy:263
+    old "skip"
+    new "kipsay"
+
+    # 00preferences.rpy:266
+    old "skip unseen [text]"
+    new "kipsay unseenay [text]"
+
+    # 00preferences.rpy:271
+    old "skip unseen text"
+    new "kipsay unseenay exttay"
+
+    # 00preferences.rpy:273
+    old "begin skipping"
+    new "eginbay kippingsay"
+
+    # 00preferences.rpy:277
+    old "after choices"
+    new "afteray oiceschay"
+
+    # 00preferences.rpy:284
+    old "skip after choices"
+    new "kipsay afteray oiceschay"
+
+    # 00preferences.rpy:286
+    old "auto-forward time"
+    new "autoay-orwardfay imetay"
+
+    # 00preferences.rpy:300
+    old "auto-forward"
+    new "autoay-orwardfay"
+
+    # 00preferences.rpy:307
+    old "Auto forward"
+    new "Utoaay orwardfay"
+
+    # 00preferences.rpy:310
+    old "auto-forward after click"
+    new "autoay-orwardfay afteray ickclay"
+
+    # 00preferences.rpy:319
+    old "automatic move"
+    new "automaticay ovemay"
+
+    # 00preferences.rpy:328
+    old "wait for voice"
+    new "aitway orfay oicevay"
+
+    # 00preferences.rpy:337
+    old "voice sustain"
+    new "oicevay ustainsay"
+
+    # 00preferences.rpy:346
+    old "self voicing"
+    new "elfsay oicingvay"
+
+    # 00preferences.rpy:355
+    old "clipboard voicing"
+    new "ipboardclay oicingvay"
+
+    # 00preferences.rpy:364
+    old "debug voicing"
+    new "ebugday oicingvay"
+
+    # 00preferences.rpy:373
+    old "emphasize audio"
+    new "emphasizeay audioay"
+
+    # 00preferences.rpy:382
+    old "rollback side"
+    new "ollbackray idesay"
+
+    # 00preferences.rpy:392
+    old "gl powersave"
+    new "glay owersavepay"
+
+    # 00preferences.rpy:398
+    old "gl framerate"
+    new "glay ameratefray"
+
+    # 00preferences.rpy:401
+    old "gl tearing"
+    new "glay earingtay"
+
+    # 00preferences.rpy:413
+    old "music volume"
+    new "usicmay olumevay"
+
+    # 00preferences.rpy:414
+    old "sound volume"
+    new "oundsay olumevay"
+
+    # 00preferences.rpy:415
+    old "voice volume"
+    new "oicevay olumevay"
+
+    # 00preferences.rpy:416
+    old "mute music"
+    new "utemay usicmay"
+
+    # 00preferences.rpy:417
+    old "mute sound"
+    new "utemay oundsay"
+
+    # 00preferences.rpy:418
+    old "mute voice"
+    new "utemay oicevay"
+
+    # 00preferences.rpy:419
+    old "mute all"
+    new "utemay allay"
+
+    # 00preferences.rpy:498
     old "Clipboard voicing enabled. Press 'shift+C' to disable."
     new "Lipboardcay oicingvay enableday. Resspay 'iftshay+Cay' otay isableday."
 
-    # 00preferences.rpy:477
+    # 00preferences.rpy:500
     old "Self-voicing would say \"[renpy.display.tts.last]\". Press 'alt+shift+V' to disable."
     new "Elfsay-oicingvay ouldway aysay \"[renpy.display.tts.last]\". Resspay 'altay+iftshay+Vay' otay isableday."
 
-    # 00preferences.rpy:479
+    # 00preferences.rpy:502
     old "Self-voicing enabled. Press 'v' to disable."
     new "Elfsay-oicingvay enableday. Resspay 'vay' otay isableday."
 
@@ -337,67 +561,67 @@ translate piglatin strings:
     old "An error is being simulated."
     new "Naay erroray isay eingbay imulatedsay."
 
-    # 00updater.rpy:667
+    # 00updater.rpy:672
     old "Either this project does not support updating, or the update status file was deleted."
     new "Ithereay histay rojectpay oesday otnay upportsay updatingay, oray hetay updateay atusstay ilefay asway eletedday."
 
-    # 00updater.rpy:681
+    # 00updater.rpy:686
     old "This account does not have permission to perform an update."
     new "Histay accountay oesday otnay avehay ermissionpay otay erformpay anay updateay."
 
-    # 00updater.rpy:684
+    # 00updater.rpy:689
     old "This account does not have permission to write the update log."
     new "Histay accountay oesday otnay avehay ermissionpay otay riteway hetay updateay oglay."
 
-    # 00updater.rpy:711
+    # 00updater.rpy:716
     old "Could not verify update signature."
     new "Ouldcay otnay erifyvay updateay ignaturesay."
 
-    # 00updater.rpy:986
+    # 00updater.rpy:991
     old "The update file was not downloaded."
     new "Hetay updateay ilefay asway otnay ownloadedday."
 
-    # 00updater.rpy:1004
+    # 00updater.rpy:1009
     old "The update file does not have the correct digest - it may have been corrupted."
     new "Hetay updateay ilefay oesday otnay avehay hetay orrectcay igestday - itay aymay avehay eenbay orruptedcay."
 
-    # 00updater.rpy:1060
+    # 00updater.rpy:1065
     old "While unpacking {}, unknown type {}."
     new "Hileway unpackingay {}, unknownay ypetay {}."
 
-    # 00updater.rpy:1407
+    # 00updater.rpy:1412
     old "Updater"
     new "Pdateruay"
 
-    # 00updater.rpy:1418
+    # 00updater.rpy:1423
     old "This program is up to date."
     new "Histay rogrampay isay upay otay ateday."
 
-    # 00updater.rpy:1420
+    # 00updater.rpy:1425
     old "[u.version] is available. Do you want to install it?"
     new "[u.version] isay availableay. Oday ouyay antway otay installay itay?"
 
-    # 00updater.rpy:1422
+    # 00updater.rpy:1427
     old "Preparing to download the updates."
     new "Reparingpay otay ownloadday hetay updatesay."
 
-    # 00updater.rpy:1424
+    # 00updater.rpy:1429
     old "Downloading the updates."
     new "Ownloadingday hetay updatesay."
 
-    # 00updater.rpy:1426
+    # 00updater.rpy:1431
     old "Unpacking the updates."
     new "Npackinguay hetay updatesay."
 
-    # 00updater.rpy:1430
+    # 00updater.rpy:1435
     old "The updates have been installed. The program will restart."
     new "Hetay updatesay avehay eenbay installeday. Hetay rogrampay illway estartray."
 
-    # 00updater.rpy:1432
+    # 00updater.rpy:1437
     old "The updates have been installed."
     new "Hetay updatesay avehay eenbay installeday."
 
-    # 00updater.rpy:1434
+    # 00updater.rpy:1439
     old "The updates were cancelled."
     new "Hetay updatesay ereway ancelledcay."
 
diff --git a/launcher/game/tl/piglatin/developer.rpy b/launcher/game/tl/piglatin/developer.rpy
index 165ce7b..37a0614 100644
--- a/launcher/game/tl/piglatin/developer.rpy
+++ b/launcher/game/tl/piglatin/developer.rpy
@@ -69,23 +69,23 @@ translate piglatin strings:
     old "Type to filter: "
     new "Ypetay otay ilterfay: "
 
-    # _developer/developer.rpym:572
+    # _developer/developer.rpym:575
     old "Textures: [tex_count] ([tex_size_mb:.1f] MB)"
     new "Exturestay: [tex_count] ([tex_size_mb:.1f] Bmay)"
 
-    # _developer/developer.rpym:576
+    # _developer/developer.rpym:579
     old "Image cache: [cache_pct:.1f]% ([cache_size_mb:.1f] MB)"
     new "Mageiay achecay: [cache_pct:.1f]% ([cache_size_mb:.1f] Bmay)"
 
-    # _developer/developer.rpym:586
+    # _developer/developer.rpym:589
     old "✔ "
     new "✔ "
 
-    # _developer/developer.rpym:589
+    # _developer/developer.rpym:592
     old "✘ "
     new "✘ "
 
-    # _developer/developer.rpym:594
+    # _developer/developer.rpym:597
     old "\n{color=#cfc}✔ predicted image (good){/color}\n{color=#fcc}✘ unpredicted image (bad){/color}\n{color=#fff}Drag to move.{/color}"
     new "\n{color=#cfc}✔ redictedpay imageay (oodgay){/color}\n{color=#fcc}✘ unpredicteday imageay (adbay){/color}\n{color=#fff}Ragday otay ovemay.{/color}"
 
diff --git a/launcher/game/tl/piglatin/launcher.rpy b/launcher/game/tl/piglatin/launcher.rpy
index c47d261..7fb2a9c 100644
--- a/launcher/game/tl/piglatin/launcher.rpy
+++ b/launcher/game/tl/piglatin/launcher.rpy
@@ -365,51 +365,71 @@ translate piglatin strings:
     old "This is probably because Ren'Py is running directly from a Macintosh drive image. To fix this, quit this launcher, copy the entire %s folder somewhere else on your computer, and run Ren'Py again."
     new "Histay isay robablypay ecausebay Enray'Ypay isay unningray irectlyday omfray aay Acintoshmay riveday imageay. Otay ixfay histay, uitqay histay auncherlay, opycay hetay entireay %say olderfay omewheresay elseay onay ouryay omputercay, anday unray Enray'Ypay againay."
 
-    # editor.rpy:150
-    old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
-    new "{b}Ecommendedray.{/b} Aay etabay editoray ithway anay easyay otay useay interfaceay anday eaturesfay hattay aiday inay evelopmentday, uchsay asay pellsay-eckingchay. Ditraeay urrentlycay ackslay hetay Meiay upportsay equiredray orfay Hinesecay, Apanesejay, anday Oreankay exttay inputay."
+    # editor.rpy:152
+    old "(Recommended) A modern and approachable text editor."
+    new "(Ecommendedray) Aay odernmay anday approachableay exttay editoray."
 
-    # editor.rpy:151
-    old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
-    new "{b}Ecommendedray.{/b} Aay etabay editoray ithway anay easyay otay useay interfaceay anday eaturesfay hattay aiday inay evelopmentday, uchsay asay pellsay-eckingchay. Ditraeay urrentlycay ackslay hetay Meiay upportsay equiredray orfay Hinesecay, Apanesejay, anday Oreankay exttay inputay. Noay Inuxlay, Ditraeay equiresray xPythonway."
+    # editor.rpy:164
+    old "Up to 150 MB download required."
+    new "Puay otay 501ay Bmay ownloadday equiredray."
 
-    # editor.rpy:167
+    # editor.rpy:178
+    old "A mature editor. Editra lacks the IME support required for Chinese, Japanese, and Korean text input."
+    new "Aay aturemay editoray. Ditraeay ackslay hetay Meiay upportsay equiredray orfay Hinesecay, Apanesejay, anday Oreankay exttay inputay."
+
+    # editor.rpy:179
+    old "A mature editor. Editra lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
+    new "Aay aturemay editoray. Ditraeay ackslay hetay Meiay upportsay equiredray orfay Hinesecay, Apanesejay, anday Oreankay exttay inputay. Noay Inuxlay, Ditraeay equiresray xPythonway."
+
+    # editor.rpy:195
     old "This may have occured because wxPython is not installed on this system."
     new "Histay aymay avehay occureday ecausebay xPythonway isay otnay installeday onay histay ystemsay."
 
-    # editor.rpy:169
+    # editor.rpy:197
     old "Up to 22 MB download required."
     new "Puay otay 22ay Bmay ownloadday equiredray."
 
-    # editor.rpy:182
+    # editor.rpy:210
     old "A mature editor that requires Java."
     new "Aay aturemay editoray hattay equiresray Avajay."
 
-    # editor.rpy:182
+    # editor.rpy:210
     old "1.8 MB download required."
     new "1ay.8ay Bmay ownloadday equiredray."
 
-    # editor.rpy:182
+    # editor.rpy:210
     old "This may have occured because Java is not installed on this system."
     new "Histay aymay avehay occureday ecausebay Avajay isay otnay installeday onay histay ystemsay."
 
-    # editor.rpy:191
+    # editor.rpy:219
+    old "System Editor"
+    new "Ystemsay Ditoreay"
+
+    # editor.rpy:219
     old "Invokes the editor your operating system has associated with .rpy files."
     new "Nvokesiay hetay editoray ouryay operatingay ystemsay ashay associateday ithway .pyray ilesfay."
 
-    # editor.rpy:207
+    # editor.rpy:235
+    old "None"
+    new "Onenay"
+
+    # editor.rpy:235
     old "Prevents Ren'Py from opening a text editor."
     new "Reventspay Enray'Ypay omfray openingay aay exttay editoray."
 
-    # editor.rpy:359
+    # editor.rpy:338
+    old "Edit [text]."
+    new "Diteay [text]."
+
+    # editor.rpy:387
     old "An exception occured while launching the text editor:\n[exception!q]"
     new "Naay exceptionay occureday hileway aunchinglay hetay exttay editoray:\n[exception!q]"
 
-    # editor.rpy:457
+    # editor.rpy:519
     old "Select Editor"
     new "Electsay Ditoreay"
 
-    # editor.rpy:472
+    # editor.rpy:534
     old "A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed."
     new "Aay exttay editoray isay hetay rogrampay ouyay'llay useay otay editay Enray'Ypay criptsay ilesfay. Erehay, ouyay ancay electsay hetay editoray Enray'Ypay illway useay. Fiay otnay alreadyay resentpay, hetay editoray illway ebay automaticallyay ownloadedday anday installeday."
 
@@ -477,63 +497,67 @@ translate piglatin strings:
     old "Edit File"
     new "Diteay Ilefay"
 
-    # front_page.rpy:214
+    # front_page.rpy:215
+    old "Open project"
+    new "Penoay rojectpay"
+
+    # front_page.rpy:217
     old "All script files"
     new "Llaay criptsay ilesfay"
 
-    # front_page.rpy:218
+    # front_page.rpy:221
     old "Actions"
     new "Ctionsaay"
 
-    # front_page.rpy:227
+    # front_page.rpy:230
     old "Navigate Script"
     new "Avigatenay Criptsay"
 
-    # front_page.rpy:228
+    # front_page.rpy:231
     old "Check Script (Lint)"
     new "Heckcay Criptsay (Intlay)"
 
-    # front_page.rpy:231
+    # front_page.rpy:234
     old "Change/Update GUI"
     new "Hangecay/Pdateuay Uigay"
 
-    # front_page.rpy:233
+    # front_page.rpy:236
     old "Change Theme"
     new "Hangecay Hemetay"
 
-    # front_page.rpy:236
+    # front_page.rpy:239
     old "Delete Persistent"
     new "Eleteday Ersistentpay"
 
-    # front_page.rpy:245
+    # front_page.rpy:248
     old "Build Distributions"
     new "Uildbay Istributionsday"
 
-    # front_page.rpy:247
+    # front_page.rpy:250
     old "Android"
     new "Ndroidaay"
 
-    # front_page.rpy:248
+    # front_page.rpy:251
     old "iOS"
     new "iOSay"
 
-    # front_page.rpy:249
+    # front_page.rpy:252
     old "Generate Translations"
     new "Enerategay Ranslationstay"
 
-    # front_page.rpy:250
+    # front_page.rpy:253
     old "Extract Dialogue"
     new "Xtracteay Ialogueday"
 
-    # front_page.rpy:267
+    # front_page.rpy:270
     old "Checking script for potential problems..."
     new "Heckingcay criptsay orfay otentialpay roblemspay..."
 
-    # front_page.rpy:282
+    # front_page.rpy:285
     old "Deleting persistent data..."
     new "Eletingday ersistentpay ataday..."
 
-    # front_page.rpy:290
+    # front_page.rpy:293
     old "Recompiling all rpy files into rpyc files..."
     new "Ecompilingray allay pyray ilesfay intoay pycray ilesfay..."
 
@@ -805,63 +829,63 @@ translate piglatin strings:
     old "Navigate: [project.current.display_name!q]"
     new "Avigatenay: [project.current.display_name!q]"
 
-    # navigation.rpy:177
+    # navigation.rpy:178
     old "Order: "
     new "Rderoay: "
 
-    # navigation.rpy:178
+    # navigation.rpy:179
     old "alphabetical"
     new "alphabeticalay"
 
-    # navigation.rpy:180
+    # navigation.rpy:181
     old "by-file"
     new "ybay-ilefay"
 
-    # navigation.rpy:182
+    # navigation.rpy:183
     old "natural"
     new "aturalnay"
 
-    # navigation.rpy:194
+    # navigation.rpy:195
     old "Category:"
     new "Ategorycay:"
 
-    # navigation.rpy:196
+    # navigation.rpy:198
     old "files"
     new "ilesfay"
 
-    # navigation.rpy:197
+    # navigation.rpy:199
     old "labels"
     new "abelslay"
 
-    # navigation.rpy:198
+    # navigation.rpy:200
     old "defines"
     new "efinesday"
 
-    # navigation.rpy:199
+    # navigation.rpy:201
     old "transforms"
     new "ansformstray"
 
-    # navigation.rpy:200
+    # navigation.rpy:202
     old "screens"
     new "creenssay"
 
-    # navigation.rpy:201
+    # navigation.rpy:203
     old "callables"
     new "allablescay"
 
-    # navigation.rpy:202
+    # navigation.rpy:204
     old "TODOs"
     new "Odostay"
 
-    # navigation.rpy:241
+    # navigation.rpy:243
     old "+ Add script file"
     new "+ Ddaay criptsay ilefay"
 
-    # navigation.rpy:249
+    # navigation.rpy:251
     old "No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."
     new "Onay Odotay ommentscay oundfay.\n\nOtay reatecay oneay, includeay \"# Odotay\" inay ouryay criptsay."
 
-    # navigation.rpy:256
+    # navigation.rpy:258
     old "The list of names is empty."
     new "Hetay istlay ofay amesnay isay emptyay."
 
@@ -1013,139 +1037,139 @@ translate piglatin strings:
     old "Have you backed up your projects recently?"
     new "Avehay ouyay ackedbay upay ouryay rojectspay ecentlyray?"
 
-    # project.rpy:276
+    # project.rpy:280
     old "Launching the project failed."
     new "Aunchinglay hetay rojectpay ailedfay."
 
-    # project.rpy:276
+    # project.rpy:280
     old "Please ensure that your project launches normally before running this command."
     new "Leasepay ensureay hattay ouryay rojectpay auncheslay ormallynay eforebay unningray histay ommandcay."
 
-    # project.rpy:292
+    # project.rpy:296
     old "Ren'Py is scanning the project..."
     new "Enray'Ypay isay canningsay hetay rojectpay..."
 
-    # project.rpy:721
+    # project.rpy:725
     old "Launching"
     new "Aunchinglay"
 
-    # project.rpy:755
+    # project.rpy:759
     old "PROJECTS DIRECTORY"
     new "Rojectspay Irectoryday"
 
-    # project.rpy:755
+    # project.rpy:759
     old "Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
     new "Leasepay oosechay hetay rojectspay irectoryday usingay hetay irectoryday ooserchay.\n{b}Hetay irectoryday ooserchay aymay avehay openeday ehindbay histay indowway.{/b}"
 
-    # project.rpy:755
+    # project.rpy:759
     old "This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."
     new "Histay auncherlay illway cansay orfay rojectspay inay histay irectoryday, illway reatecay ewnay rojectspay inay histay irectoryday, anday illway aceplay uiltbay rojectspay intoay histay irectoryday."
 
-    # project.rpy:760
+    # project.rpy:764
     old "Ren'Py has set the projects directory to:"
     new "Enray'Ypay ashay etsay hetay rojectspay irectoryday otay:"
 
-    # translations.rpy:92
+    # translations.rpy:91
     old "Translations: [project.current.display_name!q]"
     new "Ranslationstay: [project.current.display_name!q]"
 
-    # translations.rpy:133
+    # translations.rpy:132
     old "The language to work with. This should only contain lower-case ASCII characters and underscores."
     new "Hetay anguagelay otay orkway ithway. Histay ouldshay onlyay ontaincay owerlay-asecay Sciiaay aracterschay anday underscoresay."
 
-    # translations.rpy:159
+    # translations.rpy:158
     old "Generate empty strings for translations"
     new "Enerategay emptyay ringsstay orfay anslationstray"
 
-    # translations.rpy:177
+    # translations.rpy:176
     old "Generates or updates translation files. The files will be placed in game/tl/[persistent.translate_language!q]."
     new "Eneratesgay oray updatesay anslationtray ilesfay. Hetay ilesfay illway ebay acedplay inay amegay/ltay/[persistent.translate_language!q]."
 
-    # translations.rpy:197
+    # translations.rpy:196
     old "Extract String Translations"
     new "Xtracteay Tringsay Ranslationstay"
 
-    # translations.rpy:199
+    # translations.rpy:198
     old "Merge String Translations"
     new "Ergemay Tringsay Ranslationstay"
 
-    # translations.rpy:204
+    # translations.rpy:203
     old "Replace existing translations"
     new "Eplaceray existingay anslationstray"
 
-    # translations.rpy:205
+    # translations.rpy:204
     old "Reverse languages"
     new "Everseray anguageslay"
 
-    # translations.rpy:209
+    # translations.rpy:208
     old "Update Default Interface Translations"
     new "Pdateuay Efaultday Nterfaceiay Ranslationstay"
 
-    # translations.rpy:229
+    # translations.rpy:228
     old "The extract command allows you to extract string translations from an existing project into a temporary file.\n\nThe merge command merges extracted translations into another project."
     new "Hetay extractay ommandcay allowsay ouyay otay extractay ringstay anslationstray omfray anay existingay rojectpay intoay aay emporarytay ilefay.\n\nHetay ergemay ommandcay ergesmay extracteday anslationstray intoay anotheray rojectpay."
 
-    # translations.rpy:253
+    # translations.rpy:252
     old "Ren'Py is generating translations...."
     new "Enray'Ypay isay eneratinggay anslationstray...."
 
-    # translations.rpy:264
+    # translations.rpy:263
     old "Ren'Py has finished generating [language] translations."
     new "Enray'Ypay ashay inishedfay eneratinggay [language] anslationstray."
 
-    # translations.rpy:277
+    # translations.rpy:276
     old "Ren'Py is extracting string translations..."
     new "Enray'Ypay isay extractingay ringstay anslationstray..."
 
-    # translations.rpy:280
+    # translations.rpy:279
     old "Ren'Py has finished extracting [language] string translations."
     new "Enray'Ypay ashay inishedfay extractingay [language] ringstay anslationstray."
 
-    # translations.rpy:300
+    # translations.rpy:299
     old "Ren'Py is merging string translations..."
     new "Enray'Ypay isay ergingmay ringstay anslationstray..."
 
-    # translations.rpy:303
+    # translations.rpy:302
     old "Ren'Py has finished merging [language] string translations."
     new "Enray'Ypay ashay inishedfay ergingmay [language] ringstay anslationstray."
 
-    # translations.rpy:314
+    # translations.rpy:313
     old "Updating default interface translations..."
     new "Pdatinguay efaultday interfaceay anslationstray..."
 
-    # translations.rpy:343
+    # translations.rpy:342
     old "Extract Dialogue: [project.current.display_name!q]"
     new "Xtracteay Ialogueday: [project.current.display_name!q]"
 
-    # translations.rpy:359
+    # translations.rpy:358
     old "Format:"
     new "Ormatfay:"
 
-    # translations.rpy:367
+    # translations.rpy:366
     old "Tab-delimited Spreadsheet (dialogue.tab)"
     new "Abtay-elimitedday Preadsheetsay (ialogueday.abtay)"
 
-    # translations.rpy:368
+    # translations.rpy:367
     old "Dialogue Text Only (dialogue.txt)"
     new "Ialogueday Exttay Nlyoay (ialogueday.xttay)"
 
-    # translations.rpy:381
+    # translations.rpy:380
     old "Strip text tags from the dialogue."
     new "Tripsay exttay agstay omfray hetay ialogueday."
 
-    # translations.rpy:382
+    # translations.rpy:381
     old "Escape quotes and other special characters."
     new "Scapeeay uotesqay anday otheray pecialsay aracterschay."
 
-    # translations.rpy:383
+    # translations.rpy:382
     old "Extract all translatable strings, not just dialogue."
     new "Xtracteay allay anslatabletray ringsstay, otnay ustjay ialogueday."
 
-    # translations.rpy:411
+    # translations.rpy:410
     old "Ren'Py is extracting dialogue...."
     new "Enray'Ypay isay extractingay ialogueday...."
 
-    # translations.rpy:415
+    # translations.rpy:414
     old "Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[persistent.dialogue_format] in the base directory."
     new "Enray'Ypay ashay inishedfay extractingay ialogueday. Hetay extracteday ialogueday ancay ebay oundfay inay ialogueday.[persistent.dialogue_format] inay hetay asebay irectoryday."
 
diff --git a/launcher/game/tl/piglatin/screens.rpy b/launcher/game/tl/piglatin/screens.rpy
index 74cc2ef..329c71f 100644
--- a/launcher/game/tl/piglatin/screens.rpy
+++ b/launcher/game/tl/piglatin/screens.rpy
@@ -205,471 +205,471 @@ translate piglatin strings:
     old "## Reserve space for the navigation section."
     new "## Eserveray pacesay orfay hetay avigationnay ectionsay."
 
-    # screens.rpy:471
+    # screens.rpy:473
     old "Return"
     new "Eturnray"
 
-    # screens.rpy:534
+    # screens.rpy:536
     old "## About screen"
     new "## Boutaay creensay"
 
-    # screens.rpy:536
+    # screens.rpy:538
     old "## This screen gives credit and copyright information about the game and Ren'Py."
     new "## Histay creensay ivesgay reditcay anday opyrightcay informationay aboutay hetay amegay anday Enray'Ypay."
 
-    # screens.rpy:539
+    # screens.rpy:541
     old "## There's nothing special about this screen, and hence it also serves as an example of how to make a custom screen."
     new "## Heretay'say othingnay pecialsay aboutay histay creensay, anday encehay itay alsoay ervessay asay anay exampleay ofay owhay otay akemay aay ustomcay creensay."
 
-    # screens.rpy:546
+    # screens.rpy:548
     old "## This use statement includes the game_menu screen inside this one. The vbox child is then included inside the viewport inside the game_menu screen."
     new "## Histay useay atementstay includesay hetay ame_menugay creensay insideay histay oneay. Hetay boxvay ildchay isay hentay includeday insideay hetay iewportvay insideay hetay ame_menugay creensay."
 
-    # screens.rpy:556
+    # screens.rpy:558
     old "Version [config.version!t]\n"
     new "Ersionvay [config.version!t]\n"
 
-    # screens.rpy:558
+    # screens.rpy:560
     old "## gui.about is usually set in options.rpy."
     new "## uigay.aboutay isay usuallyay etsay inay optionsay.pyray."
 
-    # screens.rpy:562
+    # screens.rpy:564
     old "Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]"
     new "Ademay ithway {a=https://www.renpy.org/}Enray'Ypay{/a} [renpy.version_only].\n\n[renpy.license!t]"
 
-    # screens.rpy:565
+    # screens.rpy:567
     old "## This is redefined in options.rpy to add text to the about screen."
     new "## Histay isay edefinedray inay optionsay.pyray otay adday exttay otay hetay aboutay creensay."
 
-    # screens.rpy:577
+    # screens.rpy:579
     old "## Load and Save screens"
     new "## Oadlay anday Avesay creenssay"
 
-    # screens.rpy:579
+    # screens.rpy:581
     old "## These screens are responsible for letting the player save the game and load it again. Since they share nearly everything in common, both are implemented in terms of a third screen, file_slots."
     new "## Hesetay creenssay areay esponsibleray orfay ettinglay hetay ayerplay avesay hetay amegay anday oadlay itay againay. Incesay heytay areshay earlynay everythingay inay ommoncay, othbay areay implementeday inay ermstay ofay aay hirdtay creensay, ile_slotsfay."
 
-    # screens.rpy:583
+    # screens.rpy:585
     old "## https://www.renpy.org/doc/html/screen_special.html#save https://www.renpy.org/doc/html/screen_special.html#load"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#avesay ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#oadlay"
 
-    # screens.rpy:602
+    # screens.rpy:604
     old "Page {}"
     new "Agepay {}"
 
-    # screens.rpy:602
+    # screens.rpy:604
     old "Automatic saves"
     new "Utomaticaay avessay"
 
-    # screens.rpy:602
+    # screens.rpy:604
     old "Quick saves"
     new "Uickqay avessay"
 
-    # screens.rpy:608
+    # screens.rpy:610
     old "## This ensures the input will get the enter event before any of the buttons do."
     new "## Histay ensuresay hetay inputay illway etgay hetay enteray eventay eforebay anyay ofay hetay uttonsbay oday."
 
-    # screens.rpy:612
+    # screens.rpy:614
     old "## The page name, which can be edited by clicking on a button."
     new "## Hetay agepay amenay, hichway ancay ebay editeday ybay ickingclay onay aay uttonbay."
 
-    # screens.rpy:624
+    # screens.rpy:626
     old "## The grid of file slots."
     new "## Hetay idgray ofay ilefay otsslay."
 
-    # screens.rpy:644
+    # screens.rpy:646
     old "{#file_time}%A, %B %d %Y, %H:%M"
     new "{#file_time}%Aay, %Bay %day %Yay, %Hay:%May"
 
-    # screens.rpy:644
+    # screens.rpy:646
     old "empty slot"
     new "emptyay otslay"
 
-    # screens.rpy:652
+    # screens.rpy:654
     old "## Buttons to access other pages."
     new "## Uttonsbay otay accessay otheray agespay."
 
-    # screens.rpy:661
+    # screens.rpy:663
     old "<"
     new "<"
 
-    # screens.rpy:664
+    # screens.rpy:666
     old "{#auto_page}A"
     new "{#auto_page}Aay"
 
-    # screens.rpy:667
+    # screens.rpy:669
     old "{#quick_page}Q"
     new "{#quick_page}Qay"
 
-    # screens.rpy:669
+    # screens.rpy:671
     old "## range(1, 10) gives the numbers from 1 to 9."
     new "## angeray(1ay, 01ay) ivesgay hetay umbersnay omfray 1ay otay 9ay."
 
-    # screens.rpy:673
+    # screens.rpy:675
     old ">"
     new ">"
 
-    # screens.rpy:708
+    # screens.rpy:710
     old "## Preferences screen"
     new "## Referencespay creensay"
 
-    # screens.rpy:710
+    # screens.rpy:712
     old "## The preferences screen allows the player to configure the game to better suit themselves."
     new "## Hetay referencespay creensay allowsay hetay ayerplay otay onfigurecay hetay amegay otay etterbay uitsay hemselvestay."
 
-    # screens.rpy:713
+    # screens.rpy:715
     old "## https://www.renpy.org/doc/html/screen_special.html#preferences"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#referencespay"
 
-    # screens.rpy:730
+    # screens.rpy:732
     old "Display"
     new "Isplayday"
 
-    # screens.rpy:731
+    # screens.rpy:733
     old "Window"
     new "Indowway"
 
-    # screens.rpy:732
+    # screens.rpy:734
     old "Fullscreen"
     new "Ullscreenfay"
 
-    # screens.rpy:736
+    # screens.rpy:738
     old "Rollback Side"
     new "Ollbackray Idesay"
 
-    # screens.rpy:737
+    # screens.rpy:739
     old "Disable"
     new "Isableday"
 
-    # screens.rpy:738
+    # screens.rpy:740
     old "Left"
     new "Eftlay"
 
-    # screens.rpy:739
+    # screens.rpy:741
     old "Right"
     new "Ightray"
 
-    # screens.rpy:744
+    # screens.rpy:746
     old "Unseen Text"
     new "Nseenuay Exttay"
 
-    # screens.rpy:745
+    # screens.rpy:747
     old "After Choices"
     new "Fteraay Hoicescay"
 
-    # screens.rpy:746
+    # screens.rpy:748
     old "Transitions"
     new "Ransitionstay"
 
-    # screens.rpy:748
+    # screens.rpy:750
     old "## Additional vboxes of type \"radio_pref\" or \"check_pref\" can be added here, to add additional creator-defined preferences."
     new "## Dditionalaay boxesvay ofay ypetay \"adio_prefray\" oray \"eck_prefchay\" ancay ebay addeday erehay, otay adday additionalay reatorcay-efinedday referencespay."
 
-    # screens.rpy:759
+    # screens.rpy:761
     old "Text Speed"
     new "Exttay Peedsay"
 
-    # screens.rpy:763
+    # screens.rpy:765
     old "Auto-Forward Time"
     new "Utoaay-Orwardfay Imetay"
 
-    # screens.rpy:770
+    # screens.rpy:772
     old "Music Volume"
     new "Usicmay Olumevay"
 
-    # screens.rpy:777
+    # screens.rpy:779
     old "Sound Volume"
     new "Oundsay Olumevay"
 
-    # screens.rpy:783
+    # screens.rpy:785
     old "Test"
     new "Esttay"
 
-    # screens.rpy:787
+    # screens.rpy:789
     old "Voice Volume"
     new "Oicevay Olumevay"
 
-    # screens.rpy:798
+    # screens.rpy:800
     old "Mute All"
     new "Utemay Llaay"
 
-    # screens.rpy:874
+    # screens.rpy:876
     old "## History screen"
     new "## Istoryhay creensay"
 
-    # screens.rpy:876
+    # screens.rpy:878
     old "## This is a screen that displays the dialogue history to the player. While there isn't anything special about this screen, it does have to access the dialogue history stored in _history_list."
     new "## Histay isay aay creensay hattay isplaysday hetay ialogueday istoryhay otay hetay ayerplay. Hileway heretay isnay'tay anythingay pecialsay aboutay histay creensay, itay oesday avehay otay accessay hetay ialogueday istoryhay oredstay inay history_list_ay."
 
-    # screens.rpy:880
+    # screens.rpy:882
     old "## https://www.renpy.org/doc/html/history.html"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/istoryhay.tmlhay"
 
-    # screens.rpy:886
+    # screens.rpy:888
     old "## Avoid predicting this screen, as it can be very large."
     new "## Voidaay redictingpay histay creensay, asay itay ancay ebay eryvay argelay."
 
-    # screens.rpy:897
+    # screens.rpy:899
     old "## This lays things out properly if history_height is None."
     new "## Histay ayslay hingstay outay roperlypay ifay istory_heighthay isay Onenay."
 
-    # screens.rpy:906
+    # screens.rpy:908
     old "## Take the color of the who text from the Character, if set."
     new "## Aketay hetay olorcay ofay hetay howay exttay omfray hetay Haractercay, ifay etsay."
 
-    # screens.rpy:914
+    # screens.rpy:916
     old "The dialogue history is empty."
     new "Hetay ialogueday istoryhay isay emptyay."
 
-    # screens.rpy:917
+    # screens.rpy:919
     old "## This determines what tags are allowed to be displayed on the history screen."
     new "## Histay eterminesday hatway agstay areay alloweday otay ebay isplayedday onay hetay istoryhay creensay."
 
-    # screens.rpy:964
+    # screens.rpy:966
     old "## Help screen"
     new "## Elphay creensay"
 
-    # screens.rpy:966
+    # screens.rpy:968
     old "## A screen that gives information about key and mouse bindings. It uses other screens (keyboard_help, mouse_help, and gamepad_help) to display the actual help."
     new "## Aay creensay hattay ivesgay informationay aboutay eykay anday ousemay indingsbay. Tiay usesay otheray creenssay (eyboard_helpkay, ouse_helpmay, anday amepad_helpgay) otay isplayday hetay actualay elphay."
 
-    # screens.rpy:985
+    # screens.rpy:987
     old "Keyboard"
     new "Eyboardkay"
 
-    # screens.rpy:986
+    # screens.rpy:988
     old "Mouse"
     new "Ousemay"
 
-    # screens.rpy:989
+    # screens.rpy:991
     old "Gamepad"
     new "Amepadgay"
 
-    # screens.rpy:1002
+    # screens.rpy:1004
     old "Enter"
     new "Ntereay"
 
-    # screens.rpy:1003
+    # screens.rpy:1005
     old "Advances dialogue and activates the interface."
     new "Dvancesaay ialogueday anday activatesay hetay interfaceay."
 
-    # screens.rpy:1006
+    # screens.rpy:1008
     old "Space"
     new "Pacesay"
 
-    # screens.rpy:1007
+    # screens.rpy:1009
     old "Advances dialogue without selecting choices."
     new "Dvancesaay ialogueday ithoutway electingsay oiceschay."
 
-    # screens.rpy:1010
+    # screens.rpy:1012
     old "Arrow Keys"
     new "Rrowaay Eyskay"
 
-    # screens.rpy:1011
+    # screens.rpy:1013
     old "Navigate the interface."
     new "Avigatenay hetay interfaceay."
 
-    # screens.rpy:1014
+    # screens.rpy:1016
     old "Escape"
     new "Scapeeay"
 
-    # screens.rpy:1015
+    # screens.rpy:1017
     old "Accesses the game menu."
     new "Ccessesaay hetay amegay enumay."
 
-    # screens.rpy:1018
+    # screens.rpy:1020
     old "Ctrl"
     new "Trlcay"
 
-    # screens.rpy:1019
+    # screens.rpy:1021
     old "Skips dialogue while held down."
     new "Kipssay ialogueday hileway eldhay ownday."
 
-    # screens.rpy:1022
+    # screens.rpy:1024
     old "Tab"
     new "Abtay"
 
-    # screens.rpy:1023
+    # screens.rpy:1025
     old "Toggles dialogue skipping."
     new "Ogglestay ialogueday kippingsay."
 
-    # screens.rpy:1026
+    # screens.rpy:1028
     old "Page Up"
     new "Agepay Puay"
 
-    # screens.rpy:1027
+    # screens.rpy:1029
     old "Rolls back to earlier dialogue."
     new "Ollsray ackbay otay earlieray ialogueday."
 
-    # screens.rpy:1030
+    # screens.rpy:1032
     old "Page Down"
     new "Agepay Ownday"
 
-    # screens.rpy:1031
+    # screens.rpy:1033
     old "Rolls forward to later dialogue."
     new "Ollsray orwardfay otay aterlay ialogueday."
 
-    # screens.rpy:1035
+    # screens.rpy:1037
     old "Hides the user interface."
     new "Ideshay hetay useray interfaceay."
 
-    # screens.rpy:1039
+    # screens.rpy:1041
     old "Takes a screenshot."
     new "Akestay aay creenshotsay."
 
-    # screens.rpy:1043
+    # screens.rpy:1045
     old "Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}."
     new "Ogglestay assistiveay {a=https://www.renpy.org/l/voicing}elfsay-oicingvay{/a}."
 
-    # screens.rpy:1049
+    # screens.rpy:1051
     old "Left Click"
     new "Eftlay Lickcay"
 
-    # screens.rpy:1053
+    # screens.rpy:1055
     old "Middle Click"
     new "Iddlemay Lickcay"
 
-    # screens.rpy:1057
+    # screens.rpy:1059
     old "Right Click"
     new "Ightray Lickcay"
 
-    # screens.rpy:1061
+    # screens.rpy:1063
     old "Mouse Wheel Up\nClick Rollback Side"
     new "Ousemay Heelway Puay\nLickcay Ollbackray Idesay"
 
-    # screens.rpy:1065
+    # screens.rpy:1067
     old "Mouse Wheel Down"
     new "Ousemay Heelway Ownday"
 
-    # screens.rpy:1072
+    # screens.rpy:1074
     old "Right Trigger\nA/Bottom Button"
     new "Ightray Riggertay\nAay/Ottombay Uttonbay"
 
-    # screens.rpy:1076
+    # screens.rpy:1078
     old "Left Trigger\nLeft Shoulder"
     new "Eftlay Riggertay\nEftlay Houldersay"
 
-    # screens.rpy:1080
+    # screens.rpy:1082
     old "Right Shoulder"
     new "Ightray Houldersay"
 
-    # screens.rpy:1085
+    # screens.rpy:1087
     old "D-Pad, Sticks"
     new "Day-Adpay, Tickssay"
 
-    # screens.rpy:1089
+    # screens.rpy:1091
     old "Start, Guide"
     new "Tartsay, Uidegay"
 
-    # screens.rpy:1093
+    # screens.rpy:1095
     old "Y/Top Button"
     new "Yay/Optay Uttonbay"
 
-    # screens.rpy:1096
+    # screens.rpy:1098
     old "Calibrate"
     new "Alibratecay"
 
-    # screens.rpy:1124
+    # screens.rpy:1126
     old "## Additional screens"
     new "## Dditionalaay creenssay"
 
-    # screens.rpy:1128
+    # screens.rpy:1130
     old "## Confirm screen"
     new "## Onfirmcay creensay"
 
-    # screens.rpy:1130
+    # screens.rpy:1132
     old "## The confirm screen is called when Ren'Py wants to ask the player a yes or no question."
     new "## Hetay onfirmcay creensay isay alledcay henway Enray'Ypay antsway otay askay hetay ayerplay aay esyay oray onay uestionqay."
 
-    # screens.rpy:1133
+    # screens.rpy:1135
     old "## https://www.renpy.org/doc/html/screen_special.html#confirm"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#onfirmcay"
 
-    # screens.rpy:1137
+    # screens.rpy:1139
     old "## Ensure other screens do not get input while this screen is displayed."
     new "## Nsureeay otheray creenssay oday otnay etgay inputay hileway histay creensay isay isplayedday."
 
-    # screens.rpy:1161
+    # screens.rpy:1163
     old "Yes"
     new "Esyay"
 
-    # screens.rpy:1162
+    # screens.rpy:1164
     old "No"
     new "Onay"
 
-    # screens.rpy:1164
+    # screens.rpy:1166
     old "## Right-click and escape answer \"no\"."
     new "## Ightray-ickclay anday escapeay answeray \"onay\"."
 
-    # screens.rpy:1191
+    # screens.rpy:1193
     old "## Skip indicator screen"
     new "## Kipsay indicatoray creensay"
 
-    # screens.rpy:1193
+    # screens.rpy:1195
     old "## The skip_indicator screen is displayed to indicate that skipping is in progress."
     new "## Hetay kip_indicatorsay creensay isay isplayedday otay indicateay hattay kippingsay isay inay rogresspay."
 
-    # screens.rpy:1196
+    # screens.rpy:1198
     old "## https://www.renpy.org/doc/html/screen_special.html#skip-indicator"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#kipsay-indicatoray"
 
-    # screens.rpy:1208
+    # screens.rpy:1210
     old "Skipping"
     new "Kippingsay"
 
-    # screens.rpy:1215
+    # screens.rpy:1217
     old "## This transform is used to blink the arrows one after another."
     new "## Histay ansformtray isay useday otay inkblay hetay arrowsay oneay afteray anotheray."
 
-    # screens.rpy:1242
+    # screens.rpy:1244
     old "## We have to use a font that has the BLACK RIGHT-POINTING SMALL TRIANGLE glyph in it."
     new "## Eway avehay otay useay aay ontfay hattay ashay hetay Lackbay Ightray-Ointingpay Mallsay Riangletay yphglay inay itay."
 
-    # screens.rpy:1247
+    # screens.rpy:1249
     old "## Notify screen"
     new "## Otifynay creensay"
 
-    # screens.rpy:1249
+    # screens.rpy:1251
     old "## The notify screen is used to show the player a message. (For example, when the game is quicksaved or a screenshot has been taken.)"
     new "## Hetay otifynay creensay isay useday otay owshay hetay ayerplay aay essagemay. (Orfay exampleay, henway hetay amegay isay uicksavedqay oray aay creenshotsay ashay eenbay akentay.)"
 
-    # screens.rpy:1252
+    # screens.rpy:1254
     old "## https://www.renpy.org/doc/html/screen_special.html#notify-screen"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#otifynay-creensay"
 
-    # screens.rpy:1286
+    # screens.rpy:1288
     old "## NVL screen"
     new "## Vlnay creensay"
 
-    # screens.rpy:1288
+    # screens.rpy:1290
     old "## This screen is used for NVL-mode dialogue and menus."
     new "## Histay creensay isay useday orfay Vlnay-odemay ialogueday anday enusmay."
 
-    # screens.rpy:1290
+    # screens.rpy:1292
     old "## https://www.renpy.org/doc/html/screen_special.html#nvl"
     new "## ttpshay://wwway.enpyray.orgay/ocday/tmlhay/creen_specialsay.tmlhay#vlnay"
 
-    # screens.rpy:1301
+    # screens.rpy:1303
     old "## Displays dialogue in either a vpgrid or the vbox."
     new "## Isplaysday ialogueday inay eitheray aay pgridvay oray hetay boxvay."
 
-    # screens.rpy:1314
+    # screens.rpy:1316
     old "## Displays the menu, if given. The menu may be displayed incorrectly if config.narrator_menu is set to True, as it is above."
     new "## Isplaysday hetay enumay, ifay ivengay. Hetay enumay aymay ebay isplayedday incorrectlyay ifay onfigcay.arrator_menunay isay etsay otay Ruetay, asay itay isay aboveay."
 
-    # screens.rpy:1344
+    # screens.rpy:1346
     old "## This controls the maximum number of NVL-mode entries that can be displayed at once."
     new "## Histay ontrolscay hetay aximummay umbernay ofay Vlnay-odemay entriesay hattay ancay ebay isplayedday atay onceay."
 
-    # screens.rpy:1406
+    # screens.rpy:1408
     old "## Mobile Variants"
     new "## Obilemay Ariantsvay"
 
-    # screens.rpy:1413
+    # screens.rpy:1415
     old "## Since a mouse may not be present, we replace the quick menu with a version that uses fewer and bigger buttons that are easier to touch."
     new "## Incesay aay ousemay aymay otnay ebay resentpay, eway eplaceray hetay uickqay enumay ithway aay ersionvay hattay usesay ewerfay anday iggerbay uttonsbay hattay areay easieray otay ouchtay."
 
-    # screens.rpy:1429
+    # screens.rpy:1431
     old "Menu"
     new "Enumay"
 
diff --git a/launcher/game/tl/russian/common.rpy b/launcher/game/tl/russian/common.rpy
index 4c852d8..c6e1195 100644
--- a/launcher/game/tl/russian/common.rpy
+++ b/launcher/game/tl/russian/common.rpy
@@ -153,14 +153,58 @@ translate russian strings:
     old "{#month_short}Dec"
     new "{#month_short}Дек"
 
-    # 00action_file.rpy:235
+    # 00action_file.rpy:237
     old "%b %d, %H:%M"
     new "%d %b, %H:%M"
 
-    # 00action_file.rpy:825
+    # 00action_file.rpy:344
+    old "Save slot %s: [text]"
+    new "Слот сохранения %s: [text]"
+
+    # 00action_file.rpy:417
+    old "Load slot %s: [text]"
+    new "Слот загрузки %s: [text]"
+
+    # 00action_file.rpy:459
+    old "Delete slot [text]"
+    new "Удалить слот [text]"
+
+    # 00action_file.rpy:539
+    old "File page auto"
+    new "Автосохранения"
+
+    # 00action_file.rpy:541
+    old "File page quick"
+    new "Быстрые сохранения"
+
+    # 00action_file.rpy:543
+    old "File page [text]"
+    new "Страница сохранений [text]"
+
+    # 00action_file.rpy:733
+    old "Next file page."
+    new "Следующая страница сохранений"
+
+    # 00action_file.rpy:797
+    old "Previous file page."
+    new "Предыдущая страница сохранений"
+
+    # 00action_file.rpy:858
     old "Quick save complete."
     new "Быстрое сохранение завершено."
 
+    # 00action_file.rpy:876
+    old "Quick save."
+    new "Быстрое сохранение"
+
+    # 00action_file.rpy:895
+    old "Quick load."
+    new "Быстрая загрузка"
+
+    # 00action_other.rpy:344
+    old "Language [text]"
+    new "Язык [text]"
+
     # 00director.rpy:703
     old "The interactive director is not enabled here."
     new "Интерактивный директор недоступен."
@@ -285,11 +329,11 @@ translate russian strings:
     old "Are you sure you want to skip unseen dialogue to the next choice?"
     new "Вы уверены, что хотите пропустить непрочитанные диалоги до следующего выбора?"
 
-    # 00keymap.rpy:255
+    # 00keymap.rpy:258
     old "Failed to save screenshot as %s."
     new "Провалена попытка сохранить скриншот как %s."
 
-    # 00keymap.rpy:267
+    # 00keymap.rpy:270
     old "Saved screenshot as %s."
     new "Скриншот сохранён как %s."
 
@@ -299,29 +343,209 @@ translate russian strings:
 
     # 00library.rpy:147
     old "Clipboard voicing enabled. "
-    new "Озвучка буфера обмена включена. "
+    new "Озвучка буфера обмена включена."
 
     # 00library.rpy:148
     old "Self-voicing enabled. "
-    new "Синтезатор речи включён. "
+    new "Синтезатор речи включён."
+
+    # 00library.rpy:150
+    old "bar"
+    new ". Полоса настройки"
+
+    # 00library.rpy:151
+    old "selected"
+    new ". На данный момент это выбрано"
+
+    # 00library.rpy:152
+    old "viewport"
+    new "порт просмотра"
 
-    # 00library.rpy:183
+    # 00library.rpy:153
+    old "horizontal scroll"
+    new ". горизонтальная полоса прокрутки"
+
+    # 00library.rpy:154
+    old "vertical scroll"
+    new ". вертикальная полоса прокрутки"
+
+    # 00library.rpy:155
+    old "activate"
+    new "элемент активирован"
+
+    # 00library.rpy:156
+    old "deactivate"
+    new "элемент деактивирован"
+
+    # 00library.rpy:157
+    old "increase"
+    new "больше" ### но полоса прокрутки тоже здесь!
+
+    # 00library.rpy:158
+    old "decrease"
+    new "меньше" ###
+
+    # 00library.rpy:193
     old "Skip Mode"
     new "Режим Пропуска"
 
-    # 00library.rpy:266
+    # 00library.rpy:279
     old "This program contains free software under a number of licenses, including the MIT License and GNU Lesser General Public License. A complete list of software, including links to full source code, can be found {a=https://www.renpy.org/l/license}here{/a}."
     new "Эта программа содержит свободное и открытое программное обеспечение под несколькими лицензиями, включая лицензию MIT и GNU Lesser General Public. Полный список лицензий, включая ссылки на полный исходный код, можно найти {a=https://www.renpy.org/l/license}здесь{/a}."
 
-    # 00preferences.rpy:472
+    # 00preferences.rpy:207
+    old "display"
+    new "режим экрана"
+
+    # 00preferences.rpy:219
+    old "transitions"
+    new "переходы"
+
+    # 00preferences.rpy:228
+    old "skip transitions"
+    new "пропускать переходы"
+
+    # 00preferences.rpy:230
+    old "video sprites"
+    new "видео-спрайты"
+
+    # 00preferences.rpy:239
+    old "show empty window"
+    new "показывать пустое окно диалога"
+
+    # 00preferences.rpy:248
+    old "text speed"
+    new "скорость текста"
+
+    # 00preferences.rpy:256
+    old "joystick"
+    new "джойстик"
+
+    # 00preferences.rpy:256
+    old "joystick..."
+    new "джойстик..."
+
+    # 00preferences.rpy:263
+    old "skip"
+    new "пропускать"
+
+    # 00preferences.rpy:266
+    old "skip unseen [text]"
+    new "пропускать весь [text]" ###
+
+    # 00preferences.rpy:271
+    old "skip unseen text"
+    new "пропускать весь текст"
+
+    # 00preferences.rpy:273
+    old "begin skipping"
+    new "начать пропуск"
+
+    # 00preferences.rpy:277
+    old "after choices"
+    new "после выборов"
+
+    # 00preferences.rpy:284
+    old "skip after choices"
+    new "пропускать после выборов"
+
+    # 00preferences.rpy:286
+    old "auto-forward time"
+    new "скорость авточтения"
+
+    # 00preferences.rpy:300
+    old "auto-forward"
+    new "авточтение" ###
+
+    # 00preferences.rpy:307
+    old "Auto forward"
+    new "Авточтение" ###
+
+    # 00preferences.rpy:310
+    old "auto-forward after click"
+    new "продолжать авточтение после клика"
+
+    # 00preferences.rpy:319
+    old "automatic move"
+    new "автоматически передвигать мышь к кнопке" ###
+
+    # 00preferences.rpy:328
+    old "wait for voice"
+    new "ждать голос"
+
+    # 00preferences.rpy:337
+    old "voice sustain"
+    new "не останавливать голос"
+
+    # 00preferences.rpy:346
+    old "self voicing"
+    new "озвучка через синтезатор речи"
+
+    # 00preferences.rpy:355
+    old "clipboard voicing"
+    new "синтез речи из буфера обмена"
+
+    # 00preferences.rpy:364
+    old "debug voicing"
+    new "режим дебага синтеза речи"
+
+    # 00preferences.rpy:373
+    old "emphasize audio"
+    new "усилить громкость заранее заданных звуковых каналов за счёт приглушения остальных каналов"
+
+    # 00preferences.rpy:382
+    old "rollback side"
+    new "сторона отката"
+
+    # 00preferences.rpy:392
+    old "gl powersave"
+    new "настройка графики. Экономия энергии"
+
+    # 00preferences.rpy:398
+    old "gl framerate"
+    new "настройка графики. Частота кадров"
+
+    # 00preferences.rpy:401
+    old "gl tearing"
+    new "настройка графики. Разрывание кадров"
+
+    # 00preferences.rpy:413
+    old "music volume"
+    new "громкость музыки"
+
+    # 00preferences.rpy:414
+    old "sound volume"
+    new "громкость звуков"
+
+    # 00preferences.rpy:415
+    old "voice volume"
+    new "громкость голоса"
+
+    # 00preferences.rpy:416
+    old "mute music"
+    new "без музыки"
+
+    # 00preferences.rpy:417
+    old "mute sound"
+    new "без звуков"
+
+    # 00preferences.rpy:418
+    old "mute voice"
+    new "без голоса"
+
+    # 00preferences.rpy:419
+    old "mute all"
+    new "режим без звука"
+
+    # 00preferences.rpy:498
     old "Clipboard voicing enabled. Press 'shift+C' to disable."
     new "Озвучка буфера обмена включена. Нажмите 'shift+C', чтобы отключить её."
 
-    # 00preferences.rpy:474
+    # 00preferences.rpy:500
     old "Self-voicing would say \"[renpy.display.tts.last]\". Press 'alt+shift+V' to disable."
     new "Синтезатор речи должен сказать \"[renpy.display.tts.last]\". Нажмите 'alt+shift+V', чтобы отключить его."
 
-    # 00preferences.rpy:476
+    # 00preferences.rpy:502
     old "Self-voicing enabled. Press 'v' to disable."
     new "Синтезатор речи включён. Нажмите 'v', чтобы отключить его."
 
@@ -337,67 +561,67 @@ translate russian strings:
     old "An error is being simulated."
     new "Симулируется ошибка."
 
-    # 00updater.rpy:667
+    # 00updater.rpy:672
     old "Either this project does not support updating, or the update status file was deleted."
     new "Или этот проект не поддерживает обновление, или файл статуса обновления был удалён."
 
-    # 00updater.rpy:681
+    # 00updater.rpy:686
     old "This account does not have permission to perform an update."
     new "У этого аккаунта нет прав проводить обновление."
 
-    # 00updater.rpy:684
+    # 00updater.rpy:689
     old "This account does not have permission to write the update log."
     new "У этого аккаунта нет прав писать лог обновления."
 
-    # 00updater.rpy:711
+    # 00updater.rpy:716
     old "Could not verify update signature."
     new "Не могу верифицировать подпись обновления."
 
-    # 00updater.rpy:986
+    # 00updater.rpy:991
     old "The update file was not downloaded."
     new "Файл обновления не был загружен."
 
-    # 00updater.rpy:1004
+    # 00updater.rpy:1009
     old "The update file does not have the correct digest - it may have been corrupted."
     new "Файл обновления не содержит корректного дайджеста — он может быть повреждён."
 
-    # 00updater.rpy:1060
+    # 00updater.rpy:1065
     old "While unpacking {}, unknown type {}."
     new "При распаковке {} обнаружен неизвестный тип {}."
 
-    # 00updater.rpy:1407
+    # 00updater.rpy:1412
     old "Updater"
     new "Обновление"
 
-    # 00updater.rpy:1418
+    # 00updater.rpy:1423
     old "This program is up to date."
     new "Эта программа обновлена."
 
-    # 00updater.rpy:1420
+    # 00updater.rpy:1425
     old "[u.version] is available. Do you want to install it?"
     new "[u.version] доступна. Вы хотите её установить?"
 
-    # 00updater.rpy:1422
+    # 00updater.rpy:1427
     old "Preparing to download the updates."
     new "Подготовка к загрузке обновлений."
 
-    # 00updater.rpy:1424
+    # 00updater.rpy:1429
     old "Downloading the updates."
     new "Загрузка обновлений."
 
-    # 00updater.rpy:1426
+    # 00updater.rpy:1431
     old "Unpacking the updates."
     new "Распаковка обновлений."
 
-    # 00updater.rpy:1430
+    # 00updater.rpy:1435
     old "The updates have been installed. The program will restart."
     new "Обновления установлены. Программа будет перезапущена."
 
-    # 00updater.rpy:1432
+    # 00updater.rpy:1437
     old "The updates have been installed."
     new "Обновления были установлены."
 
-    # 00updater.rpy:1434
+    # 00updater.rpy:1439
     old "The updates were cancelled."
     new "Обновления были отменены."
 
diff --git a/launcher/game/tl/russian/developer.rpy b/launcher/game/tl/russian/developer.rpy
index f70949d..b035bed 100644
--- a/launcher/game/tl/russian/developer.rpy
+++ b/launcher/game/tl/russian/developer.rpy
@@ -69,23 +69,23 @@ translate russian strings:
     old "Type to filter: "
     new "Текущий фильтр: "
 
-    # _developer/developer.rpym:572
+    # _developer/developer.rpym:575
     old "Textures: [tex_count] ([tex_size_mb:.1f] MB)"
     new "Текстур: [tex_count] ([tex_size_mb:.1f] МБ)"
 
-    # _developer/developer.rpym:576
+    # _developer/developer.rpym:579
     old "Image cache: [cache_pct:.1f]% ([cache_size_mb:.1f] MB)"
     new "Кеш изображений: [cache_pct:.1f]% ([cache_size_mb:.1f] МБ)"
 
-    # _developer/developer.rpym:586
+    # _developer/developer.rpym:589
     old "✔ "
     new "✔ "
 
-    # _developer/developer.rpym:589
+    # _developer/developer.rpym:592
     old "✘ "
     new "✘ "
 
-    # _developer/developer.rpym:594
+    # _developer/developer.rpym:597
     old "\n{color=#cfc}✔ predicted image (good){/color}\n{color=#fcc}✘ unpredicted image (bad){/color}\n{color=#fff}Drag to move.{/color}"
     new "\n{color=#cfc}✔ предсказанное изображение (хорошо){/color}\n{color=#fcc}✘ внезапное изображение (плохо){/color}\n{color=#fff}Нажмите, чтобы передвинуть.{/color}"
 
diff --git a/launcher/game/tl/russian/error.rpy b/launcher/game/tl/russian/error.rpy
index fc83bf1..afdc38b 100644
--- a/launcher/game/tl/russian/error.rpy
+++ b/launcher/game/tl/russian/error.rpy
@@ -33,87 +33,87 @@ translate russian strings:
     old "Powersave"
     new "Экономия энергии"
 
-    # 00gltest.rpy:149
+    # 00gltest.rpy:145
     old "Framerate"
     new "Частота кадров"
 
-    # 00gltest.rpy:153
+    # 00gltest.rpy:149
     old "Screen"
     new "Экранная"
 
-    # 00gltest.rpy:157
+    # 00gltest.rpy:153
     old "60"
     new "60"
 
-    # 00gltest.rpy:161
+    # 00gltest.rpy:157
     old "30"
     new "30"
 
-    # 00gltest.rpy:167
+    # 00gltest.rpy:163
     old "Tearing"
     new "Разрывание кадров"
 
-    # 00gltest.rpy:183
+    # 00gltest.rpy:179
     old "Changes will take effect the next time this program is run."
     new "Изменения вступят в силу при следующем запуске программы."
 
-    # 00gltest.rpy:217
+    # 00gltest.rpy:213
     old "Performance Warning"
     new "Предупреждение Производительности"
 
-    # 00gltest.rpy:222
+    # 00gltest.rpy:218
     old "This computer is using software rendering."
     new "Этот компьютер использует программный рендеринг."
 
-    # 00gltest.rpy:224
+    # 00gltest.rpy:220
     old "This computer is not using shaders."
     new "Этот компьютер не использует шейдеры."
 
-    # 00gltest.rpy:226
+    # 00gltest.rpy:222
     old "This computer is displaying graphics slowly."
     new "Этот компьютер медленно отображает графику."
 
-    # 00gltest.rpy:228
+    # 00gltest.rpy:224
     old "This computer has a problem displaying graphics: [problem]."
     new "У этого компьютера проблема с отображением графики: [problem]"
 
-    # 00gltest.rpy:233
+    # 00gltest.rpy:229
     old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
     new "Графические драйвера устарели или работают неверно. Это может привести к медленному или неверному отображению графики. Обновление DirectX может решить эту проблему."
 
-    # 00gltest.rpy:235
+    # 00gltest.rpy:231
     old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
     new "Графические драйвера устарели или работают неверно. Это может привести к медленному или неверному отображению графики."
 
-    # 00gltest.rpy:240
+    # 00gltest.rpy:236
     old "Update DirectX"
     new "Обновить DirectX"
 
-    # 00gltest.rpy:246
+    # 00gltest.rpy:242
     old "Continue, Show this warning again"
     new "Продолжить, Показать это предупреждение снова"
 
-    # 00gltest.rpy:250
+    # 00gltest.rpy:246
     old "Continue, Don't show warning again"
     new "Продолжить, Не показывать это предупреждение снова."
 
-    # 00gltest.rpy:268
+    # 00gltest.rpy:264
     old "Updating DirectX."
     new "Обновляю DirectX."
 
-    # 00gltest.rpy:272
+    # 00gltest.rpy:268
     old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
     new "Установщик DirectX был запущен. Возможно, что он запустился в свёрнутом состоянии. Пожалуйста, следуйте инструкциям для установки DirectX."
 
-    # 00gltest.rpy:276
+    # 00gltest.rpy:272
     old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
     new "{b}Предупреждение:{/b} Установщик DirectX по умолчанию пытается установить панель инструментов Bing. Если вы этого не хотите, снимите соответствующую галочку."
 
-    # 00gltest.rpy:280
+    # 00gltest.rpy:276
     old "When setup finishes, please click below to restart this program."
     new "По завершению установки, щёлкните, чтобы перезапустить программу."
 
-    # 00gltest.rpy:282
+    # 00gltest.rpy:278
     old "Restart"
     new "Перезапустить"
 
@@ -141,75 +141,75 @@ translate russian strings:
     old "Back (B)"
     new "Back (B)"
 
-    # _errorhandling.rpym:523
+    # _errorhandling.rpym:528
     old "Open"
     new "Журнал"
 
-    # _errorhandling.rpym:525
+    # _errorhandling.rpym:530
     old "Opens the traceback.txt file in a text editor."
     new "Открывает файл traceback.txt в текстовом редакторе."
 
-    # _errorhandling.rpym:527
+    # _errorhandling.rpym:532
     old "Copy"
     new "Копировать"
 
-    # _errorhandling.rpym:529
+    # _errorhandling.rpym:534
     old "Copies the traceback.txt file to the clipboard."
     new "Копирует файл traceback.txt в буфер обмена."
 
-    # _errorhandling.rpym:556
+    # _errorhandling.rpym:561
     old "An exception has occurred."
     new "Возникло исключение."
 
-    # _errorhandling.rpym:576
+    # _errorhandling.rpym:581
     old "Rollback"
     new "Назад"
 
-    # _errorhandling.rpym:578
+    # _errorhandling.rpym:583
     old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
     new "Пытается вернуться назад, позволяя вам сохраниться или принять другой выбор."
 
-    # _errorhandling.rpym:581
+    # _errorhandling.rpym:586
     old "Ignore"
     new "Игнорировать"
 
-    # _errorhandling.rpym:585
+    # _errorhandling.rpym:590
     old "Ignores the exception, allowing you to continue."
     new "Игнорирует это исключение, позволяя вам продолжить."
 
-    # _errorhandling.rpym:587
+    # _errorhandling.rpym:592
     old "Ignores the exception, allowing you to continue. This often leads to additional errors."
     new "Игнорирует это исключение, позволяя вам продолжить. Зачастую это ведёт к дополнительным ошибкам."
 
-    # _errorhandling.rpym:591
+    # _errorhandling.rpym:596
     old "Reload"
     new "Перезагрузить"
 
-    # _errorhandling.rpym:593
+    # _errorhandling.rpym:598
     old "Reloads the game from disk, saving and restoring game state if possible."
     new "Перезагружает игру с диска, сохраняя и восстанавливая её состояние, если это возможно."
 
-    # _errorhandling.rpym:596
+    # _errorhandling.rpym:601
     old "Console"
     new "Консоль"
 
-    # _errorhandling.rpym:598
+    # _errorhandling.rpym:603
     old "Opens a console to allow debugging the problem."
     new "Открывает консоль, позволяющую отладить проблему."
 
-    # _errorhandling.rpym:608
+    # _errorhandling.rpym:613
     old "Quits the game."
     new "Выходит из игры."
 
-    # _errorhandling.rpym:632
+    # _errorhandling.rpym:637
     old "Parsing the script failed."
     new "Обработка сценария завершилась неудачно."
 
-    # _errorhandling.rpym:658
+    # _errorhandling.rpym:663
     old "Opens the errors.txt file in a text editor."
     new "Открывает файл errors.txt в текстовом редакторе."
 
-    # _errorhandling.rpym:662
+    # _errorhandling.rpym:667
     old "Copies the errors.txt file to the clipboard."
     new "Копирует файл errors.txt в буфер обмена."
 
diff --git a/launcher/game/tl/russian/launcher.rpy b/launcher/game/tl/russian/launcher.rpy
index 310838a..701466b 100644
--- a/launcher/game/tl/russian/launcher.rpy
+++ b/launcher/game/tl/russian/launcher.rpy
@@ -365,59 +365,71 @@ translate russian strings:
     old "This is probably because Ren'Py is running directly from a Macintosh drive image. To fix this, quit this launcher, copy the entire %s folder somewhere else on your computer, and run Ren'Py again."
     new "Вероятно, это из-за того, что Ren'Py запущена напрямую из образа диска Mac. Чтобы исправить это, выйдите из лаунчера и скопируйте всю папку %s куда-нибудь ещё на компьютер и снова запустите Ren'Py."
 
-    # editor.rpy:150
-    old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input."
-    new "{b}Рекомендуется.{/b} Бета-редактор с простым интерфейсом и возможностями, помогающими в разработке, такими, как проверка орфографии. Editra на данный момент не поддерживает IME, необходимые для ввода Китайского, Японского и Корейского текстов."
+    # editor.rpy:152
+    old "(Recommended) A modern and approachable text editor."
+    new "(Рекомендуется) Современный, доступный текстовый редактор."
 
-    # editor.rpy:151
-    old "{b}Recommended.{/b} A beta editor with an easy to use interface and features that aid in development, such as spell-checking. Editra currently lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
-    new "{b}Рекомендуется.{/b} Бета-редактор с простым интерфейсом и возможностями, помогающими в разработке, такими, как проверка орфографии. Editra на данный момент не поддерживает IME, необходимые для ввода Китайского, Японского и Корейского текстов. На Linux, Editra требует wxPython."
+    # editor.rpy:164
+    old "Up to 150 MB download required."
+    new "Требуется скачать 150 МБ."
 
-    # editor.rpy:167
+    # editor.rpy:178
+    old "A mature editor. Editra lacks the IME support required for Chinese, Japanese, and Korean text input."
+    new "Старый, проверенный бета-редактор. Editra на данный момент не поддерживает IME, необходимые для ввода Китайского, Японского и Корейского текстов."
+
+    # editor.rpy:179
+    old "A mature editor. Editra lacks the IME support required for Chinese, Japanese, and Korean text input. On Linux, Editra requires wxPython."
+    new "Старый, проверенный бета-редактор. Editra на данный момент не поддерживает IME, необходимые для ввода Китайского, Японского и Корейского текстов. На Linux, Editra требует wxPython."
+
+    # editor.rpy:195
     old "This may have occured because wxPython is not installed on this system."
     new "Это могло случиться из-за того, что wxPython не установлен на этой системе."
 
-    # editor.rpy:169
+    # editor.rpy:197
     old "Up to 22 MB download required."
     new "Требуется скачать 22 МБ."
 
-    # editor.rpy:182
+    # editor.rpy:210
     old "A mature editor that requires Java."
     new "Проверенный временем редактор. Требует Java."
 
-    # editor.rpy:182
+    # editor.rpy:210
     old "1.8 MB download required."
     new "Требуется скачать 1.8 МБ."
 
-    # editor.rpy:182
+    # editor.rpy:210
     old "This may have occured because Java is not installed on this system."
     new "Это могло случиться из-за того, что Java не установлена в данной системе."
 
-    # editor.rpy:191
+    # editor.rpy:219
     old "System Editor"
     new "Системный"
 
-    # editor.rpy:191
+    # editor.rpy:219
     old "Invokes the editor your operating system has associated with .rpy files."
     new "Включает текстовый редактор, ассоциированный в вашей системе с файлами .rpy."
 
-    # editor.rpy:207
+    # editor.rpy:235
     old "None"
     new "Нет"
 
-    # editor.rpy:207
+    # editor.rpy:235
     old "Prevents Ren'Py from opening a text editor."
     new "Не позволяет Ren'Py запускать текстовый редактор."
 
-    # editor.rpy:359
+    # editor.rpy:338
+    old "Edit [text]."
+    new "Редактировать [text]"
+
+    # editor.rpy:387
     old "An exception occured while launching the text editor:\n[exception!q]"
     new "Возникла ошибка при запуске текстового редактора:\n[exception!q]"
 
-    # editor.rpy:457
+    # editor.rpy:519
     old "Select Editor"
     new "Выберите редактор"
 
-    # editor.rpy:472
+    # editor.rpy:534
     old "A text editor is the program you'll use to edit Ren'Py script files. Here, you can select the editor Ren'Py will use. If not already present, the editor will be automatically downloaded and installed."
     new "Текстовый редактор — программа, необходимая для редактирования сценариев Ren'Py. Здесь, вы можете выбрать редактор, который будет использовать Ren'Py. Если такового нет, редактор будет автоматически загружен и установлен."
 
@@ -485,63 +497,67 @@ translate russian strings:
     old "Edit File"
     new "Редактировать Файл"
 
-    # front_page.rpy:214
+    # front_page.rpy:215
+    old "Open project"
+    new "Открыть проект"
+
+    # front_page.rpy:217
     old "All script files"
     new "все файлы сценария"
 
-    # front_page.rpy:218
+    # front_page.rpy:221
     old "Actions"
     new "Действия с Проектом"
 
-    # front_page.rpy:227
+    # front_page.rpy:230
     old "Navigate Script"
     new "Навигация по cценарию"
 
-    # front_page.rpy:228
+    # front_page.rpy:231
     old "Check Script (Lint)"
     new "Проверить скрипт (Lint)"
 
-    # front_page.rpy:231
+    # front_page.rpy:234
     old "Change/Update GUI"
     new "Изменить/Обновить GUI"
 
-    # front_page.rpy:233
+    # front_page.rpy:236
     old "Change Theme"
     new "Сменить тему"
 
-    # front_page.rpy:236
+    # front_page.rpy:239
     old "Delete Persistent"
     new "Очистить постоянные"
 
-    # front_page.rpy:245
+    # front_page.rpy:248
     old "Build Distributions"
     new "Построить дистрибутивы"
 
-    # front_page.rpy:247
+    # front_page.rpy:250
     old "Android"
     new "Android"
 
-    # front_page.rpy:248
+    # front_page.rpy:251
     old "iOS"
     new "iOS"
 
-    # front_page.rpy:249
+    # front_page.rpy:252
     old "Generate Translations"
     new "Создать переводы"
 
-    # front_page.rpy:250
+    # front_page.rpy:253
     old "Extract Dialogue"
     new "Извлечь диалог"
 
-    # front_page.rpy:267
+    # front_page.rpy:270
     old "Checking script for potential problems..."
     new "Проверка потенциальных проблем сценария..."
 
-    # front_page.rpy:282
+    # front_page.rpy:285
     old "Deleting persistent data..."
     new "Удаление постоянных данных..."
 
-    # front_page.rpy:290
+    # front_page.rpy:293
     old "Recompiling all rpy files into rpyc files..."
     new "Перекомпиляция всех файлов rpy в файлы rpyc..."
 
@@ -817,59 +833,59 @@ translate russian strings:
     old "Order: "
     new "Порядок: "
 
-    # navigation.rpy:178
+    # navigation.rpy:179
     old "alphabetical"
     new "алфавитный"
 
-    # navigation.rpy:180
+    # navigation.rpy:181
     old "by-file"
     new "по файлу"
 
-    # navigation.rpy:182
+    # navigation.rpy:183
     old "natural"
     new "натуральный"
 
-    # navigation.rpy:194
+    # navigation.rpy:195
     old "Category:"
     new "Категория:"
 
-    # navigation.rpy:196
+    # navigation.rpy:198
     old "files"
     new "файлы"
 
-    # navigation.rpy:197
+    # navigation.rpy:199
     old "labels"
     new "метки"
 
-    # navigation.rpy:198
+    # navigation.rpy:200
     old "defines"
     new "определения"
 
-    # navigation.rpy:199
+    # navigation.rpy:201
     old "transforms"
     new "трансформации"
 
-    # navigation.rpy:200
+    # navigation.rpy:202
     old "screens"
     new "экраны"
 
-    # navigation.rpy:201
+    # navigation.rpy:203
     old "callables"
     new "вызываемые"
 
-    # navigation.rpy:202
+    # navigation.rpy:204
     old "TODOs"
     new "TODO"
 
-    # navigation.rpy:241
+    # navigation.rpy:243
     old "+ Add script file"
     new "+ Добавить файл сценария"
 
-    # navigation.rpy:249
+    # navigation.rpy:251
     old "No TODO comments found.\n\nTo create one, include \"# TODO\" in your script."
     new "Не найдено комментариев TODO.\n\nЧтобы создать такой, включите \"#TODO\" в ваш сценарий"
 
-    # navigation.rpy:256
+    # navigation.rpy:258
     old "The list of names is empty."
     new "Список имён пуст."
 
@@ -1021,139 +1037,139 @@ translate russian strings:
     old "Have you backed up your projects recently?"
     new "Давно сохраняли свои проекты?"
 
-    # project.rpy:276
+    # project.rpy:280
     old "Launching the project failed."
     new "Запуск проекта провален."
 
-    # project.rpy:276
+    # project.rpy:280
     old "Please ensure that your project launches normally before running this command."
     new "Пожалуйста, убедитесь, что ваш проект нормально запускается перед использованием этой команды."
 
-    # project.rpy:292
+    # project.rpy:296
     old "Ren'Py is scanning the project..."
     new "Ren'Py сканирует проект..."
 
-    # project.rpy:721
+    # project.rpy:725
     old "Launching"
     new "Запускаю"
 
-    # project.rpy:755
+    # project.rpy:759
     old "PROJECTS DIRECTORY"
     new "ДИРЕКТОРИЯ ПРОЕКТОВ"
 
-    # project.rpy:755
+    # project.rpy:759
     old "Please choose the projects directory using the directory chooser.\n{b}The directory chooser may have opened behind this window.{/b}"
     new "Пожалуйста, выберите директорию проектов, используя выборщик директорий.\n{b}Он мог появиться позади этого окна.{/b}"
 
-    # project.rpy:755
+    # project.rpy:759
     old "This launcher will scan for projects in this directory, will create new projects in this directory, and will place built projects into this directory."
     new "Лаунчер будет искать проекты в этой директории, создавать новые проекты в этой директории, и размещать построенные проекты в этой директории."
 
-    # project.rpy:760
+    # project.rpy:764
     old "Ren'Py has set the projects directory to:"
     new "Ren'Py установила директорию проектов на:"
 
-    # translations.rpy:92
+    # translations.rpy:91
     old "Translations: [project.current.display_name!q]"
     new "Переводы: [project.current.display_name!q]"
 
-    # translations.rpy:133
+    # translations.rpy:132
     old "The language to work with. This should only contain lower-case ASCII characters and underscores."
     new "Язык работы. Он должен содержать только не-заглавные символы ASCII и подчёркивания."
 
-    # translations.rpy:159
+    # translations.rpy:158
     old "Generate empty strings for translations"
     new "Генерировать пустые строки для переводов"
 
-    # translations.rpy:177
+    # translations.rpy:176
     old "Generates or updates translation files. The files will be placed in game/tl/[persistent.translate_language!q]."
     new "Генерирует или обновляет файлы переводов. Файлы будут помещены в game/tl/[persistent.translate_language!q]."
 
-    # translations.rpy:197
+    # translations.rpy:196
     old "Extract String Translations"
     new "Извлечь Строки Для Перевода"
 
-    # translations.rpy:199
+    # translations.rpy:198
     old "Merge String Translations"
     new "Объединить Строки Перевода"
 
-    # translations.rpy:204
+    # translations.rpy:203
     old "Replace existing translations"
     new "Заменить существующие переводы"
 
-    # translations.rpy:205
+    # translations.rpy:204
     old "Reverse languages"
     new "Обратить языки"
 
-    # translations.rpy:209
+    # translations.rpy:208
     old "Update Default Interface Translations"
     new "Обновить Базовый Перевод Интерфейса"
 
-    # translations.rpy:229
+    # translations.rpy:228
     old "The extract command allows you to extract string translations from an existing project into a temporary file.\n\nThe merge command merges extracted translations into another project."
     new "Команда извлечения позволяет вам извлечь переводимые строки из существующего проекта во временный файл.\n\nКоманда объединения объединяет извлечённые переводы в другой перевод."
 
-    # translations.rpy:253
+    # translations.rpy:252
     old "Ren'Py is generating translations...."
     new "Ren'Py создаёт переводы..."
 
-    # translations.rpy:264
+    # translations.rpy:263
     old "Ren'Py has finished generating [language] translations."
     new "Ren'Py закончила создавать перевод для [language]."
 
-    # translations.rpy:277
+    # translations.rpy:276
     old "Ren'Py is extracting string translations..."
     new "Ren'Py извлекает переводимые строки..."
 
-    # translations.rpy:280
+    # translations.rpy:279
     old "Ren'Py has finished extracting [language] string translations."
     new "Ren'Py завершила извлечение [language] строк перевода."
 
-    # translations.rpy:300
+    # translations.rpy:299
     old "Ren'Py is merging string translations..."
     new "Ren'Py объединяет строки перевода..."
 
-    # translations.rpy:303
+    # translations.rpy:302
     old "Ren'Py has finished merging [language] string translations."
     new "Ren'Py завершила объединение [language] строк перевода."
 
-    # translations.rpy:314
+    # translations.rpy:313
     old "Updating default interface translations..."
     new "Обновляю базовый перевод интерфейса..."
 
-    # translations.rpy:343
+    # translations.rpy:342
     old "Extract Dialogue: [project.current.display_name!q]"
     new "Извлечь диалог: [project.current.display_name!q]"
 
-    # translations.rpy:359
+    # translations.rpy:358
     old "Format:"
     new "Формат:"
 
-    # translations.rpy:367
+    # translations.rpy:366
     old "Tab-delimited Spreadsheet (dialogue.tab)"
     new "Табулированная таблица (dialogue.tab)"
 
-    # translations.rpy:368
+    # translations.rpy:367
     old "Dialogue Text Only (dialogue.txt)"
     new "Только текст диалога (dialogue.txt)"
 
-    # translations.rpy:381
+    # translations.rpy:380
     old "Strip text tags from the dialogue."
     new "Убрать текстовые теги из диалога."
 
-    # translations.rpy:382
+    # translations.rpy:381
     old "Escape quotes and other special characters."
     new "Включать кавычки и регулярные выражения."
 
-    # translations.rpy:383
+    # translations.rpy:382
     old "Extract all translatable strings, not just dialogue."
     new "Извлечь все переводимые строки, не только диалог."
 
-    # translations.rpy:411
+    # translations.rpy:410
     old "Ren'Py is extracting dialogue...."
     new "Ren'Py извлекает диалог..."
 
-    # translations.rpy:415
+    # translations.rpy:414
     old "Ren'Py has finished extracting dialogue. The extracted dialogue can be found in dialogue.[persistent.dialogue_format] in the base directory."
     new "Ren'Py завершила извлечение диалога. Извлечённый диалог можно найти в файле dialogue.[persistent.dialogue_format] в директории проекта."
 
diff --git a/launcher/game/tl/russian/obsolete.rpy b/launcher/game/tl/russian/obsolete.rpy
new file mode 100644
index 0000000..645636d
--- /dev/null
+++ b/launcher/game/tl/russian/obsolete.rpy
@@ -0,0 +1,27 @@
+
+translate russian strings:
+
+    # _layout/classic_joystick_preferences.rpym:94
+    old "Joystick Mapping"
+    new "Раскладка джойстика"
+
+    # _layout/classic_load_save.rpym:138
+    old "Empty Slot."
+    new "Пустой слот"
+
+    # _layout/classic_load_save.rpym:170
+    old "a"
+    new "а"
+
+    # _layout/classic_load_save.rpym:179
+    old "q"
+    new "б"
+
+    # _compat/gamemenu.rpym:355
+    old "Previous"
+    new "Назад"
+
+    # _compat/gamemenu.rpym:362
+    old "Next"
+    new "Далее"
+
diff --git a/launcher/game/tl/russian/screens.rpy b/launcher/game/tl/russian/screens.rpy
index fd80f18..6c0b996 100644
--- a/launcher/game/tl/russian/screens.rpy
+++ b/launcher/game/tl/russian/screens.rpy
@@ -209,91 +209,91 @@ translate russian strings:
     old "Return"
     new "Вернуться"
 
-    # screens.rpy:534
+    # screens.rpy:536
     old "## About screen"
     new "## Экран Об игре"
 
-    # screens.rpy:536
+    # screens.rpy:538
     old "## This screen gives credit and copyright information about the game and Ren'Py."
     new "## Этот экран показывает авторскую информацию об игре и Ren'Py."
 
-    # screens.rpy:539
+    # screens.rpy:541
     old "## There's nothing special about this screen, and hence it also serves as an example of how to make a custom screen."
     new "## В этом экране нет ничего особенного, и он служит только примером того, каким можно сделать свой экран."
 
-    # screens.rpy:546
+    # screens.rpy:548
     old "## This use statement includes the game_menu screen inside this one. The vbox child is then included inside the viewport inside the game_menu screen."
     new "## Этот оператор включает игровое меню внутрь этого экрана. Дочерний vbox включён в порт просмотра внутри экрана игрового меню."
 
-    # screens.rpy:556
+    # screens.rpy:558
     old "Version [config.version!t]\n"
     new "Версия [config.version!t]\n"
 
-    # screens.rpy:558
+    # screens.rpy:560
     old "## gui.about is usually set in options.rpy."
     new "## gui.about обычно установлено в options.rpy."
 
-    # screens.rpy:562
+    # screens.rpy:564
     old "Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]"
     new "Сделано с помощью {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]"
 
-    # screens.rpy:565
+    # screens.rpy:567
     old "## This is redefined in options.rpy to add text to the about screen."
     new "## Это переустанавливается в options.rpy для добавления текста на экран Об игре."
 
-    # screens.rpy:577
+    # screens.rpy:579
     old "## Load and Save screens"
     new "## Экраны загрузки и сохранения"
 
-    # screens.rpy:579
+    # screens.rpy:581
     old "## These screens are responsible for letting the player save the game and load it again. Since they share nearly everything in common, both are implemented in terms of a third screen, file_slots."
     new "## Эти экраны ответственны за возможность сохранять и загружать игру. Так как они почти одинаковые, оба реализованы по правилам третьего экрана — file_slots."
 
-    # screens.rpy:583
+    # screens.rpy:585
     old "## https://www.renpy.org/doc/html/screen_special.html#save https://www.renpy.org/doc/html/screen_special.html#load"
     new "## https://www.renpy.org/doc/html/screen_special.html#save \n https://www.renpy.org/doc/html/screen_special.html#load"
 
-    # screens.rpy:602
+    # screens.rpy:604
     old "Page {}"
     new "{} страница"
 
-    # screens.rpy:602
+    # screens.rpy:604
     old "Automatic saves"
     new "Автосохранения"
 
-    # screens.rpy:602
+    # screens.rpy:604
     old "Quick saves"
     new "Быстрые сохранения"
 
-    # screens.rpy:608
+    # screens.rpy:610
     old "## This ensures the input will get the enter event before any of the buttons do."
-    new "## Это гарантирует, что ввод будет иметь приоритет над любой другой кнопкой на событие входа." ###
+    new "## Это гарантирует, что ввод будет принимать enter перед остальными кнопками."
 
-    # screens.rpy:612
+    # screens.rpy:614
     old "## The page name, which can be edited by clicking on a button."
     new "## Номер страницы, который может быть изменён посредством клика на кнопку."
 
-    # screens.rpy:624
+    # screens.rpy:626
     old "## The grid of file slots."
     new "## Таблица слотов."
 
-    # screens.rpy:644
+    # screens.rpy:646
     old "{#file_time}%A, %B %d %Y, %H:%M"
     new "{#file_time}%A, %d %B %Y, %H:%M"
 
-    # screens.rpy:644
+    # screens.rpy:646
     old "empty slot"
     new "Пустой слот"
 
-    # screens.rpy:652
+    # screens.rpy:654
     old "## Buttons to access other pages."
     new "## Кнопки для доступа к другим страницам."
 
-    # screens.rpy:661
+    # screens.rpy:663
     old "<"
     new "<"
 
-    # screens.rpy:664
+    # screens.rpy:666
     old "{#auto_page}A"
     new "{#auto_page}А"
 
@@ -301,375 +301,375 @@ translate russian strings:
     old "{#quick_page}Q"
     new "{#quick_page}Б"
 
-    # screens.rpy:669
+    # screens.rpy:671
     old "## range(1, 10) gives the numbers from 1 to 9."
     new "## range(1, 10) задаёт диапазон значений от 1 до 9."
 
-    # screens.rpy:673
+    # screens.rpy:675
     old ">"
     new ">"
 
-    # screens.rpy:708
+    # screens.rpy:710
     old "## Preferences screen"
     new "## Экран настроек"
 
-    # screens.rpy:710
+    # screens.rpy:712
     old "## The preferences screen allows the player to configure the game to better suit themselves."
     new "## Экран настроек позволяет игроку настраивать игру под себя."
 
-    # screens.rpy:713
+    # screens.rpy:715
     old "## https://www.renpy.org/doc/html/screen_special.html#preferences"
     new "## https://www.renpy.org/doc/html/screen_special.html#preferences"
 
-    # screens.rpy:730
+    # screens.rpy:732
     old "Display"
     new "Режим экрана"
 
-    # screens.rpy:731
+    # screens.rpy:733
     old "Window"
     new "Оконный"
 
-    # screens.rpy:732
+    # screens.rpy:734
     old "Fullscreen"
     new "Полный"
 
-    # screens.rpy:736
+    # screens.rpy:738
     old "Rollback Side"
     new "Сторона отката"
 
-    # screens.rpy:737
+    # screens.rpy:739
     old "Disable"
     new "Отключено"
 
-    # screens.rpy:738
+    # screens.rpy:740
     old "Left"
     new "Левая"
 
-    # screens.rpy:739
+    # screens.rpy:741
     old "Right"
     new "Правая"
 
-    # screens.rpy:744
+    # screens.rpy:746
     old "Unseen Text"
     new "Всего текста"
 
-    # screens.rpy:745
+    # screens.rpy:747
     old "After Choices"
     new "После выборов"
 
-    # screens.rpy:746
+    # screens.rpy:748
     old "Transitions"
     new "Переходов"
 
-    # screens.rpy:748
+    # screens.rpy:750
     old "## Additional vboxes of type \"radio_pref\" or \"check_pref\" can be added here, to add additional creator-defined preferences."
     new "## Дополнительные vbox'ы типа \"radio_pref\" или \"check_pref\" могут быть добавлены сюда для добавления новых настроек."
 
-    # screens.rpy:759
+    # screens.rpy:761
     old "Text Speed"
     new "Скорость текста"
 
-    # screens.rpy:763
+    # screens.rpy:765
     old "Auto-Forward Time"
     new "Скорость авточтения"
 
-    # screens.rpy:770
+    # screens.rpy:772
     old "Music Volume"
     new "Громкость музыки"
 
-    # screens.rpy:777
+    # screens.rpy:779
     old "Sound Volume"
     new "Громкость звуков"
 
-    # screens.rpy:783
+    # screens.rpy:785
     old "Test"
     new "Тест"
 
-    # screens.rpy:787
+    # screens.rpy:789
     old "Voice Volume"
     new "Громкость голоса"
 
-    # screens.rpy:798
+    # screens.rpy:800
     old "Mute All"
     new "Без звука"
 
-    # screens.rpy:874
+    # screens.rpy:876
     old "## History screen"
     new "## Экран истории"
 
-    # screens.rpy:876
+    # screens.rpy:878
     old "## This is a screen that displays the dialogue history to the player. While there isn't anything special about this screen, it does have to access the dialogue history stored in _history_list."
     new "## Этот экран показывает игроку историю диалогов. Хотя в этом экране нет ничего особенного, он имеет доступ к истории диалогов, хранимом в _history_list."
 
-    # screens.rpy:880
+    # screens.rpy:882
     old "## https://www.renpy.org/doc/html/history.html"
     new "## https://www.renpy.org/doc/html/history.html"
 
-    # screens.rpy:886
+    # screens.rpy:888
     old "## Avoid predicting this screen, as it can be very large."
     new "## Избегайте предсказывания этого экрана, так как он может быть очень массивным."
 
-    # screens.rpy:897
+    # screens.rpy:899
     old "## This lays things out properly if history_height is None."
     new "## Это всё правильно уравняет, если history_height будет установлен на None."
 
-    # screens.rpy:906
+    # screens.rpy:908
     old "## Take the color of the who text from the Character, if set."
     new "## Берёт цвет из who параметра персонажа, если он установлен."
 
-    # screens.rpy:914
+    # screens.rpy:916
     old "The dialogue history is empty."
     new "История диалогов пуста."
 
-    # screens.rpy:917
+    # screens.rpy:919
     old "## This determines what tags are allowed to be displayed on the history screen."
     new "## Это определяет, какие теги могут отображаться на экране истории."
 
-    # screens.rpy:964
+    # screens.rpy:966
     old "## Help screen"
     new "## Экран помощи"
 
-    # screens.rpy:966
+    # screens.rpy:968
     old "## A screen that gives information about key and mouse bindings. It uses other screens (keyboard_help, mouse_help, and gamepad_help) to display the actual help."
     new "## Экран, дающий информацию о клавишах управления. Он использует другие экраны (keyboard_help, mouse_help, и gamepad_help), чтобы показывать актуальную помощь."
 
-    # screens.rpy:985
+    # screens.rpy:987
     old "Keyboard"
     new "Клавиатура"
 
-    # screens.rpy:986
+    # screens.rpy:988
     old "Mouse"
     new "Мышь"
 
-    # screens.rpy:989
+    # screens.rpy:991
     old "Gamepad"
     new "Геймпад"
 
-    # screens.rpy:1002
+    # screens.rpy:1004
     old "Enter"
     new "Enter"
 
-    # screens.rpy:1003
+    # screens.rpy:1005
     old "Advances dialogue and activates the interface."
     new "Прохождение диалогов, активация интерфейса."
 
-    # screens.rpy:1006
+    # screens.rpy:1008
     old "Space"
     new "Пробел"
 
-    # screens.rpy:1007
+    # screens.rpy:1009
     old "Advances dialogue without selecting choices."
     new "Прохождение диалогов без возможности делать выбор."
 
-    # screens.rpy:1010
+    # screens.rpy:1012
     old "Arrow Keys"
     new "Стрелки"
 
-    # screens.rpy:1011
+    # screens.rpy:1013
     old "Navigate the interface."
     new "Навигация по интерфейсу."
 
-    # screens.rpy:1014
+    # screens.rpy:1016
     old "Escape"
     new "Esc"
 
-    # screens.rpy:1015
+    # screens.rpy:1017
     old "Accesses the game menu."
     new "Вход в игровое меню."
 
-    # screens.rpy:1018
+    # screens.rpy:1020
     old "Ctrl"
     new "Ctrl"
 
-    # screens.rpy:1019
+    # screens.rpy:1021
     old "Skips dialogue while held down."
     new "Пропускает диалоги, пока зажат."
 
-    # screens.rpy:1022
+    # screens.rpy:1024
     old "Tab"
     new "Tab"
 
-    # screens.rpy:1023
+    # screens.rpy:1025
     old "Toggles dialogue skipping."
     new "Включает режим пропуска."
 
-    # screens.rpy:1026
+    # screens.rpy:1028
     old "Page Up"
     new "Page Up"
 
-    # screens.rpy:1027
+    # screens.rpy:1029
     old "Rolls back to earlier dialogue."
     new "Откат назад по сюжету игры."
 
-    # screens.rpy:1030
+    # screens.rpy:1032
     old "Page Down"
     new "Page Down"
 
-    # screens.rpy:1031
+    # screens.rpy:1033
     old "Rolls forward to later dialogue."
     new "Откатывает предыдущее действие вперёд."
 
-    # screens.rpy:1035
+    # screens.rpy:1037
     old "Hides the user interface."
     new "Скрывает интерфейс пользователя."
 
-    # screens.rpy:1039
+    # screens.rpy:1041
     old "Takes a screenshot."
     new "Делает снимок экрана."
 
-    # screens.rpy:1043
+    # screens.rpy:1045
     old "Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}."
     new "Включает поддерживаемый {a=https://www.renpy.org/l/voicing}синтезатор речи{/a}."
 
-    # screens.rpy:1049
+    # screens.rpy:1051
     old "Left Click"
     new "Левый клик"
 
-    # screens.rpy:1053
+    # screens.rpy:1055
     old "Middle Click"
     new "Клик колёсиком"
 
-    # screens.rpy:1057
+    # screens.rpy:1059
     old "Right Click"
     new "Правый клик"
 
-    # screens.rpy:1061
+    # screens.rpy:1063
     old "Mouse Wheel Up\nClick Rollback Side"
     new "Колёсико вверх\nКлик на сторону отката"
 
-    # screens.rpy:1065
+    # screens.rpy:1067
     old "Mouse Wheel Down"
     new "Колёсико вниз"
 
-    # screens.rpy:1072
+    # screens.rpy:1074
     old "Right Trigger\nA/Bottom Button"
     new "Правый триггер\nA/Нижняя кнопка"
 
-    # screens.rpy:1076
+    # screens.rpy:1078
     old "Left Trigger\nLeft Shoulder"
     new "Левый Триггер\nЛевый Бампер"
 
-    # screens.rpy:1080
+    # screens.rpy:1082
     old "Right Shoulder"
     new "Правый бампер"
 
-    # screens.rpy:1085
+    # screens.rpy:1087
     old "D-Pad, Sticks"
     new "Крестовина, Стики"
 
-    # screens.rpy:1089
+    # screens.rpy:1091
     old "Start, Guide"
     new "Start, Guide"
 
-    # screens.rpy:1093
+    # screens.rpy:1095
     old "Y/Top Button"
     new "Y/Верхняя кнопка"
 
-    # screens.rpy:1096
+    # screens.rpy:1098
     old "Calibrate"
     new "Калибровка"
 
-    # screens.rpy:1124
+    # screens.rpy:1126
     old "## Additional screens"
     new "## Дополнительные экраны"
 
-    # screens.rpy:1128
+    # screens.rpy:1130
     old "## Confirm screen"
     new "## Экран подтверждения"
 
-    # screens.rpy:1130
+    # screens.rpy:1132
     old "## The confirm screen is called when Ren'Py wants to ask the player a yes or no question."
     new "## Экран подтверждения вызывается, когда Ren'Py хочет спросить у игрока вопрос Да или Нет."
 
-    # screens.rpy:1133
+    # screens.rpy:1135
     old "## https://www.renpy.org/doc/html/screen_special.html#confirm"
     new "## https://www.renpy.org/doc/html/screen_special.html#confirm"
 
-    # screens.rpy:1137
+    # screens.rpy:1139
     old "## Ensure other screens do not get input while this screen is displayed."
     new "## Гарантирует, что другие экраны будут недоступны, пока показан этот экран."
 
-    # screens.rpy:1161
+    # screens.rpy:1163
     old "Yes"
     new "Да"
 
-    # screens.rpy:1162
+    # screens.rpy:1164
     old "No"
     new "Нет"
 
-    # screens.rpy:1164
+    # screens.rpy:1166
     old "## Right-click and escape answer \"no\"."
     new "## Правый клик и esc, как ответ \"Нет\"."
 
-    # screens.rpy:1191
+    # screens.rpy:1193
     old "## Skip indicator screen"
     new "## Экран индикатора пропуска"
 
-    # screens.rpy:1193
+    # screens.rpy:1195
     old "## The skip_indicator screen is displayed to indicate that skipping is in progress."
     new "## Экран индикатора пропуска появляется для того, чтобы показать, что идёт пропуск."
 
-    # screens.rpy:1196
+    # screens.rpy:1198
     old "## https://www.renpy.org/doc/html/screen_special.html#skip-indicator"
     new "## https://www.renpy.org/doc/html/screen_special.html#skip-indicator"
 
-    # screens.rpy:1208
+    # screens.rpy:1210
     old "Skipping"
     new "Пропускаю"
 
-    # screens.rpy:1215
+    # screens.rpy:1217
     old "## This transform is used to blink the arrows one after another."
     new "## Эта трансформация используется, чтобы мигать стрелками одна за другой."
 
-    # screens.rpy:1242
+    # screens.rpy:1244
     old "## We have to use a font that has the BLACK RIGHT-POINTING SMALL TRIANGLE glyph in it."
     new "## Нам надо использовать шрифт, имеющий в себе символ U+25B8 (стрелку выше)."
 
-    # screens.rpy:1247
+    # screens.rpy:1249
     old "## Notify screen"
     new "## Экран уведомлений"
 
-    # screens.rpy:1249
+    # screens.rpy:1251
     old "## The notify screen is used to show the player a message. (For example, when the game is quicksaved or a screenshot has been taken.)"
     new "## Экран уведомлений используется, чтобы показать игроку оповещение. (Например, когда игра автосохранилась, или был сделан скриншот)"
 
-    # screens.rpy:1252
+    # screens.rpy:1254
     old "## https://www.renpy.org/doc/html/screen_special.html#notify-screen"
     new "## https://www.renpy.org/doc/html/screen_special.html#notify-screen"
 
-    # screens.rpy:1286
+    # screens.rpy:1288
     old "## NVL screen"
     new "## Экран NVL"
 
-    # screens.rpy:1288
+    # screens.rpy:1290
     old "## This screen is used for NVL-mode dialogue and menus."
     new "## Этот экран используется в диалогах и меню режима NVL."
 
-    # screens.rpy:1290
+    # screens.rpy:1292
     old "## https://www.renpy.org/doc/html/screen_special.html#nvl"
     new "## https://www.renpy.org/doc/html/screen_special.html#nvl"
 
-    # screens.rpy:1301
+    # screens.rpy:1303
     old "## Displays dialogue in either a vpgrid or the vbox."
     new "## Показывает диалог или в vpgrid, или в vbox."
 
-    # screens.rpy:1314
+    # screens.rpy:1316
     old "## Displays the menu, if given. The menu may be displayed incorrectly if config.narrator_menu is set to True, as it is above."
     new "## Показывает меню, если есть. Меню может показываться некорректно, если config.narrator_menu установлено на True."
 
-    # screens.rpy:1344
+    # screens.rpy:1346
     old "## This controls the maximum number of NVL-mode entries that can be displayed at once."
     new "## Это контролирует максимальное число строк NVL, могущих показываться за раз."
 
-    # screens.rpy:1406
+    # screens.rpy:1408
     old "## Mobile Variants"
     new "## Мобильные варианты"
 
-    # screens.rpy:1413
+    # screens.rpy:1415
     old "## Since a mouse may not be present, we replace the quick menu with a version that uses fewer and bigger buttons that are easier to touch."
     new "## Раз мышь может не использоваться, мы заменили быстрое меню версией, использующей меньше кнопок, но больших по размеру, чтобы их было легче касаться."
 
-    # screens.rpy:1429
+    # screens.rpy:1431
     old "Menu"
     new "Меню"
 
diff --git a/launcher/game/translations.rpy b/launcher/game/translations.rpy
index f1202ed..93cd0a6 100644
--- a/launcher/game/translations.rpy
+++ b/launcher/game/translations.rpy
@@ -68,7 +68,6 @@ init python:
             os.unlink(write_test)
 
         except:
-            raise
             tempdir = tempfile.mkdtemp()
 
         strings_json = os.path.join(tempdir, "strings.json")
diff --git a/renpy/__init__.py b/renpy/__init__.py
index 714c615..d975c9b 100644
--- a/renpy/__init__.py
+++ b/renpy/__init__.py
@@ -41,7 +41,7 @@ except ImportError:
     vc_version = 0
 
 # The tuple giving the version number.
-version_tuple = (6, 99, 14, 1, vc_version)
+version_tuple = (6, 99, 14, 3, vc_version)
 
 # The name of this version.
 version_name = "A funny thing happened."
diff --git a/renpy/ast.py b/renpy/ast.py
index 7fa7cde..9074758 100644
--- a/renpy/ast.py
+++ b/renpy/ast.py
@@ -479,6 +479,15 @@ class Node(object):
         # Does nothing by default.
         return
 
+    warp = False
+
+    def can_warp(self):
+        """
+        Returns true if this should be run while warping, False otherwise.
+        """
+
+        return self.warp
+
 
 def say_menu_with(expression, callback):
     """
@@ -831,7 +840,12 @@ class Python(Node):
         super(Python, self).__init__(loc)
 
         self.hide = hide
-        self.code = PyCode(python_code, loc=loc, mode='exec')
+
+        if hide:
+            self.code = PyCode(python_code, loc=loc, mode='hide')
+        else:
+            self.code = PyCode(python_code, loc=loc, mode='exec')
+
         self.store = store
 
     def diff_info(self):
@@ -882,7 +896,12 @@ class EarlyPython(Node):
         super(EarlyPython, self).__init__(loc)
 
         self.hide = hide
-        self.code = PyCode(python_code, loc=loc, mode='exec')
+
+        if hide:
+            self.code = PyCode(python_code, loc=loc, mode='hide')
+        else:
+            self.code = PyCode(python_code, loc=loc, mode='exec')
+
         self.store = store
 
     def diff_info(self):
@@ -1089,6 +1108,8 @@ class Show(Node):
         'atl',
         ]
 
+    warp = True
+
     def __init__(self, loc, imspec, atl=None):
         """
         @param imspec: A triple consisting of an image name (itself a
@@ -1120,6 +1141,8 @@ class Show(Node):
 
 class ShowLayer(Node):
 
+    warp = True
+
     __slots__ = [
         'layer',
         'at_list',
@@ -1164,6 +1187,8 @@ class Scene(Node):
         'atl',
         ]
 
+    warp = True
+
     def __init__(self, loc, imgspec, layer, atl=None):
         """
         @param imspec: A triple consisting of an image name (itself a
@@ -1214,6 +1239,8 @@ class Hide(Node):
         'imspec',
         ]
 
+    warp = True
+
     def __init__(self, loc, imgspec):
         """
         @param imspec: A triple consisting of an image name (itself a
@@ -1838,6 +1865,13 @@ class UserStatement(Node):
     def get_code(self, dialogue_filter=None):
         return self.line
 
+    def can_warp(self):
+
+        if self.call("warp"):
+            return True
+
+        return False
+
 
 def create_store(name):
     if name not in renpy.config.special_namespaces:
@@ -2001,7 +2035,10 @@ class Default(Node):
             d.ever_been_changed.add("_defaults_set")
 
         if self.varname not in defaults_set:
-            d[self.varname] = renpy.python.py_eval_bytecode(self.code.bytecode)
+
+            if start or (self.varname not in d.ever_been_changed):
+                d[self.varname] = renpy.python.py_eval_bytecode(self.code.bytecode)
+
             d.ever_been_changed.add(self.varname)
 
             defaults_set.add(self.varname)
@@ -2068,15 +2105,17 @@ class Translate(Node):
 
     __slots__ = [
         "identifier",
+        "alternate",
         "language",
         "block",
         "after",
         ]
 
-    def __init__(self, loc, identifier, language, block):
+    def __init__(self, loc, identifier, language, block, alternate=None):
         super(Translate, self).__init__(loc)
 
         self.identifier = identifier
+        self.alternate = alternate
         self.language = language
         self.block = block
 
@@ -2101,6 +2140,9 @@ class Translate(Node):
         if self.after is old:
             self.after = new
 
+    def lookup(self):
+        return renpy.game.script.translator.lookup_translate(self.identifier, getattr(self, "alternate", None))
+
     def execute(self):
 
         statement_name("translate")
@@ -2114,18 +2156,19 @@ class Translate(Node):
             renpy.game.seen_translates_count += 1
             renpy.game.new_translates_count += 1
 
-        next_node(renpy.game.script.translator.lookup_translate(self.identifier))
+        next_node(self.lookup())
 
         renpy.game.context().translate_identifier = self.identifier
+        renpy.game.context().alternate_translate_identifier = getattr(self, "alternate", None)
         renpy.game.context().translate_block_language = self.language
 
     def predict(self):
-        node = renpy.game.script.translator.lookup_translate(self.identifier)
+        node = self.lookup()
         return [ node ]
 
     def scry(self):
         rv = Scry()
-        rv._next = renpy.game.script.translator.lookup_translate(self.identifier)
+        rv._next = self.lookup()
         return rv
 
     def get_children(self, f):
@@ -2157,6 +2200,7 @@ class EndTranslate(Node):
         statement_name("end translate")
 
         renpy.game.context().translate_identifier = None
+        renpy.game.context().alternate_translate_identifier = None
         renpy.game.context().translate_block_language = None
 
 
diff --git a/renpy/atl.py b/renpy/atl.py
index ebd7817..95d1bff 100644
--- a/renpy/atl.py
+++ b/renpy/atl.py
@@ -480,12 +480,13 @@ class ATLTransformBase(renpy.object.Object):
 
         block = self.atl.compile(self.context)
 
-        if len(block.statements) == 1 and isinstance(block.statements[0], Interpolation):
-
-            interp = block.statements[0]
-
-            if interp.duration == 0 and interp.properties:
-                self.properties = interp.properties[:]
+        if all(
+            isinstance(statement, Interpolation) and statement.duration == 0
+            for statement in block.statements
+        ):
+            self.properties = []
+            for interp in block.statements:
+                self.properties.extend(interp.properties)
 
         if not constant and renpy.display.predict.predicting:
             self.predict_block = block
@@ -538,6 +539,10 @@ class ATLTransformBase(renpy.object.Object):
             events.append(self.transform_event)
             self.last_transform_event = self.transform_event
 
+        if self.transform_event in renpy.config.repeat_transform_events:
+            self.transform_event = None
+            self.last_transform_event = None
+
         old_exception_info = renpy.game.exception_info
 
         if (self.atl_st_offset is None) or (st - self.atl_st_offset) < 0:
diff --git a/renpy/audio/music.py b/renpy/audio/music.py
index 1bd8d2f..f696ece 100644
--- a/renpy/audio/music.py
+++ b/renpy/audio/music.py
@@ -172,6 +172,9 @@ def queue(filenames, channel="music", loop=None, clear_queue=True, fadein=0, tig
     if isinstance(filenames, basestring):
         filenames = [ filenames ]
 
+    if renpy.config.skipping == "fast":
+        stop(channel)
+
     with renpy.audio.audio.lock:
 
         try:
diff --git a/renpy/character.py b/renpy/character.py
index 97c8a81..5b33f2a 100644
--- a/renpy/character.py
+++ b/renpy/character.py
@@ -957,6 +957,9 @@ class ADVCharacter(object):
 
             renpy.store._side_image_attributes = attrs
 
+            if not interact:
+                renpy.store._side_image_attributes_reset = True
+
         if renpy.config.voice_tag_callback is not None:
             renpy.config.voice_tag_callback(self.voice_tag)
 
diff --git a/renpy/common/000statements.rpy b/renpy/common/000statements.rpy
index 9b21ab1..203b30e 100644
--- a/renpy/common/000statements.rpy
+++ b/renpy/common/000statements.rpy
@@ -39,7 +39,17 @@ init -1200 python:
 
 python early hide:
 
-    # Music play - The example of a full statement.
+    def warp_audio(p):
+        """
+        Determines if we should play this statement while warping.
+        """
+
+        if p.get("channel", None) is not None:
+            channel = eval(p["channel"])
+        else:
+            channel = "music"
+
+        return renpy.music.is_music(channel)
 
     def parse_play_music(l):
 
@@ -139,7 +149,8 @@ python early hide:
                               parse=parse_play_music,
                               execute=execute_play_music,
                               predict=predict_play_music,
-                              lint=lint_play_music)
+                              lint=lint_play_music,
+                              warp=warp_audio)
 
     # From here on, we'll steal bits of other statements when defining other
     # statements.
@@ -187,7 +198,8 @@ python early hide:
     renpy.register_statement('queue music',
                               parse=parse_queue_music,
                               execute=execute_queue_music,
-                              lint=lint_play_music)
+                              lint=lint_play_music,
+                              warp=warp_audio)
 
     def parse_stop_music(l):
         fadeout = "None"
@@ -220,12 +232,25 @@ python early hide:
 
     renpy.register_statement('stop music',
                               parse=parse_stop_music,
-                              execute=execute_stop_music)
+                              execute=execute_stop_music,
+                              warp=warp_audio)
 
 
     # Sound statements. They share alot with the equivalent music
     # statements.
 
+    def warp_sound(p):
+        """
+        Determines if we should play this statement while warping.
+        """
+
+        if p.get("channel", None) is not None:
+            channel = eval(p["channel"])
+        else:
+            channel = "sound"
+
+        return renpy.music.is_music(channel)
+
     def execute_play_sound(p):
 
         if p["channel"] is not None:
@@ -252,7 +277,8 @@ python early hide:
     renpy.register_statement('play sound',
                               parse=parse_play_music,
                               execute=execute_play_sound,
-                              lint=lint_play_sound)
+                              lint=lint_play_sound,
+                              warp=warp_sound)
 
     def execute_queue_sound(p):
         if p["channel"] is not None:
@@ -271,7 +297,8 @@ python early hide:
     renpy.register_statement('queue sound',
                               parse=parse_queue_music,
                               execute=execute_queue_sound,
-                              lint=lint_play_sound)
+                              lint=lint_play_sound,
+                              warp=warp_sound)
 
     def execute_stop_sound(p):
         if p["channel"] is not None:
@@ -285,7 +312,8 @@ python early hide:
 
     renpy.register_statement('stop sound',
                               parse=parse_stop_music,
-                              execute=execute_stop_sound)
+                              execute=execute_stop_sound,
+                              warp=warp_sound)
 
 
     # Generic play/queue/stop statements. These take a channel name as
@@ -345,17 +373,20 @@ python early hide:
                               parse=parse_play_generic,
                               execute=execute_play_music,
                               predict=predict_play_music,
-                              lint=lint_play_generic)
+                              lint=lint_play_generic,
+                              warp=warp_audio)
 
     renpy.register_statement('queue',
                               parse=parse_queue_generic,
                               execute=execute_queue_music,
-                              lint=lint_play_generic)
+                              lint=lint_play_generic,
+                              warp=warp_audio)
 
     renpy.register_statement('stop',
                               parse=parse_stop_generic,
                               execute=execute_stop_music,
-                              lint=lint_stop_generic)
+                              lint=lint_stop_generic,
+                              warp=warp_audio)
 
 
 
@@ -399,6 +430,9 @@ python early hide:
     # Should we predict screens?
     config.predict_screen_statements = True
 
+    def warp_true():
+        return True
+
     def parse_show_call_screen(l):
 
         # Parse a name.
@@ -498,7 +532,8 @@ python early hide:
                               parse=parse_show_call_screen,
                               execute=execute_show_screen,
                               predict=predict_screen,
-                              lint=lint_screen)
+                              lint=lint_screen,
+                              warp=warp_true)
 
     renpy.register_statement("call screen",
                               parse=parse_show_call_screen,
@@ -508,4 +543,5 @@ python early hide:
 
     renpy.register_statement("hide screen",
                               parse=parse_hide_screen,
-                              execute=execute_hide_screen)
+                              execute=execute_hide_screen,
+                              warp=warp_true)
diff --git a/renpy/common/000window.rpy b/renpy/common/000window.rpy
index 4781a91..efdbc07 100644
--- a/renpy/common/000window.rpy
+++ b/renpy/common/000window.rpy
@@ -54,7 +54,7 @@ init -1200 python:
         if trans is False:
             trans = config.window_show_transition
 
-        if _preferences.show_empty_window:
+        if _preferences.show_empty_window and (not renpy.game.after_rollback):
             renpy.with_statement(None)
             store._window = True
             renpy.with_statement(trans)
@@ -79,7 +79,7 @@ init -1200 python:
         if trans is False:
             trans = config.window_hide_transition
 
-        if _preferences.show_empty_window:
+        if _preferences.show_empty_window and (not renpy.game.after_rollback):
             renpy.with_statement(None)
             store._window = False
             renpy.with_statement(trans)
@@ -164,13 +164,16 @@ python early hide:
     renpy.register_statement('window show',
                               parse=parse_window,
                               execute=execute_window_show,
-                              lint=lint_window)
+                              lint=lint_window,
+                              warp=lambda : True)
 
     renpy.register_statement('window hide',
                               parse=parse_window,
                               execute=execute_window_hide,
-                              lint=lint_window)
+                              lint=lint_window,
+                              warp=lambda : True)
 
     renpy.register_statement('window auto',
                              parse=parse_window_auto,
-                             execute=execute_window_auto)
+                             execute=execute_window_auto,
+                             warp=lambda : True)
diff --git a/renpy/common/00action_file.rpy b/renpy/common/00action_file.rpy
index 0fdd7e6..cb70b55 100644
--- a/renpy/common/00action_file.rpy
+++ b/renpy/common/00action_file.rpy
@@ -341,7 +341,7 @@ init -1500 python:
             self.page = page
             self.cycle = cycle
 
-            self.alt = "Save slot %s: [text]" % (name,)
+            self.alt = __("Save slot %s: [text]") % (name,)
 
         def __call__(self):
 
@@ -414,7 +414,7 @@ init -1500 python:
             self.page = page
             self.newest = newest
 
-            self.alt = "Load slot %s: [text]" % (name,)
+            self.alt = __("Load slot %s: [text]") % (name,)
 
 
         def __call__(self):
@@ -456,7 +456,7 @@ init -1500 python:
              If true, prompts before deleting a file.
          """
 
-        alt = "Delete slot [text]"
+        alt = _("Delete slot [text]")
 
         def __init__(self, name, confirm=True, page=None):
             self.name = name
@@ -534,7 +534,13 @@ init -1500 python:
 
         def __init__(self, page):
             self.page = str(page)
-            self.alt = "File page [text]"
+
+            if page == "auto":
+                self.alt = _("File page auto")
+            elif page == "quick":
+                self.alt = _("File page quick")
+            else:
+                self.alt = _("File page [text]")
 
         def __call__(self):
             if not self.get_sensitive():
@@ -724,7 +730,7 @@ init -1500 python:
              If true, we can go to the first page when on the last file page if max is set.
          """
 
-        alt = "Next file page"
+        alt = _("Next file page.")
 
         def __init__(self, max=None, wrap=False):
 
@@ -788,7 +794,7 @@ init -1500 python:
              If true, we can go to the last page when on the first file page if max is set.
          """
 
-        alt = "Previous file page"
+        alt = _("Previous file page.")
 
         def __init__(self, max=None, wrap=False):
 
@@ -867,7 +873,7 @@ init -1500 python:
             Notify(message),
             ]
 
-        rv[0].alt = "Quick save."
+        rv[0].alt = _("Quick save.")
 
         if not getattr(renpy.context(), "_menu", False):
             rv.insert(0, FileTakeScreenshot())
@@ -886,7 +892,7 @@ init -1500 python:
         """
 
         rv = FileLoad(1, page="quick", confirm=confirm, newest=False)
-        rv.alt = "Quick load."
+        rv.alt = _("Quick load.")
         return rv
 
 init 1050 python hide:
diff --git a/renpy/common/00action_other.rpy b/renpy/common/00action_other.rpy
index ee90f03..6f053ba 100644
--- a/renpy/common/00action_other.rpy
+++ b/renpy/common/00action_other.rpy
@@ -33,6 +33,11 @@ init -1500 python:
         def __init__(self, action):
             self.action = action
 
+            try:
+                self.alt = action.alt
+            except:
+                pass
+
         def __call__(self):
             return self.action.__call__()
 
@@ -336,7 +341,7 @@ init -1500 python:
             the default language of the game script.
         """
 
-        alt = "Language [text]"
+        alt = _("Language [text]")
 
         def __init__(self, language):
             self.language = language
diff --git a/renpy/common/00build.rpy b/renpy/common/00build.rpy
index f062779..49cd025 100644
--- a/renpy/common/00build.rpy
+++ b/renpy/common/00build.rpy
@@ -132,6 +132,7 @@ init -1500 python in build:
         ("dialogue.txt", None),
         ("dialogue.tab", None),
         ("profile_screen.txt", None),
+        ("files.txt", None),
 
         ("tmp/", None),
         ("game/saves/", None),
diff --git a/renpy/common/00gui.rpy b/renpy/common/00gui.rpy
index 6e45a7c..c8fc5da 100644
--- a/renpy/common/00gui.rpy
+++ b/renpy/common/00gui.rpy
@@ -186,6 +186,8 @@ init -1100 python in gui:
     renpy.pure("gui.SetPreference")
     renpy.pure("gui.TogglePreference")
 
+    # The extension used for auto-defined images.
+    button_image_extension = ".png"
 
     def button_properties(kind):
         """
@@ -241,9 +243,9 @@ init -1100 python in gui:
         backgrounds = [ ]
 
         if kind != "button":
-            backgrounds.append("gui/button/" + kind[:-7] + "_[prefix_]background.png")
+            backgrounds.append("gui/button/" + kind[:-7] + "_[prefix_]background" + button_image_extension)
 
-        backgrounds.append("gui/button/[prefix_]background.png")
+        backgrounds.append("gui/button/[prefix_]background" + button_image_extension)
 
         if renpy.variant("small"):
             backgrounds = [ i.replace("gui/button", "gui/phone/button") for i in backgrounds ] + backgrounds
diff --git a/renpy/common/00library.rpy b/renpy/common/00library.rpy
index 467cf5e..377cc29 100644
--- a/renpy/common/00library.rpy
+++ b/renpy/common/00library.rpy
@@ -147,6 +147,16 @@ init -1700 python:
     _("Clipboard voicing enabled. ")
     _("Self-voicing enabled. ")
 
+    _("bar")
+    _("selected")
+    _("viewport")
+    _("horizontal scroll")
+    _("vertical scroll")
+    _("activate")
+    _("deactivate")
+    _("increase")
+    _("decrease")
+
     def sv(what, interact=True):
         """
         Uses the narrator to speak `what` iff self-voicing is enabled.
@@ -284,7 +294,78 @@ init -1000 python:
 
     # Record the builtins.
     renpy.lint.renpy_builtins = set(globals())
-    renpy.lint.renpy_builtins.remove('menu')
+
+    for i in """
+adv
+anim
+blinds
+center
+default
+default_transition
+dissolve
+ease
+easeinbottom
+easeinleft
+easeinright
+easeintop
+easeoutbottom
+easeoutleft
+easeoutright
+easeouttop
+fade
+hpunch
+irisin
+irisout
+left
+menu
+mouse_visible
+move
+moveinbottom
+moveinleft
+moveinright
+moveintop
+moveoutbottom
+moveoutleft
+moveoutright
+moveouttop
+name_only
+nvl
+nvl_variant
+offscreenleft
+offscreenright
+pixellate
+pushdown
+pushleft
+pushright
+pushup
+right
+save_name
+slideawaydown
+slideawayleft
+slideawayright
+slideawayup
+slidedown
+slideleft
+slideright
+slideup
+squares
+suppress_overlay
+sv
+top
+topleft
+topright
+truecenter
+vpunch
+wipedown
+wipeleft
+wiperight
+wipeup
+zoomin
+zoominout
+zoomout
+""".split():
+
+        renpy.lint.renpy_builtins.remove(i)
 
 # After init, make some changes based on if config.developer is True.
 init 1700 python hide:
diff --git a/renpy/common/00nvl_mode.rpy b/renpy/common/00nvl_mode.rpy
index 05eb894..327a621 100644
--- a/renpy/common/00nvl_mode.rpy
+++ b/renpy/common/00nvl_mode.rpy
@@ -237,11 +237,29 @@ init -1500 python:
         nvl_show_core()
 
     def nvl_show(with_):
+        """
+        :doc: nvl
+
+        The python equivalent of the ``nvl show`` statement.
+
+        `with_`
+            The transition to use to show the NVL-mode window.
+        """
+
         nvl_show_core()
         renpy.with_statement(with_)
         store._last_say_who = "nvl"
 
     def nvl_hide(with_):
+        """
+        :doc: nvl
+
+        The python equivalent of the ``nvl hide`` statement.
+
+        `with_`
+            The transition to use to hide the NVL-mode window.
+        """
+
         nvl_show_core()
         renpy.with_statement(None)
         renpy.with_statement(with_)
@@ -348,7 +366,10 @@ init -1500 python:
             else:
                 checkpoint = True
 
-            self.push_nvl_list(who, what, multiple=multiple)
+            if multiple is not None:
+                self.push_nvl_list(who, what, multiple=multiple)
+            else:
+                self.push_nvl_list(who, what)
 
             renpy.display_say(
                 who,
@@ -362,7 +383,10 @@ init -1500 python:
 
         def do_done(self, who, what, multiple=None):
 
-            self.push_nvl_list(who, what, multiple=multiple)
+            if multiple is not None:
+                self.push_nvl_list(who, what, multiple=multiple)
+            else:
+                self.push_nvl_list(who, what)
 
             if multiple is None:
                 start = -1
@@ -407,6 +431,12 @@ init -1500 python:
         kind=adv)
 
     def nvl_clear():
+        """
+        :doc: nvl
+
+        The python equivalent of the ``nvl clear`` statement.
+        """
+
         store.nvl_list = [ ]
 
     # Run clear at the start of the game.
@@ -414,6 +444,16 @@ init -1500 python:
 
 
     def nvl_menu(items):
+        """
+        :doc: nvl
+
+        A Python function that displays a menu in NVL style. This is rarely
+        used directly. Instead, it's assigned to the :var:`menu` variable,
+        using something like::
+
+            define menu = nvl_menu
+        """
+
 
         renpy.mode('nvl_menu')
 
diff --git a/renpy/common/00preferences.rpy b/renpy/common/00preferences.rpy
index f920272..6a27d4c 100644
--- a/renpy/common/00preferences.rpy
+++ b/renpy/common/00preferences.rpy
@@ -204,7 +204,7 @@ init -1500 python:
 
         def get():
 
-            if name == "display":
+            if name == _("display"):
                 if value == "fullscreen":
                     return SetField(_preferences, "fullscreen", True)
                 elif value == "window":
@@ -216,7 +216,7 @@ init -1500 python:
                 elif isinstance(value, (int, float)):
                     return __DisplayAction(value)
 
-            elif name == "transitions":
+            elif name == _("transitions"):
 
                 if value == "all":
                     return SetField(_preferences, "transitions", 2)
@@ -225,9 +225,9 @@ init -1500 python:
                 elif value == "none":
                     return SetField(_preferences, "transitions", 0)
                 elif value == "toggle":
-                    return ToggleField(_preferences, "transitions", true_value=2, false_value=0)
+                    return ToggleField(_preferences, "transitions", true_value=2, false_value=0), _("skip transitions")
 
-            elif name == "video sprites":
+            elif name == _("video sprites"):
 
                 if value == "show":
                     return SetField(_preferences, "video_image_fallback", False)
@@ -236,7 +236,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "video_image_fallback")
 
-            elif name == "show empty window":
+            elif name == _("show empty window"):
 
                 if value == "show":
                     return SetField(_preferences, "show_empty_window", True)
@@ -245,7 +245,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "show_empty_window")
 
-            elif name == "text speed":
+            elif name == _("text speed"):
 
                 if value is None:
                     bar_range = range or 200
@@ -253,36 +253,37 @@ init -1500 python:
                 elif isinstance(value, int):
                     return SetField(_preferences, "text_cps", value)
 
-            elif name == "joystick" or name == "joystick...":
+            elif name == _("joystick") or name == _("joystick..."):
 
                 if renpy.display.joystick.enabled or config.always_has_joystick:
                     return ShowMenu("joystick_preferences")
                 else:
                     return None
 
-            elif name == "skip":
+            elif name == _("skip"):
 
                 if value == "all messages" or value == "all":
-                    return SetField(_preferences, "skip_unseen", True)
+                    return SetField(_preferences, "skip_unseen", True), _("skip unseen [text]")
+
                 elif value == "seen messages" or value == "seen":
-                    return SetField(_preferences, "skip_unseen", False)
+                    return SetField(_preferences, "skip_unseen", False), _("skip unseen [text]")
                 elif value == "toggle":
-                    return ToggleField(_preferences, "skip_unseen")
+                    return ToggleField(_preferences, "skip_unseen"), _("skip unseen text")
 
-            elif name == "begin skipping":
+            elif name == _("begin skipping"):
 
                 return Skip()
 
-            elif name == "after choices":
+            elif name == _("after choices"):
 
                 if value == "keep skipping" or value == "keep" or value == "skip":
                     return SetField(_preferences, "skip_after_choices", True)
                 elif value == "stop skipping" or value == "stop":
                     return SetField(_preferences, "skip_after_choices", False)
                 elif value == "toggle":
-                    return ToggleField(_preferences, "skip_after_choices")
+                    return ToggleField(_preferences, "skip_after_choices"), _("skip after choices")
 
-            elif name == "auto-forward time":
+            elif name == _("auto-forward time"):
 
                 if value is None:
 
@@ -296,16 +297,17 @@ init -1500 python:
                 elif isinstance(value, int):
                     return SetField(_preferences, "afm_time", value)
 
-            elif name == "auto-forward":
+            elif name == _("auto-forward"):
 
                 if value == "enable":
                     return SetField(_preferences, "afm_enable", True)
                 elif value == "disable":
                     return SetField(_preferences, "afm_enable", False)
                 elif value == "toggle":
-                    return ToggleField(_preferences, "afm_enable")
+                    return ToggleField(_preferences, "afm_enable"), _("Auto forward")
+
 
-            elif name == "auto-forward after click":
+            elif name == _("auto-forward after click"):
 
                 if value == "enable":
                     return SetField(_preferences, "afm_after_click", True)
@@ -314,7 +316,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "afm_after_click")
 
-            elif name == "automatic move":
+            elif name == _("automatic move"):
 
                 if value == "enable":
                     return SetField(_preferences, "mouse_move", True)
@@ -323,7 +325,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "mouse_move")
 
-            elif name == "wait for voice":
+            elif name == _("wait for voice"):
 
                 if value == "enable":
                     return SetField(_preferences, "wait_voice", True)
@@ -332,7 +334,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "wait_voice")
 
-            elif name == "voice sustain":
+            elif name == _("voice sustain"):
 
                 if value == "enable":
                     return SetField(_preferences, "voice_sustain", True)
@@ -341,7 +343,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "voice_sustain")
 
-            elif name == "self voicing":
+            elif name == _("self voicing"):
 
                 if value == "enable":
                     return SetField(_preferences, "self_voicing", True)
@@ -350,7 +352,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "self_voicing")
 
-            elif name == "clipboard voicing":
+            elif name == _("clipboard voicing"):
 
                 if value == "enable":
                     return SetField(_preferences, "self_voicing", "clipboard")
@@ -359,7 +361,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "self_voicing", true_value="clipboard")
 
-            elif name == "debug voicing":
+            elif name == _("debug voicing"):
 
                 if value == "enable":
                     return SetField(_preferences, "self_voicing", "debug")
@@ -368,7 +370,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "self_voicing", true_value="debug")
 
-            elif name == "emphasize audio":
+            elif name == _("emphasize audio"):
 
                 if value == "enable":
                     return SetField(_preferences, "emphasize_audio", True)
@@ -377,7 +379,7 @@ init -1500 python:
                 elif value == "toggle":
                     return ToggleField(_preferences, "emphasize_audio")
 
-            elif name == "rollback side":
+            elif name == _("rollback side"):
 
                 if value in [ "left", "right", "disable" ]:
                     if renpy.mobile:
@@ -387,16 +389,16 @@ init -1500 python:
 
                     return SetField(_preferences, field, value)
 
-            elif name == "gl powersave":
+            elif name == _("gl powersave"):
                 if value == "toggle":
                     return [ ToggleField(_preferences, "gl_powersave"), _DisplayReset() ]
                 else:
                     return [ SetField(_preferences, "gl_powersave", value), _DisplayReset() ]
 
-            elif name == "gl framerate":
+            elif name == _("gl framerate"):
                 return [ SetField(_preferences, "gl_framerate", value), _DisplayReset() ]
 
-            elif name == "gl tearing":
+            elif name == _("gl tearing"):
                 return [ SetField(_preferences, "gl_tearing", value), _DisplayReset() ]
 
             mixer_names = {
@@ -406,31 +408,45 @@ init -1500 python:
                 "all" : _preferences.get_all_mixers(),
             }
 
+            # Make these available to the translation system
+            if False:
+                _("music volume")
+                _("sound volume")
+                _("voice volume")
+                _("mute music")
+                _("mute sound")
+                _("mute voice")
+                _("mute all")
+
             n = name.split()
 
             if n[-1] == "volume":
                 if len(n) == 3 and n[0] == "mixer":
+                    alt = n[1] + " volume"
                     mixer = n[1]
                 elif len(n) == 2:
+                    alt = n[0] + " volume"
                     mixer = mixer_names.get(n[0], n[0])
 
                 if value is None:
-                    return MixerValue(mixer)
+                    return MixerValue(mixer), alt
                 else:
-                    return SetMixer(mixer, value)
+                    return SetMixer(mixer, value), __(alt) + " [text]"
 
             if n[-1] == "mute":
                 if len(n) == 3 and n[0] == "mixer":
+                    alt = "mute " + n[1]
                     mixer = n[1]
                 elif len(n) == 2:
+                    alt = "mute " + n[0]
                     mixer = mixer_names.get(n[0], n[0])
 
                 if value == "enable":
-                    return SetMute(mixer, True)
+                    return SetMute(mixer, True), __(alt) + " [text]"
                 elif value == "disable":
-                    return SetMute(mixer, False)
+                    return SetMute(mixer, False), __(alt) + " [text]"
                 elif value == "toggle":
-                    return ToggleMute(mixer)
+                    return ToggleMute(mixer), alt
 
             else:
                 raise Exception("Preference(%r, %r) is unknown." % (name , value))
@@ -438,7 +454,16 @@ init -1500 python:
         rv = get()
 
         if rv is not None:
-            rv.alt = name + " [text]"
+
+            if isinstance(rv, tuple):
+                rv, alt = rv
+            else:
+                alt = None
+
+            if alt is not None:
+                rv.alt = __(alt)
+            else:
+                rv.alt = __(name) + " [text]"
 
         return rv
 
diff --git a/renpy/common/00start.rpy b/renpy/common/00start.rpy
index 1523466..c6ecea5 100644
--- a/renpy/common/00start.rpy
+++ b/renpy/common/00start.rpy
@@ -196,6 +196,10 @@ label _start:
         renpy.block_rollback()
 
     call _gl_test
+
+    python hide:
+        renpy.warp.warp()
+
     call _load_reload_game from _call__load_reload_game_1
 
     python hide:
diff --git a/renpy/common/00updater.rpy b/renpy/common/00updater.rpy
index f579040..9a460b2 100644
--- a/renpy/common/00updater.rpy
+++ b/renpy/common/00updater.rpy
@@ -654,7 +654,12 @@ init -1500 python in updater:
                     rv = os.path.join(self.app, "/".join(path[1:]))
                     return rv
 
-            return os.path.join(self.base, name)
+            rv = os.path.join(self.base, name)
+
+            if renpy.windows:
+                rv = "\\\\?\\" + rv.replace("/", "\\")
+
+            return rv
 
         def load_state(self):
             """
diff --git a/renpy/common/00voice.rpy b/renpy/common/00voice.rpy
index 0fbf2f0..05c368d 100644
--- a/renpy/common/00voice.rpy
+++ b/renpy/common/00voice.rpy
@@ -305,9 +305,14 @@ init -1500 python:
             self.tag = _voice.tag
 
             if not self.filename and config.auto_voice:
-                tlid = renpy.game.context().translate_identifier
 
-                if tlid is not None:
+                for tlid in [
+                    renpy.game.context().translate_identifier,
+                    renpy.game.context().alternate_translate_identifier,
+                    ]:
+
+                    if tlid is None:
+                        continue
 
                     if isinstance(config.auto_voice, (str, unicode)):
                         fn = config.auto_voice.format(id=tlid)
@@ -323,6 +328,8 @@ init -1500 python:
                         else:
                             self.filename = fn
 
+                        break
+
                 self.tlid = tlid
 
             if self.filename:
diff --git a/renpy/common/_developer/developer.rpym b/renpy/common/_developer/developer.rpym
index deeba57..15c6ca7 100644
--- a/renpy/common/_developer/developer.rpym
+++ b/renpy/common/_developer/developer.rpym
@@ -518,7 +518,10 @@ label _filename_list:
 
     python hide:
         import os
-        f = file("files.txt", "w")
+
+        FILES_TXT = os.path.join(renpy.config.basedir, "files.txt")
+
+        f = file(FILES_TXT, "w")
 
         for dirname, dirs, files in os.walk(config.gamedir):
 
@@ -533,7 +536,7 @@ label _filename_list:
 
         f.close()
 
-        renpy.launch_editor(["files.txt"], transient=1)
+        renpy.launch_editor([ FILES_TXT ], transient=1)
 
     return
 
diff --git a/renpy/config.py b/renpy/config.py
index 65a672b..d28ceda 100644
--- a/renpy/config.py
+++ b/renpy/config.py
@@ -873,6 +873,12 @@ optimize_texture_bounds = True
 # Should we predict everything in a ConditionSwitch?
 conditionswitch_predict_all = False
 
+# Transform events to deliver each time one happens.
+repeat_transform_events = [ "show", "replace", "update" ]
+
+# How many statements should we warp through?
+warp_limit = 1000
+
 del os
 del collections
 
diff --git a/renpy/defaultstore.py b/renpy/defaultstore.py
index 209161f..d9cc85a 100644
--- a/renpy/defaultstore.py
+++ b/renpy/defaultstore.py
@@ -421,6 +421,7 @@ _in_replay = None
 
 # Used to store the side image attributes.
 _side_image_attributes = None
+_side_image_attributes_reset = False
 
 # True if we're in the main_menu, False otherwise. This controls autosave,
 # among other things.
diff --git a/renpy/display/behavior.py b/renpy/display/behavior.py
index f8e793b..fd706db 100644
--- a/renpy/display/behavior.py
+++ b/renpy/display/behavior.py
@@ -21,6 +21,7 @@
 
 # This contains various Displayables that handle events.
 
+from __future__ import print_function
 
 import renpy.display
 import renpy.audio
@@ -88,31 +89,41 @@ def compile_event(key, keydown):
     while part[0] in MODIFIERS:
         modifiers.add(part.pop(0))
 
+    key = "_".join(part)
+
     if "repeat" in modifiers:
         rv += " and (ev.repeat)"
     else:
         rv += " and (not ev.repeat)"
 
-    if "alt" in modifiers:
-        rv += " and (ev.mod & %d)" % pygame.KMOD_ALT
-    else:
-        rv += " and not (ev.mod & %d)" % pygame.KMOD_ALT
+    if key not in [ "K_LALT", "K_RALT" ]:
 
-    if "meta" in modifiers:
-        rv += " and (ev.mod & %d)" % pygame.KMOD_META
-    else:
-        rv += " and not (ev.mod & %d)" % pygame.KMOD_META
+        if "alt" in modifiers:
+            rv += " and (ev.mod & %d)" % pygame.KMOD_ALT
+        else:
+            rv += " and not (ev.mod & %d)" % pygame.KMOD_ALT
 
-    if "ctrl" in modifiers:
-        rv += " and (ev.mod & %d)" % pygame.KMOD_CTRL
-    else:
-        rv += " and not (ev.mod & %d)" % pygame.KMOD_CTRL
+    if key not in [ "K_LGUI", "K_RGUI" ]:
+
+        if "meta" in modifiers:
+            rv += " and (ev.mod & %d)" % pygame.KMOD_META
+        else:
+            rv += " and not (ev.mod & %d)" % pygame.KMOD_META
 
-    if "shift" in modifiers:
-        rv += " and (ev.mod & %d)" % pygame.KMOD_SHIFT
+    if key not in [ "K_LCTRL", "K_RCTRL" ]:
 
-    if "noshift" in modifiers:
-        rv += " and not (ev.mod & %d)" % pygame.KMOD_SHIFT
+        if "ctrl" in modifiers:
+            rv += " and (ev.mod & %d)" % pygame.KMOD_CTRL
+        else:
+            rv += " and not (ev.mod & %d)" % pygame.KMOD_CTRL
+
+    if key not in [ "K_LSHIFT", "K_RSHIFT" ]:
+
+        if "shift" in modifiers:
+            rv += " and (ev.mod & %d)" % pygame.KMOD_SHIFT
+
+        if "noshift" in modifiers:
+            rv += " and not (ev.mod & %d)" % pygame.KMOD_SHIFT
 
     if len(part) == 1:
         if len(part[0]) != 1:
@@ -130,8 +141,6 @@ def compile_event(key, keydown):
             else:
                 return "(False)"
 
-        key = "_".join(part)
-
         rv += " and ev.key == %d)" % (getattr(pygame.constants, key))
 
     return rv
@@ -909,7 +918,12 @@ class Button(renpy.display.layout.Window):
         return ""
 
     def _tts_all(self):
-        return self._tts_common(alt(self.action))
+        rv = self._tts_common(alt(self.action))
+
+        if self.is_selected():
+            rv += " " + renpy.minstore.__("selected")
+
+        return rv
 
 # Reimplementation of the TextButton widget as a Button and a Text
 # widget.
@@ -1221,7 +1235,7 @@ class Input(renpy.text.text.Text):  # @UndefinedVariable
         if not self.editable:
             return None
 
-        if pygame.key.get_mods() & pygame.KMOD_LALT:
+        if (ev.type == pygame.KEYDOWN) and (pygame.key.get_mods() & pygame.KMOD_LALT) and (not ev.unicode):
             return None
 
         l = len(self.content)
@@ -1766,7 +1780,7 @@ class Bar(renpy.display.core.Displayable):
         ignore_event = False
 
         if not grabbed and map_event(ev, "bar_activate"):
-            renpy.display.tts.speak("activate")
+            renpy.display.tts.speak(renpy.minstore.__("activate"))
             renpy.display.focus.set_grab(self)
             self.set_style_prefix("selected_hover_", True)
             just_grabbed = True
@@ -1783,12 +1797,12 @@ class Bar(renpy.display.core.Displayable):
                 decrease = "bar_left"
 
             if map_event(ev, decrease):
-                renpy.display.tts.speak("decrease")
+                renpy.display.tts.speak(renpy.minstore.__("decrease"))
                 value -= self.adjustment.step
                 ignore_event = True
 
             if map_event(ev, increase):
-                renpy.display.tts.speak("increase")
+                renpy.display.tts.speak(renpy.minstore.__("increase"))
                 value += self.adjustment.step
                 ignore_event = True
 
@@ -1819,16 +1833,18 @@ class Bar(renpy.display.core.Displayable):
                 value = int(value)
 
             if value < 0:
+                renpy.display.tts.speak("")
                 value = 0
 
             if value > range:
+                renpy.display.tts.speak("")
                 value = range
 
         if invert:
             value = range - value
 
         if grabbed and not just_grabbed and map_event(ev, "bar_deactivate"):
-            renpy.display.tts.speak("deactivate")
+            renpy.display.tts.speak(renpy.minstore.__("deactivate"))
             self.set_style_prefix("hover_", True)
             renpy.display.focus.set_grab(None)
             ignore_event = True
@@ -1855,9 +1871,9 @@ class Bar(renpy.display.core.Displayable):
         if self.value is not None:
             alt = self.value.alt
         else:
-            alt = "Bar"
+            alt = ""
 
-        return self._tts_common(alt)
+        return self._tts_common(alt) + renpy.minstore.__("bar")
 
 
 class Conditional(renpy.display.layout.Container):
diff --git a/renpy/display/core.py b/renpy/display/core.py
index dd94ffe..74b5d5f 100644
--- a/renpy/display/core.py
+++ b/renpy/display/core.py
@@ -1864,6 +1864,9 @@ class Interface(object):
         if self.safe_mode:
             renderer = "sw"
 
+        if (renderer == "angle") and (not renpy.windows):
+            renderer = "auto"
+
         renpy.config.renderer = renderer
 
         if renderer == "auto":
@@ -2220,6 +2223,10 @@ class Interface(object):
         scene_lists.replace_transient()
         scene_lists.shown_window = False
 
+        if renpy.store._side_image_attributes_reset:
+            renpy.store._side_image_attributes = None
+            renpy.store._side_image_attributes_reset = False
+
     def set_transition(self, transition, layer=None, force=False):
         """
         Sets the transition that will be performed as part of the next
@@ -2383,9 +2390,13 @@ class Interface(object):
             anim = renpy.config.mouse[getattr(renpy.store, 'default_mouse', 'default')]
 
         img, x, y = anim[self.ticks % len(anim)]
-        tex = renpy.display.im.load_image(img)
+        rend = renpy.display.im.load_image(img)
+
+        tex = rend.children[0][0]
+        xo = rend.children[0][1]
+        yo = rend.children[0][2]
 
-        return False, x, y, tex
+        return False, x - xo, y - yo, tex
 
     def set_mouse_pos(self, x, y, duration):
         """
@@ -2647,6 +2658,10 @@ class Interface(object):
             if renpy.game.log is not None:
                 renpy.game.log.did_interaction = True
 
+            if renpy.store._side_image_attributes_reset:
+                renpy.store._side_image_attributes = None
+                renpy.store._side_image_attributes_reset = False
+
     def consider_gc(self):
         """
         Considers if we should peform a garbage collection.
@@ -2717,7 +2732,12 @@ class Interface(object):
                     step += 1
                     continue
 
-                result = self.prediction_coroutine.send(expensive)
+                try:
+                    result = self.prediction_coroutine.send(expensive)
+                except ValueError:
+                    # Saw this happen once during a quit, giving a
+                    # ValueError: generator already executing
+                    result = None
 
                 if result is None:
                     self.prediction_coroutine = None
diff --git a/renpy/display/im.py b/renpy/display/im.py
index 7dd7562..ee771e9 100644
--- a/renpy/display/im.py
+++ b/renpy/display/im.py
@@ -704,7 +704,7 @@ class ZipFileImage(ImageBase):
 
 class Composite(ImageBase):
     """
-    :doc: im_im
+    :undocumented:
 
     This image manipulator composites multiple images together to
     form a single image.
@@ -774,7 +774,7 @@ class Composite(ImageBase):
 
 class Scale(ImageBase):
     """
-    :doc: im_im
+    :undocumented:
 
     An image manipulator that scales `im` (an image manipulator) to
     `width` and `height`.
@@ -1715,10 +1715,10 @@ def load_image(im):
     """
     :doc: udd_utility
 
-    Loads the image manipulator `im` using the image cache, and returns a texture.
+    Loads the image manipulator `im` using the image cache, and returns a render.
     """
 
-    return cache.get(image(im), texture=True)
+    return cache.get(image(im), render=True)
 
 
 def load_surface(im):
diff --git a/renpy/display/image.py b/renpy/display/image.py
index e4c0c7f..8289e00 100644
--- a/renpy/display/image.py
+++ b/renpy/display/image.py
@@ -853,7 +853,21 @@ class ShownImageInfo(renpy.object.Object):
             return None
 
         if len(matches) == 1:
-            return matches[0]
+
+            rv = matches[0]
+
+            d = images.get(rv, None)
+            ca = getattr(d, "_choose_attributes", None)
+
+            if ca is not None:
+
+                required = set()
+                optional = set(i for i in optional if i not in rv)
+                tag = " ".join(rv)
+
+                rv =  rv + ca(tag, required, optional)
+
+            return rv
 
         if exception_name:
             raise Exception("Showing '" + " ".join(exception_name) + "' is ambiguous, possible images include: " + ", ".join(" ".join(i) for i in matches))
diff --git a/renpy/display/layout.py b/renpy/display/layout.py
index 4f113eb..6e0187c 100644
--- a/renpy/display/layout.py
+++ b/renpy/display/layout.py
@@ -259,8 +259,9 @@ class Container(renpy.display.core.Displayable):
         return False
 
 
-def LiveComposite(size, *args, **properties):
+def Composite(size, *args, **properties):
     """
+    :name: Composite
     :doc: disp_imagelike
 
     This creates a new displayable of `size`, by compositing other
@@ -276,7 +277,7 @@ def LiveComposite(size, *args, **properties):
 
     ::
 
-       image eileen composite = LiveComposite(
+       image eileen composite = Composite(
            (300, 600),
            (0, 0), "body.png",
            (0, 0), "clothes.png",
@@ -299,8 +300,13 @@ def LiveComposite(size, *args, **properties):
     return rv
 
 
+LiveComposite = Composite
+
+
 class Position(Container):
     """
+    :undocumented:
+
     Controls the placement of a displayable on the screen, using
     supplied position properties. This is the non-curried form of
     Position, which should be used when the user has directly created
@@ -1263,8 +1269,8 @@ class DynamicDisplayable(renpy.display.core.Displayable):
 
                 for i in child:
                     renpy.display.predict.displayable(i)
-                else:
-                    renpy.display.predict.displayable(child)
+            else:
+                renpy.display.predict.displayable(child)
 
         except:
             pass
@@ -1450,19 +1456,23 @@ class IgnoresEvents(Container):
         return None
 
 
-def LiveCrop(rect, child, **properties):
+def Crop(rect, child, **properties):
     """
     :doc: disp_imagelike
+    :name: Crop
 
     This created a displayable by cropping `child` to `rect`, where
     `rect` is an (x, y, width, height) tuple. ::
 
-        image eileen cropped = LiveCrop((0, 0, 300, 300), "eileen happy")
+        image eileen cropped = Crop((0, 0, 300, 300), "eileen happy")
     """
 
     return renpy.display.motion.Transform(child, crop=rect, **properties)
 
 
+LiveCrop = Crop
+
+
 class Side(Container):
 
     possible_positions = set([ 'tl', 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'c'])
@@ -1739,15 +1749,16 @@ class AdjustTimes(Container):
         return self.child.get_placement()
 
 
-class LiveTile(Container):
+class Tile(Container):
     """
     :doc: disp_imagelike
+    :name: Tile
 
     Tiles `child` until it fills the area allocated to this displayable.
 
     ::
 
-        image bg tile = LiveTile("bg.png")
+        image bg tile = Tile("bg.png")
 
     """
 
@@ -1783,6 +1794,9 @@ class LiveTile(Container):
         return rv
 
 
+LiveTile = Tile
+
+
 class Flatten(Container):
     """
     :doc: disp_imagelike
@@ -1833,11 +1847,7 @@ class AlphaMask(Container):
     opaque where `child` and `mask` are both opaque.
 
     The `child` and `mask` parameters may be arbitrary displayables. The
-    size of the AlphaMask is the size of the overlap between `child` and
-    `mask`.
-
-    Note that this takes different arguments from :func:`im.AlphaMask`,
-    which uses the mask's color channel.
+    size of the AlphaMask is the size of `child`.
     """
 
     def __init__(self, child, mask, **properties):
@@ -1846,24 +1856,19 @@ class AlphaMask(Container):
         self.add(child)
         self.mask = renpy.easy.displayable(mask)
         self.null = None
-        self.size = None
 
     def render(self, width, height, st, at):
 
         cr = renpy.display.render.render(self.child, width, height, st, at)
-        mr = renpy.display.render.render(self.mask, width, height, st, at)
-
-        cw, ch = cr.get_size()
-        mw, mh = mr.get_size()
+        w, h = cr.get_size()
 
-        w = min(cw, mw)
-        h = min(ch, mh)
-        size = (w, h)
+        mr = renpy.display.render.Render(w, h)
+        mr.place(self.mask, main=False)
 
-        if self.size != size:
-            self.null = Null(w, h)
+        if self.null is None:
+            self.null = Fixed()
 
-        nr = renpy.display.render.render(self.null, width, height, st, at)
+        nr = renpy.display.render.render(self.null, w, h, st, at)
 
         rv = renpy.display.render.Render(w, h, opaque=False)
 
diff --git a/renpy/display/screen.py b/renpy/display/screen.py
index db3c3bd..6199772 100644
--- a/renpy/display/screen.py
+++ b/renpy/display/screen.py
@@ -285,7 +285,20 @@ class ScreenDisplayable(renpy.display.layout.Container):
     class is responsible for managing the display of a screen.
     """
 
-    nosave = [ 'screen', 'child', 'children', 'transforms', 'widgets', 'old_widgets', 'hidden_widgets', 'old_transforms', 'cache', 'profile', 'phase', 'use_cache' ]
+    nosave = [
+        'screen',
+        'child',
+        'children',
+        'transforms',
+        'widgets',
+        'old_widgets',
+        'hidden_widgets',
+        'old_transforms',
+        'cache',
+        'miss_cache',
+        'profile',
+        'phase',
+        'use_cache' ]
 
     restarting = False
     hiding = False
@@ -302,6 +315,7 @@ class ScreenDisplayable(renpy.display.layout.Container):
         self.cache = { }
         self.phase = UPDATE
         self.use_cache = { }
+        self.miss_cache = { }
 
         self.profile = profile.get(self.screen_name, None)
 
@@ -362,6 +376,11 @@ class ScreenDisplayable(renpy.display.layout.Container):
         else:
             self.use_cache = { }
 
+        # A version of the cache that's used when we have a screen that is
+        # being displayed with the same tag with a cached copy of the screen
+        # we want to display.
+        self.miss_cache = { }
+
         # What widgets and transforms were the last time this screen was
         # updated. Used to communicate with the ui module, and only
         # valid during an update - not used at other times.
@@ -604,6 +623,9 @@ class ScreenDisplayable(renpy.display.layout.Container):
         self.old_transforms = None
         self.old_transfers = True
 
+        if self.miss_cache:
+            self.miss_cache.clear()
+
         # Deal with the case where the screen version changes.
         if (self.cache.get(NAME, None) is not old_cache) and (self.current_transform_event is None) and (self.phase == UPDATE):
             self.current_transform_event = "update"
@@ -1057,6 +1079,7 @@ def show_screen(_screen_name, *_args, **kwargs):
 
     if old_d and old_d.cache:
         d.cache = old_d.cache
+        d.miss_cache = cache_get(screen, _args, kwargs)
         d.phase = UPDATE
     else:
         d.cache = cache_get(screen, _args, kwargs)
diff --git a/renpy/display/swdraw.py b/renpy/display/swdraw.py
index 4cf79df..ce84331 100644
--- a/renpy/display/swdraw.py
+++ b/renpy/display/swdraw.py
@@ -1046,6 +1046,9 @@ class SWDraw(object):
                 cx = int(cx)
                 cy = int(cy)
 
+                if cx < 0 or cy < 0:
+                    return False
+
                 cw, ch = child.get_size()
                 if cx >= cw or cy >= ch:
                     return False
diff --git a/renpy/display/video.py b/renpy/display/video.py
index e562b98..47fb2a1 100644
--- a/renpy/display/video.py
+++ b/renpy/display/video.py
@@ -186,6 +186,14 @@ def render_movie(channel, width, height):
     return rv
 
 
+def default_play_callback(old, new):  # @UnusedVariable
+
+    renpy.audio.music.play(new._play, channel=new.channel, loop=True, synchro_start=True)
+
+    if new.mask:
+        renpy.audio.music.play(new.mask, channel=new.mask_channel, loop=True, synchro_start=True)
+
+
 class Movie(renpy.display.core.Displayable):
     """
     :doc: movie
@@ -232,6 +240,33 @@ class Movie(renpy.display.core.Displayable):
         sprites.) Users can also choose to fall back to this image as a
         preference if video is too taxing for their system.
 
+    ``play_callback``
+        If not None, a function that's used to start the movies playing.
+        (This may do things like queue a transition between sprites, if
+        desired.) It's called with the following arguments:
+
+        `old`
+            The old Movie object, or None if the movie is not playing.
+        `new`
+            The new Movie object.
+
+        A movie object has the `play` parameter available as ``_play``,
+        while the ``channel``, ``mask``, and ``mask_channel`` fields
+        correspond to the given parameters.
+
+        Generally, this will want to use :func:`renpy.music.play` to start
+        the movie playing on the given channel, with synchro_start=True.
+        A minimal implementation is::
+
+            def play_callback(old, new):
+
+                renpy.music.play(new._play, channel=new.channel, loop=True, synchro_start=True)
+
+                if new.mask:
+                    renpy.music.play(new.mask, channel=new.mask_channel, loop=True, synchro_start=True)
+
+
+
     This displayable will be transparent when the movie is not playing.
     """
 
@@ -244,6 +279,8 @@ class Movie(renpy.display.core.Displayable):
 
     image = None
 
+    play_callback = None
+
     def ensure_channel(self, name):
 
         if name is None:
@@ -254,7 +291,7 @@ class Movie(renpy.display.core.Displayable):
 
         renpy.audio.music.register_channel(name, renpy.config.movie_mixer, loop=True, stop_on_mute=False, movie=True)
 
-    def __init__(self, fps=24, size=None, channel="movie", play=None, mask=None, mask_channel=None, image=None, **properties):
+    def __init__(self, fps=24, size=None, channel="movie", play=None, mask=None, mask_channel=None, image=None, play_callback=None, **properties):
         super(Movie, self).__init__(**properties)
 
         global auto_channel_serial
@@ -280,6 +317,8 @@ class Movie(renpy.display.core.Displayable):
 
         self.image = renpy.easy.displayable_or_none(image)
 
+        self.play_callback = play_callback
+
         if (self.channel == "movie") and (renpy.config.hw_video) and renpy.mobile:
             raise Exception("Movie(channel='movie') doesn't work on mobile when config.hw_video is true. (Use a different channel argument.)")
 
@@ -342,10 +381,11 @@ class Movie(renpy.display.core.Displayable):
 
         if self._play != old_play:
             if self._play:
-                renpy.audio.music.play(self._play, channel=self.channel, loop=True, synchro_start=True)
 
-                if self.mask:
-                    renpy.audio.music.play(self.mask, channel=self.mask_channel, loop=True, synchro_start=True)
+                if self.play_callback is not None:
+                    self.play_callback(old, self)
+                else:
+                    default_play_callback(old, self)
 
             else:
                 renpy.audio.music.stop(channel=self.channel)
diff --git a/renpy/dump.py b/renpy/dump.py
index b4e8e4a..4b52886 100644
--- a/renpy/dump.py
+++ b/renpy/dump.py
@@ -242,7 +242,14 @@ def dump(error):
         pass
 
     if args.json_dump != "-":
-        with file(args.json_dump, "w") as f:
+        new = args.json_dump + ".new"
+
+        with file(new, "w") as f:
             json.dump(result, f)
+
+        if os.path.exists(args.json_dump):
+            os.unlink(args.json_dump)
+
+        os.rename(new, args.json_dump)
     else:
         json.dump(result, sys.stdout, indent=2)
diff --git a/renpy/editor.py b/renpy/editor.py
index aeaefe9..6d55e95 100644
--- a/renpy/editor.py
+++ b/renpy/editor.py
@@ -66,7 +66,7 @@ class Editor(object):
 
     def open(self, filename, line=None, **kwargs):  # @ReservedAssignment
         """
-        Ensures `path` is open in the editor. This may be called multiple
+        Ensures `filename` is open in the editor. This may be called multiple
         times per transaction.
 
         `line`
@@ -77,6 +77,14 @@ class Editor(object):
         should be given focus in a tabbed editor environment.
         """
 
+    # This should be set to True if the editor supports projects.
+    has_projects = False
+
+    def open_project(self, directory):
+        """
+        Opens `directory` as a project in the editor.
+        """
+
 
 class SystemEditor(Editor):
 
diff --git a/renpy/execution.py b/renpy/execution.py
index 71da5d1..5d66970 100644
--- a/renpy/execution.py
+++ b/renpy/execution.py
@@ -130,7 +130,7 @@ class Context(renpy.object.Object):
     does participates in rollback.
     """
 
-    __version__ = 15
+    __version__ = 16
 
     nosave = [ 'next_node' ]
 
@@ -188,6 +188,9 @@ class Context(renpy.object.Object):
         if version < 15:
             self.abnormal_stack = [ False ] * len(self.return_stack)
 
+        if version < 16:
+            self.alternate_translate_identifier = None
+
     def __init__(self, rollback, context=None, clear=False):
         """
         `clear`
@@ -293,6 +296,9 @@ class Context(renpy.object.Object):
         # The identifier of the current translate block.
         self.translate_identifier = None
 
+        # The alternate identifier of the current translate block.
+        self.alternate_translate_identifier = None
+
         # The language of the current translate block.
         self.translate_block_language = None
 
@@ -437,6 +443,9 @@ class Context(renpy.object.Object):
         developer = renpy.config.developer
         tracing = sys.gettrace() is not None
 
+        # Is this the first time through the loop?
+        first = True
+
         while node:
 
             this_node = node
@@ -455,7 +464,7 @@ class Context(renpy.object.Object):
                 if ll_entry not in self.line_log:
                     self.line_log.append(ll_entry)
 
-            if self.force_checkpoint or (node.rollback == "force"):
+            if first or self.force_checkpoint or (node.rollback == "force"):
                 update_rollback = True
                 force_rollback = True
             elif not renpy.config.all_nodes_rollback and (node.rollback == "never"):
@@ -465,12 +474,14 @@ class Context(renpy.object.Object):
                 update_rollback = True
                 force_rollback = False
 
+            first = False
+
             if update_rollback:
 
                 if self.rollback and renpy.game.log:
                     renpy.game.log.begin(force=force_rollback)
 
-                if self.force_checkpoint:
+                if self.rollback and self.force_checkpoint:
                     renpy.game.log.checkpoint(hard=False)
                     self.force_checkpoint = False
 
diff --git a/renpy/exports.py b/renpy/exports.py
index 367d9f4..7119f29 100644
--- a/renpy/exports.py
+++ b/renpy/exports.py
@@ -232,6 +232,9 @@ def can_rollback():
     Returns true if we can rollback.
     """
 
+    if not renpy.config.rollback_enabled:
+        return False
+
     return renpy.game.log.can_rollback()
 
 
@@ -491,7 +494,7 @@ def get_attributes(tag, layer=None):
     :doc: image_func
 
     Return a tuple giving the image attributes for the image with `tag`. If
-    the image is now showing, returns None.
+    the image is not showing, returns None.
 
     `layer`
         The layer to check. If None, uses the default layer for `tag`.
@@ -947,6 +950,7 @@ def display_menu(items,
                  **kwargs):
     """
     :doc: se_menu
+    :name: renpy.display_menu
     :args: (items, interact=True, screen="choice")
 
     This displays a menu to the user. `items` should be a list of 2-item tuples.
@@ -2647,6 +2651,11 @@ def call_screen(_screen_name, *args, **kwargs):
 
     renpy.exports.mode('screen')
 
+    with_none = renpy.config.implicit_with_none
+
+    if "_with_none" in kwargs:
+        with_none = kwargs.pop("_with_none")
+
     show_screen(_screen_name, _transient=True, *args, **kwargs)
 
     roll_forward = renpy.exports.roll_forward_info()
@@ -2658,11 +2667,6 @@ def call_screen(_screen_name, *args, **kwargs):
 
     renpy.exports.checkpoint(rv)
 
-    with_none = renpy.config.implicit_with_none
-
-    if "_with_none" in kwargs:
-        with_none = kwargs.pop("_with_none")
-
     if with_none:
         renpy.game.interface.do_with(None, None)
 
@@ -3509,3 +3513,19 @@ def get_on_battery():
     else:
         old_battery = False
         return False
+
+
+def get_say_image_tag():
+    """
+    :doc: image_func
+
+    Returns the tag corresponding to the currently speaking character (the
+    `image` argument given to that character). Returns None if no character
+    is speaking or the current speaking character does not have a corresponding
+    image tag.
+    """
+
+    if renpy.store._side_image_attributes is None:
+        return None
+
+    return renpy.store._side_image_attributes[0]
diff --git a/renpy/main.py b/renpy/main.py
index 7fd0798..9dca2b9 100644
--- a/renpy/main.py
+++ b/renpy/main.py
@@ -122,16 +122,6 @@ def run(restart):
 
     game.context().goto_label(start_label)
 
-    # Perhaps warp.
-    warp_label = renpy.warp.warp()
-
-    if warp_label is not None:
-
-        game.context().goto_label(warp_label)
-        game.context().call('_after_warp')
-
-        renpy.config.skipping = None
-
     try:
         renpy.exports.log("--- " + time.ctime())
         renpy.exports.log("")
@@ -391,6 +381,10 @@ def main():
     game.persistent = renpy.persistent.init()
     game.preferences = game.persistent._preferences
 
+    for i in renpy.game.persistent._seen_translates:  # @UndefinedVariable
+        if i in renpy.game.script.translator.default_translates:
+            renpy.game.seen_translates_count += 1
+
     if game.persistent._virtual_size:
         renpy.config.screen_width, renpy.config.screen_height = game.persistent._virtual_size
 
@@ -450,10 +444,6 @@ def main():
 
         game.persistent._virtual_size = renpy.config.screen_width, renpy.config.screen_height
 
-        for i in renpy.game.persistent._seen_translates:  # @UndefinedVariable
-            if i in renpy.game.script.translator.default_translates:
-                renpy.game.seen_translates_count += 1
-
         log_clock("Running init code")
 
         renpy.pyanalysis.load_cache()
diff --git a/renpy/persistent.py b/renpy/persistent.py
index d09ae46..7c64511 100644
--- a/renpy/persistent.py
+++ b/renpy/persistent.py
@@ -490,7 +490,7 @@ def MultiPersistent(name):
             break
 
     try:
-        rv = loads(file(fn).read())
+        rv = loads(file(fn, "rb").read())
     except:
         rv = _MultiPersistent()
 
diff --git a/renpy/python.py b/renpy/python.py
index 2ff1cd6..5a00651 100644
--- a/renpy/python.py
+++ b/renpy/python.py
@@ -86,6 +86,7 @@ def get_store_module(name):
 from renpy.pydict import DictItems, find_changes
 
 EMPTY_DICT = { }
+EMPTY_SET = set()
 
 
 class StoreDict(dict):
@@ -123,26 +124,48 @@ class StoreDict(dict):
 
         self.old = DictItems(self)
 
-    def get_changes(self):
+    def get_changes(self, cycle):
         """
         For every key that has changed since begin() was called, returns a
         dictionary mapping the key to its value when begin was called, or
         deleted if it did not exist when begin was called.
 
-        As a side-effect, updates self.ever_been_changed.
+        As a side-effect, updates self.ever_been_changed, and returns the
+        changes to ever_been_changed as well.
+
+        `cycle`
+            If true, this cycles the old changes to the new changes. If
+            False, does not.
         """
 
         new = DictItems(self)
         rv = find_changes(self.old, new, deleted)
-        self.old = new
+
+        if cycle:
+            self.old = new
 
         if rv is None:
-            return EMPTY_DICT
+            return EMPTY_DICT, EMPTY_SET
 
-        for k in rv:
-            self.ever_been_changed.add(k)
+        delta_ebc = set()
 
-        return rv
+        if cycle:
+
+            for k in rv:
+                if k not in self.ever_been_changed:
+                    self.ever_been_changed.add(k)
+                    delta_ebc.add(k)
+
+        return rv, delta_ebc
+
+
+def begin_stores():
+    """
+    Calls .begin on every store dict.
+    """
+
+    for sd in store_dicts.itervalues():
+        sd.begin()
 
 
 # A map from the name of a store dict to the corresponding StoreDict object.
@@ -472,18 +495,23 @@ class WrapNode(ast.NodeTransformer):
 wrap_node = WrapNode()
 
 
-def set_filename(filename, offset, tree):
-    """Set the filename attribute to filename on every node in tree"""
-    worklist = [tree]
-    while worklist:
-        node = worklist.pop(0)
-        node.filename = filename
+def wrap_hide(tree):
+    """
+    Wraps code inside a python hide or python early hide block inside a
+    function, so it gets its own scope that works the way Python expects
+    it to.
+    """
 
-        lineno = getattr(node, 'lineno', None)
-        if lineno is not None:
-            node.lineno = lineno + offset
+    hide = ast.parse("""\
+def _execute_python_hide(): pass;
+_execute_python_hide()
+""")
 
-        worklist.extend(node.getChildNodes())
+    for i in ast.walk(hide):
+        ast.copy_location(i, hide.body[0])
+
+    hide.body[0].body = tree.body
+    tree.body = hide.body
 
 
 unicode_re = re.compile(ur'[\u0080-\uffff]')
@@ -604,15 +632,23 @@ def py_compile(source, mode, filename='<none>', lineno=1, ast_node=False, cache=
     try:
         line_offset = lineno - 1
 
+        if mode == "hide":
+            py_mode = "exec"
+        else:
+            py_mode = mode
+
         try:
             flags = new_compile_flags
-            tree = compile(source, filename, mode, ast.PyCF_ONLY_AST | flags, 1)
+            tree = compile(source, filename, py_mode, ast.PyCF_ONLY_AST | flags, 1)
         except:
             flags = old_compile_flags
-            tree = compile(source, filename, mode, ast.PyCF_ONLY_AST | flags, 1)
+            tree = compile(source, filename, py_mode, ast.PyCF_ONLY_AST | flags, 1)
 
         tree = wrap_node.visit(tree)
 
+        if mode == "hide":
+            wrap_hide(tree)
+
         ast.fix_missing_locations(tree)
         ast.increment_lineno(tree, lineno - 1)
 
@@ -621,7 +657,7 @@ def py_compile(source, mode, filename='<none>', lineno=1, ast_node=False, cache=
         if ast_node:
             return tree.body
 
-        rv = compile(tree, filename, mode, flags, 1)
+        rv = compile(tree, filename, py_mode, flags, 1)
 
         if cache:
             py_compile_cache[key] = rv
@@ -643,6 +679,11 @@ def py_compile_exec_bytecode(source, **kwargs):
     return marshal.dumps(code)
 
 
+def py_compile_hide_bytecode(source, **kwargs):
+    code = py_compile(source, 'hide', cache=False, **kwargs)
+    return marshal.dumps(code)
+
+
 def py_compile_eval_bytecode(source, **kwargs):
     source = source.strip()
     code = py_compile(source, 'eval', cache=False, **kwargs)
@@ -1077,7 +1118,7 @@ class Rollback(renpy.object.Object):
     execution of this element.
     """
 
-    __version__ = 4
+    __version__ = 5
 
     identifier = None
 
@@ -1095,6 +1136,10 @@ class Rollback(renpy.object.Object):
         # A map of maps name -> (variable -> value)
         self.stores = { }
 
+        # A map from store name to the changes to ever_been_changed that
+        # need to be reverted.
+        self.delta_ebc = { }
+
         # If true, we retain the data in this rollback when a load occurs.
         self.retain_after_load = False
 
@@ -1130,6 +1175,9 @@ class Rollback(renpy.object.Object):
         if version < 4:
             self.hard_checkpoint = self.checkpoint
 
+        if version < 5:
+            self.delta_ebc = { }
+
     def purge_unreachable(self, reachable, wait):
         """
         Adds objects that are reachable from the store of this
@@ -1190,7 +1238,7 @@ class Rollback(renpy.object.Object):
         for name, changes in self.stores.iteritems():
             store = store_dicts.get(name, None)
             if store is None:
-                return
+                continue
 
             for name, value in changes.iteritems():
                 if value is deleted:
@@ -1199,6 +1247,14 @@ class Rollback(renpy.object.Object):
                 else:
                     store[name] = value
 
+        for name, changes in self.delta_ebc.iteritems():
+
+            store = store_dicts.get(name, None)
+            if store is None:
+                continue
+
+            store.ever_been_changed -= changes
+
         rng.pushback(self.random)
 
         renpy.game.contexts.pop()
@@ -1306,16 +1362,27 @@ class RollbackLog(renpy.object.Object):
 
         # We only begin a checkpoint if the previous statement reached a checkpoint,
         # or an interaction took place. (Or we're forced.)
-        if (not force) and (self.current and not self.current.checkpoint) and (not self.did_interaction):
+        ignore = True
+
+        if force:
+            ignore = False
+        elif self.did_interaction:
+            ignore = False
+        elif self.current is not None:
+            if self.current.checkpoint:
+                ignore = False
+            elif self.current.retain_after_load:
+                ignore = False
+
+        if ignore:
             return
 
         self.did_interaction = False
 
         if self.current is not None:
-            self.complete()
+            self.complete(True)
         else:
-            for sd in store_dicts.itervalues():
-                sd.begin()
+            begin_stores()
 
         # If the log is too long, prune it.
         if len(self.log) > renpy.config.rollback_length:
@@ -1346,19 +1413,22 @@ class RollbackLog(renpy.object.Object):
 
         self.rolled_forward = False
 
-    def complete(self):
+    def complete(self, begin=False):
         """
         Called after a node is finished executing, before a save
         begins, or right before a rollback is attempted. This may be
         called more than once between calls to begin, and should always
         be called after an update to the store but before a rollback
         occurs.
+
+        `begin`
+            Should be true if called from begin().
         """
 
         # Update self.current.stores with the changes from each store.
         # Also updates .ever_been_changed.
         for name, sd in store_dicts.iteritems():
-            self.current.stores[name] = sd.get_changes()
+            self.current.stores[name], self.current.delta_ebc[name] = sd.get_changes(begin)
 
         # Update the list of mutated objects and what we need to do to
         # restore them.
@@ -1498,7 +1568,7 @@ class RollbackLog(renpy.object.Object):
                 if (self.current.context.current == fwd_name
                         and data == fwd_data
                         and (keep_rollback or self.rolled_forward)
-                    ):
+                        ):
                     self.forward.pop(0)
                 else:
                     self.forward = [ ]
@@ -1528,8 +1598,12 @@ class RollbackLog(renpy.object.Object):
         when the game is loaded.
         """
 
+        if renpy.display.predict.predicting:
+            return
+
         self.retain_after_load_flag = True
         self.current.retain_after_load = True
+        renpy.game.context().force_checkpoint = True
 
     def fix_rollback(self):
         if not self.rollback_is_fixed and len(self.log) > 1:
@@ -1682,6 +1756,8 @@ class RollbackLog(renpy.object.Object):
 
         renpy.game.contexts.extend(other_contexts)
 
+        begin_stores()
+
         # Restart the context or the top context.
         if replace_context:
 
@@ -1706,7 +1782,7 @@ class RollbackLog(renpy.object.Object):
         """
 
         # Purge unreachable objects, so we don't save them.
-        self.complete()
+        self.complete(False)
         roots = self.get_roots()
         self.purge_unreachable(roots, wait=wait)
 
diff --git a/renpy/screenlang.py b/renpy/screenlang.py
index ef0712b..07bb5dd 100644
--- a/renpy/screenlang.py
+++ b/renpy/screenlang.py
@@ -80,9 +80,6 @@ class Positional(object):
         if parser:
             parser.add(self)
 
-# Used to generate the documentation
-all_keyword_names = set()
-
 
 class Keyword(object):
     """
@@ -92,11 +89,10 @@ class Keyword(object):
     def __init__(self, name):
         self.name = name
 
-        all_keyword_names.add(self.name)
-
         if parser:
             parser.add(self)
 
+
 STYLE_PREFIXES = [
     '',
     'insensitive_',
@@ -119,9 +115,6 @@ class Style(object):
     def __init__(self, name):
         self.name = name
 
-        for j in STYLE_PREFIXES:
-            all_keyword_names.add(j + self.name)
-
         if parser:
             parser.add(self)
 
@@ -135,9 +128,6 @@ class PrefixStyle(object):
         self.prefix = prefix
         self.name = name
 
-        for j in STYLE_PREFIXES:
-            all_keyword_names.add(prefix + j + self.name)
-
         if parser:
             parser.add(self)
 
@@ -922,6 +912,7 @@ class PassParser(Parser):
     def parse(self, l, name):
         return self.parse_exec("pass", l.number)
 
+
 PassParser("pass")
 
 
@@ -940,6 +931,7 @@ class DefaultParser(Parser):
 
         return self.parse_exec(code, l.number)
 
+
 DefaultParser("default")
 
 
@@ -981,6 +973,7 @@ class UseParser(Parser):
 
         return self.parse_exec(code, lineno)
 
+
 UseParser("use")
 
 
@@ -1044,6 +1037,7 @@ class IfParser(Parser):
 
         return [ rv ]
 
+
 IfParser("if")
 
 
@@ -1118,6 +1112,7 @@ class ForParser(Parser):
 
         return rv
 
+
 ForParser("for")
 
 
@@ -1143,6 +1138,7 @@ class PythonParser(Parser):
 
         return self.parse_exec(python_code, lineno)
 
+
 PythonParser("$", True)
 PythonParser("python", False)
 
@@ -1358,6 +1354,7 @@ class ScreenParser(Parser):
 
         return screen
 
+
 screen_parser = ScreenParser()
 screen_parser.add(all_statements)
 
diff --git a/renpy/script.py b/renpy/script.py
index 0e1315a..42522c9 100644
--- a/renpy/script.py
+++ b/renpy/script.py
@@ -805,6 +805,8 @@ class Script(object):
 
                     if i.mode == 'exec':
                         code = renpy.python.py_compile_exec_bytecode(i.source, filename=i.location[0], lineno=i.location[1])
+                    elif i.mode == 'hide':
+                        code = renpy.python.py_compile_hide_bytecode(i.source, filename=i.location[0], lineno=i.location[1])
                     elif i.mode == 'eval':
                         code = renpy.python.py_compile_eval_bytecode(i.source, filename=i.location[0], lineno=i.location[1])
 
diff --git a/renpy/sl2/slast.py b/renpy/sl2/slast.py
index 7ae253a..8acda21 100644
--- a/renpy/sl2/slast.py
+++ b/renpy/sl2/slast.py
@@ -105,7 +105,15 @@ class SLContext(renpy.ui.Addable):
 
         # A cache associated with this context. The cache maps from
         # statement serial to information associated with the statement.
-        self.cache = { }
+        self.new_cache = { }
+
+        # The old cache, used to take information from the old version of
+        # this displayable.
+        self.old_cache = { }
+
+        # The miss cache, used to take information that isn't present in
+        # old_cache.
+        self.miss_cache = { }
 
         # The number of times a particular use statement has been called
         # in the current screen. We use this to generate a unique name for
@@ -152,6 +160,10 @@ class SLContext(renpy.ui.Addable):
         # to speed things up.
         self.unlikely = False
 
+        # The old and new generations of the use_cache.
+        self.new_use_cache = { }
+        self.old_use_cache = { }
+
     def add(self, d, key):
         self.children.append(d)
 
@@ -652,10 +664,12 @@ class SLDisplayable(SLBlock):
 
         screen = renpy.ui.screen
 
-        cache = context.cache.get(self.serial, None)
+        cache = context.old_cache.get(self.serial, None) or context.miss_cache.get(self.serial, None)
 
         if not isinstance(cache, SLCache):
-            context.cache[self.serial] = cache = SLCache()
+            cache = SLCache()
+
+        context.new_cache[self.serial] = cache
 
         copy_on_change = cache.copy_on_change
 
@@ -811,7 +825,7 @@ class SLDisplayable(SLBlock):
                 if self.scope:
                     keywords["scope"] = ctx.scope
 
-                if self.replaces and context.updating:
+                if self.replaces and ctx.updating:
                     keywords['replaces'] = old_main
 
                 # Pass the context
@@ -1394,11 +1408,17 @@ class SLFor(SLBlock):
 
             value = [ 0 ]
 
-        newcaches = {}
-        oldcaches = context.cache.get(self.serial, newcaches)
+        newcaches = { }
+
+        oldcaches = context.old_cache.get(self.serial, newcaches) or { }
 
         if not isinstance(oldcaches, dict):
-            oldcaches = newcaches
+            oldcaches = { }
+
+        misscaches = context.miss_cache.get(self.serial, newcaches) or { }
+
+        if not isinstance(misscaches, dict):
+            misscaches = { }
 
         ctx = SLContext(context)
 
@@ -1406,13 +1426,17 @@ class SLFor(SLBlock):
 
             ctx.scope[variable] = v
 
-            cache = oldcaches.get(index, None)
+            ctx.old_cache = oldcaches.get(index, None) or { }
 
-            if not isinstance(cache, dict):
-                cache = {}
+            if not isinstance(ctx.old_cache, dict):
+                ctx.old_cache = {}
 
-            newcaches[index] = cache
-            ctx.cache = cache
+            ctx.miss_cache = misscaches.get(index, None) or { }
+
+            if not isinstance(ctx.miss_cache, dict):
+                ctx.miss_cache = {}
+
+            newcaches[index] = ctx.new_cache = { }
 
             # Inline of SLBlock.execute.
 
@@ -1426,7 +1450,7 @@ class SLFor(SLBlock):
             if context.unlikely:
                 break
 
-        context.cache[self.serial] = newcaches
+        context.new_cache[self.serial] = newcaches
 
         if ctx.fail:
             context.fail = True
@@ -1636,40 +1660,29 @@ class SLUse(SLNode):
 
         # Figure out the cache to use.
 
-        # True if we want to force-mark this as an update.
-        update = False
-
-        if (not context.predicting) and self.id:
+        ctx = SLContext(context)
+        ctx.new_cache = context.new_cache[self.serial] = { }
+        ctx.miss_cache = context.miss_cache.get(self.serial, None) or { }
 
-            # If we have an id, look it up in the current screen's use_cache.
+        if self.id:
 
-            current_screen = renpy.display.screen.current_screen()
             use_id = (self.target, eval(self.id, context.globals, context.scope))
 
-            cache = current_screen.use_cache.get(use_id, None)
-
-            if cache is not None:
-                update = True
-
-            else:
-
-                if cache is None:
-                    cache = context.cache.get(self.serial, None)
+            ctx.old_cache = context.old_use_cache.get(use_id, None) or context.old_cache.get(self.serial, None) or { }
 
-                if not isinstance(cache, dict):
-                    cache = { }
+            if use_id in ctx.old_use_cache:
+                ctx.updating = True
 
-            context.cache[self.serial] = cache
-            current_screen.use_cache[use_id] = cache
+            ctx.new_use_cache[use_id] = ctx.new_cache
 
         else:
 
-            # Otherwise, look up the cache based on the statement's location.
+            ctx.old_cache = context.old_cache.get(self.serial, None) or { }
 
-            cache = context.cache.get(self.serial, None)
-
-            if not isinstance(cache, dict):
-                context.cache[self.serial] = cache = { }
+        if not isinstance(ctx.old_cache, dict):
+            ctx.old_cache = { }
+        if not isinstance(ctx.miss_cache, dict):
+            ctx.miss_cache = { }
 
         # Evaluate the arguments.
         try:
@@ -1689,12 +1702,8 @@ class SLUse(SLNode):
         if ast.parameters is not None:
             new_scope = ast.parameters.apply(args, kwargs, ignore_errors=context.predicting)
 
-            scope = cache.get("scope", None)
-
-            if scope is None:
-                scope = cache["scope"] = new_scope
-            else:
-                scope.update(new_scope)
+            scope = ctx.old_cache.get("scope", None) or ctx.miss_cache.get("scope", None) or { }
+            scope.update(new_scope)
 
         else:
 
@@ -1707,14 +1716,9 @@ class SLUse(SLNode):
         scope["_scope"] = scope
 
         # Run the child screen.
-        ctx = SLContext(context)
         ctx.scope = scope
-        ctx.cache = cache
         ctx.parent = weakref.ref(context)
 
-        if update:
-            ctx.updating = True
-
         ctx.transclude = self.block
 
         try:
@@ -1753,20 +1757,21 @@ class SLTransclude(SLNode):
         if not context.transclude:
             return
 
-        cache = context.cache.get(self.serial, None)
-
-        if not isinstance(cache, dict):
-            context.cache[self.serial] = cache = { }
-
-        cache["transclude"] = context.transclude
-
         parent = context.parent
         if parent is not None:
             parent = parent()
 
         ctx = SLContext(parent)
+        ctx.new_cache = context.new_cache[self.serial] = { }
+        ctx.old_cache = context.old_cache.get(self.serial, None) or { }
+        ctx.miss_cache = context.miss_cache.get(self.serial, None) or { }
 
-        ctx.cache = cache
+        if not isinstance(ctx.old_cache, dict):
+            ctx.old_cache = { }
+        if not isinstance(ctx.miss_cache, dict):
+            ctx.miss_cache = { }
+
+        ctx.new_cache["transclude"] = context.transclude
 
         ctx.children = context.children
         ctx.showif = context.showif
@@ -1994,6 +1999,7 @@ class SLScreen(SLBlock):
             debug = True
 
         context = SLContext()
+
         context.scope = scope
         context.globals = renpy.python.store_dicts["store"]
         context.debug = debug
@@ -2002,20 +2008,30 @@ class SLScreen(SLBlock):
 
         name = scope["_name"]
 
-        main_cache = current_screen.cache
+        def get_cache(d):
+            rv = d.get(name, None)
 
-        cache = main_cache.get(name, None)
-        if (not isinstance(cache, dict)) or (cache["version"] != self.version):
-            cache = { "version" : self.version }
-            main_cache[name] = cache
+            if (not isinstance(rv, dict)) or (rv.get("version", None) != self.version):
+                rv = { "version" : self.version }
+                d[name] = rv
 
-        context.cache = cache
+            return rv
+
+        context.old_cache = get_cache(current_screen.cache)
+        context.miss_cache = get_cache(current_screen.miss_cache)
+        context.new_cache = { "version" : self.version }
+
+        context.old_use_cache = current_screen.use_cache
+        context.new_use_cache = { }
 
         self.const_ast.execute(context)
 
         for i in context.children:
             renpy.ui.implicit_add(i)
 
+        current_screen.cache[name] = context.new_cache
+        current_screen.use_cache = context.new_use_cache
+
 
 class ScreenCache(object):
 
diff --git a/renpy/sl2/slparser.py b/renpy/sl2/slparser.py
index 3d06938..15a38c7 100644
--- a/renpy/sl2/slparser.py
+++ b/renpy/sl2/slparser.py
@@ -19,10 +19,11 @@
 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+import collections
 import renpy.sl2
 import renpy.sl2.slast as slast
 
-# A list of style prefixes that we know of.
+# A tuple of style prefixes that we know of.
 STYLE_PREFIXES = [
     '',
     'insensitive_',
@@ -61,8 +62,8 @@ class Positional(object):
             parser.add(self)
 
 
-# Used to generate the documentation
-all_keyword_names = set()
+# This is a map from (prefix, use_style_prefixes) to a set of property names.
+properties = collections.defaultdict(set)
 
 
 class Keyword(object):
@@ -73,7 +74,7 @@ class Keyword(object):
     def __init__(self, name):
         self.name = name
 
-        all_keyword_names.add(self.name)
+        properties['', False].add(name)
 
         if parser:
             parser.add(self)
@@ -87,8 +88,7 @@ class Style(object):
     def __init__(self, name):
         self.name = name
 
-        for j in STYLE_PREFIXES:
-            all_keyword_names.add(j + self.name)
+        properties['', True].add(self.name)
 
         if parser:
             parser.add(self)
@@ -103,8 +103,7 @@ class PrefixStyle(object):
         self.prefix = prefix
         self.name = name
 
-        for j in STYLE_PREFIXES:
-            all_keyword_names.add(prefix + j + self.name)
+        properties[prefix, True].add(self.name)
 
         if parser:
             parser.add(self)
diff --git a/renpy/statements.py b/renpy/statements.py
index 9f5ec21..e8d809d 100644
--- a/renpy/statements.py
+++ b/renpy/statements.py
@@ -30,7 +30,7 @@ registry = { }
 parsers = renpy.parser.ParseTrie()
 
 
-def register(name, parse=None, lint=None, execute=None, predict=None, next=None, scry=None, block=False, init=False, translatable=False, execute_init=None, label=None):  # @ReservedAssignment
+def register(name, parse=None, lint=None, execute=None, predict=None, next=None, scry=None, block=False, init=False, translatable=False, execute_init=None, label=None, warp=None):  # @ReservedAssignment
     """
     :doc: statement_register
     :name: renpy.register_statement
@@ -85,6 +85,12 @@ def register(name, parse=None, lint=None, execute=None, predict=None, next=None,
         statement. If it returns a string, that string is used as the statement
         label, which can be called and jumped to like any other label.
 
+    `warp`
+        This is a function that is called to determine if this statement
+        should execute during warping. If the function exists and returns
+        true, it's run during warp, otherwise the statement is not run
+        during warp.
+
     `scry`
         Used internally by Ren'Py.
 
@@ -93,6 +99,7 @@ def register(name, parse=None, lint=None, execute=None, predict=None, next=None,
         is not already inside an init block, it's automatically placed inside
         an init 0 block.) This calls the execute function, in addition to the
         execute_init function.
+
     """
     name = tuple(name.split())
 
@@ -103,7 +110,8 @@ def register(name, parse=None, lint=None, execute=None, predict=None, next=None,
                           predict=predict,
                           next=next,
                           scry=scry,
-                          label=label)
+                          label=label,
+                          warp=warp)
 
     # The function that is called to create an ast.UserStatement.
     def parse_user_statement(l, loc):
diff --git a/renpy/text/font.py b/renpy/text/font.py
index 7442b8a..ace6fbe 100644
--- a/renpy/text/font.py
+++ b/renpy/text/font.py
@@ -64,7 +64,7 @@ class ImageFont(object):
             g = textsupport.Glyph()  # @UndefinedVariable
 
             g.character = ord(c)
-            g.ascent = self.height
+            g.ascent = self.baseline
             g.line_spacing = self.height
 
             width = self.width.get(c, None)
@@ -117,7 +117,8 @@ class SFont(ImageFont):
                  spacewidth,
                  default_kern,
                  kerns,
-                 charset):
+                 charset,
+                 baseline=None):
 
         super(SFont, self).__init__()
 
@@ -126,6 +127,7 @@ class SFont(ImageFont):
         self.default_kern = default_kern
         self.kerns = kerns
         self.charset = charset
+        self.baseline = baseline
 
     def load(self):
 
@@ -140,7 +142,11 @@ class SFont(ImageFont):
         sw, sh = surf.get_size()
         height = sh
         self.height = height  # W0201
-        self.baseline = height  # W0201
+        if self.baseline is None:
+            self.baseline = height  # W0201
+        elif self.baseline < 0:
+            # Negative value is the distance from the bottom (vs top)
+            self.baseline = height + self.baseline  # W0201
 
         # Create space characters.
         self.chars[u' '] = renpy.display.pgrender.surface((self.spacewidth, height), True)
@@ -391,7 +397,7 @@ class ScaledImageFont(ImageFont):
 
 
 def register_sfont(name=None, size=None, bold=False, italics=False, underline=False,
-                   filename=None, spacewidth=10, default_kern=0, kerns={},
+                   filename=None, spacewidth=10, baseline=None, default_kern=0, kerns={},
                    charset=u"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"):
     """
     :doc: image_fonts
@@ -423,6 +429,13 @@ def register_sfont(name=None, size=None, bold=False, italics=False, underline=Fa
     `spacewidth`
         The width of a space character, an integer in pixels.
 
+    `baseline`
+        The distance from the top of the font to the baseline (the invisible
+        line letters sit on), an integer in pixels.  If this font is mixed with
+        other fonts, their baselines will be aligned.  Negative values indicate
+        distance from the bottom of the font instead, and ``None`` means the
+        baseline equals the height (i.e., is at the very bottom of the font).
+
     `default_kern`
         The default kern spacing between characters, in pixels.
 
@@ -442,7 +455,7 @@ def register_sfont(name=None, size=None, bold=False, italics=False, underline=Fa
     if name is None or size is None or filename is None:
         raise Exception("When registering an SFont, the font name, font size, and filename are required.")
 
-    sf = SFont(filename, spacewidth, default_kern, kerns, charset)
+    sf = SFont(filename, spacewidth, default_kern, kerns, charset, baseline)
     image_fonts[(name, size, bold, italics)] = sf
 
 
diff --git a/renpy/translation/__init__.py b/renpy/translation/__init__.py
index f0ee5d6..92d38ed 100644
--- a/renpy/translation/__init__.py
+++ b/renpy/translation/__init__.py
@@ -170,13 +170,17 @@ class ScriptTranslator(object):
 
         self.chain_worklist = unchained
 
-    def lookup_translate(self, identifier):
+    def lookup_translate(self, identifier, alternate=None):
 
         identifier = identifier.replace('.', '_')
         language = renpy.game.preferences.language
 
         if language is not None:
             tl = self.language_translates.get((identifier, language), None)
+
+            if (tl is None) and alternate:
+                tl = self.language_translates.get((identifier, language), alternate)
+
         else:
             tl = None
 
@@ -203,6 +207,8 @@ class Restructurer(object):
 
     def __init__(self, children):
         self.label = None
+        self.alternate = None
+
         self.identifiers = set()
         self.callback(children)
 
@@ -215,22 +221,12 @@ class Restructurer(object):
 
         return False
 
-    def create_translate(self, block):
-        """
-        Creates an ast.Translate that wraps `block`. The block may only contain
-        translatable statements.
-        """
-
-        md5 = hashlib.md5()
-
-        for i in block:
-            code = i.get_code()
-            md5.update(code.encode("utf-8") + "\r\n")
+    def unique_identifier(self, label, digest):
 
-        if self.label:
-            base = self.label.replace('.', '_') + "_" + md5.hexdigest()[:8]
+        if label is None:
+            base = digest
         else:
-            base = md5.hexdigest()[:8]
+            base = label.replace(".", "_") + "_" + digest
 
         i = 0
         suffix = ""
@@ -245,10 +241,34 @@ class Restructurer(object):
             i += 1
             suffix = "_{0}".format(i)
 
+        return identifier
+
+    def create_translate(self, block):
+        """
+        Creates an ast.Translate that wraps `block`. The block may only contain
+        translatable statements.
+        """
+
+        md5 = hashlib.md5()
+
+        for i in block:
+            code = i.get_code()
+            md5.update(code.encode("utf-8") + "\r\n")
+
+        digest = md5.hexdigest()[:8]
+
+        identifier = self.unique_identifier(self.label, digest)
         self.identifiers.add(identifier)
+
+        if self.alternate is not None:
+            alternate = self.unique_identifier(self.alternate, digest)
+            self.identifiers.add(alternate)
+        else:
+            alternate = None
+
         loc = (block[0].filename, block[0].linenumber)
 
-        tl = renpy.ast.Translate(loc, identifier, None, block)
+        tl = renpy.ast.Translate(loc, identifier, None, block, alternate=alternate)
         tl.name = block[0].name + ("translate",)
 
         ed = renpy.ast.EndTranslate(loc)
@@ -269,7 +289,12 @@ class Restructurer(object):
 
             if isinstance(i, renpy.ast.Label):
                 if not i.hide:
-                    self.label = i.name
+
+                    if i.name.startswith("_"):
+                        self.alternate = i.name
+                    else:
+                        self.label = i.name
+                        self.alternate = None
 
             if not isinstance(i, renpy.ast.Translate):
                 i.restructure(self.callback)
diff --git a/renpy/translation/generation.py b/renpy/translation/generation.py
index 8da89ed..f05fa2f 100644
--- a/renpy/translation/generation.py
+++ b/renpy/translation/generation.py
@@ -207,6 +207,10 @@ def write_translates(filename, language, filter):  # @ReservedAssignment
         if (t.identifier, language) in translator.language_translates:
             continue
 
+        if hasattr(t, "alternate"):
+            if (t.alternate, language) in translator.language_translates:
+                continue
+
         f = open_tl_file(tl_filename)
 
         if label is None:
diff --git a/renpy/ui.py b/renpy/ui.py
index db48265..bfabd64 100644
--- a/renpy/ui.py
+++ b/renpy/ui.py
@@ -1108,8 +1108,8 @@ def viewport_common(vpfunc, _spacing_to_side, scrollbars=None, **properties):
         vscrollbar_properties.setdefault("style", "vscrollbar")
 
     alt = viewport_properties.get("alt", "viewport")
-    scrollbar_properties.setdefault("alt", alt + " horizontal scrollbar")
-    vscrollbar_properties.setdefault("alt", alt + " vertical scrollbar")
+    scrollbar_properties.setdefault("alt", renpy.minstore.__(alt) + " " + renpy.minstore.__("horizontal scroll"))
+    vscrollbar_properties.setdefault("alt", renpy.minstore.__(alt) + " " + renpy.minstore.__("vertical scroll"))
 
     if scrollbars == "vertical":
 
diff --git a/renpy/vc_version.py b/renpy/vc_version.py
index 0e06cba..9dd0202 100644
--- a/renpy/vc_version.py
+++ b/renpy/vc_version.py
@@ -1 +1 @@
-vc_version = 3218
\ No newline at end of file
+vc_version = 3347
\ No newline at end of file
diff --git a/renpy/warp.py b/renpy/warp.py
index 4e5af33..57f0f89 100644
--- a/renpy/warp.py
+++ b/renpy/warp.py
@@ -51,24 +51,48 @@ def warp():
     if not renpy.config.developer:
         raise Exception("Can't warp, developer mode disabled.")
 
+    if not filename.startswith("game/"):
+        filename = "game/" + filename
+
     # First, compute for each statement reachable from a scene statement,
     # one statement that reaches that statement.
 
     prev = { }
 
-    workset = { n for n in renpy.game.script.namemap.itervalues() if isinstance(n, renpy.ast.Scene) }
-    seenset = set(workset)
+    seenset = set(renpy.game.script.namemap.values())
 
     # This is called to indicate that next can be executed following node.
     def add(node, next):  # @ReservedAssignment
-        if next not in seenset:
-            seenset.add(next)
-            workset.add(next)
+
+        if next not in prev:
             prev[next] = node
+            return
+
+        # Try to figure out which node to use.
+
+        old = prev[next]
+
+        def prefer(fn):
+            if fn(node, old):
+                return node
+
+            if fn(old, node):
+                return old
+
+            return None
+
+        n = None
+        n = n or prefer(lambda a, b : (a.filename == next.filename) and (b.filename != next.filename))
+        n = n or prefer(lambda a, b : (a.linenumber <= next.linenumber) and (b.linenumber > next.linenumber))
+        n = n or prefer(lambda a, b : (a.linenumber >= b.linenumber))
+        n = n or node
+
+        prev[next] = n
 
-    while workset:
+    for n in seenset:
 
-        n = workset.pop()
+        if isinstance(n, renpy.ast.Translate) and n.language:
+            continue
 
         if isinstance(n, renpy.ast.Menu):
             for i in n.items:
@@ -98,7 +122,6 @@ def warp():
 
         if isinstance(n, renpy.ast.UserStatement):
             add(n, n.get_next())
-
         elif getattr(n, 'next', None) is not None:
             add(n, n.next)
 
@@ -107,11 +130,12 @@ def warp():
 
     candidates = [ (n.linenumber, n)
                    for n in seenset
-                   if n.filename.endswith('/' + filename) and n.linenumber <= line ]
+                   if n.filename == filename and n.linenumber <= line
+                   ]
 
     # We didn't find any candidate statements, so give up the warp.
     if not candidates:
-        return
+        raise Exception("Could not find a statement to warp to. ({})".format(spec))
 
     # Sort the list of candidates, so they're ordered by linenumber.
     candidates.sort()
@@ -126,22 +150,37 @@ def warp():
     while True:
         n = prev.get(n, None)
         if n:
+            del prev[n]
             run.append(n)
         else:
             break
 
     run.reverse()
 
+    run = run[-renpy.config.warp_limit:]
+
+    renpy.config.skipping = "fast"
+
     # Determine which statements we want to execute, and then run
     # only them.
 
-    toexecute = ( renpy.ast.Scene, renpy.ast.Show, renpy.ast.Hide )
-
     for n in run:
-        if isinstance(n, toexecute):
-            n.execute()
+
+        if n.can_warp():
+
+            # Execute, if possible.
+            try:
+                n.execute()
+            except:
+                pass
 
     # Now, return the name of the place where we will warp to. This
     # becomes the new starting point of the game.
 
-    return node.name
+    renpy.config.skipping = None
+    renpy.game.after_rollback = True
+
+    renpy.exports.block_rollback()
+
+    renpy.game.context().goto_label(node.name)
+    raise renpy.game.RestartContext("_after_warp")
diff --git a/sphinx/game/doc.py b/sphinx/game/doc.py
index bee6fae..0baab21 100644
--- a/sphinx/game/doc.py
+++ b/sphinx/game/doc.py
@@ -11,47 +11,25 @@ import os
 
 import __builtin__
 
-# Keywords in the Ren'Py script language.
-KEYWORD1 = """\
+# Additional keywords in the Ren'Py script language.
+SCRIPT_KEYWORDS = """\
 $
 as
 at
 behind
-call
 expression
-hide
-if
-in
-image
-init
-jump
-menu
 onlayer
-python
-return
-scene
-set
-show
-with
-while
 zorder
-transform
-play
-queue
-stop
-pause
-define
-screen
-label
-voice
-translate
+strings
+take
+nointeract
+elif
+old
+new
 """
 
-# Words that are sometimes statement keywords, like for ATL
-# or Screen language statements.
-KEYWORD2 = """\
-nvl
-window
+# ATL Keywords.
+ATL_KEYWORDS = """\
 repeat
 block
 contains
@@ -66,50 +44,141 @@ clockwise
 counterclockwise
 circles
 knot
-null
-text
-hbox
-vbox
-fixed
-grid
-side
-frame
-key
-timer
-input
-button
-imagebutton
-textbutton
-bar
-vbar
-viewport
-imagemap
-hotspot
-hotbar
-transform
-add
-use
+"""
+
+# SL2 Keywords (that aren't statements).
+SL2_KEYWORDS = """\
+tag
 has
-style
 """
 
 
+def script_keywords():
+
+    tries = [ renpy.parser.statements ]
+
+    rv = set()
+
+    while tries:
+        trie = tries.pop(0)
+        for k, v in trie.words.items():
+            rv.add(k)
+            tries.append(v)
+
+    rv.remove("layer")
+
+    return rv
+
+
+script_keywords()
+
+
+def sl2_keywords():
+
+    rv = set()
+
+    for i in renpy.sl2.slparser.all_statements:
+        rv.add(i.name)
+
+    rv.remove("icon")
+    rv.remove("iconbutton")
+
+    return rv
+
+
+def sl2_regexps():
+
+    rv = [ ]
+
+    groups = collections.defaultdict(set)
+    has_style = { }
+
+    for k, v in renpy.sl2.slparser.properties.items():
+        prefix, style = k
+
+        has_style[prefix] = style
+
+        if prefix == "icon_":
+            continue
+
+        props = tuple(sorted(v))
+
+        groups[props, style].add(prefix)
+
+    style_part2 = "(?:" + "|".join(sorted(renpy.sl2.slparser.STYLE_PREFIXES)) + ")"
+
+    items = list(groups.items())
+    items.sort(key=lambda a : ( tuple(sorted(a[1])), a[0][1] ) )
+
+    for k, prefixes in items:
+        names, style = k
+
+        if len(prefixes) > 1:
+            part1 = "(?:" + "|".join(prefixes) + ")"
+        else:
+            part1 = tuple(prefixes)[0]
+
+        if style:
+            part2 = style_part2
+        else:
+            part2 = ""
+
+        part3 = "(?:" + "|".join(sorted(names)) + ")"
+
+        re = part1 + part2 + part3
+        rv.append(re)
+
+    return rv
+
+
+def expanded_sl2_properties():
+
+    rv = set()
+
+    for k, v in renpy.sl2.slparser.properties.items():
+        prefix, style = k
+
+        if prefix == "icon_":
+            continue
+
+        if style:
+            style_prefixes = renpy.sl2.slparser.STYLE_PREFIXES
+        else:
+            style_prefixes = [ '' ]
+
+        for i in style_prefixes:
+            for j in v:
+                rv.add(prefix + i + j)
+
+    rv = list(rv)
+    rv.sort()
+
+    return rv
+
+
 def write_keywords():
     f = file("source/keywords.py", "w")
 
-    kwlist = list(keyword.kwlist)
-    kwlist.extend(KEYWORD1.split())
-    kwlist.extend(KEYWORD2.split())
+    kwlist = set(keyword.kwlist)
+    kwlist |= script_keywords()
+    kwlist |= sl2_keywords()
+    kwlist |= set(ATL_KEYWORDS.split())
+    kwlist |= set(SCRIPT_KEYWORDS.split())
+    kwlist |= set(SL2_KEYWORDS.split())
+
+    kwlist = list(kwlist)
 
     kwlist.sort()
 
     f.write("keywords = %r\n" % kwlist)
+    f.write("keyword_regex = %r\n" % ("|".join(re.escape(i) for i in kwlist)))
 
-    properties = list(i for i in renpy.sl2.slparser.all_keyword_names if i not in kwlist)
-    properties.sort()
+    properties = [ i for i in expanded_sl2_properties() if i not in kwlist ]
 
     f.write("properties = %r\n" % properties)
 
+    f.write("property_regexes = %r\n" % sl2_regexps())
+
     f.close()
 
     shutil.copy("source/keywords.py", "../tutorial/game/keywords.py")
diff --git a/sphinx/source/changelog.rst b/sphinx/source/changelog.rst
index 000b362..b7a0099 100644
--- a/sphinx/source/changelog.rst
+++ b/sphinx/source/changelog.rst
@@ -2,8 +2,147 @@
 Full Changelog
 ==============
 
+.. _renpy-6.99.14.3:
+
+6.99.14.3
+=========
+
+Changes
+-------
+
+The :func:`AlphaMask` displayable now places its mask inside the child
+displayable, in the same way that AlphaDissolve always has. This allows
+the mask to be created using ATL or other transforms.
+
+Several obsolete image manipulators have been deprecated, and removed from
+the documentation. These are image manipulators that have been completely
+replaced by :func:`Transform`.
+
+Several functions have been renamed, to remove a pointless Live prefix.
+
+* LiveComposite is now :func:`Composite`
+* LiveCrop is now :func:`Crop`
+* LiveTile is now :func:`Tile`
+
+The old names have been retained as compatibility alias.
+
+
+Fixes
+-----
+
+This release fixes an issue where children of for statements in screens would
+not get their data propagated through screen update cycles. This manifested
+in complicated ways, such as transitions repeating and slow text refusing
+to work.
+
+This release displays the newest save slot in the selected color, as
+intended. This applies to newly created games, older projects can update
+by adding to the bottom of gui.rpy::
+
+    define gui.slot_button_text_selected_idle_color = gui.selected_color
+    define gui.slot_button_text_selected_hover_color = gui.hover_color
+
+A problem introduced in 6.99.14.2 with the the default statement
+not working after a rollback has been fixed. This should only ever
+have affected games that were updated after a save was first
+created.
+
+.. _renpy-6.99.14.2:
+
+6.99.14.2
+=========
+
+Features and Changes
+--------------------
+
+The Atom text editor is now supported in Ren'Py. When it is selected, Ren'Py
+will download Atom, and will create a new profile with the language-renpy,
+renpy-dark-syntax, and renpy-light-syntax Atom plugins installed, along with
+a few default setting to make Ren'Py programming easier.
+
+It is now possible to supply a baseline to image-based fonts.
+
+When a screen in the default gui scrolls, the pageup and pagedown keys will
+now work to scroll it. (This only works with newly-created projects.)
+
+The :func:`Movie` displayable now takes a play_callback argument, which
+specifies a function that is called to play a movie. This function can
+do things like queue up a transition movie before queuing the usual loop,
+making for smooth transitions.
+
+The new :func:`renpy.get_say_image_tag` function makes it possible to
+retrieve the name of the speaking character.
+
+ATL interpolation can now interpolate from a transform with multiple
+lines in it, provided none of the lines takes time to complete.
+
+Adding the from statement to a call no longer changes the translation
+identifier. (Which is also used by the automatic voice code.) Since this
+would be a breaking change, Ren'Py also computes the old-style translation
+identifier and uses that if it exists.
+
+The _choose_attributes method is called when only a single displayable can
+be located. This supports the AttributeImage beta (https://github.com/renpy/ai).
+
+The new :var:`gui.button_image_extension` variable allows button images to be
+.webps without changing Ren'Py itself.
+
+Self-Voicing
+------------
+
+Ren'Py's self-voicing mode, which provides accessibility for blind
+users, has been improved:
+
+* Selected buttons say the word "selected" after them.
+* Bars say the world "bar" after them.
+* Some actions have had their self-voicing information changed to better
+  reflect how the action is used in the new GUI.
+* Alt text built into Ren'Py can be translated.
+
+While this can change some of the self-voicing output, the changes
+should not affect any translations that already exist.
+
+Fixes
+-----
+
+An issue where a save or auto-save could rarely cause data corruption
+in the non-saved game has been fixed.
+
+Python hide statements are now run in a python function context, which
+makes certain constructs (like generator expressions) compile and run
+correctly.
+
+Global labels now behave as described in the documentation, even when
+indented.
+
+A regression with custom mouse cursors that could cause the mouse to
+jump around wildly has been fixed.
+
+An issue with side images persisting after a menu was shown has been fixed.
+
+Ren'Py no longer stores the state of displayables that are not being shown
+in a screen that has been replaced. (This was an issue when the first screen
+is re-show, and the displayables took their old state.)
+
+The show and replace events are now always delivered to a transform in a
+screen. While this behavior was always intended and could occur whenever
+a screen was shown, previously caching could prevent some show events
+from being delivered.
+
+Characters that require the alt key can be typed. (The alt key is necessary
+to type particular characters in European languages.)
+
+When the Android build system fails to rename a file or directory, it will
+retry for 60 seconds before giving up. This is an attempt to work around
+antivirus software breaking Windows semantics.
+
+
 .. _renpy-6.99.14.1:
 
+
+6.99.14.1
+=========
+
 Image Prediction and Caching
 ----------------------------
 
diff --git a/sphinx/source/credits.rst b/sphinx/source/credits.rst
index e0c460d..c94ee13 100644
--- a/sphinx/source/credits.rst
+++ b/sphinx/source/credits.rst
@@ -19,6 +19,7 @@ the omission in future versions.
 * Aleema
 * Alessio
 * Alexandre Tranchant
+* Andyl_kl
 * Apricotorange
 * Arowana-vx
 * Asfdfdfd
@@ -52,6 +53,7 @@ the omission in future versions.
 * Emmeken
 * Enerccio
 * Eniko
+* Eevee (Lexy Munroe)
 * Evilantishad0w
 * Franck_v
 * Gas
@@ -125,6 +127,7 @@ the omission in future versions.
 * Tmrwiz
 * Viliam Búr
 * Vollschauer
+* William Tumeo
 * Winter Wolves
 * Xavi-Mat
 * Xela
diff --git a/sphinx/source/displayables.rst b/sphinx/source/displayables.rst
index 41d7e90..8174ac2 100644
--- a/sphinx/source/displayables.rst
+++ b/sphinx/source/displayables.rst
@@ -123,6 +123,16 @@ Dynamic displayables display a child displayable based on the state of
 the game. They do not take any properties, as layout is controlled
 by the properties of the child displayable they return.
 
+Note that these dynamic displayables always display their current state.
+Because of this, a dynamic displayable will not participate in a
+transition. (Or more precisely, it will display the same thing in both the
+old and new states of the transition.)
+
+By design, dynamic displayables are intended to be used for things that
+change rarely and when an image define this way is off screen (Such as
+a character customization system), and not for things that change
+frequently, such as character emotions.
+
 .. include:: inc/disp_dynamic
 
 
@@ -184,27 +194,19 @@ Image Manipulators
 ------------------
 
 An image manipulator is a displayable that takes an image or image
-manipulator, performs an operation to it, and stores the result of
-that operation in the image cache. Since image manipulators can be
-predicted like images, they can perform expensive operations without
-incuring a display-time overhead.
-
-Image manipulators are limited to storing image data to the
-cache. This means that their result is of a fixed size, known in
-advance, and they can't change in response to game state or
-input. Generally, image manipulators can only take images or other
+manipulator, and either loads it or performs an operation on it.
+Image manipulators can only take images or other
 image manipulators as input.
 
 An image manipulator can be used any place a displayable can, but not
 vice-versa. An :func:`Image` is a kind of image manipulator, so an
 Image can be used whenever an image manipulator is required.
 
-Many image manipulators provide the same functionality as other
-displayables. Most of these exist so they can be provided as input to
-other image manipulators, and so the game-maker can choose between
-cache memory usage and work done at render-time. There's also an
-element of historical accident here - many of these image manipulators
-predate their equivalents.
+With the few exceptions listed below, the use of image manipulators is
+historic. A number of image manipulators that had been documented in the
+past should no longer be used, as they suffer from inherent problems.
+In many cases, the :func:`Transform` displayable provides similar
+functionality in a more general manner, while fixing the problems.
 
 .. include:: inc/im_im
 
diff --git a/sphinx/source/gui.rst b/sphinx/source/gui.rst
index 20bd277..f9d7cb9 100644
--- a/sphinx/source/gui.rst
+++ b/sphinx/source/gui.rst
@@ -635,6 +635,10 @@ The following variables set various properties of buttons:
     The horizontal alignment of the button text. 0.0 is left-aligned,
     0.5 is centered, and 1.0 is right-aligned.
 
+.. var:: gui.button_image_extension = ".png"
+
+    The extension for button images. This could be changed to .webp
+    to use WEBP button images instead of png ones.
 
 These variables can be prefixed with the button kind to configure a
 property for a particular kind of button. For example,
diff --git a/sphinx/source/incompatible.rst b/sphinx/source/incompatible.rst
index 53bbd44..cd027c2 100644
--- a/sphinx/source/incompatible.rst
+++ b/sphinx/source/incompatible.rst
@@ -61,7 +61,7 @@ compatible with the font file's license.)
 6.99.11
 -------
 
-The order of exection of ``style`` and ``translate`` statements has
+The order of execution of ``style`` and ``translate`` statements has
 changed, as documented in :ref:`the changelog <renpy-6.99.11>`. To
 revent this change, add the code::
 
@@ -70,8 +70,8 @@ revent this change, add the code::
 Note that reverting this change may prevent the new GUI from working.
 
 
-The :var:`config.quit_action` variable has changed it's default to one
-that cause the quit prompt to be displayed of the in-game context. To
+The :var:`config.quit_action` variable has changed its default to one
+that causes the quit prompt to be displayed of the in-game context. To
 revert to the old behavior, add the code::
 
     define config.quit_action = ui.gamemenus("_quit_prompt")
diff --git a/sphinx/source/keywords.py b/sphinx/source/keywords.py
index 8c8623b..a09b2f4 100644
--- a/sphinx/source/keywords.py
+++ b/sphinx/source/keywords.py
@@ -1,2 +1,4 @@
-keywords = ['$', 'add', 'and', 'animation', 'as', 'as', 'assert', 'at', 'bar', 'behind', 'block', 'break', 'button', 'call', 'choice', 'circles', 'class', 'clockwise', 'contains', 'continue', 'counterclockwise', 'def', 'define', 'del', 'elif', 'else', 'event', 'except', 'exec', 'expression', 'finally', 'fixed', 'for', 'frame', 'from', 'function', 'global', 'grid', 'has', 'hbox', 'hide', 'hotbar', 'hotspot', 'if', 'if', 'image', 'imagebutton', 'imagemap', 'import', 'in', 'in', 'init', 'in [...]
-properties = ['action', 'activate_additive', 'activate_adjust_spacing', 'activate_align', 'activate_alignaround', 'activate_alpha', 'activate_alt', 'activate_anchor', 'activate_angle', 'activate_antialias', 'activate_area', 'activate_around', 'activate_background', 'activate_bar_invert', 'activate_bar_resizing', 'activate_bar_vertical', 'activate_base_bar', 'activate_black_color', 'activate_bold', 'activate_bottom_bar', 'activate_bottom_gutter', 'activate_bottom_margin', 'activate_bottom [...]
+keywords = ['$', 'add', 'and', 'animation', 'as', 'assert', 'at', u'auto', 'bar', 'behind', 'block', 'break', 'button', 'call', 'choice', 'circles', 'class', u'clear', 'clockwise', 'contains', 'continue', 'counterclockwise', 'def', 'default', 'define', 'del', 'drag', 'draggroup', 'elif', 'else', 'event', 'except', 'exec', 'expression', 'finally', 'fixed', 'for', 'frame', 'from', 'function', 'global', 'grid', 'has', 'hbox', 'hide', 'hotbar', 'hotspot', 'if', 'image', 'imagebutton', 'image [...]
+keyword_regex = u'\\$|add|and|animation|as|assert|at|auto|bar|behind|block|break|button|call|choice|circles|class|clear|clockwise|contains|continue|counterclockwise|def|default|define|del|drag|draggroup|elif|else|event|except|exec|expression|finally|fixed|for|frame|from|function|global|grid|has|hbox|hide|hotbar|hotspot|if|image|imagebutton|imagemap|import|in|init|input|is|jump|key|knot|label|lambda|menu|mousearea|music|new|nointeract|not|null|nvl|offset|old|on|onlayer|or|parallel|pass|pa [...]
+properties = ['action', 'activate_additive', 'activate_adjust_spacing', 'activate_align', 'activate_alignaround', 'activate_alpha', 'activate_alt', 'activate_anchor', 'activate_angle', 'activate_antialias', 'activate_area', 'activate_around', 'activate_background', 'activate_bar_invert', 'activate_bar_resizing', 'activate_bar_vertical', 'activate_base_bar', 'activate_black_color', 'activate_bold', 'activate_bottom_bar', 'activate_bottom_gutter', 'activate_bottom_margin', 'activate_bottom [...]
+property_regexes = [u'(?:action|activate_sound|adjustment|allow|alpha|alternate|alternate_keysym|arguments|arrowkeys|at|auto|cache|caption|changed|child_size|clicked|cols|default|drag_handle|drag_joined|drag_name|drag_offscreen|drag_raise|draggable|dragged|droppable|dropped|edgescroll|exclude|focus|focus_mask|ground|height|hover|hovered|id|idle|image_style|insensitive|keysym|layer|length|modal|mouse_drop|mousewheel|pagekeys|pixel_width|predict|prefix|properties|range|repeat|rows|scope|sc [...]
diff --git a/sphinx/source/movie.rst b/sphinx/source/movie.rst
index 75adfba..87a50f2 100644
--- a/sphinx/source/movie.rst
+++ b/sphinx/source/movie.rst
@@ -66,18 +66,7 @@ channel, with white being full opacity and black being full transparency.
 
 Movies played by the Movie displayable loop automatically.
 
-There are three very important parameters to the Movie displayable, two of
-which should always be provided.
-
-`channel`
-    A string giving the name of the channel that the movie will be played on.
-
-    This must always be provided, and should never
-    *not* be left at the default of "movie", and should not be the name
-    of an audio channel. Names should be chosen such that only one
-    Movie will be displaying on a given channel at the same time. Channels
-    provided will be automatically registered using :func:`renpy.music.register_channel`,
-    if not already registered.
+A Movie takes two parameters:
 
 `play`
     A string giving the name of a movie file to play.
@@ -85,11 +74,13 @@ which should always be provided.
     This should always be provided.
 
 `mask`
-    A string giving the name of a movie file to use as an alpha mask.
+    A string giving the name of a movie file to use as an alpha mask. It should
+    be the same size, duration, and framerate as the movie file provided to
+    `play`.
 
 Here's an example of defining a movie sprite::
 
-    image eileen movie = Movie(channel="eileen", play="eileen_movie.webm", mask="eileen_mask.webm")
+    image eileen movie = Movie(play="eileen_movie.webm", mask="eileen_mask.webm")
 
 The movie sprite can be shown using the show statement, which automatically starts the
 movie playing. It will be automatically stopped when the displayable is hidden. ::
@@ -106,7 +97,7 @@ A Movie displayable can also be used as part of a screen, provided it is created
 during the init phase (for example, as part of an image statement.) ::
 
 
-    image main_menu = Movie(channel="main_menu", play="main_menu.ogv")
+    image main_menu = Movie(play="main_menu.ogv")
 
     screen main_menu:
         add "main_menu"
diff --git a/sphinx/source/multiple.rst b/sphinx/source/multiple.rst
index 71a76c4..fe26575 100644
--- a/sphinx/source/multiple.rst
+++ b/sphinx/source/multiple.rst
@@ -46,34 +46,34 @@ displayed at once.
 In our example above, the window corresponding to each block of dialogue
 are given the names:
 
-* block1_multiple2_window
-* block2_multiple2_window
+* block1_multiple2_say_window
+* block2_multiple2_say_window
 
 This naming scheme is used for the dialogue, name, and namebox, as well
 as the window. It's designed so style inheritance is useful here. For
 the window styles we'll have:
 
-window
+say_window
     Used for the normal case of a single dialogue window, this can serve as
     a base for all dialogue windows.
 
-multiple2_window
+multiple2_say_window
     This can be used for properties common to the two dialogue windows,
     like changing the background and reducing the margin and padding.
 
-block1_multiple2_window
+block1_multiple2_say_window
     This could be used to position the first of the two dialogue windows,
     such as using xalign 0.0 to put it on the left side.
 
-block2_multiple2_window
+block2_multiple2_say_window
     Similarly, this can be used to position the second window, with
     xalign 1.0 putting it on the right side.
 
 The Multiple Say Screen
 -----------------------
 
-For more control, there is the multiple say screen. When it exists, the
-multiple say screen is used in place of the normal say screen. It takes
+For more control, there is the multiple\_say screen. When it exists, the
+multiple\_say screen is used in place of the normal say screen. It takes
 a third argument, `multiple`, which is a tuple. The first component of
 the tuple is the block number, and the second is the total number of
 screens.
diff --git a/sphinx/source/nvl_mode.rst b/sphinx/source/nvl_mode.rst
index 4ac06bc..541a9ad 100644
--- a/sphinx/source/nvl_mode.rst
+++ b/sphinx/source/nvl_mode.rst
@@ -205,6 +205,11 @@ The following config variables control nvl-related functionality.
 
     If true, NVL-mode rollback will occur a full page at a time.
 
+Python Functions
+----------------
+
+.. include:: inc/nvl
+
 
 Paged Rollback
 --------------
diff --git a/sphinx/source/sponsors.html b/sphinx/source/sponsors.html
index 7ad25e8..4ea8692 100644
--- a/sphinx/source/sponsors.html
+++ b/sphinx/source/sponsors.html
@@ -1,106 +1,124 @@
 <ul class='sponsors'>
-    <li> Adia Alderson (6.99.13, 6.99.14)
-    <li> Aleema (6.99.13, 6.99.14)
-    <li> <a href="http://alexdodge.net/" rel="nofollow">Alex Dodge</a> (6.99.14)
-    <li> <a href="https://rabidb.com/" rel="nofollow">AlexSSZ</a> (6.99.13,6.99.14)
-    <li> Asatiir (6.99.13, 6.99.14)
-    <li> Belfort and Bastion (6.99.13, 6.99.14)
-    <li> <a href="http://biotikos-development.blogspot.com.es" rel="nofollow">Biotikos Development</a> (6.99.13,6.99.14)
-    <li> Bob (6.99.13, 6.99.14)
-    <li> Booom313's tinker corner (6.99.14)
-    <li> Boreas (6.99.13, 6.99.14)
-    <li> <a href="http://boyslaughplus.moe" rel="nofollow">Boys Laugh +</a> (6.99.13,6.99.14)
-    <li> Brett Douglas (6.99.14)
-    <li> Brimney (6.99.13, 6.99.14)
-    <li> Bruni Multimedia (6.99.14)
+    <li> Adia Alderson (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Aleema (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://alexdodge.net/" rel="nofollow">Alex Dodge</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="https://rabidb.com/" rel="nofollow">AlexSSZ</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="https://lemmasoft.renai.us/forums/viewtopic.php?f=51&t=34131" rel="nofollow">AR09FQF-AQ09FRF</a> (6.99.14.1,6.99.14.2)
+    <li> Asatiir (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Belfort and Bastion (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://biotikos-development.blogspot.com.es" rel="nofollow">Biotikos Development</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Bob (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://bobcgames.tumblr.com" rel="nofollow">Bob Conway</a> (6.99.14.1,6.99.14.2)
+    <li> Booom313's Support Corner (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Booom313's tinker corner (6.99.14.1, 6.99.14.2)
+    <li> Boreas (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://boyslaughplus.moe" rel="nofollow">Boys Laugh +</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Bradley Todd Whitesell (6.99.14.2)
+    <li> Brett Douglas (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Brimney (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Bruni Multimedia (6.99.14, 6.99.14.1, 6.99.14.2)
     <li> <a href="http://www.bura.cl" rel="nofollow">BURA</a> (6.99.13)
-    <li> Cara Hillstock (6.99.13, 6.99.14)
-    <li> Charlene Gilbert (6.99.13, 6.99.14)
-    <li> <a href="http://charliethegoldfish.com" rel="nofollow">Charlie Francis Cassidy</a> (6.99.13,6.99.14)
-    <li> Chrysoula Tzavelas (6.99.13, 6.99.14)
-    <li> <a href="https://cloverfirefly.itch.io" rel="nofollow">cloverfirefly</a> (6.99.13,6.99.14)
-    <li> <a href="https://www.renpy.org/agegate?url=https://obscurasoft.com/" rel="nofollow">Coming Out On Top</a> (6.99.13,6.99.14)
-    <li> <a href="http://www.computerart.club/" rel="nofollow">computerart.club</a> (6.99.14)
-    <li> <a href="http://cultofape.com" rel="nofollow">CultOfApe</a> (6.99.14)
-    <li> Culture4Jam (6.99.13, 6.99.14)
-    <li> <a href="www.darksirengames.com" rel="nofollow">DarkSirenGames</a> (6.99.13,6.99.14)
-    <li> David Koster (6.99.14)
-    <li> <a href="http://www.deadlinesoft.com" rel="nofollow">DeadlineSoft</a> (6.99.13,6.99.14)
-    <li> <a href="https://twitter.com/princessdealtry" rel="nofollow">Diplomatic Relations</a> (6.99.13,6.99.14)
-    <li> <a href="http://coriginate.com" rel="nofollow">Ds110</a> (6.99.13,6.99.14)
-    <li> E. William Brown (6.99.13, 6.99.14)
-    <li> Euan 'Xolf' Robertson (6.99.13, 6.99.14)
+    <li> Cara Hillstock (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Charlene Gilbert (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://charliethegoldfish.com" rel="nofollow">Charlie Francis Cassidy</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Cherry Kiss Games (6.99.14.1, 6.99.14.2)
+    <li> Chrysoula Tzavelas (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://cloverfirefly.itch.io" rel="nofollow">cloverfirefly</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="https://www.renpy.org/agegate?url=https://obscurasoft.com/" rel="nofollow">Coming Out On Top</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://www.computerart.club/" rel="nofollow">computerart.club</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://cultofape.com" rel="nofollow">CultOfApe</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> Culture4Jam (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://dark-aii.net" rel="nofollow">Dark-Aii</a> (6.99.14.1,6.99.14.2)
+    <li> <a href="www.darksirengames.com" rel="nofollow">DarkSirenGames</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> David Koster (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> David Yingling (6.99.14.1, 6.99.14.2)
+    <li> <a href="http://www.deadlinesoft.com" rel="nofollow">DeadlineSoft</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Denny Cheng (6.99.14.2)
+    <li> <a href="https://twitter.com/princessdealtry" rel="nofollow">Diplomatic Relations</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://coriginate.com" rel="nofollow">Ds110</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> E. William Brown (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Euan 'Xolf' Robertson (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
     <li> Eve Hallows (6.99.13, 6.99.14)
-    <li> Exiscoming (6.99.14)
+    <li> Exiscoming (6.99.14, 6.99.14.1, 6.99.14.2)
     <li> <a href="http://store.steampowered.com/app/560250/Galaxy_Girls/" rel="nofollow">Galaxy Girls</a> (6.99.13,6.99.14)
-    <li> <a href="https://goldengamebarn.com/" rel="nofollow">Golden Game Barn</a> (6.99.13,6.99.14)
-    <li> Great Chicken Studio (6.99.14)
-    <li> Gunso (6.99.13, 6.99.14)
-    <li> Happimochi (6.99.14)
+    <li> <a href="https://goldengamebarn.com/" rel="nofollow">Golden Game Barn</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Great Chicken Studio (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Gunso (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
     <li> Happimochi (6.99.13, 6.99.14)
-    <li> I_Jemin (6.99.13, 6.99.14)
-    <li> <a href="https://irredeemable.net/" rel="nofollow">Irredeemable Games</a> (6.99.14)
-    <li> J. C. Holder (6.99.13, 6.99.14)
-    <li> James Tyner (6.99.13, 6.99.14)
-    <li> JeongPyo Lee (6.99.13, 6.99.14)
-    <li> Joanna B (6.99.13, 6.99.14)
-    <li> jonnymelabo (6.99.13, 6.99.14)
-    <li> Josh Kaplan (6.99.13, 6.99.14)
+    <li> Happimochi (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://ijemin.com" rel="nofollow">I_Jemin</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="https://irredeemable.net/" rel="nofollow">Irredeemable Games</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> J. C. Holder (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> James Tyner (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> JeongPyo Lee (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Joanna B (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> jonnymelabo (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Josh Kaplan (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
     <li> K. Starbuck (6.99.13, 6.99.14)
-    <li> Kayde Initials (6.99.13, 6.99.14)
-    <li> <a href="http://kexboy.com" rel="nofollow">KEXBOY</a> (6.99.13,6.99.14)
-    <li> <a href="http://www.gamesbykinmoku.com" rel="nofollow">Kinmoku</a> (6.99.13,6.99.14)
-    <li> Kosmos Games (6.99.14)
-    <li> lain105/EckoMars (6.99.13, 6.99.14)
-    <li> LateWhiteRabbit (6.99.14)
-    <li> <a href="http://trash.moe/" rel="nofollow">Lore</a> (6.99.13,6.99.14)
-    <li> Luke Jackson (6.99.13, 6.99.14)
-    <li> <a href="http://luscious-spirit-studios.tumblr.com/" rel="nofollow">Luscious Spirit Studios</a> (6.99.13,6.99.14)
-    <li> M. I. Madrone (6.99.13, 6.99.14)
-    <li> Maeve Bandruid (6.99.13, 6.99.14)
-    <li> <a href="https://www.renpy.org/agegate?url=https://www.patreon.com/manitu" rel="nofollow">MANITU Games CO.</a> (6.99.13,6.99.14)
-    <li> <a href="https://manorstories.fr" rel="nofollow">ManorStories</a> (6.99.14)
-    <li> <a href="http://www.marionettecode.com/" rel="nofollow">Marionette</a> (6.99.14)
+    <li> Kayde Initials (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://kexboy.com" rel="nofollow">KEXBOY</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://www.gamesbykinmoku.com" rel="nofollow">Kinmoku</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Kosmos Games (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> lain105/EckoMars (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> LateWhiteRabbit (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://twitter.com/Seirei_sama" rel="nofollow">Lethargic</a> (6.99.14.1,6.99.14.2)
+    <li> <a href="https://www.renpy.org/agegate?url=https://www.lewdlab.com/" rel="nofollow">Lewdlab</a> (6.99.14.1,6.99.14.2)
+    <li> Lictor (6.99.14.2)
+    <li> <a href="http://trash.moe/" rel="nofollow">Lore</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Luke Jackson (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://luscious-spirit-studios.tumblr.com/" rel="nofollow">Luscious Spirit Studios</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> M. I. Madrone (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Maeve Bandruid (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://www.renpy.org/agegate?url=https://www.patreon.com/manitu" rel="nofollow">MANITU Games CO.</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="https://manorstories.fr" rel="nofollow">ManorStories</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://www.marionettecode.com/" rel="nofollow">Marionette</a> (6.99.14,6.99.14.1,6.99.14.2)
     <li> MAW.3D.Art (6.99.13)
-    <li> Max J Sher (6.99.13, 6.99.14)
-    <li> <a href="https://meagantrott.com" rel="nofollow">Meagan Trott</a> (6.99.13,6.99.14)
-    <li> <a href="http://metasepia.icecavern.net" rel="nofollow">Metasepia Games</a> (6.99.13,6.99.14)
-    <li> Michaela Laws (6.99.13, 6.99.14)
+    <li> Max J Sher (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://meagantrott.com" rel="nofollow">Meagan Trott</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://metasepia.icecavern.net" rel="nofollow">Metasepia Games</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Meyvol (6.99.14.1, 6.99.14.2)
+    <li> Michaela Laws (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
     <li> <a href="https://ms45.itch.io" rel="nofollow">Ms .45</a> (6.99.13)
-    <li> <a href="http://cafe.naver.com/vmo" rel="nofollow">NaverCafe VMO</a> (6.99.13,6.99.14)
-    <li> Nicholas Swenson (6.99.14)
-    <li> <a href="https://www.patreon.com/nikraria" rel="nofollow">nikraria</a> (6.99.13,6.99.14)
-    <li> Panthera Morag (6.99.13, 6.99.14)
-    <li> Patricia (6.99.13, 6.99.14)
-    <li> <a href="http://peachpattch.com/" rel="nofollow">peachpattch</a> (6.99.14)
-    <li> plasterbrain (6.99.13, 6.99.14)
-    <li> Ploppertje (6.99.13, 6.99.14)
-    <li> Podge (6.99.13, 6.99.14)
+    <li> <a href="http://cafe.naver.com/vmo" rel="nofollow">NaverCafe VMO</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Nicholas Swenson (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://www.patreon.com/nikraria" rel="nofollow">nikraria</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://devety.com" rel="nofollow">Oleksii olety Kyrylchuk</a> (6.99.14.1,6.99.14.2)
+    <li> Panthera Morag (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Patricia (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://peachpattch.com/" rel="nofollow">peachpattch</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> philat (6.99.14.1, 6.99.14.2)
+    <li> plasterbrain (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Ploppertje (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Podge (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
     <li> Puriwit Sesupaponphong (6.99.13)
-    <li> <a href="http://razzartvisual.com/" rel="nofollow">Razz</a> (6.99.13,6.99.14)
-    <li> René Dudfield (6.99.13, 6.99.14)
-    <li> Richard (6.99.14)
-    <li> <a href="http://impqueen.com/" rel="nofollow">Rinmaru</a> (6.99.13,6.99.14)
-    <li> <a href="http://sunkoiwish.com/" rel="nofollow">Royce A Xaiyeon</a> (6.99.13,6.99.14)
-    <li> Ryan Balgos (6.99.14)
-    <li> Ryan Whited (6.99.14)
-    <li> Sam Yang (6.99.13, 6.99.14)
-    <li> <a href="http://sleepyagents.co.uk" rel="nofollow">Sleepy Agents</a> (6.99.13,6.99.14)
-    <li> Spyros Panagiotopoulos (6.99.14)
-    <li> Stefan Gagne (6.99.13, 6.99.14)
-    <li> Taosym (6.99.13, 6.99.14)
-    <li> Teofilo Hurtado (6.99.14)
-    <li> Thomas Charlie (6.99.13, 6.99.14)
-    <li> Timothy Landreth (6.99.13, 6.99.14)
-    <li> TJ Huckabee (6.99.13, 6.99.14)
+    <li> <a href="http://razzartvisual.com/" rel="nofollow">Razz</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> René Dudfield (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Richard (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://impqueen.com/" rel="nofollow">Rinmaru</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://sunkoiwish.com/" rel="nofollow">Royce A Xaiyeon</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> Ryan Balgos (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Ryan Whited (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://saiffyros.wordpress.com/" rel="nofollow">Saiffyros</a> (6.99.14,6.99.14.1,6.99.14.2)
+    <li> Sam Yang (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://sleepyagents.co.uk" rel="nofollow">Sleepy Agents</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://store.steampowered.com/app/570350/Sorry_Entschuldigung__A_Psychological_Horror_Visual_Novel/" rel="nofollow">Sorry. (Entschuldigung)</a> (6.99.14.2)
+    <li> Spyros Panagiotopoulos (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Steamlynx (6.99.14.1, 6.99.14.2)
+    <li> Stefan Gagne (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Taosym (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Teofilo Hurtado (6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Thomas Charlie (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> Timothy Landreth (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> TJ Huckabee (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
     <li> ToastCrust (6.99.13, 6.99.14)
-    <li> Tobias Wüthrich (6.99.13, 6.99.14)
-    <li> trooper6 (6.99.13, 6.99.14)
-    <li> <a href="https://www.youtube.com/tryinmorning" rel="nofollow">tryinmorning</a> (6.99.13,6.99.14)
-    <li> <a href="http://www.visualsaga.com/" rel="nofollow">Visual Saga</a> (6.99.13,6.99.14)
+    <li> Tobias Wüthrich (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> trooper6 (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="https://www.youtube.com/tryinmorning" rel="nofollow">tryinmorning</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="https://studiomugenjohncel.wordpress.com/" rel="nofollow">Uncle Mugen (Mugenjohncel</a> (6.99.14.2)
+    <li> <a href="http://www.visualsaga.com/" rel="nofollow">Visual Saga</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
     <li> Vollschauer (6.99.13, 6.99.14)
-    <li> <a href="https://www.facebook.com/weeabooriot" rel="nofollow">Weeabooriot Cosplay</a> (6.99.13,6.99.14)
-    <li> William Tumeo (6.99.13, 6.99.14)
-    <li> <a href="http://winterwolves.com/ambersmagicshop.htm" rel="nofollow">Winter Wolves</a> (6.99.13,6.99.14)
-    <li> <a href="http://astralore.com/" rel="nofollow">Yakmala!</a> (6.99.13,6.99.14)
+    <li> <a href="https://www.facebook.com/weeabooriot" rel="nofollow">Weeabooriot Cosplay</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> William Tumeo (6.99.13, 6.99.14, 6.99.14.1, 6.99.14.2)
+    <li> <a href="http://winterwolves.com/ambersmagicshop.htm" rel="nofollow">Winter Wolves</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
+    <li> <a href="http://astralore.com/" rel="nofollow">Yakmala!</a> (6.99.13,6.99.14,6.99.14.1,6.99.14.2)
 </ul>
diff --git a/sphinx/source/text.rst b/sphinx/source/text.rst
index e1b1311..8ba818f 100644
--- a/sphinx/source/text.rst
+++ b/sphinx/source/text.rst
@@ -269,7 +269,7 @@ Tags that apply to all text are:
     shadows) to the given color. The color should be in #rgb, #rgba,
     #rrggbb, or #rrggbbaa format. ::
 
-        "Let's have a {color=#00ff00}Green{/color} outline."
+        "Let's have a {outlinecolor=#00ff00}Green{/outlinecolor} outline."
 
 .. text-tag:: plain
 
diff --git a/templates/portuguese/game/options.rpy b/templates/portuguese/game/options.rpy
index 20c8335..8d5521e 100644
--- a/templates/portuguese/game/options.rpy
+++ b/templates/portuguese/game/options.rpy
@@ -1,199 +1,134 @@
-## This file contains some of the options that can be changed to customize
-## your Ren'Py game. It only contains the most common options... there
-## is quite a bit more customization you can do.
+## Este arquivo contém algumas das opções que podem ser mudadas para
+## personalizar o jogo Ren'Py. Ele apenas contém as opções mais comuns.
+## Você ainda pode adicionar mais personalizações.
 ##
-## Lines beginning with two '#' marks are comments, and you shouldn't
-## uncomment them. Lines beginning with a single '#' mark are
-## commented-out code, and you may want to uncomment them when
-## appropriate.
-##
-## - Este archivo contiene algunas de las opciones que pueden cambiarse para
-##   personalizar el juego Ren'Py. Solo figuran las opciones más comunes.
-##   Es posible añadir muchas más personalizaciones.
-##
-## - Las líneas que empiezan con dos marcas '#' son comentarios, no debes
-##   eliminar las marcas. Las líneas que comienzan con una sola marca '#'
-##   contienen código no activo. La marca '#' puede eliminarse si se quiere
-##   utilizar esa característica.
+## As linhas começadas com dois hashtags '#' são comentários, você não deve
+## apagá-las. As linhas começadas apenas com um hashtag '#' 
+## contém código não ativo e você pode desejar apagar a hashtag '#' acaso
+## julgar apropriado.
 
 init -1 python hide:
 
-    ## Should we enable the use of developer tools? This should be
-    ## set to False before the game is released, so the user can't
-    ## cheat using developer tools.
-    ## - Esta variable habilita las herramientas de desarrollo. Debe ser
-    ##   ajustada a False antes del lanzamiento del juego, así el usuario
-    ##   no puede hacer trampas usando las herramientas de desarrollo.
+    ## Esta variável habilita as ferramentas de desenvolvedor. Deve ser
+    ## ajustada para falsa ('False') antes do lançamento do jogo, assim o usuário 
+    ## não poderá utilizar 'cheats' utilizando as ferramentas do desenvolvedor.
 
     config.developer = True
 
-    ## These control the width and height of the screen.
-    ## - Control de la anchura y altura de la pantalla.
+    ## Estes são os controles da largura e da altura da tela. 
 
     config.screen_width = 800
     config.screen_height = 600
 
-    ## This controls the title of the window, when Ren'Py is
-    ## running in a window.
-    ## - Título de la ventana, cuando Ren'Py se ejecuta en modo ventana.
+    ## Estes são os controles para modificar o título da janela, quando Ren'Py é executado em modo janela.
 
     config.window_title = u"PROJECT_NAME"
 
-    ## These control the name and version of the game, that are reported
-    ## with tracebacks and other debugging logs.
-    ## - Control del nombre y versión del juego; se utilizan en los
-    ##   rastreos y otras funciones de depuración.
+    ## Estes são os controles do nome e da versão do jogo; eles são utilizados nos 
+    ## rastreamentos e outros logs de depuração.
+    
     config.name = "PROJECT_NAME"
     config.version = "0.0"
 
     #########################################
-    ## Themes
-    ## - Temas
-
-    ## We then want to call a theme function. theme.roundrect is
-    ## a theme that features the use of rounded rectangles.
-    ##
-    ## The theme function takes a number of parameters that can
-    ## customize the color scheme.
+    ## Temas
 
-    ## - Para utilizar una función de tema, utilizamos themes.roundrect.
-    ##   Este tema configura el uso de rectángulos redondeados.
+    ## Para utilizar uma função de tema, utilizamos themes.roundrect.
+    ## Este tema configura o uso de retângulos arredondados.
     ##
-    ## - La función de tema acepta una serie de parámetros que pueden
-    ##   personalizar la paleta de colores.
+    ## A função de tema aceita uma série de parâmetros que podem 
+    ## personalizar o esquema de cores.
 
     theme.roundrect(
 
-        ## The color of an idle widget face.
-        ## - Color base de un elemento (widget).
+        ## Cor base de um elemento (widget).
         widget = "#003c78",
 
-        ## The color of a focused widget face.
-        ## - Color de un elemento con foco.
+        ## Cor de um elemento com foco.
         widget_hover = "#0050a0",
 
-        ## The color of the text in a widget.
-        ## - Color del texto en un elemento.
+        ## Cor do texto em um elemento.
         widget_text = "#c8ffff",
 
-        ## The color of the text in a selected widget. (For
-        ## example, the current value of a preference.)
-        ## - Color del texto en un elemento seleccionado (por ejemplo,
-        ##   el valor actual de una preferencia).
+        ## Cor do texto em um elemento selecionado (por exemplo,
+        ## o valor atual de uma preferência).
         widget_selected = "#ffffc8",
 
-        ## The color of a disabled widget face.
-        ## - Color de un elemento deshabilitado.
+        ## Cor de um elemento desabilitado.
         disabled = "#404040",
 
-        ## The color of disabled widget text.
-        ## - Color del texto de un elemento deshabilitado.
+        ## Cor do texto de um elemento desabilitado.
         disabled_text = "#c8c8c8",
 
-        ## The color of informational labels.
-        ## - Color de las etiquetas de información.
+        ## Cor das etiquetas de informação.
         label = "#ffffff",
 
-        ## The color of a frame containing widgets.
-        ## - Color del marco que contiene los elementos.
+        ## Cor do quadro ('Frame') que contém os elementos.
         frame = "#6496c8",
 
-        ## If this is True, the in-game window is rounded. If False,
-        ## the in-game window is square.
-        ## - Si es 'True', la ventana interna del juego tendrà las
-        ##   esquinas redondeadas. Si es 'False', serà rectangular.
+        ## Se esta variável estiver designada como 'True', a janela interna do jogo terá os
+        ## cantos arredondados. Se for 'False', será retângular.
         rounded_window = False,
 
-        ## The background of the main menu. This can be a color
-        ## beginning with '#', or an image filename. The latter
-        ## should take up the full height and width of the screen.
-        ## - Fondo del menú principal. Puede ser un color que
-        ##   comience con '#' o bien el nombre de un archivo de imagen.
-        ##   En ese caso, debe ocupar el ancho y alto de la pantalla.
+        ## Fundo do menu principal. Pode ser uma cor que
+        ## começa com '#' ou também pode ser o nome de um arquivo de imagem.
+        ## No segundo caso, deve ocupar completamente o comprimento e altura da tela. 
         mm_root = "#dcebff",
 
-        ## The background of the game menu. This can be a color
-        ## beginning with '#', or an image filename. The latter
-        ## should take up the full height and width of the screen.
-        ## - Fondo del menú del juego. Puede ser un color que
-        ##   comience con '#' o bien el nombre de un archivo de imagen.
-        ##   En ese caso, debe ocupar el ancho y alto de la pantalla.
+        ## Fundo do menu do jogo. Pode ser uma cor que
+        ## começa com '#' ou também pode ser o nome de um arquivo de imagem.
+        ## No segundo caso, deve ocupar completamente o comprimento e altura da tela.
         gm_root = "#dcebff",
 
-        ## And we're done with the theme. The theme will customize
-        ## various styles, so if we want to change them, we should
-        ## do so below.
-        ## - Hemos terminado con el tema. El tema personalizará varios
-        ##   estilos, que pueden ser cambiados más abajo.
+        ## Acabamos com esse tema. O tema personalizará vários
+        ## estilos, que podem ser modificados mais abaixo. 
         )
 
-
     #########################################
-    ## These settings let you customize the window containing the
-    ## dialogue and narration, by replacing it with an image.
-    ## - Estos ajustes permiten personalizar la ventana que contiene
-    ##   el diálogo y la narración, reemplazándola con una imagen.
-
-    ## The background of the window. In a Frame, the two numbers
-    ## are the size of the left/right and top/bottom borders,
-    ## respectively.
-    ## - Fondo de la ventana. Usando un marco ('Frame'), los dos números
-    ##   indican la dimensión de los bordes izquierdo/derecho y
-    ##   superior/inferior, respectivamente.
+    ## Estas configurações permitem personalizar a tela que contém 
+    ## o diálogo e a narração, substituindo-a com uma imagem.
+
+    ## Fundo da tela. Em um quadro ('Frame'), os dois números são
+    ## as dimensões das bordas esquerda/direita e 
+    ## superior/inferior, respectivamente.
 
     # style.window.background = Frame("frame.png", 12, 12)
 
-    ## Margin is space surrounding the window, where the background
-    ## is not drawn.
-    ## - El margen es el espacio alrededor de la ventana, en el cual el
-    ##   fondo no aparece.
+    ## A margem é o espaço ao redor da tela, cujo qual o
+    ## fundo não aparece.
 
     # style.window.left_margin = 6
     # style.window.right_margin = 6
     # style.window.top_margin = 6
     # style.window.bottom_margin = 6
 
-    ## Padding is space inside the window, where the background is
-    ## drawn.
-    ## - El 'relleno' ('padding') es el margen interior a la ventana,
-    ##   en el cual el fondo sí se dibuja, pero no el texto.
+    ## O 'preenchimento' ('padding') é o espaço dentro da janela, 
+    ## em que o o fundo é desenhado, mas não o texto.
 
     # style.window.left_padding = 6
     # style.window.right_padding = 6
     # style.window.top_padding = 6
     # style.window.bottom_padding = 6
 
-    ## This is the minimum height of the window, including the margins
-    ## and padding.
-    ## - Altura mínima de la ventana, incluyendo margen y 'relleno'.
+    ## Altura mínima da tela, incluíndo margem e preenchimento.
 
     # style.window.yminimum = 250
 
 
     #########################################
-    ## This lets you change the placement of the main menu.
-    ## - Esta sección permite cambiar la disposición del menú principal.
-
-    ## The way placement works is that we find an anchor point
-    ## inside a displayable, and a position (pos) point on the
-    ## screen. We then place the displayable so the two points are
-    ## at the same place.
-    ## - La colocación funciona de la siguiente manera: Primero se
-    ##   establece un punto de anclaje (anchor) dentro de un elemento
-    ##   gràfico (displayable), a continuación un punto de posición (pos)
-    ##   en la pantalla. Finalmente se coloca el elemento gràfico de forma
-    ##   que ambos puntos coincidan.
-
-    ## An anchor/pos can be given as an integer or a floating point
-    ## number. If an integer, the number is interpreted as a number
-    ## of pixels from the upper-left corner. If a floating point,
-    ## the number is interpreted as a fraction of the size of the
-    ## displayable or screen.
-    ## - Los puntos de anclaje y de posición (anchor/pos) pueden indicarse
-    ##   con un número entero o decimal. Un entero indica los píxeles desde
-    ##   la esquina superior izquierda. Un decimal, en cambio, se interpreta
-    ##   como fracción de las dimensiones del elemento gráfico o la
-    ##   pantalla.
+    ## Esta seção permite você alterar a disposição do menu principal.
+
+    ## O ajuste funciona da seguinte maneira: primeiro é
+    ## estabelecido um ponto de ancoragem (anchor) dentro de um elemento
+    ## gráfico (disponível) e a posição (pos) de um ponto na tela. 
+    ## Por fim, é colocado o elemento gráfico de forma 
+    ## que ambos os pontos coincidam.
+
+    ## Os pontos de ancoragem e de posição (anchor/pos) podem ser indicados 
+    ## com um número inteiro ou decimal (int/float). Se ele for inteiro, 
+    ## os pixels desde o canto superior esquerdo. Se ele for decimal, 
+    ## é interpretado como a fração das dimensões do elemento gráfico ou da
+    ## tela.
 
     # style.mm_menu_frame.xpos = 0.5
     # style.mm_menu_frame.xanchor = 0.5
@@ -202,205 +137,151 @@ init -1 python hide:
 
 
     #########################################
-    ## These let you customize the default font used for text in Ren'Py.
-    ## - Personalización del tipo de letra utilizado por defecto.
+    ## Personalização do tipo de letra utilizado por padrão.
 
-    ## The file containing the default font.
-    ## - Archivo del tipo de letra.
+    ## O arquivo que contém a fonte padrão.
 
     # style.default.font = "DejaVuSans.ttf"
 
-    ## The default size of text.
-    ## - Tamaño de letra por defecto.
+    ## O tamanho padrão da fonte.
 
     # style.default.size = 22
 
-    ## Note that these only change the size of some of the text. Other
-    ## buttons have their own styles.
-    ## - Nota: Solo cambia el tamaño de parte del texto. Otros botones
-    ##   tienen sus propios estilos.
+    ## Nota: Isso apenas muda o tamanho da fonte do texto. Outros botões 
+    ## têm seus próprios estilos.
 
 
     #########################################
-    ## These settings let you change some of the sounds that are used by
-    ## Ren'Py.
-    ## - Ajuste de algunos de los sonidos utilizados por Ren'Py.
+    ## Ajuste de alguns sons utilizados por Ren'Py.
 
-    ## Set this to False if the game does not have any sound effects.
-    ## - Ajustar a 'False' si el juego no tiene efectos de sonido.
+    ## Ajuste para falso ('False') acaso o jogo não tiver efeitos de som. 
 
     config.has_sound = True
 
-    ## Set this to False if the game does not have any music.
-    ## - Ajustar a 'False' si el juego no tiene música.
+    ## Ajuste para falso ('False') acaso o jogo não tiver música. 
 
     config.has_music = True
 
-    ## Set this to True if the game has voicing.
-    ## - Ajustar a 'True' si el juego contiene voces.
+    ## Ajuste para verdadeiro ('True') acaso o jogo conter vozes. 
 
     config.has_voice = False
 
-    ## Sounds that are used when button and imagemaps are clicked.
-    ## - Sonidos utilizados cuando se hace clic en un botón.
+    ## Sons utilizados quando se clica em um botão.
 
     # style.button.activate_sound = "click.wav"
     # style.imagemap.activate_sound = "click.wav"
 
-    ## Sounds that are used when entering and exiting the game menu.
-    ## - Sonidos utilizados cuando se entra o sale del menú del juego.
+    ## Sons utilizados quando se entra ou sai do menu do jogo.
 
     # config.enter_sound = "click.wav"
     # config.exit_sound = "click.wav"
 
-    ## A sample sound that can be played to check the sound volume.
-    ## - Sonido de ejemplo utilizado para comprobar el volumen.
+    ## Som de exemplo utilizado para checar o volume do som.
 
     # config.sample_sound = "click.wav"
 
-    ## Music that is played while the user is at the main menu.
-    ## - Música del menú principal.
+    ## Música do menu principal.
 
     # config.main_menu_music = "main_menu_theme.ogg"
 
 
     #########################################
-    ## Help.
-    ## - Ayuda.
-
-    ## This lets you configure the help option on the Ren'Py menus.
-    ## It may be:
-    ## - A label in the script, in which case that label is called to
-    ##   show help to the user.
-    ## - A file name relative to the base directory, which is opened in a
-    ##   web browser.
-    ## - None, to disable help.
-
-    ## - Configuración de la opción de ayuda de los menús de Ren'Py.
-    ##   Puede ser:
-    ##   - Una etiqueta (label) en el 'script', en cuyo caso se llama esa
-    ##     etiqueta para mostrar la ayuda al usuario.
-    ##   - El nombre de un archivo relativo al directorio base, que se abre
-    ##     en un navegador web.
-    ##   - 'None', para deshabilitar la ayuda (se debe eliminar el botón
-    ##     de ayuda en las pantallas 'screens').
+    ## Ajuda
+
+    ## Configuração das opções de ajuda dos menus de Ren'Py.
+    ## Pode ser:
+    ## - Uma etiqueta (label) no 'script', em cujo qual se chama essa
+    ##   etiqueta para mostrar a ajuda ao usuário.
+    ## - O nome de um arquivo relativo ao diretório base, que é aberto 
+    ##   em um navegador web.
+    ## - 'None', para desabilitar a ajuda (deve-se eliminar o botão
+    ##   de ajuda nas telas).
     config.help = "README.html"
 
 
     #########################################
-    ## Transitions.
-    ## - Transiciones.
+    ## Transições.
 
-    ## Used when entering the game menu from the game.
-    ## - Desde el juego al menú del juego.
+    ## Usada da abertura para o menu do jogo. 
     config.enter_transition = None
 
-    ## Used when exiting the game menu to the game.
-    ## - Desde el menú del juego al juego.
+    ## Usada quando saímos do menu do jogo para o jogo. 
     config.exit_transition = None
 
-    ## Used between screens of the game menu.
-    ## - Entre pantallas del menú del juego.
+    ## Usada entre as telas do menu do jogo.
     config.intra_transition = None
 
-    ## Used when entering the game menu from the main menu.
-    ## - Desde el menú principal al menú del juego.
+    ## Usada do menu principal para o menu do jogo.
     config.main_game_transition = None
 
-    ## Used when returning to the main menu from the game.
-    ## - Desde el juego al menú principal.
+    ## Usada para retornar para o menu principal do jogo. 
     config.game_main_transition = None
 
-    ## Used when entering the main menu from the splashscreen.
-    ## - Desde la pantalla splash al menú principal.
+    ## Usada quando entramos no menu principal pela tela de abertura
     config.end_splash_transition = None
 
-    ## Used when entering the main menu after the game has ended.
-    ## - Al menú principal cuando el juego ha terminado.
+    ## Usada quando entramos no menu principal após o jogo ser terminado. 
     config.end_game_transition = None
 
-    ## Used when a game is loaded.
-    ## - Cuando se carga una partida.
+    ## Usada quando o jogo é carregado.
     config.after_load_transition = None
 
-    ## Used when the window is shown.
-    ## - Cuando se muestra una ventana.
+    ## Usada quando se mostra uma janela.
     config.window_show_transition = None
 
-    ## Used when the window is hidden.
-    ## - Cuando se oculta una ventana.
+    ## Usada quando se oculta uma janela.
     config.window_hide_transition = None
 
-    ## Used when showing NVL-mode text directly after ADV-mode text.
-    ## - Cuando se usa texto en modo NVL inmediatamente después de
-    ##   texto en modo ADV.
+    ## Usada quando se usa texto no modo NVL imediatamente depois do 
+    ## texto em modo ADV.
     config.adv_nvl_transition = dissolve
 
-    ## Used when showing ADV-mode text directly after NVL-mode text.
-    ## - Cuando se usa texto en modo ADV inmediatamente después de
-    ##   texto en modo NVL.
+    ## Usada quando se usa texto no modo ADV imediatamente depois do 
+    ## texto em modo NVL.
     config.nvl_adv_transition = dissolve
 
-    ## Used when yesno is shown.
-    ## - Cuando se muestra la pantalla Sí/No
+    ## Usada quando se mostra a tela Sim/Não ('Yes/No')
     config.enter_yesno_transition = None
 
-    ## Used when the yesno is hidden.
-    ## - Cuando se oculta la pantalla Sí/No
+    ## Usada quando se oculta a tela Sim/Não ('Yes/No')
     config.exit_yesno_transition = None
 
-    ## Used when entering a replay.
-    ## - Cuando se entra a una repetición.
+    ## Usada quando se entra em uma repetição ('Replay')
     config.enter_replay_transition = None
 
-    ## Used when exiting a replay.
-    ## - Cuando se sale de una repetición.
+    ## Usada ao sair de uma repetição ('Replay')
     config.exit_replay_transition = None
 
-    ## Used when the image is changed by a say statement with image attributes.
-    ## - Cuando la imagen cambia por una sentencia 'say' con atributos de
-    ##   imagen.
+    ## Usada quando a imagem é substituída por uma sentença 'say' com
+    ## atributos de imagem.
     config.say_attribute_transition = None
 
     #########################################
-    ## This is the name of the directory where the game's data is
-    ## stored. (It needs to be set early, before any other init code
-    ## is run, so the persistent information can be found by the init code.)
-    ## - Nombre del directorio en el cual se almacenan los datos del juego.
-    ##   (Debe ajustarse al inicio, antes de los otros bloques 'init', para
-    ##   que la información persistente pueda ser encontrada por el código
-    ##   'init'.)
+    ## Nome do diretório no qual estão armazenados os dados do jogo.
+    ## (Deve ser ajustado no início, antes dos outros blocos 'init', para
+    ## que a informação salva possa ser encontrada pelo código 'init'.)
 python early:
     config.save_directory = "PROJECT_NAME-UNIQUE"
 
 init -1 python hide:
     #########################################
-    ## Default values of Preferences.
-    ## - Valores por defecto de las Opciones
+    ## Valores padrão das opções. 
 
-    ## Note: These options are only evaluated the first time a
-    ## game is run. To have them run a second time, delete
-    ## game/saves/persistent
-    ## - Nota: Estas opciones tan solo son evaluadas la primera vez que
-    ##   se ejecuta un juego. Para que sean evaluadas una segunda vez,
-    ##   bórrese games/saves/persistent
+    ## Nota: Estas opções são somente consideradas na primeira vez que
+    ## um jogo é executado. Para que sejam carregadas uma segunda vez, 
+    ## por favor deletar 'game/saves/persistent'.
 
-    ## Should we start in fullscreen mode?
-    ## - Ajusta a 'True' para comenzar en pantalla completa
+    ## Ajuste para verdadeiro ('True') para iniciar com a tela cheia (fullscreen).
 
     config.default_fullscreen = False
 
-    ## The default text speed in characters per second. 0 is infinite.
-    ## - Velocidad del texto por defecto en caracteres por segundo.
-    ##   0 es infinito.
+    ## Velocidade do texto padrão em caracteres por segundo. 0 é infinito. 
 
     config.default_text_cps = 0
 
-    ## The default auto-forward time setting.
-    ## - El ajuste de auto-avance por defecto.
+    ## O ajuste de auto-avanço por padrão. 
 
     config.default_afm_time = 10
 
     #########################################
-    ## More customizations can go here.
-    ## - Más personalizaciones pueden ir aquí.
+    ## Mais customizações podem vir aqui.
diff --git a/the_question/game/screens.rpy b/the_question/game/screens.rpy
index 005fa5d..3eb1d08 100644
--- a/the_question/game/screens.rpy
+++ b/the_question/game/screens.rpy
@@ -436,6 +436,7 @@ screen game_menu(title, scroll=None):
                         scrollbars "vertical"
                         mousewheel True
                         draggable True
+                        pagekeys True
 
                         side_yfill True
 
@@ -451,6 +452,7 @@ screen game_menu(title, scroll=None):
                         scrollbars "vertical"
                         mousewheel True
                         draggable True
+                        pagekeys True
 
                         side_yfill True
 
diff --git a/the_question/game/tl/russian/common.rpy b/the_question/game/tl/russian/common.rpy
index f9996d3..b68142a 100644
--- a/the_question/game/tl/russian/common.rpy
+++ b/the_question/game/tl/russian/common.rpy
@@ -157,171 +157,83 @@ translate russian strings:
     old "%b %d, %H:%M"
     new "%d %b, %H:%M"
 
-    # 00action_file.rpy:825
+    # 00action_file.rpy:820
     old "Quick save complete."
     new "Быстрое сохранение завершено."
 
-    # 00director.rpy:693
-    old "The interactive director is not enabled here."
-    new "Интерактивный директор недоступен."
-
-    # 00director.rpy:1480
-    old "Done"
-    new "Принять"
-
-    # 00director.rpy:1488
-    old "(statement)"
-    new "(функция)"
-
-    # 00director.rpy:1489
-    old "(tag)"
-    new "(тег)"
-
-    # 00director.rpy:1490
-    old "(attributes)"
-    new "(аттрибут)"
-
-    # 00director.rpy:1491
-    old "(transform)"
-    new "(трансформация)"
-
-    # 00director.rpy:1516
-    old "(transition)"
-    new "(переход)"
-
-    # 00director.rpy:1528
-    old "(channel)"
-    new "(канал)"
-
-    # 00director.rpy:1529
-    old "(filename)"
-    new "(имя файла)"
-
-    # 00director.rpy:1554
-    old "Change"
-    new "Изменить"
-
-    # 00director.rpy:1556
-    old "Add"
-    new "Добавить"
-
-    # 00director.rpy:1559
-    old "Cancel"
-    new "Отмена"
-
-    # 00director.rpy:1562
-    old "Remove"
-    new "Убрать"
-
-    # 00director.rpy:1595
-    old "Statement:"
-    new "Функции:"
-
-    # 00director.rpy:1616
-    old "Tag:"
-    new "Теги:"
-
-    # 00director.rpy:1632
-    old "Attributes:"
-    new "Аттрибут:"
-
-    # 00director.rpy:1650
-    old "Transforms:"
-    new "Трансформации:"
-
-    # 00director.rpy:1669
-    old "Behind:"
-    new "Позади:"
-
-    # 00director.rpy:1688
-    old "Transition:"
-    new "Переходы:"
-
-    # 00director.rpy:1706
-    old "Channel:"
-    new "Каналы:"
-
-    # 00director.rpy:1724
-    old "Audio Filename:"
-    new "Имя файла:"
-
-    # 00gui.rpy:240
+    # 00gui.rpy:234
     old "Are you sure?"
     new "Вы уверены?"
 
-    # 00gui.rpy:241
+    # 00gui.rpy:235
     old "Are you sure you want to delete this save?"
     new "Вы уверены, что хотите удалить это сохранение?"
 
-    # 00gui.rpy:242
+    # 00gui.rpy:236
     old "Are you sure you want to overwrite your save?"
     new "Вы уверены, что хотите перезаписать ваше сохранение?"
 
-    # 00gui.rpy:243
+    # 00gui.rpy:237
     old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
     new "Загрузка игры приведёт к потере несохранённого прогресса.\nВы уверены, что хотите это сделать?"
 
-    # 00gui.rpy:244
+    # 00gui.rpy:238
     old "Are you sure you want to quit?"
     new "Вы уверены, что хотите выйти?"
 
-    # 00gui.rpy:245
+    # 00gui.rpy:239
     old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
     new "Вы уверены, что хотите вернуться в главное меню?\nЭто приведёт к потере несохранённого прогресса."
 
-    # 00gui.rpy:246
+    # 00gui.rpy:240
     old "Are you sure you want to end the replay?"
     new "Вы уверены, что хотите завершить повтор?"
 
-    # 00gui.rpy:247
+    # 00gui.rpy:241
     old "Are you sure you want to begin skipping?"
     new "Вы уверены, что хотите начать пропуск?"
 
-    # 00gui.rpy:248
+    # 00gui.rpy:242
     old "Are you sure you want to skip to the next choice?"
     new "Вы точно хотите пропустить всё до следующего выбора?"
 
-    # 00gui.rpy:249
+    # 00gui.rpy:243
     old "Are you sure you want to skip unseen dialogue to the next choice?"
     new "Вы уверены, что хотите пропустить непрочитанные диалоги до следующего выбора?"
 
-    # 00keymap.rpy:254
-    old "Failed to save screenshot as %s."
-    new "Провалена попытка сохранить скриншот как %s."
-
-    # 00keymap.rpy:266
+    # 00keymap.rpy:259
     old "Saved screenshot as %s."
     new "Скриншот сохранён как %s."
 
-    # 00library.rpy:146
+    # 00library.rpy:142
     old "Self-voicing disabled."
     new "Синтезатор речи отключён."
 
-    # 00library.rpy:147
+    # 00library.rpy:143
     old "Clipboard voicing enabled. "
-    new "Озвучка буфера обмена включена. "
+    new "Озвучка буфера обмена включена."
 
-    # 00library.rpy:148
+    # 00library.rpy:144
     old "Self-voicing enabled. "
-    new "Синтезатор речи включён. "
+    new "Синтезатор речи включён."
 
-    # 00library.rpy:183
+    # 00library.rpy:179
     old "Skip Mode"
     new "Режим Пропуска"
 
-    # 00library.rpy:266
+    # 00library.rpy:262
     old "This program contains free software under a number of licenses, including the MIT License and GNU Lesser General Public License. A complete list of software, including links to full source code, can be found {a=https://www.renpy.org/l/license}here{/a}."
     new "Эта программа содержит свободное и открытое программное обеспечение под несколькими лицензиями, включая лицензию MIT и GNU Lesser General Public. Полный список лицензий, включая ссылки на полный исходный код, можно найти {a=https://www.renpy.org/l/license}здесь{/a}."
 
-    # 00preferences.rpy:442
+    # 00preferences.rpy:429
     old "Clipboard voicing enabled. Press 'shift+C' to disable."
     new "Озвучка буфера обмена включена. Нажмите 'shift+C', чтобы отключить её."
 
-    # 00preferences.rpy:444
+    # 00preferences.rpy:431
     old "Self-voicing would say \"[renpy.display.tts.last]\". Press 'alt+shift+V' to disable."
     new "Синтезатор речи должен сказать \"[renpy.display.tts.last]\". Нажмите 'alt+shift+V', чтобы отключить его."
 
-    # 00preferences.rpy:446
+    # 00preferences.rpy:433
     old "Self-voicing enabled. Press 'v' to disable."
     new "Синтезатор речи включён. Нажмите 'v', чтобы отключить его."
 
@@ -363,83 +275,87 @@ translate russian strings:
 
     # 00updater.rpy:1055
     old "While unpacking {}, unknown type {}."
-    new "При распаковке {}, обнаружен неизвестный тип {}."
+    new "При распаковке {} обнаружен неизвестный тип {}."
 
-    # 00updater.rpy:1402
+    # 00updater.rpy:1399
     old "Updater"
     new "Обновление"
 
-    # 00updater.rpy:1409
+    # 00updater.rpy:1406
     old "An error has occured:"
     new "Возникла ошибка:"
 
-    # 00updater.rpy:1411
+    # 00updater.rpy:1408
     old "Checking for updates."
     new "Проверка обновлений."
 
-    # 00updater.rpy:1413
+    # 00updater.rpy:1410
     old "This program is up to date."
     new "Эта программа обновлена."
 
-    # 00updater.rpy:1415
+    # 00updater.rpy:1412
     old "[u.version] is available. Do you want to install it?"
     new "[u.version] доступна. Вы хотите её установить?"
 
-    # 00updater.rpy:1417
+    # 00updater.rpy:1414
     old "Preparing to download the updates."
     new "Подготовка к загрузке обновлений."
 
-    # 00updater.rpy:1419
+    # 00updater.rpy:1416
     old "Downloading the updates."
     new "Загрузка обновлений."
 
-    # 00updater.rpy:1421
+    # 00updater.rpy:1418
     old "Unpacking the updates."
     new "Распаковка обновлений."
 
-    # 00updater.rpy:1423
+    # 00updater.rpy:1420
     old "Finishing up."
     new "Завершаю..."
 
-    # 00updater.rpy:1425
+    # 00updater.rpy:1422
     old "The updates have been installed. The program will restart."
     new "Обновления установлены. Программа будет перезапущена."
 
-    # 00updater.rpy:1427
+    # 00updater.rpy:1424
     old "The updates have been installed."
     new "Обновления были установлены."
 
-    # 00updater.rpy:1429
+    # 00updater.rpy:1426
     old "The updates were cancelled."
     new "Обновления были отменены."
 
-    # 00updater.rpy:1444
+    # 00updater.rpy:1441
     old "Proceed"
     new "Продолжить"
 
-    # 00gallery.rpy:573
+    # 00updater.rpy:1444
+    old "Cancel"
+    new "Отмена"
+
+    # 00gallery.rpy:563
     old "Image [index] of [count] locked."
     new "Изображение [index] из [count] закрыто."
 
-    # 00gallery.rpy:593
+    # 00gallery.rpy:583
     old "prev"
     new "пред"
 
-    # 00gallery.rpy:594
+    # 00gallery.rpy:584
     old "next"
     new "след"
 
-    # 00gallery.rpy:595
+    # 00gallery.rpy:585
     old "slideshow"
     new "слайд-шоу"
 
-    # 00gallery.rpy:596
+    # 00gallery.rpy:586
     old "return"
     new "вернуться"
 
     # 00gltest.rpy:64
     old "Graphics Acceleration"
-    new "Графическое Ускорение"
+    new "Graphics Acceleration"
 
     # 00gltest.rpy:70
     old "Automatically Choose"
@@ -447,85 +363,81 @@ translate russian strings:
 
     # 00gltest.rpy:75
     old "Force Angle/DirectX Renderer"
-    new "Насильно Отображать Через Angle/DirectX"
+    new "Принудительный Angle/DirectX"
 
     # 00gltest.rpy:79
     old "Force OpenGL Renderer"
-    new "Насильно Отображать Через OpenGL"
+    new "Принудительный OpenGL"
 
     # 00gltest.rpy:83
     old "Force Software Renderer"
-    new "Насильно Отображать Программно"
-
-    # 00gltest.rpy:89
-    old "NPOT"
-    new "NPOT (OpenGL 2+)"
+    new "Принудительный Программный"
 
     # 00gltest.rpy:93
     old "Enable"
-    new "Активировать"
+    new "Активировано"
 
-    # 00gltest.rpy:124
+    # 00gltest.rpy:109
     old "Changes will take effect the next time this program is run."
     new "Изменения вступят в силу при следующем запуске программы."
 
-    # 00gltest.rpy:156
+    # 00gltest.rpy:141
     old "Performance Warning"
     new "Предупреждение Производительности"
 
-    # 00gltest.rpy:161
+    # 00gltest.rpy:146
     old "This computer is using software rendering."
     new "Этот компьютер использует программный рендеринг."
 
-    # 00gltest.rpy:163
+    # 00gltest.rpy:148
     old "This computer is not using shaders."
     new "Этот компьютер не использует шейдеры."
 
-    # 00gltest.rpy:165
+    # 00gltest.rpy:150
     old "This computer is displaying graphics slowly."
     new "Этот компьютер медленно отображает графику."
 
-    # 00gltest.rpy:167
+    # 00gltest.rpy:152
     old "This computer has a problem displaying graphics: [problem]."
     new "У этого компьютера проблема с отображением графики: [problem]"
 
-    # 00gltest.rpy:172
+    # 00gltest.rpy:157
     old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
     new "Графические драйвера устарели или работают неверно. Это может привести к медленному или неверному отображению графики. Обновление DirectX может решить эту проблему."
 
-    # 00gltest.rpy:174
+    # 00gltest.rpy:159
     old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
     new "Графические драйвера устарели или работают неверно. Это может привести к медленному или неверному отображению графики."
 
-    # 00gltest.rpy:179
+    # 00gltest.rpy:164
     old "Update DirectX"
     new "Обновить DirectX"
 
-    # 00gltest.rpy:185
+    # 00gltest.rpy:170
     old "Continue, Show this warning again"
     new "Продолжить, Показать это предупреждение снова"
 
-    # 00gltest.rpy:189
+    # 00gltest.rpy:174
     old "Continue, Don't show warning again"
     new "Продолжить, Не показывать это предупреждение снова."
 
-    # 00gltest.rpy:207
+    # 00gltest.rpy:192
     old "Updating DirectX."
     new "Обновляю DirectX."
 
-    # 00gltest.rpy:211
+    # 00gltest.rpy:196
     old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
     new "Установщик DirectX был запущен. Возможно, что он запустился в свёрнутом состоянии. Пожалуйста, следуйте инструкциям для установки DirectX."
 
-    # 00gltest.rpy:215
+    # 00gltest.rpy:200
     old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
     new "{b}Предупреждение:{/b} Установщик DirectX по умолчанию пытается установить панель инструментов Bing. Если вы этого не хотите, снимите соответствующую галочку."
 
-    # 00gltest.rpy:219
+    # 00gltest.rpy:204
     old "When setup finishes, please click below to restart this program."
     new "По завершению установки, щёлкните, чтобы перезапустить программу."
 
-    # 00gltest.rpy:221
+    # 00gltest.rpy:206
     old "Restart"
     new "Перезапустить"
 
@@ -553,75 +465,618 @@ translate russian strings:
     old "Back (B)"
     new "Back (B)"
 
-    # _errorhandling.rpym:523
+    # _errorhandling.rpym:519
     old "Open"
     new "Журнал"
 
-    # _errorhandling.rpym:525
+    # _errorhandling.rpym:521
     old "Opens the traceback.txt file in a text editor."
     new "Открывает файл traceback.txt в текстовом редакторе."
 
-    # _errorhandling.rpym:527
+    # _errorhandling.rpym:523
     old "Copy"
     new "Копировать"
 
-    # _errorhandling.rpym:529
+    # _errorhandling.rpym:525
     old "Copies the traceback.txt file to the clipboard."
     new "Копирует файл traceback.txt в буфер обмена."
 
-    # _errorhandling.rpym:556
+    # _errorhandling.rpym:543
     old "An exception has occurred."
     new "Возникло исключение."
 
-    # _errorhandling.rpym:576
+    # _errorhandling.rpym:562
     old "Rollback"
     new "Назад"
 
-    # _errorhandling.rpym:578
+    # _errorhandling.rpym:564
     old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
     new "Пытается вернуться назад, позволяя вам сохраниться или принять другой выбор."
 
-    # _errorhandling.rpym:581
+    # _errorhandling.rpym:567
     old "Ignore"
     new "Игнорировать"
 
-    # _errorhandling.rpym:585
-    old "Ignores the exception, allowing you to continue."
-    new "Игнорирует это исключение, позволяя вам продолжить."
-
-    # _errorhandling.rpym:587
+    # _errorhandling.rpym:569
     old "Ignores the exception, allowing you to continue. This often leads to additional errors."
     new "Игнорирует это исключение, позволяя вам продолжить. Зачастую это ведёт к дополнительным ошибкам."
 
-    # _errorhandling.rpym:591
+    # _errorhandling.rpym:572
     old "Reload"
     new "Перезагрузить"
 
-    # _errorhandling.rpym:593
+    # _errorhandling.rpym:574
     old "Reloads the game from disk, saving and restoring game state if possible."
     new "Перезагружает игру с диска, сохраняя и восстанавливая её состояние, если это возможно."
 
-    # _errorhandling.rpym:596
+    # _errorhandling.rpym:576
     old "Console"
     new "Консоль"
 
-    # _errorhandling.rpym:598
+    # _errorhandling.rpym:578
     old "Opens a console to allow debugging the problem."
     new "Открывает консоль, позволяющую отладить проблему."
 
-    # _errorhandling.rpym:608
+    # _errorhandling.rpym:590
     old "Quits the game."
     new "Выходит из игры."
 
-    # _errorhandling.rpym:632
+    # _errorhandling.rpym:614
     old "Parsing the script failed."
     new "Обработка сценария завершилась неудачно."
 
-    # _errorhandling.rpym:658
+    # _errorhandling.rpym:640
     old "Opens the errors.txt file in a text editor."
     new "Открывает файл errors.txt в текстовом редакторе."
 
-    # _errorhandling.rpym:662
+    # _errorhandling.rpym:644
     old "Copies the errors.txt file to the clipboard."
     new "Копирует файл errors.txt в буфер обмена."
 
+    # _developer/developer.rpym:38
+    old "Developer Menu"
+    new "Меню разработчика"
+
+    # _developer/developer.rpym:43
+    old "Reload Game (Shift+R)"
+    new "Перезагрузить игру (Shift+R)"
+
+    # _developer/developer.rpym:45
+    old "Console (Shift+O)"
+    new "Консоль (Shift+O)"
+
+    # _developer/developer.rpym:47
+    old "Variable Viewer"
+    new "Просмотр переменных"
+
+    # _developer/developer.rpym:49
+    old "Theme Test"
+    new "Theme Test"
+
+    # _developer/developer.rpym:51
+    old "Image Location Picker"
+    new "Инструмент позиционирования на изображениях"
+
+    # _developer/developer.rpym:53
+    old "Filename List"
+    new "Список файлов"
+
+    # _developer/developer.rpym:57
+    old "Show Image Load Log"
+    new "Show Image Load Log"
+
+    # _developer/developer.rpym:60
+    old "Hide Image Load Log"
+    new "Hide Image Load Log"
+
+    # _developer/developer.rpym:95
+    old "Nothing to inspect."
+    new "Переменные не заданы."
+
+    # _developer/developer.rpym:217
+    old "Return to the developer menu"
+    new "Вернуться в меню разработчика"
+
+    # _developer/developer.rpym:377
+    old "Rectangle: %r"
+    new "Прямоугольник: %r"
+
+    # _developer/developer.rpym:382
+    old "Mouse position: %r"
+    new "Позиция мыши: %r"
+
+    # _developer/developer.rpym:387
+    old "Right-click or escape to quit."
+    new "Нажмите правую кнопку мыши или ESC чтобы выйти."
+
+    # _developer/developer.rpym:419
+    old "Rectangle copied to clipboard."
+    new "Координаты прямоугольника скопированы в буфер обмена."
+
+    # _developer/developer.rpym:422
+    old "Position copied to clipboard."
+    new "Координаты позиции скопированы в буфер обмена."
+
+    # _developer/developer.rpym:531
+    old "✔ "
+    new "✔ "
+
+    # _developer/developer.rpym:534
+    old "✘ "
+    new "✘ "
+
+    # _developer/developer.rpym:539
+    old "\n{color=#cfc}✔ predicted image (good){/color}\n{color=#fcc}✘ unpredicted image (bad){/color}\n{color=#fff}Drag to move.{/color}"
+    new "\n{color=#cfc}✔ предсказанное изображение (хорошо){/color}\n{color=#fcc}✘ внезапное изображение (плохо){/color}\n{color=#fff}Нажмите, чтобы передвинуть.{/color}"
+
+    # _developer/inspector.rpym:38
+    old "Displayable Inspector"
+    new "Диспетчер объектов"
+
+    # _developer/inspector.rpym:61
+    old "Size"
+    new "Разрешение"
+
+    # _developer/inspector.rpym:65
+    old "Style"
+    new "Стиль"
+
+    # _developer/inspector.rpym:71
+    old "Location"
+    new "Местоположение"
+
+    # _developer/inspector.rpym:122
+    old "Inspecting Styles of [displayable_name!q]"
+    new "Инспектирую стили [displayable_name!q]"
+
+    # _developer/inspector.rpym:139
+    old "displayable:"
+    new "объект:"
+
+    # _developer/inspector.rpym:145
+    old "        (no properties affect the displayable)"
+    new "        (на объект не влияют никакие параметры)"
+
+    # _developer/inspector.rpym:147
+    old "        (default properties omitted)"
+    new "        (настройки по умолчанию опущены)"
+
+    # _developer/inspector.rpym:185
+    old "<repr() failed>"
+    new "<repr() провален>"
+
+    # 00console.rpy:208
+    old "Press <esc> to exit console. Type help for help.\n"
+    new "Нажмите <esc>, чтобы выйти из консоли. Введите help для помощи.\n"
+
+    # 00console.rpy:212
+    old "Ren'Py script enabled."
+    new "Ren'Py script активирован."
+
+    # 00console.rpy:214
+    old "Ren'Py script disabled."
+    new "Ren'Py script деактивирован."
+
+    # 00console.rpy:424
+    old "help: show this help"
+    new "help: показывает помощь"
+
+    # 00console.rpy:429
+    old "commands:\n"
+    new "команды:\n"
+
+    # 00console.rpy:439
+    old " <renpy script statement>: run the statement\n"
+    new " <оператор renpy script>: запуск оператора\n"
+
+    # 00console.rpy:441
+    old " <python expression or statement>: run the expression or statement"
+    new " <выражение или оператор python>: запустить выражение или оператор"
+
+    # 00console.rpy:449
+    old "clear: clear the console history"
+    new "clear: очищает историю консоли"
+
+    # 00console.rpy:453
+    old "exit: exit the console"
+    new "exit: выход из консоли"
+
+    # 00console.rpy:461
+    old "load <slot>: loads the game from slot"
+    new "load <слот>: загружает игру из выбранного слота"
+
+    # 00console.rpy:474
+    old "save <slot>: saves the game in slot"
+    new "save <слот>: сохраняет игру в выбранный слот"
+
+    # 00console.rpy:485
+    old "reload: reloads the game, refreshing the scripts"
+    new "reload: перезагружает игру, обновляет скрипты"
+
+    # 00console.rpy:493
+    old "watch <expression>: watch a python expression"
+    new "watch <выражение>: наблюдать за выражением python"
+
+    # 00console.rpy:519
+    old "unwatch <expression>: stop watching an expression"
+    new "unwatch <выражение>: прекратить наблюдать за выражением"
+
+    # 00console.rpy:550
+    old "unwatchall: stop watching all expressions"
+    new "unwatchall: глобальное прекращение наблюдения"
+
+    # 00console.rpy:567
+    old "jump <label>: jumps to label"
+    new "jump <label>: прыжок на метку"
+
+
+translate None strings:
+
+    # 00action_file.rpy:344
+    old "Save slot %s: [text]"
+    new "Слот сохранения %s: [text]"
+
+    # 00action_file.rpy:417
+    old "Load slot %s: [text]"
+    new "Слот загрузки %s: [text]"
+
+    # 00action_file.rpy:459
+    old "Delete slot [text]"
+    new "Удалить слот [text]"
+
+    # 00action_file.rpy:539
+    old "File page auto"
+    new "Автосохранения"
+
+    # 00action_file.rpy:541
+    old "File page quick"
+    new "Быстрые сохранения"
+
+    # 00action_file.rpy:543
+    old "File page [text]"
+    new "Страница сохранений [text]"
+
+    # 00action_file.rpy:733
+    old "Next file page."
+    new "Следующая страница сохранений"
+
+    # 00action_file.rpy:797
+    old "Previous file page."
+    new "Предыдущая страница сохранений"
+
+    # 00action_file.rpy:876
+    old "Quick save."
+    new "Быстрое сохранение"
+
+    # 00action_file.rpy:895
+    old "Quick load."
+    new "Быстрая загрузка"
+
+    # 00action_other.rpy:344
+    old "Language [text]"
+    new "Язык [text]"
+
+    # 00director.rpy:703
+    old "The interactive director is not enabled here."
+    new "Интерактивный директор недоступен."
+
+    # 00director.rpy:1490
+    old "Done"
+    new "Принять"
+
+    # 00director.rpy:1498
+    old "(statement)"
+    new "(функция)"
+
+    # 00director.rpy:1499
+    old "(tag)"
+    new "(тег)"
+
+    # 00director.rpy:1500
+    old "(attributes)"
+    new "(аттрибут)"
+
+    # 00director.rpy:1501
+    old "(transform)"
+    new "(трансформация)"
+
+    # 00director.rpy:1526
+    old "(transition)"
+    new "(переход)"
+
+    # 00director.rpy:1538
+    old "(channel)"
+    new "(канал)"
+
+    # 00director.rpy:1539
+    old "(filename)"
+    new "(имя файла)"
+
+    # 00director.rpy:1564
+    old "Change"
+    new "Изменить"
+
+    # 00director.rpy:1566
+    old "Add"
+    new "Добавить"
+
+    # 00director.rpy:1572
+    old "Remove"
+    new "Убрать"
+
+    # 00director.rpy:1605
+    old "Statement:"
+    new "Функции:"
+
+    # 00director.rpy:1626
+    old "Tag:"
+    new "Теги:"
+
+    # 00director.rpy:1642
+    old "Attributes:"
+    new "Аттрибут:"
+
+    # 00director.rpy:1660
+    old "Transforms:"
+    new "Трансформации:"
+
+    # 00director.rpy:1679
+    old "Behind:"
+    new "Позади:"
+
+    # 00director.rpy:1698
+    old "Transition:"
+    new "Переходы:"
+
+    # 00director.rpy:1716
+    old "Channel:"
+    new "Каналы:"
+
+    # 00director.rpy:1734
+    old "Audio Filename:"
+    new "Имя файла:"
+
+    # 00keymap.rpy:258
+    old "Failed to save screenshot as %s."
+    new "Провалена попытка сохранить скриншот как %s."
+
+    # 00library.rpy:150
+    old "bar"
+    new ". Полоса настройки"
+
+    # 00library.rpy:151
+    old "selected"
+    new ". На данный момент это выбрано"
+
+    # 00library.rpy:152
+    old "viewport"
+    new "порт просмотра"
+
+    # 00library.rpy:153
+    old "horizontal scroll"
+    new ". горизонтальная полоса прокрутки"
+
+    # 00library.rpy:154
+    old "vertical scroll"
+    new ". вертикальная полоса прокрутки"
+
+    # 00library.rpy:155
+    old "activate"
+    new "элемент активирован"
+
+    # 00library.rpy:156
+    old "deactivate"
+    new "элемент деактивирован"
+
+    # 00library.rpy:157
+    old "increase"
+    new "больше"
+
+    # 00library.rpy:158
+    old "decrease"
+    new "меньше"
+
+    # 00preferences.rpy:207
+    old "display"
+    new "режим экрана"
+
+    # 00preferences.rpy:219
+    old "transitions"
+    new "переходы"
+
+    # 00preferences.rpy:228
+    old "skip transitions"
+    new "пропускать переходы"
+
+    # 00preferences.rpy:230
+    old "video sprites"
+    new "видео-спрайты"
+
+    # 00preferences.rpy:239
+    old "show empty window"
+    new "показывать пустое окно диалога"
+
+    # 00preferences.rpy:248
+    old "text speed"
+    new "скорость текста"
+
+    # 00preferences.rpy:256
+    old "joystick"
+    new "джойстик"
+
+    # 00preferences.rpy:256
+    old "joystick..."
+    new "джойстик..."
+
+    # 00preferences.rpy:263
+    old "skip"
+    new "пропускать"
+
+    # 00preferences.rpy:266
+    old "skip unseen [text]"
+    new "пропускать весь [text]"
+
+    # 00preferences.rpy:271
+    old "skip unseen text"
+    new "пропускать весь текст"
+
+    # 00preferences.rpy:273
+    old "begin skipping"
+    new "начать пропуск"
+
+    # 00preferences.rpy:277
+    old "after choices"
+    new "после выборов"
+
+    # 00preferences.rpy:284
+    old "skip after choices"
+    new "пропускать после выборов"
+
+    # 00preferences.rpy:286
+    old "auto-forward time"
+    new "скорость авточтения"
+
+    # 00preferences.rpy:300
+    old "auto-forward"
+    new "авточтение"
+
+    # 00preferences.rpy:307
+    old "Auto forward"
+    new "Авточтение"
+
+    # 00preferences.rpy:310
+    old "auto-forward after click"
+    new "продолжать авточтение после клика"
+
+    # 00preferences.rpy:319
+    old "automatic move"
+    new "автоматически передвигать мышь к кнопке"
+
+    # 00preferences.rpy:328
+    old "wait for voice"
+    new "ждать голос"
+
+    # 00preferences.rpy:337
+    old "voice sustain"
+    new "не останавливать голос"
+
+    # 00preferences.rpy:346
+    old "self voicing"
+    new "озвучка через синтезатор речи"
+
+    # 00preferences.rpy:355
+    old "clipboard voicing"
+    new "синтез речи из буфера обмена"
+
+    # 00preferences.rpy:364
+    old "debug voicing"
+    new "режим дебага синтеза речи"
+
+    # 00preferences.rpy:373
+    old "emphasize audio"
+    new "усилить громкость заранее заданных звуковых каналов за счёт приглушения остальных каналов"
+
+    # 00preferences.rpy:382
+    old "rollback side"
+    new "сторона отката"
+
+    # 00preferences.rpy:392
+    old "gl powersave"
+    new "настройка графики. Экономия энергии"
+
+    # 00preferences.rpy:398
+    old "gl framerate"
+    new "настройка графики. Частота кадров"
+
+    # 00preferences.rpy:401
+    old "gl tearing"
+    new "настройка графики. Разрывание кадров"
+
+    # 00preferences.rpy:413
+    old "music volume"
+    new "громкость музыки"
+
+    # 00preferences.rpy:414
+    old "sound volume"
+    new "громкость звуков"
+
+    # 00preferences.rpy:415
+    old "voice volume"
+    new "громкость голоса"
+
+    # 00preferences.rpy:416
+    old "mute music"
+    new "без музыки"
+
+    # 00preferences.rpy:417
+    old "mute sound"
+    new "без звуков"
+
+    # 00preferences.rpy:418
+    old "mute voice"
+    new "без голоса"
+
+    # 00preferences.rpy:419
+    old "mute all"
+    new "режим без звука"
+
+    # 00gltest.rpy:70
+    old "Renderer"
+    new "Рендер"
+
+    # 00gltest.rpy:93
+    old "NPOT"
+    new "NPOT (OpenGL 2+)"
+
+    # 00gltest.rpy:131
+    old "Powersave"
+    new "Экономия энергии"
+
+    # 00gltest.rpy:145
+    old "Framerate"
+    new "Частота кадров"
+
+    # 00gltest.rpy:149
+    old "Screen"
+    new "Экранная"
+
+    # 00gltest.rpy:153
+    old "60"
+    new "60"
+
+    # 00gltest.rpy:157
+    old "30"
+    new "30"
+
+    # 00gltest.rpy:163
+    old "Tearing"
+    new "Разрывание кадров"
+
+    # _errorhandling.rpym:590
+    old "Ignores the exception, allowing you to continue."
+    new "Игнорирует это исключение, позволяя вам продолжить."
+
+    # _developer/developer.rpym:43
+    old "Interactive Director (D)"
+    new "Интерактивный Директор (D)"
+
+    # _developer/developer.rpym:57
+    old "Show Image Load Log (F4)"
+    new "Показать лог загрузки изображений (F4)"
+
+    # _developer/developer.rpym:60
+    old "Hide Image Load Log (F4)"
+    new "Скрыть лог загрузки изображений (F4)"
+
+    # _developer/developer.rpym:447
+    old "Type to filter: "
+    new "Текущий фильтр: "
+
+    # _developer/developer.rpym:575
+    old "Textures: [tex_count] ([tex_size_mb:.1f] MB)"
+    new "Текстур: [tex_count] ([tex_size_mb:.1f] МБ)"
+
+    # _developer/developer.rpym:579
+    old "Image cache: [cache_pct:.1f]% ([cache_size_mb:.1f] MB)"
+    new "Кеш изображений: [cache_pct:.1f]% ([cache_size_mb:.1f] МБ)"
+
diff --git a/the_question/game/tl/russian/options.rpy b/the_question/game/tl/russian/options.rpy
index 2882468..dbc5be0 100644
--- a/the_question/game/tl/russian/options.rpy
+++ b/the_question/game/tl/russian/options.rpy
@@ -1,4 +1,5 @@
-translate russian strings:
+
+translate russian strings:
 
     # options.rpy:15
     old "The Question"
diff --git a/the_question/game/tl/russian/screens.rpy b/the_question/game/tl/russian/screens.rpy
index f5aa9c5..cb3945f 100644
--- a/the_question/game/tl/russian/screens.rpy
+++ b/the_question/game/tl/russian/screens.rpy
@@ -65,335 +65,339 @@ translate russian strings:
     old "Quit"
     new "Выход"
 
-    # screens.rpy:465
+    # screens.rpy:467
     old "Return"
     new "Вернуться"
 
-    # screens.rpy:549
+    # screens.rpy:551
     old "[config.version!t]\n"
     new "[config.version!t]\n"
 
-    # screens.rpy:593
+    # screens.rpy:555
     old "Updated Character Art"
     new "Новый дизайн персонажа"
 
-    # screens.rpy:554
+    # screens.rpy:556
     old "Deji"
     new "Deji"
 
-    # screens.rpy:558
+    # screens.rpy:560
     old "Original Character Art"
     new "Оригинал персонажа"
 
-    # screens.rpy:559
+    # screens.rpy:561
     old "Derik"
     new "Derik"
 
-    # screens.rpy:565
+    # screens.rpy:567
     old "Updated Background Art"
     new "Новые фоны"
 
-    # screens.rpy:566
+    # screens.rpy:568
     old "Mugenjohncel"
     new "Mugenjohncel"
 
-    # screens.rpy:570
+    # screens.rpy:572
     old "Original Background Art"
     new "Оригинальные фоны"
 
-    # screens.rpy:571
+    # screens.rpy:573
     old "DaFool"
     new "DaFool"
 
-    # screens.rpy:577
+    # screens.rpy:579
     old "Music By"
     new "Музыка"
 
-    # screens.rpy:578
+    # screens.rpy:580
     old "Alessio"
     new "Alessio"
 
-    # screens.rpy:584
+    # screens.rpy:586
     old "Update Written By"
     new "Новый сценарий"
 
-    # screens.rpy:585
+    # screens.rpy:587
     old "Lore"
     new "Lore"
 
-    # screens.rpy:589
+    # screens.rpy:591
     old "Originally Written By "
     new "Оригинал сценария"
 
-    # screens.rpy:590
+    # screens.rpy:592
     old "mikey (ATP Projects)"
     new "mikey (ATP Projects)"
 
-    # screens.rpy:593
+    # screens.rpy:595
     old "\nMade with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only]"
     new "\nСделано с помощью {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only]"
 
-    # screens.rpy:595
+    # screens.rpy:597
     old "[renpy.license!t]"
     new "[renpy.license!t]"
 
-    # screens.rpy:641
+    # screens.rpy:643
     old "Page {}"
     new "{} страница"
 
-    # screens.rpy:641
+    # screens.rpy:643
     old "Automatic saves"
     new "Автосохранения"
 
-    # screens.rpy:641
+    # screens.rpy:643
     old "Quick saves"
     new "Быстрые сохранения"
 
-    # screens.rpy:683
+    # screens.rpy:685
     old "{#file_time}%A, %B %d %Y, %H:%M"
     new "{#file_time}%A, %d %B %Y, %H:%M"
 
-    # screens.rpy:683
+    # screens.rpy:685
     old "empty slot"
     new "Пустой слот"
 
-    # screens.rpy:700
+    # screens.rpy:702
     old "<"
     new "<"
 
-    # screens.rpy:703
+    # screens.rpy:705
     old "{#auto_page}A"
     new "{#auto_page}А"
 
-    # screens.rpy:706
+    # screens.rpy:708
     old "{#quick_page}Q"
     new "{#quick_page}Б"
 
-    # screens.rpy:712
+    # screens.rpy:714
     old ">"
     new ">"
 
-    # screens.rpy:774
+    # screens.rpy:776
     old "Display"
     new "Режим экрана"
 
-    # screens.rpy:775
+    # screens.rpy:777
     old "Window"
     new "Оконный"
 
-    # screens.rpy:776
+    # screens.rpy:778
     old "Fullscreen"
     new "Полный"
 
-    # screens.rpy:780
+    # screens.rpy:782
     old "Rollback Side"
     new "Сторона отката"
 
-    # screens.rpy:781
+    # screens.rpy:783
     old "Disable"
     new "Отключено"
 
-    # screens.rpy:782
+    # screens.rpy:784
     old "Left"
     new "Левая"
 
-    # screens.rpy:783
+    # screens.rpy:785
     old "Right"
     new "Правая"
 
-    # screens.rpy:788
+    # screens.rpy:790
     old "Unseen Text"
     new "Всего текста"
 
-    # screens.rpy:789
+    # screens.rpy:791
     old "After Choices"
     new "После выборов"
 
-    # screens.rpy:790
+    # screens.rpy:792
     old "Transitions"
     new "Переходов"
 
-    # screens.rpy:803
+    # screens.rpy:800
+    old "Language"
+    new "Язык"
+
+    # screens.rpy:815
     old "Text Speed"
     new "Скорость текста"
 
-    # screens.rpy:807
+    # screens.rpy:819
     old "Auto-Forward Time"
     new "Скорость авточтения"
 
-    # screens.rpy:814
+    # screens.rpy:826
     old "Music Volume"
     new "Громкость музыки"
 
-    # screens.rpy:821
+    # screens.rpy:833
     old "Sound Volume"
     new "Громкость звуков"
 
-    # screens.rpy:827
+    # screens.rpy:839
     old "Test"
     new "Тест"
 
-    # screens.rpy:831
+    # screens.rpy:843
     old "Voice Volume"
     new "Громкость голоса"
 
-    # screens.rpy:842
+    # screens.rpy:854
     old "Mute All"
     new "Без звука"
 
-    # screens.rpy:958
+    # screens.rpy:970
     old "The dialogue history is empty."
     new "История диалогов пуста."
 
-    # screens.rpy:1023
+    # screens.rpy:1035
     old "Keyboard"
     new "Клавиатура"
 
-    # screens.rpy:1024
+    # screens.rpy:1036
     old "Mouse"
     new "Мышь"
 
-    # screens.rpy:1027
+    # screens.rpy:1039
     old "Gamepad"
     new "Геймпад"
 
-    # screens.rpy:1040
+    # screens.rpy:1052
     old "Enter"
     new "Enter"
 
-    # screens.rpy:1041
+    # screens.rpy:1053
     old "Advances dialogue and activates the interface."
     new "Прохождение диалогов, активация интерфейса."
 
-    # screens.rpy:1044
+    # screens.rpy:1056
     old "Space"
     new "Пробел"
 
-    # screens.rpy:1045
+    # screens.rpy:1057
     old "Advances dialogue without selecting choices."
     new "Прохождение диалогов без возможности делать выбор."
 
-    # screens.rpy:1048
+    # screens.rpy:1060
     old "Arrow Keys"
     new "Стрелки"
 
-    # screens.rpy:1049
+    # screens.rpy:1061
     old "Navigate the interface."
     new "Навигация по интерфейсу."
 
-    # screens.rpy:1052
+    # screens.rpy:1064
     old "Escape"
-    new "Escape"
+    new "Esc"
 
-    # screens.rpy:1053
+    # screens.rpy:1065
     old "Accesses the game menu."
     new "Вход в игровое меню."
 
-    # screens.rpy:1056
+    # screens.rpy:1068
     old "Ctrl"
     new "Ctrl"
 
-    # screens.rpy:1057
+    # screens.rpy:1069
     old "Skips dialogue while held down."
     new "Пропускает диалоги, пока зажат."
 
-    # screens.rpy:1060
+    # screens.rpy:1072
     old "Tab"
     new "Tab"
 
-    # screens.rpy:1061
+    # screens.rpy:1073
     old "Toggles dialogue skipping."
     new "Включает режим пропуска."
 
-    # screens.rpy:1064
+    # screens.rpy:1076
     old "Page Up"
     new "Page Up"
 
-    # screens.rpy:1065
+    # screens.rpy:1077
     old "Rolls back to earlier dialogue."
     new "Откат назад по сюжету игры."
 
-    # screens.rpy:1068
+    # screens.rpy:1080
     old "Page Down"
     new "Page Down"
 
-    # screens.rpy:1069
+    # screens.rpy:1081
     old "Rolls forward to later dialogue."
     new "Откатывает предыдущее действие вперёд."
 
-    # screens.rpy:1073
+    # screens.rpy:1085
     old "Hides the user interface."
     new "Скрывает интерфейс пользователя."
 
-    # screens.rpy:1077
+    # screens.rpy:1089
     old "Takes a screenshot."
     new "Делает снимок экрана."
 
-    # screens.rpy:1081
+    # screens.rpy:1093
     old "Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}."
     new "Включает поддерживаемый {a=https://www.renpy.org/l/voicing}синтезатор речи{/a}."
 
-    # screens.rpy:1087
+    # screens.rpy:1099
     old "Left Click"
     new "Левый клик"
 
-    # screens.rpy:1091
+    # screens.rpy:1103
     old "Middle Click"
     new "Клик колёсиком"
 
-    # screens.rpy:1095
+    # screens.rpy:1107
     old "Right Click"
     new "Правый клик"
 
-    # screens.rpy:1099
+    # screens.rpy:1111
     old "Mouse Wheel Up\nClick Rollback Side"
     new "Колёсико вверх\nКлик на сторону отката"
 
-    # screens.rpy:1103
+    # screens.rpy:1115
     old "Mouse Wheel Down"
     new "Колёсико вниз"
 
-    # screens.rpy:1110
+    # screens.rpy:1122
     old "Right Trigger\nA/Bottom Button"
     new "Правый триггер\nA/Нижняя кнопка"
 
-    # screens.rpy:1114
+    # screens.rpy:1126
     old "Left Trigger\nLeft Shoulder"
     new "Левый Триггер\nЛевый Бампер"
 
-    # screens.rpy:1118
+    # screens.rpy:1130
     old "Right Shoulder"
     new "Правый бампер"
 
-    # screens.rpy:1122
+    # screens.rpy:1134
     old "D-Pad, Sticks"
     new "Крестовина, Стики"
 
-    # screens.rpy:1126
+    # screens.rpy:1138
     old "Start, Guide"
     new "Start, Guide"
 
-    # screens.rpy:1130
+    # screens.rpy:1142
     old "Y/Top Button"
     new "Y/Верхняя кнопка"
 
-    # screens.rpy:1133
+    # screens.rpy:1145
     old "Calibrate"
     new "Калибровка"
 
-    # screens.rpy:1198
+    # screens.rpy:1210
     old "Yes"
     new "Да"
 
-    # screens.rpy:1199
+    # screens.rpy:1211
     old "No"
     new "Нет"
 
-    # screens.rpy:1245
+    # screens.rpy:1257
     old "Skipping"
     new "Пропускаю"
 
-    # screens.rpy:1466
+    # screens.rpy:1478
     old "Menu"
     new "Меню"
 
diff --git a/the_question/game/tl/russian/script.rpy b/the_question/game/tl/russian/script.rpy
index 10df489..6691e25 100644
--- a/the_question/game/tl/russian/script.rpy
+++ b/the_question/game/tl/russian/script.rpy
@@ -13,7 +13,7 @@ translate russian start_d48fb984:
 # game/script.rpy:23
 translate russian start_622654e3:
 
-    # "I've had a lot of other thoughts on my mind…thoughts that culminate in a question."
+    # "I've had a lot of other thoughts on my mind...thoughts that culminate in a question."
     "У меня было много разных мыслей в голове… и все эти мысли кульминировались вопросом."
 
 # game/script.rpy:25
@@ -37,7 +37,7 @@ translate russian start_1d44d9d7:
 # game/script.rpy:37
 translate russian start_1c8af99f:
 
-    # "But recently… I've felt that I want something more."
+    # "But recently... I've felt that I want something more."
     "Но в последнее время… Я почувствовал, что мне хочется чего-то большего."
 
 # game/script.rpy:39
@@ -55,7 +55,7 @@ translate russian rightaway_cf214f74:
 # game/script.rpy:60
 translate russian rightaway_f5f51c33:
 
-    # m "Good…"
+    # m "Good..."
     m "Хорошо…"
 
 # game/script.rpy:62
@@ -97,7 +97,7 @@ translate russian rightaway_8f173bb5:
 # game/script.rpy:77
 translate russian rightaway_aa84c954:
 
-    # m "Hey… Umm…"
+    # m "Hey... Umm..."
     m "Эй… Эмм…"
 
 # game/script.rpy:82
@@ -109,13 +109,13 @@ translate russian rightaway_79becbf8:
 # game/script.rpy:84
 translate russian rightaway_6a5d032c:
 
-    # "I'll ask her…!"
+    # "I'll ask her...!"
     "Я спрошу её..!"
 
 # game/script.rpy:86
 translate russian rightaway_29e68260:
 
-    # m "Ummm… Will you…"
+    # m "Ummm... Will you..."
     m "Эммм… Хотела бы ты…"
 
 # game/script.rpy:88
@@ -133,7 +133,7 @@ translate russian rightaway_16b8cb94:
 # game/script.rpy:94
 translate russian rightaway_289664f3:
 
-    # "She looks so shocked that I begin to fear the worst. But then…"
+    # "She looks so shocked that I begin to fear the worst. But then..."
     "Она выглядела столь шокированной, что я начал бояться худшего. Но затем…"
 
 # game/script.rpy:98
@@ -175,7 +175,7 @@ translate russian game_fa834128:
 # game/script.rpy:121
 translate russian game_d9b28ade:
 
-    # m "And I thought maybe you could help me…since I know how you like to draw."
+    # m "And I thought maybe you could help me...since I know how you like to draw."
     m "И я думал, что ты могла бы помочь мне… так как я знаю, как тебе нравится рисовать."
 
 # game/script.rpy:123
@@ -235,7 +235,7 @@ translate russian book_2277f2aa:
 # game/script.rpy:154
 translate russian book_ccd3e9b0:
 
-    # m "That's great! So…would you be interested in working with me as an artist?"
+    # m "That's great! So...would you be interested in working with me as an artist?"
     m "Это отлично! Так… ты хочешь работать со мной в качестве художницы?"
 
 # game/script.rpy:156
@@ -271,13 +271,13 @@ translate russian marry_285256a1:
 # game/script.rpy:178
 translate russian marry_27260f18:
 
-    # "And one day…"
+    # "And one day..."
     "И в один день…"
 
 # game/script.rpy:183
 translate russian marry_bf690666:
 
-    # s "Hey…"
+    # s "Hey..."
     s "Эй…"
 
 # game/script.rpy:185
@@ -307,13 +307,13 @@ translate russian marry_f913278c:
 # game/script.rpy:197
 translate russian marry_4ba892a0:
 
-    # m "A while…"
+    # m "A while..."
     m "Некоторое время…"
 
 # game/script.rpy:201
 translate russian marry_39d7f0df:
 
-    # s "These last few years we've been making visual novels together, spending time together, helping each other…"
+    # s "These last few years we've been making visual novels together, spending time together, helping each other..."
     s "Последнюю пару лет мы делаем визуальные новеллы и проводим время вместе, помогаем друг другу…"
 
 # game/script.rpy:203
@@ -325,7 +325,7 @@ translate russian marry_1516df50:
 # game/script.rpy:205
 translate russian marry_3234b0ab:
 
-    # m "Sylvie…"
+    # m "Sylvie..."
     m "Сильви…"
 
 # game/script.rpy:209
@@ -355,7 +355,7 @@ translate russian marry_81ed468b:
 # game/script.rpy:219
 translate russian marry_1c4ae954:
 
-    # m "I guess… I was too worried about timing. I wanted to ask the right question at the right time."
+    # m "I guess... I was too worried about timing. I wanted to ask the right question at the right time."
     m "Думаю… Я просто слишком волновался о времени. Я хотел задать правильный вопрос в правильное время."
 
 # game/script.rpy:223
@@ -373,7 +373,7 @@ translate russian marry_ca27786f:
 # game/script.rpy:230
 translate russian marry_621ed4fc:
 
-    # "Our visual novel duo lives on even after we're married…and I try my best to be more decisive."
+    # "Our visual novel duo lives on even after we're married...and I try my best to be more decisive."
     "Наш дуэт разработки жил и после нашей свадьбы… и я изо всех сил старался стать решительнее."
 
 # game/script.rpy:232
@@ -409,7 +409,7 @@ translate russian later_982e14b6:
 # game/script.rpy:249
 translate russian later_f0f9a061:
 
-    # "I guess I'll never know the answer to my question now…"
+    # "I guess I'll never know the answer to my question now..."
     "Полагаю, теперь я никогда не узнаю ответ на мой вопрос…"
 
 # game/script.rpy:251
diff --git a/tutorial/game/01example.rpy b/tutorial/game/01example.rpy
index c16602b..385c6a2 100644
--- a/tutorial/game/01example.rpy
+++ b/tutorial/game/01example.rpy
@@ -617,3 +617,20 @@ init python:
         print("The game contains {} examples.".format(len(examples)))
 
     config.lint_stats_callbacks.append(lint_stats_callback)
+
+    import base64
+
+image _finaleimage = im.Data(base64.b64decode("""
+    iVBORw0KGgoAAAANSUhEUgAAAPAAAAEvCAYAAAB7SkzcAAAgAElEQVR42u2debydVXnvv+85mVYSAisECAEE3jCHeQdkRnAziGit9MDFqfZWT/SqFdtqUtteqa2VY9WiXms5t9faax3K6RUHqgzbAZkEzmYSIlNeEiCEhCRPIIG8mc57/1jrPdnn5Ix7fvd+fp/PzklyztnDetf3fZ611jMEqDKrpL8/EGEaluMt/KHAW4E3AJuBHwCftrA+WLx4QEerNRXoEGQW3k4P6/sFPggcOMKPPWXh/cADweLFO3XUFGBVc8DbAZwisBS4AugY7UeBRy18RIR7516klrjV1KFDkEmdLvAFoGucaxgAxwostZajdNgUYFXjre/pAj3AhRP8lWnA+QIf3Njfv5+OoAKsahy8xwh8Hjhvkr86B3gHcNFGt3ZWKcCqOsO7v8BflQFvqjcAV1k4VkdTAVbVURtv758i8HHgcmBKmU8z [...]
+    """), "finale.png")
+
+
+image _finale:
+    "_finaleimage"
+    yalign 0.3
+    xanchor 1.0 xpos 0.0
+    pause 90.0
+    easein 1.5 xanchor 0.0 xpos .25
+    pause 3.0
+    easeout 1.5 xanchor 1.0 xpos 0.0
+    repeat
diff --git a/tutorial/game/indepth_minigame.rpy b/tutorial/game/indepth_minigame.rpy
index 2c2cee7..8bbaaed 100644
--- a/tutorial/game/indepth_minigame.rpy
+++ b/tutorial/game/indepth_minigame.rpy
@@ -273,7 +273,7 @@ label pong_done:
 
     e "Minigames can spice up your visual novel, but be careful – not every visual novel player wants to be good at arcade games."
 
-    e "Part of the reason Ren'Py works well it's that it's meant for certain types of games, like visual novels and life simulations."
+    e "Part of the reason Ren'Py works well is that it's meant for certain types of games, like visual novels and life simulations."
 
     e "The further afield you get from those games, the more you'll find yourself fighting Ren'Py. At some point, it makes sense to consider other engines."
 
diff --git a/tutorial/game/keywords.py b/tutorial/game/keywords.py
index 8c8623b..a09b2f4 100644
--- a/tutorial/game/keywords.py
+++ b/tutorial/game/keywords.py
@@ -1,2 +1,4 @@
-keywords = ['$', 'add', 'and', 'animation', 'as', 'as', 'assert', 'at', 'bar', 'behind', 'block', 'break', 'button', 'call', 'choice', 'circles', 'class', 'clockwise', 'contains', 'continue', 'counterclockwise', 'def', 'define', 'del', 'elif', 'else', 'event', 'except', 'exec', 'expression', 'finally', 'fixed', 'for', 'frame', 'from', 'function', 'global', 'grid', 'has', 'hbox', 'hide', 'hotbar', 'hotspot', 'if', 'if', 'image', 'imagebutton', 'imagemap', 'import', 'in', 'in', 'init', 'in [...]
-properties = ['action', 'activate_additive', 'activate_adjust_spacing', 'activate_align', 'activate_alignaround', 'activate_alpha', 'activate_alt', 'activate_anchor', 'activate_angle', 'activate_antialias', 'activate_area', 'activate_around', 'activate_background', 'activate_bar_invert', 'activate_bar_resizing', 'activate_bar_vertical', 'activate_base_bar', 'activate_black_color', 'activate_bold', 'activate_bottom_bar', 'activate_bottom_gutter', 'activate_bottom_margin', 'activate_bottom [...]
+keywords = ['$', 'add', 'and', 'animation', 'as', 'assert', 'at', u'auto', 'bar', 'behind', 'block', 'break', 'button', 'call', 'choice', 'circles', 'class', u'clear', 'clockwise', 'contains', 'continue', 'counterclockwise', 'def', 'default', 'define', 'del', 'drag', 'draggroup', 'elif', 'else', 'event', 'except', 'exec', 'expression', 'finally', 'fixed', 'for', 'frame', 'from', 'function', 'global', 'grid', 'has', 'hbox', 'hide', 'hotbar', 'hotspot', 'if', 'image', 'imagebutton', 'image [...]
+keyword_regex = u'\\$|add|and|animation|as|assert|at|auto|bar|behind|block|break|button|call|choice|circles|class|clear|clockwise|contains|continue|counterclockwise|def|default|define|del|drag|draggroup|elif|else|event|except|exec|expression|finally|fixed|for|frame|from|function|global|grid|has|hbox|hide|hotbar|hotspot|if|image|imagebutton|imagemap|import|in|init|input|is|jump|key|knot|label|lambda|menu|mousearea|music|new|nointeract|not|null|nvl|offset|old|on|onlayer|or|parallel|pass|pa [...]
+properties = ['action', 'activate_additive', 'activate_adjust_spacing', 'activate_align', 'activate_alignaround', 'activate_alpha', 'activate_alt', 'activate_anchor', 'activate_angle', 'activate_antialias', 'activate_area', 'activate_around', 'activate_background', 'activate_bar_invert', 'activate_bar_resizing', 'activate_bar_vertical', 'activate_base_bar', 'activate_black_color', 'activate_bold', 'activate_bottom_bar', 'activate_bottom_gutter', 'activate_bottom_margin', 'activate_bottom [...]
+property_regexes = [u'(?:action|activate_sound|adjustment|allow|alpha|alternate|alternate_keysym|arguments|arrowkeys|at|auto|cache|caption|changed|child_size|clicked|cols|default|drag_handle|drag_joined|drag_name|drag_offscreen|drag_raise|draggable|dragged|droppable|dropped|edgescroll|exclude|focus|focus_mask|ground|height|hover|hovered|id|idle|image_style|insensitive|keysym|layer|length|modal|mouse_drop|mousewheel|pagekeys|pixel_width|predict|prefix|properties|range|repeat|rows|scope|sc [...]
diff --git a/tutorial/game/screens.rpy b/tutorial/game/screens.rpy
index abc6b0f..3573450 100644
--- a/tutorial/game/screens.rpy
+++ b/tutorial/game/screens.rpy
@@ -448,6 +448,8 @@ screen game_menu(title, scroll=None):
                         scrollbars "vertical"
                         mousewheel True
                         draggable True
+                        pagekeys True
+
 
                         side_yfill True
 
@@ -463,6 +465,7 @@ screen game_menu(title, scroll=None):
                         scrollbars "vertical"
                         mousewheel True
                         draggable True
+                        pagekeys True
 
                         side_yfill True
 
diff --git a/tutorial/game/script.rpy b/tutorial/game/script.rpy
index 8084d18..e3a4111 100644
--- a/tutorial/game/script.rpy
+++ b/tutorial/game/script.rpy
@@ -199,6 +199,9 @@ label end:
     show eileen happy at center
     with move
 
+    show _finale behind eileen
+
+
     e "Thank you for viewing this tutorial."
 
     e "If you'd like to see a full Ren'Py game, select \"The Question\" in the launcher."
diff --git a/tutorial/game/tl/piglatin/common.rpy b/tutorial/game/tl/piglatin/common.rpy
index 800959c..8fe0882 100644
--- a/tutorial/game/tl/piglatin/common.rpy
+++ b/tutorial/game/tl/piglatin/common.rpy
@@ -157,10 +157,54 @@ translate piglatin strings:
     old "%b %d, %H:%M"
     new "%bay %day, %Hay:%May"
 
-    # 00action_file.rpy:852
+    # 00action_file.rpy:344
+    old "Save slot %s: [text]"
+    new "Avesay otslay %say: [text]"
+
+    # 00action_file.rpy:417
+    old "Load slot %s: [text]"
+    new "Oadlay otslay %say: [text]"
+
+    # 00action_file.rpy:459
+    old "Delete slot [text]"
+    new "Eleteday otslay [text]"
+
+    # 00action_file.rpy:539
+    old "File page auto"
+    new "Ilefay agepay autoay"
+
+    # 00action_file.rpy:541
+    old "File page quick"
+    new "Ilefay agepay uickqay"
+
+    # 00action_file.rpy:543
+    old "File page [text]"
+    new "Ilefay agepay [text]"
+
+    # 00action_file.rpy:733
+    old "Next file page."
+    new "Extnay ilefay agepay."
+
+    # 00action_file.rpy:797
+    old "Previous file page."
+    new "Reviouspay ilefay agepay."
+
+    # 00action_file.rpy:858
     old "Quick save complete."
     new "Uickqay avesay ompletecay."
 
+    # 00action_file.rpy:876
+    old "Quick save."
+    new "Uickqay avesay."
+
+    # 00action_file.rpy:895
+    old "Quick load."
+    new "Uickqay oadlay."
+
+    # 00action_other.rpy:344
+    old "Language [text]"
+    new "Anguagelay [text]"
+
     # 00director.rpy:703
     old "The interactive director is not enabled here."
     new "Hetay interactiveay irectorday isay otnay enableday erehay."
@@ -305,23 +349,203 @@ translate piglatin strings:
     old "Self-voicing enabled. "
     new "Elfsay-oicingvay enableday. "
 
-    # 00library.rpy:183
+    # 00library.rpy:150
+    old "bar"
+    new "arbay"
+
+    # 00library.rpy:151
+    old "selected"
+    new "electedsay"
+
+    # 00library.rpy:152
+    old "viewport"
+    new "iewportvay"
+
+    # 00library.rpy:153
+    old "horizontal scroll"
+    new "orizontalhay crollsay"
+
+    # 00library.rpy:154
+    old "vertical scroll"
+    new "erticalvay crollsay"
+
+    # 00library.rpy:155
+    old "activate"
+    new "activateay"
+
+    # 00library.rpy:156
+    old "deactivate"
+    new "eactivateday"
+
+    # 00library.rpy:157
+    old "increase"
+    new "increaseay"
+
+    # 00library.rpy:158
+    old "decrease"
+    new "ecreaseday"
+
+    # 00library.rpy:193
     old "Skip Mode"
     new "Kipsay Odemay"
 
-    # 00library.rpy:269
+    # 00library.rpy:279
     old "This program contains free software under a number of licenses, including the MIT License and GNU Lesser General Public License. A complete list of software, including links to full source code, can be found {a=https://www.renpy.org/l/license}here{/a}."
     new "Histay rogrampay ontainscay eefray oftwaresay underay aay umbernay ofay icenseslay, includingay hetay Itmay Icenselay anday Nugay Esserlay Eneralgay Ublicpay Icenselay. Aay ompletecay istlay ofay oftwaresay, includingay inkslay otay ullfay ourcesay odecay, ancay ebay oundfay {a=https://www.renpy.org/l/license}erehay{/a}."
 
-    # 00preferences.rpy:475
+    # 00preferences.rpy:207
+    old "display"
+    new "isplayday"
+
+    # 00preferences.rpy:219
+    old "transitions"
+    new "ansitionstray"
+
+    # 00preferences.rpy:228
+    old "skip transitions"
+    new "kipsay ansitionstray"
+
+    # 00preferences.rpy:230
+    old "video sprites"
+    new "ideovay pritessay"
+
+    # 00preferences.rpy:239
+    old "show empty window"
+    new "owshay emptyay indowway"
+
+    # 00preferences.rpy:248
+    old "text speed"
+    new "exttay peedsay"
+
+    # 00preferences.rpy:256
+    old "joystick"
+    new "oystickjay"
+
+    # 00preferences.rpy:256
+    old "joystick..."
+    new "oystickjay..."
+
+    # 00preferences.rpy:263
+    old "skip"
+    new "kipsay"
+
+    # 00preferences.rpy:266
+    old "skip unseen [text]"
+    new "kipsay unseenay [text]"
+
+    # 00preferences.rpy:271
+    old "skip unseen text"
+    new "kipsay unseenay exttay"
+
+    # 00preferences.rpy:273
+    old "begin skipping"
+    new "eginbay kippingsay"
+
+    # 00preferences.rpy:277
+    old "after choices"
+    new "afteray oiceschay"
+
+    # 00preferences.rpy:284
+    old "skip after choices"
+    new "kipsay afteray oiceschay"
+
+    # 00preferences.rpy:286
+    old "auto-forward time"
+    new "autoay-orwardfay imetay"
+
+    # 00preferences.rpy:300
+    old "auto-forward"
+    new "autoay-orwardfay"
+
+    # 00preferences.rpy:307
+    old "Auto forward"
+    new "Utoaay orwardfay"
+
+    # 00preferences.rpy:310
+    old "auto-forward after click"
+    new "autoay-orwardfay afteray ickclay"
+
+    # 00preferences.rpy:319
+    old "automatic move"
+    new "automaticay ovemay"
+
+    # 00preferences.rpy:328
+    old "wait for voice"
+    new "aitway orfay oicevay"
+
+    # 00preferences.rpy:337
+    old "voice sustain"
+    new "oicevay ustainsay"
+
+    # 00preferences.rpy:346
+    old "self voicing"
+    new "elfsay oicingvay"
+
+    # 00preferences.rpy:355
+    old "clipboard voicing"
+    new "ipboardclay oicingvay"
+
+    # 00preferences.rpy:364
+    old "debug voicing"
+    new "ebugday oicingvay"
+
+    # 00preferences.rpy:373
+    old "emphasize audio"
+    new "emphasizeay audioay"
+
+    # 00preferences.rpy:382
+    old "rollback side"
+    new "ollbackray idesay"
+
+    # 00preferences.rpy:392
+    old "gl powersave"
+    new "glay owersavepay"
+
+    # 00preferences.rpy:398
+    old "gl framerate"
+    new "glay ameratefray"
+
+    # 00preferences.rpy:401
+    old "gl tearing"
+    new "glay earingtay"
+
+    # 00preferences.rpy:413
+    old "music volume"
+    new "usicmay olumevay"
+
+    # 00preferences.rpy:414
+    old "sound volume"
+    new "oundsay olumevay"
+
+    # 00preferences.rpy:415
+    old "voice volume"
+    new "oicevay olumevay"
+
+    # 00preferences.rpy:416
+    old "mute music"
+    new "utemay usicmay"
+
+    # 00preferences.rpy:417
+    old "mute sound"
+    new "utemay oundsay"
+
+    # 00preferences.rpy:418
+    old "mute voice"
+    new "utemay oicevay"
+
+    # 00preferences.rpy:419
+    old "mute all"
+    new "utemay allay"
+
+    # 00preferences.rpy:498
     old "Clipboard voicing enabled. Press 'shift+C' to disable."
     new "Lipboardcay oicingvay enableday. Resspay 'iftshay+Cay' otay isableday."
 
-    # 00preferences.rpy:477
+    # 00preferences.rpy:500
     old "Self-voicing would say \"[renpy.display.tts.last]\". Press 'alt+shift+V' to disable."
     new "Elfsay-oicingvay ouldway aysay \"[renpy.display.tts.last]\". Resspay 'altay+iftshay+Vay' otay isableday."
 
-    # 00preferences.rpy:479
+    # 00preferences.rpy:502
     old "Self-voicing enabled. Press 'v' to disable."
     new "Elfsay-oicingvay enableday. Resspay 'vay' otay isableday."
 
@@ -337,83 +561,83 @@ translate piglatin strings:
     old "An error is being simulated."
     new "Naay erroray isay eingbay imulatedsay."
 
-    # 00updater.rpy:667
+    # 00updater.rpy:672
     old "Either this project does not support updating, or the update status file was deleted."
     new "Ithereay histay rojectpay oesday otnay upportsay updatingay, oray hetay updateay atusstay ilefay asway eletedday."
 
-    # 00updater.rpy:681
+    # 00updater.rpy:686
     old "This account does not have permission to perform an update."
     new "Histay accountay oesday otnay avehay ermissionpay otay erformpay anay updateay."
 
-    # 00updater.rpy:684
+    # 00updater.rpy:689
     old "This account does not have permission to write the update log."
     new "Histay accountay oesday otnay avehay ermissionpay otay riteway hetay updateay oglay."
 
-    # 00updater.rpy:711
+    # 00updater.rpy:716
     old "Could not verify update signature."
     new "Ouldcay otnay erifyvay updateay ignaturesay."
 
-    # 00updater.rpy:986
+    # 00updater.rpy:991
     old "The update file was not downloaded."
     new "Hetay updateay ilefay asway otnay ownloadedday."
 
-    # 00updater.rpy:1004
+    # 00updater.rpy:1009
     old "The update file does not have the correct digest - it may have been corrupted."
     new "Hetay updateay ilefay oesday otnay avehay hetay orrectcay igestday - itay aymay avehay eenbay orruptedcay."
 
-    # 00updater.rpy:1060
+    # 00updater.rpy:1065
     old "While unpacking {}, unknown type {}."
     new "Hileway unpackingay {}, unknownay ypetay {}."
 
-    # 00updater.rpy:1407
+    # 00updater.rpy:1412
     old "Updater"
     new "Pdateruay"
 
-    # 00updater.rpy:1414
+    # 00updater.rpy:1419
     old "An error has occured:"
     new "Naay erroray ashay occureday:"
 
-    # 00updater.rpy:1416
+    # 00updater.rpy:1421
     old "Checking for updates."
     new "Heckingcay orfay updatesay."
 
-    # 00updater.rpy:1418
+    # 00updater.rpy:1423
     old "This program is up to date."
     new "Histay rogrampay isay upay otay ateday."
 
-    # 00updater.rpy:1420
+    # 00updater.rpy:1425
     old "[u.version] is available. Do you want to install it?"
     new "[u.version] isay availableay. Oday ouyay antway otay installay itay?"
 
-    # 00updater.rpy:1422
+    # 00updater.rpy:1427
     old "Preparing to download the updates."
     new "Reparingpay otay ownloadday hetay updatesay."
 
-    # 00updater.rpy:1424
+    # 00updater.rpy:1429
     old "Downloading the updates."
     new "Ownloadingday hetay updatesay."
 
-    # 00updater.rpy:1426
+    # 00updater.rpy:1431
     old "Unpacking the updates."
     new "Npackinguay hetay updatesay."
 
-    # 00updater.rpy:1428
+    # 00updater.rpy:1433
     old "Finishing up."
     new "Inishingfay upay."
 
-    # 00updater.rpy:1430
+    # 00updater.rpy:1435
     old "The updates have been installed. The program will restart."
     new "Hetay updatesay avehay eenbay installeday. Hetay rogrampay illway estartray."
 
-    # 00updater.rpy:1432
+    # 00updater.rpy:1437
     old "The updates have been installed."
     new "Hetay updatesay avehay eenbay installeday."
 
-    # 00updater.rpy:1434
+    # 00updater.rpy:1439
     old "The updates were cancelled."
     new "Hetay updatesay ereway ancelledcay."
 
-    # 00updater.rpy:1449
+    # 00updater.rpy:1454
     old "Proceed"
     new "Roceedpay"
 
diff --git a/tutorial/game/tl/piglatin/indepth_minigame.rpy b/tutorial/game/tl/piglatin/indepth_minigame.rpy
index 96c5638..6cde76e 100644
--- a/tutorial/game/tl/piglatin/indepth_minigame.rpy
+++ b/tutorial/game/tl/piglatin/indepth_minigame.rpy
@@ -66,10 +66,10 @@ translate piglatin pong_done_5781d902:
     e "Inigamesmay ancay picesay upay ouryay isualvay ovelnay, utbay ebay arefulcay – otnay everyay isualvay ovelnay ayerplay antsway otay ebay oodgay atay arcadeay amesgay."
 
 # game/indepth_minigame.rpy:276
-translate piglatin pong_done_849cf6db:
+translate piglatin pong_done_631325c8:
 
-    # e "Part of the reason Ren'Py works well it's that it's meant for certain types of games, like visual novels and life simulations."
-    e "Artpay ofay hetay easonray Enray'Ypay orksway ellway itay'say hattay itay'say eantmay orfay ertaincay ypestay ofay amesgay, ikelay isualvay ovelsnay anday ifelay imulationssay."
+    # e "Part of the reason Ren'Py works well is that it's meant for certain types of games, like visual novels and life simulations."
+    e "Artpay ofay hetay easonray Enray'Ypay orksway ellway isay hattay itay'say eantmay orfay ertaincay ypestay ofay amesgay, ikelay isualvay ovelsnay anday ifelay imulationssay."
 
 # game/indepth_minigame.rpy:278
 translate piglatin pong_done_61d60761:
diff --git a/tutorial/game/tl/piglatin/screens.rpy b/tutorial/game/tl/piglatin/screens.rpy
index b2fc338..54b9444 100644
--- a/tutorial/game/tl/piglatin/screens.rpy
+++ b/tutorial/game/tl/piglatin/screens.rpy
@@ -65,263 +65,263 @@ translate piglatin strings:
     old "Quit"
     new "Uitqay"
 
-    # screens.rpy:477
+    # screens.rpy:480
     old "Return"
     new "Eturnray"
 
-    # screens.rpy:561
+    # screens.rpy:564
     old "Version [config.version!t]\n"
     new "Ersionvay [config.version!t]\n"
 
-    # screens.rpy:567
+    # screens.rpy:570
     old "Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]"
     new "Ademay ithway {a=https://www.renpy.org/}Enray'Ypay{/a} [renpy.version_only].\n\n[renpy.license!t]"
 
-    # screens.rpy:607
+    # screens.rpy:610
     old "Page {}"
     new "Agepay {}"
 
-    # screens.rpy:607
+    # screens.rpy:610
     old "Automatic saves"
     new "Utomaticaay avessay"
 
-    # screens.rpy:607
+    # screens.rpy:610
     old "Quick saves"
     new "Uickqay avessay"
 
-    # screens.rpy:649
+    # screens.rpy:652
     old "{#file_time}%A, %B %d %Y, %H:%M"
     new "{#file_time}%Aay, %Bay %day %Yay, %Hay:%May"
 
-    # screens.rpy:649
+    # screens.rpy:652
     old "empty slot"
     new "emptyay otslay"
 
-    # screens.rpy:666
+    # screens.rpy:669
     old "<"
     new "<"
 
-    # screens.rpy:669
+    # screens.rpy:672
     old "{#auto_page}A"
     new "{#auto_page}Aay"
 
-    # screens.rpy:672
+    # screens.rpy:675
     old "{#quick_page}Q"
     new "{#quick_page}Qay"
 
-    # screens.rpy:678
+    # screens.rpy:681
     old ">"
     new ">"
 
-    # screens.rpy:740
+    # screens.rpy:743
     old "Display"
     new "Isplayday"
 
-    # screens.rpy:741
+    # screens.rpy:744
     old "Window"
     new "Indowway"
 
-    # screens.rpy:742
+    # screens.rpy:745
     old "Fullscreen"
     new "Ullscreenfay"
 
-    # screens.rpy:754
+    # screens.rpy:757
     old "Unseen Text"
     new "Nseenuay Exttay"
 
-    # screens.rpy:755
+    # screens.rpy:758
     old "After Choices"
     new "Fteraay Hoicescay"
 
-    # screens.rpy:761
+    # screens.rpy:764
     old "Examples"
     new "Xampleseay"
 
-    # screens.rpy:770
+    # screens.rpy:773
     old "Language"
     new "Anguagelay"
 
-    # screens.rpy:790
+    # screens.rpy:793
     old "Text Speed"
     new "Exttay Peedsay"
 
-    # screens.rpy:794
+    # screens.rpy:797
     old "Auto-Forward Time"
     new "Utoaay-Orwardfay Imetay"
 
-    # screens.rpy:801
+    # screens.rpy:804
     old "Music Volume"
     new "Usicmay Olumevay"
 
-    # screens.rpy:808
+    # screens.rpy:811
     old "Sound Volume"
     new "Oundsay Olumevay"
 
-    # screens.rpy:814
+    # screens.rpy:817
     old "Test"
     new "Esttay"
 
-    # screens.rpy:818
+    # screens.rpy:821
     old "Voice Volume"
     new "Oicevay Olumevay"
 
-    # screens.rpy:829
+    # screens.rpy:832
     old "Mute All"
     new "Utemay Llaay"
 
-    # screens.rpy:945
+    # screens.rpy:948
     old "The dialogue history is empty."
     new "Hetay ialogueday istoryhay isay emptyay."
 
-    # screens.rpy:1010
+    # screens.rpy:1013
     old "Keyboard"
     new "Eyboardkay"
 
-    # screens.rpy:1011
+    # screens.rpy:1014
     old "Mouse"
     new "Ousemay"
 
-    # screens.rpy:1014
+    # screens.rpy:1017
     old "Gamepad"
     new "Amepadgay"
 
-    # screens.rpy:1027
+    # screens.rpy:1030
     old "Enter"
     new "Ntereay"
 
-    # screens.rpy:1028
+    # screens.rpy:1031
     old "Advances dialogue and activates the interface."
     new "Dvancesaay ialogueday anday activatesay hetay interfaceay."
 
-    # screens.rpy:1031
+    # screens.rpy:1034
     old "Space"
     new "Pacesay"
 
-    # screens.rpy:1032
+    # screens.rpy:1035
     old "Advances dialogue without selecting choices."
     new "Dvancesaay ialogueday ithoutway electingsay oiceschay."
 
-    # screens.rpy:1035
+    # screens.rpy:1038
     old "Arrow Keys"
     new "Rrowaay Eyskay"
 
-    # screens.rpy:1036
+    # screens.rpy:1039
     old "Navigate the interface."
     new "Avigatenay hetay interfaceay."
 
-    # screens.rpy:1039
+    # screens.rpy:1042
     old "Escape"
     new "Scapeeay"
 
-    # screens.rpy:1040
+    # screens.rpy:1043
     old "Accesses the game menu."
     new "Ccessesaay hetay amegay enumay."
 
-    # screens.rpy:1043
+    # screens.rpy:1046
     old "Ctrl"
     new "Trlcay"
 
-    # screens.rpy:1044
+    # screens.rpy:1047
     old "Skips dialogue while held down."
     new "Kipssay ialogueday hileway eldhay ownday."
 
-    # screens.rpy:1047
+    # screens.rpy:1050
     old "Tab"
     new "Abtay"
 
-    # screens.rpy:1048
+    # screens.rpy:1051
     old "Toggles dialogue skipping."
     new "Ogglestay ialogueday kippingsay."
 
-    # screens.rpy:1051
+    # screens.rpy:1054
     old "Page Up"
     new "Agepay Puay"
 
-    # screens.rpy:1052
+    # screens.rpy:1055
     old "Rolls back to earlier dialogue."
     new "Ollsray ackbay otay earlieray ialogueday."
 
-    # screens.rpy:1055
+    # screens.rpy:1058
     old "Page Down"
     new "Agepay Ownday"
 
-    # screens.rpy:1056
+    # screens.rpy:1059
     old "Rolls forward to later dialogue."
     new "Ollsray orwardfay otay aterlay ialogueday."
 
-    # screens.rpy:1060
+    # screens.rpy:1063
     old "Hides the user interface."
     new "Ideshay hetay useray interfaceay."
 
-    # screens.rpy:1064
+    # screens.rpy:1067
     old "Takes a screenshot."
     new "Akestay aay creenshotsay."
 
-    # screens.rpy:1068
+    # screens.rpy:1071
     old "Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}."
     new "Ogglestay assistiveay {a=https://www.renpy.org/l/voicing}elfsay-oicingvay{/a}."
 
-    # screens.rpy:1074
+    # screens.rpy:1077
     old "Left Click"
     new "Eftlay Lickcay"
 
-    # screens.rpy:1078
+    # screens.rpy:1081
     old "Middle Click"
     new "Iddlemay Lickcay"
 
-    # screens.rpy:1082
+    # screens.rpy:1085
     old "Right Click"
     new "Ightray Lickcay"
 
-    # screens.rpy:1086
+    # screens.rpy:1089
     old "Mouse Wheel Up\nClick Rollback Side"
     new "Ousemay Heelway Puay\nLickcay Ollbackray Idesay"
 
-    # screens.rpy:1090
+    # screens.rpy:1093
     old "Mouse Wheel Down"
     new "Ousemay Heelway Ownday"
 
-    # screens.rpy:1097
+    # screens.rpy:1100
     old "Right Trigger\nA/Bottom Button"
     new "Ightray Riggertay\nAay/Ottombay Uttonbay"
 
-    # screens.rpy:1101
+    # screens.rpy:1104
     old "Left Trigger\nLeft Shoulder"
     new "Eftlay Riggertay\nEftlay Houldersay"
 
-    # screens.rpy:1105
+    # screens.rpy:1108
     old "Right Shoulder"
     new "Ightray Houldersay"
 
-    # screens.rpy:1109
+    # screens.rpy:1112
     old "D-Pad, Sticks"
     new "Day-Adpay, Tickssay"
 
-    # screens.rpy:1113
+    # screens.rpy:1116
     old "Start, Guide"
     new "Tartsay, Uidegay"
 
-    # screens.rpy:1117
+    # screens.rpy:1120
     old "Y/Top Button"
     new "Yay/Optay Uttonbay"
 
-    # screens.rpy:1120
+    # screens.rpy:1123
     old "Calibrate"
     new "Alibratecay"
 
-    # screens.rpy:1185
+    # screens.rpy:1188
     old "Yes"
     new "Esyay"
 
-    # screens.rpy:1186
+    # screens.rpy:1189
     old "No"
     new "Onay"
 
-    # screens.rpy:1232
+    # screens.rpy:1235
     old "Skipping"
     new "Kippingsay"
 
-    # screens.rpy:1453
+    # screens.rpy:1456
     old "Menu"
     new "Enumay"
 
diff --git a/tutorial/game/tl/piglatin/script.rpy b/tutorial/game/tl/piglatin/script.rpy
index 7c9e200..7495b56 100644
--- a/tutorial/game/tl/piglatin/script.rpy
+++ b/tutorial/game/tl/piglatin/script.rpy
@@ -11,37 +11,37 @@ translate piglatin start_d3abb53c:
     # e "In this tutorial, we'll teach you the basics of Ren'Py, so you can make games of your own. We'll also demonstrate many features, so you can see what Ren'Py is capable of."
     e "Niay histay utorialtay, eway'llay eachtay ouyay hetay asicsbay ofay Enray'Ypay, osay ouyay ancay akemay amesgay ofay ouryay ownay. Eway'llay alsoay emonstrateday anymay eaturesfay, osay ouyay ancay eesay hatway Enray'Ypay isay apablecay ofay."
 
-# game/script.rpy:202
+# game/script.rpy:205
 translate piglatin end_b2482727:
 
     # e "Thank you for viewing this tutorial."
     e "Hanktay ouyay orfay iewingvay histay utorialtay."
 
-# game/script.rpy:204
+# game/script.rpy:207
 translate piglatin end_38362e36:
 
     # e "If you'd like to see a full Ren'Py game, select \"The Question\" in the launcher."
     e "Fiay ouyay'day ikelay otay eesay aay ullfay Enray'Ypay amegay, electsay \"Hetay Uestionqay\" inay hetay auncherlay."
 
-# game/script.rpy:206
+# game/script.rpy:209
 translate piglatin end_02527d05:
 
     # e "You can download new versions of Ren'Py from {a=https://www.renpy.org/}https://www.renpy.org/{/a}. For help and discussion, check out the {a=https://lemmasoft.renai.us/forums/}Lemma Soft Forums{/a}."
     e "Ouyay ancay ownloadday ewnay ersionsvay ofay Enray'Ypay omfray {a=https://www.renpy.org/}ttpshay://wwway.enpyray.orgay/{/a}. Orfay elphay anday iscussionday, eckchay outay hetay {a=https://lemmasoft.renai.us/forums/}Emmalay Oftsay Orumsfay{/a}."
 
-# game/script.rpy:208
+# game/script.rpy:211
 translate piglatin end_c9d03136:
 
     # e "We'd like to thank Piroshki for contributing my sprites; Mugenjohncel for Lucy, the band, and drawn backgrounds; and Jake for the magic circle."
     e "Eway'day ikelay otay hanktay Iroshkipay orfay ontributingcay ymay pritessay; Ugenjohncelmay orfay Ucylay, hetay andbay, anday rawnday ackgroundsbay; anday Akejay orfay hetay agicmay irclecay."
 
-# game/script.rpy:210
+# game/script.rpy:213
 translate piglatin end_762dc07a:
 
     # e "The background music is \"Sunflower Slow Drag\", by Scott Joplin and Scott Hayden, performed by the United States Marine Band. The concert music is by Alessio."
     e "Hetay ackgroundbay usicmay isay \"Unflowersay Lowsay Ragday\", ybay Cottsay Oplinjay anday Cottsay Aydenhay, erformedpay ybay hetay Niteduay Tatessay Arinemay Andbay. Hetay oncertcay usicmay isay ybay Lessioaay."
 
-# game/script.rpy:214
+# game/script.rpy:217
 translate piglatin end_a634d396:
 
     # e "We look forward to seeing what you create with Ren'Py. Have fun!"
diff --git a/tutorial/game/tl/russian/01example.rpy b/tutorial/game/tl/russian/01example.rpy
index ffd45c0..9f6b1f9 100644
--- a/tutorial/game/tl/russian/01example.rpy
+++ b/tutorial/game/tl/russian/01example.rpy
@@ -1,11 +1,11 @@
 
 translate russian strings:
 
-    # 01example.rpy:472
+    # 01example.rpy:473
     old "Copied the example to the clipboard."
     new "Пример скопирован в буфер обмена."
 
-    # 01example.rpy:545
+    # 01example.rpy:546
     old "copy"
     new "копировать"
 
diff --git a/tutorial/game/tl/russian/common.rpy b/tutorial/game/tl/russian/common.rpy
index 8f86426..c8f295f 100644
--- a/tutorial/game/tl/russian/common.rpy
+++ b/tutorial/game/tl/russian/common.rpy
@@ -157,318 +157,86 @@ translate russian strings:
     old "%b %d, %H:%M"
     new "%d %b, %H:%M"
 
-    # 00action_file.rpy:825
+    # 00action_file.rpy:820
     old "Quick save complete."
     new "Быстрое сохранение завершено."
 
-    # 00director.rpy:689
-    old "The interactive director is not enabled here."
-    new "Интерактивный директор недоступен."
-
-    # 00director.rpy:1461
-    old "Done"
-    new "Принять"
-
-    # 00director.rpy:1469
-    old "(statement)"
-    new "(функция)"
-
-    # 00director.rpy:1470
-    old "(tag)"
-    new "(тег)"
-
-    # 00director.rpy:1471
-    old "(attributes)"
-    new "(аттрибут)"
-
-    # 00director.rpy:1472
-    old "(transform)"
-    new "(трансформация)"
-
-    # 00director.rpy:1497
-    old "(transition)"
-    new "(переход)"
-
-    # 00director.rpy:1509
-    old "(channel)"
-    new "(канал)"
-
-    # 00director.rpy:1510
-    old "(filename)"
-    new "(имя файла)"
-
-    # 00director.rpy:1535
-    old "Change"
-    new "Изменить"
-
-    # 00director.rpy:1537
-    old "Add"
-    new "Добавить"
-
-    # 00director.rpy:1540
-    old "Cancel"
-    new "Отмена"
-
-    # 00director.rpy:1543
-    old "Remove"
-    new "Убрать"
-
-    # 00director.rpy:1576
-    old "Statement:"
-    new "Функции:"
-
-    # 00director.rpy:1597
-    old "Tag:"
-    new "Теги:"
-
-    # 00director.rpy:1613
-    old "Attributes:"
-    new "Аттрибут:"
-
-    # 00director.rpy:1631
-    old "Transforms:"
-    new "Трансформации:"
-
-    # 00director.rpy:1650
-    old "Behind:"
-    new "Позади:"
-
-    # 00director.rpy:1669
-    old "Transition:"
-    new "Переходы:"
-
-    # 00director.rpy:1687
-    old "Channel:"
-    new "Каналы:"
-
-    # 00director.rpy:1705
-    old "Audio Filename:"
-    new "Имя файла:"
-
-    # 00gui.rpy:240
+    # 00gui.rpy:234
     old "Are you sure?"
     new "Вы уверены?"
 
-    # 00gui.rpy:241
+    # 00gui.rpy:235
     old "Are you sure you want to delete this save?"
     new "Вы уверены, что хотите удалить это сохранение?"
 
-    # 00gui.rpy:242
+    # 00gui.rpy:236
     old "Are you sure you want to overwrite your save?"
     new "Вы уверены, что хотите перезаписать ваше сохранение?"
 
-    # 00gui.rpy:243
+    # 00gui.rpy:237
     old "Loading will lose unsaved progress.\nAre you sure you want to do this?"
     new "Загрузка игры приведёт к потере несохранённого прогресса.\nВы уверены, что хотите это сделать?"
 
-    # 00gui.rpy:244
+    # 00gui.rpy:238
     old "Are you sure you want to quit?"
     new "Вы уверены, что хотите выйти?"
 
-    # 00gui.rpy:245
+    # 00gui.rpy:239
     old "Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
     new "Вы уверены, что хотите вернуться в главное меню?\nЭто приведёт к потере несохранённого прогресса."
 
-    # 00gui.rpy:246
+    # 00gui.rpy:240
     old "Are you sure you want to end the replay?"
     new "Вы уверены, что хотите завершить повтор?"
 
-    # 00gui.rpy:247
+    # 00gui.rpy:241
     old "Are you sure you want to begin skipping?"
     new "Вы уверены, что хотите начать пропуск?"
 
-    # 00gui.rpy:248
+    # 00gui.rpy:242
     old "Are you sure you want to skip to the next choice?"
     new "Вы точно хотите пропустить всё до следующего выбора?"
 
-    # 00gui.rpy:249
+    # 00gui.rpy:243
     old "Are you sure you want to skip unseen dialogue to the next choice?"
     new "Вы уверены, что хотите пропустить непрочитанные диалоги до следующего выбора?"
 
-    # 00keymap.rpy:262
+    # 00keymap.rpy:259
     old "Saved screenshot as %s."
     new "Скриншот сохранён как %s."
 
-    # 00library.rpy:146
+    # 00library.rpy:142
     old "Self-voicing disabled."
     new "Синтезатор речи отключён."
 
-    # 00library.rpy:147
+    # 00library.rpy:143
     old "Clipboard voicing enabled. "
-    new "Озвучка буфера обмена включена. "
+    new "Озвучка буфера обмена включена."
 
-    # 00library.rpy:148
+    # 00library.rpy:144
     old "Self-voicing enabled. "
-    new "Синтезатор речи включён. "
+    new "Синтезатор речи включён."
 
-    # 00library.rpy:183
+    # 00library.rpy:179
     old "Skip Mode"
     new "Режим Пропуска"
 
-    # 00library.rpy:266
+    # 00library.rpy:262
     old "This program contains free software under a number of licenses, including the MIT License and GNU Lesser General Public License. A complete list of software, including links to full source code, can be found {a=https://www.renpy.org/l/license}here{/a}."
     new "Эта программа содержит свободное и открытое программное обеспечение под несколькими лицензиями, включая лицензию MIT и GNU Lesser General Public. Полный список лицензий, включая ссылки на полный исходный код, можно найти {a=https://www.renpy.org/l/license}здесь{/a}."
 
-    # 00preferences.rpy:442
+    # 00preferences.rpy:429
     old "Clipboard voicing enabled. Press 'shift+C' to disable."
     new "Озвучка буфера обмена включена. Нажмите 'shift+C', чтобы отключить её."
 
-    # 00preferences.rpy:444
+    # 00preferences.rpy:431
     old "Self-voicing would say \"[renpy.display.tts.last]\". Press 'alt+shift+V' to disable."
     new "Синтезатор речи должен сказать \"[renpy.display.tts.last]\". Нажмите 'alt+shift+V', чтобы отключить его."
 
-    # 00preferences.rpy:446
+    # 00preferences.rpy:433
     old "Self-voicing enabled. Press 'v' to disable."
     new "Синтезатор речи включён. Нажмите 'v', чтобы отключить его."
 
-    # _compat\gamemenu.rpym:198
-    old "Empty Slot."
-    new "Пустой слот."
-
-    # _compat\gamemenu.rpym:355
-    old "Previous"
-    new "Предыдущий"
-
-    # _compat\gamemenu.rpym:362
-    old "Next"
-    new "Следующий"
-
-    # _compat\preferences.rpym:428
-    old "Joystick Mapping"
-    new "Назначение джойстика"
-
-    # _developer\developer.rpym:38
-    old "Developer Menu"
-    new "Меню разработчика"
-
-    # _developer\developer.rpym:43
-    old "Interactive Director (D)"
-    new "Интерактивный Директор (D)"
-
-    # _developer\developer.rpym:45
-    old "Reload Game (Shift+R)"
-    new "Перезагрузить игру (Shift+R)"
-
-    # _developer\developer.rpym:47
-    old "Console (Shift+O)"
-    new "Консоль (Shift+O)"
-
-    # _developer\developer.rpym:49
-    old "Variable Viewer"
-    new "Просмотр переменных"
-
-    # _developer\developer.rpym:53
-    old "Image Location Picker"
-    new "Инструмент позиционирования на изображениях"
-
-    # _developer\developer.rpym:55
-    old "Filename List"
-    new "Список файлов"
-
-    # _developer\developer.rpym:59
-    old "Show Image Load Log"
-    new "Показать лог загрузки изображений"
-
-    # _developer\developer.rpym:62
-    old "Hide Image Load Log"
-    new "Скрыть лог загрузки изображений"
-
-    # _developer\developer.rpym:67
-    old "Show Texture Size"
-    new "Показать размер текстур"
-
-    # _developer\developer.rpym:70
-    old "Hide Texture size"
-    new "Скрыть размер текстур"
-
-    # _developer\developer.rpym:108
-    old "Nothing to inspect."
-    new "Переменные не заданы."
-
-    # _developer\developer.rpym:236
-    old "Return to the developer menu"
-    new "Вернуться в меню разработчика"
-
-    # _developer\developer.rpym:396
-    old "Rectangle: %r"
-    new "Прямоугольник: %r"
-
-    # _developer\developer.rpym:401
-    old "Mouse position: %r"
-    new "Позиция мыши: %r"
-
-    # _developer\developer.rpym:406
-    old "Right-click or escape to quit."
-    new "Нажмите правую кнопку мыши или ESC чтобы выйти."
-
-    # _developer\developer.rpym:438
-    old "Rectangle copied to clipboard."
-    new "Координаты прямоугольника скопированы в буфер обмена."
-
-    # _developer\developer.rpym:441
-    old "Position copied to clipboard."
-    new "Координаты позиции скопированы в буфер обмена."
-
-    # _developer\developer.rpym:550
-    old "✔ "
-    new "✔ "
-
-    # _developer\developer.rpym:553
-    old "✘ "
-    new "✘ "
-
-    # _developer\developer.rpym:558
-    old "\n{color=#cfc}✔ predicted image (good){/color}\n{color=#fcc}✘ unpredicted image (bad){/color}\n{color=#fff}Drag to move.{/color}"
-    new "\n{color=#cfc}✔ предсказанное изображение (хорошо){/color}\n{color=#fcc}✘ внезапное изображение (плохо){/color}\n{color=#fff}Нажмите, чтобы передвинуть.{/color}"
-
-    # _developer\developer.rpym:569
-    old "{size_mb:,.1f} MB in {count} textures."
-    new "{size_mb:,.1f} МБ при количестве текстур: {count}."
-
-    # _developer\inspector.rpym:38
-    old "Displayable Inspector"
-    new "Диспетчер объектов"
-
-    # _developer\inspector.rpym:61
-    old "Size"
-    new "Разрешение"
-
-    # _developer\inspector.rpym:65
-    old "Style"
-    new "Стиль"
-
-    # _developer\inspector.rpym:71
-    old "Location"
-    new "Местоположение"
-
-    # _developer\inspector.rpym:122
-    old "Inspecting Styles of [displayable_name!q]"
-    new "Инспектирую стили [displayable_name!q]"
-
-    # _developer\inspector.rpym:139
-    old "displayable:"
-    new "объект:"
-
-    # _developer\inspector.rpym:145
-    old "        (no properties affect the displayable)"
-    new "        (на объект не влияют никакие параметры)"
-
-    # _developer\inspector.rpym:147
-    old "        (default properties omitted)"
-    new "        (настройки по умолчанию опущены)"
-
-    # _developer\inspector.rpym:185
-    old "<repr() failed>"
-    new "<repr() провален>"
-
-    # _layout\classic_load_save.rpym:170
-    old "a"
-    new "а"
-
-    # _layout\classic_load_save.rpym:179
-    old "q"
-    new "б"
-
     # 00iap.rpy:217
     old "Contacting App Store\nPlease Wait..."
     new "Связываюсь с App Store\nПожалуйста, ждите..."
@@ -483,7 +251,7 @@ translate russian strings:
 
     # 00updater.rpy:668
     old "Either this project does not support updating, or the update status file was deleted."
-    new "Или этот проект не поддерживает обновление или файл статуса обновления был удалён."
+    new "Или этот проект не поддерживает обновление, или файл статуса обновления был удалён."
 
     # 00updater.rpy:682
     old "This account does not have permission to perform an update."
@@ -507,7 +275,7 @@ translate russian strings:
 
     # 00updater.rpy:1055
     old "While unpacking {}, unknown type {}."
-    new "При распаковке {}, обнаружен неизвестный тип {}."
+    new "При распаковке {} обнаружен неизвестный тип {}."
 
     # 00updater.rpy:1399
     old "Updater"
@@ -543,7 +311,7 @@ translate russian strings:
 
     # 00updater.rpy:1420
     old "Finishing up."
-    new "Завершаю."
+    new "Завершаю..."
 
     # 00updater.rpy:1422
     old "The updates have been installed. The program will restart."
@@ -561,29 +329,33 @@ translate russian strings:
     old "Proceed"
     new "Продолжить"
 
-    # 00gallery.rpy:573
+    # 00updater.rpy:1444
+    old "Cancel"
+    new "Отмена"
+
+    # 00gallery.rpy:563
     old "Image [index] of [count] locked."
     new "Изображение [index] из [count] закрыто."
 
-    # 00gallery.rpy:593
+    # 00gallery.rpy:583
     old "prev"
     new "пред"
 
-    # 00gallery.rpy:594
+    # 00gallery.rpy:584
     old "next"
     new "след"
 
-    # 00gallery.rpy:595
+    # 00gallery.rpy:585
     old "slideshow"
     new "слайд-шоу"
 
-    # 00gallery.rpy:596
+    # 00gallery.rpy:586
     old "return"
     new "вернуться"
 
     # 00gltest.rpy:64
     old "Graphics Acceleration"
-    new "Графическое Ускорение"
+    new "Graphics Acceleration"
 
     # 00gltest.rpy:70
     old "Automatically Choose"
@@ -591,89 +363,85 @@ translate russian strings:
 
     # 00gltest.rpy:75
     old "Force Angle/DirectX Renderer"
-    new "Насильно Отображать Через Angle/DirectX"
+    new "Принудительный Angle/DirectX"
 
     # 00gltest.rpy:79
     old "Force OpenGL Renderer"
-    new "Насильно Отображать Через OpenGL"
+    new "Принудительный OpenGL"
 
     # 00gltest.rpy:83
     old "Force Software Renderer"
-    new "Насильно Отображать Программно"
-
-    # 00gltest.rpy:89
-    old "NPOT"
-    new "NPOT (OpenGL 2+)"
+    new "Принудительный Программный"
 
     # 00gltest.rpy:93
     old "Enable"
-    new "Активировать"
+    new "Активировано"
 
     # 00gltest.rpy:97
     old "Disable"
-    new "Деактивировать"
+    new "Отключено"
 
-    # 00gltest.rpy:124
+    # 00gltest.rpy:109
     old "Changes will take effect the next time this program is run."
     new "Изменения вступят в силу при следующем запуске программы."
 
-    # 00gltest.rpy:156
+    # 00gltest.rpy:141
     old "Performance Warning"
     new "Предупреждение Производительности"
 
-    # 00gltest.rpy:161
+    # 00gltest.rpy:146
     old "This computer is using software rendering."
     new "Этот компьютер использует программный рендеринг."
 
-    # 00gltest.rpy:163
+    # 00gltest.rpy:148
     old "This computer is not using shaders."
     new "Этот компьютер не использует шейдеры."
 
-    # 00gltest.rpy:165
+    # 00gltest.rpy:150
     old "This computer is displaying graphics slowly."
     new "Этот компьютер медленно отображает графику."
 
-    # 00gltest.rpy:167
+    # 00gltest.rpy:152
     old "This computer has a problem displaying graphics: [problem]."
     new "У этого компьютера проблема с отображением графики: [problem]"
 
-    # 00gltest.rpy:172
+    # 00gltest.rpy:157
     old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display. Updating DirectX could fix this problem."
     new "Графические драйвера устарели или работают неверно. Это может привести к медленному или неверному отображению графики. Обновление DirectX может решить эту проблему."
 
-    # 00gltest.rpy:174
+    # 00gltest.rpy:159
     old "Its graphics drivers may be out of date or not operating correctly. This can lead to slow or incorrect graphics display."
     new "Графические драйвера устарели или работают неверно. Это может привести к медленному или неверному отображению графики."
 
-    # 00gltest.rpy:179
+    # 00gltest.rpy:164
     old "Update DirectX"
     new "Обновить DirectX"
 
-    # 00gltest.rpy:185
+    # 00gltest.rpy:170
     old "Continue, Show this warning again"
     new "Продолжить, Показать это предупреждение снова"
 
-    # 00gltest.rpy:189
+    # 00gltest.rpy:174
     old "Continue, Don't show warning again"
     new "Продолжить, Не показывать это предупреждение снова."
 
-    # 00gltest.rpy:207
+    # 00gltest.rpy:192
     old "Updating DirectX."
     new "Обновляю DirectX."
 
-    # 00gltest.rpy:211
+    # 00gltest.rpy:196
     old "DirectX web setup has been started. It may start minimized in the taskbar. Please follow the prompts to install DirectX."
     new "Установщик DirectX был запущен. Возможно, что он запустился в свёрнутом состоянии. Пожалуйста, следуйте инструкциям для установки DirectX."
 
-    # 00gltest.rpy:215
+    # 00gltest.rpy:200
     old "{b}Note:{/b} Microsoft's DirectX web setup program will, by default, install the Bing toolbar. If you do not want this toolbar, uncheck the appropriate box."
     new "{b}Предупреждение:{/b} Установщик DirectX по умолчанию пытается установить панель инструментов Bing. Если вы этого не хотите, снимите соответствующую галочку."
 
-    # 00gltest.rpy:219
+    # 00gltest.rpy:204
     old "When setup finishes, please click below to restart this program."
     new "По завершению установки, щёлкните, чтобы перезапустить программу."
 
-    # 00gltest.rpy:221
+    # 00gltest.rpy:206
     old "Restart"
     new "Перезапустить"
 
@@ -701,75 +469,618 @@ translate russian strings:
     old "Back (B)"
     new "Back (B)"
 
-    # _errorhandling.rpym:523
+    # _errorhandling.rpym:519
     old "Open"
     new "Журнал"
 
-    # _errorhandling.rpym:525
+    # _errorhandling.rpym:521
     old "Opens the traceback.txt file in a text editor."
     new "Открывает файл traceback.txt в текстовом редакторе."
 
-    # _errorhandling.rpym:527
+    # _errorhandling.rpym:523
     old "Copy"
     new "Копировать"
 
-    # _errorhandling.rpym:529
+    # _errorhandling.rpym:525
     old "Copies the traceback.txt file to the clipboard."
     new "Копирует файл traceback.txt в буфер обмена."
 
-    # _errorhandling.rpym:556
+    # _errorhandling.rpym:543
     old "An exception has occurred."
     new "Возникло исключение."
 
-    # _errorhandling.rpym:576
+    # _errorhandling.rpym:562
     old "Rollback"
     new "Назад"
 
-    # _errorhandling.rpym:578
+    # _errorhandling.rpym:564
     old "Attempts a roll back to a prior time, allowing you to save or choose a different choice."
     new "Пытается вернуться назад, позволяя вам сохраниться или принять другой выбор."
 
-    # _errorhandling.rpym:581
+    # _errorhandling.rpym:567
     old "Ignore"
     new "Игнорировать"
 
-    # _errorhandling.rpym:585
-    old "Ignores the exception, allowing you to continue."
-    new "Игнорирует исключение, позволяя вам продолжить."
-
-    # _errorhandling.rpym:587
+    # _errorhandling.rpym:569
     old "Ignores the exception, allowing you to continue. This often leads to additional errors."
     new "Игнорирует это исключение, позволяя вам продолжить. Зачастую это ведёт к дополнительным ошибкам."
 
-    # _errorhandling.rpym:591
+    # _errorhandling.rpym:572
     old "Reload"
     new "Перезагрузить"
 
-    # _errorhandling.rpym:593
+    # _errorhandling.rpym:574
     old "Reloads the game from disk, saving and restoring game state if possible."
     new "Перезагружает игру с диска, сохраняя и восстанавливая её состояние, если это возможно."
 
-    # _errorhandling.rpym:596
+    # _errorhandling.rpym:576
     old "Console"
     new "Консоль"
 
-    # _errorhandling.rpym:598
+    # _errorhandling.rpym:578
     old "Opens a console to allow debugging the problem."
     new "Открывает консоль, позволяющую отладить проблему."
 
-    # _errorhandling.rpym:608
+    # _errorhandling.rpym:590
     old "Quits the game."
     new "Выходит из игры."
 
-    # _errorhandling.rpym:632
+    # _errorhandling.rpym:614
     old "Parsing the script failed."
     new "Обработка сценария завершилась неудачно."
 
-    # _errorhandling.rpym:658
+    # _errorhandling.rpym:640
     old "Opens the errors.txt file in a text editor."
     new "Открывает файл errors.txt в текстовом редакторе."
 
-    # _errorhandling.rpym:662
+    # _errorhandling.rpym:644
     old "Copies the errors.txt file to the clipboard."
     new "Копирует файл errors.txt в буфер обмена."
 
+    # _developer/developer.rpym:38
+    old "Developer Menu"
+    new "Меню разработчика"
+
+    # _developer/developer.rpym:43
+    old "Reload Game (Shift+R)"
+    new "Перезагрузить игру (Shift+R)"
+
+    # _developer/developer.rpym:45
+    old "Console (Shift+O)"
+    new "Консоль (Shift+O)"
+
+    # _developer/developer.rpym:47
+    old "Variable Viewer"
+    new "Просмотр переменных"
+
+    # _developer/developer.rpym:49
+    old "Theme Test"
+    new "Theme Test"
+
+    # _developer/developer.rpym:51
+    old "Image Location Picker"
+    new "Инструмент позиционирования на изображениях"
+
+    # _developer/developer.rpym:53
+    old "Filename List"
+    new "Список файлов"
+
+    # _developer/developer.rpym:57
+    old "Show Image Load Log"
+    new "Show Image Load Log"
+
+    # _developer/developer.rpym:60
+    old "Hide Image Load Log"
+    new "Hide Image Load Log"
+
+    # _developer/developer.rpym:95
+    old "Nothing to inspect."
+    new "Переменные не заданы."
+
+    # _developer/developer.rpym:217
+    old "Return to the developer menu"
+    new "Вернуться в меню разработчика"
+
+    # _developer/developer.rpym:377
+    old "Rectangle: %r"
+    new "Прямоугольник: %r"
+
+    # _developer/developer.rpym:382
+    old "Mouse position: %r"
+    new "Позиция мыши: %r"
+
+    # _developer/developer.rpym:387
+    old "Right-click or escape to quit."
+    new "Нажмите правую кнопку мыши или ESC чтобы выйти."
+
+    # _developer/developer.rpym:419
+    old "Rectangle copied to clipboard."
+    new "Координаты прямоугольника скопированы в буфер обмена."
+
+    # _developer/developer.rpym:422
+    old "Position copied to clipboard."
+    new "Координаты позиции скопированы в буфер обмена."
+
+    # _developer/developer.rpym:531
+    old "✔ "
+    new "✔ "
+
+    # _developer/developer.rpym:534
+    old "✘ "
+    new "✘ "
+
+    # _developer/developer.rpym:539
+    old "\n{color=#cfc}✔ predicted image (good){/color}\n{color=#fcc}✘ unpredicted image (bad){/color}\n{color=#fff}Drag to move.{/color}"
+    new "\n{color=#cfc}✔ предсказанное изображение (хорошо){/color}\n{color=#fcc}✘ внезапное изображение (плохо){/color}\n{color=#fff}Нажмите, чтобы передвинуть.{/color}"
+
+    # _developer/inspector.rpym:38
+    old "Displayable Inspector"
+    new "Диспетчер объектов"
+
+    # _developer/inspector.rpym:61
+    old "Size"
+    new "Разрешение"
+
+    # _developer/inspector.rpym:65
+    old "Style"
+    new "Стиль"
+
+    # _developer/inspector.rpym:71
+    old "Location"
+    new "Местоположение"
+
+    # _developer/inspector.rpym:122
+    old "Inspecting Styles of [displayable_name!q]"
+    new "Инспектирую стили [displayable_name!q]"
+
+    # _developer/inspector.rpym:139
+    old "displayable:"
+    new "объект:"
+
+    # _developer/inspector.rpym:145
+    old "        (no properties affect the displayable)"
+    new "        (на объект не влияют никакие параметры)"
+
+    # _developer/inspector.rpym:147
+    old "        (default properties omitted)"
+    new "        (настройки по умолчанию опущены)"
+
+    # _developer/inspector.rpym:185
+    old "<repr() failed>"
+    new "<repr() провален>"
+
+    # 00console.rpy:208
+    old "Press <esc> to exit console. Type help for help.\n"
+    new "Нажмите <esc>, чтобы выйти из консоли. Введите help для помощи.\n"
+
+    # 00console.rpy:212
+    old "Ren'Py script enabled."
+    new "Ren'Py script активирован."
+
+    # 00console.rpy:214
+    old "Ren'Py script disabled."
+    new "Ren'Py script деактивирован."
+
+    # 00console.rpy:424
+    old "help: show this help"
+    new "help: показывает помощь"
+
+    # 00console.rpy:429
+    old "commands:\n"
+    new "команды:\n"
+
+    # 00console.rpy:439
+    old " <renpy script statement>: run the statement\n"
+    new " <оператор renpy script>: запуск оператора\n"
+
+    # 00console.rpy:441
+    old " <python expression or statement>: run the expression or statement"
+    new " <выражение или оператор python>: запустить выражение или оператор"
+
+    # 00console.rpy:449
+    old "clear: clear the console history"
+    new "clear: очищает историю консоли"
+
+    # 00console.rpy:453
+    old "exit: exit the console"
+    new "exit: выход из консоли"
+
+    # 00console.rpy:461
+    old "load <slot>: loads the game from slot"
+    new "load <слот>: загружает игру из выбранного слота"
+
+    # 00console.rpy:474
+    old "save <slot>: saves the game in slot"
+    new "save <слот>: сохраняет игру в выбранный слот"
+
+    # 00console.rpy:485
+    old "reload: reloads the game, refreshing the scripts"
+    new "reload: перезагружает игру, обновляет скрипты"
+
+    # 00console.rpy:493
+    old "watch <expression>: watch a python expression"
+    new "watch <выражение>: наблюдать за выражением python"
+
+    # 00console.rpy:519
+    old "unwatch <expression>: stop watching an expression"
+    new "unwatch <выражение>: прекратить наблюдать за выражением"
+
+    # 00console.rpy:550
+    old "unwatchall: stop watching all expressions"
+    new "unwatchall: глобальное прекращение наблюдения"
+
+    # 00console.rpy:567
+    old "jump <label>: jumps to label"
+    new "jump <label>: прыжок на метку"
+
+
+translate None strings:
+
+    # 00action_file.rpy:344
+    old "Save slot %s: [text]"
+    new "Слот сохранения %s: [text]"
+
+    # 00action_file.rpy:417
+    old "Load slot %s: [text]"
+    new "Слот загрузки %s: [text]"
+
+    # 00action_file.rpy:459
+    old "Delete slot [text]"
+    new "Удалить слот [text]"
+
+    # 00action_file.rpy:539
+    old "File page auto"
+    new "Автосохранения"
+
+    # 00action_file.rpy:541
+    old "File page quick"
+    new "Быстрые сохранения"
+
+    # 00action_file.rpy:543
+    old "File page [text]"
+    new "Страница сохранений [text]"
+
+    # 00action_file.rpy:733
+    old "Next file page."
+    new "Следующая страница сохранений"
+
+    # 00action_file.rpy:797
+    old "Previous file page."
+    new "Предыдущая страница сохранений"
+
+    # 00action_file.rpy:876
+    old "Quick save."
+    new "Быстрое сохранение"
+
+    # 00action_file.rpy:895
+    old "Quick load."
+    new "Быстрая загрузка"
+
+    # 00action_other.rpy:344
+    old "Language [text]"
+    new "Язык [text]"
+
+    # 00director.rpy:703
+    old "The interactive director is not enabled here."
+    new "Интерактивный директор недоступен."
+
+    # 00director.rpy:1490
+    old "Done"
+    new "Принять"
+
+    # 00director.rpy:1498
+    old "(statement)"
+    new "(функция)"
+
+    # 00director.rpy:1499
+    old "(tag)"
+    new "(тег)"
+
+    # 00director.rpy:1500
+    old "(attributes)"
+    new "(аттрибут)"
+
+    # 00director.rpy:1501
+    old "(transform)"
+    new "(трансформация)"
+
+    # 00director.rpy:1526
+    old "(transition)"
+    new "(переход)"
+
+    # 00director.rpy:1538
+    old "(channel)"
+    new "(канал)"
+
+    # 00director.rpy:1539
+    old "(filename)"
+    new "(имя файла)"
+
+    # 00director.rpy:1564
+    old "Change"
+    new "Изменить"
+
+    # 00director.rpy:1566
+    old "Add"
+    new "Добавить"
+
+    # 00director.rpy:1572
+    old "Remove"
+    new "Убрать"
+
+    # 00director.rpy:1605
+    old "Statement:"
+    new "Функции:"
+
+    # 00director.rpy:1626
+    old "Tag:"
+    new "Теги:"
+
+    # 00director.rpy:1642
+    old "Attributes:"
+    new "Аттрибут:"
+
+    # 00director.rpy:1660
+    old "Transforms:"
+    new "Трансформации:"
+
+    # 00director.rpy:1679
+    old "Behind:"
+    new "Позади:"
+
+    # 00director.rpy:1698
+    old "Transition:"
+    new "Переходы:"
+
+    # 00director.rpy:1716
+    old "Channel:"
+    new "Каналы:"
+
+    # 00director.rpy:1734
+    old "Audio Filename:"
+    new "Имя файла:"
+
+    # 00keymap.rpy:258
+    old "Failed to save screenshot as %s."
+    new "Провалена попытка сохранить скриншот как %s."
+
+    # 00library.rpy:150
+    old "bar"
+    new ". Полоса настройки"
+
+    # 00library.rpy:151
+    old "selected"
+    new ". На данный момент это выбрано"
+
+    # 00library.rpy:152
+    old "viewport"
+    new "порт просмотра"
+
+    # 00library.rpy:153
+    old "horizontal scroll"
+    new ". горизонтальная полоса прокрутки"
+
+    # 00library.rpy:154
+    old "vertical scroll"
+    new ". вертикальная полоса прокрутки"
+
+    # 00library.rpy:155
+    old "activate"
+    new "элемент активирован"
+
+    # 00library.rpy:156
+    old "deactivate"
+    new "элемент деактивирован"
+
+    # 00library.rpy:157
+    old "increase"
+    new "больше"
+
+    # 00library.rpy:158
+    old "decrease"
+    new "меньше"
+
+    # 00preferences.rpy:207
+    old "display"
+    new "режим экрана"
+
+    # 00preferences.rpy:219
+    old "transitions"
+    new "переходы"
+
+    # 00preferences.rpy:228
+    old "skip transitions"
+    new "пропускать переходы"
+
+    # 00preferences.rpy:230
+    old "video sprites"
+    new "видео-спрайты"
+
+    # 00preferences.rpy:239
+    old "show empty window"
+    new "показывать пустое окно диалога"
+
+    # 00preferences.rpy:248
+    old "text speed"
+    new "скорость текста"
+
+    # 00preferences.rpy:256
+    old "joystick"
+    new "джойстик"
+
+    # 00preferences.rpy:256
+    old "joystick..."
+    new "джойстик..."
+
+    # 00preferences.rpy:263
+    old "skip"
+    new "пропускать"
+
+    # 00preferences.rpy:266
+    old "skip unseen [text]"
+    new "пропускать весь [text]"
+
+    # 00preferences.rpy:271
+    old "skip unseen text"
+    new "пропускать весь текст"
+
+    # 00preferences.rpy:273
+    old "begin skipping"
+    new "начать пропуск"
+
+    # 00preferences.rpy:277
+    old "after choices"
+    new "после выборов"
+
+    # 00preferences.rpy:284
+    old "skip after choices"
+    new "пропускать после выборов"
+
+    # 00preferences.rpy:286
+    old "auto-forward time"
+    new "скорость авточтения"
+
+    # 00preferences.rpy:300
+    old "auto-forward"
+    new "авточтение"
+
+    # 00preferences.rpy:307
+    old "Auto forward"
+    new "Авточтение"
+
+    # 00preferences.rpy:310
+    old "auto-forward after click"
+    new "продолжать авточтение после клика"
+
+    # 00preferences.rpy:319
+    old "automatic move"
+    new "автоматически передвигать мышь к кнопке"
+
+    # 00preferences.rpy:328
+    old "wait for voice"
+    new "ждать голос"
+
+    # 00preferences.rpy:337
+    old "voice sustain"
+    new "не останавливать голос"
+
+    # 00preferences.rpy:346
+    old "self voicing"
+    new "озвучка через синтезатор речи"
+
+    # 00preferences.rpy:355
+    old "clipboard voicing"
+    new "синтез речи из буфера обмена"
+
+    # 00preferences.rpy:364
+    old "debug voicing"
+    new "режим дебага синтеза речи"
+
+    # 00preferences.rpy:373
+    old "emphasize audio"
+    new "усилить громкость заранее заданных звуковых каналов за счёт приглушения остальных каналов"
+
+    # 00preferences.rpy:382
+    old "rollback side"
+    new "сторона отката"
+
+    # 00preferences.rpy:392
+    old "gl powersave"
+    new "настройка графики. Экономия энергии"
+
+    # 00preferences.rpy:398
+    old "gl framerate"
+    new "настройка графики. Частота кадров"
+
+    # 00preferences.rpy:401
+    old "gl tearing"
+    new "настройка графики. Разрывание кадров"
+
+    # 00preferences.rpy:413
+    old "music volume"
+    new "громкость музыки"
+
+    # 00preferences.rpy:414
+    old "sound volume"
+    new "громкость звуков"
+
+    # 00preferences.rpy:415
+    old "voice volume"
+    new "громкость голоса"
+
+    # 00preferences.rpy:416
+    old "mute music"
+    new "без музыки"
+
+    # 00preferences.rpy:417
+    old "mute sound"
+    new "без звуков"
+
+    # 00preferences.rpy:418
+    old "mute voice"
+    new "без голоса"
+
+    # 00preferences.rpy:419
+    old "mute all"
+    new "режим без звука"
+
+    # 00gltest.rpy:70
+    old "Renderer"
+    new "Рендер"
+
+    # 00gltest.rpy:93
+    old "NPOT"
+    new "NPOT (OpenGL 2+)"
+
+    # 00gltest.rpy:131
+    old "Powersave"
+    new "Экономия энергии"
+
+    # 00gltest.rpy:145
+    old "Framerate"
+    new "Частота кадров"
+
+    # 00gltest.rpy:149
+    old "Screen"
+    new "Экранная"
+
+    # 00gltest.rpy:153
+    old "60"
+    new "60"
+
+    # 00gltest.rpy:157
+    old "30"
+    new "30"
+
+    # 00gltest.rpy:163
+    old "Tearing"
+    new "Разрывание кадров"
+
+    # _errorhandling.rpym:590
+    old "Ignores the exception, allowing you to continue."
+    new "Игнорирует это исключение, позволяя вам продолжить."
+
+    # _developer/developer.rpym:43
+    old "Interactive Director (D)"
+    new "Интерактивный Директор (D)"
+
+    # _developer/developer.rpym:57
+    old "Show Image Load Log (F4)"
+    new "Показать лог загрузки изображений (F4)"
+
+    # _developer/developer.rpym:60
+    old "Hide Image Load Log (F4)"
+    new "Скрыть лог загрузки изображений (F4)"
+
+    # _developer/developer.rpym:447
+    old "Type to filter: "
+    new "Текущий фильтр: "
+
+    # _developer/developer.rpym:575
+    old "Textures: [tex_count] ([tex_size_mb:.1f] MB)"
+    new "Текстур: [tex_count] ([tex_size_mb:.1f] МБ)"
+
+    # _developer/developer.rpym:579
+    old "Image cache: [cache_pct:.1f]% ([cache_size_mb:.1f] MB)"
+    new "Кеш изображений: [cache_pct:.1f]% ([cache_size_mb:.1f] МБ)"
+
diff --git a/tutorial/game/tl/russian/indepth_minigame.rpy b/tutorial/game/tl/russian/indepth_minigame.rpy
index c62edeb..9b0803b 100644
--- a/tutorial/game/tl/russian/indepth_minigame.rpy
+++ b/tutorial/game/tl/russian/indepth_minigame.rpy
@@ -66,9 +66,9 @@ translate russian pong_done_5781d902:
     e "Мини-игры могут добавить в вашу визуальную новеллу свою остринку, но будьте осторожны — не каждый игрок хорош в аркадных играх."
 
 # game/indepth_minigame.rpy:276
-translate russian pong_done_849cf6db:
+translate russian pong_done_631325c8:
 
-    # e "Part of the reason Ren'Py works well it's that it's meant for certain types of games, like visual novels and life simulations."
+    # e "Part of the reason Ren'Py works well is that it's meant for certain types of games, like visual novels and life simulations."
     e "Одна из причин, почему Ren'Py так хорошо справляется со своей ролью, состоит в том, что он предназначен для определённого типа игр: визуальных новелл, симуляторов жизни и похожих жанров."
 
 # game/indepth_minigame.rpy:278
diff --git a/tutorial/game/tl/russian/screens.rpy b/tutorial/game/tl/russian/screens.rpy
index 1a43a94..f8db997 100644
--- a/tutorial/game/tl/russian/screens.rpy
+++ b/tutorial/game/tl/russian/screens.rpy
@@ -65,263 +65,263 @@ translate russian strings:
     old "Quit"
     new "Выход"
 
-    # screens.rpy:474
+    # screens.rpy:480
     old "Return"
     new "Вернуться"
 
-    # screens.rpy:558
+    # screens.rpy:564
     old "Version [config.version!t]\n"
     new "Версия [config.version!t]\n"
 
-    # screens.rpy:564
+    # screens.rpy:570
     old "Made with {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]"
     new "Сделано с помощью {a=https://www.renpy.org/}Ren'Py{/a} [renpy.version_only].\n\n[renpy.license!t]"
 
-    # screens.rpy:604
+    # screens.rpy:610
     old "Page {}"
     new "{} страница"
 
-    # screens.rpy:604
+    # screens.rpy:610
     old "Automatic saves"
     new "Автосохранения"
 
-    # screens.rpy:604
+    # screens.rpy:610
     old "Quick saves"
     new "Быстрые сохранения"
 
-    # screens.rpy:646
+    # screens.rpy:652
     old "{#file_time}%A, %B %d %Y, %H:%M"
     new "{#file_time}%A, %d %B %Y, %H:%M"
 
-    # screens.rpy:646
+    # screens.rpy:652
     old "empty slot"
     new "Пустой слот"
 
-    # screens.rpy:663
+    # screens.rpy:669
     old "<"
     new "<"
 
-    # screens.rpy:666
+    # screens.rpy:672
     old "{#auto_page}A"
     new "{#auto_page}А"
 
-    # screens.rpy:669
+    # screens.rpy:675
     old "{#quick_page}Q"
     new "{#quick_page}Б"
 
-    # screens.rpy:675
+    # screens.rpy:681
     old ">"
     new ">"
 
-    # screens.rpy:737
+    # screens.rpy:743
     old "Display"
     new "Режим экрана"
 
-    # screens.rpy:738
+    # screens.rpy:744
     old "Window"
     new "Оконный"
 
-    # screens.rpy:739
+    # screens.rpy:745
     old "Fullscreen"
     new "Полный"
 
-    # screens.rpy:751
+    # screens.rpy:757
     old "Unseen Text"
     new "Всего текста"
 
-    # screens.rpy:752
+    # screens.rpy:758
     old "After Choices"
     new "После выборов"
 
-    # screens.rpy:758
+    # screens.rpy:764
     old "Examples"
     new "Примеры"
 
-    # screens.rpy:767
+    # screens.rpy:773
     old "Language"
     new "Язык"
 
-    # screens.rpy:787
+    # screens.rpy:793
     old "Text Speed"
     new "Скорость текста"
 
-    # screens.rpy:791
+    # screens.rpy:797
     old "Auto-Forward Time"
     new "Скорость авточтения"
 
-    # screens.rpy:798
+    # screens.rpy:804
     old "Music Volume"
     new "Громкость музыки"
 
-    # screens.rpy:805
+    # screens.rpy:811
     old "Sound Volume"
     new "Громкость звука"
 
-    # screens.rpy:811
+    # screens.rpy:817
     old "Test"
     new "Тест"
 
-    # screens.rpy:815
+    # screens.rpy:821
     old "Voice Volume"
     new "Громкость голоса"
 
-    # screens.rpy:826
+    # screens.rpy:832
     old "Mute All"
     new "Без звука"
 
-    # screens.rpy:942
+    # screens.rpy:948
     old "The dialogue history is empty."
     new "История диалогов пуста."
 
-    # screens.rpy:1007
+    # screens.rpy:1013
     old "Keyboard"
     new "Клавиатура"
 
-    # screens.rpy:1008
+    # screens.rpy:1014
     old "Mouse"
     new "Мышь"
 
-    # screens.rpy:1011
+    # screens.rpy:1017
     old "Gamepad"
     new "Геймпад"
 
-    # screens.rpy:1024
+    # screens.rpy:1030
     old "Enter"
     new "Enter"
 
-    # screens.rpy:1025
+    # screens.rpy:1031
     old "Advances dialogue and activates the interface."
     new "Прохождение диалогов и активация интерфейса."
 
-    # screens.rpy:1028
+    # screens.rpy:1034
     old "Space"
     new "Пробел"
 
-    # screens.rpy:1029
+    # screens.rpy:1035
     old "Advances dialogue without selecting choices."
     new "Прохождение диалогов, но не позволяет делать выбор."
 
-    # screens.rpy:1032
+    # screens.rpy:1038
     old "Arrow Keys"
     new "Стрелки"
 
-    # screens.rpy:1033
+    # screens.rpy:1039
     old "Navigate the interface."
     new "Навигация по интерфейсу."
 
-    # screens.rpy:1036
+    # screens.rpy:1042
     old "Escape"
     new "Esc"
 
-    # screens.rpy:1037
+    # screens.rpy:1043
     old "Accesses the game menu."
     new "Вход в игровое меню."
 
-    # screens.rpy:1040
+    # screens.rpy:1046
     old "Ctrl"
     new "Ctrl"
 
-    # screens.rpy:1041
+    # screens.rpy:1047
     old "Skips dialogue while held down."
     new "Пропускает диалоги, пока зажат."
 
-    # screens.rpy:1044
+    # screens.rpy:1050
     old "Tab"
     new "Tab"
 
-    # screens.rpy:1045
+    # screens.rpy:1051
     old "Toggles dialogue skipping."
     new "Включает режим пропуска."
 
-    # screens.rpy:1048
+    # screens.rpy:1054
     old "Page Up"
     new "Page Up"
 
-    # screens.rpy:1049
+    # screens.rpy:1055
     old "Rolls back to earlier dialogue."
     new "Откат назад по сюжету игры."
 
-    # screens.rpy:1052
+    # screens.rpy:1058
     old "Page Down"
     new "Page Down"
 
-    # screens.rpy:1053
+    # screens.rpy:1059
     old "Rolls forward to later dialogue."
     new "Откатывает предыдущее действие вперёд."
 
-    # screens.rpy:1057
+    # screens.rpy:1063
     old "Hides the user interface."
     new "Скрывает интерфейс пользователя."
 
-    # screens.rpy:1061
+    # screens.rpy:1067
     old "Takes a screenshot."
     new "Делает снимок экрана."
 
-    # screens.rpy:1065
+    # screens.rpy:1071
     old "Toggles assistive {a=https://www.renpy.org/l/voicing}self-voicing{/a}."
     new "Включает поддерживаемый {a=https://www.renpy.org/l/voicing}синтезатор речи{/a}."
 
-    # screens.rpy:1071
+    # screens.rpy:1077
     old "Left Click"
     new "Левый клик"
 
-    # screens.rpy:1075
+    # screens.rpy:1081
     old "Middle Click"
     new "Клик колёсиком"
 
-    # screens.rpy:1079
+    # screens.rpy:1085
     old "Right Click"
     new "Правый клик"
 
-    # screens.rpy:1083
+    # screens.rpy:1089
     old "Mouse Wheel Up\nClick Rollback Side"
     new "Колёсико вверх\nКлик на сторону отката"
 
-    # screens.rpy:1087
+    # screens.rpy:1093
     old "Mouse Wheel Down"
     new "Колёсико вниз"
 
-    # screens.rpy:1094
+    # screens.rpy:1100
     old "Right Trigger\nA/Bottom Button"
     new "Правый триггер\nA/Нижняя кнопка"
 
-    # screens.rpy:1098
+    # screens.rpy:1104
     old "Left Trigger\nLeft Shoulder"
     new "Левый Триггер\nЛевый Бампер"
 
-    # screens.rpy:1102
+    # screens.rpy:1108
     old "Right Shoulder"
     new "Правый бампер"
 
-    # screens.rpy:1106
+    # screens.rpy:1112
     old "D-Pad, Sticks"
     new "Крестовина, Стики"
 
-    # screens.rpy:1110
+    # screens.rpy:1116
     old "Start, Guide"
     new "Start, Guide"
 
-    # screens.rpy:1114
+    # screens.rpy:1120
     old "Y/Top Button"
     new "Y/Верхняя кнопка"
 
-    # screens.rpy:1117
+    # screens.rpy:1123
     old "Calibrate"
     new "Калибровка"
 
-    # screens.rpy:1182
+    # screens.rpy:1188
     old "Yes"
     new "Да"
 
-    # screens.rpy:1183
+    # screens.rpy:1189
     old "No"
     new "Нет"
 
-    # screens.rpy:1229
+    # screens.rpy:1235
     old "Skipping"
     new "Пропускаю"
 
-    # screens.rpy:1450
+    # screens.rpy:1456
     old "Menu"
     new "Меню"
 
diff --git a/tutorial/game/tl/russian/script.rpy b/tutorial/game/tl/russian/script.rpy
index 9335d87..36fc4d0 100644
--- a/tutorial/game/tl/russian/script.rpy
+++ b/tutorial/game/tl/russian/script.rpy
@@ -11,37 +11,37 @@ translate russian start_d3abb53c:
     # e "In this tutorial, we'll teach you the basics of Ren'Py, so you can make games of your own. We'll also demonstrate many features, so you can see what Ren'Py is capable of."
     e "Здесь мы обучим вас основам Ren'Py, чтобы вы сами могли создавать свои игры. Мы также продемонстрируем множество разнообразных возможностей, чтобы вы увидели, на что способен Ren'Py."
 
-# game/script.rpy:202
+# game/script.rpy:205
 translate russian end_b2482727:
 
     # e "Thank you for viewing this tutorial."
     e "Спасибо за просмотр этого обучения."
 
-# game/script.rpy:204
+# game/script.rpy:207
 translate russian end_38362e36:
 
     # e "If you'd like to see a full Ren'Py game, select \"The Question\" in the launcher."
     e "Если вы хотите увидеть полноценную Ren'Py-игру, выберите \"Вопрос\" в Launcher."
 
-# game/script.rpy:206
+# game/script.rpy:209
 translate russian end_02527d05:
 
     # e "You can download new versions of Ren'Py from {a=https://www.renpy.org/}https://www.renpy.org/{/a}. For help and discussion, check out the {a=https://lemmasoft.renai.us/forums/}Lemma Soft Forums{/a}."
     e "Вы можете скачать новые версии Ren'Py с {a=https://www.renpy.org/}https://www.renpy.org/{/a}. Для помощи и обсуждения, смотрите {a=https://lemmasoft.renai.us/forums/}форумы Lemma Soft{/a}."
 
-# game/script.rpy:208
+# game/script.rpy:211
 translate russian end_c9d03136:
 
     # e "We'd like to thank Piroshki for contributing my sprites; Mugenjohncel for Lucy, the band, and drawn backgrounds; and Jake for the magic circle."
     e "Мы хотели бы поблагодарить Piroshki за мои изображения, Mugenjohncel за Люси, рок-группу и фоны, и Jake — за волшебный круг."
 
-# game/script.rpy:210
+# game/script.rpy:213
 translate russian end_762dc07a:
 
     # e "The background music is \"Sunflower Slow Drag\", by Scott Joplin and Scott Hayden, performed by the United States Marine Band. The concert music is by Alessio."
     e "Музыка, играющая на заднем фоне — \"Sunflower Slow Drag\", написанная Scott Joplin и Scott Hayden, и исполненная United States Marine Band. Музыка концерта написана Alessio."
 
-# game/script.rpy:214
+# game/script.rpy:217
 translate russian end_a634d396:
 
     # e "We look forward to seeing what you create with Ren'Py. Have fun!"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/renpy.git



More information about the Pkg-games-commits mailing list