Doors #156
| @@ -2,17 +2,17 @@ | |||||||
|     #######                    #############         |     #######                    #############         | ||||||
|     #.H...#                    #...........#         |     #.H...#                    #...........#         | ||||||
|     #.....#                #####...........#         |     #.....#                #####...........#         | ||||||
|     #.....#                #............H..#         |     #.....#                #...&........H..#         | ||||||
|     #.#####                #.###...........#         |     #.#####                #.###...........#         | ||||||
|     #.#                    #.# #...........#         |     #.#                    #.# #...........#         | ||||||
|     #.#                    #.# #############         |     #.#                    #.# #############         | ||||||
|     #.#                    #.#                       |     #.#                    #.#                       | ||||||
|     #.####                 #.#                       |     #.####                 #.#                       | ||||||
|     #....#                 #.#                       |     #....#                 #.#                       | ||||||
|     ####.###################.#                       |     ####&###################&#                       | ||||||
|        #.....................#     ################# |        #.....................#     ################# | ||||||
|        #.....................#     #...............# |        #.....................#     #...............# | ||||||
|        #.....................#######...............# |        #.....................#######...............# | ||||||
|        #...........................................# |        #.....................&.....&...............# | ||||||
|        #.....................#######...............# |        #.....................#######...............# | ||||||
|        #######################     ################# |        #######################     ################# | ||||||
|   | |||||||
| @@ -82,6 +82,7 @@ TexturePack.ASCII_PACK = TexturePack( | |||||||
|     BOW=')', |     BOW=')', | ||||||
|     CHEST='□', |     CHEST='□', | ||||||
|     CHESTPLATE='(', |     CHESTPLATE='(', | ||||||
|  |     DOOR='&', | ||||||
|     EAGLE='µ', |     EAGLE='µ', | ||||||
|     EMPTY=' ', |     EMPTY=' ', | ||||||
|     EXPLOSION='%', |     EXPLOSION='%', | ||||||
| @@ -124,6 +125,8 @@ TexturePack.SQUIRREL_PACK = TexturePack( | |||||||
|     BOW='🏹', |     BOW='🏹', | ||||||
|     CHEST='🧰', |     CHEST='🧰', | ||||||
|     CHESTPLATE='🦺', |     CHESTPLATE='🦺', | ||||||
|  |     DOOR=('🚪', curses.COLOR_WHITE, (1000, 1000, 1000), | ||||||
|  |           curses.COLOR_WHITE, (1000, 1000, 1000)), | ||||||
|     EAGLE='🦅', |     EAGLE='🦅', | ||||||
|     EMPTY='  ', |     EMPTY='  ', | ||||||
|     EXPLOSION='💥', |     EXPLOSION='💥', | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ from random import randint | |||||||
| from typing import Dict, Optional, Tuple | from typing import Dict, Optional, Tuple | ||||||
|  |  | ||||||
| from .items import Item | from .items import Item | ||||||
| from ..interfaces import FightingEntity, InventoryHolder | from ..interfaces import FightingEntity, InventoryHolder, Tile | ||||||
| from ..translations import gettext as _ | from ..translations import gettext as _ | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -152,6 +152,12 @@ class Player(InventoryHolder, FightingEntity): | |||||||
|                     return True |                     return True | ||||||
|                 elif entity.is_item(): |                 elif entity.is_item(): | ||||||
|                     entity.hold(self) |                     entity.hold(self) | ||||||
|  |         tile = self.map.tiles[y][x] | ||||||
|  |         if tile == Tile.DOOR and move_if_possible: | ||||||
|  |             # Open door | ||||||
|  |             self.map.tiles[y][x] = Tile.FLOOR | ||||||
|  |             self.map.compute_visibility(y, x, self.vision) | ||||||
|  |             return super().check_move(y, x, move_if_possible) | ||||||
|         return super().check_move(y, x, move_if_possible) |         return super().check_move(y, x, move_if_possible) | ||||||
|  |  | ||||||
|     def save_state(self) -> dict: |     def save_state(self) -> dict: | ||||||
|   | |||||||
| @@ -199,7 +199,9 @@ class Game: | |||||||
|             self.map_index = 0 |             self.map_index = 0 | ||||||
|             return |             return | ||||||
|         while self.map_index >= len(self.maps): |         while self.map_index >= len(self.maps): | ||||||
|             self.maps.append(broguelike.Generator().run()) |             m = broguelike.Generator().run() | ||||||
|  |             m.logs = self.logs | ||||||
|  |             self.maps.append(m) | ||||||
|         new_map = self.map |         new_map = self.map | ||||||
|         new_map.floor = self.map_index |         new_map.floor = self.map_index | ||||||
|         old_map.remove_entity(self.player) |         old_map.remove_entity(self.player) | ||||||
| @@ -417,6 +419,7 @@ class Game: | |||||||
|             self.maps = [Map().load_state(map_dict) for map_dict in d["maps"]] |             self.maps = [Map().load_state(map_dict) for map_dict in d["maps"]] | ||||||
|             for i, m in enumerate(self.maps): |             for i, m in enumerate(self.maps): | ||||||
|                 m.floor = i |                 m.floor = i | ||||||
|  |                 m.logs = self.logs | ||||||
|         except KeyError as error: |         except KeyError as error: | ||||||
|             self.message = _("Some keys are missing in your save file.\n" |             self.message = _("Some keys are missing in your save file.\n" | ||||||
|                              "Your save seems to be corrupt. It got deleted.")\ |                              "Your save seems to be corrupt. It got deleted.")\ | ||||||
|   | |||||||
| @@ -390,6 +390,7 @@ class Tile(Enum): | |||||||
|     WALL = auto() |     WALL = auto() | ||||||
|     FLOOR = auto() |     FLOOR = auto() | ||||||
|     LADDER = auto() |     LADDER = auto() | ||||||
|  |     DOOR = auto() | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def from_ascii_char(ch: str) -> "Tile": |     def from_ascii_char(ch: str) -> "Tile": | ||||||
| @@ -430,7 +431,7 @@ class Tile(Enum): | |||||||
|         """ |         """ | ||||||
|         Is this Tile a wall? |         Is this Tile a wall? | ||||||
|         """ |         """ | ||||||
|         return self == Tile.WALL |         return self == Tile.WALL or self == Tile.DOOR | ||||||
|  |  | ||||||
|     def is_ladder(self) -> bool: |     def is_ladder(self) -> bool: | ||||||
|         """ |         """ | ||||||
|   | |||||||
| @@ -26,9 +26,11 @@ DEFAULT_PARAMS = { | |||||||
|     "spawn_per_region": [1, 2], |     "spawn_per_region": [1, 2], | ||||||
| } | } | ||||||
|  |  | ||||||
| def dist(level, y1, x1, y2, x2): |  | ||||||
|  | def dist(level: List[List[Tile]], y1: int, x1: int, y2: int, x2: int) -> int: | ||||||
|     """ |     """ | ||||||
|     Compute the minimum walking distance between points (y1, x1) and (y2, x2) on a Tile grid |     Compute the minimum walking distance between points (y1, x1) and (y2, x2) | ||||||
|  |     on a Tile grid | ||||||
|     """ |     """ | ||||||
|     # simple breadth first search |     # simple breadth first search | ||||||
|     copy = [[t for t in row] for row in level] |     copy = [[t for t in row] for row in level] | ||||||
| @@ -97,8 +99,7 @@ class Generator: | |||||||
|         making (door_y, door_x) in the room correspond with (y, x) in the level |         making (door_y, door_x) in the room correspond with (y, x) in the level | ||||||
|         """ |         """ | ||||||
|         rh, rw = len(room), len(room[0]) |         rh, rw = len(room), len(room[0]) | ||||||
|         # maybe place Tile.DOOR here instead ? |         level[y][x] = Tile.DOOR | ||||||
|         level[y][x] = Tile.FLOOR |  | ||||||
|         for ry in range(rh): |         for ry in range(rh): | ||||||
|             for rx in range(rw): |             for rx in range(rw): | ||||||
|                 if room[ry][rx] == Tile.FLOOR: |                 if room[ry][rx] == Tile.FLOOR: | ||||||
| @@ -248,8 +249,8 @@ class Generator: | |||||||
|             if room[y][x] == Tile.EMPTY and \ |             if room[y][x] == Tile.EMPTY and \ | ||||||
|                     Generator.build_door(room, y, x, dy, dx, length): |                     Generator.build_door(room, y, x, dy, dx, length): | ||||||
|                 break |                 break | ||||||
|         else: |         else:  # pragma: no cover | ||||||
|             return None, None |             return None, None, None, None | ||||||
|  |  | ||||||
|         return y + length * dy, x + length * dx, dy, dx |         return y + length * dy, x + length * dx, dy, dx | ||||||
|  |  | ||||||
| @@ -324,8 +325,8 @@ class Generator: | |||||||
|         top left corner of the room on the level, then log them as a |         top left corner of the room on the level, then log them as a | ||||||
|         spawnable region |         spawnable region | ||||||
|         """ |         """ | ||||||
|         if self.queued_area != None: |         if self.queued_area is not None: | ||||||
|             translated_area = [[y+ry, x+rx] for ry, rx in self.queued_area] |             translated_area = [[y + ry, x + rx] for ry, rx in self.queued_area] | ||||||
|             self.spawn_areas.append(translated_area) |             self.spawn_areas.append(translated_area) | ||||||
|         self.queued_area = None |         self.queued_area = None | ||||||
|  |  | ||||||
| @@ -334,11 +335,6 @@ class Generator: | |||||||
|         Populate every spawnable area with some randomly chosen, randomly |         Populate every spawnable area with some randomly chosen, randomly | ||||||
|         placed entity |         placed entity | ||||||
|         """ |         """ | ||||||
|         if self.queued_area is not None: |  | ||||||
|             translated_area = [[y + ry, x + rx] for ry, rx in self.queued_area] |  | ||||||
|             self.spawn_areas.append(translated_area) |  | ||||||
|         self.queued_area = None |  | ||||||
|  |  | ||||||
|         min_c, max_c = self.params["spawn_per_region"] |         min_c, max_c = self.params["spawn_per_region"] | ||||||
|         for region in self.spawn_areas: |         for region in self.spawn_areas: | ||||||
|             entity_count = randint(min_c, max_c) |             entity_count = randint(min_c, max_c) | ||||||
|   | |||||||
| @@ -134,13 +134,13 @@ class TestEntities(unittest.TestCase): | |||||||
|         self.map.remove_entity(entity2) |         self.map.remove_entity(entity2) | ||||||
|  |  | ||||||
|         # Test following the player and finding the player as target |         # Test following the player and finding the player as target | ||||||
|         self.player.move(5, 5) |         self.player.move(6, 5) | ||||||
|         fam.move(4, 5) |         fam.move(5, 5) | ||||||
|         fam.target = None |         fam.target = None | ||||||
|         self.player.move_down() |         self.player.move_down() | ||||||
|         self.map.tick(self.player) |         self.map.tick(self.player) | ||||||
|         self.assertTrue(fam.target == self.player) |         self.assertTrue(fam.target == self.player) | ||||||
|         self.assertEqual(fam.y, 5) |         self.assertEqual(fam.y, 6) | ||||||
|         self.assertEqual(fam.x, 5) |         self.assertEqual(fam.x, 5) | ||||||
|  |  | ||||||
|         # Test random move |         # Test random move | ||||||
|   | |||||||
| @@ -728,6 +728,7 @@ class TestGame(unittest.TestCase): | |||||||
|         self.game.player.inventory.clear() |         self.game.player.inventory.clear() | ||||||
|         ring = RingCritical() |         ring = RingCritical() | ||||||
|         ring.hold(self.game.player) |         ring.hold(self.game.player) | ||||||
|  |         self.game.display_actions(DisplayActions.REFRESH) | ||||||
|         old_critical = self.game.player.critical |         old_critical = self.game.player.critical | ||||||
|         self.game.handle_key_pressed(KeyValues.EQUIP) |         self.game.handle_key_pressed(KeyValues.EQUIP) | ||||||
|         self.assertEqual(self.game.player.critical, |         self.assertEqual(self.game.player.critical, | ||||||
| @@ -951,3 +952,18 @@ class TestGame(unittest.TestCase): | |||||||
|         # Exit the menu |         # Exit the menu | ||||||
|         self.game.handle_key_pressed(KeyValues.SPACE) |         self.game.handle_key_pressed(KeyValues.SPACE) | ||||||
|         self.assertEqual(self.game.state, GameMode.PLAY) |         self.assertEqual(self.game.state, GameMode.PLAY) | ||||||
|  |  | ||||||
|  |     def test_doors(self) -> None: | ||||||
|  |         """ | ||||||
|  |         Check that the user can open doors. | ||||||
|  |         """ | ||||||
|  |         self.game.state = GameMode.PLAY | ||||||
|  |  | ||||||
|  |         self.game.player.move(9, 8) | ||||||
|  |         self.assertEqual(self.game.map.tiles[10][8], Tile.DOOR) | ||||||
|  |         # Open door | ||||||
|  |         self.game.handle_key_pressed(KeyValues.DOWN) | ||||||
|  |         self.assertEqual(self.game.map.tiles[10][8], Tile.FLOOR) | ||||||
|  |         self.assertEqual(self.game.player.y, 10) | ||||||
|  |         self.assertEqual(self.game.player.x, 8) | ||||||
|  |         self.game.display_actions(DisplayActions.REFRESH) | ||||||
|   | |||||||
| @@ -26,16 +26,17 @@ class TestBroguelike(unittest.TestCase): | |||||||
|  |  | ||||||
|     def is_connex(self, grid: List[List[Tile]]) -> bool: |     def is_connex(self, grid: List[List[Tile]]) -> bool: | ||||||
|         h, w = len(grid), len(grid[0]) |         h, w = len(grid), len(grid[0]) | ||||||
|         y, x = randint(0, h - 1), randint(0, w - 1) |         y, x = -1, -1 | ||||||
|         while not (grid[y][x].can_walk()): |         while not grid[y][x].can_walk(): | ||||||
|             y, x = randint(0, h - 1), randint(0, w - 1) |             y, x = randint(0, h - 1), randint(0, w - 1) | ||||||
|         queue = Map.neighbourhood(grid, y, x) |         queue = Map.neighbourhood(grid, y, x) | ||||||
|         while queue: |         while queue: | ||||||
|             y, x = queue.pop() |             y, x = queue.pop() | ||||||
|             if grid[y][x].can_walk(): |             if grid[y][x].can_walk() or grid[y][x] == Tile.DOOR: | ||||||
|                 grid[y][x] = Tile.WALL |                 grid[y][x] = Tile.WALL | ||||||
|                 queue += Map.neighbourhood(grid, y, x) |                 queue += Map.neighbourhood(grid, y, x) | ||||||
|         return not any([t.can_walk() for row in grid for t in row]) |         return not any([t.can_walk() or t == Tile.DOOR | ||||||
|  |                         for row in grid for t in row]) | ||||||
|  |  | ||||||
|     def test_build_doors(self) -> None: |     def test_build_doors(self) -> None: | ||||||
|         m = self.stom(".  .\n.  .\n.  .\n") |         m = self.stom(".  .\n.  .\n.  .\n") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user