changeset 445:b0abb05811f7

Make pytouhou.game.player an extension type, and move the GameOver exception there since it makes more sense.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 17 Aug 2013 04:44:28 +0200
parents f26c8ab57257
children 3a33ed7f3b85
files eosd pytouhou/game/game.py pytouhou/game/item.py pytouhou/game/player.pxd pytouhou/game/player.py pytouhou/game/player.pyx pytouhou/vm/eclrunner.py
diffstat 6 files changed, 80 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/eosd
+++ b/eosd
@@ -56,8 +56,7 @@ from pytouhou.ui.window import Window
 from pytouhou.resource.loader import Loader
 from pytouhou.ui.gamerunner import GameRunner
 from pytouhou.games.eosd import EoSDCommon, EoSDGame
-from pytouhou.game.game import GameOver
-from pytouhou.game.player import PlayerState
+from pytouhou.game.player import PlayerState, GameOver
 from pytouhou.formats.t6rp import T6RP, Level
 from pytouhou.utils.random import Random
 from pytouhou.vm.msgrunner import NextStage
@@ -161,7 +160,7 @@ def main(path, data, stage_num, rank, ch
                 previous_level = replay.levels[stage_num - 1]
                 states[0].score = previous_level.score
                 states[0].effective_score = previous_level.score
-            states[0].point_items = level.point_items
+            states[0].points = level.point_items
             states[0].power = level.power
             states[0].lives = level.lives
             states[0].bombs = level.bombs
--- a/pytouhou/game/game.py
+++ b/pytouhou/game/game.py
@@ -24,11 +24,6 @@ from pytouhou.game.text import Text
 from pytouhou.game.face import Face
 
 
-
-class GameOver(Exception):
-    pass
-
-
 class Game(object):
     def __init__(self, players, stage, rank, difficulty, bullet_types,
                  laser_types, item_types, nb_bullets_max=None, width=384,
@@ -342,7 +337,7 @@ class Game(object):
             if not player.state.touchable:
                 continue
 
-            px, py = player.x, player.y
+            px, py = player.state.x, player.state.y
             phalf_size = player.sht.hitbox
             px1, px2 = px - phalf_size, px + phalf_size
             py1, py2 = py - phalf_size, py + phalf_size
--- a/pytouhou/game/item.py
+++ b/pytouhou/game/item.py
@@ -168,7 +168,8 @@ class Item(Element):
                                                    (3.,), 180)
 
         if self.player is not None:
-            self.angle = atan2(self.player.y - self.y, self.player.x - self.x)
+            player_state = self.player.state
+            self.angle = atan2(player_state.y - self.y, player_state.x - self.x)
             self.x += cos(self.angle) * self.speed
             self.y += sin(self.angle) * self.speed
         elif self.speed_interpolator is None:
new file mode 100644
--- /dev/null
+++ b/pytouhou/game/player.pxd
@@ -0,0 +1,22 @@
+from pytouhou.game.element cimport Element
+
+cdef class PlayerState:
+    cdef public double x, y
+    cdef public bint touchable, focused
+    cdef public long character, score, effective_score, lives, bombs, power, graze, points, invulnerable_time, power_bonus
+
+
+cdef class Player(Element):
+    cdef public PlayerState state
+    cdef public object _game
+    cdef public long death_time
+
+    cdef object anm
+    cdef tuple speeds
+    cdef long fire_time, direction
+
+    cdef void set_anim(self, index)
+    cpdef play_sound(self, str name)
+    cpdef collide(self)
+    cdef void fire(self)
+    cpdef update(self, long keystate)
rename from pytouhou/game/player.py
rename to pytouhou/game/player.pyx
--- a/pytouhou/game/player.py
+++ b/pytouhou/game/player.pyx
@@ -12,21 +12,22 @@
 ## GNU General Public License for more details.
 ##
 
+from libc.math cimport M_PI as pi
 
-from pytouhou.game.element import Element
-from pytouhou.game.sprite import Sprite
+from pytouhou.game.sprite cimport Sprite
 from pytouhou.vm.anmrunner import ANMRunner
 from pytouhou.game.bullettype import BulletType
-from pytouhou.game.bullet import Bullet
+from pytouhou.game.bullet cimport Bullet
 from pytouhou.game.lasertype import LaserType
 from pytouhou.game.laser import PlayerLaser
-from pytouhou.game.game import GameOver
-
-from math import pi
 
 
-class PlayerState(object):
-    def __init__(self, character=0, score=0, power=0, lives=2, bombs=3):
+class GameOver(Exception):
+    pass
+
+
+cdef class PlayerState:
+    def __init__(self, long character=0, long score=0, long power=0, long lives=2, long bombs=3):
         self.character = character # ReimuA/ReimuB/MarisaA/MarisaB/...
 
         self.score = score
@@ -53,8 +54,8 @@ class PlayerState(object):
                            self.power, self.lives, self.bombs)
 
 
-class Player(Element):
-    def __init__(self, state, game, anm):
+cdef class Player(Element):
+    def __init__(self, PlayerState state, game, anm):
         Element.__init__(self)
 
         self._game = game
@@ -68,39 +69,29 @@ class Player(Element):
         self.fire_time = 0
 
         self.state = state
-        self.direction = None
+        self.direction = 0
 
         self.set_anim(0)
 
         self.death_time = 0
 
 
-    @property
-    def x(self):
-        return self.state.x
-
-
-    @property
-    def y(self):
-        return self.state.y
-
-
-    def set_anim(self, index):
+    cdef void set_anim(self, index):
         self.sprite = Sprite()
         self.anmrunner = ANMRunner(self.anm, index, self.sprite)
 
 
-    def play_sound(self, name):
+    cpdef play_sound(self, str name):
         self._game.sfx_player.play('%s.wav' % name)
 
 
-    def collide(self):
+    cpdef collide(self):
         if not self.state.invulnerable_time and not self.death_time and self.state.touchable: # Border Between Life and Death
             self.death_time = self._game.frame
             self._game.new_effect((self.state.x, self.state.y), 17)
             self._game.modify_difficulty(-1600)
             self.play_sound('pldead00')
-            for i in range(16):
+            for i in xrange(16):
                 self._game.new_particle((self.state.x, self.state.y), 11, 256) #TODO: find the real size and range.
 
 
@@ -112,7 +103,10 @@ class Player(Element):
         self.state.focused = False
 
 
-    def fire(self):
+    cdef void fire(self):
+        cdef double x, y
+        cdef long shot_power
+
         sht = self.focused_sht if self.state.focused else self.sht
 
         # Don’t use min() since sht.shots could be an empty dict.
@@ -123,20 +117,24 @@ class Player(Element):
 
         bullets = self._game.players_bullets
         lasers = self._game.players_lasers
-        nb_bullets_max = self._game.nb_bullets_max
+        nb_bullets_max = <long>self._game.nb_bullets_max
 
         if self.fire_time % 5 == 0:
             self.play_sound('plst00')
 
         for shot in sht.shots[power]:
             origin = self.orbs[shot.orb - 1] if shot.orb else self.state
+            shot_type = <unsigned char>shot.type
 
-            if shot.type == 3:
+            if shot_type == 3:
                 if self.fire_time != 30:
                     continue
 
-                number = shot.delay #TODO: number can do very surprising things, like removing any bullet creation from enemies with 3. For now, crash when not 0 or 1.
-                if lasers[number]:
+                #TODO: number can do very surprising things, like removing any
+                # bullet creation from enemies with 3. For now, crash when not
+                # an actual laser number.
+                number = <long>shot.delay
+                if lasers[number] is not None:
                     continue
 
                 laser_type = LaserType(self.anm, shot.sprite % 256, 68)
@@ -146,7 +144,7 @@ class Player(Element):
             if (self.fire_time + shot.delay) % shot.interval != 0:
                 continue
 
-            if nb_bullets_max is not None and len(bullets) == nb_bullets_max:
+            if nb_bullets_max != 0 and len(bullets) == nb_bullets_max:
                 break
 
             x = origin.x + shot.pos[0]
@@ -157,7 +155,7 @@ class Player(Element):
                                      shot.sprite % 256 + 32, #TODO: find the real cancel anim
                                      0, 0, 0, 0.)
             #TODO: Type 1 (homing bullets)
-            if shot.type == 2:
+            if shot_type == 2:
                 #TODO: triple-check acceleration!
                 bullets.append(Bullet((x, y), bullet_type, 0,
                                       shot.angle, shot.speed,
@@ -172,15 +170,17 @@ class Player(Element):
                                       damage=shot.damage, hitbox=shot.hitbox))
 
 
-    def update(self, keystate):
+    cpdef update(self, long keystate):
+        cdef double dx, dy
+
         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]
             try:
-                dx, dy = {16: (0.0, -speed), 32: (0.0, speed), 64: (-speed, 0.0), 128: (speed, 0.0),
+                dx, dy = {16: (0., -speed), 32: (0., speed), 64: (-speed, 0.), 128: (speed, 0.),
                           16|64: (-diag_speed, -diag_speed), 16|128: (diag_speed, -diag_speed),
                           32|64: (-diag_speed, diag_speed), 32|128:  (diag_speed, diag_speed)}[keystate & (16|32|64|128)]
             except KeyError:
-                dx, dy = 0.0, 0.0
+                dx, dy = 0., 0.
 
             if dx < 0 and self.direction != -1:
                 self.set_anim(1)
@@ -188,13 +188,17 @@ class Player(Element):
             elif dx > 0 and self.direction != +1:
                 self.set_anim(3)
                 self.direction = +1
-            elif dx == 0 and self.direction is not None:
+            elif dx == 0 and self.direction != 0:
                 self.set_anim({-1: 2, +1: 4}[self.direction])
-                self.direction = None
+                self.direction = 0
 
             self.state.x += dx
             self.state.y += dy
 
+            #XXX
+            self.x = self.state.x
+            self.y = self.state.y
+
             if self.state.x < 8.:
                 self.state.x = 8.
             if self.state.x > self._game.width - 8:
@@ -227,7 +231,7 @@ class Player(Element):
                 self.fire_time -= 1
 
         if self.death_time:
-            time = self._game.frame - self.death_time
+            time = <long>self._game.frame - self.death_time
             if time == 6: # too late, you are dead :(
                 self.state.touchable = False
                 if self.state.power > 16:
@@ -235,7 +239,7 @@ class Player(Element):
                 else:
                     self.state.power = 0
                 for laser in self._game.players_lasers:
-                    if laser:
+                    if laser is not None:
                         laser.cancel()
 
                 self.state.lives -= 1
@@ -245,7 +249,7 @@ class Player(Element):
                     if self._game.continues < 0:
                         raise GameOver
 
-                    for i in range(5):
+                    for i in xrange(5):
                         self._game.drop_bonus(self.state.x, self.state.y, 4,
                                               end_pos=(self._game.prng.rand_double() * 288 + 48,
                                                        self._game.prng.rand_double() * 192 - 64))
@@ -261,7 +265,7 @@ class Player(Element):
                     self._game.drop_bonus(self.state.x, self.state.y, 2,
                                           end_pos=(self._game.prng.rand_double() * 288 + 48, # 102h.exe@0x41f3dc
                                                    self._game.prng.rand_double() * 192 - 64))        # @0x41f3
-                    for i in range(5):
+                    for i in xrange(5):
                         self._game.drop_bonus(self.state.x, self.state.y, 0,
                                               end_pos=(self._game.prng.rand_double() * 288 + 48,
                                                        self._game.prng.rand_double() * 192 - 64))
@@ -270,21 +274,21 @@ class Player(Element):
                 self.sprite.mirrored = False
                 self.sprite.blendfunc = 0
                 self.sprite.rescale = 0.75, 1.5
-                self.sprite.fade(26, 96, lambda x: x)
-                self.sprite.scale_in(26, 0.00, 2.5, lambda x: x)
+                self.sprite.fade(26, 96)
+                self.sprite.scale_in(26, 0., 2.5)
 
             elif time == 32:
                 self.state.x = float(self._game.width) / 2. #TODO
                 self.state.y = float(self._game.width) #TODO
-                self.direction = None
+                self.direction = 0
 
                 self.sprite = Sprite()
                 self.anmrunner = ANMRunner(self.anm, 0, self.sprite)
                 self.sprite.alpha = 128
-                self.sprite.rescale = 0.0, 2.5
-                self.sprite.fade(30, 255, lambda x: x)
+                self.sprite.rescale = 0., 2.5
+                self.sprite.fade(30, 255)
                 self.sprite.blendfunc = 1
-                self.sprite.scale_in(30, 1., 1., lambda x: x)
+                self.sprite.scale_in(30, 1., 1.)
 
             elif time == 61: # respawned
                 self.state.touchable = True
--- a/pytouhou/vm/eclrunner.py
+++ b/pytouhou/vm/eclrunner.py
@@ -203,10 +203,10 @@ class ECLRunner(object):
                 return self._enemy.z
             elif value == -10018:
                 player = self._enemy.select_player()
-                return player.x
+                return player.state.x
             elif value == -10019:
                 player = self._enemy.select_player()
-                return player.y
+                return player.state.y
             elif value == -10021:
                 return self._enemy.get_player_angle()
             elif value == -10022: