diff options
Diffstat (limited to 'unrpyc/renpy/atl.py')
-rw-r--r-- | unrpyc/renpy/atl.py | 1544 |
1 files changed, 0 insertions, 1544 deletions
diff --git a/unrpyc/renpy/atl.py b/unrpyc/renpy/atl.py deleted file mode 100644 index f314e3e..0000000 --- a/unrpyc/renpy/atl.py +++ /dev/null @@ -1,1544 +0,0 @@ -# Copyright 2004-2013 Tom Rothamel <pytom@bishoujo.us> -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation files -# (the "Software"), to deal in the Software without restriction, -# including without limitation the rights to use, copy, modify, merge, -# publish, distribute, sublicense, and/or sell copies of the Software, -# and to permit persons to whom the Software is furnished to do so, -# subject to the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# 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 renpy.display -import random - -def compiling(loc): - file, number = loc #@ReservedAssignment - - renpy.game.exception_info = "Compiling ATL code at %s:%d" % (file, number) - -def executing(loc): - file, number = loc #@ReservedAssignment - - renpy.game.exception_info = "Executing ATL code at %s:%d" % (file, number) - - -# A map from the name of a time warp function to the function itself. -warpers = { } - -def atl_warper(f): - name = f.__name__ - warpers[name] = f - return f - -# The pause warper is used internally when no other warper is -# specified. -@atl_warper -def pause(t): - if t < 1.0: - return 0.0 - else: - return 1.0 - -position = object() - -# A dictionary giving property names and the corresponding default -# values. -PROPERTIES = { - "pos" : (position, position), - "xpos" : position, - "ypos" : position, - "anchor" : (position, position), - "xanchor" : position, - "yanchor" : position, - "xaround" : position, - "yaround" : position, - "xanchoraround" : float, - "yanchoraround" : float, - "align" : (float, float), - "xalign" : float, - "yalign" : float, - "rotate" : float, - "rotate_pad" : bool, - "transform_anchor" : bool, - "xzoom" : float, - "yzoom" : float, - "zoom" : float, - "alpha" : float, - "around" : (position, position), - "alignaround" : (float, float), - "angle" : float, - "radius" : float, - "crop" : (float, float, float, float), - "size" : (int, int), - "corner1" : (float, float), - "corner2" : (float, float), - "subpixel" : bool, - "delay" : float, - "xoffset" : float, - "yoffset" : float, - "offset" : (int, int), - "xcenter" : position, - "ycenter" : position, - } - - -def correct_type(v, b, ty): - """ - Corrects the type of v to match ty. b is used to inform the match. - """ - - if ty is position: - if v is None: - return None - else: - return type(b)(v) - else: - return ty(v) - - -def interpolate(t, a, b, type): #@ReservedAssignment - """ - Linearly interpolate the arguments. - """ - - if t >= 1.0: - return b - - # Recurse into tuples. - if isinstance(b, tuple): - if a is None: - a = [ None ] * len(b) - - return tuple(interpolate(t, i, j, ty) for i, j, ty in zip(a, b, type)) - - # Deal with booleans, nones, etc. - elif b is None or isinstance(b, bool): - if t >= 1.0: - return b - else: - return a - - # Interpolate everything else. - else: - if a is None: - a = 0 - - return correct_type(a + t * (b - a), b, type) - -# Interpolate the value of a spline. This code is based on Aenakume's code, -# from 00splines.rpy. -def interpolate_spline(t, spline): - - if isinstance(spline[-1], tuple): - return tuple(interpolate_spline(t, i) for i in zip(*spline)) - - if spline[0] is None: - return spline[-1] - - if len(spline) == 2: - t_p = 1.0 - t - - rv = t_p * spline[0] + t * spline[-1] - - elif len(spline) == 3: - t_pp = (1.0 - t)**2 - t_p = 2 * t * (1.0 - t) - t2 = t**2 - - rv = t_pp * spline[0] + t_p * spline[1] + t2 * spline[2] - - elif len(spline) == 4: - - t_ppp = (1.0 - t)**3 - t_pp = 3 * t * (1.0 - t)**2 - t_p = 3 * t**2 * (1.0 - t) - t3 = t**3 - - rv = t_ppp * spline[0] + t_pp * spline[1] + t_p * spline[2] + t3 * spline[3] - - else: - raise Exception("ATL can't interpolate splines of length %d." % len(spline)) - - return correct_type(rv, spline[-1], position) - - -# This is the context used when compiling an ATL statement. It stores the -# scopes that are used to evaluate the various expressions in the statement, -# and has a method to do the evaluation and return a result. -class Context(object): - def __init__(self, context): - self.context = context - - def eval(self, expr): #@ReservedAssignment - expr = renpy.python.escape_unicode(expr) - return eval(expr, renpy.store.__dict__, self.context) #@UndefinedVariable - -# This is intended to be subclassed by ATLTransform. It takes care of -# managing ATL execution, which allows ATLTransform itself to not care -# much about the contents of this file. -class ATLTransformBase(renpy.object.Object): - - # Compatibility with older saves. - parameters = renpy.ast.ParameterInfo([ ], [ ], None, None) - - def __init__(self, atl, context, parameters): - - # The constructor will be called by atltransform. - - if parameters is None: - parameters = ATLTransformBase.parameters - - # The parameters that we take. - self.parameters = parameters - - # The raw code that makes up this ATL statement. - self.atl = atl - - # The context in which execution occurs. - self.context = Context(context) - - # The code after it has been compiled into a block. - self.block = None - - # The properties of the block, if it contains only an - # Interpolation. - self.properties = None - - # The state of the statement we are executing. As this can be - # shared between more than one object (in the case of a hide), - # the data must not be altered. - self.atl_state = None - - # Are we done? - self.done = False - - # The transform event we are going to process. - self.transform_event = None - - # The transform event we last processed. - self.last_transform_event = None - - # The child transform event we last processed. - self.last_child_transform_event = None - - def take_execution_state(self, t): - """ - Updates self to begin executing from the same point as t. This - requires that t.atl is self.atl. - """ - - super(ATLTransformBase, self).take_execution_state(t) - - if t.atl is not self.atl: - return - - self.done = t.done - self.block = t.block - self.atl_state = t.atl_state - self.transform_event = t.transform_event - self.last_transform_event = t.last_transform_event - self.last_child_transform_event = t.last_child_transform_event - - self.st = t.st - self.at = t.at - self.st_offset = t.st_offset - self.at_offset = t.at_offset - - if self.child is renpy.display.motion.null: - self.child = t.child - - - def __call__(self, *args, **kwargs): - - context = self.context.context.copy() - - for k, v in self.parameters.parameters: - if v is not None: - context[k] = renpy.python.py_eval(v) - - positional = list(self.parameters.positional) - args = list(args) - - child = None - - if not positional and args: - child = args.pop(0) - - # Handle positional arguments. - while positional and args: - name = positional.pop(0) - value = args.pop(0) - - if name in kwargs: - raise Exception('Parameter %r is used as both a positional and keyword argument to a transition.' % name) - - context[name] = value - - if args: - raise Exception("Too many arguments passed to ATL transform.") - - # Handle keyword arguments. - for k, v in kwargs.items(): - - if k in positional: - positional.remove(k) - context[k] = v - elif k in context: - context[k] = v - elif k == 'child': - child = v - else: - raise Exception('Parameter %r is not known by ATL Transform.' % k) - - if child is None: - child = self.child - - if child is None: - child = renpy.display.motion.get_null() - - # Create a new ATL Transform. - parameters = renpy.ast.ParameterInfo({}, positional, None, None) - - rv = renpy.display.motion.ATLTransform( - atl=self.atl, - child=child, - style=self.style_arg, - context=context, - parameters=parameters) - - rv.take_state(self) - - return rv - - - def compile(self): #@ReservedAssignment - """ - Compiles the ATL code into a block. As necessary, updates the - properties. - """ - - if self.parameters.positional and self.parameters.positional[0][1] is None: - raise Exception("Cannot compile ATL Transform, as it's missing positional parameter %s." % self.parameters.positional[0]) - - old_exception_info = renpy.game.exception_info - - self.block = self.atl.compile(self.context) - - if len(self.block.statements) == 1 \ - and isinstance(self.block.statements[0], Interpolation): - - interp = self.block.statements[0] - - if interp.duration == 0 and interp.properties: - self.properties = interp.properties[:] - - renpy.game.exception_info = old_exception_info - - - def execute(self, trans, st, at): - - if self.done: - return None - - if not self.block: - self.compile() - - # Propagate transform_events from children. - if self.child: - if self.child.transform_event != self.last_child_transform_event: - self.last_child_transform_event = self.child.transform_event - self.transform_event = self.child.transform_event - - # Hide request. - if trans.hide_request: - self.transform_event = "hide" - - if trans.replaced_request: - self.transform_event = "replaced" - - # Notice transform events. - if self.transform_event != self.last_transform_event: - event = self.transform_event - self.last_transform_event = self.transform_event - else: - event = None - - old_exception_info = renpy.game.exception_info - - if self.atl.animation: - timebase = at - else: - timebase = st - - action, arg, pause = self.block.execute(trans, timebase, self.atl_state, event) - - renpy.game.exception_info = old_exception_info - - # print "Executing", self, self.state, self.xpos, self.ypos - - if action == "continue": - self.atl_state = arg - else: - self.done = True - - return pause - - def predict_one(self): - self.atl.predict(self.context) - - def visit(self): - if not self.block: - self.compile() - - return self.children + self.block.visit() - - -# The base class for raw ATL statements. -class RawStatement(renpy.object.Object): - - def __init__(self, loc): - super(RawStatement, self).__init__() - self.loc = loc - - # Compiles this RawStatement into a Statement, by using ctx to - # evaluate expressions as necessary. - def compile(self, ctx): #@ReservedAssignment - raise Exception("Compile not implemented.") - - # Predicts the images used by this statement. - def predict(self, ctx): - return - -# The base class for compiled ATL Statements. -class Statement(renpy.object.Object): - - def __init__(self, loc): - super(Statement, self).__init__() - self.loc = loc - - # trans is the transform we're working on. - # st is the time since this statement started executing. - # state is the state stored by this statement, or None if - # we've just started executing this statement. - # event is an event we're triggering. - # - # "continue", state, pause - Causes this statement to execute - # again, with the given state passed in the second time around. - # - # - # "next", timeleft, pause - Causes the next statement to execute, - # with timeleft being the amount of time left after this statement - # finished. - # - # "event", (name, timeleft), pause - Causes an event to be reported, - # and control to head up to the event handler. - # - # "repeat", (count, timeleft), pause - Causes the repeat behavior - # to occur. - # - # As the Repeat statement can only appear in a block, only Block - # needs to deal with the repeat behavior. - # - # Pause is the amount of time until execute should be called again, - # or None if there's no need to call execute ever again. - def execute(self, trans, st, state, event): - raise Exception("Not implemented.") - - # Return a list of displayable children. - def visit(self): - return [ ] - -# This represents a Raw ATL block. -class RawBlock(RawStatement): - - # Should we use the animation timebase or the showing timebase? - animation = False - - def __init__(self, loc, statements, animation): - - super(RawBlock, self).__init__(loc) - - # A list of RawStatements in this block. - self.statements = statements - - self.animation = animation - - def compile(self, ctx): #@ReservedAssignment - compiling(self.loc) - - statements = [ i.compile(ctx) for i in self.statements ] - - return Block(self.loc, statements) - - def predict(self, ctx): - for i in self.statements: - i.predict(ctx) - - -# A compiled ATL block. -class Block(Statement): - def __init__(self, loc, statements): - - super(Block, self).__init__(loc) - - # A list of statements in the block. - self.statements = statements - - # The start times of various statements. - self.times = [ ] - - for i, s in enumerate(statements): - if isinstance(s, Time): - self.times.append((s.time, i + 1)) - - self.times.sort() - - def execute(self, trans, st, state, event): - - executing(self.loc) - - # Unpack the state. - if state is not None: - index, start, loop_start, repeats, times, child_state = state - else: - index, start, loop_start, repeats, times, child_state = 0, 0, 0, 0, self.times[:], None - - # What we might be returning. - action = "continue" - arg = None - pause = None - - while action == "continue": - - # Target is the time we're willing to execute to. - # Max_pause is how long we'll wait before executing again. - - # If we have times queued up, then use them to inform target - # and time. - if times: - time, tindex = times[0] - target = min(time, st) - max_pause = time - target - - # Otherwise, take the defaults. - else: - target = st - max_pause = 15 - - while True: - - # If we've hit the last statement, it's the end of - # this block. - if index >= len(self.statements): - return "next", target - start, None - - - # Find the statement and try to run it. - stmt = self.statements[index] - action, arg, pause = stmt.execute(trans, target - start, child_state, event) - - # On continue, persist our state. - if action == "continue": - if pause is None: - pause = max_pause - - action, arg, pause = "continue", (index, start, loop_start, repeats, times, arg), min(max_pause, pause) - break - - elif action == "event": - return action, arg, pause - - # On next, advance to the next statement in the block. - elif action == "next": - index += 1 - start = target - arg - child_state = None - - # On repeat, either terminate the block, or go to - # the first statement. - elif action == "repeat": - - count, arg = arg - loop_end = target - arg - duration = loop_end - loop_start - - if duration <= 0: - raise Exception("ATL appears to be in an infinite loop.") - - # Figure how many durations can occur between the - # start of the loop and now. - new_repeats = int((target - loop_start) / duration) - - if count is not None: - if repeats + new_repeats >= count: - new_repeats = count - repeats - loop_start += new_repeats * duration - return "next", target - loop_start, None - - repeats += new_repeats - loop_start = loop_start + new_repeats * duration - start = loop_start - index = 0 - child_state = None - - if times: - time, tindex = times[0] - if time <= target: - times.pop(0) - - index = tindex - start = time - child_state = None - - continue - - return action, arg, pause - - def visit(self): - return [ j for i in self.statements for j in i.visit() ] - -# This can become one of four things: -# -# - A pause. -# - An interpolation (which optionally can also reference other -# blocks, as long as they're not time-dependent, and have the same -# arity as the interpolation). -# - A call to another block. -# - A command to change the image, perhaps with a transition. -# -# We won't decide which it is until runtime, as we need the -# values of the variables here. -class RawMultipurpose(RawStatement): - - warp_function = None - - def __init__(self, loc): - - super(RawMultipurpose, self).__init__(loc) - - self.warper = None - self.duration = None - self.properties = [ ] - self.expressions = [ ] - self.splines = [ ] - self.revolution = None - self.circles = "0" - - def add_warper(self, name, duration, warp_function): - self.warper = name - self.duration = duration - self.warp_function = warp_function - - def add_property(self, name, exprs): - self.properties.append((name, exprs)) - - def add_expression(self, expr, with_clause): - self.expressions.append((expr, with_clause)) - - def add_revolution(self, revolution): - self.revolution = revolution - - def add_circles(self, circles): - self.circles = circles - - def add_spline(self, name, exprs): - self.splines.append((name, exprs)) - - def compile(self, ctx): #@ReservedAssignment - - compiling(self.loc) - - # Figure out what kind of statement we have. If there's no - # interpolator, and no properties, than we have either a - # call, or a child statement. - if (self.warper is None and - self.warp_function is None and - not self.properties and - not self.splines and - len(self.expressions) == 1): - - expr, withexpr = self.expressions[0] - - child = ctx.eval(expr) - if withexpr: - transition = ctx.eval(withexpr) - else: - transition = None - - if isinstance(child, (int, float)): - return Interpolation(self.loc, "pause", child, [ ], None, 0, [ ]) - - if isinstance(child, ATLTransformBase): - child.compile() - return child.block - - else: - return Child(self.loc, child, transition) - - compiling(self.loc) - - # Otherwise, we probably have an interpolation statement. - - if self.warp_function: - warper = ctx.eval(self.warp_function) - else: - warper = self.warper or "pause" - - if warper not in warpers: - raise Exception("ATL Warper %s is unknown at runtime." % warper) - - properties = [ ] - - for name, expr in self.properties: - if name not in PROPERTIES: - raise Exception("ATL Property %s is unknown at runtime." % property) - - value = ctx.eval(expr) - properties.append((name, value)) - - splines = [ ] - - for name, exprs in self.splines: - if name not in PROPERTIES: - raise Exception("ATL Property %s is unknown at runtime." % property) - - values = [ ctx.eval(i) for i in exprs ] - - splines.append((name, values)) - - for expr, _with in self.expressions: - try: - value = ctx.eval(expr) - except: - raise Exception("Could not evaluate expression %r when compiling ATL." % expr) - - if not isinstance(value, ATLTransformBase): - raise Exception("Expression %r is not an ATL transform, and so cannot be included in an ATL interpolation." % expr) - - value.compile() - - if value.properties is None: - raise Exception("ATL transform %r is too complicated to be included in interpolation." % expr) - - - properties.extend(value.properties) - - duration = ctx.eval(self.duration) - circles = ctx.eval(self.circles) - - return Interpolation(self.loc, warper, duration, properties, self.revolution, circles, splines) - - def predict(self, ctx): - - for i, _j in self.expressions: - - try: - i = ctx.eval(i) - except: - continue - - if isinstance(i, ATLTransformBase): - i.atl.predict(ctx) - return - - try: - renpy.easy.predict(i) - except: - continue - -# This lets us have an ATL transform as our child. -class RawContainsExpr(RawStatement): - - def __init__(self, loc, expr): - - super(RawContainsExpr, self).__init__(loc) - - self.expression = expr - - def compile(self, ctx): #@ReservedAssignment - compiling(self.loc) - child = ctx.eval(self.expression) - return Child(self.loc, child, None) - - -# This allows us to have multiple children, inside a Fixed. -class RawChild(RawStatement): - - def __init__(self, loc, child): - - super(RawChild, self).__init__(loc) - - self.children = [ child ] - - def compile(self, ctx): #@ReservedAssignment - box = renpy.display.layout.MultiBox(layout='fixed') - - for i in self.children: - box.add(renpy.display.motion.ATLTransform(i, context=ctx.context)) - - return Child(self.loc, box, None) - - -# This changes the child of this statement, optionally with a transition. -class Child(Statement): - - def __init__(self, loc, child, transition): - - super(Child, self).__init__(loc) - - self.child = renpy.easy.displayable(child) - self.transition = transition - - def execute(self, trans, st, state, event): - - executing(self.loc) - - old_child = trans.raw_child - - if (old_child is not None) and (old_child is not renpy.display.motion.null) and (self.transition is not None): - child = self.transition(old_widget=old_child, - new_widget=self.child) - else: - child = self.child - - trans.set_child(child) - trans.raw_child = self.child - - return "next", st, None - - def visit(self): - return [ self.child ] - - -# This causes interpolation to occur. -class Interpolation(Statement): - - def __init__(self, loc, warper, duration, properties, revolution, circles, splines): - - super(Interpolation, self).__init__(loc) - - self.warper = warper - self.duration = duration - self.properties = properties - self.splines = splines - - # The direction we revolve in: cw, ccw, or None. - self.revolution = revolution - - # The number of complete circles we make. - self.circles = circles - - def execute(self, trans, st, state, event): - - executing(self.loc) - - warper = warpers.get(self.warper, self.warper) - - if self.duration: - complete = min(1.0, st / self.duration) - else: - complete = 1.0 - - complete = warper(complete) - - if state is None: - - # Create a new transform state, and apply the property - # changes to it. - newts = renpy.display.motion.TransformState() - newts.take_state(trans.state) - - for k, v in self.properties: - setattr(newts, k, v) - - # Now, the things we change linearly are in the difference - # between the new and old states. - linear = trans.state.diff(newts) - - revolution = None - splines = [ ] - - # Clockwise revolution. - if self.revolution is not None: - - # Remove various irrelevant motions. - for i in [ 'xpos', 'ypos', - 'xanchor', 'yanchor', - 'xaround', 'yaround', - 'xanchoraround', 'yanchoraround', - ]: - - linear.pop(i, None) - - if newts.xaround is not None: - - # Ensure we rotate around the new point. - trans.state.xaround = newts.xaround - trans.state.yaround = newts.yaround - trans.state.xanchoraround = newts.xanchoraround - trans.state.yanchoraround = newts.yanchoraround - - # Get the start and end angles and radii. - startangle = trans.state.angle - endangle = newts.angle - startradius = trans.state.radius - endradius = newts.radius - - # Make sure the revolution is in the appropriate direction, - # and contains an appropriate number of circles. - - if self.revolution == "clockwise": - if endangle < startangle: - startangle -= 360 - - startangle -= self.circles * 360 - - elif self.revolution == "counterclockwise": - if endangle > startangle: - startangle += 360 - - startangle += self.circles * 360 - - # Store the revolution. - revolution = (startangle, endangle, startradius, endradius) - - # Figure out the splines. - for name, values in self.splines: - splines.append((name, [ getattr(trans.state, name) ] + values)) - - state = (linear, revolution, splines) - - # Ensure that we set things, even if they don't actually - # change from the old state. - for k, v in self.properties: - if k not in linear: - setattr(trans.state, k, v) - - else: - linear, revolution, splines = state - - # Linearly interpolate between the things in linear. - for k, (old, new) in linear.items(): - value = interpolate(complete, old, new, PROPERTIES[k]) - - setattr(trans.state, k, value) - - # Handle the revolution. - if revolution is not None: - startangle, endangle, startradius, endradius = revolution - trans.state.angle = interpolate(complete, startangle, endangle, float) - trans.state.radius = interpolate(complete, startradius, endradius, float) - - - # Handle any splines we might have. - for name, values in splines: - value = interpolate_spline(complete, values) - setattr(trans.state, name, value) - - if st >= self.duration: - return "next", st - self.duration, None - else: - if not self.properties and not self.revolution and not self.splines: - return "continue", state, self.duration - st - else: - return "continue", state, 0 - - -# Implementation of the repeat statement. -class RawRepeat(RawStatement): - - def __init__(self, loc, repeats): - - super(RawRepeat, self).__init__(loc) - - self.repeats = repeats - - def compile(self, ctx): #@ReservedAssignment - - compiling(self.loc) - - repeats = self.repeats - - if repeats is not None: - repeats = ctx.eval(repeats) - - return Repeat(self.loc, repeats) - -class Repeat(Statement): - - def __init__(self, loc, repeats): - - super(Repeat, self).__init__(loc) - - self.repeats = repeats - - def execute(self, trans, st, state, event): - return "repeat", (self.repeats, st), 0 - - -# Parallel statement. - -class RawParallel(RawStatement): - - def __init__(self, loc, block): - - super(RawParallel, self).__init__(loc) - self.blocks = [ block ] - - def compile(self, ctx): #@ReservedAssignment - return Parallel(self.loc, [i.compile(ctx) for i in self.blocks]) - - def predict(self, ctx): - for i in self.blocks: - i.predict(ctx) - - -class Parallel(Statement): - - def __init__(self, loc, blocks): - super(Parallel, self).__init__(loc) - self.blocks = blocks - - def execute(self, trans, st, state, event): - - executing(self.loc) - - if state is None: - state = [ (i, None) for i in self.blocks ] - - # The amount of time left after finishing this block. - left = [ ] - - # The duration of the pause. - pauses = [ ] - - # The new state structure. - newstate = [ ] - - for i, istate in state: - - action, arg, pause = i.execute(trans, st, istate, event) - - if pause is not None: - pauses.append(pause) - - if action == "continue": - newstate.append((i, arg)) - elif action == "next": - left.append(arg) - elif action == "event": - return action, arg, pause - - if newstate: - return "continue", newstate, min(pauses) - else: - return "next", min(left), None - - def visit(self): - return [ j for i in self.blocks for j in i.visit() ] - - -# The choice statement. - -class RawChoice(RawStatement): - - def __init__(self, loc, chance, block): - super(RawChoice, self).__init__(loc) - - self.choices = [ (chance, block) ] - - def compile(self, ctx): #@ReservedAssignment - compiling(self.loc) - return Choice(self.loc, [ (ctx.eval(chance), block.compile(ctx)) for chance, block in self.choices]) - - def predict(self, ctx): - for _i, j in self.choices: - j.predict(ctx) - -class Choice(Statement): - - def __init__(self, loc, choices): - - super(Choice, self).__init__(loc) - - self.choices = choices - - def execute(self, trans, st, state, event): - - executing(self.loc) - - if state is None: - - total = 0 - for chance, choice in self.choices: - total += chance - - n = random.uniform(0, total) - - for chance, choice in self.choices: - if n < chance: - break - n -= chance - - cstate = None - - else: - choice, cstate = state - - action, arg, pause = choice.execute(trans, st, cstate, event) - - if action == "continue": - return "continue", (choice, arg), pause - else: - return action, arg, None - - def visit(self): - return [ j for i in self.choices for j in i[1].visit() ] - - -# The Time statement. - -class RawTime(RawStatement): - - def __init__(self, loc, time): - - super(RawTime, self).__init__(loc) - self.time = time - - def compile(self, ctx): #@ReservedAssignment - compiling(self.loc) - return Time(self.loc, ctx.eval(self.time)) - -class Time(Statement): - - def __init__(self, loc, time): - super(Time, self).__init__(loc) - - self.time = time - - def execute(self, trans, st, state, event): - return "continue", None, None - - -# The On statement. - -class RawOn(RawStatement): - - def __init__(self, loc, name, block): - super(RawOn, self).__init__(loc) - - self.handlers = { name : block } - - def compile(self, ctx): #@ReservedAssignment - - compiling(self.loc) - - handlers = { } - - for k, v in self.handlers.items(): - handlers[k] = v.compile(ctx) - - return On(self.loc, handlers) - - def predict(self, ctx): - for i in self.handlers.values(): - i.predict(ctx) - -class On(Statement): - - def __init__(self, loc, handlers): - super(On, self).__init__(loc) - - self.handlers = handlers - - def execute(self, trans, st, state, event): - - executing(self.loc) - - # If it's our first time through, start in the start state. - if state is None: - name, start, cstate = ("start", st, None) - else: - name, start, cstate = state - - # If we have an external event, and we have a handler for it, - # handle it. - if event in self.handlers: - - # Do not allow people to abort the hide handler with another - # event. - if name != "hide": - name = event - start = st - cstate = None - - - while True: - - # If we don't have a handler, return until we change event. - if name not in self.handlers: - return "continue", (name, start, cstate), None - - action, arg, pause = self.handlers[name].execute(trans, st - start, cstate, event) - - # If we get a continue, save our state. - if action == "continue": - - # If it comes from a hide block, indicate that. - if name == "hide" or name == "replaced": - trans.hide_response = False - trans.replaced_response = False - - return "continue", (name, start, arg), pause - - # If we get a next, then try going to the default - # event, unless we're already in default, in which case we - # go to None. - elif action == "next": - if name == "default" or name == "hide" or name == "replaced": - name = None - else: - name = "default" - - start = st - arg - cstate = None - - continue - - # If we get an event, then either handle it if we can, or - # pass it up the stack if we can't. - elif action == "event": - - name, arg = arg - - if name in self.handlers: - start = max(st - arg, st - 30) - cstate = None - continue - - return "event", (name, arg), None - - def visit(self): - return [ j for i in self.handlers.values() for j in i.visit() ] - - -# Event statement. - -class RawEvent(RawStatement): - - def __init__(self, loc, name): - super(RawEvent, self).__init__(loc) - - self.name = name - - def compile(self, ctx): #@ReservedAssignment - return Event(self.loc, self.name) - - -class Event(Statement): - - def __init__(self, loc, name): - super(Event, self).__init__(loc) - - self.name = name - - def execute(self, trans, st, state, event): - return "event", (self.name, st), None - - -class RawFunction(RawStatement): - - def __init__(self, loc, expr): - super(RawFunction, self).__init__(loc) - - self.expr = expr - - def compile(self, ctx): #@ReservedAssignment - compiling(self.loc) - return Function(self.loc, ctx.eval(self.expr)) - - -class Function(Statement): - - def __init__(self, loc, function): - super(Function, self).__init__(loc) - - self.function = function - - def execute(self, trans, st, state, event): - fr = self.function(trans, st, trans.at) - - if fr is not None: - return "continue", None, fr - else: - return "next", 0, None - - -# This parses an ATL block. -def parse_atl(l): - - l.advance() - block_loc = l.get_location() - - statements = [ ] - - animation = False - - while not l.eob: - - loc = l.get_location() - - if l.keyword('repeat'): - - repeats = l.simple_expression() - statements.append(RawRepeat(loc, repeats)) - - elif l.keyword('block'): - l.require(':') - l.expect_eol() - l.expect_block('block') - - block = parse_atl(l.subblock_lexer()) - statements.append(block) - - elif l.keyword('contains'): - - expr = l.simple_expression() - - if expr: - - l.expect_noblock('contains expression') - statements.append(RawContainsExpr(loc, expr)) - - else: - - l.require(':') - l.expect_eol() - l.expect_block('contains') - - block = parse_atl(l.subblock_lexer()) - statements.append(RawChild(loc, block)) - - elif l.keyword('parallel'): - l.require(':') - l.expect_eol() - l.expect_block('parallel') - - block = parse_atl(l.subblock_lexer()) - statements.append(RawParallel(loc, block)) - - elif l.keyword('choice'): - - chance = l.simple_expression() - if not chance: - chance = "1.0" - - l.require(':') - l.expect_eol() - l.expect_block('choice') - - block = parse_atl(l.subblock_lexer()) - statements.append(RawChoice(loc, chance, block)) - - elif l.keyword('on'): - - name = l.require(l.word) - - l.require(':') - l.expect_eol() - l.expect_block('on') - - block = parse_atl(l.subblock_lexer()) - statements.append(RawOn(loc, name, block)) - - elif l.keyword('time'): - time = l.require(l.simple_expression) - l.expect_noblock('time') - - statements.append(RawTime(loc, time)) - - elif l.keyword('function'): - expr = l.require(l.simple_expression) - l.expect_noblock('function') - - statements.append(RawFunction(loc, expr)) - - elif l.keyword('event'): - name = l.require(l.word) - l.expect_noblock('event') - - statements.append(RawEvent(loc, name)) - - elif l.keyword('pass'): - l.expect_noblock('pass') - statements.append(None) - - elif l.keyword('animation'): - l.expect_noblock('animation') - animation = True - - else: - - # If we can't assign it it a statement more specifically, - # we try to parse it into a RawMultipurpose. That will - # then be turned into another statement, as appropriate. - - # The RawMultipurpose we add things to. - rm = renpy.atl.RawMultipurpose(loc) - - # Is the last clause an expression? - last_expression = False - - # Is this clause an expression? - this_expression = False - - # First, look for a warper. - cp = l.checkpoint() - warper = l.name() - - - if warper in warpers: - duration = l.require(l.simple_expression) - warp_function = None - - elif warper == "warp": - - warper = None - warp_function = l.require(l.simple_expression) - duration = l.require(l.simple_expression) - - else: - l.revert(cp) - - warper = None - warp_function = None - duration = "0" - - rm.add_warper(warper, duration, warp_function) - - # Now, look for properties and simple_expressions. - while True: - - # Update expression status. - last_expression = this_expression - this_expression = False - - if l.keyword('pass'): - continue - - # Parse revolution keywords. - if l.keyword('clockwise'): - rm.add_revolution('clockwise') - continue - - if l.keyword('counterclockwise'): - rm.add_revolution('counterclockwise') - continue - - if l.keyword('circles'): - expr = l.require(l.simple_expression) - rm.add_circles(expr) - - # Try to parse a property. - cp = l.checkpoint() - - prop = l.name() - - if prop in PROPERTIES: - - expr = l.require(l.simple_expression) - - # We either have a property or a spline. It's the - # presence of knots that determine which one it is. - - knots = [ ] - - while l.keyword('knot'): - knots.append(l.require(l.simple_expression)) - - if knots: - knots.append(expr) - rm.add_spline(prop, knots) - else: - rm.add_property(prop, expr) - - continue - - # Otherwise, try to parse it as a simple expressoon, - # with an optional with clause. - - l.revert(cp) - - expr = l.simple_expression() - - if not expr: - break - - if last_expression: - l.error('ATL statement contains two expressions in a row; is one of them a misspelled property? If not, separate them with pass.') - - this_expression = True - - if l.keyword("with"): - with_expr = l.require(l.simple_expression) - else: - with_expr = None - - rm.add_expression(expr, with_expr) - - l.expect_noblock('ATL') - - statements.append(rm) - - - if l.eol(): - l.advance() - continue - - l.require(",", "comma or end of line") - - - # Merge together statements that need to be merged together. - - merged = [ ] - old = None - - for new in statements: - - if isinstance(old, RawParallel) and isinstance(new, RawParallel): - old.blocks.extend(new.blocks) - continue - - elif isinstance(old, RawChoice) and isinstance(new, RawChoice): - old.choices.extend(new.choices) - continue - - elif isinstance(old, RawChild) and isinstance(new, RawChild): - old.children.extend(new.children) - continue - - elif isinstance(old, RawOn) and isinstance(new, RawOn): - old.handlers.update(new.handlers) - continue - - # None is a pause statement, which gets skipped, but also - # prevents things from combining. - elif new is None: - old = new - continue - - merged.append(new) - old = new - - return RawBlock(block_loc, merged, animation) |