Mercurial > touhou
changeset 316:f0be7ea62330
Fix a bug with ECL instruction 96, and fix overall ECL handling.
The issue with instruction 96 was about death callbacks,
being executed on the caller of instruction 96 instead of the dying enemies.
This was introduced by changeset 5930b33a0370.
Additionnaly, ECL processes are now an attribute of the Enemy,
and death/timeout conditions are checked right after the ECL frame,
even if the ECL script has already ended, just like in the original game.
| author | Thibaut Girka <thib@sitedethib.com> |
|---|---|
| date | Thu, 29 Mar 2012 21:18:35 +0200 |
| parents | e935ed8dc5e6 |
| children | 8579c43c124c |
| files | pytouhou/game/enemy.py pytouhou/game/game.py pytouhou/vm/eclrunner.py |
| diffstat | 3 files changed, 34 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/pytouhou/game/enemy.py +++ b/pytouhou/game/enemy.py @@ -28,6 +28,7 @@ self._anm_wrapper = anm_wrapper self._type = _type + self.process = None self.sprite = None self.anmrunner = None self.removed = False @@ -340,6 +341,9 @@ def update(self): + if self.process: + self.process.run_iteration() + x, y = self.x, self.y if self.update_mode == 1:
--- a/pytouhou/game/game.py +++ b/pytouhou/game/game.py @@ -163,10 +163,12 @@ def run_iter(self, keystate): # 1. VMs. self.ecl_runner.run_iter() + + # 2. Modify difficulty if self.frame % (32*60) == (32*60): #TODO: check if that is really that frame. self.modify_difficulty(+100) - # 2. Filter out destroyed enemies + # 3. Filter out destroyed enemies self.enemies = [enemy for enemy in self.enemies if not enemy.removed] self.effects = [effect for effect in self.effects if not effect.removed] self.bullets = [bullet for bullet in self.bullets if not bullet.removed] @@ -174,7 +176,7 @@ self.items = [item for item in self.items if not item.removed] - # 3. Let's play! + # 4. Let's play! # In the original game, updates are done in prioritized functions called "chains" # We have to mimic this functionnality to be replay-compatible with the official game. @@ -191,7 +193,7 @@ laser.update() self.interface.update() # Pri 12 - # 4. Cleaning + # 5. Clean up self.cleanup() self.frame += 1
--- a/pytouhou/vm/eclrunner.py +++ b/pytouhou/vm/eclrunner.py @@ -25,7 +25,7 @@ class ECLMainRunner(object): __metaclass__ = MetaRegistry - __slots__ = ('_ecl', '_game', 'processes', 'frame', + __slots__ = ('_ecl', '_game', 'frame', 'instruction_pointer', 'boss_wait') @@ -35,8 +35,6 @@ self.frame = 0 self.boss_wait = False - self.processes = [] - self.instruction_pointer = 0 @@ -64,9 +62,6 @@ else: callback(self, sub, instr_type, *args) - self.processes[:] = (process for process in self.processes - if process.run_iteration()) - if not (self._game.msg_wait or self.boss_wait): self.frame += 1 @@ -79,10 +74,10 @@ y = self._game.prng.rand_double() * 416 if z < -990: #102h.exe@0x411881 z = self._game.prng.rand_double() * 800 - enemy = self._game.new_enemy((x, y, z), life, instr_type, bonus_dropped, die_score) - process = ECLRunner(self._ecl, sub, enemy, self._game) - self.processes.append(process) - process.run_iteration() + enemy = self._game.new_enemy((x, y, z), life, instr_type, + bonus_dropped, die_score) + enemy.process = ECLRunner(self._ecl, sub, enemy, self._game) #TODO + enemy.process.run_iteration() @instruction(0) @@ -126,7 +121,8 @@ class ECLRunner(object): __metaclass__ = MetaRegistry __slots__ = ('_ecl', '_enemy', '_game', 'variables', 'sub', 'frame', - 'instruction_pointer', 'comparison_reg', 'stack') + 'instruction_pointer', 'comparison_reg', 'stack', + 'running') def __init__(self, ecl, sub, enemy, game): # Things not supposed to change @@ -134,6 +130,8 @@ self._enemy = enemy self._game = game + self.running = True + # Things supposed to change (and be put in the stack) self.variables = [0, 0, 0, 0, 0., 0., 0., 0., @@ -145,6 +143,7 @@ def switch_to_sub(self, sub): + self.running = True self.frame = 0 self.sub = sub self.instruction_pointer = 0 @@ -207,20 +206,15 @@ else: raise Exception('What the hell, man!') + def run_iteration(self): - # First, if enemy is dead, return - if self._enemy.removed: - return False - - # Then, check for callbacks - self.handle_callbacks() - - # Now, process script - while True: + # Process script + while self.running: try: frame, instr_type, rank_mask, param_mask, args = self._ecl.subs[self.sub][self.instruction_pointer] except IndexError: - return False + self.running = False + break if frame > self.frame: break @@ -240,7 +234,9 @@ logger.debug('executed opcode %d (args: %r)', instr_type, args) self.frame += 1 - return True + + # Handle callbacks + self.handle_callbacks() def _getval(self, value): @@ -826,16 +822,15 @@ @instruction(96) def kill_enemies(self): - for proc in self._game.ecl_runner.processes: - if proc._enemy.boss: + for enemy in self._game.enemies: + if enemy.boss: pass # Bosses are immune to 96 - elif proc._enemy.touchable: - proc._enemy.life = 0 - elif proc._enemy.death_callback > 0: + elif enemy.touchable: + enemy.life = 0 + elif enemy.death_callback > 0: #TODO: check - #TODO: refactor - self.switch_to_sub(proc._enemy.death_callback) - proc._enemy.death_callback = -1 + enemy.process.switch_to_sub(enemy.death_callback) + enemy.death_callback = -1 @instruction(97)
