Esempio n. 1
0
    def convert_field(self, value, conversion):
        value, kwargs = value

        if conversion is None:
            return value

        if not conversion:
            raise ValueError("Conversion specifier can't be empty.")

        if set(conversion) - set("rstqulci!"):
            raise ValueError(
                "Unknown symbols in conversion specifier, this must use only the \"rstqulci\"."
            )

        if "r" in conversion:
            value = repr(value)
            conversion = conversion.replace("r", "")
        elif "s" in conversion:
            value = str(value)
            conversion = conversion.replace("s", "")

        if not conversion:
            return value

        # All conversion symbols below assume we have a string.
        if not isinstance(value, basestring):
            value = str(value)

        if "t" in conversion:
            value = renpy.translation.translate_string(value)

        if "i" in conversion:
            try:
                value = self.vformat(value, (), kwargs)
            except RuntimeError:  # PY3 RecursionError
                raise ValueError(
                    "Substitution {!r} refers to itself in a loop.".format(
                        value))

        if "q" in conversion:
            value = value.replace("{", "{{")

        if "u" in conversion:
            value = value.upper()

        if "l" in conversion:
            value = value.lower()

        if "c" in conversion and value:
            value = value[0].upper() + value[1:]

        return value
Esempio n. 2
0
def cycle_saves(name, count):
    """
    :doc: loadsave

    Rotates the first `count` saves beginning with `name`.

    For example, if the name is auto- and the count is 10, then
    auto-9 will be renamed to auto-10, auto-8 will be renamed to auto-9,
    and so on until auto-1 is renamed to auto-2.
    """

    for i in range(count - 1, 0, -1):
        rename_save(name + str(i), name + str(i + 1))
Esempio n. 3
0
def detect_user_locale():
    import locale
    if renpy.windows:
        import ctypes
        windll = ctypes.windll.kernel32  # type: ignore
        locale_name = locale.windows_locale.get(
            windll.GetUserDefaultUILanguage())
    elif renpy.android:
        from jnius import autoclass  # type: ignore
        Locale = autoclass('java.util.Locale')
        locale_name = str(Locale.getDefault().getLanguage())
    elif renpy.ios:
        import pyobjus  # type: ignore
        NSLocale = pyobjus.autoclass("NSLocale")
        languages = NSLocale.preferredLanguages()
        locale_name = languages.objectAtIndex_(0).UTF8String().decode("utf-8")
        locale_name.replace("-", "_")
    else:
        locale_name = locale.getdefaultlocale()
        if locale_name is not None:
            locale_name = locale_name[0]

    if locale_name is None:
        return None, None

    normalize = locale.normalize(locale_name)
    if normalize == locale_name:
        language = region = locale_name
    else:
        locale_name = normalize
        if '.' in locale_name:
            locale_name, _ = locale_name.split('.', 1)
        language, region = locale_name.lower().split("_")
    return language, region
Esempio n. 4
0
    def write(self, s):

        if not isinstance(s, str):
            s = str(s, "utf-8", "replace")

        if not renpy.config.log_to_stdout:
            self.real_file.write(s)
            self.real_file.flush()

        if renpy.ios:
            return

        s = self.buffer + s

        lines = s.split("\n")

        try:
            callbacks = self.get_callbacks()
        except:
            callbacks = []

        for l in lines[:-1]:
            self.log.write("%s", l)

            for i in callbacks:
                try:
                    i(l)
                except:
                    pass

        self.buffer = lines[-1]
Esempio n. 5
0
    def enqueue(self, filenames, loop=True, synchro_start=False, fadein=0, tight=None, loop_only=False, relative_volume=1.0):

        with lock:

            for filename in filenames:
                filename, _, _ = self.split_filename(filename, False)
                renpy.game.persistent._seen_audio[str(filename)] = True # type: ignore

            if not loop_only:

                if tight is None:
                    tight = self.tight

                self.keep_queue += 1

                for filename in filenames:
                    qe = QueueEntry(filename, fadein, tight, False, relative_volume)
                    self.queue.append(qe)

                    # Only fade the first thing in.
                    fadein = 0

                self.wait_stop = synchro_start
                self.synchro_start = synchro_start

            if loop:
                self.loop = list(filenames)
            else:
                self.loop = [ ]
Esempio n. 6
0
def check_text_tags(s):
    """
    :doc: lint

    Checks the text tags in s for correctness. Returns an error string if there is
    an error, or None if there is no error.
    """

    all_tags = dict(text_tags)

    custom_tags = renpy.config.custom_text_tags
    if custom_tags:
        all_tags.update(custom_tags)

    self_closing_custom_tags = renpy.config.self_closing_custom_text_tags
    if self_closing_custom_tags:
        all_tags.update(dict.fromkeys(self_closing_custom_tags, False))

    try:
        tokens = textsupport.tokenize(str(s))
    except Exception as e:
        return e.args[0]

    tag_stack = []

    for type, text in tokens:  # @ReservedAssignment
        if type != TAG:
            continue

        if text[0] == "#":
            continue

        # Strip off arguments for tags.
        if text.find('=') != -1:
            text = text[:text.find('=')]

        # Closing tag.
        if text and text[0] == '/':
            if not tag_stack:
                return "Close text tag '%s' does not match an open text tag." % text

            if tag_stack[-1] != text[1:]:
                return "Close text tag '%s' does not match open text tag '%s'." % (
                    text, tag_stack[-1])

            tag_stack.pop()
            continue

        if text not in all_tags:
            return "Text tag '%s' is not known." % text

        if all_tags[text]:
            tag_stack.append(text)

    if tag_stack:
        return "One or more text tags were left open at the end of the string: " + ", ".join(
            ["'" + i + "'" for i in tag_stack])

    return None
Esempio n. 7
0
    def write_dialogue(self):
        """
        Writes the dialogue to the file.
        """

        lines = []

        translator = renpy.game.script.translator

        for label, t in translator.file_translates[self.filename]:

            if label is None:
                label = ""

            for n in t.block:

                if isinstance(n, renpy.ast.Say):

                    if not n.who:
                        who = ""
                    else:
                        who = n.who

                    what = n.what

                    if self.notags:
                        what = notags_filter(what)

                    if self.escape:
                        what = quote_unicode(what)
                    elif self.tdf:
                        what = what.replace("\\", "\\\\")
                        what = what.replace("\t", "\\t")
                        what = what.replace("\n", "\\n")

                    if self.tdf:

                        lines.append([
                            t.identifier,
                            who,
                            what,
                            n.filename,
                            str(n.linenumber),
                            n.get_code(what_filter)
                            ])

                    else:
                        lines.append([what])

        if self.strings:
            lines.extend(self.get_strings())

            # If we're tab-delimited, we have line number info, which means we
            # can sort the list so everything's in order, for menus and stuff.
            if self.tdf:
                lines.sort(key=lambda x: int(x[4]))

        for line in lines:
            self.f.write("\t".join(line) + "\n")
Esempio n. 8
0
def interact(type='misc', roll_forward=None, **kwargs):  # @ReservedAssignment
    """
    :doc: ui
    :args: (roll_forward=None, mouse='default')

    Causes an interaction with the user, and returns the result of that
    interaction. This causes Ren'Py to redraw the screen and begin processing
    input events. When a displayable returns a value in response to an event,
    that value is returned from ui.interact, and the interaction ends.

    This function is rarely called directly. It is usually called by other
    parts of Ren'Py, including the say statement, menu statement, with statement,
    pause statement, call screen, :func:`renpy.input`, among many other
    functions. However, it can be called directly if necessary.

    When an interaction ends, the transient layer and all screens shown with
    transient=True are cleared from the scene lists.

    The following arguments are documented. As other, undocumented arguments
    exist for Ren'Py's internal use, please pass all arguments as keyword
    arguments.

    `roll_forward`
        The information that will be returned by this function when a
        roll forward occurs. (If None, the roll forward is ignored.) This
        should usually be passed the result of the :func:`renpy.roll_forward_info`
        function.

    `mouse`
        The style of mouse cursor to use during this function.
    """

    if stack is None:
        raise Exception("Interaction not allowed during init phase.")

    if renpy.config.skipping == "fast":
        renpy.config.skipping = None

    if len(stack) != 1:
        raise Exception(
            "ui.interact called with non-empty widget/layer stack. Did you forget a ui.close() somewhere?\nStack was "
            + ('\n'.join([str(item) for item in stack])))

    if at_stack:
        raise Exception("ui.interact called with non-empty at stack.")

    renpy.game.context().info._current_interact_type = type
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
    renpy.game.context().info._last_interact_type = type

    if renpy.exports.in_fixed_rollback() and roll_forward is not None:
        return roll_forward
    else:
        return rv
