summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--brutalmaze/__init__.py2
-rw-r--r--brutalmaze/__main__.py (renamed from brutalmaze/game.py)23
-rw-r--r--brutalmaze/characters.py17
-rw-r--r--brutalmaze/constants.py23
-rw-r--r--brutalmaze/maze.py21
-rw-r--r--brutalmaze/misc.py12
-rw-r--r--brutalmaze/soundfx/__init__.py1
-rw-r--r--brutalmaze/weapons.py10
-rw-r--r--pyproject.toml4
9 files changed, 50 insertions, 63 deletions
diff --git a/brutalmaze/__init__.py b/brutalmaze/__init__.py
index ce4296a..1eca2a1 100644
--- a/brutalmaze/__init__.py
+++ b/brutalmaze/__init__.py
@@ -1,3 +1,3 @@
 """Minimalist thrilling shoot 'em up game"""
 
-from .game import __version__
+from .__main__ import __version__
diff --git a/brutalmaze/game.py b/brutalmaze/__main__.py
index 8b11228..a9a0e98 100644
--- a/brutalmaze/game.py
+++ b/brutalmaze/__main__.py
@@ -1,5 +1,5 @@
-# game.py - main module, starts game and main loop
-# Copyright (C) 2017-2020  Nguyễn Gia Phong
+# Game initialization and main loop
+# Copyright (C) 2017-2021  Nguyễn Gia Phong
 #
 # This file is part of Brutal Maze.
 #
@@ -16,12 +16,13 @@
 # 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.9.4'
+__version__ = '1.0.0'
 
 import re
 from argparse import ArgumentParser, FileType, RawTextHelpFormatter
 from configparser import ConfigParser
 from contextlib import redirect_stdout
+from importlib.resources import open_binary, path, read_text
 from io import StringIO
 from math import atan2, pi, radians
 from os.path import join as pathjoin, pathsep
@@ -35,7 +36,7 @@ from palace import Context, Device, free, use_context
 from pygame import KEYDOWN, MOUSEBUTTONUP, QUIT, VIDEORESIZE
 from pygame.time import Clock, get_ticks
 
-from .constants import HERO_SPEED, ICON, MIDDLE, SETTINGS, SFX, SFX_NOISE
+from .constants import HERO_SPEED, MIDDLE, SFX
 from .maze import Maze
 from .misc import deg, join, play, sign
 
@@ -55,7 +56,9 @@ class ConfigReader:
 
     def __init__(self, filenames):
         self.config = ConfigParser()
-        self.config.read(SETTINGS)  # default configuration
+        # Default configuration
+        with path('brutalmaze', 'settings.ini') as settings:
+            self.config.read(settings)
         self.config.read(filenames)
 
     # Fallback to None when attribute is missing
@@ -108,7 +111,9 @@ class Game:
     def __init__(self, config: ConfigReader):
         pygame.init()
         self.headless = config.headless and config.server
-        if not self.headless: pygame.display.set_icon(ICON)
+        if not self.headless:
+            with open_binary('brutalmaze', 'icon.png') as icon:
+                pygame.display.set_icon(pygame.image.load(icon))
         self.actx = None if self.headless else Context(Device())
         self._mute = config.muted
 
@@ -138,7 +143,7 @@ class Game:
             use_context(self.actx)
             self.actx.listener.position = MIDDLE, -MIDDLE, 0
             self.actx.listener.gain = not self._mute
-            self._source = play(SFX_NOISE)
+            self._source = play('noise.ogg')
             self._source.looping = True
         return self
 
@@ -403,7 +408,7 @@ def main():
                         help='run server without graphics or sound')
     args = parser.parse_args()
     if args.defaultcfg is not None:
-        with open(SETTINGS) as settings: args.defaultcfg.write(settings.read())
+        args.defaultcfg.write(read_text('brutalmaze', 'settings.ini'))
         args.defaultcfg.close()
         exit()
 
@@ -426,5 +431,5 @@ def main():
             while game.update(): game.user_control()
 
 
-# Allow launching the game via invoking ``python -m brutalmaze.game''
+# Allow launching the game via invoking ``python -m brutalmaze''
 if __name__ == '__main__': main()
diff --git a/brutalmaze/characters.py b/brutalmaze/characters.py
index 1c37be9..12eebb5 100644
--- a/brutalmaze/characters.py
+++ b/brutalmaze/characters.py
@@ -1,5 +1,5 @@
-# characters.py - module for hero and enemy classes
-# Copyright (C) 2017-2020  Nguyễn Gia Phong
+# Hero and enemy classes
+# Copyright (C) 2017-2021  Nguyễn Gia Phong
 #
 # This file is part of Brutal Maze.
 #
@@ -23,10 +23,9 @@ from math import atan2, gcd, pi, sin
 from random import choice, randrange, shuffle
 from sys import modules
 
-from .constants import (ADJACENTS, AROUND_HERO, ATTACK_SPEED, EMPTY,
-                        ENEMIES, ENEMY, ENEMY_HP, ENEMY_SPEED, FIRANGE,
-                        HEAL_SPEED, HERO_HP, MIDDLE, MIN_BEAT, SFX_HEART,
-                        SFX_SLASH_HERO, SFX_SPAWN, SQRT2, TANGO, WALL)
+from .constants import (ADJACENTS, AROUND_HERO, ATTACK_SPEED, EMPTY, ENEMIES,
+                        ENEMY, ENEMY_HP, ENEMY_SPEED, FIRANGE, HEAL_SPEED,
+                        HERO_HP, MIDDLE, MIN_BEAT, SQRT2, TANGO, WALL)
 from .misc import fill_aapolygon, play, randsign, regpoly, sign
 from .weapons import Bullet
 
@@ -84,7 +83,7 @@ class Hero:
             if self.wound < 0: self.wound = 0.0
         self.wounds.append(0.0)
         if self.next_beat <= 0:
-            play(SFX_HEART)
+            play('heart.ogg')
             self.next_beat = MIN_BEAT*(2 - self.wound/HERO_HP)
         else:
             self.next_beat -= 1000 / fps
@@ -221,7 +220,7 @@ class Enemy:
             if self.maze.map[srcx+i//w][srcy+i//u] == WALL: return False
         self.awake = True
         self.maze.map[self.x][self.y] = ENEMY
-        play(SFX_SPAWN, self.x, self.y)
+        play('spawn.ogg', self.x, self.y)
         return True
 
     def fire(self):
@@ -311,7 +310,7 @@ class Enemy:
             if not self.spin_queue and not self.fire() and not self.move():
                 self.spin_queue = randsign() * self.spin_speed
                 if not self.maze.hero.dead:
-                    play(SFX_SLASH_HERO, self.x, self.y, self.get_slash())
+                    play('slash-hero.ogg', self.x, self.y, self.get_slash())
             if round(self.spin_queue) != 0:
                 self.angle += sign(self.spin_queue) * pi / 2 / self.spin_speed
                 self.spin_queue -= sign(self.spin_queue)
diff --git a/brutalmaze/constants.py b/brutalmaze/constants.py
index 396cc2b..69ea94d 100644
--- a/brutalmaze/constants.py
+++ b/brutalmaze/constants.py
@@ -1,5 +1,5 @@
-# constants.py - module for shared constants
-# Copyright (C) 2017-2020  Nguyễn Gia Phong
+# Shared constants
+# Copyright (C) 2017-2021  Nguyễn Gia Phong
 #
 # This file is part of Brutal Maze.
 #
@@ -20,23 +20,8 @@ __doc__ = 'Brutal Maze module for shared constants'
 
 from string import ascii_lowercase
 
-import pygame
-from pkg_resources import resource_filename as pkg_file
-
-SETTINGS = pkg_file('brutalmaze', 'settings.ini')
-ICON = pygame.image.load(pkg_file('brutalmaze', 'icon.png'))
-
-SFX_NOISE = pkg_file('brutalmaze', 'soundfx/noise.ogg')
-SFX_SPAWN = pkg_file('brutalmaze', 'soundfx/spawn.ogg')
-SFX_SLASH_ENEMY = pkg_file('brutalmaze', 'soundfx/slash-enemy.ogg')
-SFX_SLASH_HERO = pkg_file('brutalmaze', 'soundfx/slash-hero.ogg')
-SFX_SHOT_ENEMY = pkg_file('brutalmaze', 'soundfx/shot-enemy.ogg')
-SFX_SHOT_HERO = pkg_file('brutalmaze', 'soundfx/shot-hero.ogg')
-SFX_MISSED = pkg_file('brutalmaze', 'soundfx/missed.ogg')
-SFX_HEART = pkg_file('brutalmaze', 'soundfx/heart.ogg')
-SFX_LOSE = pkg_file('brutalmaze', 'soundfx/lose.ogg')
-SFX = (SFX_NOISE, SFX_SPAWN, SFX_SLASH_ENEMY, SFX_SLASH_HERO,
-       SFX_SHOT_ENEMY, SFX_SHOT_HERO, SFX_MISSED, SFX_HEART, SFX_LOSE)
+SFX = ('noise.ogg', 'spawn.ogg', 'missed.ogg', 'heart.ogg', 'lose.ogg',
+       'slash-enemy.ogg', 'slash-hero.ogg', 'shot-enemy.ogg', 'shot-hero.ogg')
 
 SQRT2 = 2 ** 0.5
 INIT_SCORE = 2
diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py
index d64e77f..a31fb86 100644
--- a/brutalmaze/maze.py
+++ b/brutalmaze/maze.py
@@ -1,5 +1,5 @@
-# maze.py - module for the maze class
-# Copyright (C) 2017-2020  Nguyễn Gia Phong
+# Maze class
+# Copyright (C) 2017-2021  Nguyễn Gia Phong
 #
 # This file is part of Brutal Maze.
 #
@@ -31,9 +31,8 @@ from .constants import (ADJACENTS, ATTACK_SPEED, BG_COLOR,
                         BULLET_LIFETIME, CELL_NODES, CELL_WIDTH, COLORS,
                         EMPTY, ENEMIES, ENEMY, ENEMY_HP, FG_COLOR, HERO,
                         HERO_HP, HERO_SPEED, INIT_SCORE, JSON_SEPARATORS,
-                        MAX_WOUND, MAZE_SIZE, MIDDLE, ROAD_WIDTH,
-                        SFX_LOSE, SFX_MISSED, SFX_SLASH_ENEMY, SFX_SPAWN,
-                        SQRT2, TANGO_VALUES, WALL, WALL_WIDTH)
+                        MAX_WOUND, MAZE_SIZE, MIDDLE, ROAD_WIDTH, SQRT2,
+                        TANGO_VALUES, WALL, WALL_WIDTH)
 from .misc import around, deg, fill_aapolygon, json_rec, play, regpoly, sign
 from .weapons import LockOn
 
