Merge branch 'master' of ctpug.org.za:koperkapel
authorSimon Cross <hodgestar@gmail.com>
Sat, 5 Mar 2016 19:52:27 +0000 (21:52 +0200)
committerSimon Cross <hodgestar@gmail.com>
Sat, 5 Mar 2016 19:52:27 +0000 (21:52 +0200)
14 files changed:
README
koperkapel/gamelib/enemy_generator.py
koperkapel/gamelib/enemy_roach.py [new file with mode: 0644]
koperkapel/gamelib/level.py
koperkapel/loaders/levelloader.py
koperkapel/roaches.py
koperkapel/scenes/level.py
koperkapel/scenes/roach_management.py
koperkapel/scenes/viewlevel.py
koperkapel/serums.py
koperkapel/util.py [new file with mode: 0644]
koperkapel/vehicles/base.py
koperkapel/weapons.py
run_game.py

diff --git a/README b/README
index a21e2e2ae26fbd9383df36502269ab12842615a0..0553d38a17bf6c4642ab132c05fa2e7059a3517b 100644 (file)
--- a/README
+++ b/README
@@ -10,6 +10,16 @@ can be found at https://pygame-zero.readthedocs.org/en/latest/installation.html.
 Running the game
 ================
 
+This game requires Python 3.
+
 Run the game using:
 
 $ python -m koperkapel
+
+or, if your default python is Python 2,
+
+$ python3 -m koperkapel
+
+or just
+
+$ ./run_game.py
index 3003064c8ae4a6f9e6b11bea7499e3c4305b70a3..1329660b1881140768f557e2912c5e0305a018ee 100644 (file)
@@ -4,17 +4,21 @@ import os
 from pgzero.actor import Actor
 from pgzero.clock import each_tick
 
+from .enemy_roach import get_enemy_roach
+
 class EnemyGenerator(Actor):
     """Generators are currently invisble, but we want the update hook."""
 
-    def __init__(self, info):
+    def __init__(self, info, level):
         self.gen_pos = info['pos']
+        self.level = level
         self.enemy_type = info['type']
         self.rate = info['rate']
         self.max_enemies = info['max']
         self._time_since_last_update = 0
         self.paused = False
         each_tick(self.update)
+        self._made_enemies = []
         super().__init__(os.path.join('weapons', 'blank'))
 
     def update(self, dt):
@@ -22,8 +26,18 @@ class EnemyGenerator(Actor):
             return
         self._time_since_last_update += dt
         if self._time_since_last_update > self.rate:
-            print('A horrible monster (%s) appears' % self.enemy_type, self.gen_pos)
-            self._time_since_last_update = 0
+            if len(self._made_enemies) < self.max_enemies:
+                self._make_enemy()
+
+    def _make_enemy(self):
+        if self.enemy_type == 'roach':
+            roach = get_enemy_roach()
+            self._made_enemies.append(roach)
+            self.level.add_enemy(roach, *self.gen_pos)
+
+    def killed(self, enemy):
+        if enemy in self._made_enemies:
+            self._made_enemies.remove(enemy)
 
     def pause(self):
         self.paused = True
diff --git a/koperkapel/gamelib/enemy_roach.py b/koperkapel/gamelib/enemy_roach.py
new file mode 100644 (file)
index 0000000..95b3e19
--- /dev/null
@@ -0,0 +1,11 @@
+# Roach utilities
+
+from ..roaches import t32_roaches, WorldRoach
+
+
+def get_enemy_roach():
+    # red
+    roach = t32_roaches.assemble(WorldRoach(), color=(255, 0, 0, 255))
+    roach.anchor = (0, 0)
+    roach.game_pos = (0, 0)
+    return roach
index bcc319a2886d2f5e530d30ff70be6f7f50478a09..3df9fe03598dc598db85666491d342370c7b2eee 100644 (file)
@@ -1,5 +1,7 @@
 """ Class holding the level info """
 
+import random
+
 
 class Level(object):
 
@@ -84,3 +86,30 @@ class Level(object):
 
     def get_exit_level(self):
         return self.exit["next level"]
