changeset 235:e59bd7979ddc

Do a little cleanup, and fix PCB SHT usage.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 31 Dec 2011 16:31:10 +0100
parents 3cbfa2c11dec
children 741860192b56
files pytouhou/formats/exe.py pytouhou/formats/sht.py pytouhou/game/player.py pytouhou/games/eosd.py pytouhou/games/pcb.py
diffstat 5 files changed, 82 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/formats/exe.py
+++ b/pytouhou/formats/exe.py
@@ -13,7 +13,9 @@
 ## GNU General Public License for more details.
 ##
 
+from copy import copy
 from struct import Struct, unpack
+
 from pytouhou.utils.pe import PEFile
 
 from pytouhou.utils.helpers import get_logger
@@ -125,7 +127,7 @@ class SHT(object):
         character_records_va = list(cls.find_character_defs(pe_file))[0]
 
         characters = []
-        shots_offsets = []
+        shots_offsets = {}
         for character in xrange(4):
             sht = cls()
 
@@ -140,15 +142,21 @@ class SHT(object):
             sht.diagonal_speed = speed * SQ2
             sht.diagonal_focused_speed = speed_focused * SQ2
 
-            # Read from “push” operand
-            pe_file.seek_to_va(shots_func_offset + 4)
-            offset = unpack('<I', file.read(4))[0]
-            shots_offsets.append(offset)
+            # Characters might have different shot types whether they are
+            # focused or not, but properties read earlier apply to both modes.
+            focused_sht = copy(sht)
+            characters.append((sht, focused_sht))
 
-            characters.append(sht)
+            for sht, func_offset in ((sht, shots_func_offset), (focused_sht, shots_func_offset_focused)):
+                # Read from “push” operand
+                pe_file.seek_to_va(func_offset + 4)
+                offset, = unpack('<I', file.read(4))
+                if offset not in shots_offsets:
+                    shots_offsets[offset] = []
+                shots_offsets[offset].append(sht)
 
         character = 0
-        for shots_offset in shots_offsets:
+        for shots_offset, shts in shots_offsets.iteritems():
             pe_file.seek_to_va(shots_offset)
 
             level_count = 9
@@ -157,11 +165,10 @@ class SHT(object):
                 shots_count, power, offset = unpack('<III', file.read(3*4))
                 levels.append((shots_count, power, offset))
 
-            sht = characters[character]
-            sht.shots = {}
+            shots = {}
 
             for shots_count, power, offset in levels:
-                sht.shots[power] = []
+                shots[power] = []
                 pe_file.seek_to_va(offset)
 
                 for i in xrange(shots_count):
@@ -175,7 +182,10 @@ class SHT(object):
                     shot.pos = (x, y)
                     shot.hitbox = (hitbox_x, hitbox_y)
 
-                    sht.shots[power].append(shot)
+                    shots[power].append(shot)
+
+            for sht in shts:
+                sht.shots = shots
 
             character += 1
 
--- a/pytouhou/formats/sht.py
+++ b/pytouhou/formats/sht.py
@@ -29,7 +29,7 @@ class Shot(object):
         self.speed = 0.
         self.damage = 0
         self.orb = 0
-        self.shot_type = 0
+        self.type = 0
         self.sprite = 0
         self.unknown1 = None
         self.unknown2 = None
--- a/pytouhou/game/player.py
+++ b/pytouhou/game/player.py
@@ -16,6 +16,7 @@
 from pytouhou.game.sprite import Sprite
 from pytouhou.vm.anmrunner import ANMRunner
 from pytouhou.game.bullettype import BulletType
+from pytouhou.game.bullet import Bullet
 
 from math import pi
 
@@ -43,23 +44,20 @@ class PlayerState(object):
 
 
 class Player(object):
-    def __init__(self, state, game, anm_wrapper, hitbox_size=2.5, graze_hitbox_size=42., speeds=None):
+    def __init__(self, state, game, anm_wrapper):
         self._sprite = None
         self._anmrunner = None
         self._game = game
         self.anm_wrapper = anm_wrapper
 
-        self.speeds = speeds
+        self.speeds = (self.sht.horizontal_vertical_speed,
+                       self.sht.diagonal_speed,
+                       self.sht.horizontal_vertical_focused_speed,
+                       self.sht.diagonal_focused_speed)
 
-        self.hitbox_size = hitbox_size
-        self.hitbox_half_size = self.hitbox_size / 2.
-        self.graze_hitbox_size = graze_hitbox_size
-        self.graze_hitbox_half_size = self.graze_hitbox_size / 2.
+        self.hitbox_half_size = self.sht.hitbox / 2.
+        self.graze_hitbox_half_size = self.sht.graze_hitbox / 2.
 
-        self.bullet_type = BulletType(anm_wrapper, 64, 96, 0, 0, 0, hitbox_size=4)
-        self.bullet_launch_interval = 5
-        self.bullet_speed = 12.
-        self.bullet_launch_angle = -pi/2
         self.fire_time = 0
 
         self.state = state
@@ -107,6 +105,47 @@ class Player(object):
         self.state.focused = False
 
 
+    def fire(self):
+        sht = self.focused_sht if self.state.focused else self.sht
+        power = min(power for power in sht.shots if self.state.power < power)
+
+        bullets = self._game.players_bullets
+        nb_bullets_max = self._game.nb_bullets_max
+
+        for shot in sht.shots[power]:
+            if shot.type == 3: # TODO: Lasers aren't implemented yet
+                continue
+
+            if (self.fire_time + shot.delay) % shot.interval != 0:
+                continue
+
+            if nb_bullets_max is not None and len(bullets) == nb_bullets_max:
+                break
+
+            origin = self.orbs[shot.orb - 1] if shot.orb else self
+            x = origin.x + shot.pos[0]
+            y = origin.y + shot.pos[1]
+
+            #TODO: find a better way to do that.
+            bullet_type = BulletType(self.anm_wrapper, shot.sprite % 256,
+                                     shot.sprite % 256 + 32, #TODO: find the real cancel anim
+                                     0, 0, 0, 0.)
+            if shot.type == 2:
+                #TODO: triple-check acceleration!
+                bullets.append(Bullet((x, y), bullet_type, 0,
+                                      shot.angle, shot.speed,
+                                      (-1, 0, 0, 0, 0.15, -pi/2., 0., 0.),
+                                      16, self, self._game, player_bullet=True,
+                                      damage=shot.damage, hitbox=shot.hitbox))
+            #TODO: types 1 and 4
+            else:
+                bullets.append(Bullet((x, y), bullet_type, 0,
+                                      shot.angle, shot.speed,
+                                      (0, 0, 0, 0, 0., 0., 0., 0.),
+                                      0, self, self._game, player_bullet=True,
+                                      damage=shot.damage, hitbox=shot.hitbox))
+
+
     def update(self, keystate):
         if self.death_time == 0 or self._game.frame - self.death_time > 60:
             speed, diag_speed = self.speeds[2:] if self.state.focused else self.speeds[:2]
--- a/pytouhou/games/eosd.py
+++ b/pytouhou/games/eosd.py
@@ -18,7 +18,6 @@ from pytouhou.game.game import Game
 from pytouhou.game.bullettype import BulletType
 from pytouhou.game.itemtype import ItemType
 from pytouhou.game.player import Player
-from pytouhou.game.bullet import Bullet
 from pytouhou.game.orb import Orb
 
 from math import pi
@@ -41,7 +40,7 @@ class EoSDGame(Game):
                         BulletType(etama3, 7, 13, 20, 20, 20, hitbox_size=11),
                         BulletType(etama3, 8, 13, 20, 20, 20, hitbox_size=9),
                         BulletType(etama4, 0, 1, 2, 2, 2, hitbox_size=32)]
-        #TODO: hitbox
+
         item_types = [ItemType(etama3, 0, 7), #Power
                       ItemType(etama3, 1, 8), #Point
                       ItemType(etama3, 2, 9), #Big power
@@ -51,10 +50,7 @@ class EoSDGame(Game):
                       ItemType(etama3, 6, 13)] #Star
 
         characters = resource_loader.get_eosd_characters('102h.exe')
-
-        players = []
-        for player in player_states:
-            players.append(EoSDPlayer(player, self, resource_loader, sht=characters[player.character]))
+        players = [EoSDPlayer(state, self, resource_loader, characters[state.character]) for state in player_states]
 
         Game.__init__(self, resource_loader, players, stage, rank, difficulty,
                       bullet_types, item_types, nb_bullets_max=640, **kwargs)
@@ -62,16 +58,13 @@ class EoSDGame(Game):
 
 
 class EoSDPlayer(Player):
-    def __init__(self, state, game, resource_loader, speeds=None, hitbox_size=2.5, graze_hitbox_size=42., sht=None):
-        self.sht = sht
+    def __init__(self, state, game, resource_loader, character):
+        self.sht = character[0]
+        self.focused_sht = character[1]
         anm_wrapper = resource_loader.get_anm_wrapper(('player0%d.anm' % (state.character // 2),))
         self.anm_wrapper = anm_wrapper
 
-        Player.__init__(self, state, game, anm_wrapper,
-                        speeds=(self.sht.horizontal_vertical_speed,
-                                self.sht.diagonal_speed,
-                                self.sht.horizontal_vertical_focused_speed,
-                                self.sht.diagonal_focused_speed))
+        Player.__init__(self, state, game, anm_wrapper)
 
         self.orbs = [Orb(self.anm_wrapper, 128, self.state, None),
                      Orb(self.anm_wrapper, 129, self.state, None)]
@@ -123,44 +116,3 @@ class EoSDPlayer(Player):
         for orb in self.orbs:
             orb.update()
 
-
-    def fire(self):
-        sht = self.sht
-        power = min(power for power in sht.shots if self.state.power < power)
-
-        bullets = self._game.players_bullets
-        nb_bullets_max = self._game.nb_bullets_max
-
-        for shot in sht.shots[power]:
-            if shot.type == 3: # TODO: Lasers aren't implemented yet
-                continue
-
-            if self.fire_time % shot.interval != shot.delay:
-                continue
-
-            if nb_bullets_max is not None and len(bullets) == nb_bullets_max:
-                break
-
-            origin = self.orbs[shot.orb - 1] if shot.orb else self
-            x = origin.x + shot.pos[0]
-            y = origin.y + shot.pos[1]
-
-            #TODO: find a better way to do that.
-            bullet_type = BulletType(self.anm_wrapper, shot.sprite % 256,
-                                     shot.sprite % 256 + 32, #TODO: find the real cancel anim
-                                     0, 0, 0, 0.)
-            if shot.type == 2:
-                #TODO: triple-check acceleration!
-                bullets.append(Bullet((x, y), bullet_type, 0,
-                                      shot.angle, shot.speed,
-                                      (-1, 0, 0, 0, 0.15, -pi/2., 0., 0.),
-                                      16, self, self._game, player_bullet=True,
-                                      damage=shot.damage, hitbox=shot.hitbox))
-            #TODO: types 1 and 4
-            else:
-                bullets.append(Bullet((x, y), bullet_type, 0,
-                                      shot.angle, shot.speed,
-                                      (0, 0, 0, 0, 0., 0., 0., 0.),
-                                      0, self, self._game, player_bullet=True,
-                                      damage=shot.damage, hitbox=shot.hitbox))
-
--- a/pytouhou/games/pcb.py
+++ b/pytouhou/games/pcb.py
@@ -18,7 +18,6 @@ from pytouhou.game.game import Game
 from pytouhou.game.bullettype import BulletType
 from pytouhou.game.itemtype import ItemType
 from pytouhou.game.player import Player
-from pytouhou.game.bullet import Bullet
 from pytouhou.game.orb import Orb
 
 from math import pi
@@ -38,7 +37,7 @@ class PCBGame(Game):
                         BulletType(etama3, 7, 13, 20, 20, 20, hitbox_size=11),
                         BulletType(etama3, 8, 13, 20, 20, 20, hitbox_size=9),
                         BulletType(etama4, 0, 1, 2, 2, 2, hitbox_size=32)]
-        #TODO: hitbox
+
         item_types = [ItemType(etama3, 0, 7), #Power
                       ItemType(etama3, 1, 8), #Point
                       ItemType(etama3, 2, 9), #Big power
@@ -47,9 +46,7 @@ class PCBGame(Game):
                       ItemType(etama3, 5, 12), #1up
                       ItemType(etama3, 6, 13)] #Star
 
-        players = []
-        for player in player_states:
-            players.append(PCBPlayer(player, self, resource_loader))
+        players = [PCBPlayer(state, self, resource_loader) for state in player_states]
 
         Game.__init__(self, resource_loader, players, stage, rank, difficulty,
                       bullet_types, item_types, nb_bullets_max=640, **kwargs)
@@ -57,17 +54,14 @@ class PCBGame(Game):
 
 
 class PCBPlayer(Player):
-    def __init__(self, state, game, resource_loader, speed=4., hitbox_size=2.5, graze_hitbox_size=42.):
+    def __init__(self, state, game, resource_loader):
         number = '%d%s' % (state.character // 2, 'b' if state.character % 2 else 'a')
         self.sht = resource_loader.get_sht('ply0%s.sht' % number)
         self.focused_sht = resource_loader.get_sht('ply0%ss.sht' % number)
         anm_wrapper = resource_loader.get_anm_wrapper(('player0%d.anm' % (state.character // 2),))
+        self.anm_wrapper = anm_wrapper
 
-        Player.__init__(self, state, game, anm_wrapper,
-                        speeds=(self.sht.horizontal_vertical_speed,
-                                self.sht.diagonal_speed,
-                                self.sht.horizontal_vertical_focused_speed,
-                                self.sht.diagonal_focused_speed))
+        Player.__init__(self, state, game, anm_wrapper)
 
         self.orbs = [Orb(self.anm_wrapper, 128, self.state, None),
                      Orb(self.anm_wrapper, 129, self.state, None)]
@@ -119,25 +113,3 @@ class PCBPlayer(Player):
         for orb in self.orbs:
             orb.update()
 
-
-    def fire(self):
-        sht = self.focused_sht if self.state.focused else self.sht
-        power = min(power for power in sht.shots if self.state.power < power)
-
-        bullets = self._game.players_bullets
-        nb_bullets_max = self._game.nb_bullets_max
-
-        for shot in sht.shots[power]:
-            if self.fire_time % shot.interval == 0:
-                if nb_bullets_max is not None and len(bullets) == nb_bullets_max:
-                    break
-
-                origin = self.orbs[shot.orb - 1] if shot.orb else self
-                x = origin.x + shot.pos[0]
-                y = origin.y + shot.pos[1]
-
-                bullets.append(Bullet((x, y), self.bullet_type, 0,
-                                      shot.angle, shot.speed,
-                                      (0, 0, 0, 0, 0., 0., 0., 0.),
-                                      0, self, self._game, player_bullet=True,
-                                      damage=shot.damage, hitbox=shot.hitbox))