From 6f5e2612e8d2b2515612e3dee6dc5ab115f0c1a3 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Tue, 1 Dec 2020 02:45:30 +0100 Subject: [PATCH] Implement doors. --- config.json | 1 + plomrogue/commands.py | 2 +- plomrogue/mapping.py | 34 ++++++++++++++++++++++------------ plomrogue/tasks.py | 16 ++++++++++++++++ plomrogue/things.py | 24 ++++++++++++++++++++++-- rogue_chat.html | 13 ++++++++++++- rogue_chat.py | 8 ++++++-- rogue_chat_curses.py | 9 +++++++-- 8 files changed, 87 insertions(+), 20 deletions(-) diff --git a/config.json b/config.json index 15022fe..33243af 100644 --- a/config.json +++ b/config.json @@ -16,6 +16,7 @@ "take_thing": "z", "drop_thing": "u", "teleport": "p", + "door": "D", "help": "h", "toggle_map_mode": "L", "toggle_tile_draw": "m", diff --git a/plomrogue/commands.py b/plomrogue/commands.py index 6532b72..94d1c59 100644 --- a/plomrogue/commands.py +++ b/plomrogue/commands.py @@ -44,7 +44,7 @@ def cmd_ALL(game, msg, connection_id): if not speaker: raise GameError('need to be logged in for this') largest_audible_distance = 20 - dijkstra_map = DijkstraMap(game.maps, speaker.position, + dijkstra_map = DijkstraMap(game.things, game.maps, speaker.position, largest_audible_distance, game.get_map) for c_id in game.sessions: listener = game.get_player(c_id) diff --git a/plomrogue/mapping.py b/plomrogue/mapping.py index 5822dad..b4fadd7 100644 --- a/plomrogue/mapping.py +++ b/plomrogue/mapping.py @@ -209,7 +209,7 @@ class Map(): class SourcedMap(Map): - def __init__(self, source_maps, source_center, radius, get_map): + def __init__(self, things, source_maps, source_center, radius, get_map): self.source_maps = source_maps self.radius = radius example_map = get_map(YX(0, 0)) @@ -220,6 +220,20 @@ class SourcedMap(Map): for yx in self: big_yx, _ = self.source_yxyx(yx) get_map(big_yx) + self.source_map_segment = '' + obstacles = {} + for yxyx in [t.position for t in things if t.blocking]: + if yxyx == source_center: + continue + if yxyx[0] not in obstacles: + obstacles[yxyx[0]] = [] + obstacles[yxyx[0]] += [yxyx[1]] + for yx in self: + big_yx, little_yx = self.source_yxyx(yx) + if big_yx in obstacles and little_yx in obstacles[big_yx]: + self.source_map_segment += 'X' + else: + self.source_map_segment += self.source_maps[big_yx][little_yx] def source_yxyx(self, yx): absolute_yx = yx + self.offset @@ -247,14 +261,10 @@ class DijkstraMap(SourcedMap): self.terrain = [255] * self.size_i self[self.center] = 0 shrunk = True - source_map_segment = '' - for yx in self: - big_yx, little_yx = self.source_yxyx(yx) - source_map_segment += self.source_maps[big_yx][little_yx] while shrunk: shrunk = False for i in range(self.size_i): - if source_map_segment[i] == 'X': + if self.source_map_segment[i] == 'X': continue neighbors = self.geometry.get_neighbors_i(i) for direction in [d for d in neighbors if neighbors[d]]: @@ -286,10 +296,10 @@ class FovMap(SourcedMap): self.shadow_cones = [] self.circle_out(self.center, self.shadow_process) - def throws_shadow(self, big_yx, little_yx): - return self.source_maps[big_yx][little_yx] == 'X' + def throws_shadow(self, yx): + return self.source_map_segment[self.get_position_index(yx)] == 'X' - def shadow_process(self, yx, source_yxyx, distance_to_center, dir_i, dir_progress): + def shadow_process(self, yx, distance_to_center, dir_i, dir_progress): # Possible optimization: If no shadow_cones yet and self[yx] == '.', # skip all. CIRCLE = 360 # Since we'll float anyways, number is actually arbitrary. @@ -329,7 +339,7 @@ class FovMap(SourcedMap): if in_shadow_cone(cone): return self[yx] = '.' - if self.throws_shadow(*source_yxyx): + if self.throws_shadow(yx): unmerged = True while merge_cone(cone): unmerged = False @@ -368,12 +378,12 @@ class FovMap(SourcedMap): for dir_progress in range(distance): direction = self.circle_out_directions[dir_i] yx = self.circle_out_move(yx, direction) - source_yxyx = self.source_yxyx(yx) - f(yx, source_yxyx, distance, dir_i, dir_progress) + f(yx, distance, dir_i, dir_progress) distance += 1 + class FovMapHex(FovMap): circle_out_directions = ('DOWNLEFT', 'LEFT', 'UPLEFT', 'UPRIGHT', 'RIGHT', 'DOWNRIGHT') diff --git a/plomrogue/tasks.py b/plomrogue/tasks.py index a7bcf37..a7f1dcf 100644 --- a/plomrogue/tasks.py +++ b/plomrogue/tasks.py @@ -112,3 +112,19 @@ class Task_DROP(Task): def do(self): self.thing.carrying = None + + + +class Task_DOOR(Task): + todo = 1 + + def do(self): + self.thing.carrying = None + action_radius = list(self.thing.game.map_geometry. + get_neighbors_yxyx(self.thing.position).values()) + for t in [t for t in self.thing.game.things if + t.type_ == 'Door' and t.position in action_radius]: + if t.blocking: + t.open() + else: + t.close() diff --git a/plomrogue/things.py b/plomrogue/things.py index a51b2b2..4d319b9 100644 --- a/plomrogue/things.py +++ b/plomrogue/things.py @@ -74,6 +74,26 @@ class Thing_SpawnPoint(Thing): +class Thing_DoorSpawner(ThingSpawner): + child_type = 'Door' + + + +class Thing_Door(Thing): + symbol_hint = 'D' + blocking = False + portable = True + + def open(self): + self.blocking = False + self.portable = True + + def close(self): + self.blocking = True + self.portable = False + + + class ThingAnimate(Thing): blocking = True @@ -122,8 +142,8 @@ class ThingAnimate(Thing): if self._fov: return self._fov fov_map_class = self.game.map_geometry.fov_map_class - self._fov = fov_map_class(self.game.maps, self.position, 12, - self.game.get_map) + self._fov = fov_map_class(self.game.things, self.game.maps, self.position, + 12, self.game.get_map) return self._fov def fov_test(self, big_yx, little_yx): diff --git a/rogue_chat.html b/rogue_chat.html index ded3658..da13b13 100644 --- a/rogue_chat.html +++ b/rogue_chat.html @@ -53,6 +53,7 @@ keyboard input/control: + @@ -95,6 +96,7 @@ keyboard input/control:
  • teleport:
  • pick up thing:
  • drop thing: +
  • open/close:
  • @@ -200,6 +202,7 @@ let key_descriptions = { 'teleport': 'teleport', 'take_thing': 'pick up thing', 'drop_thing': 'drop thing', + 'door': 'open/close', 'toggle_map_mode': 'toggle map view', 'toggle_tile_draw': 'toggle protection character drawing', 'hex_move_upleft': 'up-left', @@ -431,6 +434,7 @@ let server = { }; } else if (tokens[0] === 'TASKS') { game.tasks = tokens[1].split(','); + console.log(game.tasks); tui.mode_write.legal = game.tasks.includes('WRITE'); } else if (tokens[0] === 'THING_TYPE') { game.thing_types[tokens[1]] = tokens[2] @@ -599,11 +603,13 @@ let tui = { 'take_thing': 'PICK_UP', 'drop_thing': 'DROP', 'move': 'MOVE', + 'door': 'DOOR', }, init: function() { this.mode_chat.available_modes = ["play", "study", "edit", "admin_enter"] this.mode_play.available_modes = ["chat", "study", "edit", "admin_enter"] - this.mode_play.available_actions = ["move", "take_thing", "drop_thing", "teleport"]; + this.mode_play.available_actions = ["move", "take_thing", "drop_thing", + "teleport", "door"]; this.mode_study.available_modes = ["chat", "play", "admin_enter", "edit"] this.mode_study.available_actions = ["toggle_map_mode", "move_explorer"]; this.mode_admin.available_modes = ["admin_thing_protect", "control_pw_type", @@ -1382,6 +1388,8 @@ tui.inputEl.addEventListener('keydown', (event) => { server.send(["TASK:PICK_UP"]); } else if (event.key === tui.keys.drop_thing && tui.task_action_on('drop_thing')) { server.send(["TASK:DROP"]); + } else if (event.key === tui.keys.door && tui.task_action_on('door')) { + server.send(["TASK:DOOR"]); } else if (event.key in tui.movement_keys && tui.task_action_on('move')) { server.send(['TASK:MOVE', tui.movement_keys[event.key]]); } else if (event.key === tui.keys.teleport) { @@ -1498,6 +1506,9 @@ document.getElementById("drop_thing").onclick = function() { document.getElementById("flatten").onclick = function() { server.send(['TASK:FLATTEN_SURROUNDINGS', tui.password]); }; +document.getElementById("door").onclick = function() { + server.send(['TASK:DOOR']); +}; document.getElementById("teleport").onclick = function() { game.teleport(); }; diff --git a/rogue_chat.py b/rogue_chat.py index 3ace630..7bd86ed 100755 --- a/rogue_chat.py +++ b/rogue_chat.py @@ -11,9 +11,10 @@ from plomrogue.commands import (cmd_ALL, cmd_LOGIN, cmd_NICK, cmd_PING, cmd_THIN cmd_GOD_THING_PROTECTION, cmd_THING_PROTECTION, cmd_SET_MAP_CONTROL_PASSWORD, cmd_SPAWN_POINT) from plomrogue.tasks import (Task_WAIT, Task_MOVE, Task_WRITE, Task_PICK_UP, - Task_DROP, Task_FLATTEN_SURROUNDINGS) + Task_DROP, Task_FLATTEN_SURROUNDINGS, Task_DOOR) from plomrogue.things import (Thing_Player, Thing_Item, Thing_ItemSpawner, - Thing_SpawnPoint, Thing_SpawnPointSpawner) + Thing_SpawnPoint, Thing_SpawnPointSpawner, + Thing_Door, Thing_DoorSpawner) from plomrogue.config import config game = Game(config['savefile']) @@ -51,11 +52,14 @@ game.register_task(Task_WRITE) game.register_task(Task_FLATTEN_SURROUNDINGS) game.register_task(Task_PICK_UP) game.register_task(Task_DROP) +game.register_task(Task_DOOR) game.register_thing_type(Thing_Player) game.register_thing_type(Thing_Item) game.register_thing_type(Thing_ItemSpawner) game.register_thing_type(Thing_SpawnPoint) game.register_thing_type(Thing_SpawnPointSpawner) +game.register_thing_type(Thing_Door) +game.register_thing_type(Thing_DoorSpawner) game.read_savefile() game.io.start_loop() for port in config['servers']: diff --git a/rogue_chat_curses.py b/rogue_chat_curses.py index 2066f6c..7e5437f 100755 --- a/rogue_chat_curses.py +++ b/rogue_chat_curses.py @@ -383,7 +383,7 @@ class TUI: import json self.mode_play.available_modes = ["chat", "study", "edit", "admin_enter"] self.mode_play.available_actions = ["move", "take_thing", "drop_thing", - "teleport"] + "teleport", "door"] 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", @@ -427,6 +427,7 @@ class TUI: 'take_thing': 'z', 'drop_thing': 'u', 'teleport': 'p', + 'door': 'D', 'help': 'h', 'toggle_map_mode': 'L', 'toggle_tile_draw': 'm', @@ -857,13 +858,15 @@ class TUI: 'drop_thing': 'drop thing', 'toggle_map_mode': 'toggle map view', 'toggle_tile_draw': 'toggle protection character drawing', + 'door': 'open/close', } action_tasks = { 'flatten': 'FLATTEN_SURROUNDINGS', 'take_thing': 'PICK_UP', 'drop_thing': 'DROP', - 'move': 'MOVE' + 'door': 'DOOR', + 'move': 'MOVE', } curses.curs_set(False) # hide cursor @@ -1016,6 +1019,8 @@ class TUI: self.send('TASK:PICK_UP') elif key == self.keys['drop_thing'] and task_action_on('drop_thing'): self.send('TASK:DROP') + elif key == self.keys['door'] and task_action_on('door'): + self.send('TASK:DOOR') elif key == self.keys['teleport']: player = self.game.get_thing(self.game.player_id) if player.position in self.game.portals: -- 2.30.2