+
+    def is_on_enemy(self, x, y):
+        for enemy in self.enemies:
+            if (x, y) == enemy.game_pos:
+                return True
+        return False
+
+    def get_enemy(self, x, y):
+        for enemy in self.enemies:
+            if (x, y) == enemy.game_pos:
+                return enemy
+        return None
+
+    def add_enemy(self, enemy, x, y):
+        """Add an enemy to an empty floor space near x, y"""
+        added = False
+        while not added:
+            if self.can_walk(x, y, 'floor'):
+                if not self.is_on_friend(x, y):
+                    if not self.is_on_enemy(x, y):
+                        added = True
+                        enemy.game_pos = (x, y)
+                        self.enemies.append(enemy)
+                        added = True
+            x += random.randint(-1, 1)
+            y += random.randint(-1, 1)
+
index a775838dc54b1b02c18734ab69709d4a34c16230..14db3bee5419de099d785e50d87fbbc7db72783c 100644 (file)
@@ -73,7 +73,7 @@ class LevelLoader(ResourceLoader):
         for item in level_data['items']:
             self._level.items.append(get_item(item))
         for generator in level_data['enemy generators']:
-            enemy = EnemyGenerator(generator)
+            enemy = EnemyGenerator(generator, self._level)
             self._level.enemy_generators.append(enemy)
         return self._level
 
index b708a88b9b0219f65bee7656b924362113cca6a8..1d77563953442090efc97e766d62d0dd243569d2 100644 (file)
@@ -4,6 +4,7 @@ from pgzero.loaders import images
 from pygame.constants import BLEND_RGBA_MULT
 from .actors.animsurf import AnimatedSurfActor
 from .serums import roach_serum_color
+from .util import safepath
 
 NAMES = [
     "roupert",
@@ -75,8 +76,8 @@ class RoachFactory:
         self.frames = 4
 
     def assemble_frame(self, i, color, roach_data, weapon=None):
-        roach = images.load("roach%s/roach_%d" % (self.suffix, i + 1))
-        eyes = images.load("roach%s/eyes_%d" % (self.suffix, i + 1))
+        roach = images.load(safepath("roach%s/roach_%d") % (self.suffix, i + 1))
+        eyes = images.load(safepath("roach%s/eyes_%d") % (self.suffix, i + 1))
         if weapon is None:
             frame = roach.copy()
             frame.fill(color, None, BLEND_RGBA_MULT)
@@ -88,8 +89,9 @@ class RoachFactory:
         frame.blit(eyes, (0, 0))
         return frame
 
-    def assemble(self, roach_data, weapon=None):
-        color = roach_serum_color(roach_data)
+    def assemble(self, roach_data, color=None, weapon=None):
+        if not color:
+            color = roach_serum_color(roach_data)
         frames = []
         frames = [
             self.assemble_frame(i, color, roach_data, weapon)
index a6844663caf020b5ffdafb3d9ad6c470ab677e14..e5d102a265d9772b9095d3915166c1bbf479dceb 100644 (file)
@@ -146,7 +146,9 @@ class GameLevelScene(BaseLevelScene):
 
     def _can_move(self, x, y):
         if self._mode == 'walk':
-            return self._level.can_walk(x, y, self._level_layer)
+            if not self._level.is_on_enemy(x, y):
+                return self._level.can_walk(x, y, self._level_layer)
+            return False
         elif self._mode == 'fly':
             return self._level.can_fly(x, y, self._level_layer)
         elif self._mode == 'crawl':
@@ -198,11 +200,22 @@ class GameLevelScene(BaseLevelScene):
         for item in self._items:
             item.pos = self.calc_offset(
                 item.game_pos[0] * TILE_SIZE, item.game_pos[1] * TILE_SIZE)
+        self._check_enemies()
+        for enemy in self._enemies:
+            enemy.pos = self.calc_offset(
+                enemy.game_pos[0] * TILE_SIZE, enemy.game_pos[1] * TILE_SIZE)
         more = self._check_held_keys(dt)
         if more:
             events.extend(more)
         return events
 
+    def _check_enemies(self):
+        if len(self._level.enemies) != len(self._enemies):
+            # New nemy has spawned
+            for enemy in self._level.enemies:
+                if enemy not in self._enemies:
+                    self._enemies.add(enemy)
+
     def _check_held_keys(self, dt):
         for key in self._held_keys:
             self._last_key_down += dt
index 4e41b9c538608d0dd7df2097335a772556d1331a..dd05e755404334f6b37394a044a02b30f1ec6f78 100644 (file)
@@ -11,6 +11,7 @@ from ..roaches import big_roaches, roach_by_name
 from ..serums import big_serums, roach_is_serumless, SERUMS
 from ..vehicles.base import Vehicle
 from .base import Scene, ChangeSceneEvent, defer_to_update
+from ..util import safepath
 
 
 TOOLBAR_LEFT_X = WIDTH * 3 // 4
@@ -135,10 +136,10 @@ class RoachesScene(Scene):
 
     def _init_pads(self):
         self._roach_pad = self._pad_layer.add(
-            Actor("roach_management/roach_pad", anchor=("left", "bottom")))
+            Actor(safepath("roach_management/roach_pad"), anchor=("left", "bottom")))
         self._roach_pad.pos = (TOOLBAR_LEFT_X, TOOLBAR_MID_Y)
         self._inventory_pad = self._pad_layer.add(
-            Actor("roach_management/inventory_pad", anchor=("left", "top")))
+            Actor(safepath("roach_management/inventory_pad"), anchor=("left", "top")))
         self._inventory_pad.pos = (TOOLBAR_LEFT_X, TOOLBAR_MID_Y)
 
     def _add_button(self, name, anchor, inset, pos, action):
