about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
authorNguyễn Gia Phong <vn.mcsinyx@gmail.com>2018-06-25 21:40:19 +0700
committerNguyễn Gia Phong <vn.mcsinyx@gmail.com>2018-06-28 10:31:04 +0700
commitfc05e0ccee392985d67872507bc5476a5775142c (patch)
treef31a5333361d142466b142a90a1d3ed5dde3d2be
parent3507a52ac720afc7c22a1354033e65b4df64faae (diff)
downloadbrutalmaze-fc05e0ccee392985d67872507bc5476a5775142c.tar.gz
Prevent gang-bang and re-balance gameplay
-rw-r--r--brutalmaze/characters.py21
-rw-r--r--brutalmaze/constants.py3
-rw-r--r--brutalmaze/game.py2
-rw-r--r--brutalmaze/maze.py37
-rwxr-xr-xsetup.py2
5 files changed, 38 insertions, 27 deletions
diff --git a/brutalmaze/characters.py b/brutalmaze/characters.py
index 7aead58..b6ab9af 100644
--- a/brutalmaze/characters.py
+++ b/brutalmaze/characters.py
@@ -19,6 +19,7 @@
 
 __doc__ = 'Brutal Maze module for hero and enemy classes'
 
+from collections import deque
 from math import atan, atan2, sin, pi
 from random import choice, randrange, shuffle
 from sys import modules
@@ -40,7 +41,7 @@ class Hero:
         angle (float): angle of the direction the hero pointing (in radians)
         color (tuple of pygame.Color): colors of the hero on different HPs
         R (int): circumradius of the regular triangle representing the hero
-        next_heal (float): ms until the hero gains back healing ability
+        next_heal (float): minimum wound in ATTACK_SPEED allowing healing again
         next_beat (float): time until next heart beat (in ms)
         next_strike (float): time until the hero can do the next attack (in ms)
         slashing (bool): flag indicates if the hero is doing close-range attack
@@ -49,6 +50,7 @@ class Hero:
         spin_speed (float): speed of spinning (in frames per slash)
         spin_queue (float): frames left to finish spinning
         wound (float): amount of wound
+        wounds (deque of float): wounds in time of an attack (ATTACK_SPEED)
         sfx_heart (pygame.mixer.Sound): heart beat sound effect
     """
     def __init__(self, surface, fps, maze_size):
@@ -58,10 +60,12 @@ class Hero:
         self.angle, self.color = -pi * 3 / 4, TANGO['Aluminium']
         self.R = (w * h / sin(pi*2/3) / 624) ** 0.5
 
-        self.next_heal = self.next_beat = self.next_strike = 0.0
+        self.next_heal = -1.0
+        self.next_beat = self.next_strike = 0.0
         self.slashing = self.firing = self.dead = False
         self.spin_speed = fps / HERO_HP
         self.spin_queue = self.wound = 0.0
+        self.wounds = deque([0.0])
 
         self.sfx_heart = SFX_HEART
 
@@ -73,11 +77,14 @@ class Hero:
         old_speed = self.spin_speed
         self.spin_speed = fps / (HERO_HP-self.wound**0.5)
         self.spin_queue *= self.spin_speed / old_speed
-        if self.next_heal <= 0:
+
+        if len(self.wounds) > fps * ATTACK_SPEED / 1000: self.wounds.popleft()
+        if sum(self.wounds) < self.next_heal: self.next_heal = -1.0
+        self.wound += self.wounds[-1]
+        if self.next_heal < 0:
             self.wound -= HEAL_SPEED / self.spin_speed / HERO_HP
             if self.wound < 0: self.wound = 0.0
-        else:
-            self.next_heal -= 1000.0 / fps
+        self.wounds.append(0.0)
         if self.next_beat <= 0:
             play(self.sfx_heart)
             self.next_beat = MIN_BEAT*(2 - self.wound/HERO_HP)
@@ -100,7 +107,7 @@ class Hero:
         """Return the number of sides the hero has. While the hero is
         generally a trigon, Agent Orange may turn him into a square.
         """
-        return 3 if self.next_heal <= 0 else 4
+        return 3 if self.next_heal < 0 else 4
 
     def update_angle(self, angle):
         """Turn to the given angle if the hero is not busy slashing."""
@@ -252,7 +259,7 @@ class Enemy:
     def slash(self):
         """Return the enemy's close-range damage per frame."""
         wound = self.get_slash() / self.spin_speed
-        if self.spin_queue: self.maze.hit_hero(wound, self.color)
+        if self.spin_queue and wound: self.maze.hit_hero(wound, self.color)
         return wound
 
     def get_angle(self, reversed=False):
diff --git a/brutalmaze/constants.py b/brutalmaze/constants.py
index e742858..82e76c9 100644
--- a/brutalmaze/constants.py
+++ b/brutalmaze/constants.py
@@ -43,7 +43,7 @@ SFX_LOSE = Sound(pkg_file('brutalmaze', 'soundfx/lose.ogg'))
 if mixer is None: pygame.mixer.quit()
 
 SQRT2 = 2 ** 0.5
-INIT_SCORE = 5**0.5/2 + 0.5     # golden mean
+INIT_SCORE = 2
 ROAD_WIDTH = 3  # grids
 WALL_WIDTH = 4  # grids
 CELL_WIDTH = WALL_WIDTH + ROAD_WIDTH*2  # grids
@@ -55,6 +55,7 @@ HERO_SPEED = 5  # grid/s
 ENEMY_SPEED = 6 # grid/s
 BULLET_SPEED = 15   # grid/s
 ATTACK_SPEED = 333.333  # ms/strike
+MAX_WOUND = 1   # per attack turn
 FIRANGE = 6     # grids
 BULLET_LIFETIME = 1000.0 * FIRANGE / (BULLET_SPEED-HERO_SPEED)  # ms
 EMPTY, WALL, HERO, ENEMY = range(4)
diff --git a/brutalmaze/game.py b/brutalmaze/game.py
index 6295ae1..95b7c09 100644
--- a/brutalmaze/game.py
+++ b/brutalmaze/game.py
@@ -17,7 +17,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with Brutal Maze.  If not, see <https://www.gnu.org/licenses/>.
 
-__version__ = '0.7.5'
+__version__ = '0.7.7'
 
 import re
 from argparse import ArgumentParser, FileType, RawTextHelpFormatter
diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py
index c6f2585..ef1c2fb 100644
--- a/brutalmaze/maze.py
+++ b/brutalmaze/maze.py
@@ -30,7 +30,7 @@ from .constants import (
     EMPTY, WALL, HERO, ENEMY, ROAD_WIDTH, WALL_WIDTH, CELL_WIDTH, CELL_NODES,
     MAZE_SIZE, MIDDLE, INIT_SCORE, ENEMIES, MINW, MAXW, SQRT2, SFX_SPAWN,
     SFX_SLASH_ENEMY, SFX_LOSE, ADJACENTS, TANGO_VALUES, BG_COLOR, FG_COLOR,
-    HERO_HP, ENEMY_HP, ATTACK_SPEED, HERO_SPEED, BULLET_LIFETIME)
+    HERO_HP, ENEMY_HP, ATTACK_SPEED, MAX_WOUND, HERO_SPEED, BULLET_LIFETIME)
 from .misc import round2, sign, around, regpoly, fill_aapolygon, play
 from .weapons import Bullet
 
@@ -229,19 +229,20 @@ class Maze:
 
     def hit_hero(self, wound, color):
         """Handle the hero when he loses HP."""
-        fx = (uniform(0, sum(self.enemy_weights.values()))
-              < self.enemy_weights[color])
-        if (color == 'Butter' or color == 'ScarletRed') and fx:
-            self.hero.wound += wound * 2.5
-        elif color == 'Orange' and fx:
-            self.hero.next_heal = max(self.hero.next_heal, 0) + wound*1000
-        elif color == 'SkyBlue' and fx:
-            self.next_move = max(self.next_move, 0) + wound*1000
-        else:
-            self.hero.wound += wound
         if self.enemy_weights[color] + wound < MAXW:
             self.enemy_weights[color] += wound
-        if self.hero.wound > HERO_HP and not self.hero.dead: self.lose()
+        if color == 'Orange':
+            self.hero.next_heal = abs(self.hero.next_heal * (1 - wound))
+        elif (uniform(0, sum(self.enemy_weights.values()))
+            < self.enemy_weights[color]):
+            self.hero.next_heal = -1.0  # what doesn't kill you heals you
+            if color == 'Butter' or color == 'ScarletRed':
+                wound *= ENEMY_HP
+            elif color == 'SkyBlue':
+                self.next_move = max(self.next_move, 0) + wound*1000
+                wound = 0
+        if wound and sum(self.hero.wounds) < MAX_WOUND:
+            self.hero.wounds[-1] += wound
 
     def slash(self):
         """Handle close-range attacks."""
@@ -272,14 +273,14 @@ class Maze:
                                        self.hero.angle, 'Aluminium'))
 
         fallen = []
-        block = (self.hero.spin_queue and self.hero.next_heal <= 0
+        block = (self.hero.spin_queue and self.hero.next_heal < 0
                  and self.hero.next_strike > self.hero.spin_queue / self.fps)
 
         for i, bullet in enumerate(self.bullets):
             wound = bullet.fall_time / BULLET_LIFETIME
             bullet.update(self.fps, self.distance)
             gridx, gridy = self.get_grid(bullet.x, bullet.y)
-            if wound < 0 or not self.is_displayed(gridx, gridy):
+            if wound <= 0 or not self.is_displayed(gridx, gridy):
                 fallen.append(i)
             elif bullet.color == 'Aluminium':
                 if self.map[gridx][gridy] == WALL and self.next_move <= 0:
@@ -353,10 +354,11 @@ class Maze:
             for bullet in self.bullets: bullet.place(self.vx, self.vy)
 
         for enemy in self.enemies: enemy.update()
+        self.track_bullets()
         if not self.hero.dead:
             self.hero.update(fps)
             self.slash()
-        self.track_bullets()
+            if self.hero.wound > HERO_HP: self.lose()
 
     def resize(self, size):
         """Resize the maze."""
@@ -443,7 +445,8 @@ class Maze:
         self.enemy_weights = {color: MINW for color in ENEMIES}
         self.add_enemy()
 
-        self.next_move = self.next_slashfx = 0.0
-        self.hero.next_heal = self.hero.next_strike = 0
+        self.next_move = self.next_slashfx = self.hero.next_strike = 0.0
+        self.hero.next_heal = -1.0
         self.hero.slashing = self.hero.firing = self.hero.dead = False
         self.hero.spin_queue = self.hero.wound = 0.0
+        self.hero.wounds = deque([0.0])
diff --git a/setup.py b/setup.py
index 7461f9c..6151256 100755
--- a/setup.py
+++ b/setup.py
@@ -7,7 +7,7 @@ with open('README.rst') as f:
 
 setup(
     name='brutalmaze',
-    version='0.7.5',
+    version='0.7.7',
     description='A minimalist TPS game with fast-paced action',
     long_description=long_description,
     url='https://github.com/McSinyx/brutalmaze',