def _interior_garden(w, h, wall_material, floor_material):
    M = Map(w, h, fill_cell=C.floor_flagged)
    garden_part = Map(w // 2, h, fill_cell=C.flora_grass)
    for y in range(0, h):
        garden_part[w // 2 - 1, y] = C.floor_flagged()
    for x in range(1, w // 2 - 1):
        for y in range(1, 4):
            garden_part[x, y] = C.floor_flagged()
    for x in range(2, w // 2):
        garden_part[x, 2].put(T.water_trough())
    for y in range(h - 3, h):
        garden_part[0, y] = C.flora_tree()
        garden_part[1, y].put(T.water_trough())
        garden_part[2, y] = C.flora_flower()
    garden_part[w // 2 - 2, 0] = C.flora_flower()
    garden_part[0, h - 5].put(T.furniture_sofa())
    garden_part[1, h - 5].put(T.furniture_table_round())
    garden_part[2, h - 6].put(T.urn())
    M.meld(garden_part, 0, 0)
    garden_part2 = deepcopy(garden_part)
    garden_part2.hmirror()
    M.meld(garden_part2, w // 2 + w % 2, 0)
    for x in range(0, w // 2 - 1):
        M[x, h - 4] = C.floor_flagged()
    M.scatter(0, 0, w - 1, h - 1, [A.animal_cat()])

    return M
示例#2
0
def _interior_pantry(w, h, wall_material, floor_material):
    M = Map(w, h, fill_cell=floor_material)
    if random.random() < 0.5:
        for y in range(h):
            M[2, y] = wall_material()
        items = [T.tool_wateringcan(), T.tool_pitchfork(), T.tool_fishingrod()]
        M.scatter(0, 0, w - 1, h, items)
    else:
        M[0, 0] = C.stairs_down()
        M[0, 1].put(T.furniture_box_filled())

    return M
示例#3
0
def room_default(w, h, wall_type, floor_type):
    """
    Create an empty room with given wall type, floor type.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height
    
    wall_type : Cell
        Wall cell type

    floor_typr : Cell
        Floor cell type
    """

    M = Map(w, h, fill_cell=floor_type)

    # Create walls
    for x in range(0, w):
        M[x, 0] = wall_type()
        M[x, h - 1] = wall_type()
    for y in range(0, h):
        M[0, y] = wall_type()
        M[w - 1, y] = wall_type()

    return M
示例#4
0
def dungeon_bsp_tree(w=30, h=30, optimal_block_size=10):
    """
    Construct the dungeon map using binary space partitioning (BSP) algorithm.

    Visual
    ------
    Rectangular square-like rooms connected with 1-pixel corridors.
    These rooms evenly distributed across the map. All corridors are straight.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height

    optimal_block_size : int
        Optimal block size. Approximately equals to room size.
    """

    M = Map(w, h, fill_cell=C.wall_dungeon_rough)
    nodes = {}
    root = BSPNode('v', 1, 1, w - 1, h - 1)
    _recursive_split_tree_node(root, optimal_block_size)
    _load_leafs(root, nodes)
    _fill_rooms(M, nodes.values())
    all_edges = _get_all_edges(nodes.values())
    st_edges = _construct_spanning_tree(list(nodes.keys()), all_edges)
    _create_corridors(M, nodes, st_edges)
    return M
示例#5
0
def _room_cattle_pens(w, h, wall_material, floor_material):
    M = room_default(w, h, wall_type=C.wall_fence, floor_type=floor_material)
    M[w - 7, 0] = C.door_close_fence()
    for i in range(w * h // 3):
        grass_x = random.randint(1, w - 2)
        grass_y = random.randint(1, h - 2)
        M[grass_x, grass_y] = random.choice(
            [C.flora_grass, C.flora_cane, C.floor_grass])()
    num_cattles = h // 4 + 1
    cowshed = Map(4, 3, fill_cell=floor_material)
    for y in (1, 2):
        cowshed[0, y] = C.wall_fence()
    for y in range(0, 3):
        cowshed[3, y].put(T.water_trough())
    for x in (1, 2):
        cowshed[x, 2] = wall_material()
    cowshed[1, 1].put(T.bucket())
    cowshed_y = 1
    for x in range(num_cattles):
        copied_cowshed = deepcopy(cowshed)
        M.meld(copied_cowshed, w - 5, cowshed_y)
        cowshed_y += 3
    cows = [A.animal_cow() for _ in range(num_cattles)]
    M.scatter(1, 1, w - 5, h - 1, cows)

    return M
示例#6
0
def _room_jailer(w=5, h=5):
    M = Map(w, h, fill_cell=C.floor_flagged)

    # Create walls
    for x in range(0, w):
        M[x, 0] = C.wall_stone()
        M[x, h - 1] = C.wall_stone()
    for y in range(0, h):
        M[0, y] = C.wall_stone()
        M[w - 1, y] = C.wall_stone()
    M[w // 2, 0] = C.door_closed()

    # Place furniture and items in the room
    all_coord = [(w // 2, 1)]
    for item_class in (T.furniture_bed_single, T.furniture_chest,
                       T.furniture_chair, T.furniture_table,
                       T.furniture_torch):
        while True:
            x = random.randint(1, w - 2)
            y = random.randint(1, h - 2)
            if (x, y) not in all_coord:
                M[x, y].put(item_class())
                all_coord.append((x, y))
                break
    return M
示例#7
0
def _room_torture(w=5, h=5):
    M = Map(w, h, fill_cell=C.floor_flagged)

    # Create walls
    for x in range(0, w):
        M[x, 0] = C.wall_stone()
        M[x, h - 1] = C.wall_stone()
    for y in range(0, h):
        M[0, y] = C.wall_stone()
        M[w - 1, y] = C.wall_stone()
    M[w // 2, h - 1] = C.door_closed()
    M[w // 2 + 1, h - 2] = C.stairs_up()

    # Place furniture and items in the room
    M[w // 2, h // 2].put(T.furniture_torture())
    all_coord = [(w // 2, h - 2), (w // 2, h // 2), (w // 2 + 1, h - 2)]
    for item_class in (T.bones, T.bones_skull, T.tool_tongs):
        while True:
            x = random.randint(1, w - 2)
            y = random.randint(1, h - 2)
            if (x, y) not in all_coord:
                M[x, y].put(item_class())
                all_coord.append((x, y))
                break
    return M
示例#8
0
def world_test(w, h):
    heightmap = []
    for y in range(h):
        line = []
        for x in range(w):
            distance_corners = min([
                sqrt(x**2 + y**2),
                sqrt((w-x)**2 + y**2),
                sqrt(x**2 + (h-y)**2),
                sqrt((w-x)**2 + (h-y)**2)
            ])
            distance_edges = min([x*0.7, y*0.7, (w-x)*0.7, (h-y)*0.7])
            minus = (w + h) / 3
            c = random.randint(-w*0.7, -w*0.6) + distance_corners + distance_edges
            #print('{:> .1f}'.format(c), '', end='')
            line.append(c)
        heightmap.append(line)
    heightmap = diamond_square_2x(heightmap)
    heightmap = diamond_square_2x(heightmap, smooth_iteration=2)
    heightmap = diamond_square_2x(heightmap, smooth_iteration=3)
    heightmap = diamond_square_2x(heightmap, smooth_iteration=4)

    M = Map(len(heightmap[0]), len(heightmap), fill_cell=C.overworld_ocean)
    for y, line in enumerate(M.cells):
        for x, cell in enumerate(line):
            M[x, y] = C.overworld_ocean() if heightmap[y][x] < 0 else C.overworld_forest()
    
    M = _smooth_map(M)
    M = _smooth_map(M)
    return M
示例#9
0
def dungeon_grid_simple(w, h, room_size=4, delete_chance=0.33):
    """Dungeon map generator based on square room grid."""

    M = Map(w, h, fill_cell=C.floor_flagged)
    _create_room_grid(M, room_size=room_size)
    _create_doors(M, room_size=room_size)
    _crush_walls(M, room_size=room_size, delete_chance=delete_chance)
    return M
def _interior_garden(w, h, wall_material, floor_material):
    M = Map(w, h, fill_cell=C.floor_rocks)
    for x in range(w):
        M[x, h-1] = wall_material()
    M[w//2, h-1] = C.door_closed_wooden()
    M[w//2-1, h-1] = C.door_closed_wooden()

    return M
示例#11
0
def room_horse_box(w, h, orientation='left'):
    """
    Construct small horse box.
    """
    M = Map(w, h, fill_cell=C.floor_rocks)

    # Place watertrough and horse food.
    M[0, 0].put(T.water_trough())
    M[w - 1, 0] = C.door_closed()
    M[0, h - 1].put(T.water_trough())
    M[w - 1, h - 1] = C.wall_fence()
    if h > 2:
        for y in range(1, h - 1):
            M[0, y].put(T.water_trough())
            M[w - 1, y] = C.wall_fence()

    # Create horse box with animal or without.
    stable_with_horse_chance = random.random()
    all_coord = []
    while True:
        x = random.randint(1, w - 2)
        y = random.randint(0, h - 1)
        if (x, y) not in all_coord:
            M[x, y] = C.flora_grass()
            all_coord.append((x, y))
            break
    if stable_with_horse_chance > 0.3:
        while True:
            x = random.randint(1, w - 2)
            y = random.randint(0, h - 1)
            if (x, y) not in all_coord:
                M[x, y].put(T.farm_mangler())
                all_coord.append((x, y))
                break
        while True:
            x = random.randint(1, w - 2)
            y = random.randint(0, h - 1)
            if (x, y) not in all_coord:
                M[x, y].put(A.animal_horse())
                all_coord.append((x, y))
                break
    if orientation == 'right':
        M.hmirror()

    return M
示例#12
0
def building_stables(w=16, h=16):
    """
    Construct stables with storage and two rows of horse boxes.

    Constraints:

        - Map width and map height must be >= 16 and <=23.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height
    """

    # Initial checks. Don't accept too small/big stables
    if w < 16 or h < 16:
        raise ValueError('Building is too small: w or h < 16')
    elif w > 23 or h > 23:
        raise ValueError('Building is too big: w or h > 25')

    M = Map(w, h, fill_cell=C.floor_rocks)
    for x in range(w):
        for y in range(h):
            if random.random() > 0.75:
                M[x, y] = C.flora_grass()

    # Calculate w and h for storage, horse boxes and stables.
    horse_box_size_w = w // 2 - 4
    horse_box_size_h = 2
    stables_size_w = horse_box_size_w * 2 + 3
    stables_shift_h = (h - 1) % 3
    stables_size_h = h - stables_shift_h
    storage_size_w = w - stables_size_w + 1
    storage_size_h = h * 2 // 3
    storage_start_w = w - storage_size_w

    # Meld stables, storage, add dog.
    main_stables = room_horse_stables(stables_size_w, stables_size_h,
                                      horse_box_size_w, horse_box_size_h)
    M.meld(main_stables, 0, 0)
    main_storage = room_storage(storage_size_w, storage_size_h)
    M.meld(main_storage, storage_start_w, 0)
    M[w - (w - stables_size_w) // 2, storage_size_h].put(T.well())
    dog_place_x = random.randint(stables_size_w, w - 1)
    dog_place_y = random.randint(storage_size_h + 1, h - 1)
    M[dog_place_x, dog_place_y].put(A.animal_dog())
    if random.choice([True, False]):
        M.hmirror()

    return M
示例#13
0
def dungeon_cellular_simple(w=30,
                            h=30,
                            start_floor_chance=0.55,
                            smooth_level=3):
    """
    Construct the dungeon map using simple cellular automata.

    Note that this map can contain disconnected areas.

    Visual
    ------
    Natural-looking cave-like map.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height
    
    start_floor_chance : float
        Chance of the floor cell in the first map fill
    
    smooth_level : int
        Number of sequential smooth functions
    """

    M = Map(w, h, fill_cell=C.wall_cave)

    # Randomly fill all-but-border cells by floor with start_floor_chance probability
    for y, line in enumerate(M.cells[1:-1]):
        for x, _ in enumerate(line[1:-1]):
            chance = random.random()
            if chance <= start_floor_chance:
                M.cells[y + 1][x + 1] = C.floor_dirt()

    # Sequentially smooth the map smooth_level times
    for _ in range(smooth_level):
        M = _smooth_map(M)

    return M
示例#14
0
    def _gen_main(self, xsize, ysize, length, turn_chance=0.4):
        M = Map(xsize, ysize, fill_symbol='#')

        worm_x = random.randint(int(xsize * 0.3), int(xsize * 0.6))
        worm_y = random.randint(int(ysize * 0.3), int(ysize * 0.6))
        move = random.choice([NORTH, SOUTH, EAST, WEST])
        for _ in range(length):
            worm_x, worm_y, move = self._move_worm(M, worm_x, worm_y, move,
                                                   turn_chance)

        return M
示例#15
0
def _room_outdoor(w, h):
    M = Map(w, h, fill_cell=C.floor_rocks)
    for i in range(w*h//3):
        grass_x = random.randint(0, w-1)
        grass_y = random.randint(0, h-1)
        M[grass_x, grass_y] = random.choice([C.flora_grass, C.flora_tree, C.floor_grass])()
    for x in (1, 8):
        M[x, 0].put(T.furniture_table())
    for x in (0, 2, 7, 9):
        M[x, 0].put(T.furniture_stool())
    if w > 13:
        M[11, 0].put(T.furniture_table())
        M[10, 0].put(T.furniture_stool())
        M[12, 0].put(T.furniture_stool())
    for y in range(0, h):
        M[4, y] = C.floor_cobblestone()

    num_stables = (h - 5) // 2
    stables = Map(3, 2, fill_cell=C.void)
    for x in range(3):
        stables[x, 0] = C.wall_fence_thin()
    stables[2, 1] = C.wall_fence_thin()
    stables[0, 1] = C.door_close_fence()
    stables[1, 1].put(A.animal_horse())
    last_stable_y = h - 1
    for i in range(num_stables):
        stable_x = w - 3
        stable_y = 4 + (i * 2)
        M.meld(stables, stable_x, stable_y)
        last_stable_y = stable_y
    for x in range(w-3, w):
        M[x, last_stable_y + 2] = C.wall_fence_thin()
    M[2, h-1].put(T.sign_pointer())
    M[3, 0].put(T.light_torch())
    for y in (h//2-1, h//2):
        M[0, y].put(T.washtub())
    if w > 9:
        M[0, h//2+1].put(T.washtub())
    M[5, 0] = C.flora_flower()

    return M
示例#16
0
def dungeon_drunkard(w, h, length=None, turn_chance=0.4):
    M = Map(w, h, fill_cell=C.wall_dungeon_smooth)
    if not length:
        length = int(w * h / 2)
    worm_x = random.randint(int(w * 0.3), int(w * 0.6))
    worm_y = random.randint(int(h * 0.3), int(h * 0.6))
    move = random.choice([NORTH, SOUTH, EAST, WEST])
    for _ in range(length):
        M[worm_x, worm_y] = C.floor_flagged()
        worm_x, worm_y, move = _move_worm(M, worm_x, worm_y, move, turn_chance)

    return M
示例#17
0
def _room_prison_center(w=5, h=5):
    M = Map(w, h, fill_cell=C.floor_flagged)
    if w > 8 and h > 4:
        jailer_room = _room_jailer(w // 2 + 1, h)
        M.meld(jailer_room, 0, 0)
        torture_room = _room_torture(w - w // 2, h)
        M.meld(torture_room, (w - w // 2) - 1, 0)
    elif h > 8 and w > 4:
        jailer_room = _room_jailer(w, h // 2 + 1)
        M.meld(jailer_room, 0, 0)
        torture_room = _room_torture(w, h - h // 2)
        M.meld(torture_room, 0, (h - h // 2) - 1)
    else:
        for x in range(0, w):
            M[x, 0] = C.wall_stone()
            M[x, h - 1] = C.wall_stone()
        for y in range(0, h):
            M[0, y] = C.wall_stone()
            M[w - 1, y] = C.wall_stone()
        M[w // 2, 0] = C.door_closed()
        M[w // 2, h // 2] = C.stairs_up()

    return M
示例#18
0
def world_perlin_noise(w,
                       h,
                       scale=10.0,
                       octaves=6,
                       persistence=0.5,
                       lacunarity=2.0):
    M = Map(w, h)
    min_value = None
    max_value = None
    startx = random.randint(0, w * 100)
    starty = random.randint(0, h * 100)
    for y, line in enumerate(M.cells):
        for x, cell in enumerate(line):
            n = noise.pnoise2((startx + x) / scale, (starty + y) / scale,
                              octaves=octaves,
                              persistence=persistence,
                              lacunarity=lacunarity,
                              repeatx=w,
                              repeaty=h,
                              base=2)
            M[x, y].noise = n
            if min_value is None:
                min_value = n
            if max_value is None:
                max_value = n
            if n < min_value:
                min_value = n
            if n > max_value:
                max_value = n

    delta = (max_value - min_value) / 12

    for y, line in enumerate(M.cells):
        for x, cell in enumerate(line):
            if M[x, y].noise < min_value + delta:
                M[x, y] = C.overworld_ocean()
            elif M[x, y].noise < min_value + 5 * delta:
                M[x, y] = C.overworld_ocean()
            elif M[x, y].noise < min_value + 8 * delta:
                M[x, y] = C.overworld_plains()
            elif M[x, y].noise < min_value + 10 * delta:
                M[x, y] = C.overworld_forest()
            elif M[x, y].noise < min_value + 12 * delta:
                M[x, y] = C.overworld_mountain()
            else:
                M[x, y] = C.overworld_pinnacle()

    return M
示例#19
0
def world_test2(w=400, h=200):
    M = Map(w, h, fill_cell=C.overworld_ocean)
    '''
    plates = {i: (random.randint(0, w-1), random.randint(0, h-1)) for i in range(30)}
    for y, line in enumerate(M.cells):
        for x, cell in enumerate(line):
            intervals = {i: (plates[i][0] - x) ** 2 + (plates[i][1] - y) ** 2 for i in plates}
            #print(intervals)
            M[x, y].plate = min(intervals.items(), key=lambda item: item[1])[0]
    for y, line in enumerate(M.cells):
        for x, cell in enumerate(line):
            M[x, y] = P[M[x, y].plate]()
    for i in plates:
        M[plates[i]] = C.void()
    '''
    for y, line in enumerate(M.cells):
        for x, cell in enumerate(line):
            distance_corners = min([
                sqrt(x**2 + y**2),
                sqrt((w-x)**2 + y**2),
                sqrt(x**2 + (h-y)**2),
                sqrt((w-x)**2 + (h-y)**2)
            ])
            distance_edges = min([x, y, (w-x), (h-y)])
            minus = (w + h) / 3
            c = random.randint(-w*0.8, -w*0.6) + distance_corners + distance_edges
            #print('{:> .1f}'.format(c), '', end='')
            M[x, y] = C.overworld_ocean() if c < 0 else C.overworld_forest()
        #print()
    #for y in [0, h-1]:
    #    for x in range(M.w):
    #        M[x, y] = C.overworld_ocean()
    #for x in [0, w-1]:
    #    for y in range(M.h):
    #        M[x, y] = C.overworld_ocean()
    #for x in range(w//2-2, w//2+3):
    #    for y in range(h//2-2, h//2+3):
    #        M[x, y] = C.overworld_forest()
    
    #for y, line in enumerate(M.cells):
    #    for x, cell in enumerate(line):
    #        if sum(c.cname == 'overworld_forest' for c in M.surrounding(x, y)) >= 7:
    #            M[x, y] = C.overworld_forest()
    #M = _smooth_map(M)

    return M
示例#20
0
def _room_outdoor(w, h):
    M = Map(w, h, fill_cell=C.floor_rocks)
    for i in range(w * h // 3):
        grass_x = random.randint(1, w - 1)
        grass_y = random.randint(0, h - 2)
        M[grass_x, grass_y] = random.choice(
            [C.flora_grass, C.flora_tree, C.floor_grass])()
    M[w - 1, 0].put(T.washtub())
    for x in range(w):
        M[x, h - 1] = C.wall_fence_thin()
    for y in range(h - 1):
        M[0, y] = C.wall_fence_thin()
    for y in range(h - 1):
        M[3, y] = C.floor_rocks()
    M[3, h - 1] = C.door_close_fence()

    return M
示例#21
0
def _interior_bar(w, h, floor_material):
    M = Map(w, h, fill_cell=floor_material)
    M[0, 0].put(T.furniture_table())
    M[1, 0].put(T.furniture_stool())
    for x in range(w//3, w):
        for y in (h//3, h//3*2+1):
            M[x, y].put(T.furniture_longtable())
    M.scatter(w//3, h//3-1, w, h//3+2, [T.furniture_stool() for _ in range(w-w//3)], exclude=[(w//3, h//3-1)])
    M.scatter(w//3, h//3*2, w, h//3*2+3, [T.furniture_stool() for _ in range(w-w//3)], exclude=[(w//3, h//3*2+2)])
    M[0, h-1].put(T.furniture_table())
    M[1, h-1].put(T.furniture_stool())
    M[w-1, h-1].put(T.light_lantern_oil())
    return M
示例#22
0
def _interior_vending(w, h, wall_material, floor_material):
    M = Map(w, h, fill_cell=floor_material)
    for x in range(w):
        M[x, 2].put(T.furniture_longtable_showcase())
    M[0, 1].put(T.money_pile())
    M[w//2, 1].put(T.dining_mug())
    for x in range(1, w, 2):
        M[x, 3].put(T.furniture_stool())
    M[1, h-1].put(T.furniture_barrel())
    M[2, h-1].put(T.furniture_barrel())
    if w > 7:
        M[w-2, h-1].put(T.furniture_table())
        M[w-1, h-1].put(T.furniture_stool())
        M[w-3, h-1].put(T.furniture_stool())
    if h > 6:
        for x in range(1, w-2, 3):
            for y in range(5, h-2, 3):
                M[x, y].put(T.furniture_table())
                M[x+1, y].put(T.furniture_stool())
    return M
示例#23
0
def building_prison_linear(w=21, h=12, orientation='horizontal'):
    """
    Construct a linear prison building interior.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height
    
    """

    # Initial checks. Don't accept:
    # - Too small prisons
    # - Too wide prisons (for both horizontal and vertical orientations)
    if w < 11 or h < 11:
        raise ValueError('Building is too small: w or h < 11')
    if h > 16 and orientation == 'horizontal':
        raise ValueError(
            'Building is too big: h > 16 and orientation == "horizontal"')
    if w > 16 and orientation == 'vertical':
        raise ValueError(
            'Building is too big: w > 16 and orientation == "vertical"')

    if orientation == 'vertical':
        w, h = h, w
    M = Map(w, h, fill_cell=C.void)

    # Randomly choose where torture room and jailer room are.
    torture_left, jailer_right = None, None
    torture_left = random.choice([True, False])
    if torture_left:
        jailer_right = True
    else:
        jailer_right = False

    # Create jailer room. We have two situations: jailer room left/right.
    jailer_y_start = h // 4
    jailer_y_end = h // 3 * 2
    if jailer_right:
        # Create walls, floor and door
        for y in range(jailer_y_start, jailer_y_end + 1):
            M[w - 1, y] = C.wall_stone()
            M[w - 5, y] = C.wall_stone()
        for x in range(w - 5, w):
            M[x, jailer_y_start] = C.wall_stone()
            M[x, jailer_y_end] = C.wall_stone()
        for y in range(jailer_y_start + 1, jailer_y_end):
            for x in range(w - 4, w - 1):
                M[x, y] = C.floor_flagged()
        M[w - 5, h // 2] = C.door_closed()

        # Place some furniture
        M[w - 4, jailer_y_start + 1].put(T.furniture_table())
        M[w - 3, jailer_y_start + 1].put(T.furniture_table())
        M[w - 2, jailer_y_start + 1].put(T.furniture_chair())
        M[w - 4, jailer_y_end - 1].put(T.furniture_torch())
        M[w - 3, jailer_y_end - 1].put(T.furniture_bed_single())
        M[w - 2, jailer_y_end - 1].put(T.furniture_chest())
    else:
        # Create walls, floor and door
        for y in range(jailer_y_start, jailer_y_end + 1):
            M[0, y] = C.wall_stone()
            M[4, y] = C.wall_stone()
        for x in range(0, 5):
            M[x, jailer_y_start] = C.wall_stone()
            M[x, jailer_y_end] = C.wall_stone()
        for y in range(jailer_y_start + 1, jailer_y_end):
            for x in range(1, 4):
                M[x, y] = C.floor_flagged()
        M[4, h // 2] = C.door_closed()

        # Place some furniture
        M[1, jailer_y_start + 1].put(T.furniture_table())
        M[2, jailer_y_start + 1].put(T.furniture_table())
        M[3, jailer_y_start + 1].put(T.furniture_chair())
        M[1, jailer_y_end - 1].put(T.furniture_chest())
        M[2, jailer_y_end - 1].put(T.furniture_bed_single())
        M[3, jailer_y_end - 1].put(T.furniture_torch())

    # Create torture room. We have two situations: torture room left/right. torture_start and torture_end - x-coord.
    # If torture_end = 0 or 1, there is no place for room (only one or two walls)
    # So we expand torture room for a one cell's width (+4)
    if jailer_right:
        torture_start = 0
        torture_end = (w - 1) % 4
        if torture_end == 0:
            torture_end = 4
        if torture_end == 1:
            torture_end = 5

        # Create walls, floor and door
        for x in range(torture_start, torture_end + 1):
            M[x, 0] = C.wall_stone()
            M[x, h - 1] = C.wall_stone()
        for y in range(0, h - 1):
            M[torture_start, y] = C.wall_stone()
            M[torture_end, y] = C.wall_stone()
        for x in range(torture_start + 1, torture_end):
            for y in range(1, h - 1):
                M[x, y] = C.floor_flagged()
        M[torture_end, h // 2] = C.door_closed()

        # Place some furniture. If torture_end == 2 (just a corridor), then we set only stairs.
        M[torture_end - 1, h - 2] = C.stairs_up()
        if torture_end != 2:
            M[(torture_end - torture_start) // 2,
              h // 2].put(T.furniture_torture())
            all_coord = [(torture_end - 1, h - 2),
                         ((torture_end - torture_start) // 2, h // 2)]
            for item_class in (T.bones, T.bones_skull, T.tool_tongs):
                while True:
                    x = random.randint(1, torture_end - 1)
                    y = random.randint(1, h - 2)
                    if (x, y) not in all_coord:
                        M[x, y].put(item_class())
                        all_coord.append((x, y))
                        break
    else:
        # If torture room is right, we are using the torture room width for calculations.
        # If torture_width = 7, then we reduce torture room for a one cell's width (-4).
        torture_width = w % 4 + 4
        if torture_width == 7:
            torture_width = 3
        torture_end = w - 1

        # Create walls, floor and door
        for x in range(w - torture_width, torture_end):
            M[x, 0] = C.wall_stone()
            M[x, h - 1] = C.wall_stone()
        for y in range(0, h):
            M[w - torture_width, y] = C.wall_stone()
            M[torture_end, y] = C.wall_stone()
        for x in range(w - torture_width + 1, torture_end):
            for y in range(1, h - 1):
                M[x, y] = C.floor_flagged()
        M[w - torture_width, h // 2] = C.door_closed()

        # Place some furniture. If torture_width = 3 (just a corridor), then we set only stairs.
        M[w - 2, h - 2] = C.stairs_up()
        if torture_width != 3:
            M[w - 2, h // 2].put(T.furniture_torture())
            all_coord = [(w - 1, h - 2), (w - 2, h // 2)]
            for item_class in (T.bones, T.bones_skull, T.tool_tongs):
                while True:
                    x = random.randint(w - torture_width + 1, w - 2)
                    y = random.randint(1, h - 2)
                    if (x, y) not in all_coord:
                        M[x, y].put(item_class())
                        all_coord.append((x, y))
                        break

    # Fill corridor with a floor
    if jailer_right:
        cor_start = torture_end + 1
        cor_end = w - 6
    else:
        cor_start = 5
        cor_end = w - torture_width - 1
    if h % 2 == 1:
        for x in range(cor_start, cor_end + 1):
            M[x, h // 2] = C.floor_flagged()
    else:
        for x in range(cor_start, cor_end + 1):
            M[x, h // 2 - 1] = C.floor_flagged()
            M[x, h // 2] = C.floor_flagged()

    # Place prison cells
    number_of_cells = (cor_end - cor_start + 2) // 4
    for cell_index in range(number_of_cells):
        cell_x = (cor_start - 1) + (cell_index * 4)

        # Place upper cell
        M_cell = room_prison_cell(w=5, h=(h - 1) // 2)
        M.meld(M_cell, cell_x, 0)

        # Place lower cell
        M_cell = room_prison_cell(w=5, h=(h - 1) // 2, direction='up')
        M.meld(M_cell, cell_x, h // 2 + 1)

    if orientation == 'vertical':
        M.transpose()

    return M
示例#24
0
def building_house_tworoom(w=12,
                           h=9,
                           wall_material=None,
                           floor_material=None,
                           has_exterior=True,
                           direction='down'):
    """
    Construct house with living room, kitchen and outdoor.

    Constraints:

        - Map width and map height must be >= 9
        - Map width and map height must be <= 15
        - Wall material must be 'block', 'plank', 'brick' or 'stone'.
        - Floor material must be 'dirt', 'parquet' or 'cobblestone'.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height

    wall_material : str
        Wall's material.

    floor_material : str
        Floor's material.

    has_exterior : bool
        Flag that generates an exterior of the house.

    direction : str
        Direction of the house. Can be 'up', 'down', 'left' or 'right'.
    """
    # Initial checks. Don't accept too small/big house
    if w < 9 or h < 9:
        raise ValueError('Building is too small: w or h < 9')
    elif w > 12 or h > 12:
        raise ValueError('Building is too big: w or h > 15')
    # Choose materials
    if not wall_material:
        wall_material = random.choice(
            [C.wall_block, C.wall_plank, C.wall_brick, C.wall_stone])
    elif wall_material not in (['block', 'plank', 'brick', 'stone']):
        raise ValueError(
            'Wall material should be "block", "plank", "brick" or "stone"')
    if wall_material == 'block':
        wall_material = C.wall_block
    elif wall_material == 'plank':
        wall_material = C.wall_plank
    elif wall_material == 'brick':
        wall_material = C.wall_brick
    elif wall_material == 'stone':
        wall_material = C.wall_stone

    if not floor_material:
        floor_material = random.choice(
            [C.floor_dirt, C.floor_parquet, C.floor_cobblestone])
    elif floor_material not in (['dirt', 'parquet', 'cobblestone']):
        raise ValueError(
            'Floor material should be "dirt", "parquet" or "cobblestone"')
    if floor_material == 'dirt':
        floor_material = C.floor_dirt
    elif floor_material == 'parquet':
        floor_material = C.floor_parquet
    elif floor_material == 'cobblestone':
        floor_material = C.floor_cobblestone

    M = Map(w, h, fill_cell=C.void)
    main_room_h = h // 3 * 2
    living_room_w = w // 2 + 1
    living_room_h = h - main_room_h + 1
    main_room = _room_main(w, main_room_h, wall_material, floor_material)
    M.meld(main_room, 0, 0)
    living_room = _room_living(living_room_w, living_room_h, wall_material,
                               floor_material)
    M.meld(living_room, w - living_room_w, main_room_h - 1)
    if has_exterior:
        outdoor = _room_outdoor(w - living_room_w, living_room_h - 1)
        M.meld(outdoor, 0, main_room_h)
    if random.choice([True, False]):
        M.hmirror()

    if direction == 'up':
        M.vmirror()
    elif direction == 'left':
        M.transpose()
    elif direction == 'right':
        M.transpose()
        M.hmirror()

    return M
示例#25
0
def room_prison_cell(w=5, h=5, direction='down'):
    if direction == 'left' or direction == 'right':
        w, h = h, w
    M = Map(w, h, fill_cell=C.floor_flagged)
    prison_cell_type = random.choice(['with_prisoner', 'with_bones', 'with_blood', 'with_spider'])
    
    # Create walls
    for x in range(0, w):
        M[x, 0] = C.wall_stone()
        M[x, h-1] = C.wall_stone()
    for y in range(0, h):
        M[0, y] = C.wall_stone()
        M[w-1, y] = C.wall_stone()
    
    # Create prison bars and door
    M[1, h-1] = C.wall_bars()
    M[3, h-1] = C.wall_bars()
    M[2, h-1] = C.door_closed_bars()

    # Place some things
    all_coord = []
    if prison_cell_type == 'with_prisoner':
        for item_class in (T.furniture_napsack, T.bucket, T.furniture_torch):
            while True:
                x = random.randint(1, 3)
                y = random.randint(1, h-2)
                if (x, y) not in all_coord:
                    M[x, y].put(item_class())
                    all_coord.append((x,y))
                    break
    elif prison_cell_type == 'with_bones':
        for item_class in (T.bones, T.bones_skull):
            while True:
                x = random.randint(1, 3)
                y = random.randint(1, h-2)
                if (x, y) not in all_coord:
                    M[x, y].put(item_class())
                    all_coord.append((x, y))
                    break
    elif prison_cell_type == 'with_blood':
        for item_class in (T.bones_remains, T.effect_blood):
            while True:
                x = random.randint(1, 3)
                y = random.randint(1, h-2)
                if (x, y) not in all_coord:
                    M[x, y].put(item_class())
                    all_coord.append((x, y))
                    break
    elif prison_cell_type == 'with_spider':
        for item_class in (T.web, T.web, A.animal_spider):
            while True:
                x = random.randint(1, 3)
                y = random.randint(1, h-2)
                if (x, y) not in all_coord:
                    M[x, y].put(item_class())
                    all_coord.append((x, y))
                    break
    
    if direction == 'up':
        M.vmirror()
    elif direction == 'left':
        M.transpose()
    elif direction == 'right':
        M.transpose()
        M.hmirror()

    return M
def building_medieval_mansion(w=25, h=25, wall_material=None, floor_material=None, direction='down'):
    """
    Construct medieval mansion with living rooms, kitchen, library, treasury, servant's room and outdoor.

    Constraints:

        - Map width and map height must be >= 20
        - Map width and map height must be <= 30
        - Wall material must be 'block', 'plank', 'brick' or 'stone'.
        - Floor material must be 'dirt', 'parquet' or 'cobblestone'.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height

    wall_material : str
        Wall's material.

    floor_material : str
        Floor's material.

    direction : str
        Direction of the house. Can be 'up', 'down', 'left' or 'right'.
    """
    # Initial checks. Don't accept too small/big house
    if w < 20 or h < 20:
        raise ValueError('Building is too small: w or h < 20')
    elif w > 30 or h > 30:
        raise ValueError('Building is too big: w or h > 30')
    # Choose materials
    if not wall_material:
        wall_material = random.choice([C.wall_block, C.wall_plank, C.wall_brick, C.wall_stone])
    elif wall_material not in (['block', 'plank', 'brick', 'stone']):
        raise ValueError('Wall material should be "block", "plank", "brick" or "stone"')
    if wall_material == 'block':
        wall_material = C.wall_block
    elif wall_material == 'plank':
        wall_material = C.wall_plank
    elif wall_material == 'brick':
        wall_material = C.wall_brick
    elif wall_material == 'stone':
        wall_material = C.wall_stone

    if not floor_material:
        floor_material = random.choice([C.floor_dirt, C.floor_parquet, C.floor_cobblestone])
    elif floor_material not in (['dirt', 'parquet', 'cobblestone']):
        raise ValueError('Floor material should be "dirt", "parquet" or "cobblestone"')
    if floor_material == 'dirt':
        floor_material = C.floor_dirt
    elif floor_material == 'parquet':
        floor_material = C.floor_parquet
    elif floor_material == 'cobblestone':
        floor_material = C.floor_cobblestone

    M = Map(w, h, fill_cell=C.void)
    default_room_w = w // 4 + 1
    default_room_h = h // 4
    library_h = h // 2 - 1
    second_bedroom_h = h // 4 + 2

    treasury = _room_treasury(default_room_w, default_room_h, wall_material, floor_material)
    M.meld(treasury, 0, 0)
    bedroom = _room_bedroom(default_room_w, h-second_bedroom_h-default_room_h+2, wall_material, floor_material)
    M.meld(bedroom, 0, default_room_h-1)
    second_bedroom = _room_second_bedroom(default_room_w, second_bedroom_h, wall_material, floor_material)
    M.meld(second_bedroom, 0, h-second_bedroom_h)
    sacrifice = _room_of_sacrifice(default_room_w, default_room_h, wall_material, floor_material)
    M.meld(sacrifice, w-default_room_w, 0)
    kitchen = _room_kitchen(default_room_w, h-default_room_h*2+1, wall_material, floor_material)
    M.meld(kitchen, w-default_room_w, default_room_h-1)
    servant = _room_servant(default_room_w, default_room_h+1, wall_material, floor_material)
    M.meld(servant, w-default_room_w, h-default_room_h-1)
    library = _room_library(w-default_room_w*2+2, library_h, wall_material, floor_material)
    M.meld(library, default_room_w-1, 0)
    garden = _interior_garden(w-default_room_w*2, h-library_h, wall_material, floor_material)
    M.meld(garden, default_room_w, library_h)

    if random.choice([True, False]):
        M.hmirror()
    if direction == 'up':
        M.vmirror()
    elif direction == 'left':
        M.transpose()
    elif direction == 'right':
        M.transpose()
        M.hmirror()

    return M
示例#27
0
def building_prison_rectangular(w=17, h=17):
    """
    Construct a rectangular prison interior.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height
    
    """

    # Initial checks. Don't accept too small prisons
    if w < 17 or h < 17:
        raise ValueError('Building is too small: w or h < 17')
    M = Map(w, h, fill_cell=C.void)

    # Calculate prison cells sizes depends on prison size.
    cell_shift_w = (w - 1) % 4
    if cell_shift_w == 1:
        left_w = 4
        right_w = 5
    elif cell_shift_w == 2:
        left_w = 5
        right_w = 5
    elif cell_shift_w == 3:
        left_w = 5
        right_w = 6
    else:
        left_w = 4
        right_w = 4

    cell_shift_h = (h - 1) % 4
    if cell_shift_h == 1:
        top_h = 4
        bottom_h = 5
    elif cell_shift_h == 2:
        top_h = 5
        bottom_h = 5
    elif cell_shift_h == 3:
        top_h = 5
        bottom_h = 6
    else:
        top_h = 4
        bottom_h = 4

    # Calculate the number of prison cells fits horizontally/vertically
    num_cell_w = (w - left_w - right_w) // 4
    num_cell_h = (h - top_h - bottom_h) // 4

    # Place cells
    for cell_index in range(num_cell_w):
        cell_x = left_w + (cell_index * 4)

        # Place upper cell
        M_cell = room_prison_cell(w=5, h=top_h + 1)
        M.meld(M_cell, cell_x, 0)

        # Place lower cell
        M_cell = room_prison_cell(w=5, h=bottom_h + 1, direction='up')
        M.meld(M_cell, cell_x, h - bottom_h - 1)

    for cell_index in range(num_cell_h):
        cell_y = top_h + (cell_index * 4)

        # Place left cell
        M_cell = room_prison_cell(w=left_w + 1, h=5, direction='left')
        M.meld(M_cell, 0, cell_y)

        # Place right cell
        M_cell = room_prison_cell(w=right_w + 1, h=5, direction='right')
        M.meld(M_cell, w - right_w - 1, cell_y)

    center_room_w = w - (left_w + 1) - (right_w + 1) - 2
    center_room_h = h - (top_h + 1) - (bottom_h + 1) - 2

    center_room = _room_prison_center(center_room_w, center_room_h)
    M.meld(center_room, left_w + 2, top_h + 2)

    # Construct the corridor
    for x in range(left_w + 1, w - right_w - 1):
        M[x, top_h + 1] = C.floor_flagged()
        M[x, h - bottom_h - 2] = C.floor_flagged()
    for y in range(top_h + 1, h - bottom_h - 1):
        M[left_w + 1, y] = C.floor_flagged()
        M[w - right_w - 2, y] = C.floor_flagged()

    return M
示例#28
0
def building_hunter_robber_house(size=10, material=None, house_type=None):
    """
    Construct the hunter or robber house.

    Parameters
    ----------
    size : int
        Square map size. This attribute will be applied for both `w` and `h`.
    
    material : string
        Wall material. Can be "wooden", "stone" or None. If None, a random
        material will be chosen.

    house_type : string
        Type of the house. Can be "hunter" or "robber". If None, a random 
        type will be chosen.
    """

    # Initial check. Don't accept too small/big building
    if size < 8 or size > 17:
        raise ValueError(
            'Building is too small or too big: size < 8 or size > 17')

    # Choose materials
    if not material:
        material = random.choice(['wooden', 'stone'])
    if material not in ('wooden', 'stone'):
        raise ValueError('Material should be "stone" or "wooden"')
    wall_cell_type = C.wall_stone if material == 'stone' else C.wall_plank
    floor_cell_type = C.floor_flagged if material == 'stone' else C.floor_plank

    # Choose between robber house and hunter house
    if not house_type:
        house_type = random.choice(['robber', 'hunter'])
    if house_type not in ('robber', 'hunter'):
        raise ValueError('Type should be "robber" or "hunter"')

    M = Map(size, size, fill_cell=floor_cell_type)

    # Create outward walls
    for x in range(size):
        M[x, 0] = wall_cell_type()
        M[x, size - 1] = wall_cell_type()
    for y in range(size):
        M[0, y] = wall_cell_type()
        M[size - 1, y] = wall_cell_type()

    # Create door
    door_random = random.choice([True, False])
    door_param = size // 3 * 2
    if door_random:
        M[door_param, size - 1] = C.door_closed()
    else:
        M[0, door_param] = C.door_closed()

    # Place bonfire or hearth in the middle of the room. Place chairs
    M[size // 2 - 1, size // 2].put(T.furniture_chair())
    M[size // 2 + 1, size // 2].put(T.furniture_chair())
    if house_type == 'hunter':
        M[size // 2, size // 2].put(T.furniture_hearth())
    else:
        M[size // 2, size // 2].put(T.bonfire())

    # Randomly choose where escape is. Place stairs and wardrobes.
    escape = random.choice([True, False])
    if escape:
        M[size - 2, 1] = C.stairs_down()
        if house_type == 'robber':
            M[size - 3, 1].put(T.furniture_closet())
            M[size - 3, 2].put(T.furniture_closet())
            M[size - 2, 2].put(T.furniture_closet())
        elif house_type == 'hunter':
            M[size - 2, size - 2].put(T.furniture_closet())
    else:
        M[1, 1] = C.stairs_down()
        if house_type == 'robber':
            M[2, 1].put(T.furniture_closet())
            M[2, 2].put(T.furniture_closet())
            M[1, 2].put(T.furniture_closet())
        elif house_type == 'hunter':
            M[size - 2, size - 2].put(T.furniture_closet())

    # Place beds near walls
    beds_start = 1 if escape else size // 3 + 1
    beds_end = size // 2 if escape else size - 1
    if escape:
        for x in range(beds_start, beds_end + 1, 2):
            M[x, 1].put(T.furniture_bed_single())
    else:
        for x in range(beds_start + 1, beds_end, 2):
            M[x, 1].put(T.furniture_bed_single())

    # Place chests
    M[size - 2, size // 2 - 1].put(T.furniture_chest())
    M[size - 2, size // 2].put(T.furniture_chest())

    # Place table with chairs
    for x in range(size // 5, size // 2):
        M[x, size - 2].put(T.furniture_longtable())
    for x in range(size // 5 + 1, size // 2, 2):
        M[x, size - 3].put(T.furniture_chair())

    return M
示例#29
0
def building_housebarn(w=30, h=15, material=None):
    """
    Construct the housebarn (also known as longhouse) building interior.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height
    
    material : string
        Wall material. Can be "wooden", "stone" or None. If None, a random
        material will be chosen.
    """

    # Initial checks. Don't accept:
    # - Too small buildings
    # - Too long/square buildings
    # - Wall types that are not "stone" or "wooden"
    if w < 10 or h < 10:
        raise ValueError('Building is too small: w/h < 10')
    if not material:
        material = random.choice(['wooden', 'stone'])
    if material not in ('wooden', 'stone'):
        raise ValueError('Material should be "stone" or "wooden"')
    wall_cell_type = C.wall_stone if material == 'stone' else C.wall_plank

    is_horizontal = True if w >= h else False
    if is_horizontal:
        if w < h * 2 or w > h * 3:
            raise ValueError('Building is too long or too short.')
    else:
        if h < w * 2 or h > w * 3:
            raise ValueError('Building is too long or too short.')

    # If parameters are vertial, we firstly construct horizontal building then transpose it.
    # It allows not to use two additional different subtypes of the building which will simplify the code.
    if not is_horizontal:
        w, h = h, w
    M = Map(w, h, fill_cell=C.floor_flagged)

    # Create outward walls
    for x in range(w):
        M[x, 0] = wall_cell_type()
        M[x, h - 1] = wall_cell_type()
    for y in range(h):
        M[0, y] = wall_cell_type()
        M[w - 1, y] = wall_cell_type()

    # Randomly choose where the living part is
    living_left = random.choice([True, False])
    living_wall_x = None
    barn_wall_x = None

    # Place central doors/corridor and calculate X-positions for vertical walls
    if w % 2 == 0:
        M[w // 2, 0] = C.floor_flagged()
        M[w // 2 - 1, 0] = C.floor_flagged()
        M[w // 2, h - 1] = C.floor_flagged()
        M[w // 2 - 1, h - 1] = C.floor_flagged()
        living_wall_x = (w // 2 - 3) if living_left else (w // 2 + 2)
        barn_wall_x = (w // 2 + 2) if living_left else (w // 2 - 3)
    else:
        M[w // 2, 0] = C.door_closed_wooden()
        M[w // 2, h - 1] = C.door_closed_wooden()
        living_wall_x = (w // 2 - 2) if living_left else (w // 2 + 2)
        barn_wall_x = (w // 2 + 2) if living_left else (w // 2 - 2)

    # Place vertical walls
    for i in range(1, h // 3):
        M[living_wall_x, i] = wall_cell_type()
        M[living_wall_x, h - i - 1] = wall_cell_type()
    for i in range(1, h - 1):
        M[barn_wall_x, i] = C.wall_fence_thin()
    M[barn_wall_x, h // 2] = C.door_closed_wooden()

    # Create living room:
    # Set initial coordinates
    lx_start = 1 if living_left else living_wall_x + 1
    lx_end = living_wall_x - 1 if living_left else w - 1
    beds_dx = int((lx_end - lx_start) % 2 == 0 and not living_left)
    beds_dy = random.choice([0, 1])

    # Place beds near walls or at 1 cell from walls
    for bed_x in range(lx_start + beds_dx, lx_end, 2):
        M[bed_x, 1 + beds_dy].put(T.furniture_bed_single())
        M[bed_x, h - 2 - beds_dy].put(T.furniture_bed_single())

    # Place bonfire in the middle of the room or hearth on the side of the room
    is_bonfire = random.choice([True, False])
    if is_bonfire:
        M[(lx_start + lx_end) // 2, h // 2].put(T.bonfire())
    elif living_left:
        M[1, h // 2].put(T.furniture_hearth())
    else:
        M[w - 2, h // 2].put(T.furniture_hearth())

    # Create barn:
    # Set initial coordinates
    bx_start = 1 if not living_left else barn_wall_x + 1
    bx_end = barn_wall_x - 1 if not living_left else w - 2

    # Fill the barn floor with dirt
    for x in range(bx_start, bx_end + 1):
        for y in range(1, h - 1):
            M[x, y] = C.floor_dirt()

    is_central_barn = random.choice([True, False])
    if is_central_barn:
        # Central barn: stalls in the center, two waterthroughs on the side
        for y in range(h // 3, h * 2 // 3):
            M[bx_start + 2, y] = C.wall_fence_thin()
        for x in range(bx_start + 3, bx_end - 2, 2):
            M[x, h // 2] = C.wall_fence_thin()
            M[x, h // 2 - 1].put(T.farm_mangler())
            M[x, h // 2 + 1].put(T.farm_mangler())
            for y in range(h // 3, h * 2 // 3):
                M[x + 1, y] = C.wall_fence_thin()
        for x in range(bx_start + 1, bx_end):
            M[x, 1].put(T.water_trough())
            M[x, h - 2].put(T.water_trough())
    else:
        # Side barn: stalls on the side, one waterthrough in the center
        for x in range(bx_start, bx_end - 1, 2):
            M[x, 1].put(T.farm_mangler())
            M[x, h - 2].put(T.farm_mangler())
            for y in range(1, h // 3):
                M[x + 1, y] = C.wall_fence_thin()
            for y in range(h * 2 // 3, h - 1):
                M[x + 1, y] = C.wall_fence_thin()
        for x in range(bx_start + 2, bx_end - 1):
            M[x, h // 2].put(T.water_trough())

    # Transpose the building if it should be vertical
    if not is_horizontal:
        M.transpose()

    return M
示例#30
0
def building_kitchengarden(w=17,
                           h=17,
                           wall_material=None,
                           floor_material=None,
                           direction='down'):
    """
    Construct kitchen garden with big storage, garden beds and cattle pens.

    Constraints:

        - Map width and map height must be >= 17
        - Map width and map height must be <= 22
        - Wall material must be 'block', 'plank' or 'stone'.
        - Floor material must be 'grit' or 'rocks'.

    Parameters
    ----------
    w : int
        Map width

    h : int
        Map height

    wall_material : str
        Wall's material.

    floor_material : str
        Floor's material.

    direction : str
        Direction of the kitchen garden. Can be 'up', 'down', 'left' or 'right'.
    """
    # Initial checks. Don't accept too small/big kitchen garden
    if w < 17 or h < 17:
        raise ValueError('Building is too small: w or h < 17')
    elif w > 22 or h > 22:
        raise ValueError('Building is too big: w or h > 22')
    # Choose materials
    if not wall_material:
        wall_material = random.choice(
            [C.wall_block, C.wall_plank, C.wall_stone])
    elif wall_material not in (['block', 'plank', 'stone']):
        raise ValueError('Wall material should be "block", "plank" or "stone"')
    if wall_material == 'block':
        wall_material = C.wall_block
    elif wall_material == 'plank':
        wall_material = C.wall_plank
    elif wall_material == 'stone':
        wall_material = C.wall_stone

    if not floor_material:
        floor_chance = random.random()
        if floor_chance > 0.3:
            floor_material = C.floor_rocks
        else:
            floor_material = C.floor_grit
    elif floor_material not in (['grit', 'rocks']):
        raise ValueError('Floor material should be "grit" or "rocks"')
    if floor_material == 'grit':
        floor_material = C.floor_grit
    elif floor_material == 'rocks':
        floor_material = C.floor_rocks

    M = Map(w, h, fill_cell=floor_material)
    storage_w = w // 3 * 2
    storage_h = h // 4 + 1
    garden_beds_w = w // 2

    for i in range(w * h // 3):
        grass_x = random.randint(1, w - 1)
        grass_y = random.randint(0, h - 2)
        M[grass_x, grass_y] = random.choice(
            [C.flora_grass, C.flora_tree, C.floor_grass])()
    garden_beds = _room_garden_beds(garden_beds_w, h - storage_h + 1,
                                    wall_material, floor_material)
    M.meld(garden_beds, 0, storage_h - 1)
    cattle_pens = _room_cattle_pens(w - garden_beds_w + 1, h - storage_h + 1,
                                    wall_material, floor_material)
    M.meld(cattle_pens, garden_beds_w - 1, storage_h - 1)
    storage = _room_storage(storage_w, storage_h, wall_material,
                            floor_material, garden_beds_w)
    M.meld(storage, 0, 0)
    for x in range(storage_w, w - 1):
        M[x, storage_h // 2] = floor_material()
    for y in range(storage_h // 2, storage_h - 1):
        M[storage_w + 1, y] = floor_material()

    if random.choice([True, False]):
        M.hmirror()
    if direction == 'up':
        M.vmirror()
    elif direction == 'left':
        M.transpose()
    elif direction == 'right':
        M.transpose()
        M.hmirror()

    return M