# HG changeset patch # User Thibaut Girka # Date 1315066659 -7200 # Node ID ffe2c2b9912cbc22fcc55ec824bd57bcf777396e # Parent bcf965ede96cec935c0c8a7b746d795533463a8d Handle a few more ECL instructions. Prepare for bullet handling \o/ diff --git a/pytouhou/formats/ecl.py b/pytouhou/formats/ecl.py --- a/pytouhou/formats/ecl.py +++ b/pytouhou/formats/ecl.py @@ -101,7 +101,7 @@ class ECL(object): 101: ('i', 'set_boss_mode?'), 102: ('iffff', 'create_squares'), 103: ('fff', 'set_enemy_hitbox'), - 104: ('i', None), + 104: ('i', 'set_collidable'), 105: ('i', 'set_damageable'), 106: ('i', 'play_sound'), 107: ('i', 'set_death_flags'), diff --git a/pytouhou/game/enemymanager.py b/pytouhou/game/enemymanager.py --- a/pytouhou/game/enemymanager.py +++ b/pytouhou/game/enemymanager.py @@ -21,11 +21,12 @@ from pytouhou.utils.interpolator import from pytouhou.vm.eclrunner import ECLRunner from pytouhou.vm.anmrunner import ANMRunner from pytouhou.game.sprite import Sprite -from math import cos, sin, atan2 +from math import cos, sin, atan2, pi class Enemy(object): - def __init__(self, pos, life, _type, anm_wrapper): + def __init__(self, pos, life, _type, anm_wrapper, game_state): + self._game_state = game_state self._anm_wrapper = anm_wrapper self._sprite = None self._anmrunner = None @@ -42,6 +43,7 @@ class Enemy(object): self.damageable = True self.death_flags = 0 self.pending_bullets = [] + self.extended_bullet_attributes = (0, 0, 0, 0, 0., 0., 0., 0.) self.bullet_attributes = None self.bullet_launch_offset = (0, 0) self.death_callback = None @@ -71,25 +73,34 @@ class Enemy(object): def set_bullet_attributes(self, type_, bullet_anim, launch_anim, - bullets_per_shot, number_of_shots, speed, unknown, + bullets_per_shot, number_of_shots, speed, speed2, launch_angle, angle, flags): self.bullet_attributes = (type_, bullet_anim, launch_anim, bullets_per_shot, - number_of_shots, speed, unknown, launch_angle, + number_of_shots, speed, speed2, launch_angle, angle, flags) if not self.delay_attack: self.fire() def fire(self): + (type_, bullet_anim, launch_anim, bullets_per_shot, number_of_shots, + speed, speed2, launch_angle, angle, flags) = self.bullet_attributes + if type_ in (67, 69, 71): + launch_angle += self.get_player_angle() + if type_ in (69, 70, 71): + angle = 2. * pi / bullets_per_shot + if type_ == 71: + launch_angle += pi / bullets_per_shot #TODO pass - def select_player(self, players): - return players[0] #TODO + def select_player(self, players=None): + return (players or self._game_state.players)[0] #TODO - def get_player_angle(self, player): + def get_player_angle(self, player=None): + player = player or self.select_player() return atan2(player.y - self.y, player.x - self.x) @@ -255,7 +266,7 @@ class EnemyManager(object): y = self._game_state.prng.rand_double() * 416 if z < -990: #102h.exe@0x411881 y = self._game_state.prng.rand_double() * 800 - enemy = Enemy((x, y), life, instr_type, self.anm_wrapper) + enemy = Enemy((x, y), life, instr_type, self.anm_wrapper, self._game_state) self.enemies.append(enemy) self.processes.append(ECLRunner(self.ecl, sub, enemy, self._game_state)) diff --git a/pytouhou/vm/eclrunner.py b/pytouhou/vm/eclrunner.py --- a/pytouhou/vm/eclrunner.py +++ b/pytouhou/vm/eclrunner.py @@ -99,20 +99,19 @@ class ECLRunner(object): elif value == -10017: return self._enemy.z elif value == -10018: - player = self._enemy.select_player(self._game_state.players) + player = self._enemy.select_player() return player.x elif value == -10019: - player = self._enemy.select_player(self._game_state.players) + player = self._enemy.select_player() return player.y elif value == -10021: - player = self._enemy.select_player(self._game_state.players) - return self._enemy.get_player_angle(player) + return self._enemy.get_player_angle() elif value == -10022: return self._enemy.frame elif value == -10024: return self._enemy.life elif value == -10025: - return self._enemy.select_player(self._game_state.players).character + return self._enemy.select_player().character raise NotImplementedError(value) #TODO else: return value @@ -383,7 +382,7 @@ class ECLRunner(object): def target_player(self, unknown, speed): #TODO: unknown self._enemy.speed = speed - self._enemy.angle = self._enemy.get_player_angle(self._enemy.select_player(self._game_state.players)) + self._enemy.angle = self._enemy.get_player_angle() @instruction(56) @@ -423,12 +422,73 @@ class ECLRunner(object): @instruction(67) def set_bullet_attributes1(self, bullet_anim, launch_anim, bullets_per_shot, - number_of_shots, speed, unknown, launch_angle, - angle, flags): - self._enemy.set_bullet_attributes(1, bullet_anim, launch_anim, - bullets_per_shot, number_of_shots, - speed, unknown, launch_angle, angle, - flags) + number_of_shots, speed, speed2, launch_angle, + angle, flags): + self._enemy.set_bullet_attributes(67, bullet_anim, launch_anim, + self._getval(bullets_per_shot), + self._getval(number_of_shots), + self._getval(speed), + self._getval(speed2), + self._getval(launch_angle), + self._getval(angle), + flags) + + + @instruction(68) + def set_bullet_attributes2(self, bullet_anim, launch_anim, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags): + self._enemy.set_bullet_attributes(68, bullet_anim, launch_anim, + self._getval(bullets_per_shot), + self._getval(number_of_shots), + self._getval(speed), + self._getval(speed2), + self._getval(launch_angle), + self._getval(angle), + flags) + + + @instruction(69) + def set_bullet_attributes3(self, bullet_anim, launch_anim, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags): + self._enemy.set_bullet_attributes(69, bullet_anim, launch_anim, + self._getval(bullets_per_shot), + self._getval(number_of_shots), + self._getval(speed), + self._getval(speed2), + self._getval(launch_angle), + self._getval(angle), + flags) + + + @instruction(70) + def set_bullet_attributes4(self, bullet_anim, launch_anim, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags): + self._enemy.set_bullet_attributes(67, bullet_anim, launch_anim, + self._getval(bullets_per_shot), + self._getval(number_of_shots), + self._getval(speed), + self._getval(speed2), + self._getval(launch_angle), + self._getval(angle), + flags) + + + @instruction(71) + def set_bullet_attributes5(self, bullet_anim, launch_anim, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags): + self._enemy.set_bullet_attributes(71, bullet_anim, launch_anim, + self._getval(bullets_per_shot), + self._getval(number_of_shots), + self._getval(speed), + self._getval(speed2), + self._getval(launch_angle), + self._getval(angle), + flags) + @instruction(76) @@ -457,6 +517,11 @@ class ECLRunner(object): self._enemy.bullet_launch_offset = (x, y) + @instruction(82) + def set_extended_bullet_attributes(self, *attributes): + self._enemy.extended_bullet_attributes = attributes + + @instruction(97) def set_anim(self, sprite_index): self._enemy.set_anim(sprite_index) @@ -484,6 +549,14 @@ class ECLRunner(object): self._enemy.hitbox = (width, height) + @instruction(104) + def set_collidable(self, collidable): + """Defines whether the enemy is “collidable”. + A collision between a collidable enemy and the player will kill the player. + """ + self._enemy.collidable = bool(collidable & 1) + + @instruction(105) def set_damageable(self, damageable): self._enemy.damageable = bool(damageable & 1)