From 1fcb132eabcaa1a95bf2b527dc18c92c15016d2a Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Fri, 6 Nov 2020 01:34:33 +0100 Subject: [PATCH] Add Hex map capabilities. --- new2/plomrogue/commands.py | 9 +- new2/plomrogue/game.py | 21 +- new2/plomrogue/mapping.py | 32 +++ new2/rogue_chat_curses.py | 76 ++++--- new2/rogue_chat_nocanvas_monochrome.html | 258 +++++++++++++++-------- 5 files changed, 266 insertions(+), 130 deletions(-) diff --git a/new2/plomrogue/commands.py b/new2/plomrogue/commands.py index 3741033..bdf4824 100644 --- a/new2/plomrogue/commands.py +++ b/new2/plomrogue/commands.py @@ -1,6 +1,6 @@ from plomrogue.misc import quote from plomrogue.errors import GameError -from plomrogue.mapping import YX +from plomrogue.mapping import YX, MapGeometrySquare, MapGeometryHex @@ -89,6 +89,7 @@ def cmd_MAP_LINE(game, y, line): game.map.set_line(y, line) cmd_MAP_LINE.argtypes = 'int:nonneg string' -def cmd_MAP(game, size): - game.new_world(size) -cmd_MAP.argtypes = 'yx_tuple:pos' +def cmd_MAP(game, geometry, size): + map_geometry_class = globals()['MapGeometry' + geometry] + game.new_world(map_geometry_class(size)) +cmd_MAP.argtypes = 'string:map_geometry yx_tuple:pos' diff --git a/new2/plomrogue/game.py b/new2/plomrogue/game.py index da14846..0c09b01 100755 --- a/new2/plomrogue/game.py +++ b/new2/plomrogue/game.py @@ -1,8 +1,8 @@ from plomrogue.tasks import (Task_WAIT, Task_MOVE, Task_WRITE, Task_FLATTEN_SURROUNDINGS) from plomrogue.errors import GameError, PlayError -from plomrogue.commands import (cmd_ALL, cmd_LOGIN, cmd_QUERY, cmd_PING, - cmd_TURN, cmd_MAP_LINE, cmd_MAP, cmd_GET_ANNOTATION, +from plomrogue.commands import (cmd_ALL, cmd_LOGIN, cmd_QUERY, cmd_PING, cmd_MAP, + cmd_TURN, cmd_MAP_LINE, cmd_GET_ANNOTATION, cmd_ANNOTATE, cmd_PORTAL, cmd_GET_GAMESTATE) from plomrogue.io import GameIO from plomrogue.misc import quote @@ -75,11 +75,16 @@ class Game(GameBase): import string if string_option_type == 'direction': return self.map_geometry.get_directions() - if string_option_type == 'char': + elif string_option_type == 'char': return [c for c in string.digits + string.ascii_letters + string.punctuation + ' '] + elif string_option_type == 'map_geometry': + return ['Hex', 'Square'] return None + def get_map_geometry_shape(self): + return self.map_geometry.__class__.__name__[len('MapGeometry'):] + def send_gamestate(self, connection_id=None): """Send out game state data relevant to clients.""" @@ -91,7 +96,8 @@ class Game(GameBase): self.io.send('TURN ' + str(self.turn)) for t in self.things: send_thing(t) - self.io.send('MAP %s %s' % (self.map_geometry.size, quote(self.map.terrain))) + self.io.send('MAP %s %s %s' % (self.get_map_geometry_shape(), + self.map_geometry.size, quote(self.map.terrain))) for yx in self.portals: self.io.send('PORTAL %s %s' % (yx, quote(self.portals[yx]))) self.io.send('GAME_STATE_COMPLETE') @@ -179,7 +185,8 @@ class Game(GameBase): with open(self.io.save_file, 'w') as f: write(f, 'TURN %s' % self.turn) - write(f, 'MAP %s' % (self.map_geometry.size,)) + map_geometry_shape = self.get_map_geometry_shape() + write(f, 'MAP %s %s' % (map_geometry_shape, self.map_geometry.size,)) for y, line in self.map.lines(): write(f, 'MAP_LINE %5s %s' % (y, quote(line))) for yx in self.annotations: @@ -187,7 +194,7 @@ class Game(GameBase): for yx in self.portals: write(f, 'PORTAL %s %s' % (yx, quote(self.portals[yx]))) - def new_world(self, size): - self.map_geometry = MapGeometrySquare(YX(size.y, size.x)) + def new_world(self, map_geometry): + self.map_geometry = map_geometry self.map = Map(self.map_geometry.size) self.annotations = {} diff --git a/new2/plomrogue/mapping.py b/new2/plomrogue/mapping.py index f056e10..e0a59d8 100644 --- a/new2/plomrogue/mapping.py +++ b/new2/plomrogue/mapping.py @@ -64,6 +64,38 @@ class MapGeometrySquare(MapGeometryWithLeftRightMoves): +class MapGeometryHex(MapGeometryWithLeftRightMoves): + + def move_UPLEFT(self, start_pos): + start_indented = start_pos.y % 2 + if start_indented: + return YX(start_pos.y - 1, start_pos.x) + else: + return YX(start_pos.y - 1, start_pos.x - 1) + + def move_UPRIGHT(self, start_pos): + start_indented = start_pos.y % 2 + if start_indented: + return YX(start_pos.y - 1, start_pos.x + 1) + else: + return YX(start_pos.y - 1, start_pos.x) + + def move_DOWNLEFT(self, start_pos): + start_indented = start_pos.y % 2 + if start_indented: + return YX(start_pos.y + 1, start_pos.x) + else: + return YX(start_pos.y + 1, start_pos.x - 1) + + def move_DOWNRIGHT(self, start_pos): + start_indented = start_pos.y % 2 + if start_indented: + return YX(start_pos.y + 1, start_pos.x + 1) + else: + return YX(start_pos.y + 1, start_pos.x) + + + class Map(): def __init__(self, map_size): diff --git a/new2/rogue_chat_curses.py b/new2/rogue_chat_curses.py index 6d0f8b7..643023b 100755 --- a/new2/rogue_chat_curses.py +++ b/new2/rogue_chat_curses.py @@ -6,7 +6,7 @@ import threading from plomrogue.io_tcp import PlomSocket from plomrogue.game import GameBase from plomrogue.parser import Parser -from plomrogue.mapping import YX +from plomrogue.mapping import YX, MapGeometrySquare, MapGeometryHex from plomrogue.things import ThingBase from plomrogue.misc import quote @@ -42,10 +42,27 @@ def cmd_THING_NAME(game, thing_id, name): t.name = name cmd_THING_NAME.argtypes = 'int:nonneg string' -def cmd_MAP(game, size, content): - game.map_geometry.size = size +def cmd_MAP(game, geometry, size, content): + map_geometry_class = globals()['MapGeometry' + geometry] + game.map_geometry = map_geometry_class(size) game.map_content = content -cmd_MAP.argtypes = 'yx_tuple:pos string' + if type(game.map_geometry) == MapGeometrySquare: + game.tui.movement_keys = { + 'w': 'UP', + 'a': 'LEFT', + 's': 'DOWN', + 'd': 'RIGHT', + } + elif type(game.map_geometry) == MapGeometryHex: + game.tui.movement_keys = { + 'w': 'UPLEFT', + 'e': 'UPRIGHT', + 'd': 'RIGHT', + 'c': 'DOWNRIGHT', + 'x': 'DOWNLEFT', + 's': 'LEFT', + } +cmd_MAP.argtypes = 'string:map_geometry yx_tuple:pos string' def cmd_GAME_STATE_COMPLETE(game): game.info_db = {} @@ -113,6 +130,11 @@ class Game(GameBase): self.info_db = {} self.portals = {} + def get_string_options(self, string_option_type): + if string_option_type == 'map_geometry': + return ['Hex', 'Square'] + return None + def get_command(self, command_name): from functools import partial f = partial(self.commands[command_name], self) @@ -348,17 +370,25 @@ class TUI: if self.mode.shows_info: map_lines_split[self.explorer.y][self.explorer.x] = '?' map_lines = [] - for line in map_lines_split: - map_lines += [''.join(line)] - map_center = YX(int(self.game.map_geometry.size.y / 2), - int(self.game.map_geometry.size.x / 2)) + if type(self.game.map_geometry) == MapGeometryHex: + indent = 0 + for line in map_lines_split: + map_lines += [indent*' ' + ' '.join(line)] + indent = 0 if indent else 1 + else: + for line in map_lines_split: + map_lines += [''.join(line)] window_center = YX(int(self.size.y / 2), int(self.window_width / 2)) player = self.game.get_thing(self.game.player_id, False) center = player.position if self.mode.shows_info: center = self.explorer + if type(self.game.map_geometry) == MapGeometryHex: + center = YX(center.y, center.x * 2) offset = center - window_center + if type(self.game.map_geometry) == MapGeometryHex and offset.y % 2: + offset += YX(0, 1) term_y = max(0, -offset.y) term_x = max(0, -offset.x) map_y = max(0, offset.y) @@ -467,39 +497,27 @@ class TUI: self.switch_mode('play') self.input_ = '' elif self.mode == self.mode_study: - if key == 'c': + if key == 'C': self.switch_mode('chat') - elif key == 'p': + elif key == 'P': self.switch_mode('play') elif key == 'A': self.switch_mode('annotate', keep_position=True) - elif key == 'P': + elif key == 'p': self.switch_mode('portal', keep_position=True) - elif key == 'w': - move_explorer('UP') - elif key == 'a': - move_explorer('LEFT') - elif key == 's': - move_explorer('DOWN') - elif key == 'd': - move_explorer('RIGHT') + elif key in self.movement_keys: + move_explorer(self.movement_keys[key]) elif self.mode == self.mode_play: - if key == 'c': + if key == 'C': self.switch_mode('chat') elif key == '?': self.switch_mode('study') - if key == 'e': + if key == 'E': self.switch_mode('edit') elif key == 'f': self.send('TASK:FLATTEN_SURROUNDINGS') - elif key == 'w': - self.send('TASK:MOVE UP') - elif key == 'a': - self.send('TASK:MOVE LEFT') - elif key == 's': - self.send('TASK:MOVE DOWN') - elif key == 'd': - self.send('TASK:MOVE RIGHT') + elif key in self.movement_keys: + self.send('TASK:MOVE ' + self.movement_keys[key]) elif self.mode == self.mode_edit: self.send('TASK:WRITE ' + key) self.switch_mode('play') diff --git a/new2/rogue_chat_nocanvas_monochrome.html b/new2/rogue_chat_nocanvas_monochrome.html index f513ad9..bb4c771 100644 --- a/new2/rogue_chat_nocanvas_monochrome.html +++ b/new2/rogue_chat_nocanvas_monochrome.html @@ -4,9 +4,9 @@
-movement: + + rows: cols: @@ -21,7 +21,7 @@ command character: