changeset 199:8ec34c56fed0

Implement orbs.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Mon, 31 Oct 2011 09:38:57 -0700
parents 13918723d1bc
children 300661f2ae8a
files pytouhou/game/orb.py pytouhou/game/player.py pytouhou/games/eosd.py pytouhou/opengl/gamerenderer.pyx
diffstat 4 files changed, 134 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/pytouhou/game/orb.py
@@ -0,0 +1,44 @@
+# -*- encoding: utf-8 -*-
+##
+## Copyright (C) 2011 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 3 only.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+
+
+from pytouhou.game.sprite import Sprite
+from pytouhou.vm.anmrunner import ANMRunner
+
+
+class Orb(object):
+    def __init__(self, anm_wrapper, index, player_state, fire_func):
+        self._sprite = Sprite()
+        self._anmrunner = ANMRunner(anm_wrapper, index, self._sprite)
+        self._anmrunner.run_frame()
+
+        self.offset_x = 0
+        self.offset_y = 0
+
+        self.player_state = player_state
+        self.fire = fire_func
+
+
+    @property
+    def x(self):
+        return self.player_state.x + self.offset_x
+
+
+    @property
+    def y(self):
+        return self.player_state.y + self.offset_y
+
+
+    def update(self):
+        self._anmrunner.run_frame()
--- 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.utils.interpolator import Interpolator
 
 from math import pi
 
@@ -40,6 +41,7 @@ class PlayerState(object):
 
         self.invulnerable_time = 240
         self.touchable = True
+        self.focused = False
 
         self.power_bonus = 0 # Never goes over 30.
 
@@ -72,6 +74,9 @@ class Player(object):
 
         self.death_time = 0
 
+        self.orb_dx_interpolator = None
+        self.orb_dy_interpolator = None
+
 
     @property
     def x(self):
@@ -83,6 +88,10 @@ class Player(object):
         return self.state.y
 
 
+    def objects(self):
+        return self.orbs if self.state.power >= 8 else []
+
+
     def set_anim(self, index):
         self._sprite = Sprite()
         self._anmrunner = ANMRunner(self.anm_wrapper, index, self._sprite)
@@ -124,6 +133,32 @@ class Player(object):
             self.state.x += dx
             self.state.y += dy
 
+            if not self.state.focused and keystate & 4:
+                self.orb_dx_interpolator = Interpolator((24,), self._game.frame,
+                                                        (8,), self._game.frame + 8,
+                                                        lambda x: x ** 2)
+                self.orb_dy_interpolator = Interpolator((0,), self._game.frame,
+                                                        (-32,), self._game.frame + 8)
+                self.state.focused = True
+            elif self.state.focused and not keystate & 4:
+                self.orb_dx_interpolator = Interpolator((8,), self._game.frame,
+                                                        (24,), self._game.frame + 8,
+                                                        lambda x: x ** 2)
+                self.orb_dy_interpolator = Interpolator((-32,), self._game.frame,
+                                                        (0,), self._game.frame + 8)
+                self.state.focused = False
+
+            if self.orb_dx_interpolator:
+                self.orb_dx_interpolator.update(self._game.frame)
+                dx, = self.orb_dx_interpolator.values
+                self.orbs[0].offset_x = -dx
+                self.orbs[1].offset_x = dx
+            if self.orb_dy_interpolator:
+                self.orb_dy_interpolator.update(self._game.frame)
+                dy, = self.orb_dy_interpolator.values
+                self.orbs[0].offset_y = dy
+                self.orbs[1].offset_y = dy
+
             if self.state.invulnerable_time > 0:
                 self.state.invulnerable_time -= 1
 
@@ -192,5 +227,9 @@ class Player(object):
                 self.death_time = 0
 
 
+        for orb in self.orbs:
+            orb.update()
+
+
         self._anmrunner.run_frame()
 
--- a/pytouhou/games/eosd.py
+++ b/pytouhou/games/eosd.py
@@ -18,6 +18,7 @@ from pytouhou.game.bullettype import Bul
 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
 
@@ -72,7 +73,7 @@ class Reimu(Player):
                 bullets_per_shot = 3
             elif self.state.power < 128:
                 bullets_per_shot = 4
-            elif self.state.power >= 128:
+            else:
                 bullets_per_shot = 5
 
             bullets = self._game.players_bullets
@@ -89,12 +90,15 @@ class Reimu(Player):
                                       0, self, self._game, player_bullet=True))
                 bullet_angle += self.bullet_angle
 
+        for orb in self.orbs:
+            orb.fire(orb)
+
 
 class ReimuA(Reimu):
     def __init__(self, state, game, resource_loader):
         Reimu.__init__(self, state, game, resource_loader)
 
-        self.bulletA_type = BulletType(self.anm_wrapper, 65, 97, 0, 0, 0, hitbox_size=4, damage=48) #TODO: verify the hitbox and damages.
+        self.bulletA_type = BulletType(self.anm_wrapper, 65, 97, 0, 0, 0, hitbox_size=4, damage=14) #TODO: verify the hitbox.
         self.bulletA_speed = 12.
 
 
@@ -112,70 +116,67 @@ class ReimuB(Reimu):
     def __init__(self, state, game, resource_loader):
         Reimu.__init__(self, state, game, resource_loader)
 
-        self.bulletB_type = BulletType(self.anm_wrapper, 66, 98, 0, 0, 0, hitbox_size=4, damage=48) #TODO: verify the hitbox and damages.
+        self.bulletB_type = BulletType(self.anm_wrapper, 66, 98, 0, 0, 0, hitbox_size=4, damage=12) #TODO: verify the hitbox.
         self.bulletB_speed = 22.
 
+        self.orbs = [Orb(self.anm_wrapper, 128, self.state, self.orb_fire),
+                     Orb(self.anm_wrapper, 129, self.state, self.orb_fire)]
+        self.orbs[0].dx = -24
+        self.orbs[1].dx = 24
 
-    def fire_spine(self, offset_x):
+
+    def fire_spine(self, orb, offset_x):
         bullets = self._game.players_bullets
         nb_bullets_max = self._game.nb_bullets_max
 
         if nb_bullets_max is not None and len(bullets) == nb_bullets_max:
             return
 
-        bullets.append(Bullet((self.x + offset_x, self.y), self.bulletB_type, 0,
+        bullets.append(Bullet((orb.x + offset_x, orb.y), self.bulletB_type, 0,
                               self.bullet_launch_angle, self.bulletB_speed,
                               (0, 0, 0, 0, 0., 0., 0., 0.),
                               0, self, self._game, player_bullet=True))
 
-
-    def fire(self):
-        Reimu.fire(self)
-
+    def orb_fire(self, orb):
         if self.state.power < 8:
             return
 
         elif self.state.power < 16:
             if self.fire_time % 15 == 0:
-                for offset in (-24, 24):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, 0)
 
         elif self.state.power < 32:
             if self.fire_time % 10 == 0:
-                for offset in (-24, 24):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, 0)
 
         elif self.state.power < 48:
             if self.fire_time % 8 == 0:
-                for offset in (-24, 24):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, 0)
 
         elif self.state.power < 96:
+            if self.fire_time % 8 == 0:
+                self.fire_spine(orb, -8)
             if self.fire_time % 5 == 0:
-                for offset in (-16, 32):
-                    self.fire_spine(offset)
-            if self.fire_time % 8 == 0:
-                for offset in (-32, 16):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, 8)
 
         elif self.state.power < 128:
+            if self.fire_time % 5 == 0:
+                self.fire_spine(orb, -12)
+            if self.fire_time % 10 == 0:
+                self.fire_spine(orb, 0)
             if self.fire_time % 3 == 0:
-                for offset in (-12, 36):
-                    self.fire_spine(offset)
-            if self.fire_time % 5 == 0:
-                for offset in (-36, 12):
-                    self.fire_spine(offset)
-            if self.fire_time % 10 == 0:
-                for offset in (-24, 24):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, 12)
 
         else:
             if self.fire_time % 3 == 0:
-                for offset in (-36, -12, 12, 36):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, -12)
+                self.fire_spine(orb, 12)
             if self.fire_time % 5 == 0:
-                for offset in (-24, 24):
-                    self.fire_spine(offset)
+                self.fire_spine(orb, 0)
+
+
+    def update(self, keystate):
+        Player.update(self, keystate)
 
 
 class Marisa(Player):
@@ -194,7 +195,7 @@ class Marisa(Player):
                 bullets_per_shot = 2
             elif self.state.power < 128:
                 bullets_per_shot = 3
-            elif self.state.power >= 128:
+            else:
                 bullets_per_shot = 5
 
             bullets = self._game.players_bullets
@@ -217,10 +218,10 @@ class MarisaA(Marisa):
         Marisa.__init__(self, state, game, resource_loader)
 
         #TODO: verify the hitbox and damages.
-        self.bulletA_types = [BulletType(self.anm_wrapper, 65, 0, 0, 0, 0, hitbox_size=4, damage=48),
-                              BulletType(self.anm_wrapper, 66, 0, 0, 0, 0, hitbox_size=4, damage=48),
-                              BulletType(self.anm_wrapper, 67, 0, 0, 0, 0, hitbox_size=4, damage=48),
-                              BulletType(self.anm_wrapper, 68, 0, 0, 0, 0, hitbox_size=4, damage=48)]
+        self.bulletA_types = [BulletType(self.anm_wrapper, 65, 0, 0, 0, 0, hitbox_size=4, damage=40),
+                              BulletType(self.anm_wrapper, 66, 0, 0, 0, 0, hitbox_size=4),
+                              BulletType(self.anm_wrapper, 67, 0, 0, 0, 0, hitbox_size=4),
+                              BulletType(self.anm_wrapper, 68, 0, 0, 0, 0, hitbox_size=4)]
         self.bulletA_speed_interpolator = None
 
 
@@ -238,7 +239,17 @@ class MarisaB(Marisa):
     def __init__(self, state, game, resource_loader):
         Marisa.__init__(self, state, game, resource_loader)
 
-        self.laser_type = None
+        #TODO:  power   damages period
+        #       8       240     120
+        #       16      390     170
+        #       32      480     ???
+        #       48      510     ???
+        #       64      760     ???
+        #       80      840     ???
+        #       96      1150    270
+        #       128     1740    330
+        # The duration of the laser is period - 42.
+        # The damages are given for one laser shot on one enemy for its entire duration.
 
 
     def fire(self):
--- a/pytouhou/opengl/gamerenderer.pyx
+++ b/pytouhou/opengl/gamerenderer.pyx
@@ -152,6 +152,8 @@ cdef class GameRenderer:
             self.render_elements(game.enemies)
             self.render_elements(game.effects)
             self.render_elements(game.players)
+            for player in game.players:
+                self.render_elements(player.objects())
             self.render_elements(game.bullets)
             self.render_elements(game.cancelled_bullets)
             self.render_elements(game.players_bullets)