Doors #156
@@ -2,17 +2,17 @@
 | 
			
		||||
    #######                    #############        
 | 
			
		||||
    #.H...#                    #...........#        
 | 
			
		||||
    #.....#                #####...........#        
 | 
			
		||||
    #.....#                #............H..#        
 | 
			
		||||
    #.....#                #...&........H..#        
 | 
			
		||||
    #.#####                #.###...........#        
 | 
			
		||||
    #.#                    #.# #...........#        
 | 
			
		||||
    #.#                    #.# #############        
 | 
			
		||||
    #.#                    #.#                      
 | 
			
		||||
    #.####                 #.#                      
 | 
			
		||||
    #....#                 #.#                      
 | 
			
		||||
    ####.###################.#                      
 | 
			
		||||
    ####&###################&#                      
 | 
			
		||||
       #.....................#     #################
 | 
			
		||||
       #.....................#     #...............#
 | 
			
		||||
       #.....................#######...............#
 | 
			
		||||
       #...........................................#
 | 
			
		||||
       #.....................&.....&...............#
 | 
			
		||||
       #.....................#######...............#
 | 
			
		||||
       #######################     #################
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,7 @@ TexturePack.ASCII_PACK = TexturePack(
 | 
			
		||||
    BOW=')',
 | 
			
		||||
    CHEST='□',
 | 
			
		||||
    CHESTPLATE='(',
 | 
			
		||||
    DOOR='&',
 | 
			
		||||
    EAGLE='µ',
 | 
			
		||||
    EMPTY=' ',
 | 
			
		||||
    EXPLOSION='%',
 | 
			
		||||
@@ -124,6 +125,8 @@ TexturePack.SQUIRREL_PACK = TexturePack(
 | 
			
		||||
    BOW='🏹',
 | 
			
		||||
    CHEST='🧰',
 | 
			
		||||
    CHESTPLATE='🦺',
 | 
			
		||||
    DOOR=('🚪', curses.COLOR_WHITE, (1000, 1000, 1000),
 | 
			
		||||
          curses.COLOR_WHITE, (1000, 1000, 1000)),
 | 
			
		||||
    EAGLE='🦅',
 | 
			
		||||
    EMPTY='  ',
 | 
			
		||||
    EXPLOSION='💥',
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ from random import randint
 | 
			
		||||
from typing import Dict, Optional, Tuple
 | 
			
		||||
 | 
			
		||||
from .items import Item
 | 
			
		||||
from ..interfaces import FightingEntity, InventoryHolder
 | 
			
		||||
from ..interfaces import FightingEntity, InventoryHolder, Tile
 | 
			
		||||
from ..translations import gettext as _
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -152,6 +152,12 @@ class Player(InventoryHolder, FightingEntity):
 | 
			
		||||
                    return True
 | 
			
		||||
                elif entity.is_item():
 | 
			
		||||
                    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)
 | 
			
		||||
 | 
			
		||||
    def save_state(self) -> dict:
 | 
			
		||||
 
 | 
			
		||||
@@ -199,7 +199,9 @@ class Game:
 | 
			
		||||
            self.map_index = 0
 | 
			
		||||
            return
 | 
			
		||||
        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.floor = self.map_index
 | 
			
		||||
        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"]]
 | 
			
		||||
            for i, m in enumerate(self.maps):
 | 
			
		||||
                m.floor = i
 | 
			
		||||
                m.logs = self.logs
 | 
			
		||||
        except KeyError as error:
 | 
			
		||||
            self.message = _("Some keys are missing in your save file.\n"
 | 
			
		||||
                             "Your save seems to be corrupt. It got deleted.")\
 | 
			
		||||
 
 | 
			
		||||
@@ -390,6 +390,7 @@ class Tile(Enum):
 | 
			
		||||
    WALL = auto()
 | 
			
		||||
    FLOOR = auto()
 | 
			
		||||
    LADDER = auto()
 | 
			
		||||
    DOOR = auto()
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def from_ascii_char(ch: str) -> "Tile":
 | 
			
		||||
@@ -430,7 +431,7 @@ class Tile(Enum):
 | 
			
		||||
        """
 | 
			
		||||
        Is this Tile a wall?
 | 
			
		||||
        """
 | 
			
		||||
        return self == Tile.WALL
 | 
			
		||||
        return self == Tile.WALL or self == Tile.DOOR
 | 
			
		||||
 | 
			
		||||
    def is_ladder(self) -> bool:
 | 
			
		||||
        """
 | 
			
		||||
 
 | 
			
		||||
@@ -26,9 +26,11 @@ DEFAULT_PARAMS = {
 | 
			
		||||
    "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
 | 
			
		||||
    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
 | 
			
		||||
        """
 | 
			
		||||
        rh, rw = len(room), len(room[0])
 | 
			
		||||
        # maybe place Tile.DOOR here instead ?
 | 
			
		||||
        level[y][x] = Tile.FLOOR
 | 
			
		||||
        level[y][x] = Tile.DOOR
 | 
			
		||||
        for ry in range(rh):
 | 
			
		||||
            for rx in range(rw):
 | 
			
		||||
                if room[ry][rx] == Tile.FLOOR:
 | 
			
		||||
@@ -248,8 +249,8 @@ class Generator:
 | 
			
		||||
            if room[y][x] == Tile.EMPTY and \
 | 
			
		||||
                    Generator.build_door(room, y, x, dy, dx, length):
 | 
			
		||||
                break
 | 
			
		||||
        else:
 | 
			
		||||
            return None, None
 | 
			
		||||
        else:  # pragma: no cover
 | 
			
		||||
            return None, None, None, None
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
        spawnable region
 | 
			
		||||
        """
 | 
			
		||||
        if self.queued_area != None:
 | 
			
		||||
            translated_area = [[y+ry, x+rx] for ry, rx in self.queued_area]
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
@@ -334,11 +335,6 @@ class Generator:
 | 
			
		||||
        Populate every spawnable area with some randomly chosen, randomly
 | 
			
		||||
        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"]
 | 
			
		||||
        for region in self.spawn_areas:
 | 
			
		||||
            entity_count = randint(min_c, max_c)
 | 
			
		||||
 
 | 
			
		||||
@@ -134,13 +134,13 @@ class TestEntities(unittest.TestCase):
 | 
			
		||||
        self.map.remove_entity(entity2)
 | 
			
		||||
 | 
			
		||||
        # Test following the player and finding the player as target
 | 
			
		||||
        self.player.move(5, 5)
 | 
			
		||||
        fam.move(4, 5)
 | 
			
		||||
        self.player.move(6, 5)
 | 
			
		||||
        fam.move(5, 5)
 | 
			
		||||
        fam.target = None
 | 
			
		||||
        self.player.move_down()
 | 
			
		||||
        self.map.tick(self.player)
 | 
			
		||||
        self.assertTrue(fam.target == self.player)
 | 
			
		||||
        self.assertEqual(fam.y, 5)
 | 
			
		||||
        self.assertEqual(fam.y, 6)
 | 
			
		||||
        self.assertEqual(fam.x, 5)
 | 
			
		||||
 | 
			
		||||
        # Test random move
 | 
			
		||||
 
 | 
			
		||||
@@ -728,6 +728,7 @@ class TestGame(unittest.TestCase):
 | 
			
		||||
        self.game.player.inventory.clear()
 | 
			
		||||
        ring = RingCritical()
 | 
			
		||||
        ring.hold(self.game.player)
 | 
			
		||||
        self.game.display_actions(DisplayActions.REFRESH)
 | 
			
		||||
        old_critical = self.game.player.critical
 | 
			
		||||
        self.game.handle_key_pressed(KeyValues.EQUIP)
 | 
			
		||||
        self.assertEqual(self.game.player.critical,
 | 
			
		||||
@@ -951,3 +952,18 @@ class TestGame(unittest.TestCase):
 | 
			
		||||
        # Exit the menu
 | 
			
		||||
        self.game.handle_key_pressed(KeyValues.SPACE)
 | 
			
		||||
        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:
 | 
			
		||||
        h, w = len(grid), len(grid[0])
 | 
			
		||||
        y, x = randint(0, h - 1), randint(0, w - 1)
 | 
			
		||||
        while not (grid[y][x].can_walk()):
 | 
			
		||||
        y, x = -1, -1
 | 
			
		||||
        while not grid[y][x].can_walk():
 | 
			
		||||
            y, x = randint(0, h - 1), randint(0, w - 1)
 | 
			
		||||
        queue = Map.neighbourhood(grid, y, x)
 | 
			
		||||
        while queue:
 | 
			
		||||
            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
 | 
			
		||||
                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:
 | 
			
		||||
        m = self.stom(".  .\n.  .\n.  .\n")
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user