Exemple #1
0
    def execute(self, state, t):

        self.report()

        if renpy.display.interface.trans_pause:
            return state

        if self.pattern:

            f = renpy.test.testfocus.find_focus(self.pattern)
            if f is None:
                return state

        else:
            f = None

        if state is True:

            points = renpy.python.py_eval(self.points)
            points = [renpy.test.testfocus.find_position(f, i) for i in points]

            if len(points) < 2:
                raise Exception("A drag requires at least two points.")

            interpoints = []

            xa, ya = points[0]

            interpoints.append((xa, ya))

            for xb, yb in points[1:]:
                for i in range(1, self.steps + 1):
                    done = 1.0 * i / self.steps

                    interpoints.append((
                        int(xa + done * (xb - xa)),
                        int(ya + done * (yb - ya)),
                    ))

                xa = xb
                ya = yb

            x, y = interpoints.pop(0)

            renpy.test.testmouse.move_mouse(x, y)
            renpy.test.testmouse.press_mouse(self.button)

        else:

            interpoints = state

            x, y = interpoints.pop(0)
            renpy.test.testmouse.move_mouse(x, y)

        if not interpoints:
            renpy.test.testmouse.release_mouse(self.button)
            return None

        else:
            return interpoints
Exemple #2
0
    def event(self, ev, x, y, st):

        if self.hide_request:
            return None

        if not self.state.events: # type: ignore
            return

        children = self.children
        offsets = self.offsets

        if not offsets:
            return None

        for i in range(len(self.children) - 1, -1, -1):

            d = children[i]
            xo, yo = offsets[i]

            cx = x - xo
            cy = y - yo

            # Transform screen coordinates to child coordinates.
            cx, cy = self.forward.transform(cx, cy)

            rv = d.event(ev, cx, cy, st)
            if rv is not None:
                return rv

        return None
Exemple #3
0
    def per_interact(self):
        super(VPGrid, self).per_interact()

        exc = None
        delta = 0

        if None not in (self.grid_cols, self.grid_rows):
            delta = (self.grid_cols * self.grid_rows) - len(self.children)
            if delta > 0:
                exc = Exception("VPGrid not completely full.")

        else:
            given = self.grid_cols or self.grid_rows
            if given:  # ignore the case where one is 0 - cannot be underfull
                delta = given - (len(self.children) % given)
                # the number of aditional children needed to complete
                # within [1, given], `given` being all right
                if delta < given:
                    exc = Exception(
                        "VPGrid not completely full, needs a multiple of {} children."
                        .format(given))

        if exc is not None:
            allow_underfull = self.allow_underfull
            if allow_underfull is None:
                allow_underfull = renpy.config.allow_underfull_grids or renpy.config.allow_unfull_vpgrids

            if not allow_underfull:
                raise exc

            for _ in range(delta):
                self.add(renpy.display.layout.Null())
Exemple #4
0
def colormatrix(src, dst, matrix):
    c = [matrix[0:5], matrix[5:10], matrix[10:15], matrix[15:20]]
    offs = byte_offset(src)

    o = [None] * 4
    for i in range(0, 4):
        o[offs[i]] = i  # type: ignore

    _renpy.colormatrix(
        src,
        dst,
        c[o[0]][o[0]],
        c[o[0]][o[1]],
        c[o[0]][o[2]],
        c[o[0]][o[3]],
        c[o[0]][4],  # type: ignore
        c[o[1]][o[0]],
        c[o[1]][o[1]],
        c[o[1]][o[2]],
        c[o[1]][o[3]],
        c[o[1]][4],  # type: ignore
        c[o[2]][o[0]],
        c[o[2]][o[1]],
        c[o[2]][o[2]],
        c[o[2]][o[3]],
        c[o[2]][4],  # type: ignore
        c[o[3]][o[0]],
        c[o[3]][o[1]],
        c[o[3]][o[2]],
        c[o[3]][o[3]],
        c[o[3]][4])  # type: ignore
Exemple #5
0
    def glyphs(self, s):

        rv = [ ]

        if not s:
            return rv

        for c in s:
            g = textsupport.Glyph() # @UndefinedVariable

            g.character = ord(c)
            g.ascent = self.baseline
            g.line_spacing = self.height

            if not is_zerowidth(g.character):

                width = self.width.get(c, None)
                if width is None:
                    raise Exception("Character {0!r} not found in image-based font.".format(c))

                g.width = self.width[c]
                g.advance = self.advance[c]

            else:
                g.width = 0
                g.advance = 0

            rv.append(g)

        # Compute kerning.
        for i in range(len(s) - 1):
            kern = self.kerns.get(s[i] + s[i + 1], self.default_kern)
            rv[i].advance += kern

        return rv
