home · contact · privacy
Implement doors.
authorChristian Heller <c.heller@plomlompom.de>
Tue, 1 Dec 2020 01:45:30 +0000 (02:45 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Tue, 1 Dec 2020 01:45:30 +0000 (02:45 +0100)
config.json
plomrogue/commands.py
plomrogue/mapping.py
plomrogue/tasks.py
plomrogue/things.py
rogue_chat.html
rogue_chat.py
rogue_chat_curses.py

index 15022fea7abc533d98c1e98add2e43b675cc13ad..33243afab11043aea621f74eb283a4f70e098d31 100644 (file)
@@ -16,6 +16,7 @@
     "take_thing": "z",
     "drop_thing": "u",
     "teleport": "p",
+    "door": "D",
     "help": "h",
     "toggle_map_mode": "L",
     "toggle_tile_draw": "m",
index 6532b72bbe027ebb65d0805025140a49da8145d4..94d1c591045dcee8ffbdbcf0f7dd0ab5b5186efa 100644 (file)
@@ -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)
index 5822dada4371170542923c1c63e894e95bc3e1df..b4fadd7d30f1150b717d1ef9f5116ad21d668aed 100644 (file)
@@ -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')
index a7bcf3772a4ab8f5e0351d63bb1da6f0e86c2f52..a7f1dcf3f1d174ba43b7f3bd969a36cba2a65978 100644 (file)
@@ -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()
index a51b2b2b48083037b146cca377005ecf9994cb8b..4d319b9d21e0781b98d615d5d29f39e28392d2fd 100644 (file)
@@ -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):
index ded3658df8d8cafe2d466cc334c3f8d45733fb79..da13b13a392a3addfc48a04fcf056edf95006abb 100644 (file)
@@ -53,6 +53,7 @@ keyboard input/control: <span id="keyboard_control"></span>
     <td>
       <button id="take_thing"></button>
       <button id="drop_thing"></button>
+      <button id="door"></button>
       <button id="teleport"></button>
     </td>
   </tr>
@@ -95,6 +96,7 @@ keyboard input/control: <span id="keyboard_control"></span>
 <li>teleport: <input id="key_teleport" type="text" value="p" />
 <li>pick up thing: <input id="key_take_thing" type="text" value="z" />
 <li>drop thing: <input id="key_drop_thing" type="text" value="u" />
+<li>open/close: <input id="key_door" type="text" value="D" />
 <li><input id="key_switch_to_chat" type="text" value="t" />
 <li><input id="key_switch_to_play" type="text" value="p" />
 <li><input id="key_switch_to_study" type="text" value="?" />
@@ -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();
 };
index 3ace6307ed4b777764c3d099983d96cb0f4dab61..7bd86edc6ef5d522d88da351881de3923af50550 100755 (executable)
@@ -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']:
index 2066f6ca00a1ffc9ac0fd18323bc0335a94d391a..7e5437fa2e1af0ee3eb5fdc899951dec49b0e916 100755 (executable)
@@ -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: