about summary refs log tree commit diff homepage
path: root/brutalmaze/game.py
diff options
context:
space:
mode:
Diffstat (limited to 'brutalmaze/game.py')
-rw-r--r--brutalmaze/game.py100
1 files changed, 59 insertions, 41 deletions
diff --git a/brutalmaze/game.py b/brutalmaze/game.py
index 189c6bc..ca99a14 100644
--- a/brutalmaze/game.py
+++ b/brutalmaze/game.py
@@ -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.8.21'
+__version__ = '0.8.22'
 
 import re
 from argparse import ArgumentParser, FileType, RawTextHelpFormatter
@@ -32,7 +32,7 @@ from sys import stdout
 from threading import Thread
 
 import pygame
-from pygame import KEYDOWN, QUIT, VIDEORESIZE
+from pygame import KEYDOWN, MOUSEBUTTONUP, QUIT, VIDEORESIZE
 from pygame.time import Clock, get_ticks
 from appdirs import AppDirs
 
@@ -49,7 +49,6 @@ class ConfigReader:
                        ('Toggle mute', 'mute'),
                        ('Move left', 'left'), ('Move right', 'right'),
                        ('Move up', 'up'), ('Move down', 'down'),
-                       ('Auto move', 'autove'),
                        ('Long-range attack', 'shot'),
                        ('Close-range attack', 'slash'))
     WEIRD_MOUSE_ERR = '{}: Mouse is not a suitable control'
@@ -71,6 +70,7 @@ class ConfigReader:
         self.muted = self.config.getboolean('Sound', 'Muted')
         self.musicvol = self.config.getfloat('Sound', 'Music volume')
         self.space = self.config.getboolean('Sound', 'Space theme')
+        self.touch = self.config.getboolean('Control', 'Touch')
         self.export_dir = self.config.get('Record', 'Directory')
         self.export_rate = self.config.getint('Record', 'Frequency')
         self.server = self.config.getboolean('Server', 'Enable')
@@ -84,7 +84,7 @@ class ConfigReader:
         for cmd, alias in self.CONTROL_ALIASES:
             i = self.config.get('Control', cmd)
             if re.match('mouse[1-3]$', i.lower()):
-                if alias not in ('autove', 'shot', 'slash'):
+                if alias not in ('shot', 'slash'):
                     raise ValueError(self.WEIRD_MOUSE_ERR.format(cmd))
                 self.mouse[alias] = int(i[-1]) - 1
                 continue
@@ -98,9 +98,9 @@ class ConfigReader:
 
     def read_args(self, arguments):
         """Read and parse a ArgumentParser.Namespace."""
-        for option in (
-            'size', 'max_fps', 'muted', 'musicvol', 'space', 'export_dir',
-            'export_rate', 'server', 'host', 'port', 'timeout', 'headless'):
+        for option in ('size', 'max_fps', 'muted', 'musicvol', 'space',
+                       'touch', 'export_dir', 'export_rate', 'server',
+                       'host', 'port', 'timeout', 'headless'):
             value = getattr(arguments, option)
             if value is not None: setattr(self, option, value)
 
@@ -134,6 +134,7 @@ class Game:
         # self.fps is a float to make sure floordiv won't be used in Python 2
         self.max_fps, self.fps = config.max_fps, float(config.max_fps)
         self.musicvol = config.musicvol
+        self.touch = config.touch
         self.key, self.mouse = config.key, config.mouse
         self.maze = Maze(config.max_fps, config.size, config.headless,
                          config.export_dir, 1000.0 / config.export_rate)
@@ -175,6 +176,19 @@ class Game:
                         self.maze.reinit()
                     elif event.key == self.key['pause'] and not self.hero.dead:
                         self.paused ^= True
+            elif event.type == MOUSEBUTTONUP and self.touch:
+                # We're careless about which mouse button is clicked.
+                maze = self.maze
+                if self.hero.dead:
+                    maze.reinit()
+                else:
+                    x, y = pygame.mouse.get_pos()
+                    maze.destx, maze.desty = maze.get_grid(x, y)
+                    if maze.set_step(maze.isdisplayed):
+                        maze.target = maze.get_target(x, y)
+                        self.hero.firing = not maze.target.retired
+                    if maze.stepx == maze.stepy == 0:
+                        maze.destx = maze.desty = MIDDLE
 
         # Compare current FPS with the average of the last 10 frames
         new_fps = self.clock.get_fps()
@@ -187,7 +201,7 @@ class Game:
         self.clock.tick(self.fps)
         return True
 
-    def move(self, x, y):
+    def move(self, x=0, y=0):
         """Command the hero to move faster in the given direction."""
         maze = self.maze
         velocity = maze.distance * HERO_SPEED / self.fps
@@ -265,41 +279,37 @@ class Game:
             connection.close()
             if not self.hero.dead: self.maze.lose()
 
+    def touch_control(self):
+        """Handle touch control."""
+        maze, hero = self.maze, self.hero
+        if maze.target.retired: hero.firing = False
+        if hero.firing:
+            x, y = maze.get_pos(maze.target.x, maze.target.y)
+        else:
+            x, y = pygame.mouse.get_pos()
+        hero.update_angle(atan2(y - hero.y, x - hero.x))
+        self.move()
+
     def user_control(self):
         """Handle direct control from user's mouse and keyboard."""
-        if not self.hero.dead:
-            keys = pygame.key.get_pressed()
-            right = keys[self.key['right']] - keys[self.key['left']]
-            down = keys[self.key['down']] - keys[self.key['up']]
-
-            buttons = pygame.mouse.get_pressed()
-            try:
-                autove = keys[self.key['autove']]
-            except KeyError:
-                autove = buttons[self.mouse['autove']]
-            try:
-                firing = keys[self.key['shot']]
-            except KeyError:
-                firing = buttons[self.mouse['shot']]
-            try:
-                slashing = keys[self.key['slash']]
-            except KeyError:
-                slashing = buttons[self.mouse['slash']]
-
-            # Follow the mouse cursor
-            x, y = pygame.mouse.get_pos()
-            maze = self.maze
-            if right or down:
-                maze.destx = maze.desty = MIDDLE
-                maze.stepx = maze.stepy = 0
-            elif autove:
-                maze.destx, maze.desty = maze.get_grid(x, y)
-                maze.set_step(maze.is_displayed)
-                if maze.stepx == maze.stepy == 0:
-                    maze.destx = maze.desty = MIDDLE
-
-            angle = atan2(y - self.hero.y, x - self.hero.x)
-            self.control(right, down, angle, firing, slashing)
+        if self.hero.dead: return
+        keys = pygame.key.get_pressed()
+        buttons = pygame.mouse.get_pressed()
+
+        right = keys[self.key['right']] - keys[self.key['left']]
+        down = keys[self.key['down']] - keys[self.key['up']]
+        x, y = pygame.mouse.get_pos()
+        angle = atan2(y - self.hero.y, x - self.hero.x)
+
+        try:
+            firing = keys[self.key['shot']]
+        except KeyError:
+            firing = buttons[self.mouse['shot']]
+        try:
+            slashing = keys[self.key['slash']]
+        except KeyError:
+            slashing = buttons[self.mouse['slash']]
+        self.control(right, down, angle, firing, slashing)
 
     def __exit__(self, exc_type, exc_value, traceback):
         if self.server is not None: self.server.close()
@@ -350,6 +360,12 @@ def main():
     parser.add_argument('--default-music', action='store_false', dest='space',
                         help='use default music background')
     parser.add_argument(
+        '--touch', action='store_true', default=None,
+        help='enable touch-friendly control (fallback: {})'.format(
+            config.touch))
+    parser.add_argument('--no-touch', action='store_false', dest='touch',
+                        help='disable touch-friendly control')
+    parser.add_argument(
         '--record-dir', metavar='DIR', dest='export_dir',
         help='directory to write game records (fallback: {})'.format(
             config.export_dir or '*disabled*'))
@@ -397,5 +413,7 @@ def main():
             socket_thread.daemon = True     # make it disposable
             socket_thread.start()
             while game.update(): game.control(*game.sockinp)
+        elif config.touch:
+            while game.update(): game.touch_control()
         else:
             while game.update(): game.user_control()