diff pytouhou/vm/msgrunner.py @ 286:4838e9bab0f9

Implement dialogs (MSG files).
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sun, 12 Feb 2012 16:06:03 +0100
parents
children 61adb5453e46
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/pytouhou/vm/msgrunner.py
@@ -0,0 +1,138 @@
+# -*- encoding: utf-8 -*-
+##
+## Copyright (C) 2012 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 3 only.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+
+
+from pytouhou.utils.helpers import get_logger
+
+from pytouhou.vm.common import MetaRegistry, instruction
+from pytouhou.game.face import Face
+
+logger = get_logger(__name__)
+
+
+class MSGRunner(object):
+    __metaclass__ = MetaRegistry
+    __slots__ = ('_msg', '_game', 'frame', 'sleep_time', 'allow_skip',
+                 'frozen', 'faces', 'ended', 'instruction_pointer')
+
+    def __init__(self, msg, script, game):
+        self._msg = msg.msgs[script + 10 * (game.players[0].state.character // 2)]
+        self._game = game
+        self.frame = 0
+        self.sleep_time = 0
+        self.allow_skip = True
+        self.frozen = False
+
+        self.faces = [None, None]
+        game.msg_sprites = self.objects
+        self.ended = False
+
+        self.instruction_pointer = 0
+
+
+    def objects(self):
+        return [face for face in self.faces if face] if not self.ended else []
+
+
+    def run_iteration(self):
+        while True:
+            if self.ended:
+                return False
+
+            try:
+                frame, instr_type, args = self._msg[self.instruction_pointer]
+            except IndexError:
+                self.end()
+                return False
+
+            if frame > self.frame:
+                break
+            else:
+                self.instruction_pointer += 1
+
+            if frame == self.frame:
+                try:
+                    callback = self._handlers[instr_type]
+                except KeyError:
+                    logger.warn('unhandled msg opcode %d (args: %r)', instr_type, args)
+                else:
+                    callback(self, *args)
+
+        if not self.frozen:
+            if self.sleep_time > 0:
+                self.sleep_time -= 1
+            else:
+                self.frame += 1
+
+        for face in self.faces:
+            if face:
+                face.update()
+
+        return True
+
+
+    def skip(self):
+        self.sleep_time = 0
+
+
+    def end(self):
+        self._game.msg_runner = None
+        self._game.msg_wait = False
+        self.ended = True
+
+
+    @instruction(0)
+    def unknown0(self):
+        if self.allow_skip:
+            raise Exception #TODO: seems to crash the game, but why?
+        self.end()
+
+
+    @instruction(1)
+    def enter(self, side, effect):
+        self.faces[side] = Face(self._game.msg_anm_wrapper, effect, side)
+
+
+    @instruction(2)
+    def change_face(self, side, index):
+        face = self.faces[side]
+        if face:
+            face.load(index)
+
+
+    @instruction(4)
+    def pause(self, duration):
+        self.sleep_time = duration
+
+
+    @instruction(5)
+    def animate(self, side, effect):
+        face = self.faces[side]
+        if face:
+            face.animate(effect)
+
+
+    @instruction(6)
+    def spawn_enemy_sprite(self):
+        self._game.msg_wait = False
+
+
+    @instruction(10)
+    def freeze(self):
+        self.frozen = True
+
+
+    @instruction(13)
+    def set_allow_skip(self, boolean):
+        self.allow_skip = bool(boolean)