def test_react_on_property(self): performer = Performer(self.schedule, self.ensemble) self.assertEqual(1, self.ensemble[0].state) action = Model.Property(None, self.ensemble[0], "state", 0) rv = performer.react(action) self.assertIs(action, rv) self.assertEqual(0, self.ensemble[0].state)
def test_exact_matching(self): content = textwrap.dedent(""" .. entity:: WHATEVER Test exact ~~~~~~~~~~ One --- .. condition:: WHATEVER.value 1 One. Two --- .. condition:: WHATEVER.value 2 Two. """) script = SceneScript("inline", doc=SceneScript.read(content)) selection = script.select([DataObject(value=1)]) self.assertTrue(all(selection.values())) script.cast(selection) model = script.run() conditions = [l for s, l in model if isinstance(l, Model.Condition)] self.assertEqual(2, len(conditions)) self.assertTrue(Performer.allows(conditions[0])) self.assertFalse(Performer.allows(conditions[1]))
def test_react_on_memory(self): performer = Performer(self.schedule, self.ensemble) self.assertEqual(1, self.ensemble[0].state) action = Model.Memory(self.ensemble[0], None, 0, "text", "<html/>") rv = performer.react(action) self.assertIs(action, rv) self.assertEqual(0, self.ensemble[0].state)
def frame(self, dwell=0.3, pause=1, react=True): """ Return the next shot of dialogue as an animated frame.""" while True: try: frame = self.frames.pop(0) except IndexError: self.log.debug("No more frames.") raise if all([Performer.allows(i) for i in frame[Model.Condition]]): frame[Model.Line] = list( self.animate_lines(frame[Model.Line], dwell, pause)) frame[Model.Audio] = list( self.animate_audio(frame[Model.Audio])) frame[Model.Still] = list( self.animate_stills(frame[Model.Still])) for p in frame[Model.Property]: if react and p.object is not None: setattr(p.object, p.attr, p.val) for m in frame[Model.Memory]: if react and m.object is None: m.subject.set_state(m.state) try: if m.subject.memories[-1].state != m.state: m.subject.memories.append(m) except AttributeError: m.subject.memories = deque([m], maxlen=6) except IndexError: m.subject.memories.append(m) return frame
def setUpClass(cls): cls.asscns = associations() cls.ensemble = list(cls.asscns.ensemble()) + [ Player(name="Player").set_state(Spot.grid_1205).set_state(Time.eve_predawn) ] cls.dialogue = copy.deepcopy(episodes) cls.characters = { k.__name__: v for k, v in group_by_type(cls.ensemble).items() } cls.performer = Performer(cls.dialogue, cls.ensemble)
def frame(session, entities): """Return the next frame of action for presentation handling.""" while not session.frames: matcher = Matcher(carmen.logic.episodes) branching = list(matcher.options(session.cache.get("metadata", {}))) performer = Performer(branching, entities) folder, index, script, selection, interlude = performer.next( branching, entities) scene = performer.run(react=False) frames = list( Handler.frames(folder.paths[index], scene, dwell=0.3, pause=1)) if frames and interlude: frames[-1].append( Handler.Element( None, functools.partial(interlude, folder, index, entities, **session.cache), None, None, None)) session.frames.extend(frames) return session.frames.popleft()
def setUpClass(cls): cls.ensemble = bluemonday78.story.ensemble( bluemonday78.story.build_narrator()) cls.characters = collections.defaultdict(list) for obj in cls.ensemble: cls.characters[obj.get_state(Look)].append(obj) for obj in cls.ensemble: cls.characters[obj.get_state(Mode)].append(obj) for obj in cls.ensemble: cls.characters[obj.get_state(Trade)].append(obj) cls.performer = Performer(list(bluemonday78.story.prepare_folders()), cls.ensemble)
def test_condition_evaluation_two(self): effects = [ ConditionDirectiveTests.Rain().set_state( ConditionDirectiveTests.Weather.quiet), ConditionDirectiveTests.Sleet().set_state( ConditionDirectiveTests.Weather.stormy), ConditionDirectiveTests.Snow().set_state( ConditionDirectiveTests.Weather.stormy), ] script = SceneScript("inline", doc=SceneScript.read(self.content)) selection = script.select(effects) self.assertTrue(all(selection.values())) script.cast(selection) model = script.run() conditions = [l for s, l in model if isinstance(l, Model.Condition)] self.assertEqual(4, len(conditions)) self.assertTrue(Performer.allows(conditions[0])) self.assertFalse(Performer.allows(conditions[1])) self.assertTrue(Performer.allows(conditions[2])) self.assertFalse(Performer.allows(conditions[3]))
def test_run_filters_conditional_content(self): parent = str(Path(__file__).parent) with tempfile.NamedTemporaryFile(dir=parent, suffix=".rst") as scriptFile: scriptFile.write( ConditionDirectiveTests.content.replace( "test_model", "test_performer").encode("utf8")) scriptFile.flush() folder = SceneScript.Folder( pkg=__name__, description="Test dialogue", metadata={}, paths=[str(Path(scriptFile.name).relative_to(parent))], interludes=None) performer = Performer([folder], ConditionDirectiveTests.effects[0:1]) output = list(performer.run()) self.assertEqual( 2, len([i for i in output if isinstance(i, Model.Line)]))
def test_regex_matching_state(self): content = textwrap.dedent(""" .. entity:: WHATEVER Test exact ~~~~~~~~~~ Even ---- .. condition:: WHATEVER.state ([02468]) Even. Odd --- .. condition:: WHATEVER.state ([13579]) Odd. """) obj = Stateful() script = SceneScript("inline", doc=SceneScript.read(content)) selection = script.select([obj]) self.assertTrue(all(selection.values())) script.cast(selection) model = script.run() conditions = [l for s, l in model if isinstance(l, Model.Condition)] self.assertEqual(2, len(conditions)) self.assertTrue(Performer.allows(conditions[0]), conditions[0]) self.assertFalse(Performer.allows(conditions[1])) obj.state = 1 self.assertFalse(Performer.allows(conditions[0]), conditions[0]) self.assertTrue(Performer.allows(conditions[1]))
def main(args): log_manager = LogManager() log = log_manager.get_logger("main") if args.log_path: log.set_route(args.log_level, LogAdapter(), sys.stderr) log.set_route(log.Level.NOTSET, LogAdapter(), args.log_path) else: log.set_route(args.log_level, LogAdapter(), sys.stderr) folders, references = resolve_objects(args) matcher = Matcher(folders) performer = Performer(folders, references) interlude = None handler = HTMLHandler(dwell=args.dwell, pause=args.pause) items = [] folder = True log.info("Reading sources...") while folder and not performer.stopped: for i in range(args.repeat + 1): if performer.script: log.info("Script {0.fP}".format(performer.script)) folder, index, script, selection, interlude = performer.next( folders, references, strict=args.strict, roles=args.roles) for item in performer.run(strict=args.strict, roles=args.roles): items.extend(list(handler(item))) if interlude is not None: metadata = interlude(folder, index, references) folder = next(matcher.options(metadata)) log.info("Writing {0} items to output...".format(len(items))) print(handler.to_html(metadata=performer.metadata)) log.info("Done.") return 0
def rehearse( folders, references, handler, repeat=0, roles=1, strict=False, loop=None ): """Cast a set of objects into a sequence of scene scripts. Deliver the performance. :param folders: A sequence of :py:class:`turberfield.dialogue.model.SceneScript.Folder` objects. :param references: A sequence of Python objects. :param handler: A callable object. This will be invoked with every event from the performance. :param int repeat: Extra repetitions of each folder. :param int roles: Maximum number of roles permitted each character. :param bool strict: Only fully-cast scripts to be performed. This function is a generator. It yields events from the performance. """ if isinstance(folders, SceneScript.Folder): folders = [folders] yield from handler(references, loop=loop) matcher = Matcher(folders) performer = Performer(folders, references) while True: folder, index, script, selection, interlude = performer.next( folders, references, strict=strict, roles=roles ) yield from handler(script, loop=loop) for item in performer.run(react=False, strict=strict, roles=roles): yield from handler(item, loop=loop) if isinstance(interlude, Callable): metadata = next(handler( interlude, folder, index, references, loop=loop ), None) yield metadata if metadata is None: return branch = next(matcher.options(metadata)) if branch != folder: performer = Performer([branch], references) if not repeat: break else: repeat -= 1
def test_play(self): performer = Performer(self.schedule, self.ensemble) self.assertEqual(10, len(list(performer.run()))) self.assertEqual(1, len(performer.shots)) self.assertEqual("action", performer.shots[-1].name)
def test_stopped(self): performer = Performer(self.schedule, self.ensemble) self.assertFalse(performer.stopped)
def pending(self) -> int: return len([ frame for frame in self.frames if all([Performer.allows(i) for i in frame[Model.Condition]]) ])
def test_run_game(self): performer = Performer(self.schedule, self.ensemble) while not performer.stopped: list(performer.run())
def test_handler_frames_conditional_dialogue(self): content = textwrap.dedent(""" .. entity:: PLAYER :types: carmen.logic.Player .. entity:: NARRATOR :types: carmen.logic.Narrator Feels ~~~~~ Hungry ------ .. condition:: PLAYER.state carmen.types.Time.day_lunch [NARRATOR]_ You're hungry. [NARRATOR]_ Nom nom nom. Tired ----- .. condition:: PLAYER.state carmen.types.Time.eve [NARRATOR]_ You're tired. [NARRATOR]_ ZZZZZZZZ. """) script = SceneScript("inline", doc=SceneScript.read(content)) ensemble = [Player(name="test").set_state(Time.day_lunch), Narrator()] script.cast(script.select(ensemble)) scene = list(HandlerTests.dialogue(script.run())) conditions = [i for i in scene if isinstance(i, Model.Condition)] self.assertEqual(2, len(conditions)) self.assertTrue(Performer.allows(conditions[0])) self.assertFalse(Performer.allows(conditions[1])) rv = list(Handler.frames(None, scene, dwell=0.3, pause=1)) self.assertEqual(2, len(rv), rv) self.assertIsInstance(rv[0][0].dialogue, Model.Line) self.assertEqual(0, rv[0][0].offset) self.assertEqual(1.3, rv[0][0].duration) self.assertEqual(1.3, rv[0][1].offset) self.assertEqual(1.6, rv[0][1].duration) self.assertAlmostEqual(2.9, Handler.refresh(rv[0], min_val=0)) self.assertIsInstance(rv[1][0].dialogue, Model.Line) self.assertEqual(0, rv[1][0].offset) self.assertEqual(1.3, rv[1][0].duration) self.assertEqual(1.3, rv[1][1].offset) self.assertEqual(1.0, rv[1][1].duration) self.assertAlmostEqual(2.3, Handler.refresh(rv[1], min_val=0)) # A reminder that conditions require exact matches, unlike the # prefix-based casting by state ensemble[0].set_state(Time.eve_midnight) scene = list(HandlerTests.dialogue(script.run())) conditions = [i for i in scene if isinstance(i, Model.Condition)] self.assertEqual(2, len(conditions)) self.assertFalse(Performer.allows(conditions[0])) self.assertFalse(Performer.allows(conditions[1]))