From c7a3af00680ba0449310bbb7336a187dd4ed6bcf Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Mon, 7 Dec 2020 05:26:35 +0100 Subject: [PATCH] Add editable player faces. --- config.json | 1 + plomrogue/commands.py | 14 ++++++++++ plomrogue/game.py | 15 ++++++++++ rogue_chat.html | 64 +++++++++++++++++++++++++++---------------- rogue_chat.py | 5 +++- rogue_chat_curses.py | 50 +++++++++++++++++++++++---------- 6 files changed, 110 insertions(+), 39 deletions(-) diff --git a/config.json b/config.json index a7a51ad..7b26b53 100644 --- a/config.json +++ b/config.json @@ -14,6 +14,7 @@ "switch_to_control_tile_type": "Q", "switch_to_admin_thing_protect": "T", "flatten": "F", + "switch_to_enter_face": "f", "switch_to_take_thing": "z", "drop_thing": "u", "teleport": "p", diff --git a/plomrogue/commands.py b/plomrogue/commands.py index daa4357..0ccbdc1 100644 --- a/plomrogue/commands.py +++ b/plomrogue/commands.py @@ -313,3 +313,17 @@ def cmd_THING_INSTALLED(game, thing_id): raise GameError('thing of ID %s not installable' % thing_id) t.install() cmd_THING_INSTALLED.argtypes = 'int:pos' + +def cmd_PLAYER_FACE(game, face, connection_id): + t = game.get_player(connection_id) + if not t: + raise GameError('can only draw face when already logged in') + if len(face) != 9: + raise GameError('wrong face string length') + game.faces[t.name] = face + game.changed = True +cmd_PLAYER_FACE.argtypes = 'string' + +def cmd_GOD_PLAYER_FACE(game, name, face): + game.faces[name] = face +cmd_GOD_PLAYER_FACE.argtypes = 'string string' diff --git a/plomrogue/game.py b/plomrogue/game.py index 68d4858..017580f 100755 --- a/plomrogue/game.py +++ b/plomrogue/game.py @@ -121,6 +121,7 @@ class Game(GameBase): self.tasks = {} self.thing_types = {} self.sessions = {} + self.faces = {} self.maps = {} self.map_controls = {} self.map_control_passwords = {} @@ -199,6 +200,14 @@ class Game(GameBase): player = self.get_thing(self.sessions[connection_id]['thing_id']) return player + def get_face(self, t): + if t.type_ == 'Player': + if t.name in self.faces: + return self.faces[t.name] + else: + return 'O O' + ' v ' + '>-<' + return None + def send_gamestate(self, connection_id=None): """Send out game state data relevant to clients.""" @@ -237,6 +246,9 @@ class Game(GameBase): c_id) if hasattr(t, 'name'): self.io.send('THING_NAME %s %s' % (t.id_, quote(t.name)), c_id) + face = self.get_face(t) + if face: + self.io.send('THING_FACE %s %s' % (t.id_, quote(face)), c_id) if hasattr(t, 'thing_char'): self.io.send('THING_CHAR %s %s' % (t.id_, quote(t.thing_char)), c_id) @@ -371,6 +383,9 @@ class Game(GameBase): self.map_control_passwords[tile_class])) for pw in self.admin_passwords: write(f, 'ADMIN_PASSWORD %s' % pw) + for name in self.faces: + write(f, 'GOD_PLAYER_FACE %s %s' % (quote(name), + quote(self.faces[name]))) for t in [t for t in self.things if not t.type_ == 'Player']: write(f, 'THING %s %s %s %s' % (t.position[0], t.position[1], t.type_, t.id_)) diff --git a/rogue_chat.html b/rogue_chat.html index f7a97ec..dfeeecd 100644 --- a/rogue_chat.html +++ b/rogue_chat.html @@ -69,6 +69,7 @@ keyboard input/control: + @@ -101,6 +102,7 @@ keyboard input/control:
  • open/close:
  • consume:
  • install: +
  • @@ -160,6 +162,11 @@ let mode_helps = { 'intro': '@ enter thing protection character:', 'long': 'Change protection character for thing here.' }, + 'enter_face': { + 'short': 'enter your face', + 'intro': '@ enter face line (enter nothing to abort):', + 'long': 'Draw your face as ASCII art. The string you enter must be 9 characters long, and will be divided on display into three lines of three characters each, from top to bottom..' + }, 'write': { 'short': 'change terrain', 'intro': '', @@ -477,14 +484,13 @@ let server = { t.portable = parseInt(tokens[5]); } else if (tokens[0] === 'THING_NAME') { let t = game.get_thing(tokens[1], false); - if (t) { - t.name_ = tokens[2]; - }; + t.name_ = tokens[2]; + } else if (tokens[0] === 'THING_FACE') { + let t = game.get_thing(tokens[1], false); + t.face = tokens[2]; } else if (tokens[0] === 'THING_CHAR') { let t = game.get_thing(tokens[1], false); - if (t) { - t.thing_char = tokens[2]; - }; + t.thing_char = tokens[2]; } else if (tokens[0] === 'TASKS') { game.tasks = tokens[1].split(','); tui.mode_write.legal = game.tasks.includes('WRITE'); @@ -494,14 +500,10 @@ let server = { game.thing_types[tokens[1]] = tokens[2] } else if (tokens[0] === 'THING_CARRYING') { let t = game.get_thing(tokens[1], false); - if (t) { - t.carrying = true; - }; + t.carrying = true; } else if (tokens[0] === 'THING_INSTALLED') { let t = game.get_thing(tokens[1], false); - if (t) { - t.installed = true; - }; + t.installed = true; } else if (tokens[0] === 'TERRAIN') { game.terrains[tokens[1]] = tokens[2] } else if (tokens[0] === 'MAP') { @@ -662,6 +664,7 @@ let tui = { mode_name_thing: new Mode('name_thing', true, true), mode_command_thing: new Mode('command_thing', true), mode_take_thing: new Mode('take_thing', true), + mode_enter_face: new Mode('enter_face', true), mode_admin_enter: new Mode('admin_enter', true), mode_admin: new Mode('admin'), mode_control_pw_pw: new Mode('control_pw_pw', true), @@ -695,7 +698,7 @@ let tui = { this.mode_control_tile_draw.available_actions = ["toggle_tile_draw"]; this.mode_edit.available_modes = ["write", "annotate", "portal", "name_thing", "password", "chat", "study", "play", - "admin_enter"] + "admin_enter", "enter_face"] this.mode_edit.available_actions = ["move", "flatten", "toggle_map_mode"] this.inputEl = document.getElementById("input"); this.inputEl.focus(); @@ -1325,17 +1328,6 @@ let explorer = { if (game.fov[position_i] != '.') { info_to_cache += 'outside field of view'; } else { - let terrain_char = game.map[position_i] - let terrain_desc = '?' - if (game.terrains[terrain_char]) { - terrain_desc = game.terrains[terrain_char]; - }; - info_to_cache += 'TERRAIN: "' + terrain_char + '" / ' + terrain_desc + "\n"; - let protection = game.map_control[position_i]; - if (protection == '.') { - protection = 'unprotected'; - }; - info_to_cache += 'PROTECTION: ' + protection + '\n'; for (let t_id in game.things) { let t = game.things[t_id]; if (t.position[0] == this.position[0] && t.position[1] == this.position[1]) { @@ -1345,8 +1337,24 @@ let explorer = { protection = 'none'; } info_to_cache += " / protection: " + protection + "\n"; + if (t.face) { + info_to_cache += t.face.slice(0, 3) + '\n'; + info_to_cache += t.face.slice(3, 6) + '\n'; + info_to_cache += t.face.slice(6, 9) + '\n'; + } } } + let terrain_char = game.map[position_i] + let terrain_desc = '?' + if (game.terrains[terrain_char]) { + terrain_desc = game.terrains[terrain_char]; + }; + info_to_cache += 'TERRAIN: "' + terrain_char + '" / ' + terrain_desc + "\n"; + let protection = game.map_control[position_i]; + if (protection == '.') { + protection = 'unprotected'; + }; + info_to_cache += 'PROTECTION: ' + protection + '\n'; if (this.position in game.portals) { info_to_cache += "PORTAL: " + game.portals[this.position] + "\n"; } @@ -1427,6 +1435,14 @@ tui.inputEl.addEventListener('keydown', (event) => { tui.login_name = tui.inputEl.value; server.send(['LOGIN', tui.inputEl.value]); tui.inputEl.value = ""; + } else if (tui.mode.name == 'enter_face' && event.key == 'Enter') { + if (tui.inputEl.value.length != 9) { + tui.log_msg('? wrong input length, aborting'); + } else { + server.send(['PLAYER_FACE', tui.inputEl.value]); + } + tui.inputEl.value = ""; + tui.switch_mode('edit'); } else if (tui.mode.name == 'command_thing' && event.key == 'Enter') { if (tui.task_action_on('command')) { server.send(['TASK:COMMAND', tui.inputEl.value]); diff --git a/rogue_chat.py b/rogue_chat.py index 8aeaf81..14e23dc 100755 --- a/rogue_chat.py +++ b/rogue_chat.py @@ -12,7 +12,8 @@ from plomrogue.commands import (cmd_ALL, cmd_LOGIN, cmd_NICK, cmd_PING, cmd_THIN cmd_SET_MAP_CONTROL_PASSWORD, cmd_SPAWN_POINT, cmd_THING_MUSICPLAYER_SETTINGS, cmd_THING_MUSICPLAYER_PLAYLIST_ITEM, - cmd_THING_BOTTLE_EMPTY) + cmd_THING_BOTTLE_EMPTY, cmd_PLAYER_FACE, + cmd_GOD_PLAYER_FACE) from plomrogue.tasks import (Task_WAIT, Task_MOVE, Task_WRITE, Task_PICK_UP, Task_DROP, Task_FLATTEN_SURROUNDINGS, Task_DOOR, Task_INTOXICATE, Task_COMMAND, Task_INSTALL) @@ -56,6 +57,8 @@ game.register_command(cmd_SPAWN_POINT) game.register_command(cmd_THING_MUSICPLAYER_SETTINGS) game.register_command(cmd_THING_MUSICPLAYER_PLAYLIST_ITEM) game.register_command(cmd_THING_BOTTLE_EMPTY) +game.register_command(cmd_PLAYER_FACE) +game.register_command(cmd_GOD_PLAYER_FACE) game.register_task(Task_WAIT) game.register_task(Task_MOVE) game.register_task(Task_WRITE) diff --git a/rogue_chat_curses.py b/rogue_chat_curses.py index 7006027..89c8411 100755 --- a/rogue_chat_curses.py +++ b/rogue_chat_curses.py @@ -46,6 +46,11 @@ mode_helps = { 'intro': '@ enter thing protection character:', 'long': 'Change protection character for thing here.' }, + 'enter_face': { + 'short': 'enter your face', + 'intro': '@ enter face line (enter nothing to abort):', + 'long': 'Draw your face as ASCII art. The string you enter must be 9 characters long, and will be divided on display into three lines of three characters each, from top to bottom..' + }, 'write': { 'short': 'change terrain', 'intro': '', @@ -207,15 +212,18 @@ cmd_THING.argtypes = 'yx_tuple:nonneg string:thing_type char int:nonneg bool' def cmd_THING_NAME(game, thing_id, name): t = game.get_thing(thing_id) - if t: - t.name = name -cmd_THING_NAME.argtypes = 'int:nonneg string' + t.name = name +cmd_THING_NAME.argtypes = 'int:pos string' + +def cmd_THING_FACE(game, thing_id, face): + t = game.get_thing(thing_id) + t.face = face +cmd_THING_FACE.argtypes = 'int:pos string' def cmd_THING_CHAR(game, thing_id, c): t = game.get_thing(thing_id) - if t: - t.thing_char = c -cmd_THING_CHAR.argtypes = 'int:nonneg char' + t.thing_char = c +cmd_THING_CHAR.argtypes = 'int:pos char' def cmd_MAP(game, geometry, size, content): map_geometry_class = globals()['MapGeometry' + geometry] @@ -334,6 +342,7 @@ class Game(GameBase): self.register_command(cmd_THING_TYPE) self.register_command(cmd_THING_NAME) self.register_command(cmd_THING_CHAR) + self.register_command(cmd_THING_FACE) self.register_command(cmd_THING_CARRYING) self.register_command(cmd_THING_INSTALLED) self.register_command(cmd_TERRAIN) @@ -429,6 +438,7 @@ class TUI: mode_name_thing = Mode('name_thing', has_input_prompt=True, shows_info=True) mode_command_thing = Mode('command_thing', has_input_prompt=True) mode_take_thing = Mode('take_thing', has_input_prompt=True) + mode_enter_face = Mode('enter_face', has_input_prompt=True) is_admin = False tile_draw = False @@ -451,7 +461,7 @@ class TUI: "toggle_tile_draw"] self.mode_edit.available_modes = ["write", "annotate", "portal", "name_thing", "password", "chat", "study", "play", - "admin_enter"] + "admin_enter", "enter_face"] self.mode_edit.available_actions = ["move", "flatten", "toggle_map_mode"] self.mode = None self.host = host @@ -481,6 +491,7 @@ class TUI: 'switch_to_control_tile_type': 'Q', 'switch_to_admin_thing_protect': 'T', 'flatten': 'F', + 'switch_to_enter_face': 'f', 'switch_to_take_thing': 'z', 'drop_thing': 'u', 'teleport': 'p', @@ -690,6 +701,17 @@ class TUI: if len(self.game.fov) > pos_i and self.game.fov[pos_i] != '.': info_to_cache += 'outside field of view' else: + for t in self.game.things: + if t.position == self.explorer: + info_to_cache += 'THING: %s' % self.get_thing_info(t) + protection = t.protection + if protection == '.': + protection = 'none' + info_to_cache += ' / protection: %s\n' % protection + if hasattr(t, 'face'): + info_to_cache += t.face[0:3] + '\n' + info_to_cache += t.face[3:6] + '\n' + info_to_cache += t.face[6:9] + '\n' terrain_char = self.game.map_content[pos_i] terrain_desc = '?' if terrain_char in self.game.terrains: @@ -700,13 +722,6 @@ class TUI: if protection == '.': protection = 'unprotected' info_to_cache += 'PROTECTION: %s\n' % protection - for t in self.game.things: - if t.position == self.explorer: - info_to_cache += 'THING: %s' % self.get_thing_info(t) - protection = t.protection - if protection == '.': - protection = 'none' - info_to_cache += ' / protection: %s\n' % protection if self.explorer in self.game.portals: info_to_cache += 'PORTAL: ' +\ self.game.portals[self.explorer] + '\n' @@ -1040,6 +1055,13 @@ class TUI: self.login_name = self.input_ self.send('LOGIN ' + quote(self.input_)) self.input_ = "" + elif self.mode.name == 'enter_face' and key == '\n': + if len(self.input_) != 9: + self.log_msg('? wrong input length, aborting') + else: + self.send('PLAYER_FACE %s' % quote(self.input_)) + self.input_ = "" + self.switch_mode('edit') elif self.mode.name == 'take_thing' and key == '\n': try: i = int(self.input_) -- 2.30.2