@@ -97,10 +96,6 @@ class Maze:
         self.next_move = self.glitch = self.next_slashfx = 0.0
         self.slashd = self.hero.R + self.distance/SQRT2
 
-        self.sfx_spawn = SFX_SPAWN
-        self.sfx_slash = SFX_SLASH_ENEMY
-        self.sfx_lose = SFX_LOSE
-
     def new_cell(self, x, y):
         """Draw on the map a newly created cell
         whose coordinates are given.
@@ -291,7 +286,7 @@ class Maze:
             if d > 0:
                 wound = d * SQRT2 / self.distance
                 if self.next_slashfx <= 0:
-                    play(SFX_SLASH_ENEMY, enemy.x, enemy.y, wound)
+                    play('slash-enemy.ogg', enemy.x, enemy.y, wound)
                     self.next_slashfx = ATTACK_SPEED
                 enemy.hit(wound / self.hero.spin_speed)
                 if enemy.wound >= ENEMY_HP:
@@ -321,7 +316,7 @@ class Maze:
                     enemy = new_enemy(self, gridx, gridy)
                     enemy.awake = True
                     self.map[gridx][gridy] = ENEMY
-                    play(SFX_SPAWN, enemy.x, enemy.y)
+                    play('spawn.ogg', enemy.x, enemy.y)
                     enemy.hit(wound)
                     self.enemies.append(enemy)
                     continue
@@ -339,7 +334,7 @@ class Maze:
                 if block:
                     self.hero.next_strike = (abs(self.hero.spin_queue/self.fps)
                                              + ATTACK_SPEED)
-                    play(SFX_MISSED, gain=wound)
+                    play('missed.ogg', gain=wound)
                 else:
                     self.hit_hero(wound, bullet.color)
                     play(bullet.sfx_hit, gain=wound)
@@ -507,7 +502,7 @@ class Maze:
         self.destx = self.desty = MIDDLE
         self.stepx = self.stepy = 0
         self.vx = self.vy = 0.0
-        play(SFX_LOSE)
+        play('lose.ogg')
         self.dump_records()
 
     def reinit(self):
diff --git a/brutalmaze/misc.py b/brutalmaze/misc.py
index db1be00..94537db 100644
--- a/brutalmaze/misc.py
+++ b/brutalmaze/misc.py
@@ -1,5 +1,5 @@
-# misc.py - module for miscellaneous functions
-# Copyright (C) 2017-2020  Nguyễn Gia Phong
+# Miscellaneous functions
+# Copyright (C) 2017-2021  Nguyễn Gia Phong
 #
 # This file is part of Brutal Maze.
 #
@@ -19,6 +19,7 @@
 __doc__ = 'Brutal Maze module for miscellaneous functions'
 
 from datetime import datetime
+from importlib.resources import path as resource
 from itertools import chain
 from math import cos, degrees, pi, sin
 from os import path
@@ -86,14 +87,15 @@ def json_rec(directory):
     """Return path to JSON file to be created inside the given directory
     based on current time local to timezone in ISO 8601 format.
     """
-    return path.join(
-        directory, '{}.json'.format(datetime.now().isoformat()[:19]))
+    return path.join(directory,
+                     '{}.json'.format(datetime.now().isoformat()[:19]))
 
 
 def play(sound: str, x: float = MIDDLE, y: float = MIDDLE,
          gain: float = 1.0) -> Source:
     """Play a sound at the given position."""
-    source = Buffer(sound).play()
+    with resource('brutalmaze.soundfx', sound) as file:
+        source = Buffer(str(file)).play()
     source.spatialize = True
     source.position = x, -y, 0
     source.gain = gain
diff --git a/brutalmaze/soundfx/__init__.py b/brutalmaze/soundfx/__init__.py
new file mode 100644
index 0000000..ddc4efe
--- /dev/null
+++ b/brutalmaze/soundfx/__init__.py
@@ -0,0 +1 @@
+# This module intentional left blank to aid importlib.resources
diff --git a/brutalmaze/weapons.py b/brutalmaze/weapons.py
index e42f127..75ccb67 100644
--- a/brutalmaze/weapons.py
+++ b/brutalmaze/weapons.py
@@ -1,4 +1,4 @@
-# characters.py - module for weapon classes
+# Weapon classes
 # Copyright (C) 2017-2020  Nguyễn Gia Phong
 #
 # This file is part of Brutal Maze.
@@ -20,8 +20,7 @@ __doc__ = 'Brutal Maze module for weapon classes'
 
 from math import cos, sin
 
-from .constants import (BG_COLOR, BULLET_LIFETIME, BULLET_SPEED,
-                        ENEMY_HP, SFX_SHOT_ENEMY, SFX_SHOT_HERO, TANGO)
+from .constants import BG_COLOR, BULLET_LIFETIME, BULLET_SPEED, ENEMY_HP, TANGO
 from .misc import fill_aapolygon, regpoly
 
 
@@ -41,9 +40,9 @@ class Bullet:
         self.x, self.y, self.angle, self.color = x, y, angle, color
         self.fall_time = BULLET_LIFETIME
         if color == 'Aluminium':
-            self.sfx_hit = SFX_SHOT_ENEMY
+            self.sfx_hit = 'shot-enemy.ogg'
         else:
-            self.sfx_hit = SFX_SHOT_HERO
+            self.sfx_hit = 'shot-hero.ogg'
 
     def update(self, fps, distance):
         """Update the bullet."""
@@ -77,6 +76,7 @@ class Bullet:
 
 class LockOn:
     """Lock-on device to assist hero's aiming.
+
     This is used as a mutable object to represent a grid of wall.
 
     Attributes:
diff --git a/pyproject.toml b/pyproject.toml
index 7f80517..05d26cf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -7,7 +7,7 @@ module = 'brutalmaze'
 author = 'Nguyễn Gia Phong'
 author-email = 'mcsinyx@disroot.org'
 home-page = 'https://sr.ht/~cnx/brutalmaze'
-requires = ['appdirs', 'palace', 'pygame>=2', 'setuptools']
+requires = ['appdirs', 'palace', 'pygame>=2']
 description-file = 'README.rst'
 classifiers = [
     'Development Status :: 5 - Production/Stable',
@@ -29,4 +29,4 @@ license = 'AGPLv3+'
 Documentation = 'https://brutalmaze.rtfd.io'
 
 [tool.flit.entrypoints.console_scripts]
-brutalmaze = 'brutalmaze.game:main'
+brutalmaze = 'brutalmaze.__main__:main'