summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--README.rst6
-rw-r--r--brutalmaze/characters.py20
-rw-r--r--brutalmaze/constants.py6
-rw-r--r--brutalmaze/main.py28
-rw-r--r--brutalmaze/maze.py79
-rw-r--r--brutalmaze/utils.py6
-rw-r--r--brutalmaze/weapons.py10
-rw-r--r--screenshot.pngbin0 -> 10078 bytes
-rwxr-xr-xsetup.py4
9 files changed, 83 insertions, 76 deletions
diff --git a/README.rst b/README.rst
index 557069f..7676d22 100644
--- a/README.rst
+++ b/README.rst
@@ -4,7 +4,7 @@ Brutal Maze
 Brutal Maze is a research hash and slash game with fast-paced action and a
 minimalist art style.
 
-.. image:: https://raw.githubusercontent.com/McSinyx/brutalmaze/master/brutalmaze/icon.png
+.. image:: https://raw.githubusercontent.com/McSinyx/brutalmaze/master/screenshot.png
 
 The game features a trigon trapped in an infinite maze. As our hero tries to
 escape, the maze's border turn into aggressive squares trying to stop him. Your
@@ -26,8 +26,8 @@ Installation
 Brutal Maze is written in Python and is compatible with both version 2 and 3.
 The installation procedure should be as simply as follow:
 
-* Make sure you have Python and `pip <https://pip.pypa.io/en/latest/>`_
-  installed on your system.
+* Install Python and `pip <https://pip.pypa.io/en/latest/>`_. Make sure the
+  directory for Python executables is your ``PATH``.
 * Clone the Github repository or download the Zip achieve and unpack.
 * Open Terminal in the directory containing the repo's folder and run
   ``pip install --user brutalmaze``.
diff --git a/brutalmaze/characters.py b/brutalmaze/characters.py
index dd69d69..0490a55 100644
--- a/brutalmaze/characters.py
+++ b/brutalmaze/characters.py
@@ -17,17 +17,17 @@
 #
 # Copyright (C) 2017 Nguyễn Gia Phong
 
-__doc__ = 'brutalmaze module for hero and enemy classes'
-
 from collections import deque
 from math import atan2, sin, pi
-from random import shuffle
+from random import choice, shuffle
 
 import pygame
 
 from .constants import *
 from .utils import randsign, regpoly, fill_aapolygon, pos, sign
 
+__doc__ = 'brutalmaze module for hero and enemy classes'
+
 
 class Hero:
     """Object representing the hero."""
@@ -40,15 +40,15 @@ class Hero:
 
         self.next_strike = 0
         self.slashing = self.firing = False
-        self.spin_speed = fps / len(self.color)
+        self.spin_speed = fps / HERO_HP
         self.spin_queue = self.wound = 0.0
 
     def update(self, fps):
         """Update the hero."""
         old_speed, time = self.spin_speed, pygame.time.get_ticks()
-        self.spin_speed = fps / (len(self.color)-self.wound**0.5)
+        self.spin_speed = fps / (HERO_HP-self.wound**0.5)
         self.spin_queue *= self.spin_speed / old_speed
-        self.wound -= HEAL_SPEED / len(self.color) / self.spin_speed
+        self.wound -= HEAL_SPEED / self.spin_speed / HERO_HP
         if self.wound < 0: self.wound = 0.0
 
         if self.slashing and time >= self.next_strike:
@@ -74,9 +74,9 @@ class Hero:
 
 class Enemy:
     """Object representing an enemy."""
-    def __init__(self, surface, fps, maze, kind, x, y):
+    def __init__(self, surface, fps, maze, x, y):
         self.surface, self.maze = surface, maze
-        self.angle, self.color = pi / 4, TANGO[kind]
+        self.angle, self.color = pi / 4, TANGO[choice(ENEMIES)]
         self.x, self.y = x, y
         self.maze[x][y] = ENEMY
 
@@ -84,7 +84,7 @@ class Enemy:
         self.next_move = 0
         self.move_speed = fps / MOVE_SPEED
         self.offsetx = self.offsety = 0
-        self.spin_speed = fps / len(self.color)
+        self.spin_speed = fps / ENEMY_HP
         self.spin_queue = self.wound = 0.0
 
     def firable(self):
@@ -137,7 +137,7 @@ class Enemy:
     def update(self, fps, distance, middlex, middley):
         """Update the enemy."""
         if self.awake:
-            self.spin_speed, old_speed = fps / len(self.color), self.spin_speed
+            self.spin_speed, old_speed = fps / ENEMY_HP, self.spin_speed
             self.spin_queue *= self.spin_speed / old_speed
             if not self.spin_queue and not self.move(fps):
                 self.spin_queue = randsign() * self.spin_speed
diff --git a/brutalmaze/constants.py b/brutalmaze/constants.py
index e85c1cb..d3d97b5 100644
--- a/brutalmaze/constants.py
+++ b/brutalmaze/constants.py
@@ -18,7 +18,6 @@
 # Copyright (C) 2017 Nguyễn Gia Phong
 
 from pygame import image
-from pygame.locals import *
 from pkg_resources import resource_filename
 
 __doc__ = 'brutalmaze module for shared constants'
@@ -29,6 +28,7 @@ SQRT2 = 2 ** 0.5
 GOLDEN_MEAN = 5**0.5/2 + 0.5
 
 INIT_FPS = 30.0
+MAX_FPS = 144.0
 SIZE = 640, 480
 MAZE_SIZE = 10
 ROAD_WIDTH = 5  # grids
@@ -38,7 +38,7 @@ LAST_ROW = (MAZE_SIZE-1) * ROAD_WIDTH * 2
 INIT_SCORE = 208.2016
 MOVE_SPEED = 5  # grid/s
 BULLET_SPEED = 10   # grid/s
-HEAL_SPEED = 1.0    # HP/s
+HEAL_SPEED = 1  # HP/s
 ATTACK_SPEED = 333  # ms/strike
 BULLET_LIFETIME = 1000  # ms
 
@@ -56,5 +56,7 @@ TANGO = {'Butter': ((252, 233, 79), (237, 212, 0), (196, 160, 0)),
                        (136, 138, 133), (85, 87, 83), (46, 52, 54))}
 ENEMIES = ('Butter', 'Orange', 'Chocolate', 'Chameleon',
            'Sky Blue', 'Plum', 'Scarlet Red')
+ENEMY_HP = 3
+HERO_HP = 6
 BG_COLOR = TANGO['Aluminium'][-1]
 FG_COLOR = TANGO['Aluminium'][0]
diff --git a/brutalmaze/main.py b/brutalmaze/main.py
index eb17954..c58e9cb 100644
--- a/brutalmaze/main.py
+++ b/brutalmaze/main.py
@@ -20,8 +20,9 @@
 from collections import deque
 
 import pygame
+from pygame.locals import *
 
-from .constants import *
+from .constants import ICON, SIZE, INIT_FPS, MAX_FPS
 from .maze import Maze
 
 
@@ -38,25 +39,27 @@ def main():
             if event.type == QUIT:
                 going = False
             elif event.type == KEYDOWN:
-                if event.key in (K_UP, K_w):
-                    maze.move(0, 1)
+                if event.key in (K_ESCAPE, K_p):
+                    maze.paused ^= True
+                elif event.key in (K_UP, K_w):
+                    maze.move(up=-1)
                 elif event.key in (K_LEFT, K_a):
-                    maze.move(1, 0)
+                    maze.move(left=-1)
                 elif event.key in (K_DOWN, K_s):
-                    maze.move(0, -1)
+                    maze.move(down=-1)
                 elif event.key in (K_RIGHT, K_d):
-                    maze.move(-1, 0)
+                    maze.move(right=-1)
                 elif event.key == K_RETURN:
                     maze.hero.slashing = True
             elif event.type == KEYUP:
                 if event.key in (K_UP, K_w):
-                    maze.move(0, -1)
+                    maze.move(up=1)
                 elif event.key in (K_LEFT, K_a):
-                    maze.move(-1, 0)
+                    maze.move(left=1)
                 elif event.key in (K_DOWN, K_s):
-                    maze.move(0, 1)
+                    maze.move(down=1)
                 elif event.key in (K_RIGHT, K_d):
-                    maze.move(1, 0)
+                    maze.move(right=1)
                 elif event.key == K_RETURN:
                     maze.hero.slashing = False
             elif event.type == MOUSEBUTTONDOWN:
@@ -73,8 +76,11 @@ def main():
                 maze.resize(event.w, event.h)
         if len(flash_time) > 5:
             new_fps = 5000.0 / (flash_time[-1] - flash_time[0])
-            fps += -1 if new_fps < fps else 5
             flash_time.popleft()
+            if new_fps < fps:
+                fps -= 1
+            elif fps < MAX_FPS and not maze.paused:
+                fps += 5
         maze.update(fps)
         flash_time.append(pygame.time.get_ticks())
         clock.tick(fps)
diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py
index f9877a4..2e1e44c 100644
--- a/brutalmaze/maze.py
+++ b/brutalmaze/maze.py
@@ -22,6 +22,7 @@ from math import pi, atan, atan2, log
 from random import choice, getrandbits, uniform
 
 import pygame
+from pygame import RESIZABLE
 
 from .characters import Hero, Enemy
 from .constants import *
@@ -64,11 +65,12 @@ class Maze:
         self.rangex = range(MIDDLE - w, MIDDLE + w + 1)
         self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
         self.offsetx = self.offsety = 0.0
-        self.score = INIT_SCORE
+        self.paused, self.score = False, INIT_SCORE
 
         self.map = deque()
         for _ in range(MAZE_SIZE): self.map.extend(new_column())
-        self.right = self.down = self.rotatex = self.rotatey = 0
+        self.up = self.left = self.down = self.right = 0
+        self.rotatex = self.rotatey = 0
         self.bullets, self.enemies = [], []
         self.add_enemy()
         self.hero = Hero(self.surface, fps)
@@ -85,8 +87,7 @@ class Maze:
             x, y = choice(walls)
             if all(self.map[x + a][y + b] == WALL for a, b in ADJACENT_GRIDS):
                 continue
-            self.enemies.append(
-                Enemy(self.surface, self.fps, self.map, choice(ENEMIES), x, y))
+            self.enemies.append(Enemy(self.surface, self.fps, self.map, x, y))
             walls.remove((x, y))
 
     def draw(self):
@@ -135,6 +136,7 @@ class Maze:
         for i, enemy in enumerate(self.enemies):
             enemy.place(x, y)
             if enemy.x not in self.rangex or enemy.y not in self.rangey:
+                self.score += enemy.wound
                 enemy.die()
                 killist.append(i)
         for i in reversed(killist): self.enemies.pop(i)
@@ -175,7 +177,7 @@ class Maze:
             d = length(x, y, self.x, self.y)
             if d <= self.slashd:
                 enemy.wound += (self.slashd-d) / unit
-                if enemy.wound >= len(enemy.color):
+                if enemy.wound >= ENEMY_HP:
                     self.score += enemy.wound
                     enemy.die()
                     killist.append(i)
@@ -186,11 +188,11 @@ class Maze:
         """Handle the bullets."""
         fallen, time = [], pygame.time.get_ticks()
         for enemy in self.enemies:
+            # Chance that an enemy fire increase from 25% to 50%
             if uniform(-2, 2) > (INIT_SCORE/self.score)**2 and enemy.firable():
                 x, y = enemy.pos(self.distance, self.middlex, self.middley)
-                self.bullets.append(
-                    Bullet(self.surface, x, y, atan2(self.y - y, self.x - x),
-                           enemy.color[0]))
+                angle, color = atan2(self.y - y, self.x - x), enemy.color[0]
+                self.bullets.append(Bullet(self.surface, x, y, angle, color))
         if (self.hero.firing and not self.hero.slashing
             and time >= self.hero.next_strike):
             self.hero.next_strike = time + ATTACK_SPEED
@@ -211,7 +213,7 @@ class Maze:
                     x, y = enemy.pos(self.distance, self.middlex, self.middley)
                     if length(bullet.x, bullet.y, x, y) < self.distance:
                         enemy.wound += wound
-                        if enemy.wound >= len(enemy.color):
+                        if enemy.wound >= ENEMY_HP:
                             self.score += enemy.wound
                             enemy.die()
                             self.enemies.pop(j)
@@ -224,32 +226,29 @@ class Maze:
 
     def update(self, fps):
         """Update the maze."""
+        if self.paused: return
         self.offsetx *= fps / self.fps
         self.offsety *= fps / self.fps
         self.fps, self.speed = fps, fps / MOVE_SPEED
         self.step = self.distance / self.speed
 
-        dx, dy, d = 0, 0, self.distance*1.5 - self.hero.R
-        if self.right:
-            self.offsetx += self.right
-            s = sign(self.offsetx) * 2
-            if ((self.map[MIDDLE - s][MIDDLE - 1]
-                 or self.map[MIDDLE - s][MIDDLE]
-                 or self.map[MIDDLE - s][MIDDLE + 1])
-                and abs(self.offsetx*self.step) > d):
-                self.offsetx -= self.right
-            else:
-                dx = self.right
-        if self.down:
-            self.offsety += self.down
-            s = sign(self.offsety) * 2
-            if ((self.map[MIDDLE - 1][MIDDLE - s]
-                 or self.map[MIDDLE][MIDDLE - s]
-                 or self.map[MIDDLE + 1][MIDDLE - s])
-                and abs(self.offsety*self.step) > d):
-                self.offsety -= self.down
-            else:
-                dy = self.down
+        d = self.distance*1.5 - self.hero.R
+        dx, dy = sign(self.right) - sign(self.left), sign(self.down) - sign(self.up)
+        self.offsetx += dx
+        self.offsety += dy
+        x, y = MIDDLE - sign(self.offsetx)*2, MIDDLE - sign(self.offsety)*2
+        if ((self.map[x][MIDDLE - 1] != EMPTY
+             or self.map[x][MIDDLE] != EMPTY
+             or self.map[x][MIDDLE + 1] != EMPTY)
+            and abs(self.offsetx*self.step) > d):
+            self.offsetx -= dx
+            dx = 0
+        if ((self.map[MIDDLE - 1][y] != EMPTY
+             or self.map[MIDDLE][y] != EMPTY
+             or self.map[MIDDLE + 1][y] != EMPTY)
+            and abs(self.offsety*self.step) > d):
+            self.offsety -= dy
+            dy = 0
 
         if dx or dy:
             self.map[MIDDLE][MIDDLE] = EMPTY
@@ -263,15 +262,15 @@ class Maze:
             for bullet in self.bullets: bullet.place(dx, dy, self.step)
 
         self.draw()
+        self.slash()
+        self.track_bullets()
         for enemy in self.enemies:
             enemy.update(fps, self.distance, self.middlex, self.middley)
         self.hero.update(fps)
-        self.slash()
-        self.track_bullets()
         pygame.display.flip()
         pygame.display.set_caption('Brutal Maze - Score: {}'.format(
             int(self.score - INIT_SCORE)))
-        if self.hero.wound + 1 > len(self.hero.color): self.lose()
+        if self.hero.wound + 1 > HERO_HP: self.lose()
 
     def resize(self, w, h):
         """Resize the maze."""
@@ -289,14 +288,14 @@ class Maze:
         self.rangey = range(MIDDLE - h, MIDDLE + h + 1)
         self.slashd = self.hero.R + self.distance/SQRT2
 
-    def move(self, x, y):
-        """Command the maze to move x step/frame faster to the left and
-        y step/frame faster upward so the hero will move in the reverse
-        direction.
+    def move(self, up=0, left=0, down=0, right=0):
+        """Make the maze to move in the given directions by moving the
+        maze in the reverse way.
         """
-        self.right += x
-        self.down += y
-        self.right, self.down = sign(self.right), sign(self.down)
+        self.up += up
+        self.left += left
+        self.down += down
+        self.right += right
 
     def lose(self):
         """Handle loses."""
diff --git a/brutalmaze/utils.py b/brutalmaze/utils.py
index f972fc8..ac47d2d 100644
--- a/brutalmaze/utils.py
+++ b/brutalmaze/utils.py
@@ -17,14 +17,14 @@
 #
 # Copyright (C) 2017 Nguyễn Gia Phong
 
-__doc__ = 'brutalmaze module for hero and enemy classes'
-
 from math import cos, sin, pi
 
 import pygame
 from pygame.gfxdraw import filled_polygon, aapolygon
 
-from .constants import *
+from .constants import MIDDLE
+
+__doc__ = 'brutalmaze module for hero and enemy classes'
 
 
 def round2(number):
diff --git a/brutalmaze/weapons.py b/brutalmaze/weapons.py
index 0d2fb8c..110fc10 100644
--- a/brutalmaze/weapons.py
+++ b/brutalmaze/weapons.py
@@ -17,14 +17,14 @@
 #
 # Copyright (C) 2017 Nguyễn Gia Phong
 
-__doc__ = 'brutalmaze module for weapon classes'
-
-from math import pi, cos, sin
+from math import cos, sin
 
 from pygame.time import get_ticks
 
-from .constants import *
-from .utils import randsign, regpoly, fill_aapolygon, pos, sign
+from .constants import BULLET_LIFETIME, BULLET_SPEED
+from .utils import regpoly, fill_aapolygon
+
+__doc__ = 'brutalmaze module for weapon classes'
 
 
 class Bullet:
diff --git a/screenshot.png b/screenshot.png
new file mode 100644
index 0000000..9c2a893
--- /dev/null
+++ b/screenshot.png
Binary files differdiff --git a/setup.py b/setup.py
index d295fe9..083b11b 100755
--- a/setup.py
+++ b/setup.py
@@ -24,9 +24,9 @@ setup(
         'Natural Language :: English',
         'Operating System :: OS Independent',
         'Programming Language :: Python',
-        'Topic :: Games/Entertainment :: Role-Playing'],
+        'Topic :: Games/Entertainment :: Arcade'],
     keywords='',
     packages=['brutalmaze'],
     install_requires=['pygame>=1.9'],
-    package_data={'brutalmaze': ['*.xm']},
+    package_data={'brutalmaze': ['icon.png']},
     entry_points={'gui_scripts': ['brutalmaze = brutalmaze:main']})