Esempio n. 9
0
def humanize(n):
    s = str(n)

    rv = []

    for i, c in enumerate(reversed(s)):
        if i and not (i % 3):
            rv.insert(0, ',')

        rv.insert(0, c)

    return ''.join(rv)
Esempio n. 10
0
def filter_text_tags(s, allow=None, deny=None):
    """
    :doc: text_utility

    Returns a copy of `s` with the text tags filtered. Exactly one of the `allow` and `deny` keyword
    arguments must be given.

    `allow`
        A set of tags that are allowed. If a tag is not in this list, it is removed.

    `deny`
        A set of tags that are denied. If a tag is not in this list, it is kept in the string.
    """

    if (allow is None) and (deny is None):
        raise Exception(
            "Only one of the allow and deny keyword arguments should be given to filter_text_tags."
        )

    if (allow is not None) and (deny is not None):
        raise Exception(
            "Only one of the allow and deny keyword arguments should be given to filter_text_tags."
        )

    tokens = textsupport.tokenize(str(s))

    rv = []

    for tokentype, text in tokens:

        if tokentype == PARAGRAPH:
            rv.append("\n")
        elif tokentype == TAG:
            kind = text.partition("=")[0]

            if kind and (kind[0] == "/"):
                kind = kind[1:]

            if allow is not None:
                if kind in allow:
                    rv.append("{" + text + "}")
            else:
                if kind not in deny:
                    rv.append("{" + text + "}")
        else:
            rv.append(text.replace("{", "{{"))

    return "".join(rv)
Esempio n. 11
0
def substitute(s, scope=None, force=False, translate=True):
    """
    Performs translation and formatting on `s`, as necessary.

    `scope`
        The scope which is used in formatting, in addition to the default
        store.

    `force`
        Force substitution to occur, even if it's disabled in the config.

    `translate`
        Determines if translation occurs.

    Returns the substituted string, and a flag that is True if substitution
    occurred, or False if no substitution occurred.
    """

    if not isinstance(s, basestring):
        s = str(s)

    if translate:
        s = renpy.translation.translate_string(s)

    # Substitute.
    if not renpy.config.new_substitutions and not force:
        return s, False

    if "[" not in s:
        return s, False

    old_s = s

    if scope is not None:
        kwargs = MultipleDict(scope,
                              renpy.store.__dict__)  # @UndefinedVariable
    else:
        kwargs = renpy.store.__dict__  # @UndefinedVariable

    try:
        s = formatter.vformat(s, (), kwargs)  # type: ignore
    except Exception:
        if renpy.display.predict.predicting:  # @UndefinedVariable
            return " ", True
        raise

    return s, (s != old_s)
Esempio n. 12
0
def create_store(name):
    """
    Creates the store with `name`.
    """

    parent, _, var = name.rpartition('.')

    if parent:
        create_store(parent)

    name = str(name)

    if name in initialized_store_dicts:
        return

    initialized_store_dicts.add(name)

    # Create the dict.
    d = store_dicts.setdefault(name, StoreDict())
    d.reset()

    pyname = pystr(name)

    # Set the name.
    d["__name__"] = pyname
    d["__package__"] = pyname

    # Set up the default contents of the store.
    eval("1", d)

    for k, v in renpy.minstore.__dict__.items():
        if k not in d:
            d[k] = v

    # Create or reuse the corresponding module.
    if name in store_modules:
        sys.modules[pyname] = store_modules[name]
    else:
        store_modules[name] = sys.modules[pyname] = StoreModule(
            d)  # type: ignore

    if parent:
        store_dicts[parent][var] = sys.modules[pyname]
Esempio n. 13
0
        def parse_keyword(l, expect):
            name = l.word()

            if name is None:
                l.error(expect)

            if name not in self.keyword:
                l.error('%r is not a keyword argument or valid child for the %s statement.' % (name, self.name))

            if name in seen_keywords:
                l.error('keyword argument %r appears more than once in a %s statement.' % (name, self.name))

            seen_keywords.add(name)

            expr = self.parse_comma_expression(l)

            call_node.keywords.append(
                ast.keyword(arg=str(name), value=expr),
                )
Esempio n. 14
0
    def get_strings(self):
        """
        Finds the strings in the file.
        """

        lines = []

        filename = renpy.parser.elide_filename(self.filename)

        for ss in renpy.translation.scanstrings.scan_strings(self.filename):

            line = ss.line
            s = ss.text

            stl = renpy.game.script.translator.strings[None] # @UndefinedVariable

            # don't include s in common.rpym
            if s in stl.translations:
                continue

            # avoid to include same s
            stl.translations[s] = s

            s = renpy.translation.translate_string(s, self.language)

            if self.notags:
                s = notags_filter(s)

            if self.escape:
                s = quote_unicode(s)

            elif self.tdf:
                s = s.replace("\\", "\\\\")
                s = s.replace("\t", "\\t")
                s = s.replace("\n", "\\n")

            if self.tdf:
                lines.append(["", "", s, filename, str(line)])

            else:
                lines.append([s])

        return lines
Esempio n. 15
0
def filter_alt_text(s):
    """
    Returns a copy of `s` with the contents of text tags that shouldn't be in
    alt text filtered. This returns just the text to say, with no text tags
    at all in it.
    """

    tokens = textsupport.tokenize(str(s))

    if renpy.config.custom_text_tags or renpy.config.self_closing_custom_text_tags or (
            renpy.config.replace_text is not None):
        tokens = renpy.text.text.Text.apply_custom_tags(tokens)

    rv = []

    active = set()

    for tokentype, text in tokens:

        if tokentype == PARAGRAPH:
            rv.append("\n")
        elif tokentype == TAG:
            kind = text.partition("=")[0]

            if kind.startswith("/"):
                kind = kind[1:]
                end = True
            else:
                end = False

            if kind in renpy.config.tts_filter_tags:
                if end:
                    active.discard(kind)
                else:
                    active.add(kind)

        else:
            if not active:
                rv.append(text)

    return "".join(rv)
Esempio n. 16
0
def textwrap(s, width=78, asian=False):
    """
    Wraps the unicode string `s`, and returns a list of strings.

    `width`
        The number of half-width characters that fit on a line.
    `asian`
        True if we should make ambiguous width characters full-width, as is
        done in Asian encodings.
    """

    import unicodedata

    glyphs = []

    for c in str(s):

        eaw = unicodedata.east_asian_width(c)

        if (eaw == "F") or (eaw == "W"):
            gwidth = 20
        elif (eaw == "A"):
            if asian:
                gwidth = 20
            else:
                gwidth = 10
        else:
            gwidth = 10

        g = textsupport.Glyph()
        g.character = ord(c)
        g.ascent = 10
        g.line_spacing = 10
        g.width = gwidth
        g.advance = gwidth

        glyphs.append(g)

    textsupport.annotate_unicode(glyphs, False, 2)
    renpy.text.texwrap.linebreak_tex(glyphs, width * 10, width * 10, False)
    return textsupport.linebreak_list(glyphs)
Esempio n. 17
0
    def _update(self):
        """
        Updates the persistent data to be the latest version of
        the persistent data.
        """

        if self._preferences is None:
            self._preferences = renpy.preferences.Preferences()

        # Initialize the set of statements seen ever.
        if not self._seen_ever:
            self._seen_ever = {}

        # Initialize the set of images seen ever.
        if not self._seen_images:
            self._seen_images = {}

        # Initialize the set of chosen menu choices.
        if not self._chosen:
            self._chosen = {}

        if not self._seen_audio:
            self._seen_audio = {}

        self._seen_audio = {str(i): True for i in self._seen_audio}

        # The set of seen translate identifiers.
        if not self._seen_translates:
            self._seen_translates = set()

        # A map from the name of a field to the time that field was last
        # changed at.
        if self._changed is None:
            self._changed = {
                "_preferences": 0,
                "_seen_ever": 0,
                "_chosen": 0,
                "_seen_audio": 0,
                "_seen_translates": 0,
            }
Esempio n. 18
0
    def lookup(self, label):
        """
        Looks up the given label in the game. If the label is not found,
        raises a ScriptError.
        """

        if isinstance(label, renpy.parser.SubParse):
            label = label.block[0].name

        label = renpy.config.label_overrides.get(label, label)
        original = label

        rv = self.namemap.get(label, None)

        if (rv is None) and (renpy.config.missing_label_callback is not None):
            label = renpy.config.missing_label_callback(label)
            rv = self.namemap.get(label, None)

        if rv is None:
            raise ScriptError("could not find label '%s'." % str(original))

        return self.namemap[label]
Esempio n. 19
0
def bootstrap(renpy_base):

    global renpy # W0602

    import renpy.log # @UnusedImport

    # Remove a legacy environment setting.
    if os.environ.get("SDL_VIDEODRIVER", "") == "windib":
        del os.environ["SDL_VIDEODRIVER"]

    if not isinstance(renpy_base, str):
        renpy_base = str(renpy_base, FSENCODING)

    # If environment.txt exists, load it into the os.environ dictionary.
    if os.path.exists(renpy_base + "/environment.txt"):
        evars = { }
        with open(renpy_base + "/environment.txt", "r") as f:
            code = compile(f.read(), renpy_base + "/environment.txt", 'exec')
            exec(code, evars)
        for k, v in evars.items():
            if k not in os.environ:
                os.environ[k] = str(v)

    # Also look for it in an alternate path (the path that contains the
    # .app file.), if on a mac.
    alt_path = os.path.abspath("renpy_base")
    if ".app" in alt_path:
        alt_path = alt_path[:alt_path.find(".app") + 4]

        if os.path.exists(alt_path + "/environment.txt"):
            evars = { }
            with open(alt_path + "/environment.txt", "rb") as f:
                code = compile(f.read(), alt_path + "/environment.txt", 'exec')
                exec(code, evars)
            for k, v in evars.items():
                if k not in os.environ:
                    os.environ[k] = str(v)

    # Get a working name for the game.
    name = os.path.basename(sys.argv[0])

    if name.find(".") != -1:
        name = name[:name.find(".")]

    # Parse the arguments.
    import renpy.arguments
    args = renpy.arguments.bootstrap()

    if args.trace:
        enable_trace(args.trace)

    if args.basedir:
        basedir = os.path.abspath(args.basedir)
        if not isinstance(basedir, str):
            basedir = basedir.decode(FSENCODING)
    else:
        basedir = renpy_base

    if not os.path.exists(basedir):
        sys.stderr.write("Base directory %r does not exist. Giving up.\n" % (basedir,))
        sys.exit(1)

    # Make game/ on Android.
    if renpy.android:
        if not os.path.exists(basedir + "/game"):
            os.mkdir(basedir + "/game", 0o777)

    gamedirs = [ name ]
    game_name = name

    while game_name:
        prefix = game_name[0]
        game_name = game_name[1:]

        if prefix == ' ' or prefix == '_':
            gamedirs.append(game_name)

    gamedirs.extend([ 'game', 'data', 'launcher/game' ])

    for i in gamedirs:

        if i == "renpy":
            continue

        gamedir = basedir + "/" + i
        if os.path.isdir(gamedir):
            break
    else:
        gamedir = basedir

    sys.path.insert(0, basedir)

    if renpy.macintosh:
        # If we're on a mac, install our own os.start.
        os.startfile = mac_start # type: ignore

        # Are we starting from inside a mac app resources directory?
        if basedir.endswith("Contents/Resources/autorun"):
            renpy.macapp = True

    # Check that we have installed pygame properly. This also deals with
    # weird cases on Windows and Linux where we can't import modules. (On
    # windows ";" is a directory separator in PATH, so if it's in a parent
    # directory, we won't get the libraries in the PATH, and hence pygame
    # won't import.)
    try:
        import pygame_sdl2
        if not ("pygame" in sys.modules):
            pygame_sdl2.import_as_pygame()
    except:
        print("""\
Could not import pygame_sdl2. Please ensure that this program has been built
and unpacked properly. Also, make sure that the directories containing
this program do not contain : or ; in their names.

You may be using a system install of python. Please run {0}.sh,
{0}.exe, or {0}.app instead.
""".format(name), file=sys.stderr)

        raise

    # If we're not given a command, show the presplash.
    if args.command == "run" and not renpy.mobile:
        import renpy.display.presplash # @Reimport
        renpy.display.presplash.start(basedir, gamedir)

    # Ditto for the Ren'Py module.
    try:
        import _renpy; _renpy
    except:
        print("""\
Could not import _renpy. Please ensure that this program has been built
and unpacked properly.

You may be using a system install of python. Please run {0}.sh,
{0}.exe, or {0}.app instead.
""".format(name), file=sys.stderr)
        raise

    # Load the rest of Ren'Py.
    import renpy
    renpy.import_all()

    renpy.loader.init_importer()

    exit_status = None

    try:
        while exit_status is None:
            exit_status = 1

            try:
                renpy.game.args = args
                renpy.config.renpy_base = renpy_base
                renpy.config.basedir = basedir
                renpy.config.gamedir = gamedir
                renpy.config.args = [ ] # type: ignore

                if renpy.android:
                    renpy.config.logdir = os.environ['ANDROID_PUBLIC']
                else:
                    renpy.config.logdir = basedir

                if not os.path.exists(renpy.config.logdir):
                    os.makedirs(renpy.config.logdir, 0o777)

                renpy.main.main()

                exit_status = 0

            except KeyboardInterrupt:
                raise

            except renpy.game.UtterRestartException:

                # On an UtterRestart, reload Ren'Py.
                renpy.reload_all()

                exit_status = None

            except renpy.game.QuitException as e:
                exit_status = e.status

                if e.relaunch:
                    if hasattr(sys, "renpy_executable"):
                        subprocess.Popen([sys.renpy_executable] + sys.argv[1:]) # type: ignore
                    else:
                        subprocess.Popen([sys.executable, "-EO"] + sys.argv)

            except renpy.game.ParseErrorException:
                pass

            except Exception as e:
                renpy.error.report_exception(e)
                pass

        sys.exit(exit_status)

    finally:

        if "RENPY_SHUTDOWN_TRACE" in os.environ:
            enable_trace(int(os.environ["RENPY_SHUTDOWN_TRACE"]))

        renpy.display.tts.tts(None)

        renpy.display.im.cache.quit()

        if renpy.display.draw:
            renpy.display.draw.quit()

        renpy.audio.audio.quit()

        # Prevent subprocess from throwing errors while trying to run it's
        # __del__ method during shutdown.
        if not renpy.emscripten:
            subprocess.Popen.__del__ = popen_del # type: ignore
