+from parser import ArgError, Parser
+import game_common
+
+
+class Map(game_common.Map):
+
+ def y_cut(self, map_lines, center_y, view_height):
+ map_height = len(map_lines)
+ if map_height > view_height and center_y > view_height / 2:
+ if center_y > map_height - view_height / 2:
+ map_lines[:] = map_lines[map_height - view_height:]
+ else:
+ start = center_y - int(view_height / 2) - 1
+ map_lines[:] = map_lines[start:start + view_height]
+
+ def x_cut(self, map_lines, center_x, view_width, map_width):
+ if map_width > view_width and center_x > view_width / 2:
+ if center_x > map_width - view_width / 2:
+ cut_start = map_width - view_width
+ cut_end = None
+ else:
+ cut_start = center_x - int(view_width / 2)
+ cut_end = cut_start + view_width
+ map_lines[:] = [line[cut_start:cut_end] for line in map_lines]
+
+
+class MapSquare(Map):
+
+ def format_to_view(self, map_string, center, size):
+
+ def map_string_to_lines(map_string):
+ map_lines = []
+ start_cut = 0
+ while start_cut < len(map_string):
+ limit = start_cut + self.size[1]
+ map_lines += [map_string[start_cut:limit]]
+ start_cut = limit
+ return map_lines
+
+ map_lines = map_string_to_lines(map_string)
+ self.y_cut(map_lines, center[0], size[0])
+ self.x_cut(map_lines, center[1], size[1], self.size[1])
+ return map_lines
+
+
+class MapHex(Map):
+
+ def format_to_view(self, map_string, center, size):
+
+ def map_string_to_lines(map_string):
+ map_view_chars = ['0']
+ x = 0
+ y = 0
+ for c in map_string:
+ map_view_chars += [c, ' ']
+ x += 1
+ if x == self.size[1]:
+ map_view_chars += ['\n']
+ x = 0
+ y += 1
+ if y % 2 == 0:
+ map_view_chars += ['0']
+ if y % 2 == 0:
+ map_view_chars = map_view_chars[:-1]
+ map_view_chars = map_view_chars[:-1]
+ return ''.join(map_view_chars).split('\n')
+
+ map_lines = map_string_to_lines(map_string)
+ self.y_cut(map_lines, center[0], size[0])
+ map_width = self.size[1] * 2 + 1
+ self.x_cut(map_lines, center[1] * 2, size[1], map_width)
+ return map_lines
+
+
+map_manager = game_common.MapManager((MapHex, MapSquare))
+
+
+class World(game_common.World):
+
+ def __init__(self, game, *args, **kwargs):
+ """Extend original with local classes and empty default map.
+
+ We need the empty default map because we draw the map widget
+ on any update, even before we actually receive map data.
+ """
+ super().__init__(*args, **kwargs)
+ self.game = game
+ self.map_ = self.game.map_manager.get_map_class('Hex')()
+ self.player_position = (0, 0)
+
+
+class Game(game_common.CommonCommandsMixin):
+
+ def __init__(self):
+ self.map_manager = map_manager
+ self.parser = Parser(self)
+ self.world = World(self)
+ self.log_text = ''
+ self.to_update = {
+ 'log': True,
+ 'map': True,
+ 'turn': True,
+ }
+ self.do_quit = False
+
+ def get_command_signature(self, command_name):
+ method_candidate = 'cmd_' + command_name
+ method = None
+ argtypes = ''
+ if hasattr(self, method_candidate):
+ method = getattr(self, method_candidate)
+ if hasattr(method, 'argtypes'):
+ argtypes = method.argtypes
+ return method, argtypes
+
+ def get_string_options(self, string_option_type):
+ if string_option_type == 'geometry':
+ return self.map_manager.get_map_geometries()
+ return None
+
+ def handle_input(self, msg):
+ if msg == 'BYE':
+ self.do_quit = True
+ return
+ try:
+ command, args = self.parser.parse(msg)
+ if command is None:
+ self.log('UNHANDLED INPUT: ' + msg)
+ self.to_update['log'] = True
+ else:
+ command(*args)
+ except ArgError as e:
+ self.log('ARGUMENT ERROR: ' + msg + '\n' + str(e))
+ self.to_update['log'] = True
+
+ def log(self, msg):
+ """Prefix msg plus newline to self.log_text."""
+ self.log_text = msg + '\n' + self.log_text
+ self.to_update['log'] = True
+
+ def symbol_for_type(self, type_):
+ symbol = '?'
+ if type_ == 'human':
+ symbol = '@'
+ elif type_ == 'monster':
+ symbol = 'm'
+ return symbol
+
+ def cmd_LAST_PLAYER_TASK_RESULT(self, msg):
+ if msg != "success":
+ self.log(msg)
+ cmd_LAST_PLAYER_TASK_RESULT.argtypes = 'string'
+
+ def cmd_TURN_FINISHED(self, n):
+ """Do nothing. (This may be extended later.)"""
+ pass
+ cmd_TURN_FINISHED.argtypes = 'int:nonneg'
+
+ def cmd_TURN(self, n):
+ """Set self.turn to n, empty self.things."""
+ self.world.turn = n
+ self.world.things = []
+ self.to_update['turn'] = False
+ self.to_update['map'] = False
+ cmd_TURN.argtypes = 'int:nonneg'
+
+ def cmd_VISIBLE_MAP_LINE(self, y, terrain_line):
+ self.world.map_.set_line(y, terrain_line)
+ cmd_VISIBLE_MAP_LINE.argtypes = 'int:nonneg string'
+
+ def cmd_PLAYER_POS(self, yx):
+ self.world.player_position = yx
+ cmd_PLAYER_POS.argtypes = 'yx_tuple:pos'
+
+ def cmd_GAME_STATE_COMPLETE(self):
+ self.to_update['turn'] = True
+ self.to_update['map'] = True
+