Prevent gang-bang and re-balance gameplay

This commit is contained in:
Nguyễn Gia Phong 2018-06-25 21:40:19 +07:00
parent 3507a52ac7
commit fc05e0ccee
5 changed files with 38 additions and 27 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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])

View File

@ -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',