view pytouhou/vm/anmrunner.py @ 71:a03d7a94b997

Add support for a few ANM instructions
author Thibaut Girka <thib@sitedethib.com>
date Sat, 27 Aug 2011 20:42:16 +0200
parents a142e57218a0
children 6a08f44fa01b
line wrap: on
line source

# -*- encoding: utf-8 -*-
##
## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com>
##
## 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 random import randrange

from pytouhou.utils.helpers import get_logger
from pytouhou.vm.common import MetaRegistry, instruction

logger = get_logger(__name__)


class ANMRunner(object):
    __metaclass__ = MetaRegistry
    __slots__ = ('_anm_wrapper', '_sprite', '_running',
                 'script', 'instruction_pointer', 'frame')


    def __init__(self, anm_wrapper, script_id, sprite):
        self._anm_wrapper = anm_wrapper
        self._sprite = sprite
        self._running = True

        anm, self.script = anm_wrapper.get_script(script_id)
        self.frame = 0
        self.instruction_pointer = 0
        pass


    def run_frame(self):
        if self._sprite._removed:
            return False

        while self._running:
            try:
                frame, instr_type, args = self.script[self.instruction_pointer]
            except IndexError:
                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 opcode %d (args: %r)', instr_type, args)
                else:
                    callback(self, *args)
                    self._sprite._changed = True
        self.frame += 1
        return self._running


    @instruction(0)
    def remove(self):
        self._sprite._removed = True
        self._running = True


    @instruction(1)
    def load_sprite(self, sprite_index):
        self._sprite.anm, self._sprite.texcoords = self._anm_wrapper.get_sprite(sprite_index)


    @instruction(2)
    def set_scale(self, sx, sy):
        self._sprite.rescale = sx, sy


    @instruction(3)
    def set_alpha(self, alpha):
        self._sprite.alpha = alpha % 256 #TODO


    @instruction(4)
    def set_color(self, b, g, r):
        self._sprite.color = (r, g, b)


    @instruction(5)
    def jump(self, instruction_pointer):
        #TODO: is that really how it works?
        self.instruction_pointer = instruction_pointer
        self.frame = self.script[self.instruction_pointer][0]


    @instruction(7)
    def toggle_mirrored(self):
        self._sprite.mirrored = not self._sprite.mirrored


    @instruction(9)
    def set_rotations_3d(self, rx, ry, rz):
        self._sprite.rotations_3d = rx, ry, rz


    @instruction(10)
    def set_rotations_speed_3d(self, srx, sry, srz):
        self._sprite.rotations_speed_3d = srx, sry, srz


    @instruction(11)
    def set_scale_speed(self, ssx, ssy):
        self._sprite.scale_speed = ssx, ssy


    @instruction(12)
    def fade(self, new_alpha, duration):
        self._sprite.fade(duration, new_alpha, lambda x: x) #TODO: formula

    @instruction(15)
    @instruction(21) #TODO
    def keep_still(self):
        self._running = False

    @instruction(16)
    def load_random_sprite(self, min_idx, amp):
        #TODO: use the game's PRNG?
        self.load_sprite(min_idx + randrange(amp))


    @instruction(19)
    def move_in(self, x, y, z, duration):
        self._sprite.move_in(duration, x, y, z, lambda x: x) #TODO: formula


    @instruction(23)
    def set_corner_relative_placement(self):
        self._sprite.corner_relative_placement = True #TODO


    @instruction(25)
    def set_allow_dest_offset(self, value):
        self._sprite.allow_dest_offset = bool(value)


    @instruction(27)
    def shift_texture_x(self, dx):
        tox, toy = self._sprite.texoffsets
        self._sprite.texoffsets = tox + dx, toy


    @instruction(28)
    def shift_texture_y(self, dy):
        tox, toy = self._sprite.texoffsets
        self._sprite.texoffsets = tox, toy + dy


    @instruction(30)
    def scale_in(self, sx, sy, duration):
        self._sprite.scale_in(duration, sx, sy, lambda x: x) #TODO: formula