#!/usr/bin/env python # -*- coding: utf-8 -*- import copy import logging logging.basicConfig( format='%(levelname)s: %(message)s', level=logging.DEBUG ) import urwid import sys try: map_filename = sys.argv[1] logging.info(u'Filename argument “%s” given.' % map_filename) except IndexError: logging.critical('No filename argument given.') exit(1) try: with open(map_filename, 'r') as map_file: map_text = map_file.read().decode('utf-8') except IOError: logging.critical('Could not open file “%s”.' % map_filename) exit(1) class UT_Entity: def __init__(self, character): self.character = character def render(self): return self.character class UT_Critter(UT_Entity): def __init__(self, character): self.character = character self.playable = False player_character = u'☻' if self.character == player_character: self.playable = True self.health = 100 self.shield = 0 self.weapon = None class UT_Item(UT_Entity): pass CRITTER_TILES = (u'☻', u'☺', u'⚑', u'⚐') DEADLY_TILES = (u' ') ITEM_TILES = (u'✚', u'☣', u'☢') TRAVERSABLE_TILES = (u'.', u'%', u'✚', u'☣', u'☢', u'⛨') TELEPORT_TILES = {u'●': u'○', u'○': u'●'} class UT_Tile: def __init__(self, character): self.terrain = character self.critter = None if character in CRITTER_TILES: self.critter = UT_Critter(character) self.terrain = u'.' self.item = None if character in ITEM_TILES: self.item = UT_Item(character) self.terrain = u'.' self.deadly = False if character in DEADLY_TILES: self.deadly = True self.traversable = False if self.terrain in TRAVERSABLE_TILES: self.traversable = True self.teleports = False if character in TELEPORT_TILES.keys(): self.teleports = True self.teleport_target = TELEPORT_TILES[character] def render(self): if self.critter != None: return self.critter.render() if self.item != None: return self.item.render() return self.terrain class UT_Map: def __init__(self, text=''): self.tiles = self.parse(text) def __getitem__(self, index): return self.tiles[index] def parse(self, text): tiles = [] for x, line in enumerate(text.split('\n')): tiles.append([]) for y, character in enumerate(line): tile = UT_Tile(character) tiles[x].append(tile) return tiles def render(self): map_buffer = u'' x_max = len(self.tiles) for x in range(x_max): line = self.tiles[x] y_max = len(line) for y in range(y_max): try: tile = self.tiles[x][y] except IndexError: tile = ' ' map_buffer += tile.render() map_buffer += '\n' return map_buffer def find_critter(self, character): x_max = len(self.tiles) for x in range(x_max): line = self.tiles[x] y_max = len(line) for y in range (y_max): try: tile = self.tiles[x][y] except IndexError: tile = UT_Tile(' ') if tile.critter != None: if tile.critter.character == character: return (x, y) def find_terrain(self, character): x_max = len(self.tiles) for x in range(x_max): line = self.tiles[x] y_max = len(line) for y in range(y_max): try: tile = self.tiles[x][y] except IndexError: tile = UT_Tile(' ') if tile.terrain == character: return (x, y) class UT_Game: def __init__(self, text=''): self.map = UT_Map(text) def render(self): return self.map.render() def render_hud(self): return def teleport_critter(self, current_coords, target_coords): x_c, y_c = current_coords[0], current_coords[1] x_t, y_t = target_coords[0], target_coords[1] self.map[x_t][y_t].critter = self.map[x_c][y_c].critter self.map[x_c][y_c].critter = None def move_critter(self, current_coords, direction): assert direction in (u'←', u'↑', u'→', u'↓') x_c, y_c = current_coords[0], current_coords[1] if direction == u'←': x_t, y_t = current_coords[0], current_coords[1]-1 if direction == u'↑': x_t, y_t = current_coords[0]-1, current_coords[1] if direction == u'→': x_t, y_t = current_coords[0], current_coords[1]+1 if direction == u'↓': x_t, y_t = current_coords[0]+1, current_coords[1] current_coords = (x_c, y_c) current_tile = self.map[x_c][y_c] try: target_tile = self.map[x_t][y_t] except IndexError: current_tile.critter = None return target_coords = (x_t, y_t) if target_tile.traversable and target_tile.critter == None: self.teleport_critter(current_coords, target_coords) elif target_tile.traversable and target_tile.critter: self.move_critter(target_coords, direction) if target_tile.teleports: teleport_target = target_tile.teleport_target target_coords = self.map.find_terrain(teleport_target) self.teleport_critter(current_coords, target_coords) if target_tile.deadly: current_tile.critter = None def move_player(self, direction): player_character = u'☻' player_coords = self.map.find_critter(player_character) self.move_critter(player_coords, direction) palette = [ ('header', 'yellow', '') ] divider = urwid.Divider() divider_map = urwid.AttrMap(divider, 'header') title = urwid.Text(('header', u'u⃝ Unicode Tournament'), align='center') title_map = urwid.AttrMap(title, 'header') header = urwid.Pile([divider_map, title_map, divider_map]) game = UT_Game(map_text) map_text = urwid.Text(game.render()) fill = urwid.Filler(map_text, 'middle') body = urwid.LineBox(fill) health_symbol = urwid.Text(u'✚') health_value = urwid.Text(u'') shield_symbol = urwid.Text(u'⛨') shield_value = urwid.Text(u'') debug = urwid.Text(u'[debug]') hud = urwid.Columns([('pack', health_symbol), (5, health_value), ('pack', shield_symbol), (5, shield_value), debug], dividechars=1) footer = urwid.LineBox(hud) rounds = 0 def handle_input(key): if key == 'left': game.move_player(u'←') if key == 'up': game.move_player(u'↑') if key == 'right': game.move_player(u'→') if key == 'down': game.move_player(u'↓') if key == 'q': raise urwid.ExitMainLoop() map_text.set_text(game.map.render()) debug.set_text(repr(key)) frame = urwid.Frame(body=body, header=header, footer=footer, \ focus_part='body') loop = urwid.MainLoop(frame, palette, unhandled_input=handle_input) loop.run()