# HG changeset patch # User Emmanuel Gil Peyrot # Date 1375537737 -7200 # Node ID 40d5f3083ebcc8f6dfe756a4477d5648179605e3 # Parent f41a26971a19d91dd761812fcb617c7545cd46e2 Implement PCB’s ANM2 format and vm. diff --git a/pytouhou/formats/anm0.py b/pytouhou/formats/anm0.py --- a/pytouhou/formats/anm0.py +++ b/pytouhou/formats/anm0.py @@ -24,6 +24,7 @@ from struct import pack, unpack from pytouhou.utils.helpers import read_string, get_logger from pytouhou.formats import WrongFormatError +from pytouhou.formats.thtx import Texture logger = get_logger(__name__) @@ -39,36 +40,84 @@ class Script(list): class ANM0(object): - _instructions = {0: ('', 'delete'), - 1: ('I', 'set_sprite'), - 2: ('ff', 'set_scale'), - 3: ('I', 'set_alpha'), - 4: ('BBBx', 'set_color'), - 5: ('I', 'jump'), - 7: ('', 'toggle_mirrored'), - 9: ('fff', 'set_3d_rotations'), - 10: ('fff', 'set_3d_rotations_speed'), - 11: ('ff', 'set_scale_speed'), - 12: ('ii', 'fade'), - 13: ('', 'set_blendmode_add'), - 14: ('', 'set_blendmode_alphablend'), - 15: ('', 'keep_still'), - 16: ('ii', 'set_random_sprite'), - 17: ('fff', 'set_3d_translation'), - 18: ('fffi', 'move_to_linear'), - 19: ('fffi', 'move_to_decel'), - 20: ('fffi', 'move_to_accel'), - 21: ('', 'wait'), - 22: ('i', 'interrupt_label'), - 23: ('', 'set_corner_relative_placement'), - 24: ('', 'wait_ex'), - 25: ('i', 'set_allow_offset'), #TODO: better name - 26: ('i', 'set_automatic_orientation'), - 27: ('f', 'shift_texture_x'), - 28: ('f', 'shift_texture_y'), - 29: ('i', 'set_visible'), - 30: ('ffi', 'scale_in'), - 31: ('i', None)} + _instructions = {0: {0: ('', 'delete'), + 1: ('I', 'set_sprite'), + 2: ('ff', 'set_scale'), + 3: ('I', 'set_alpha'), + 4: ('BBBx', 'set_color'), + 5: ('I', 'jump'), + 7: ('', 'toggle_mirrored'), + 9: ('fff', 'set_3d_rotations'), + 10: ('fff', 'set_3d_rotations_speed'), + 11: ('ff', 'set_scale_speed'), + 12: ('ii', 'fade'), + 13: ('', 'set_blendmode_add'), + 14: ('', 'set_blendmode_alphablend'), + 15: ('', 'keep_still'), + 16: ('ii', 'set_random_sprite'), + 17: ('fff', 'set_3d_translation'), + 18: ('fffi', 'move_to_linear'), + 19: ('fffi', 'move_to_decel'), + 20: ('fffi', 'move_to_accel'), + 21: ('', 'wait'), + 22: ('i', 'interrupt_label'), + 23: ('', 'set_corner_relative_placement'), + 24: ('', 'wait_ex'), + 25: ('i', 'set_allow_offset'), #TODO: better name + 26: ('i', 'set_automatic_orientation'), + 27: ('f', 'shift_texture_x'), + 28: ('f', 'shift_texture_y'), + 29: ('i', 'set_visible'), + 30: ('ffi', 'scale_in'), + 31: ('i', None)}, + + 2: {0: ('', 'noop'), + 1: ('', 'delete'), + 2: ('', 'keep_still'), + 3: ('I', 'set_sprite'), + 4: ('II', 'jump_bis'), + 5: ('III', 'jump_ex'), + 6: ('fff', 'set_3d_translation'), + 7: ('ff', 'set_scale'), + 8: ('I', 'set_alpha'), + 9: ('BBBx', 'set_color'), + 10: ('', 'toggle_mirrored'), + 12: ('fff', 'set_3d_rotations'), + 13: ('fff', 'set_3d_rotations_speed'), + 14: ('ff', 'set_scale_speed'), + 15: ('ii', 'fade'), + 16: ('I', 'set_blendmode'), + 17: ('fffi', 'move_to_linear'), + 18: ('fffi', 'move_to_decel'), + 19: ('fffi', 'move_to_accel'), + 20: ('', 'wait'), + 21: ('i', 'interrupt_label'), + 22: ('', 'set_corner_relative_placement'), + 23: ('', 'wait_ex'), + 24: ('i', 'set_allow_offset'), #TODO: better name + 25: ('i', 'set_automatic_orientation'), + 26: ('f', 'shift_texture_x'), + 27: ('f', 'shift_texture_y'), + 28: ('i', 'set_visible'), + 29: ('ffi', 'scale_in'), + 30: ('i', None), + 31: ('I', None), + 32: ('IIfff', 'move_in_linear_bis'), + 33: ('IIBBBx', 'change_color_in'), + 34: ('III', 'fade_bis'), + 35: ('IIfff', 'rotate_in_bis'), + 36: ('IIff', 'scale_in_bis'), + 37: ('II', 'set_int'), + 38: ('ff', 'set_float'), + 42: ('ff', 'decrement_float'), + 50: ('fff', 'add_float'), + 52: ('fff', 'substract_float'), + 55: ('III', 'divide_int'), + 59: ('II', 'set_random_int'), + 60: ('ff', 'set_random_float'), + 69: ('IIII', 'branch_if_not_equal'), + 79: ('I', 'wait_duration'), + 80: ('I', None)}} def __init__(self): @@ -82,67 +131,113 @@ class ANM0(object): @classmethod def read(cls, file): - nb_sprites, nb_scripts, zero1 = unpack(' 0: + self._setval(variable_id, counter_value) + self.instruction_pointer = instruction_pointer + self.frame = frame + + + @instruction(16, 7) + def set_blendfunc(self, value): + self._sprite.blendfunc = bool(value & 1) + + + @instruction(32, 7) + def move_in_bis(self, duration, formula, x, y, z): + self._sprite.move_in(duration, x, y, z, self.formulae[formula]) + + + @instruction(33, 7) + def change_color_in(self, duration, formula, r, g, b): + self._sprite.change_color_in(duration, r, g, b, self.formulae[formula]) + + + @instruction(34, 7) + def fade_bis(self, duration, formula, new_alpha): + self._sprite.fade(duration, new_alpha, self.formulae[formula]) + + + @instruction(35, 7) + def rotate_in_bis(self, duration, formula, rx, ry, rz): + self._sprite.rotate_in(duration, rx, ry, rz, self.formulae[formula]) + + + @instruction(36, 7) + def scale_in_bis(self, duration, formula, sx, sy): + self._sprite.scale_in(duration, sx, sy, self.formulae[formula]) + + + @instruction(37, 7) + @instruction(38, 7) + def set_variable(self, variable_id, value): + self._setval(variable_id, value) + + + @instruction(42, 7) + def decrement(self, variable_id, value): + self._setval(variable_id, self._getval(variable_id) - self._getval(value)) + + + @instruction(50, 7) + def add(self, variable_id, a, b): + self._setval(variable_id, self._getval(a) + self._getval(b)) + + + @instruction(52, 7) + def substract(self, variable_id, a, b): + self._setval(variable_id, self._getval(a) - self._getval(b)) + + + @instruction(55, 7) + def divide_int(self, variable_id, a, b): + self._setval(variable_id, self._getval(a) // self._getval(b)) + + + @instruction(59, 7) + def set_random_int(self, variable_id, amp): + #TODO: use the game's PRNG? + self._setval(variable_id, randrange(amp)) + + + @instruction(60, 7) + def set_random_float(self, variable_id, amp): + #TODO: use the game's PRNG? + self._setval(variable_id, amp * random()) + + + @instruction(69, 7) + def branch_if_not_equal(self, variable_id, value, instruction_pointer, frame): + if self._getval(variable_id) != value: + self.instruction_pointer = instruction_pointer + self.frame = frame + assert self.frame == self.script[self.instruction_pointer][0] + + + @instruction(79, 7) + def wait_duration(self, duration): + self.timeout = self._sprite.frame + duration + self.waiting = True