about summary refs log tree commit diff homepage
path: root/brutalmaze/maze.py
diff options
context:
space:
mode:
Diffstat (limited to 'brutalmaze/maze.py')
-rw-r--r--brutalmaze/maze.py45
1 files changed, 38 insertions, 7 deletions
diff --git a/brutalmaze/maze.py b/brutalmaze/maze.py
index da0de7c..b43b0e8 100644
--- a/brutalmaze/maze.py
+++ b/brutalmaze/maze.py
@@ -36,6 +36,7 @@ from .constants import (
     BULLET_LIFETIME, JSON_SEPARATORS)
 from .misc import (
     round2, sign, deg, around, regpoly, fill_aapolygon, play, json_rec)
+from .weapons import LockOn
 
 
 class Maze:
@@ -59,6 +60,7 @@ class Maze:
         hero (Hero): the hero
         destx, desty (int): the grid the hero is moving to
         stepx, stepy (int): direction the maze is moving
+        target (Enemy or LockOn): target to automatically aim at
         next_move (float): time until the hero gets mobilized (in ms)
         glitch (float): time that the maze remain flashing colors (in ms)
         next_slashfx (float): time until next slash effect of the hero (in ms)
@@ -102,6 +104,7 @@ class Maze:
         self.map[MIDDLE][MIDDLE] = HERO
         self.destx = self.desty = MIDDLE
         self.stepx = self.stepy = 0
+        self.target = LockOn(MIDDLE, MIDDLE, retired=True)
         self.next_move = self.glitch = self.next_slashfx = 0.0
         self.slashd = self.hero.R + self.distance/SQRT2
 
@@ -152,6 +155,17 @@ class Maze:
         return (MIDDLE + round2((x-self.centerx) / self.distance),
                 MIDDLE + round2((y-self.centery) / self.distance))
 
+    def get_target(self, x, y):
+        """Return shooting target the grid containing the point (x, y).
+
+        If the grid is the hero, return a retired target.
+        """
+        gridx, gridy = self.get_grid(x, y)
+        if gridx == gridy == MIDDLE: return LockOn(gridx, gridy, True)
+        for enemy in self.enemies:
+            if not enemy.isunnoticeable(gridx, gridy): return enemy
+        return LockOn(gridx, gridy)
+
     def get_score(self):
         """Return the current score."""
         return int(self.score - INIT_SCORE)
@@ -179,7 +193,7 @@ class Maze:
         pygame.display.set_caption(
             'Brutal Maze - Score: {}'.format(self.get_score()))
 
-    def is_displayed(self, x, y):
+    def isdisplayed(self, x, y):
         """Return True if the grid (x, y) is in the displayable part
         of the map, False otherwise.
         """
@@ -212,13 +226,17 @@ class Maze:
         killist = []
         for i, enemy in enumerate(self.enemies):
             enemy.place(x, y)
-            if not self.is_displayed(enemy.x, enemy.y):
+            if not self.isdisplayed(enemy.x, enemy.y):
                 self.score += enemy.wound
                 enemy.die()
                 killist.append(i)
         for i in reversed(killist): self.enemies.pop(i)
         self.add_enemy()
 
+        # LockOn target is not yet updated.
+        if isinstance(self.target, LockOn):
+            self.target.place(x, y, self.isdisplayed)
+
         # Regenerate the maze
         if abs(self.rotatex) == CELL_WIDTH:
             self.rotatex = 0
@@ -290,7 +308,7 @@ class Maze:
             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.isdisplayed(gridx, gridy):
                 fallen.append(i)
             elif bullet.color == 'Aluminium':
                 if self.map[gridx][gridy] == WALL and self.next_move <= 0:
@@ -430,7 +448,11 @@ class Maze:
         self.slashd = self.hero.R + self.distance/SQRT2
 
     def set_step(self, check=(lambda x, y: True)):
-        """Return direction on the shortest path to the destination."""
+        """Work out next step on the shortest path to the destination.
+
+        Return whether target is impossible to reach and hero should
+        shoot toward it instead.
+        """
         if self.stepx or self.stepy and self.vx == self.vy == 0.0:
             x, y = MIDDLE - self.stepx, MIDDLE - self.stepy
             if self.stepx and not self.stepy:
@@ -443,7 +465,12 @@ class Maze:
                 w = self.map[x - 1][y] == EMPTY == self.map[x - 1][nexty]
                 e = self.map[x + 1][y] == EMPTY == self.map[x + 1][nexty]
                 self.stepx = w - e
-            return
+            return False
+
+        # Shoot WALL and ENEMY instead
+        if self.map[self.destx][self.desty] != EMPTY:
+            self.stepx = self.stepy = 0
+            return True
 
         # Forest Fire algorithm with step count
         queue = defaultdict(list, {0: [(self.destx, self.desty)]})
@@ -460,12 +487,15 @@ class Maze:
             dx, dy = MIDDLE - x, MIDDLE - y
             if dx**2 + dy**2 <= 2:
                 self.stepx, self.stepy = dx, dy
-                return
+                return False
             for i, j in around(x, y):
                 if self.map[i][j] == EMPTY and check(i, j):
                     queue[distance + 1].append((i, j))
                     count += 1
-        self.stepx, self.stepy = 0, 0
+
+        # Failed to find way to move to target
+        self.stepx = self.stepy = 0
+        return True
 
     def isfast(self):
         """Return if the hero is moving faster than HERO_SPEED."""
@@ -506,6 +536,7 @@ class Maze:
         self.add_enemy()
 
         self.next_move = self.next_slashfx = self.hero.next_strike = 0.0
+        self.target = LockOn(MIDDLE, MIDDLE, retired=True)
         self.hero.next_heal = -1.0
         self.hero.highness = 0.0
         self.hero.slashing = self.hero.firing = self.hero.dead = False