@@ -150,23 +151,23 @@ class RoachesScene(Scene):
     def _init_buttons(self):
         self._button_layer.clear()
         self._add_button(
-            "roach_management/left_button", ("left", "bottom"), (1, -1),
+            safepath("roach_management/left_button"), ("left", "bottom"), (1, -1),
             self._roach_pad.bottomleft, self._roach_left)
 
         self._add_button(
-            "roach_management/right_button", ("right", "bottom"), (-1, -1),
+            safepath("roach_management/right_button"), ("right", "bottom"), (-1, -1),
             self._roach_pad.bottomright, self._roach_right)
 
         self._add_button(
-            "roach_management/left_button", ("left", "bottom"), (1, -1),
+            safepath("roach_management/left_button"), ("left", "bottom"), (1, -1),
             self._inventory_pad.bottomleft, self._inventory_left)
 
         self._add_button(
-            "roach_management/right_button", ("right", "bottom"), (-1, -1),
+            safepath("roach_management/right_button"), ("right", "bottom"), (-1, -1),
             self._inventory_pad.bottomright, self._inventory_right)
 
         self._add_button(
-            "roach_management/eject_button", ("right", "top"), (-1, 1),
+            safepath("roach_management/eject_button"), ("right", "top"), (-1, 1),
             (TOOLBAR_LEFT_X, TOOLBAR_TOP_Y), self._eject_roach)
 
     def _roach_left(self):
index f6c56b66861b140ce95c86c8164d6e76da41e16e..28e4026ce82a154b2ccad7afdb517c2f5a34e70e 100644 (file)
@@ -1,13 +1,12 @@
 """Render a level and allow moving the scene"""
 
-import os
-
 from pygame.constants import BLEND_RGBA_MULT
 from pgzero.constants import keys
 from pgzero.loaders import images
 from .level import BaseLevelScene
 from .base import MoveViewportEvent
 from ..constants import TILE_SIZE
+from ..util import safepath
 
 
 class ViewLevelScene(BaseLevelScene):
@@ -16,7 +15,7 @@ class ViewLevelScene(BaseLevelScene):
     def enter(self, world):
         super().enter(world)
         # Mark starting position
-        self._roach = images.load(os.path.join("roach/roach_1")).copy()
+        self._roach = images.load(safepath("roach/roach_1")).copy()
         self._roach.fill((255, 0, 0, 255), None, BLEND_RGBA_MULT)
         x = self._level.start_pos[0] * TILE_SIZE
         y = self._level.start_pos[1] * TILE_SIZE
index 38794fd4926834bba5129b650f836e944c534490..22391145f2b23843f75bccad381cae6f33fc4d7f 100644 (file)
@@ -5,6 +5,7 @@ from pgzero.loaders import images
 from pygame.constants import BLEND_RGBA_MULT
 from pygame.transform import rotate
 from .actors.surf import SurfActor