Esempio n. 20
0
def report_exception(e, editor=True):
    """
    Reports an exception by writing it to standard error and
    traceback.txt. If `editor` is True, opens the traceback
    up in a text editor.

    Returns a three-item tuple, with the first item being
    a simplified traceback, the second being a full traceback,
    and the third being the traceback filename.
    """

    # Note: Doki Doki Literature club calls this as ("Words...", False).
    # For what it's worth.

    import codecs

    type, _value, tb = sys.exc_info() # @ReservedAssignment

    # Return values - which can be displayed to the user.
    simple = io.StringIO()
    full = io.StringIO()

    full_tl = traceback_list(tb)
    simple_tl = filter_traceback_list(full_tl)

    print(str(renpy.game.exception_info), file=simple)
    write_traceback_list(simple, simple_tl)
    print(type.__name__ + ":", end=' ', file=simple)
    print(str(e), file=simple)

    print("Full traceback:", file=full)
    write_traceback_list(full, full_tl)
    print(type.__name__ + ":", end=' ', file=full)
    print(str(e), file=full)

    # Write to stdout/stderr.
    try:
        sys.stdout.write("\n")
        sys.stdout.write(full.getvalue())
        sys.stdout.write("\n")
        sys.stdout.write(simple.getvalue())
    except Exception:
        pass

    print('', file=full)

    try:
        print(str(platform.platform()), file=full)
        print(renpy.version, file=full)
        print(renpy.config.name + " " + renpy.config.version, file=full)
        print(str(time.ctime()), file=full)
    except Exception:
        pass

    simple = simple.getvalue()
    full = full.getvalue()

    # Inside of the file, which may not be openable.
    try:

        f, traceback_fn = open_error_file("traceback.txt", "w")

        with f:
            f.write("\ufeff") # BOM

            print("I'm sorry, but an uncaught exception occurred.", file=f)
            print('', file=f)

            f.write(simple)

            print('', file=f)
            print("-- Full Traceback ------------------------------------------------------------", file=f)
            print('', file=f)

            f.write(full)

        try:
            renpy.util.expose_file(traceback_fn)
        except Exception:
            pass

        try:
            if editor and ((renpy.game.args.command == "run") or (renpy.game.args.errors_in_editor)): # type: ignore
                renpy.exports.launch_editor([ traceback_fn ], 1, transient=1)
        except Exception:
            pass

    except Exception:
        traceback_fn = os.path.join(renpy.config.basedir, "traceback.txt") # type: ignore

    return simple, full, traceback_fn
Esempio n. 21
0
 def __reduce__(self):
     return (AudioData, (self.data, str(self)))
Esempio n. 22
0
 def __format__(self, spec):
     return format(str(self), spec)
Esempio n. 23
0
    def find_target(self, scope=None, update=True):

        if self.locked and (self.target is not None):
            return

        if self._args.prefix is None:
            if self._duplicatable:
                prefix = self.style.prefix
            else:
                prefix = ""
        else:
            prefix = self._args.prefix

        try:
            search = []
            target = renpy.easy.dynamic_image(self.name,
                                              scope,
                                              prefix=prefix,
                                              search=search)
        except KeyError as ke:
            raise Exception(
                "In DynamicImage %r: Could not find substitution '%s'." %
                (self.name, str(ke.args[0])))
        except Exception as e:
            raise Exception("In DynamicImage %r: %r" % (self.name, e))

        if target is None:
            error = "DynamicImage %r: could not find image." % (self.name, )

            if len(search) == 1:
                error += " (%r)" % (search[0], )
            elif len(search) == 2:
                error += " (%r, %r)" % (search[0], search[1])
            elif len(search) > 2:
                error += " (%r, %r, and %d more.)" % (search[0], search[1],
                                                      len(search) - 2)

            raise Exception(error)

        if self.raw_target == target:
            return False

        if not update:
            return True

        raw_target = target  # type: renpy.display.core.Displayable
        old_target = self.target

        if raw_target._duplicatable:
            target = raw_target._duplicate(self._args)

        self.raw_target = raw_target
        self.target = target

        renpy.display.render.redraw(self, 0)

        if not old_target:
            return True

        if not isinstance(old_target, renpy.display.motion.Transform):
            return True

        if not isinstance(target, renpy.display.motion.Transform):
            self.target = target = renpy.display.motion.Transform(child=target)

        target.take_state(old_target)

        return True
Esempio n. 24
0
    def find_target(self):

        name = self.name

        if isinstance(name, renpy.display.core.Displayable):
            self.target = name
            return True

        if not isinstance(name, tuple):
            name = tuple(name.split())

        def error(msg):
            self.target = renpy.text.text.Text(msg,
                                               color=(255, 0, 0, 255),
                                               xanchor=0,
                                               xpos=0,
                                               yanchor=0,
                                               ypos=0)

            if renpy.config.debug:
                raise Exception(msg)

        target = None  # typing

        args = []

        while name:
            target = images.get(name, None)

            if target is not None:
                break

            args.insert(0, name[-1])
            name = name[:-1]

        if not name:
            error("Image '%s' not found." % ' '.join(self.name))
            return False

        if name and (self._args.name == name):
            error("Image '{}' refers to itself.".format(' '.join(name)))
            return False

        args += self._args.args

        try:

            a = self._args.copy(name=name, args=args)
            self.target = target._duplicate(a)

        except Exception as e:

            if renpy.config.raise_image_exceptions and (
                    renpy.config.debug or renpy.config.developer):
                raise

            error(str(e))
            return False

        # Copy the old transform over.
        new_transform = self.target._target()

        if isinstance(new_transform, renpy.display.transform.Transform):
            if self.old_transform is not None:
                new_transform.take_state(self.old_transform)

            self.old_transform = new_transform

        else:
            self.old_transform = None

        return True
Esempio n. 25
0
import os
import zipfile
import json

import renpy
import threading

from renpy.loadsave import clear_slot, safe_rename
import shutil

disk_lock = threading.RLock()

# A suffix used to disambguate temporary files being written by multiple
# processes.
import time
tmp = "." + str(int(time.time())) + ".tmp"


class FileLocation(object):
    """
    A location that saves files to a directory on disk.
    """
    def __init__(self, directory):
        self.directory = directory

        # Make the save directory.
        try:
            os.makedirs(self.directory)
        except:
            pass
Esempio n. 26
0
    # The tuple giving the version number.
    version_tuple = (7, 5, 0, vc_version)

    # The name of this version.
    version_name = "TBD"

else:

    # The tuple giving the version number.
    version_tuple = (8, 0, 0, vc_version)

    # The name of this version.
    version_name = "Heck Freezes Over"

# A string giving the version number only (8.0.1.123), with a suffix if needed.
version_only = ".".join(str(i) for i in version_tuple)

if not official:
    version_only += "u"
elif nightly:
    version_only += "n"

# A verbose string giving the version.
version = "Ren'Py " + version_only

# Other versions.
script_version = 5003000
savegame_suffix = "-LT1.save"
bytecode_version = 1

################################################################################
Esempio n. 27
0
def add(msg, *args):
    if not msg in added:
        added[msg] = True
        msg = str(msg) % args
        print(msg)
Esempio n. 28
0
def py_compile(source,
               mode,
               filename='<none>',
               lineno=1,
               ast_node=False,
               cache=True,
               py=None):
    """
    Compiles the given source code using the supplied codegenerator.
    Lists, List Comprehensions, and Dictionaries are wrapped when
    appropriate.

    `source`
        The source code, as a either a string, pyexpr, or ast module
        node.

    `mode`
        One of "exec" or "eval".

    `filename`
        The filename the source comes from. If a pyexpr is given, the
        filename embedded in the pyexpr is used.

    `lineno`
        The line number of the first line of source code. If a pyexpr is
        given, the filename embedded in the pyexpr is used.

    `ast_node`
        Rather than returning compiled bytecode, returns the AST object
        that would be used.
    """

    if ast_node:
        cache = False

    if isinstance(source, ast.Module):
        return compile(source, filename, mode)

    if isinstance(source, renpy.ast.PyExpr):
        filename = source.filename
        lineno = source.linenumber

        if py is None:
            py = source.py

    if py is None:
        if PY2:
            py = 2
        else:
            py = 3

    if cache:
        key = (lineno, filename, str(source), mode, renpy.script.MAGIC)

        rv = py_compile_cache.get(key, None)
        if rv is not None:
            return rv

        rv = old_py_compile_cache.get(key, None)
        if rv is not None:
            py_compile_cache[key] = rv
            return rv

        bytecode = renpy.game.script.bytecode_oldcache.get(key, None)
        if bytecode is not None:

            renpy.game.script.bytecode_newcache[key] = bytecode
            rv = marshal.loads(bytecode)
            py_compile_cache[key] = rv
            return rv

    else:
        key = None

    source = str(source)
    source = source.replace("\r", "")

    if mode == "eval":
        source = quote_eval(source)

    line_offset = lineno - 1

    try:

        if mode == "hide":
            py_mode = "exec"
        else:
            py_mode = mode

        if (not PY2) or (filename in py3_files):

            flags = py3_compile_flags

            try:
                tree = compile(source, filename, py_mode,
                               ast.PyCF_ONLY_AST | flags, 1)
            except SyntaxError as orig_e:

                try:
                    fixed_source = renpy.compat.fixes.fix_tokens(source)
                    tree = compile(fixed_source, filename, py_mode,
                                   ast.PyCF_ONLY_AST | flags, 1)
                except:
                    raise orig_e

        else:

            try:
                flags = new_compile_flags
                tree = compile(source, filename, py_mode,
                               ast.PyCF_ONLY_AST | flags, 1)
            except Exception:
                flags = old_compile_flags
                source = escape_unicode(source)
                tree = compile(source, filename, py_mode,
                               ast.PyCF_ONLY_AST | flags, 1)

        tree = wrap_node.visit(tree)

        if mode == "hide":
            wrap_hide(tree)

        fix_missing_locations(tree, 1, 0)
        ast.increment_lineno(tree, lineno - 1)

        line_offset = 0

        if ast_node:
            return tree.body

        rv = compile(tree, filename, py_mode, flags, 1)

        if cache:
            py_compile_cache[key] = rv
            renpy.game.script.bytecode_newcache[key] = marshal.dumps(rv)
            renpy.game.script.bytecode_dirty = True

        return rv

    except SyntaxError as e:

        if e.lineno is not None:
            e.lineno += line_offset

        raise e