# HG changeset patch # User Thibaut Girka # Date 1314714640 -7200 # Node ID b3bd421bb895b1f5afcdf18edcc6c9ba9d0305fc # Parent adac26098408f4a97887a28ead890f2323d7e1ba Handle a few more ECL instructions diff --git a/pytouhou/formats/ecl.py b/pytouhou/formats/ecl.py --- a/pytouhou/formats/ecl.py +++ b/pytouhou/formats/ecl.py @@ -30,7 +30,7 @@ class ECL(object): 6: ('ii', 'set_random_int'), 8: ('if', 'set_random_float'), 9: ('iff', 'set_random_float2'), - 10: ('i', None), + 10: ('i', 'store_x'), 13: ('iii', 'set_random_int2'), 14: ('iii', 'substract_int'), 15: ('iii', 'multiply_int'), @@ -66,7 +66,7 @@ class ECL(object): 57: ('ifff', 'move_to'), 59: ('iffi', 'move_to2'), 61: ('i', 'stop_in'), - 63: ('i', None), + 63: ('i', 'stop_in_accel'), 65: ('ffff', 'set_screen_box'), 66: ('', 'clear_screen_box'), 67: ('hhiiffffi', 'set_bullet_attributes'), @@ -104,7 +104,7 @@ class ECL(object): 104: ('i', None), 105: ('i', 'set_damageable'), 106: ('i', 'play_sound'), - 107: ('i', None), + 107: ('i', 'set_death_flags'), 108: ('i', 'set_death_callback?'), 109: ('ii', 'memory_write_int'), 111: ('i', 'set_life'), @@ -116,10 +116,10 @@ class ECL(object): 117: ('i', 'set_touchable'), 118: ('iihh', None), 119: ('i', 'drop_bonus'), - 120: ('i', None), + 120: ('i', 'set_automatic_orientation'), 121: ('ii', None), 122: ('i', None), - 123: ('i', None), + 123: ('i', 'skip_frames'), 124: ('i', None), 125: ('', None), 126: ('i', 'set_remaining_lives'), diff --git a/pytouhou/game/enemymanager.py b/pytouhou/game/enemymanager.py --- a/pytouhou/game/enemymanager.py +++ b/pytouhou/game/enemymanager.py @@ -51,6 +51,8 @@ class Enemy(object): self.timeout_callback = None self.remaining_lives = -1 + self.automatic_orientation = False + self.bullet_launch_interval = 0 self.delay_attack = False @@ -108,15 +110,18 @@ class Enemy(object): self.interpolator.set_interpolation_start(self.frame, (self.x, self.y)) self.interpolator.set_interpolation_end(self.frame + duration - 1, (x, y)) + self.speed = 0. + self.angle = atan2(y - self.y, x - self.x) - def stop_in(self, duration): - #TODO: interpolation method and start/stop frame - # See 97 vs 98 anim conflict + + def stop_in(self, duration, formula): if not self.speed_interpolator: - self.speed_interpolator = Interpolator((self.speed,)) + self.speed_interpolator = Interpolator((self.speed,), formula) self.speed_interpolator.set_interpolation_start(self.frame, (self.speed,)) self.speed_interpolator.set_interpolation_end(self.frame + duration, (0.,)) + self.speed = 0. + def is_visible(self, screen_width, screen_height): if self._sprite: @@ -211,8 +216,9 @@ class Enemy(object): self._sprite = None else: self._sprite.update() - if self._sprite._changed: - self._sprite.update_vertices_uvs_colors() + if self._sprite._changed or self.automatic_orientation: + angle_base = self.angle if self.automatic_orientation else 0. + self._sprite.update_vertices_uvs_colors(angle_base=angle_base) self.frame += 1 diff --git a/pytouhou/game/sprite.py b/pytouhou/game/sprite.py --- a/pytouhou/game/sprite.py +++ b/pytouhou/game/sprite.py @@ -88,7 +88,7 @@ class Sprite(object): self.offset_interpolator.set_interpolation_end(self.frame + duration - 1, (x, y, z)) - def update_vertices_uvs_colors(self, override_width=0, override_height=0): + def update_vertices_uvs_colors(self, override_width=0, override_height=0, angle_base=0.): if self.fade_interpolator: self.fade_interpolator.update(self.frame) self.alpha = int(self.fade_interpolator.values[0]) @@ -115,8 +115,11 @@ class Sprite(object): vertmat.scale2d(width, height) if self.mirrored: vertmat.flip() - if self.rotations_3d != (0., 0., 0.): - rx, ry, rz = self.rotations_3d + + rx, ry, rz = self.rotations_3d + rz += angle_base + + if (rx, ry, rz) != (0., 0., 0.): if rx: vertmat.rotate_x(-rx) if ry: diff --git a/pytouhou/vm/eclrunner.py b/pytouhou/vm/eclrunner.py --- a/pytouhou/vm/eclrunner.py +++ b/pytouhou/vm/eclrunner.py @@ -198,6 +198,11 @@ class ECLRunner(object): self._setval(variable_id, self._getval(minval) + self._getval(amp) * self._game_state.prng.rand_double()) + @instruction(10) + def store_x(self, variable_id): + self._setval(variable_id, self._enemy.x) + + @instruction(13) def set_random_int2(self, variable_id, minval, amp): self._setval(variable_id, int(self._getval(minval)) + int(self._getval(amp)) * self._game_state.prng.rand_double()) @@ -382,13 +387,17 @@ class ECLRunner(object): @instruction(59) def move_to2(self, duration, x, y, z): - #TODO: not accurate - self._enemy.move_to(duration, x, y, z, lambda x: 1.0014 * x ** 2 - 0.0012 * x) + self._enemy.move_to(duration, x, y, z, lambda x: x ** 2) @instruction(61) def stop_in(self, duration): - self._enemy.stop_in(duration) + self._enemy.stop_in(duration, lambda x: x) + + + @instruction(63) + def stop_in_accel(self, duration): + self._enemy.stop_in(duration, lambda x: 1. - x) @instruction(65) @@ -459,8 +468,13 @@ class ECLRunner(object): @instruction(105) - def set_damageable(self, vulnerable): - self._enemy.damageable = bool(vulnerable & 1) + def set_damageable(self, damageable): + self._enemy.damageable = bool(damageable & 1) + + + @instruction(107) + def set_death_flags(self, death_flags): + self._enemy.death_flags = death_flags @instruction(108) @@ -521,6 +535,18 @@ class ECLRunner(object): self._enemy.touchable = bool(value) + @instruction(120) + def set_automatic_orientation(self, flags): + #TODO: does it change anything else than the sprite's rotation? + self._enemy.automatic_orientation = bool(flags & 1) #TODO: name + + + @instruction(123) + def skip_frames(self, frames): + #TODO: is that all? + self.frame += self._getval(frames) + + @instruction(126) def set_remaining_lives(self, lives): self._enemy.remaining_lives = lives