+from .util import safepath
 
 SERUMS = ["smart", "fast", "strong"]
 
@@ -42,9 +43,9 @@ class SerumFactory:
 
     def assemble(self, name):
         assert name in SERUMS
-        puddle = images.load("serum%s/serum" % (self.suffix,))
+        puddle = images.load(safepath("serum%s/serum") % (self.suffix,))
         puddle = rotate(puddle, 90 * random.randint(0, 3))
-        serum_icon = images.load("serum%s/%s" % (
+        serum_icon = images.load(safepath("serum%s/%s") % (
             self.suffix, SERUM_TILENAME_MAP[name],))
         frame = puddle.copy()
         frame.fill(SERUM_OVERLAY_COLORS[name], None, BLEND_RGBA_MULT)
diff --git a/koperkapel/util.py b/koperkapel/util.py
new file mode 100644 (file)
index 0000000..246fb57
--- /dev/null
@@ -0,0 +1,6 @@
+"""Utility functions"""
+
+import os
+
+def safepath(path):
+    return os.path.join(*path.split("/"))
index ba21bbeb94857284f829ebbb8ccc1c731d84ee9e..2c1d9bf97d5b2e2109fc7f7cc4fbf129aacd2a5c 100644 (file)
@@ -8,6 +8,7 @@ from pgzero.loaders import images
 from ..actors.orientatedsurf import SelectableSurfActor
 from ..actors.animsurf import AnimatedSurfActor
 from ..weapons import default_weapons
+from ..util import safepath
 
 
 class Vehicle:
@@ -24,12 +25,12 @@ class Vehicle:
         self.game_pos = (0, 0)
 
     def roach_management_overlay(self):
-        return images.load("vehicles/walking/background")
+        return images.load(safepath("vehicles/walking/background"))
 
     def roach_management_frame(self):
         if self.overlay_frame_no is None:
             return None
-        return images.load("vehicle_big/%s_%d" % (
+        return images.load(safepath("vehicle_big/%s_%d") % (
             self.vehicle_type, self.overlay_frame_no))
 
     def init_seats(self):
@@ -92,7 +93,7 @@ class Vehicle:
         cls.register(Roomba)
 
     def _avatar_frame(self, i, weapon, suffix="_tiles"):
-        vehicle = images.load("vehicle%s/%s_%d" % (
+        vehicle = images.load(safepath("vehicle%s/%s_%d") % (
             suffix, self.vehicle_type, i + 1))
         frame = vehicle.copy()
         frame.blit(weapon.surf, (0, 0))
@@ -125,7 +126,7 @@ class Seat:
         self.vehicle_pos = (pos[0] * vrad, pos[1] * vrad)
 
     def actor(self):
-        seat = images.load("vehicles/walking/seat")
+        seat = images.load(safepath("vehicles/walking/seat"))
         selected_seat = seat.copy()
         selected_seat.fill(
             self.vehicle.selected_seat_overlay_color, None, BLEND_RGBA_MULT)
index da8c4c3712b6ccafeca80fed1c17bb929c9384ea..890743dbe5ccb5fb1338006a762f7874aae2a3d6 100644 (file)
@@ -2,6 +2,7 @@
 
 from pgzero.loaders import images
 from .actors.animsurf import AnimatedSurfActor
+from .util import safepath
 
 
 class Weapon:
@@ -35,10 +36,11 @@ class WeaponActor(AnimatedSurfActor):
 class WeaponFactory:
 
     def assemble_frame(self, suffix, weapon, tape):
-        surf = images.load("weapons/%s%s" % (weapon.image_name, suffix))
+        surf = images.load(safepath("weapons/%s%s")
+                            % (weapon.image_name, suffix))
         frame = surf.copy()
         if tape:
-            tape_surf = images.load("weapons/tape")
+            tape_surf = images.load(safepath("weapons/tape"))
             frame.blit(tape_surf, (0, 0))
         return frame
 
index f48806ad5197ec79c4dadd42407f4cad9b4b6833..072d2b25963b5e8ea0afd261493158f5e3f974dd 100755 (executable)
@@ -1,5 +1,6 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 
 """ Run Portentosa. """
 
 import koperkapel.__main__
+