changeset 42:1b0ca2fb89f9

Refactor ECL parsing/etc.
author Thibaut Girka <thib@sitedethib.com>
date Thu, 18 Aug 2011 22:11:39 +0200
parents 93c8dc2de923
children 7195aaf95f6e
files pytouhou/formats/ecl.py pytouhou/game/eclrunner.py pytouhou/game/enemymanager.py
diffstat 3 files changed, 139 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/formats/ecl.py
+++ b/pytouhou/formats/ecl.py
@@ -5,6 +5,117 @@ from collections import namedtuple
 
 
 class ECL(object):
+    _instructions = {0: ('', 'noop?'),
+                     1: ('I', 'delete?'),
+                     2: ('Ii', 'relative_jump'),
+                     3: ('Iii', 'relative_jump_ex'),
+                     4: ('ii', 'set_counter'),
+                     5: ('if', None),
+                     6: ('ii', None),
+                     8: ('if', None),
+                     9: ('iff', None),
+                     10: ('i', None),
+                     13: ('iii', None),
+                     14: ('iii', None),
+                     15: ('iii', None),
+                     16: ('iii', None),
+                     17: ('iii', None),
+                     18: ('i', None),
+                     20: ('iff', None),
+                     21: ('iff', None),
+                     23: ('iff', None),
+                     25: ('iffff', None),
+                     26: ('i', None),
+                     27: ('ii', None),
+                     28: ('ff', None),
+                     29: ('ii', None),
+                     30: ('ii', None),
+                     31: ('ii', None),
+                     32: ('ii', None),
+                     33: ('ii', None),
+                     34: ('ii', None),
+                     35: ('iif', None),
+                     36: ('', 'return?'),
+                     39: ('iiiii', None),
+                     43: ('fff', 'set_position'),
+                     45: ('ff', 'set_angle_and_speed'),
+                     46: ('f', 'set_rotation_speed'),
+                     47: ('f', 'set_speed'),
+                     48: ('f', 'set_acceleration'),
+                     49: ('ff', None),
+                     50: ('ff', None),
+                     51: ('ff', 'set_speed_towards_player'),
+                     52: ('iff', None),
+                     56: ('iffi', None),
+                     57: ('ifff', 'move_to'),
+                     59: ('iffi', None),
+                     61: ('i', None),
+                     63: ('i', None),
+                     65: ('ffff', None),
+                     66: ('', None),
+                     67: ('hhiiffffi', 'set_bullet_attributes'),
+                     68: ('hhiiffffi', 'set_bullet_attributes2'),
+                     69: ('hhiiffffi', 'set_bullet_attributes3'),
+                     70: ('hhiiffffi', 'set_bullet_attributes4'),
+                     74: ('hhiiffffi', 'set_bullet_attributes5'),
+                     75: ('hhiiffffi', 'set_bullet_attributes6'),
+                     76: ('i', None),
+                     77: ('i', 'set_bullet_interval'),
+                     78: ('', None),
+                     79: ('', None),
+                     81: ('fff', 'set_bullet_launch_offset'),
+                     82: ('iiiiffff', None),
+                     83: ('', None),
+                     84: ('i', None),
+                     85: ('hhfiffffiiiiii', None),
+                     86: ('hhffifffiiiiii', None),
+                     87: ('i', None),
+                     88: ('if', None),
+                     90: ('iiii', None),
+                     92: ('i', None),
+                     #93: set_spellcard, a string is there
+                     94: ('', None),
+                     95: ('ifffhhi', None),
+                     96: ('', None),
+                     97: ('i', 'set_anim'),
+                     98: ('hhhhhh', 'set_multiple_anims'),
+                     99: ('ii', None),
+                     100: ('i', 'set_death_anim'),
+                     101: ('i', 'set_boss_mode?'),
+                     102: ('iffff', None),
+                     103: ('fff', 'set_enemy_hitbox'),
+                     104: ('i', None),
+                     105: ('i', 'set_vulnerable'),
+                     106: ('i', 'play_sound'),
+                     107: ('i', None),
+                     108: ('i', 'set_death_callback?'),
+                     109: ('ii', None),
+                     111: ('i', None),
+                     112: ('i', None),
+                     113: ('i', 'set_low_life_trigger'),
+                     114: ('i', 'set_low_life_callback'),
+                     115: ('i', 'set_timeout'),
+                     116: ('i', None),
+                     117: ('i', None),
+                     118: ('iihh', None),
+                     119: ('i', None),
+                     120: ('i', None),
+                     121: ('ii', None),
+                     122: ('i', None),
+                     123: ('i', None),
+                     124: ('i', None),
+                     125: ('', None),
+                     126: ('i', 'set_remaining_lives'),
+                     127: ('i', None),
+                     128: ('i', None),
+                     129: ('ii', None),
+                     130: ('i', None),
+                     131: ('ffiiii', None),
+                     132: ('i', None),
+                     133: ('', None),
+                     134: ('', None),
+                     135: ('i', None)} #TODO
+
     def __init__(self):
         self.main = []
         self.subs = [[]]
