main menu screens and UI (a roguelike in Python, #13)

I spent some time getting a main menu and new/load game screens working, and started to get an idea of what I want the UI to do.

rltestui

After the cut is the current demo code. Note that I’ve now moved the key configuration, the level map, and definitions of things to separate files. The key config file looks like this:

k : north
j : south
h : west
l : east

up arrow : north
right arrow : east
left arrow : west
down arrow : south

keypad 8 : north
keypad 6 : east
keypad 4 : west
keypad 2 : south

p : print history

While the things definition file looks like this, in part:


- 'window'
- 35
- 12

---

- 'closed door'
- 30
- 15

---

- 'monster'
- 20
- 9
- 'AI'

And of course the level file is a hardcoded map.

Next I think I’ll have a go at adding get, drop, and throw commands along with player inventory — this should be a good test of the demo’s structure overall. Initially I added in stubs for get and drop with a key definition for each command, but today I thought about it and now I think I’m going to streamline the interface somehow.

#!/usr/bin/python

”’
libtcod OO python tutorial
This code modifies samples_py.py from libtcod 1.4.1. It shows a ‘@’
walking around a scrolling map with a source of light giving simple FOV.
It’s in the public domain.
”’

#############################################
# imports
#############################################

import os
import random
import yaml
import cProfile

import libtcod.libtcodpy as libtcod

PROFILER = cProfile.Profile()
PROFILE = False

SAVING = False

#############################################
# be things
#############################################

class Thing(object):
def __init__(self, name, x=-1, y=-1):
self.name = name
self.speed = ‘normal’
self.x = x
self.y = y

def update(self):
pass

def set_position(self, dx, dy):
self.x = self.x + dx
self.y = self.y + dy

def set_name(self, name):
self.name = name

class World(Thing):
def __init__(self):
self.cell_types = {
‘ ‘ : [‘ground’, ‘ ‘, ‘transparent’, ‘walkable’],
‘#’ : [‘wall’, ‘#’]}

super(World, self).__init__(‘world’)

self.things = []

self.level_width = 80
self.level_height = 49
file = open(‘level.txt’, ‘r’)
self.level = []
for line in file:
line = line.strip(‘ \n’)
self.level.append(line)
file.close()

self.level_make()

def level_make(self):

self.level_state = []
for line in self.level:
line_data = []
for cell in line:
line_data.append(self.cell_types[cell])
self.level_state.append(line_data)

def cells_get(self, thing=None, radius=None):
cells = []

r = 0
if radius:
r = radius

y_start = 0
x_start = 0
y_end = self.level_height
x_end = self.level_width
if thing:
y_start = max(thing.y – r, 0)
x_start = max(thing.x – r, 0)
y_end = min(self.level_height, thing.y + r + 1)
x_end = min(self.level_width, thing.x + r + 1)

for y in range(y_start, y_end):
for x in range(x_start, x_end):
cells.append((x, y))

return cells

def cell_has_monster(self, x, y):
for thing in self.things:
if (thing.x, thing.y) == (x, y) and (thing.name == ‘monster’ or thing.name == ‘player’):
return True

def cell_is_unwalkable(self, x, y):
if not ‘walkable’ in self.level_state[y][x]:
return True

def cell_has_closed_door(self, x, y):
for thing in self.things:
if (thing.x, thing.y) == (x, y) and thing.name == ‘closed door’:
return True

def door_not_closeable(self, x, y):
for thing in self.things:
if (thing.x, thing.y) == (x, y) and thing.name == ‘closed door’:
return True

def cell_type_get(self, x, y):
return self.level_state[y][x][0]

def cell_add_property(self, x, y, property):
self.level_state[y][x] = self.level_state[y][x] + [property]

class Actor(Thing):
def __init__(self, name, x, y, *handlers):
super(Actor, self).__init__(name, x, y)

self.brain = Brain()
self.brain.add_handlers(self, *handlers)

game.world.things.append(self)

def update(self):
self.brain.update()

#############################################
# do things
#############################################

class Brain(object):
def __init__(self):
self.handlers = []

def add_handlers(self, thing, *handlers):
for string in handlers:
handler = eval(string)
self.handlers.append(handler(thing, self))

def remove_handlers(self, *handlers):
for handler in handlers:
self.handlers.remove(handler)

def update(self):
for handler in self.handlers:
handler.update()

class Command(object):
def __init__(self):
self.playbook = {
‘north’ : (‘takes turn’, self.move, 0, -1),
‘east’ : (‘takes turn’, self.move, 1, 0),
‘south’ : (‘takes turn’, self.move, 0, 1),
‘west’ : (‘takes turn’, self.move, -1, 0),
‘ctrl north’ : (‘takes turn’, self.ctrl, 0, -1),
‘ctrl east’ : (‘takes turn’, self.ctrl, 1, 0),
‘ctrl south’ : (‘takes turn’, self.ctrl, 0, 1),
‘ctrl west’ : (‘takes turn’, self.ctrl, -1, 0),
‘get’ : (‘takes turn’, self.get, None),
‘drop’ : (‘takes turn’, self.drop, None),
‘print history’ : (‘free action’, self.print_history, None)}

self.rulebook = {
‘move’ : (‘cell has monster’, ‘cell is unwalkable’, ‘cell has closed door’, ‘open door implicitly’),
‘close_door’ : (‘door not closeable’,),
‘get’ : (),
‘drop’ : ()}

self.rules = {
# condition checks

‘cell has monster’ : ‘game.world.cell_has_monster(enactor.x+dx, enactor.y+dy)’,
‘cell is unwalkable’ : ‘game.world.cell_is_unwalkable(enactor.x+dx, enactor.y+dy)’,
‘cell has closed door’ : ‘game.world.cell_has_closed_door(enactor.x+dx, enactor.y+dy)’,
‘door not closeable’ : ‘game.world.door_not_closeable(enactor.x+dx, enactor.y+dy)’,

# automatic procedures

‘open door implicitly’ : ‘self.open_door_implicitly(enactor.x+dx, enactor.y+dy)’}

self.history = []

def do(self, string, enactor):
command = self.playbook[string]
command_name, args = command[1], command[2:]
command_name(enactor, *args)
self.history.append((string, enactor.name))
return command[0]

def move(self, enactor, *args):
dx, dy = args
if True in [eval(self.rules[rule]) for rule in self.rulebook[‘move’]]:
pass
else:
enactor.set_position(dx, dy)

def ctrl(self, enactor, *args):
dx, dy = args
self.close_door(enactor, dx, dy)

def get(self, enactor, *args):
pass

def drop(self, enactor, *args):
pass

def close_door(self, enactor, dx, dy):
if True in [eval(self.rules[rule]) for rule in self.rulebook[‘close_door’]]:
pass
else:
for thing in game.world.things:
if (enactor.x+dx, enactor.y+dy) == (thing.x, thing.y) and thing.name == ‘open door’:
thing.set_name(‘closed door’)

def open_door_implicitly(self, x, y):
if game.world.cell_has_closed_door(x, y):
for thing in game.world.things:
if (thing.x, thing.y) == (x, y) and thing.name == ‘closed door’:
thing.set_name(‘open door’)

def print_history(self, enactor, *args):
print self.history

class Fov(object):
def __init__(self, thing, brain):
self.thing = thing
self.brain = brain

self.brain.fov_map = None
self.brain.fov_radius = 2
self.brain.fov_map_to_world_coordinates = []

def update(self):
self.brain.fov_map_to_world_coordinates = []
cells = game.world.cells_get(self.thing, self.brain.fov_radius)

cell_first = cells[0]
cell_last = cells[len(cells)-1]

difference_right = cell_last[0] – self.thing.x
difference_bottom = cell_last[1] – self.thing.y
difference_left = self.thing.x – cell_first[0]
difference_top = self.thing.y – cell_first[1]

fov_map_size_x = difference_right + difference_left + 1
fov_map_size_y = difference_bottom + difference_top + 1

self.brain.fov_map = libtcod.map_new(fov_map_size_x, fov_map_size_y)

for i in range(len(cells)):
x, y = cells[i]
fov_map_x = i % fov_map_size_x
fov_map_y = i // fov_map_size_x
cell = game.world.level_state[y][x]
if ‘walkable’ in cell and ‘transparent’ in cell:
libtcod.map_set_properties(self.brain.fov_map, fov_map_x, fov_map_y, True, True)
elif ‘walkable’ in cell:
libtcod.map_set_properties(self.brain.fov_map, fov_map_x, fov_map_y, False, True)
elif ‘transparent’ in cell:
libtcod.map_set_properties(self.brain.fov_map, fov_map_x, fov_map_y, True, False)

for thing in game.world.things:
if thing.name == ‘window’ and (x, y) == (thing.x, thing.y):
libtcod.map_set_properties(self.brain.fov_map, fov_map_x, fov_map_y, True, False)

if thing.name == ‘closed door’ and (x, y) == (thing.x, thing.y):
libtcod.map_set_properties(self.brain.fov_map, fov_map_x, fov_map_y, False, False)

if (x, y) == (self.thing.x, self.thing.y):
fov_x_focus = fov_map_x
fov_y_focus = fov_map_y

self.brain.fov_map_to_world_coordinates.append(((fov_map_x, fov_map_y), (x, y)))

libtcod.map_compute_fov(self.brain.fov_map, fov_x_focus, fov_y_focus, self.brain.fov_radius, True)

if self.thing.name == ‘player’:
for i in range(len(cells)):
x, y = cells[i]
fov_map_x = i % fov_map_size_x
fov_map_y = i // fov_map_size_x
cell = game.world.level_state[y][x]
if (libtcod.map_is_in_fov(self.brain.fov_map, fov_map_x, fov_map_y) and
not ‘discovered’ in game.world.level_state[y][x]):
game.world.cell_add_property(x, y, ‘discovered’)

class AI(object):
def __init__(self, thing, brain):
self.choices = [‘north’, ‘south’, ‘west’, ‘east’]
self.thing = thing

def update(self):
choice = random.randint(0, 3)
command_name = self.choices[choice]
game.command.do(command_name, self.thing)

#############################################
# player
#############################################

class Awesome(object):
def __init__(self):
self.ui = UI()
self.view = View()
self.input = Input()

self.name = ”

game.view = self.view
game.input = self.input

def create(self):
self.thing = Actor(‘player’, 26, 15, ‘Fov’)
self.thing.brain.fov_radius = 5

class UI(object):
def __init__(self):
self.width = 55
self.height = 30

self.state = self.splash_draw

self.dialog = libtcod.console_new(30, 10)

self.top_pane = libtcod.console_new(53, 3)
libtcod.console_set_background_color(self.top_pane, libtcod.light_grey)
libtcod.console_clear(self.top_pane)

self.bottom_pane = libtcod.console_new(53, 3)
libtcod.console_set_background_color(self.bottom_pane, libtcod.light_grey)
libtcod.console_clear(self.bottom_pane)

self.right_pane = libtcod.console_new(21, 20)
libtcod.console_set_background_color(self.right_pane, libtcod.grey)
libtcod.console_clear(self.right_pane)

self.main_menu_options = [‘new game’, ‘load saved game’]
self.main_menu_cursor = 0
self.load_game_selected = ”
self.load_game_cursor = 0
self.save_games = []

self.chars = {
‘player’ : ‘@’,
‘monster’ : ‘?’,
‘ground’ : ‘ ‘,
‘wall’ : ‘#’,
‘window’ : libtcod.CHAR_DHLINE,
‘lamp’ : ‘l’,
‘knife’ : ‘k’,
‘open door’ : ‘-‘,
‘closed door’ : ‘+’}

self.cell_colors = {
‘wall’ : libtcod.Color(67, 65, 52),
‘ground’ : libtcod.Color(145, 140, 140),
‘dark’: libtcod.Color(1, 1, 1),
‘lit’: libtcod.Color(255, 255, 33),
‘visible’: libtcod.Color(254, 254, 233),
‘discovered’: libtcod.Color(50, 50, 100)}

font = os.path.join(‘fonts’, ‘arial12x12.png’)
libtcod.console_set_custom_font(
font,
libtcod.FONT_LAYOUT_TCOD |
libtcod.FONT_TYPE_GREYSCALE,
32,
8)

libtcod.console_init_root(
self.width,
self.height,
‘Python Demo’,
False)
libtcod.console_set_background_color(0, libtcod.dark_grey)
libtcod.mouse_show_cursor(False)
libtcod.console_credits()

def draw(self):
self.state()

def splash_draw(self):
libtcod.console_clear(0)
libtcod.console_set_foreground_color(0, libtcod.white)
libtcod.console_print_center(0, self.width//2, self.height//2-4, libtcod.BKGND_NONE, “A Python Demo”)
libtcod.console_flush()

def main_menu_draw(self):
libtcod.console_clear(0)
libtcod.console_set_foreground_color(0, libtcod.white)
libtcod.console_print_center(0, self.width//2, self.height//2-4, libtcod.BKGND_NONE, “A Python Demo”)

for i in range(len(self.main_menu_options)):
option = self.main_menu_options[i]
if i == self.main_menu_cursor:
cursor = ‘>’
else:
cursor = ‘ ‘
libtcod.console_print_left(0, 20, self.height//2+i, libtcod.BKGND_NONE, “%c%s %s%c” % (libtcod.COLCTRL_1, cursor, option, libtcod.COLCTRL_STOP))

libtcod.console_flush()

def new_game_draw(self):
libtcod.console_clear(0)
libtcod.console_set_background_color(self.dialog, libtcod.grey)
libtcod.console_clear(self.dialog)
libtcod.console_print_left(self.dialog, 2, 5, libtcod.BKGND_NONE, “%cTell me your name, hunter. %c” % (libtcod.COLCTRL_1, libtcod.COLCTRL_STOP))
libtcod.console_print_center(self.dialog, 15, 8, libtcod.BKGND_NONE, “%c%s_%c” % (libtcod.COLCTRL_1, player.name, libtcod.COLCTRL_STOP))

libtcod.console_blit(
self.dialog,
0,
0,
30,
10,
0,
(self.width – 30)/2,
10,
200)
libtcod.console_flush()

def load_game_draw(self):
libtcod.console_clear(0)
libtcod.console_set_background_color(self.dialog, libtcod.grey)
libtcod.console_clear(self.dialog)
libtcod.console_print_center(self.dialog, 15, 1, libtcod.BKGND_NONE, “%cTell me your name, hunter. %c” % (libtcod.COLCTRL_1, libtcod.COLCTRL_STOP))

i = self.load_game_cursor
game = self.save_games[i].split(‘.’)[0].replace(‘_’, ‘ ‘)
libtcod.console_print_center(self.dialog, 15, 4, libtcod.BKGND_NONE, “%c> %s%c” % (libtcod.COLCTRL_1, game, libtcod.COLCTRL_STOP))

libtcod.console_print_center(self.dialog, 15, 8, libtcod.BKGND_NONE, “%cup/down to select%c” % (libtcod.COLCTRL_1, libtcod.COLCTRL_STOP))

libtcod.console_blit(
self.dialog,
0,
0,
30,
10,
0,
(self.width – 30)/2,
10,
200)
libtcod.console_flush()

def gameplay_draw(self):
libtcod.console_clear(0)
libtcod.console_clear(self.right_pane)

libtcod.console_set_foreground_color(0, libtcod.white)
libtcod.console_print_left(self.right_pane, 1, 1, libtcod.BKGND_NONE, “HJKL move around”)
libtcod.console_print_left(self.right_pane, 1, 4, libtcod.BKGND_NONE, “%s” % player.name)
libtcod.console_print_left(self.right_pane, 1, 6, libtcod.BKGND_NONE, “game turn: %d” % game.time.turns)
libtcod.console_print_left(self.right_pane, 1, 8, libtcod.BKGND_NONE, “%s” % game.message.text)

libtcod.console_blit(
player.view.screen,
0,
0,
player.view.width,
player.view.height,
0,
1,
5,
255)

libtcod.console_blit(
self.top_pane,
0,
0,
53,
3,
0,
1,
1,
255)

libtcod.console_blit(
self.bottom_pane,
0,
0,
53,
3,
0,
1,
26,
255)

libtcod.console_blit(
self.right_pane,
0,
0,
21,
20,
0,
33,
5,
255)
libtcod.console_flush()

class View(object):
def __init__(self):
self.width = 30
self.height = 20
self.anchor_x = None
self.anchor_y = None
self.screen = libtcod.console_new(self.width, self.height)
libtcod.console_set_foreground_color(self.screen, libtcod.black)

def update(self):
libtcod.console_clear(self.screen)

self.scroll_update()

viewport = []
for j in range(self.height):
line = []
for i in range(self.width):
x, y = self.viewport_ij_to_world_xy(i, j)
cell = {
‘light’ : 0,
‘char’ : ‘ ‘,
‘fov’ : [],
‘cell_type’ : game.world.cell_type_get(x, y),
‘discovered’ : 0,
‘scalar’ : 1}

if ‘discovered’ in game.world.level_state[y][x]:
cell[‘discovered’] = 1

line.append(cell)
viewport.append(line)

maps = []
for thing in game.world.things:
if not thing.name == ‘player’:
for handler in thing.brain.handlers:
if ‘Fov’ in str(handler):
maps.append((thing, thing.brain.fov_map, thing.brain.fov_map_to_world_coordinates))

maps.append((player.thing, player.thing.brain.fov_map, player.thing.brain.fov_map_to_world_coordinates))

for tuple in maps:
thing, fov_map, fov_map_to_world_coordinates = tuple
for cell in fov_map_to_world_coordinates:
x, y = cell[1][0], cell[1][1]

if self.xy_in_viewport(x, y):
fov_map_x, fov_map_y = cell[0][0], cell[0][1]
i, j = self.world_xy_to_viewport_ij(x, y)

distance_squared = max(1, (x – thing.x) * (x – thing.x) + (y – thing.y) * (y – thing.y))
fov_radius_squared = thing.brain.fov_radius * thing.brain.fov_radius
scalar = (fov_radius_squared – distance_squared * 1.0)/fov_radius_squared

if libtcod.map_is_in_fov(fov_map, fov_map_x, fov_map_y):
viewport[j][i][‘fov’].append(thing.name)

if thing.name == ‘lamp’:
viewport[j][i][‘light’] = max(.5, scalar)

if thing.name == ‘player’:
viewport[j][i][‘scalar’] = max(.5, scalar)

for j in range(self.height):
for i in range(self.width):
cell = viewport[j][i]
affect = ‘dark’
cell_type = cell[‘cell_type’]
if ‘player’ in cell[‘fov’]:
if cell[‘light’] == 0:
affect = ‘visible’
else:
affect = ‘lit’

if cell_type == ‘wall’:
n = max(0, j-1)
e = min(self.width-1, i+1)
s = min(self.height-1, j+1)
w = max(0, i-1)
cells = [
viewport[n][w],
viewport[n][i],
viewport[n][e],
viewport[j][w],
viewport[j][e],
viewport[s][w],
viewport[s][i],
viewport[s][e]]
for adjacent_cell in cells:
if not ‘player’ in adjacent_cell[‘fov’] and adjacent_cell[‘cell_type’] == ‘ground’ and adjacent_cell[‘light’] > 0:
affect = ‘visible’
break
else:
cell[‘scalar’] = cell[‘light’]

elif cell[‘discovered’] > 0:
affect = ‘discovered’

if ‘player’ in cell[‘fov’]:
affect_color = player.ui.cell_colors[affect] * cell[‘scalar’]
else:
affect_color = player.ui.cell_colors[affect]
cell_type_color = player.ui.cell_colors[cell_type]
color = affect_color * cell_type_color
char = cell[‘char’]
libtcod.console_set_back(self.screen, i, j, color, libtcod.BKGND_SET)
libtcod.console_put_char(self.screen, i, j, char, libtcod.BKGND_NONE)

for thing in game.world.things:
i, j = self.world_xy_to_viewport_ij(thing.x, thing.y)
if self.xy_in_viewport(thing.x, thing.y) and ‘player’ in viewport[j][i][‘fov’]:
libtcod.console_put_char(self.screen, i, j, player.ui.chars[thing.name], libtcod.BKGND_NONE)

def scroll_update(self):
self.anchor_x = min(max(0, player.thing.x – self.width//2), game.world.level_width – self.width)
self.anchor_y = min(max(0, player.thing.y – self.height//2), game.world.level_height – self.height)

def world_xy_to_viewport_ij(self, x, y):
i = x – self.anchor_x
j = y – self.anchor_y
return (i, j)

def viewport_ij_to_world_xy(self, i, j):
x = i + self.anchor_x
y = j + self.anchor_y
return (x, y)

def xy_in_viewport(self, x, y):
if (self.anchor_x <= x < self.anchor_x+self.width and self.anchor_y <= y < self.anchor_y+self.height): return True class Input(object): def __init__(self): self.update_state = self.splash_update self._keys = { 'k' : 'k', 'j' : 'j', 'h' : 'h', 'l' : 'l', 'p' : 'p', libtcod.KEY_UP : 'up arrow', libtcod.KEY_RIGHT : 'right arrow', libtcod.KEY_LEFT : 'left arrow', libtcod.KEY_DOWN : 'down arrow', libtcod.KEY_KP8 : 'keypad 8', libtcod.KEY_KP6 : 'keypad 6', libtcod.KEY_KP4 : 'keypad 4', libtcod.KEY_KP2 : 'keypad 2'} file = open('keys.cfg', 'r') self.keycfg = yaml.load(file) self.ctrl = '' def get_key(self, key): if key.lctrl: self.ctrl = 'ctrl ' else: self.ctrl = '' if not key.vk == 65: return key.vk else: return chr(key.c) def update(self): self.update_state() def splash_update(self): libtcod.console_wait_for_keypress(True) def main_menu_update(self): self.key = libtcod.console_wait_for_keypress(True) if self.key.vk == libtcod.KEY_ESCAPE or libtcod.console_is_window_closed(): game.exit = True elif self.key.vk == libtcod.KEY_ENTER: pass elif self.key.vk == libtcod.KEY_DOWN: player.ui.main_menu_cursor = min(len(player.ui.main_menu_options)-1, player.ui.main_menu_cursor+1) elif self.key.vk == libtcod.KEY_UP: player.ui.main_menu_cursor = max(0, player.ui.main_menu_cursor-1) def new_game_update(self): self.key = libtcod.console_wait_for_keypress(True) if self.key.vk == libtcod.KEY_ENTER: pass elif self.key.vk == libtcod.KEY_BACKSPACE: name = player.name player.name = name[:-1] elif self.key.c: player.name = player.name + chr(self.key.c) def load_game_update(self): self.key = libtcod.console_wait_for_keypress(True) if self.key.vk == libtcod.KEY_ENTER or self.key.vk == libtcod.KEY_ESCAPE: pass elif self.key.vk == libtcod.KEY_DOWN: player.ui.load_game_cursor = min(len(player.ui.save_games)-1, player.ui.load_game_cursor+1) elif self.key.vk == libtcod.KEY_UP: player.ui.load_game_cursor = max(0, player.ui.load_game_cursor-1) def gameplay_update(self): self.key = libtcod.console_wait_for_keypress(True) key = self.get_key(self.key) if key in self._keys: key = self._keys[key] while not key in self.keycfg: if self.key.vk == libtcod.KEY_ESCAPE or libtcod.console_is_window_closed(): if SAVING: game.save() game.exit = True return game.message.text = "Try again!" player.ui.draw() self.key = libtcod.console_wait_for_keypress(True) key = self.get_key(self.key) if key in self._keys: key = self._keys[key] command_name = self.ctrl + self.keycfg[key] game.message.text = "Go!" if game.command.do(command_name, player.thing) == 'free action': self.gameplay_update() ############################################# # game ############################################# class Game(object): def __init__(self): self.world = World() self.command = Command() self.message = Message() self.time = Time() self.view = None self.input = None self.update_state = self.splash_update self.exit = False def update(self): self.update_state() def splash_update(self): player.ui.draw() self.input.update() self.update_state = self.main_menu_update player.ui.state = player.ui.main_menu_draw player.input.update_state = player.input.main_menu_update def main_menu_update(self): if not player.ui.save_games: dir = os.listdir('.') for file in dir: if 'sav' in file: player.ui.save_games.append(file) player.ui.draw() self.input.update() if self.input.key.vk == libtcod.KEY_ENTER: if player.ui.main_menu_options[player.ui.main_menu_cursor] == 'new game': self.update_state = self.new_game_update player.ui.state = player.ui.new_game_draw player.input.update_state = player.input.new_game_update elif player.ui.main_menu_options[player.ui.main_menu_cursor] == 'load saved game' and player.ui.save_games: self.update_state = self.load_game_update player.ui.state = player.ui.load_game_draw player.input.update_state = player.input.load_game_update def new_game_update(self): player.ui.draw() self.input.update() if self.input.key.vk == libtcod.KEY_ENTER: if player.ui.main_menu_options[player.ui.main_menu_cursor] == 'new game': file = open('things.txt', 'r') things = yaml.load_all(file) for thing in things: Actor(*thing) player.create() player.thing.brain.update() player.view.update() self.update_state = self.gameplay_update player.ui.state = player.ui.gameplay_draw player.input.update_state = player.input.gameplay_update elif self.input.key.vk == libtcod.KEY_ESCAPE: self.update_state = self.main_menu_update player.ui.state = player.ui.main_menu_draw player.input.update_state = player.input.main_menu_update def load_game_update(self): player.ui.draw() self.input.update() if self.input.key.vk == libtcod.KEY_ENTER: file = player.ui.save_games[player.ui.load_game_cursor] self.load(file) self.view.update() player.name = file.split('.')[0].replace('_', ' ') self.update_state = self.gameplay_update player.ui.state = player.ui.gameplay_draw player.input.update_state = player.input.gameplay_update elif self.input.key.vk == libtcod.KEY_ESCAPE: self.update_state = self.main_menu_update player.ui.state = player.ui.main_menu_draw player.input.update_state = player.input.main_menu_update def gameplay_update(self): if self.time.phase in self.time.phases_for[player.thing.speed]: self.input.update() if game.exit == True: return for thing in game.world.things: if self.time.phase in self.time.phases_for[thing.speed]: thing.update() self.time.tick() if PROFILE: PROFILER.runcall(self.view.update) PROFILER.dump_stats('profile_view_draw') else: self.view.update() def save(self): for thing in game.world.things: thing.brain.fov_map_to_world_coordinates = [] name = player.name.replace(' ', '_') + '.sav' file = open(name, 'w') yaml.dump_all([game.world.things, game.world.level_state], file) file.close() def load(self, name): file = open(name, 'r') game.world.things, game.world.level_state = yaml.load_all(file) for thing in game.world.things: if thing.name == 'player': player.thing = thing thing.brain.update() file.close() class Message(object): def __init__(self): self.text = "Go!" class Time(object): def __init__(self): self.phases = ['fast', 'normal', 'slow', 'quick', 'normal'] self.phases_for = { 'fast' : ('fast', 'normal', 'slow'), 'normal' : ('normal', 'slow'), 'slow' : ('normal'), 'quick' : ('normal', 'slow', 'quick'), 'fast+quick' : ('fast', 'normal', 'slow', 'quick'), 'fast+slow' : ('fast', 'normal'), 'quick+slow' : ('quick', 'normal'), 'fast+quick+slow' : ('fast', 'normal', 'quick')} self.phase = self.phases[1] self.phase_count = 0 self.turns = 0 def tick(self): self.phase_count += 1 self.phase = self.phases[self.phase_count % 5] if self.phase in self.phases_for['normal']: self.turns += 1 ############################################# # get it started & run ############################################# if __name__ == '__main__': # try: # import psyco # psyco.full() # except ImportError: # pass game = Game() player = Awesome() while not game.exit: game.update() player.ui.draw() [/sourcecode]

Advertisements

1 comment so far

  1. Pacian on

    I always find adding menus and stuff to be the most tedious and unrewarding part. Glad you’re getting a handle on it.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: