# HG changeset patch # User Thibaut Girka # Date 1313169223 -7200 # Node ID 444ac7bca7bcfd9af826993cf071c4f963b0c3db # Parent fa87db09fc3ac62adfcc71765633922dfb450e9e Refacto ECL stuff, add support for a few instructions, and add some culling diff --git a/pytouhou/game/eclrunner.py b/pytouhou/game/eclrunner.py new file mode 100644 --- /dev/null +++ b/pytouhou/game/eclrunner.py @@ -0,0 +1,57 @@ +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)} + if implementation: + self.implementation.update(implementation) + + self.sub = sub + self.frame = frame + 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 goto(self, frame, unknown1, unknown2, label, unknown3): + try: + sub, instruction_pointer, count = self.labels[label] + except KeyError: + pass + else: + count -= 1 + if count: + self.labels[label] = sub, instruction_pointer, count + else: + del self.labels[label] + self.frame = frame + self.sub, self.instruction_pointer = sub, instruction_pointer + + + def update(self): + frame = self.frame + while frame <= self.frame: + try: + frame, instr_type, rank_mask, param_mask, args = self.ecl.subs[self.sub][self.instruction_pointer] + except IndexError: + break #TODO: script ended, destroy enemy + + if frame == self.frame: + try: + format, callback = self.implementation[instr_type] + except KeyError: + print('Warning: unhandled opcode %d!' % instr_type) #TODO + else: + callback(*unpack('<' + format, args)) + self.instruction_pointer += 1 + + self.frame += 1 + diff --git a/pytouhou/game/enemymanager.py b/pytouhou/game/enemymanager.py --- a/pytouhou/game/enemymanager.py +++ b/pytouhou/game/enemymanager.py @@ -3,21 +3,23 @@ from io import BytesIO import os from struct import unpack, pack from pytouhou.utils.interpolator import Interpolator +from pytouhou.game.eclrunner import ECLRunner from pytouhou.game.sprite import Sprite from math import cos, sin, atan2 class Enemy(object): - def __init__(self, pos, life, _type, script, anm_wrapper): + def __init__(self, pos, life, _type, ecl_runner, anm_wrapper): self.anm_wrapper = anm_wrapper self.anm = None - self.script = list(script) + self.ecl_runner = ecl_runner self.x, self.y = pos self.life = life self.type = _type self.frame = 0 self.sprite = None + self.death_sprite = None self.movement_dependant_sprites = None self.direction = None self.interpolator = None #TODO @@ -26,40 +28,93 @@ class Enemy(object): self.rotation_speed = 0. self.acceleration = 0. + self.hitbox = (0, 0) + + self.ecl_runner.implementation.update({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 + + + def set_death_sprite(self, sprite_index): + self.death_sprite = sprite_index % 256 #TODO + + + def set_hitbox(self, width, height, depth): + self.hitbox = (width, height) + + + def set_sprite(self, sprite_index): + self.anm, self.sprite = self.anm_wrapper.get_sprite(sprite_index) + + + def set_multiple_sprites(self, default, end_left, end_right, left, right, unknown): + self.movement_dependant_sprites = end_left, end_right, left, right, unknown + self.anm, self.sprite = self.anm_wrapper.get_sprite(default) + + + def set_angle_speed(self, angle, speed): + self.angle, self.speed = angle, speed + + + def set_pos(self, x, y, z): + self.x, self.y = x, y + self.interpolator = Interpolator((x, y)) + self.interpolator.set_interpolation_start(self.frame, (x, y)) + + + def set_rotation_speed(self, speed): + self.rotation_speed = speed + + + def set_speed(self, speed): + self.speed = speed + + + def set_acceleration(self, acceleration): + self.acceleration = acceleration + + + def target_player(self, unknown, speed): + self.speed = speed #TODO: unknown + player_x, player_y = 192., 400.#TODO + self.angle = atan2(player_y - self.y, player_x - self.x) + + + def move_to(self, duration, x, y, z): + self.interpolator.set_interpolation_end(self.frame + duration, (x, y)) + + + def is_visible(self, screen_width, screen_height): + if not self.sprite: + return False + if min(x for x, y, z in self.sprite._vertices) >= screen_width - self.x: + return False + if max(x for x, y, z in self.sprite._vertices) <= -self.x: + return False + if min(y for x, y, z in self.sprite._vertices) >= screen_height - self.y: + return False + if max(y for x, y, z in self.sprite._vertices) <= -self.y: + return False + return True + def update(self, frame): - if not self.script: - return True - if self.script[0][0] == self.frame: - for instr_type, rank_mask, param_mask, args in self.script.pop(0)[1]: - if instr_type == 1: # delete - return False - elif instr_type == 97: # set_enemy_sprite - script_index, = unpack('