@@ -31,8 +142,12 @@ class ECL(object):
                     break
                 size, rank_mask, param_mask = unpack('<HHH', file.read(6))
                 data = file.read(size - 12)
-                #TODO: unpack data
-                ecl.subs[-1].append((time, opcode, rank_mask, param_mask, data))
+                if opcode in cls._instructions:
+                    args = unpack('<%s' % cls._instructions[opcode][0], data)
+                else:
+                    args = (data, )
+                    print('Warning: unknown opcode %d' % opcode) #TODO
+                ecl.subs[-1].append((time, opcode, rank_mask, param_mask, args))
 
         # Read main
         file.seek(main_offset)
--- a/pytouhou/game/eclrunner.py
+++ b/pytouhou/game/eclrunner.py
@@ -1,13 +1,10 @@
-from struct import unpack
-
-
 class ECLRunner(object):
     def __init__(self, ecl, sub, frame=0, instruction_pointer=0, implementation=None):
         self.ecl = ecl
 
         self.labels = {}
-        self.implementation = {4: ('HHI', self.set_label),
-                               3: ('IHHHH', self.goto)}
+        self.implementation = {4: (self.set_label),
+                               3: (self.goto)}
         if implementation:
             self.implementation.update(implementation)
 
@@ -16,22 +13,21 @@ class ECLRunner(object):
         self.instruction_pointer = instruction_pointer
 
 
-    def set_label(self, label, unknown, count):
-        assert unknown == 0xffff
-        self.labels[label] = (self.sub, self.instruction_pointer, count)
+    def set_label(self, label, count):
+        self.labels[label & 0xffff] = (self.sub, self.instruction_pointer, count)
 
 
-    def goto(self, frame, unknown1, unknown2, label, unknown3):
+    def goto(self, frame, instruction_pointer, label):
         try:
-            sub, instruction_pointer, count = self.labels[label]
+            sub, instruction_pointer, count = self.labels[label & 0xffff]
         except KeyError:
             pass
         else:
             count -= 1
             if count:
-                self.labels[label] = sub, instruction_pointer, count
+                self.labels[label & 0xffff] = sub, instruction_pointer, count
             else:
-                del self.labels[label]
+                del self.labels[label & 0xffff]
             self.frame = frame
             self.sub, self.instruction_pointer = sub, instruction_pointer
 
@@ -44,11 +40,11 @@ class ECLRunner(object):
 
                 if frame == self.frame:
                     try:
-                        format, callback = self.implementation[instr_type]
+                        callback = self.implementation[instr_type]
                     except KeyError:
                         print('Warning: unhandled opcode %d!' % instr_type) #TODO
                     else:
-                        callback(*unpack('<' + format, args))
+                        callback(*args)
                 if frame <= self.frame:
                     self.instruction_pointer += 1
         except IndexError:
--- a/pytouhou/game/enemymanager.py
+++ b/pytouhou/game/enemymanager.py
@@ -39,17 +39,17 @@ class Enemy(object):
         self.hitbox = (0, 0)
 
         self.ecl_runner.implementation.update({#67: ('HHIIffffI', self.set_bullet_attributes),
-                                               97: ('I', self.set_sprite),
-                                               98: ('HHHHHH', self.set_multiple_sprites),
-                                               45: ('ff', self.set_angle_speed),
-                                               43: ('fff', self.set_pos),
-                                               46: ('f', self.set_rotation_speed),
-                                               47: ('f', self.set_speed),
-                                               48: ('f', self.set_acceleration),
-                                               51: ('If', self.target_player),
-                                               57: ('Ifff', self.move_to),
-                                               100: ('I', self.set_death_sprite),
-                                               103: ('fff', self.set_hitbox)}) #TODO
+                                               97: (self.set_sprite),
+                                               98: (self.set_multiple_sprites),
+                                               45: (self.set_angle_speed),
+                                               43: (self.set_pos),
+                                               46: (self.set_rotation_speed),
+                                               47: (self.set_speed),
+                                               48: (self.set_acceleration),
+                                               51: (self.target_player),
+                                               57: (self.move_to),
+                                               100: (self.set_death_sprite),
+                                               103: (self.set_hitbox)}) #TODO
 
 
 
@@ -221,7 +221,7 @@ class EnemyManager(object):
                             y = random.rand_double() * 800 #102h.exe@0x411881
                     ecl_runner = ECLRunner(self.ecl, sub)
                     enemy = Enemy((x, y), life, instr_type, ecl_runner, self.anm_wrapper)
-                    ecl_runner.implementation[1] = ('I', self.make_enemy_deleter(enemy))
+                    ecl_runner.implementation[1] = self.make_enemy_deleter(enemy)
 
                     self.enemies.append(enemy)