Exemple #6
0
def find_position(f, position):
    """
    Returns the virtual position of a coordinate located within focus `f`.
    If position is (None, None) returns the current mouse position (if in
    the focus), or a random position.

    If `f` is None, returns a position relative to the screen as a whole.
    """

    posx, posy = position

    # Avoid moving the mouse when unnecessary.
    if renpy.test.testmouse.mouse_pos is not None:
        x, y = renpy.test.testmouse.mouse_pos
    else:
        x = random.randrange(renpy.config.screen_width)
        y = random.randrange(renpy.config.screen_height)

    if f is None:
        return (
            relative_position(x, posx, renpy.config.screen_width),
            relative_position(y, posy, renpy.config.screen_height),
            )

    orig_f = f

    # Check for the default widget.
    if f.x is None:
        f = f.copy()
        f.x = 0
        f.y = 0
        f.w = renpy.config.screen_width
        f.h = renpy.config.screen_height

    x = relative_position(x, posx, f.w) + f.x
    y = relative_position(y, posy, f.h) + f.y

    for _i in range(100):

        x = int(x)
        y = int(y)

        nf = renpy.display.render.focus_at_point(x, y)

        if nf is None:
            if orig_f.x is None:
                return x, y
        else:
            if (nf.widget == f.widget) and (nf.arg == f.arg):
                return x, y

        x = random.randrange(f.x, f.x + f.w)
        y = random.randrange(f.y, f.y + f.h)

    else:
        print()

        raise Exception("Could not locate the displayable.")
Exemple #7
0
    def write_rpyc_header(self, f):
        """
        Writes an empty version 2 .rpyc header to the open binary file `f`.
        """

        f.write(RPYC2_HEADER)

        for _i in range(3):
            f.write(struct.pack("III", 0, 0, 0))
Exemple #8
0
    def __init__(self, old, new):

        # Pick out a pivot element near the center of the list.
        new_center = (len(new) - 1) // 2
        new_pivot = new[new_center]

        # Find an element in the old list corresponding to the pivot.
        old_half = (len(old) - 1) // 2

        for i in range(0, old_half + 1):

            if old[old_half - i] is new_pivot:
                old_center = old_half - i
                break

            if old[old_half + i] is new_pivot:
                old_center = old_half + i
                break
        else:
            # If we couldn't, give up.
            self.pre = old
            self.start = 0
            self.end = 0
            self.post = []

            return

        # Figure out the position of the overlap in the center of the two lists.
        new_start = new_center
        new_end = new_center + 1

        old_start = old_center
        old_end = old_center + 1

        len_new = len(new)
        len_old = len(old)

        while new_start and old_start and (new[new_start - 1] is
                                           old[old_start - 1]):
            new_start -= 1
            old_start -= 1

        while (new_end < len_new) and (old_end < len_old) and (new[new_end] is
                                                               old[old_end]):
            new_end += 1
            old_end += 1

        # Now that we have this, we can put together the object.
        self.pre = list.__getitem__(old, slice(0, old_start))
        self.start = new_start
        self.end = new_end
        self.post = list.__getitem__(old, slice(old_end, len_old))
Exemple #9
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))
Exemple #10
0
    def event(self, ev, x, y, st):
        for i in range(len(self.children) - 1, -1, -1):
            s = self.children[i]

            if s.events:
                rv = s.cache.child.event(ev, x - s.x, y - s.y, st - s.cache.st)
                if rv is not None:
                    return rv

        if self.event_function is not None:
            return self.event_function(ev, x, y, st)
        else:
            return None
Exemple #11
0
    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().
        """

        if self.force_checkpoint:
            self.checkpoint(hard=False)
            self.force_checkpoint = False

        # Update self.current.stores with the changes from each store.
        # Also updates .ever_been_changed.
        for name, sd in renpy.python.store_dicts.items():
            delta = sd.get_changes(begin)
            if delta:
                self.current.stores[name], self.current.delta_ebc[name] = delta

        # Update the list of mutated objects and what we need to do to
        # restore them.

        for _i in range(4):

            del self.current.objects[:]

            try:
                for _k, v in self.mutated.items():

                    if v is None:
                        continue

                    (ref, clean) = v

                    obj = ref()
                    if obj is None:
                        continue

                    compressed = obj._compress(clean)
                    self.current.objects.append((obj, compressed))

                break

            except RuntimeError:
                # This can occur when self.mutated is changed as we're
                # iterating over it.
                pass
Exemple #12
0
def analyze():
    """
    Analyze the FPL and prints a report.
    """

    if not fpl:
        return

    if renpy.config.frames < 30:
        return

    start = fpl[0][0]

    for t, _, event, _ in fpl:
        if event == renpy.config.profile_to_event:
            end = t
            break
    else:
        return

    if (
            end - start
    ) < renpy.config.profile_time and not renpy.display.interface.profile_once:
        return

    s = "\n"

    renpy.log.real_stdout.write(s)
    renpy.display.log.write(s)

    times = [fpl[0][0]] * DEPTH_LEVELS

    for t, depth, event, args in fpl:
        dt = [(1000000 * (t - it)) if i <= depth else 0
              for i, it in enumerate(times)]

        s = "{: 7.0f} {: 7.0f} {: 7.0f} {: 7.0f} {}\n".format(
            dt[0],
            dt[1],
            dt[2],
            dt[3],
            event.format(*args).replace("%", "%%"),
        )

        renpy.log.real_stdout.write(s)
        renpy.display.log.write(s)

        for i in range(depth, DEPTH_LEVELS):
            times[i] = t
Exemple #13
0
    def merge_names(self, old_stmts, new_stmts, used_names):

        old_stmts = collapse_stmts(old_stmts)
        new_stmts = collapse_stmts(new_stmts)

        old_info = [ i.diff_info() for i in old_stmts ]
        new_info = [ i.diff_info() for i in new_stmts ]

        sm = difflib.SequenceMatcher(None, old_info, new_info)

        for oldl, newl, count in sm.get_matching_blocks():
            for i in range(count):
                old = old_stmts[oldl + i]
                new = new_stmts[newl + i]

                if (new.name is None) and (new.name not in used_names):
                    new.name = old.name
                    used_names.add(new.name)
Exemple #14
0
def init():
    """
    Initialize gamepad support.
    """

    if not renpy.game.preferences.pad_enabled:
        return

    try:
        pygame_sdl2.controller.init()
        load_mappings()
    except Exception:
        renpy.display.log.exception()

    if not renpy.display.interface.safe_mode:
        try:
            for i in range(pygame_sdl2.controller.get_count()):
                start(i)
        except Exception:
            renpy.display.log.exception()
Exemple #15
0
    def create(self, particles, st):
        def ranged(n):
            if isinstance(n, tuple):
                return random.uniform(n[0], n[1])
            else:
                return n

        if (st == 0) and not particles and self.fast:
            rv = []

            for _i in range(0, self.count):
                rv.append(
                    SnowBlossomParticle(self.image,
                                        ranged(self.xspeed),
                                        ranged(self.yspeed),
                                        self.border,
                                        st,
                                        random.uniform(0, 100),
                                        fast=True,
                                        rotate=self.rotate))
            return rv

        if particles is None or len(particles) < self.count:

            # Check to see if we have a particle ready to start. If not,
            # don't start it.
            if particles and st < self.starts[len(particles)]:
                return None

            return [
                SnowBlossomParticle(self.image,
                                    ranged(self.xspeed),
                                    ranged(self.yspeed),
                                    self.border,
                                    st,
                                    random.uniform(0, 100),
                                    fast=False,
                                    rotate=self.rotate)
            ]
Exemple #16
0
 def init(self):
     self.starts = [
         random.uniform(0, self.start) for _i in range(0, self.count)
     ]  # W0201
     self.starts.append(self.start)
     self.starts.sort()
Exemple #17
0
    def predict(self):
        """
        Performs image prediction, calling the given callback with each
        images that we predict to be loaded, in the rough order that
        they will be potentially loaded.
        """

        if not self.current:
            return

        if renpy.config.predict_statements_callback is None:
            return

        old_images = self.images

        # A worklist of (node, images, return_stack) tuples.
        nodes = []

        # The set of nodes we've seen. (We only consider each node once.)
        seen = set()

        # Find the roots.
        for label in renpy.config.predict_statements_callback(self.current):

            if not renpy.game.script.has_label(label):
                continue

            node = renpy.game.script.lookup(label)

            if node in seen:
                continue

            nodes.append((node, self.images, self.return_stack))
            seen.add(node)

        # Predict statements.
        for i in range(0, renpy.config.predict_statements):

            if i >= len(nodes):
                break

            node, images, return_stack = nodes[i]

            self.images = renpy.display.image.ShownImageInfo(images)
            self.predict_return_stack = return_stack

            try:

                for n in node.predict():
                    if n is None:
                        continue

                    if n not in seen:
                        nodes.append(
                            (n, self.images, self.predict_return_stack))
                        seen.add(n)

            except Exception:

                if renpy.config.debug_prediction:
                    import traceback

                    print("While predicting images.")
                    traceback.print_exc()
                    print()

            self.images = old_images
            self.predict_return_stack = None

            yield True

        yield False
Exemple #18
0
def Filmstrip(image, framesize, gridsize, delay, frames=None, loop=True, **properties):
    """
    This creates an animation from a single image. This image
    must consist of a grid of frames, with the number of columns and
    rows in the grid being taken from gridsize, and the size of each
    frame in the grid being taken from framesize. This takes frames
    and sticks them into an Animation, with the given delay between
    each frame. The frames are taken by going from left-to-right
    across the first row, left-to-right across the second row, and
    so on until all frames are consumed, or a specified number of
    frames are taken.

    @param image: The image that the frames must be taken from.

    @param framesize: A (width, height) tuple giving the size of
    each of the frames in the animation.

    @param gridsize: A (columns, rows) tuple giving the number of
    columns and rows in the grid.

    @param delay: The delay, in seconds, between frames.

    @param frames: The number of frames in this animation. If None,
    then this defaults to colums * rows frames, that is, taking
    every frame in the grid.

    @param loop: If True, loop at the end of the animation. If False,
    this performs the animation once, and then stops.

    Other keyword arguments are as for anim.SMAnimation.
    """

    width, height = framesize
    cols, rows = gridsize

    if frames is None:
        frames = cols * rows

    i = 0

    # Arguments to Animation
    args = [ ]

    for r in range(0, rows):
        for c in range(0, cols):

            x = c * width
            y = r * height

            args.append(renpy.display.im.Crop(image, x, y, width, height))
            args.append(delay)

            i += 1
            if i == frames:
                break

        if i == frames:
            break

    if not loop:
        args.pop()

    return Animation(*args, **properties)
Exemple #19
0
    def print_path(o, objs):

        prefix = ""

        seen = set()
        queue = []
        objects = []

        last = None

        for _i in range(30):

            objects.append(o)
            last = o

            print(prefix + "%x" % id(o),
                  "(%d referrers)" % len(gc.get_referrers(o)),
                  type(o),
                  end=' ')

            try:
                if isinstance(o, dict) and "__name__" in o:
                    print("with name", o["__name__"])
                else:
                    print(repr(o))
            except Exception:
                print("Bad repr.")

            found = False

            if isinstance(o, types.ModuleType):
                if not queue:
                    break

                o, prefix = queue.pop()
                continue

            if isinstance(o, weakref.WeakKeyDictionary):
                for k, v in o.items():
                    if v is objects[-4]:
                        k = k()
                        seen.add(id(k))
                        queue.append((k, prefix + " (key) "))

            for i in gc.get_referrers(o):

                if i is objs or i is objects:
                    continue

                if id(i) in seen:
                    continue

                if isinstance(i, types.FrameType):
                    continue

                seen.add(id(i))
                queue.append((i, prefix + "  "))
                found = True
                break

            if not queue:
                break

            if not found:
                print("<no parent, popping>")

            o, prefix = queue.pop()

        for i in gc.get_referrers(last):
            print(prefix + "<- %x" % id(i), type(i))

        del objects[:]
Exemple #20
0
 def add(self, sma):
     for _i in range(0, self.prob):
         sma.edges.setdefault(self.old, []).append(self)
Exemple #21
0
def main():

    gc.set_threshold(*renpy.config.gc_thresholds)

    log_clock("Bootstrap to the start of init.init")

    renpy.game.exception_info = 'Before loading the script.'

    # Clear the line cache, since the script may have changed.
    linecache.clearcache()

    # Get ready to accept new arguments.
    renpy.arguments.pre_init()

    # Init the screen language parser.
    renpy.sl2.slparser.init()

    # Init the config after load.
    renpy.config.init()

    # Reset live2d if it exists.
    try:
        renpy.gl2.live2d.reset()
    except:
        pass

    # Set up variants.
    choose_variants()
    renpy.display.touch = "touch" in renpy.config.variants

    log_clock("Early init")

    # Note the game directory.
    game.basepath = renpy.config.gamedir
    renpy.config.searchpath = [renpy.config.gamedir]

    # Find the common directory.
    commondir = __main__.path_to_common(
        renpy.config.renpy_base)  # E1101 @UndefinedVariable

    if os.path.isdir(commondir):
        renpy.config.searchpath.append(commondir)
        renpy.config.commondir = commondir
    else:
        renpy.config.commondir = None

    # Add path from env variable, if any
    if "RENPY_SEARCHPATH" in os.environ:
        renpy.config.searchpath.extend(
            os.environ["RENPY_SEARCHPATH"].split("::"))

    if renpy.android:
        renpy.config.commondir = None

        android_searchpath()

    # Load Ren'Py extensions.
    for dir in renpy.config.searchpath:  # @ReservedAssignment
        for fn in os.listdir(dir):
            if fn.lower().endswith(".rpe"):
                load_rpe(dir + "/" + fn)

    # Generate a list of extensions for each archive handler.
    archive_extensions = []
    for handler in renpy.loader.archive_handlers:
        for ext in handler.get_supported_extensions():
            if not (ext in archive_extensions):
                archive_extensions.append(ext)

    # Find archives.
    for dn in renpy.config.searchpath:

        if not os.path.isdir(dn):
            continue

        for i in sorted(os.listdir(dn)):
            base, ext = os.path.splitext(i)

            # Check if the archive does not have any of the extensions in archive_extensions
            if not (ext in archive_extensions):
                continue

            renpy.config.archives.append(base)

    renpy.config.archives.reverse()

    # Initialize archives.
    renpy.loader.index_archives()

    # Start auto-loading.
    renpy.loader.auto_init()

    log_clock("Loader init")

    # Initialize the log.
    game.log = renpy.python.RollbackLog()

    # Initialize the store.
    renpy.store.store = sys.modules['store']  # type: ignore

    # Set up styles.
    game.style = renpy.style.StyleManager()  # @UndefinedVariable
    renpy.store.style = game.style

    # Run init code in its own context. (Don't log.)
    game.contexts = [renpy.execution.Context(False)]
    game.contexts[0].init_phase = True

    renpy.execution.not_infinite_loop(60)

    # Load the script.
    renpy.game.exception_info = 'While loading the script.'
    renpy.game.script = renpy.script.Script()

    if renpy.session.get("compile", False):
        renpy.game.args.compile = True  # type: ignore

    # Set up error handling.
    renpy.exports.load_module("_errorhandling")

    if renpy.exports.loadable("tl/None/common.rpym") or renpy.exports.loadable(
            "tl/None/common.rpymc"):
        renpy.exports.load_module("tl/None/common")

    renpy.config.init_system_styles()
    renpy.style.build_styles()  # @UndefinedVariable

    log_clock("Loading error handling")

    # If recompiling everything, remove orphan .rpyc files.
    # Otherwise, will fail in case orphan .rpyc have same
    # labels as in other scripts (usually happens on script rename).
    if (renpy.game.args.command == 'compile'
        ) and not (renpy.game.args.keep_orphan_rpyc):  # type: ignore

        for (fn, dn) in renpy.game.script.script_files:

            if dn is None:
                continue

            if not os.path.isfile(os.path.join(dn, fn + ".rpy")):

                try:
                    name = os.path.join(dn, fn + ".rpyc")
                    os.rename(name, name + ".bak")
                except OSError:
                    # This perhaps shouldn't happen since either .rpy or .rpyc should exist
                    pass

        # Update script files list, so that it doesn't contain removed .rpyc's
        renpy.loader.cleardirfiles()
        renpy.game.script.scan_script_files()

    # Load all .rpy files.
    renpy.game.script.load_script()  # sets renpy.game.script.
    log_clock("Loading script")

    if renpy.game.args.command == 'load-test':  # type: ignore
        start = time.time()

        for i in range(5):
            print(i)
            renpy.game.script = renpy.script.Script()
            renpy.game.script.load_script()

        print(time.time() - start)
        sys.exit(0)

    renpy.game.exception_info = 'After loading the script.'

    # Find the save directory.
    if renpy.config.savedir is None:
        renpy.config.savedir = __main__.path_to_saves(
            renpy.config.gamedir)  # E1101 @UndefinedVariable

    if renpy.game.args.savedir:  # type: ignore
        renpy.config.savedir = renpy.game.args.savedir  # type: ignore

    # Init preferences.
    game.persistent = renpy.persistent.init()
    game.preferences = game.persistent._preferences

    for i in renpy.game.persistent._seen_translates:  # type: ignore
        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

    # Init save locations and loadsave.
    renpy.savelocation.init()

    # We need to be 100% sure we kill the savelocation thread.
    try:

        # Init save slots.
        renpy.loadsave.init()

        log_clock("Loading save slot metadata.")

        # Load persistent data from all save locations.
        renpy.persistent.update()
        game.preferences = game.persistent._preferences
        log_clock("Loading persistent")

        # Clear the list of seen statements in this game.
        game.seen_session = {}

        # Initialize persistent variables.
        renpy.store.persistent = game.persistent  # type: ignore
        renpy.store._preferences = game.preferences  # type: ignore
        renpy.store._test = renpy.test.testast._test  # type: ignore

        if renpy.parser.report_parse_errors():
            raise renpy.game.ParseErrorException()

        renpy.game.exception_info = 'While executing init code:'

        for _prio, node in game.script.initcode:

            if isinstance(node, renpy.ast.Node):
                node_start = time.time()

                renpy.game.context().run(node)

                node_duration = time.time() - node_start

                if node_duration > renpy.config.profile_init:
                    renpy.display.log.write(" - Init at %s:%d took %.5f s.",
                                            node.filename, node.linenumber,
                                            node_duration)

            else:
                # An init function.
                node()

        renpy.game.exception_info = 'After initialization, but before game start.'

        # Check if we should simulate android.
        renpy.android = renpy.android or renpy.config.simulate_android  # @UndefinedVariable

        # Re-set up the logging.
        renpy.log.post_init()

        # Run the post init code, if any.
        for i in renpy.game.post_init:
            i()

        renpy.game.script.report_duplicate_labels()

        # Sort the images.
        renpy.display.image.image_names.sort()

        game.persistent._virtual_size = renpy.config.screen_width, renpy.config.screen_height  # type: ignore

        log_clock("Running init code")

        renpy.pyanalysis.load_cache()
        log_clock("Loading analysis data")

        # Analyze the script and compile ATL.
        renpy.game.script.analyze()
        renpy.atl.compile_all()
        log_clock("Analyze and compile ATL")

        # Index the archive files. We should not have loaded an image
        # before this point. (As pygame will not have been initialized.)
        # We need to do this again because the list of known archives
        # may have changed.
        renpy.loader.index_archives()
        log_clock("Index archives")

        # Check some environment variables.
        renpy.game.less_memory = "RENPY_LESS_MEMORY" in os.environ
        renpy.game.less_mouse = "RENPY_LESS_MOUSE" in os.environ
        renpy.game.less_updates = "RENPY_LESS_UPDATES" in os.environ

        renpy.dump.dump(False)
        renpy.game.script.make_backups()
        log_clock("Dump and make backups.")

        # Initialize image cache.
        renpy.display.im.cache.init()
        log_clock("Cleaning cache")

        # Make a clean copy of the store.
        renpy.python.make_clean_stores()
        log_clock("Making clean stores")

        gc.collect(2)

        if gc.garbage:
            del gc.garbage[:]

        if renpy.config.manage_gc:
            gc.set_threshold(*renpy.config.gc_thresholds)

            gc_debug = int(os.environ.get("RENPY_GC_DEBUG", 0))

            if renpy.config.gc_print_unreachable:
                gc_debug |= gc.DEBUG_SAVEALL

            gc.set_debug(gc_debug)

        else:
            gc.set_threshold(700, 10, 10)

        log_clock("Initial gc.")

        # Start debugging file opens.
        renpy.debug.init_main_thread_open()

        # (Perhaps) Initialize graphics.
        if not game.interface:
            renpy.display.core.Interface()
            log_clock("Creating interface object")

        # Start things running.
        restart = None

        while True:

            if restart:
                renpy.display.screen.before_restart()

            try:
                try:
                    run(restart)
                finally:
                    restart = (renpy.config.end_game_transition,
                               "_invoke_main_menu", "_main_menu")
                    renpy.persistent.update(True)
                    renpy.persistent.save_MP()

            except game.FullRestartException as e:
                restart = e.reason

            finally:

                # Reset live2d if it exists.
                try:
                    renpy.gl2.live2d.reset_states()
                except:
                    pass

                # Flush any pending interface work.
                renpy.display.interface.finish_pending()

                # Give Ren'Py a couple of seconds to finish saving.
                renpy.loadsave.autosave_not_running.wait(3.0)

    finally:

        gc.set_debug(0)

        for i in renpy.config.quit_callbacks:
            i()

        renpy.loader.auto_quit()
        renpy.savelocation.quit()
        renpy.translation.write_updated_strings()

    # This is stuff we do on a normal, non-error return.
    if not renpy.display.error.error_handled:
        renpy.display.render.check_at_shutdown()
Exemple #22
0
        def draw(x0, x1, y0, y1):

            # Compute the coordinates of the left, right, top, and
            # bottom sides of the region, for both the source and
            # destination surfaces.

            # left side.
            if x0 >= 0:
                dx0 = x0
                sx0 = x0
            else:
                dx0 = dw + x0
                sx0 = sw + x0

            # right side.
            if x1 > 0:
                dx1 = x1
                sx1 = x1
            else:
                dx1 = dw + x1
                sx1 = sw + x1

            # top side.
            if y0 >= 0:
                dy0 = y0
                sy0 = y0
            else:
                dy0 = dh + y0
                sy0 = sh + y0

            # bottom side
            if y1 > 0:
                dy1 = y1
                sy1 = y1
            else:
                dy1 = dh + y1

                sy1 = sh + y1

            # Quick exit.
            if sx0 == sx1 or sy0 == sy1 or dx1 <= dx0 or dy1 <= dy0:
                return

            # Compute sizes.
            srcsize = (sx1 - sx0, sy1 - sy0)
            dstsize = (int(dx1 - dx0), int(dy1 - dy0))

            # Get a subsurface.
            surf = source.subsurface((sx0, sy0, srcsize[0], srcsize[1]))

            # Scale or tile if we have to.
            if dstsize != srcsize:

                if self.tile:
                    tilew, tileh = srcsize
                    dstw, dsth = dstsize

                    xtiles = max(1, dstw // tilew + (1 if dstw % tilew else 0))
                    ytiles = max(1, dsth // tileh + (1 if dsth % tileh else 0))

                    if dstw % tilew or dsth % tileh:
                        # Area is not an exact integer number of tiles

                        if self.tile == "integer":
                            if dstw % tilew / float(tilew) < self.tile_ratio:
                                xtiles = max(1, xtiles - 1)
                            if dsth % tileh / float(tileh) < self.tile_ratio:
                                ytiles = max(1, ytiles - 1)

                    # Tile at least one tile in each direction
                    surf2 = renpy.display.pgrender.surface_unscaled(
                        (tilew * xtiles, tileh * ytiles), surf)

                    for y in range(0, ytiles):
                        for x in range(0, xtiles):
                            surf2.blit(surf, (x * tilew, y * tileh))

                    if self.tile is True:
                        # Trim the tiled surface to required size
                        surf = surf2.subsurface((0, 0, dstw, dsth))
                    else:
                        # Using integer full 'tiles' per side
                        srcsize = (tilew * xtiles, tileh * ytiles)
                        surf = surf2

                if dstsize != srcsize:
                    surf2 = renpy.display.scale.real_transform_scale(
                        surf, dstsize)
                    surf = surf2

            # Blit.
            dest.blit(surf, (dx0, dy0))
Exemple #23
0
def draw_special(what, dest, x, y):
    """
    This handles the special drawing operations, such as dissolve and
    image dissolve. `x` and `y` are the offsets of the thing to be drawn
    relative to the destination rectangle, and are always negative.
    """

    dw, dh = dest.get_size()

    w = min(dw, what.width + x)
    h = min(dh, what.height + y)

    if w <= 0 or h <= 0:
        return

    if what.operation == DISSOLVE:

        bottom = what.children[0][0].render_to_texture(True)
        top = what.children[1][0].render_to_texture(True)

        if what.operation_alpha:
            target = surface(w, h, True)
        else:
            target = dest.subsurface((0, 0, w, h))

        renpy.display.module.blend(
            bottom.subsurface((-x, -y, w, h)),
            top.subsurface((-x, -y, w, h)),
            target,
            int(what.operation_complete * 255))

        if what.operation_alpha:
            dest.blit(target, (0, 0))

    elif what.operation == IMAGEDISSOLVE:

        image = what.children[0][0].render_to_texture(True)
        bottom = what.children[1][0].render_to_texture(True)
        top = what.children[2][0].render_to_texture(True)

        if what.operation_alpha:
            target = surface(w, h, True)
        else:
            target = dest.subsurface((0, 0, w, h))

        ramplen = what.operation_parameter

        ramp = b"\x00" * 256

        for i in range(0, ramplen):
            ramp += bchr(255 * i // ramplen)

        ramp += b"\xff" * 256

        step = int(what.operation_complete * (256 + ramplen))
        ramp = ramp[step:step + 256]

        renpy.display.module.imageblend(
            bottom.subsurface((-x, -y, w, h)),
            top.subsurface((-x, -y, w, h)),
            target,
            image.subsurface((-x, -y, w, h)),
            ramp)

        if what.operation_alpha:
            dest.blit(target, (0, 0))

    elif what.operation == PIXELLATE:

        surf = what.children[0][0].render_to_texture(dest.get_masks()[3])

        px = what.operation_parameter

        renpy.display.module.pixellate(
            surf.subsurface((-x, -y, w, h)),
            dest.subsurface((0, 0, w, h)),
            px, px, px, px)

    elif what.operation == FLATTEN:
        surf = what.children[0][0].render_to_texture(dest.get_masks()[3])
        dest.subsurface((0, 0, w, h)).blit(surf, (0, 0))

    else:
        raise Exception("Unknown operation: %d" % what.operation)
Exemple #24
0
    def add(self, font, start, end, target=None, target_increment=False):
        """
        :doc: font_group

        Associates a range of characters with a `font`.

        `start`
            The start of the range. This may be a single-character string, or
            an integer giving a unicode code point. If start is None, then the
            font is used as the default.

        `end`
            The end of the range. This may be a single-character string, or an
            integer giving a unicode code point. This is ignored if start is
            None.

        `target`
            If given, associates the given range of characters with specific
            characters from the given font, depending on target_increment.
            This may be a single-character string, or an integer giving a
            unicode code point. This is ignored if the character had already
            been added.

        `target_increment`
            If True, the [start, end] range is mapped to the
            [target, target+end-start] range. If False, every character from the
            range is associated with the target character.

        When multiple .add() calls include the same character, the first call
        takes precedence.

        This returns the FontGroup, so that multiple calls to .add() can be
        chained together.
        """

        if start is None:

            if isinstance(font, FontGroup):
                for k, v in font.map.items():
                    if k not in self.map:
                        self.map[k] = v
            else:
                if None not in self.map:
                    self.map[None] = font

            return self

        if not isinstance(start, int):
            start = ord(start)

        if not isinstance(end, int):
            end = ord(end)

        if target and not isinstance(target, int):
            target = ord(target)

        if end < start:
            raise Exception(
                "In FontGroup.add, the start of a character range must be before the end of the range."
            )

        for i in range(start, end + 1):
            if i not in self.map:
                self.map[i] = font

                if target is not None:
                    self.char_map[i] = target

                    if target_increment:
                        target += 1

        return self
Exemple #25
0
        def draw(x0, x1, y0, y1):

            # Compute the coordinates of the left, right, top, and
            # bottom sides of the region, for both the source and
            # destination surfaces.

            # left side.
            if x0 >= 0:
                dx0 = x0
                sx0 = x0
            else:
                dx0 = dw + x0
                sx0 = sw + x0

            # right side.
            if x1 > 0:
                dx1 = x1
                sx1 = x1
            else:
                dx1 = dw + x1
                sx1 = sw + x1

            # top side.
            if y0 >= 0:
                dy0 = y0
                sy0 = y0
            else:
                dy0 = dh + y0
                sy0 = sh + y0

            # bottom side
            if y1 > 0:
                dy1 = y1
                sy1 = y1
            else:
                dy1 = dh + y1
                sy1 = sh + y1

            # Quick exit.
            if sx0 == sx1 or sy0 == sy1:
                return

            # Compute sizes.
            csw = sx1 - sx0
            csh = sy1 - sy0
            cdw = dx1 - dx0
            cdh = dy1 - dy0

            if csw <= 0 or csh <= 0 or cdh <= 0 or cdw <= 0:
                return

            # Get a subsurface.
            cr = crend.subsurface((sx0, sy0, csw, csh))

            # Scale or tile if we have to.
            if csw != cdw or csh != cdh:

                if self.tile:
                    ctw, cth = cdw, cdh

                    xtiles = max(1, cdw // csw + (1 if cdw % csw else 0))
                    ytiles = max(1, cdh // csh + (1 if cdh % csh else 0))

                    if cdw % csw or cdh % csh:
                        # Area is not an exact integer number of tiles

                        if self.tile == "integer":
                            if cdw % csw / float(csw) < self.tile_ratio:
                                xtiles = max(1, xtiles - 1)
                            if cdh % csh / float(csh) < self.tile_ratio:
                                ytiles = max(1, ytiles - 1)

                            # Set size of the used tiles (ready to scale)
                            ctw, cth = csw * xtiles, csh * ytiles

                    newcr = Render(ctw, cth)
                    newcr.xclipping = True
                    newcr.yclipping = True

                    for x in range(0, xtiles):
                        for y in range(0, ytiles):
                            newcr.blit(cr, (x * csw, y * csh))

                    csw, csh = ctw, cth
                    cr = newcr

                if csw != cdw or csh != cdh:
                    # Subsurface needs scaling
                    newcr = Render(cdw, cdh)
                    newcr.forward = Matrix2D(1.0 * csw / cdw, 0, 0,
                                             1.0 * csh / cdh)
                    newcr.reverse = Matrix2D(1.0 * cdw / csw, 0, 0,
                                             1.0 * cdh / csh)
                    newcr.blit(cr, (0, 0))

                    cr = newcr

            # Blit.
            rv.blit(cr, (dx0, dy0))
            return
Exemple #26
0
def revertable_range(*args):
    return RevertableList(range(*args))