changeset 492:887de1309491

Add friendly fire in netplay.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sat, 21 Sep 2013 20:26:39 +0200
parents 2276229282fd
children 26c082870dcf
files eosd pytouhou/game/bullet.pxd pytouhou/game/bullet.pyx pytouhou/game/enemy.pyx pytouhou/game/game.pxd pytouhou/game/game.pyx pytouhou/game/player.pxd pytouhou/game/player.pyx pytouhou/games/eosd.py
diffstat 9 files changed, 65 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/eosd
+++ b/eosd
@@ -48,6 +48,7 @@ parser.add_argument('--verbosity', metav
 parser.add_argument('--game', metavar='GAME', choices=['EoSD'], default='EoSD', help='Select the game engine to use.')
 parser.add_argument('--port', metavar='PORT', type=int, default=0, help='Local port to use for netplay')
 parser.add_argument('--remote', metavar='REMOTE', default=None, help='Remote address')
+parser.add_argument('--no-friendly-fire', action='store_false', help='Allow friendly-fire during netplay.')
 
 args = parser.parse_args()
 
@@ -101,7 +102,7 @@ class GameBossRush(Game):
 
 def main(window, path, data, stage_num, rank, character, replay, save_filename,
          skip_replay, boss_rush, debug, enable_background, enable_particles,
-         enable_music, hints, verbosity, port, remote):
+         enable_music, hints, verbosity, port, remote, friendly_fire):
 
     resource_loader = Loader(path)
 
@@ -153,12 +154,12 @@ def main(window, path, data, stage_num, 
 
         prng = Random(0)
         con = Network(port, addr, selected_player)
-        states = [PlayerState(character=1, power=default_power, continues=continues),
-                  PlayerState(character=3, power=default_power, continues=continues)]
+        states = [PlayerState(0, character=1, power=default_power, continues=continues),
+                  PlayerState(1, character=3, power=default_power, continues=continues)]
     else:
         con = None
         selected_player = 0
-        states = [PlayerState(character=character, power=default_power, continues=continues)]
+        states = [PlayerState(0, character=character, power=default_power, continues=continues)]
 
     if hints:
         with open(hints, 'rb') as file:
@@ -204,7 +205,9 @@ def main(window, path, data, stage_num, 
 
         hints_stage = hints.stages[stage_num - 1] if hints else None
 
-        game = game_class(resource_loader, states, stage_num, rank, difficulty, common, prng=prng, hints=hints_stage)
+        game = game_class(resource_loader, states, stage_num, rank, difficulty,
+                          common, prng=prng, hints=hints_stage,
+                          friendly_fire=friendly_fire)
 
         if not enable_particles:
             def new_particle(pos, anim, amp, number=1, reverse=False, duration=24):
@@ -251,7 +254,8 @@ with SDL():
     main(window, args.path, tuple(args.data), args.stage, args.rank,
          args.character, args.replay, args.save_replay, args.skip_replay,
          args.boss_rush, args.debug, args.no_background, args.no_particles,
-         args.no_music, args.hints, args.verbosity, args.port, args.remote)
+         args.no_music, args.hints, args.verbosity, args.port, args.remote,
+         args.no_friendly_fire)
 
     import gc
     gc.collect()
--- a/pytouhou/game/bullet.pxd
+++ b/pytouhou/game/bullet.pxd
@@ -12,7 +12,7 @@ cdef class Bullet(Element):
     cdef public State state
     cdef public unsigned long flags, frame, sprite_idx_offset, damage
     cdef public double dx, dy, angle, speed
-    cdef public bint player_bullet, was_visible, grazed
+    cdef public bint was_visible, grazed
     cdef public Element target
     cdef public BulletType _bullet_type
     cdef public list attributes
@@ -20,6 +20,7 @@ cdef class Bullet(Element):
     cdef double hitbox[2]
     cdef Interpolator speed_interpolator
     cdef Game _game
+    cdef long player
 
     cdef bint is_visible(self, unsigned int screen_width, unsigned int screen_height) except? False
     cpdef set_anim(self, sprite_idx_offset=*)
--- a/pytouhou/game/bullet.pyx
+++ b/pytouhou/game/bullet.pyx
@@ -21,7 +21,7 @@ from pytouhou.game.sprite cimport Sprite
 cdef class Bullet(Element):
     def __init__(self, pos, BulletType bullet_type, unsigned long sprite_idx_offset,
                        double angle, double speed, attributes, unsigned long flags, target, Game game,
-                       bint player_bullet=False, unsigned long damage=0, tuple hitbox=None):
+                       long player=-1, unsigned long damage=0, tuple hitbox=None):
         cdef double launch_mult
 
         Element.__init__(self, pos)
@@ -51,7 +51,7 @@ cdef class Bullet(Element):
         self.speed = speed
         self.dx, self.dy = cos(angle) * speed, sin(angle) * speed
 
-        self.player_bullet = player_bullet
+        self.player = player
         self.damage = damage
 
         #TODO
@@ -73,7 +73,7 @@ cdef class Bullet(Element):
         else:
             self.launch()
 
-        if self.player_bullet:
+        if self.player >= 0:
             self.sprite.angle = angle - pi
         else:
             self.sprite.angle = angle
@@ -102,7 +102,7 @@ cdef class Bullet(Element):
 
         bt = self._bullet_type
         self.sprite = Sprite()
-        if self.player_bullet:
+        if self.player >= 0:
             self.sprite.angle = self.angle - pi
         else:
             self.sprite.angle = self.angle
@@ -130,7 +130,7 @@ cdef class Bullet(Element):
         # Cancel animation
         bt = self._bullet_type
         self.sprite = Sprite()
-        if self.player_bullet:
+        if self.player >= 0:
             self.sprite.angle = self.angle - pi
         else:
             self.sprite.angle = self.angle
--- a/pytouhou/game/enemy.pyx
+++ b/pytouhou/game/enemy.pyx
@@ -336,7 +336,6 @@ cdef class Enemy(Element):
                 continue
 
             half_size[0] = laser.hitbox[0]
-            half_size[1] = laser.hitbox[1]
             lx, ly = laser.x, laser.y * 2.
             lx1, lx2 = lx - half_size[0], lx + half_size[0]
 
--- a/pytouhou/game/game.pxd
+++ b/pytouhou/game/game.pxd
@@ -12,6 +12,8 @@ cdef class Game:
     cdef public bint time_stop, msg_wait
     cdef public unsigned short deaths_count, next_bonus
 
+    cdef bint friendly_fire
+
     cdef list msg_sprites(self)
     cdef list lasers_sprites(self)
     cdef void modify_difficulty(self, long diff) except *
--- a/pytouhou/game/game.pyx
+++ b/pytouhou/game/game.pyx
@@ -26,7 +26,8 @@ from pytouhou.game.face import Face
 cdef class Game:
     def __init__(self, players, long stage, long rank, long difficulty, bullet_types,
                  laser_types, item_types, long nb_bullets_max=0, long width=384,
-                 long height=448, prng=None, interface=None, hints=None):
+                 long height=448, prng=None, interface=None, hints=None,
+                 friendly_fire=True):
         self.width, self.height = width, height
 
         self.nb_bullets_max = nb_bullets_max
@@ -72,6 +73,7 @@ cdef class Game:
         self.deaths_count = self.prng.rand_uint16() % 3
         self.next_bonus = self.prng.rand_uint16() % 8
 
+        self.friendly_fire = friendly_fire
         self.last_keystate = 0
 
 
@@ -386,6 +388,7 @@ cdef class Game:
         cdef Item item
         cdef PlayerLaser player_laser
         cdef Laser laser
+        cdef PlayerLaser plaser
         cdef double player_pos[2]
 
         if self.time_stop:
@@ -458,6 +461,40 @@ cdef class Game:
                     #TODO: display a static particle during one frame at
                     # 12 pixels of the player, in the axis of the “collision”.
 
+            # Check for friendly-fire only if there are multiple players.
+            if self.friendly_fire and len(self.players) > 1:
+                for bullet in self.players_bullets:
+                    if bullet.state != LAUNCHED:
+                        continue
+
+                    if bullet.player == player_state.number:
+                        continue
+
+                    bhalf_width = bullet.hitbox[0]
+                    bhalf_height = bullet.hitbox[1]
+                    bx, by = bullet.x, bullet.y
+                    bx1, bx2 = bx - bhalf_width, bx + bhalf_width
+                    by1, by2 = by - bhalf_height, by + bhalf_height
+
+                    if not (bx2 < px1 or bx1 > px2
+                            or by2 < py1 or by1 > py2):
+                        bullet.collide()
+                        if player_state.invulnerable_time == 0:
+                            player.collide()
+
+                for plaser in self.players_lasers:
+                    if not plaser:
+                        continue
+
+                    lhalf_width = plaser.hitbox[0]
+                    lx, ly = plaser.x, plaser.y * 2.
+                    lx1, lx2 = lx - lhalf_width, lx + lhalf_width
+
+                    if not (lx2 < px1 or lx1 > px2
+                            or ly < py1):
+                        if player_state.invulnerable_time == 0:
+                            player.collide()
+
             #TODO: is it the right place?
             if py < 128 and player_state.power >= 128: #TODO: check py.
                 self.autocollect(player)
--- a/pytouhou/game/player.pxd
+++ b/pytouhou/game/player.pxd
@@ -7,6 +7,7 @@ cdef class PlayerState:
     cdef public long character, score, effective_score, lives, bombs, power
     cdef public long graze, points
 
+    cdef long number
     cdef long invulnerable_time, power_bonus, continues, continues_used, miss,
     cdef long bombs_used
 
--- a/pytouhou/game/player.pyx
+++ b/pytouhou/game/player.pyx
@@ -27,8 +27,9 @@ class GameOver(Exception):
 
 
 cdef class PlayerState:
-    def __init__(self, long character=0, long score=0, long power=0,
-                 long lives=2, long bombs=3, long continues=0):
+    def __init__(self, long number, long character=0, long score=0,
+                 long power=0, long lives=2, long bombs=3, long continues=0):
+        self.number = number
         self.character = character # ReimuA/ReimuB/MarisaA/MarisaB/...
 
         self.score = score
@@ -161,13 +162,13 @@ cdef class Player(Element):
                 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,
+                                      16, self, self._game, player=self.state.number,
                                       damage=shot.damage, hitbox=shot.hitbox))
             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,
+                                      0, self, self._game, player=self.state.number,
                                       damage=shot.damage, hitbox=shot.hitbox))
 
 
--- a/pytouhou/games/eosd.py
+++ b/pytouhou/games/eosd.py
@@ -82,7 +82,7 @@ class EoSDCommon(object):
 class EoSDGame(Game):
     def __init__(self, resource_loader, player_states, stage, rank, difficulty,
                  common, nb_bullets_max=640, width=384, height=448, prng=None,
-                 hints=None):
+                 hints=None, friendly_fire=True):
 
         self.etama = common.etama #XXX
         try:
@@ -124,7 +124,7 @@ class EoSDGame(Game):
         Game.__init__(self, players, stage, rank, difficulty,
                       common.bullet_types, common.laser_types,
                       common.item_types, nb_bullets_max, width, height, prng,
-                      common.interface, hints)
+                      common.interface, hints, friendly_fire)