X-Git-Url: https://plomlompom.com/repos/feed.xml?a=blobdiff_plain;f=rogue_chat_curses.py;h=70d60b27f1c6ee8abfccf31f6b3d0a0f73d54d2e;hb=a81ea397900267331c15c1cda5d349b22a49ea16;hp=eb708a249a3ddc6c4392e2349fa81d0587de7d43;hpb=b72c8aea9efa8005534e6cef7e8f8fae5cf0918e;p=plomrogue2 diff --git a/rogue_chat_curses.py b/rogue_chat_curses.py index eb708a2..70d60b2 100755 --- a/rogue_chat_curses.py +++ b/rogue_chat_curses.py @@ -27,6 +27,10 @@ mode_helps = { 'short': 'name thing', 'long': 'Give name to/change name of thing here.' }, + 'command_thing': { + 'short': 'command thing', + 'long': 'Enter a command to the thing you carry. Enter nothing to return to play mode.' + }, 'admin_thing_protect': { 'short': 'change thing protection', 'long': 'Change protection character for thing here.' @@ -130,12 +134,12 @@ class PlomSocketClient(PlomSocket): pass # we assume socket will be known as dead by now def cmd_TURN(game, n): - game.info_db = {} - game.info_hints = [] + game.annotations = {} game.turn = n game.things = [] game.portals = {} game.turn_complete = False + game.fov = '' cmd_TURN.argtypes = 'int:nonneg' def cmd_LOGIN_OK(game): @@ -151,6 +155,11 @@ def cmd_ADMIN_OK(game): game.tui.do_refresh = True cmd_ADMIN_OK.argtypes = '' +def cmd_REPLY(game, msg): + game.tui.log_msg('#MUSICPLAYER: ' + msg) + game.tui.do_refresh = True +cmd_REPLY.argtypes = 'string' + def cmd_CHAT(game, msg): game.tui.log_msg('# ' + msg) game.tui.do_refresh = True @@ -179,7 +188,7 @@ cmd_THING_NAME.argtypes = 'int:nonneg string' def cmd_THING_CHAR(game, thing_id, c): t = game.get_thing(thing_id) if t: - t.player_char = c + t.thing_char = c cmd_THING_CHAR.argtypes = 'int:nonneg char' def cmd_MAP(game, geometry, size, content): @@ -215,10 +224,9 @@ cmd_MAP_CONTROL.argtypes = 'string' def cmd_GAME_STATE_COMPLETE(game): if game.tui.mode.name == 'post_login_wait': game.tui.switch_mode('play') - if game.tui.mode.shows_info: - game.tui.query_info() game.turn_complete = True game.tui.do_refresh = True + game.tui.info_cached = None cmd_GAME_STATE_COMPLETE.argtypes = '' def cmd_PORTAL(game, position, msg): @@ -241,12 +249,8 @@ def cmd_ARGUMENT_ERROR(game, msg): game.tui.do_refresh = True cmd_ARGUMENT_ERROR.argtypes = 'string' -def cmd_ANNOTATION_HINT(game, position): - game.info_hints += [position] -cmd_ANNOTATION_HINT.argtypes = 'yx_tuple:nonneg' - def cmd_ANNOTATION(game, position, msg): - game.info_db[position] = msg + game.annotations[position] = msg if game.tui.mode.shows_info: game.tui.do_refresh = True cmd_ANNOTATION.argtypes = 'yx_tuple:nonneg string' @@ -254,6 +258,7 @@ cmd_ANNOTATION.argtypes = 'yx_tuple:nonneg string' def cmd_TASKS(game, tasks_comma_separated): game.tasks = tasks_comma_separated.split(',') game.tui.mode_write.legal = 'WRITE' in game.tasks + game.tui.mode_command_thing.legal = 'COMMAND' in game.tasks cmd_TASKS.argtypes = 'string' def cmd_THING_TYPE(game, thing_type, symbol_hint): @@ -268,6 +273,14 @@ def cmd_PONG(game): pass cmd_PONG.argtypes = '' +def cmd_DEFAULT_COLORS(game): + game.tui.set_default_colors() +cmd_DEFAULT_COLORS.argtypes = '' + +def cmd_RANDOM_COLORS(game): + game.tui.set_random_colors() +cmd_RANDOM_COLORS.argtypes = '' + class Game(GameBase): turn_complete = False tasks = {} @@ -279,6 +292,7 @@ class Game(GameBase): self.register_command(cmd_ADMIN_OK) self.register_command(cmd_PONG) self.register_command(cmd_CHAT) + self.register_command(cmd_REPLY) self.register_command(cmd_PLAYER_ID) self.register_command(cmd_TURN) self.register_command(cmd_THING) @@ -290,17 +304,17 @@ class Game(GameBase): self.register_command(cmd_MAP_CONTROL) self.register_command(cmd_PORTAL) self.register_command(cmd_ANNOTATION) - self.register_command(cmd_ANNOTATION_HINT) self.register_command(cmd_GAME_STATE_COMPLETE) self.register_command(cmd_ARGUMENT_ERROR) self.register_command(cmd_GAME_ERROR) self.register_command(cmd_PLAY_ERROR) self.register_command(cmd_TASKS) self.register_command(cmd_FOV) + self.register_command(cmd_DEFAULT_COLORS) + self.register_command(cmd_RANDOM_COLORS) self.map_content = '' self.player_id = -1 - self.info_db = {} - self.info_hints = [] + self.annotations = {} self.portals = {} self.terrains = {} @@ -375,15 +389,17 @@ class TUI: mode_post_login_wait = Mode('post_login_wait', is_intro=True) mode_password = Mode('password', has_input_prompt=True) mode_name_thing = Mode('name_thing', has_input_prompt=True, shows_info=True) + mode_command_thing = Mode('command_thing', has_input_prompt=True) is_admin = False tile_draw = False def __init__(self, host): import os import json - self.mode_play.available_modes = ["chat", "study", "edit", "admin_enter"] + self.mode_play.available_modes = ["chat", "study", "edit", "admin_enter", + "command_thing"] self.mode_play.available_actions = ["move", "take_thing", "drop_thing", - "teleport", "door"] + "teleport", "door", "consume"] self.mode_study.available_modes = ["chat", "play", "admin_enter", "edit"] self.mode_study.available_actions = ["toggle_map_mode", "move_explorer"] self.mode_admin.available_modes = ["admin_thing_protect", "control_pw_type", @@ -419,6 +435,7 @@ class TUI: 'switch_to_edit': 'E', 'switch_to_write': 'm', 'switch_to_name_thing': 'N', + 'switch_to_command_thing': 'O', 'switch_to_admin_enter': 'A', 'switch_to_control_pw_type': 'C', 'switch_to_control_tile_type': 'Q', @@ -427,6 +444,7 @@ class TUI: 'take_thing': 'z', 'drop_thing': 'u', 'teleport': 'p', + 'consume': 'C', 'door': 'D', 'help': 'h', 'toggle_map_mode': 'L', @@ -453,6 +471,8 @@ class TUI: self.input_lines = [] self.fov = '' self.flash = False + self.map_lines = [] + self.offset = YX(0,0) curses.wrapper(self.loop) def connect(self): @@ -509,14 +529,9 @@ class TUI: if len(self.log) > 100: self.log = self.log[-100:] - def query_info(self): - self.send('GET_ANNOTATION ' + str(self.explorer)) - def restore_input_values(self): - if self.mode.name == 'annotate' and self.explorer in self.game.info_db: - info = self.game.info_db[self.explorer] - if info != '(none)': - self.input_ = info + if self.mode.name == 'annotate' and self.explorer in self.game.annotations: + self.input_ = self.game.annotations[self.explorer] elif self.mode.name == 'portal' and self.explorer in self.game.portals: self.input_ = self.game.portals[self.explorer] elif self.mode.name == 'password': @@ -570,8 +585,6 @@ class TUI: if self.mode.shows_info or self.mode.name == 'control_tile_draw': player = self.game.get_thing(self.game.player_id) self.explorer = YX(player.position.y, player.position.x) - if self.mode.shows_info: - self.query_info() if self.mode.is_single_char_entry: self.show_help = True if self.mode.name == 'waiting_for_server': @@ -581,6 +594,8 @@ class TUI: self.send('LOGIN ' + quote(self.login_name)) else: self.log_msg('@ enter username') + elif self.mode.name == 'command_thing': + self.send('TASK:COMMAND ' + quote('HELP')) elif self.mode.name == 'admin_enter': self.log_msg('@ enter admin password:') elif self.mode.name == 'control_pw_type': @@ -596,19 +611,75 @@ class TUI: self.input_ = "" self.restore_input_values() + def set_default_colors(self): + curses.init_color(1, 1000, 1000, 1000) + curses.init_color(2, 0, 0, 0) + self.do_refresh = True + + def set_random_colors(self): + + def rand(offset): + import random + return int(offset + random.random()*375) + + curses.init_color(1, rand(625), rand(625), rand(625)) + curses.init_color(2, rand(0), rand(0), rand(0)) + self.do_refresh = True + + def get_info(self): + if self.info_cached: + return self.info_cached + pos_i = self.explorer.y * self.game.map_geometry.size.x + self.explorer.x + info_to_cache = '' + if len(self.game.fov) > pos_i and self.game.fov[pos_i] != '.': + info_to_cache += 'outside field of view' + else: + terrain_char = self.game.map_content[pos_i] + terrain_desc = '?' + if terrain_char in self.game.terrains: + terrain_desc = self.game.terrains[terrain_char] + info_to_cache += 'TERRAIN: "%s" / %s\n' % (terrain_char, + terrain_desc) + protection = self.game.map_control_content[pos_i] + if protection == '.': + protection = 'unprotected' + info_to_cache += 'PROTECTION: %s\n' % protection + for t in self.game.things: + if t.position == self.explorer: + protection = t.protection + if protection == '.': + protection = 'none' + info_to_cache += 'THING: %s / %s' %\ + (t.type_, self.game.thing_types[t.type_]) + if hasattr(t, 'thing_char'): + info_to_cache += t.thing_char + if hasattr(t, 'name'): + info_to_cache += ' (%s)' % t.name + info_to_cache += ' / protection: %s\n' % protection + if self.explorer in self.game.portals: + info_to_cache += 'PORTAL: ' +\ + self.game.portals[self.explorer] + '\n' + else: + info_to_cache += 'PORTAL: (none)\n' + if self.explorer in self.game.annotations: + info_to_cache += 'ANNOTATION: ' +\ + self.game.annotations[self.explorer] + self.info_cached = info_to_cache + return self.info_cached + def loop(self, stdscr): import datetime def safe_addstr(y, x, line): if y < self.size.y - 1 or x + len(line) < self.size.x: - stdscr.addstr(y, x, line) + stdscr.addstr(y, x, line, curses.color_pair(1)) else: # workaround to cut_i = self.size.x - x - 1 cut = line[:cut_i] last_char = line[cut_i] - stdscr.addstr(y, self.size.x - 2, last_char) + stdscr.addstr(y, self.size.x - 2, last_char, curses.color_pair(1)) stdscr.insstr(y, self.size.x - 2, ' ') - stdscr.addstr(y, x, cut) + stdscr.addstr(y, x, cut, curses.color_pair(1)) def handle_input(msg): command, args = self.parser.parse(msg) @@ -650,9 +721,8 @@ class TUI: def move_explorer(direction): target = self.game.map_geometry.move_yx(self.explorer, direction) if target: + self.info_cached = None self.explorer = target - if self.mode.shows_info: - self.query_info() if self.tile_draw: self.send_tile_control_command() else: @@ -671,42 +741,7 @@ class TUI: safe_addstr(max_y - i - 1, self.window_width, lines[i]) def draw_info(): - if not self.game.turn_complete: - return - pos_i = self.explorer.y * self.game.map_geometry.size.x + self.explorer.x - info = 'MAP VIEW: %s\n' % self.map_mode - if self.game.fov[pos_i] != '.': - info += 'outside field of view' - else: - terrain_char = self.game.map_content[pos_i] - terrain_desc = '?' - if terrain_char in self.game.terrains: - terrain_desc = self.game.terrains[terrain_char] - info += 'TERRAIN: "%s" / %s\n' % (terrain_char, terrain_desc) - protection = self.game.map_control_content[pos_i] - if protection == '.': - protection = 'unprotected' - info += 'PROTECTION: %s\n' % protection - for t in self.game.things: - if t.position == self.explorer: - protection = t.protection - if protection == '.': - protection = 'none' - info += 'THING: %s / %s' % (t.type_, - self.game.thing_types[t.type_]) - if hasattr(t, 'player_char'): - info += t.player_char - if hasattr(t, 'name'): - info += ' (%s)' % t.name - info += ' / protection: %s\n' % protection - if self.explorer in self.game.portals: - info += 'PORTAL: ' + self.game.portals[self.explorer] + '\n' - else: - info += 'PORTAL: (none)\n' - if self.explorer in self.game.info_db: - info += 'ANNOTATION: ' + self.game.info_db[self.explorer] - else: - info += 'ANNOTATION: waiting …' + info = 'MAP VIEW: %s\n%s' % (self.map_mode, self.get_info()) lines = msg_into_lines_of_width(info, self.window_width) height_header = 2 for i in range(len(lines)): @@ -734,64 +769,65 @@ class TUI: 'MODE: %s – %s' % (self.mode.short_desc, help)) def draw_map(): - if not self.game.turn_complete: + if not self.game.turn_complete and len(self.map_lines) == 0: return - map_lines_split = [] - for y in range(self.game.map_geometry.size.y): - start = self.game.map_geometry.size.x * y - end = start + self.game.map_geometry.size.x - if self.map_mode == 'protections': - map_lines_split += [[c + ' ' for c - in self.game.map_control_content[start:end]]] + if self.game.turn_complete: + map_lines_split = [] + for y in range(self.game.map_geometry.size.y): + start = self.game.map_geometry.size.x * y + end = start + self.game.map_geometry.size.x + if self.map_mode == 'protections': + map_lines_split += [[c + ' ' for c + in self.game.map_control_content[start:end]]] + else: + map_lines_split += [[c + ' ' for c + in self.game.map_content[start:end]]] + if self.map_mode == 'terrain + annotations': + for p in self.game.annotations: + map_lines_split[p.y][p.x] = 'A ' + elif self.map_mode == 'terrain + things': + for p in self.game.portals.keys(): + original = map_lines_split[p.y][p.x] + map_lines_split[p.y][p.x] = original[0] + 'P' + used_positions = [] + for t in self.game.things: + symbol = self.game.thing_types[t.type_] + meta_char = ' ' + if hasattr(t, 'thing_char'): + meta_char = t.thing_char + if t.position in used_positions: + meta_char = '+' + map_lines_split[t.position.y][t.position.x] = symbol + meta_char + used_positions += [t.position] + player = self.game.get_thing(self.game.player_id) + if self.mode.shows_info or self.mode.name == 'control_tile_draw': + map_lines_split[self.explorer.y][self.explorer.x] = '??' + elif self.map_mode != 'terrain + things': + map_lines_split[player.position.y][player.position.x] = '??' + self.map_lines = [] + if type(self.game.map_geometry) == MapGeometryHex: + indent = 0 + for line in map_lines_split: + self.map_lines += [indent * ' ' + ''.join(line)] + indent = 0 if indent else 1 else: - map_lines_split += [[c + ' ' for c - in self.game.map_content[start:end]]] - if self.map_mode == 'terrain + annotations': - for p in self.game.info_hints: - map_lines_split[p.y][p.x] = 'A ' - elif self.map_mode == 'terrain + things': - for p in self.game.portals.keys(): - original = map_lines_split[p.y][p.x] - map_lines_split[p.y][p.x] = original[0] + 'P' - used_positions = [] - for t in self.game.things: - symbol = self.game.thing_types[t.type_] - meta_char = ' ' - if hasattr(t, 'player_char'): - meta_char = t.player_char - if t.position in used_positions: - meta_char = '+' - map_lines_split[t.position.y][t.position.x] = symbol + meta_char - used_positions += [t.position] - player = self.game.get_thing(self.game.player_id) - if self.mode.shows_info or self.mode.name == 'control_tile_draw': - map_lines_split[self.explorer.y][self.explorer.x] = '??' - elif self.map_mode != 'terrain + things': - map_lines_split[player.position.y][player.position.x] = '??' - map_lines = [] - 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)) - center = player.position - if self.mode.shows_info or self.mode.name == 'control_tile_draw': - center = self.explorer - 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) - map_x = max(0, offset.x) + for line in map_lines_split: + self.map_lines += [''.join(line)] + window_center = YX(int(self.size.y / 2), + int(self.window_width / 2)) + center = player.position + if self.mode.shows_info or self.mode.name == 'control_tile_draw': + center = self.explorer + center = YX(center.y, center.x * 2) + self.offset = center - window_center + if type(self.game.map_geometry) == MapGeometryHex and self.offset.y % 2: + self.offset += YX(0, 1) + term_y = max(0, -self.offset.y) + term_x = max(0, -self.offset.x) + map_y = max(0, self.offset.y) + map_x = max(0, self.offset.x) while (term_y < self.size.y and map_y < self.game.map_geometry.size.y): - to_draw = map_lines[map_y][map_x:self.window_width + offset.x] + to_draw = self.map_lines[map_y][map_x:self.window_width + self.offset.x] safe_addstr(term_y, term_x, to_draw) term_y += 1 map_y += 1 @@ -836,6 +872,7 @@ class TUI: def draw_screen(): stdscr.clear() + stdscr.bkgd(' ', curses.color_pair(1)) recalc_input_lines() if self.mode.has_input_prompt: draw_input() @@ -859,6 +896,7 @@ class TUI: 'toggle_map_mode': 'toggle map view', 'toggle_tile_draw': 'toggle protection character drawing', 'door': 'open/close', + 'consume': 'consume', } action_tasks = { @@ -867,10 +905,14 @@ class TUI: 'drop_thing': 'DROP', 'door': 'DOOR', 'move': 'MOVE', + 'command': 'COMMAND', + 'consume': 'INTOXICATE', } curses.curs_set(False) # hide cursor - curses.use_default_colors() + curses.start_color() + self.set_default_colors() + curses.init_pair(1, 1, 2) stdscr.timeout(10) reset_screen_size() self.explorer = YX(0, 0) @@ -926,6 +968,13 @@ class TUI: self.login_name = self.input_ self.send('LOGIN ' + quote(self.input_)) self.input_ = "" + elif self.mode.name == 'command_thing' and key == '\n': + if self.input_ == '': + self.log_msg('@ aborted') + self.switch_mode('play') + elif task_action_on('command'): + self.send('TASK:COMMAND ' + quote(self.input_)) + self.input_ = "" elif self.mode.name == 'control_pw_pw' and key == '\n': if self.input_ == '': self.log_msg('@ aborted') @@ -1021,6 +1070,8 @@ class TUI: self.send('TASK:DROP') elif key == self.keys['door'] and task_action_on('door'): self.send('TASK:DOOR') + elif key == self.keys['consume'] and task_action_on('consume'): + self.send('TASK:INTOXICATE') elif key == self.keys['teleport']: player = self.game.get_thing(self.game.player_id) if player.position in self.game.portals: