Skip to content

Commit

Permalink
All tile/map data is properly managed by state
Browse files Browse the repository at this point in the history
- Removed tilemap and outline
- Properly handling images and walls etc...
- Improvements are possible now that it's more standardized
Closes #107
  • Loading branch information
tredfern committed May 28, 2021
1 parent 99ad3fa commit e7d9b11
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 355 deletions.
183 changes: 66 additions & 117 deletions game/rules/map/generators/dungeon.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ local terrain = require "game.rules.map.terrain"
local createCorridor = require "game.rules.map.generators.corridor"
local Rooms = require "game.rules.map.rooms"
local placeItems = require "game.rules.map.generators.place_items"
local Outline = require "game.rules.map.outline"
local TileMap = require "game.rules.map.tile_map"
local Walls = require "assets.graphics.walls"
local Position = require "game.rules.world.position"
local Orientation = require "game.rules.world.orientation"
local Actions = require "game.rules.map.actions"
local Selectors = require "game.rules.map.selectors"
local store = require "game.store"
local generator = {}

Expand Down Expand Up @@ -73,10 +72,10 @@ function generator.divide(node, current_level, max_levels)
return node
end

function generator.create_rooms(node, outline, level)
function generator.create_rooms(node, level)
if node.left or node.right then
generator.create_rooms(node.left, outline, level)
generator.create_rooms(node.right, outline, level)
generator.create_rooms(node.left, level)
generator.create_rooms(node.right, level)
return
end

Expand All @@ -87,32 +86,32 @@ function generator.create_rooms(node, outline, level)
local y = node.y + love.math.random(node.height - height)

node.room = Rooms.rectangular(x, y, width, height, level)
outline:addRoom(node.room)
store.dispatch(Actions.addRoom(node.room))
end

function generator.generate(width, height, levels)
local outline = Outline:new(width, height, levels)

for level = 1, levels do
local root = generator.create_node(1, 1, width, height)
generator.divide(root, 1, DEPTH)
generator.create_rooms(root, outline, level)
generator.create_corridors(root, outline, level)
generator.create_rooms(root, level)
generator.create_corridors(root, level)

-- Connect to lower floor
generator.connectLevels(outline, level, level - 1)
generator.connectLevels(level, level - 1)
end
local tileMap = generator.buildTileMap(outline)
placeItems(outline, tileMap)
return outline, tileMap

generator.fillWalls(width, height, levels)
generator.calculateSprites(width, height, levels)
placeItems()
generator.addFeatures()

end


function generator.create_corridors(node, outline, level)
function generator.create_corridors(node, level)
if node.left or node.right then
generator.create_corridors(node.left, outline, level)
generator.create_corridors(node.right, outline, level)
generator.create_corridors(node.left, level)
generator.create_corridors(node.right, level)
end

--Connect the left and right nodes together...
Expand All @@ -127,110 +126,58 @@ function generator.create_corridors(node, outline, level)
local end_y = love.math.random(end_room.y, end_room.y + end_room.height - 1)

local corridor = createCorridor(start_x, start_y, end_x, end_y, level)
outline:addCorridor(corridor)
store.dispatch(Actions.addCorridor(corridor))
end
end

---
-- Moving soon
---

function generator.buildTileMap(outline)
local map = TileMap:new()

for _, room in ipairs(outline.rooms) do
generator.buildRoom(map, room)
end

for _, corridor in ipairs(outline.corridors) do
generator.buildCorridor(map, corridor)
end

generator.fillWalls(map)
generator.calculateSprites(map)
generator.addFeatures(outline, map)

return map
end

function generator.buildCorridor(map, corridor)
for _, square in ipairs(corridor.path) do
local p = Position(square.x, square.y, corridor.level)
local tile = map:getTile(p)
if tile == nil or tile.terrain == nil then
map:updateTile(p, { terrain = terrain.list.corridor })
end
end
end

function generator.fillWalls(map)
for x = 1, map.width do
for y = 1, map.height do
for z = 1, map.levels do
local pos = Position(x, y, z)
if map:getTile(pos) == nil then
local neighbors = map:getNeighbors(pos)
local list = tables.keysToList(neighbors)
if tables.any(list, function(tile) return tile.position.z == z and not tile.isWall end) then
map:updateTile(pos, { terrain = terrain.list.wall, isWall = true })
store.dispatch(Actions.setTileProperties(pos, { terrain = terrain.list.wall, isWall = true }))
end
end
function generator.fillWalls(width, height, levels)
for pos in Position.box(Position(1, 1, 1), Position(width, height, levels)) do
if Selectors.getTile(store.getState(), pos) == nil then
local neighbors = Selectors.getNeighbors(store.getState(), pos)
local list = tables.keysToList(neighbors)
if tables.any(list, function(tile) return tile.position.z == pos.z and not tile.isWall end) then
store.dispatch(Actions.setTileProperties(
pos,
{ terrain = terrain.list.wall, isWall = true, blocksMovement = true }
))
end
end
end
end

function generator.buildRoom(map, room)
for x = 0, room.width - 1 do
for y = 0, room.height - 1 do
map:updateTile(Position(room.x + x, room.y + y, room.level), { terrain = terrain.list.room, room = room })
end
end
end

function generator.calculateSprites(map)
function generator.calculateSprites(width, height, levels)
local sprite = require "game.rules.graphics.sprite"
for x = 1, map.width do
for y=1,map.height do
for z = 1,map.levels do
local tile = map:getTile(Position(x, y, z))
local neighbors = map:getNeighbors(Position(x, y, z))

if tile and tile.terrain then
if tile.terrain.images then
local tileImage = sprite.fromImage(tables.pickRandom(tile.terrain.images))
tileImage.color = tile.terrain.color
store.dispatch(Actions.setTileProperties(Position(x, y, z), { sprite = tileImage }))
end
if tile.isWall then
local sequence = { "n", "s", "e", "w" }
local index = ""

for _, v in ipairs(sequence) do
if neighbors[v] and neighbors[v].isWall then
index = index .. v
end
end
for pos in Position.box(Position(1, 1, 1), Position(width, height, levels)) do
local neighbors = Selectors.getNeighbors(store.getState(), pos)
local tile = neighbors.center
if tile and tile.terrain then
if tile.terrain.images then
local tileImage = sprite.fromImage(tables.pickRandom(tile.terrain.images))
tileImage.color = tile.terrain.color
store.dispatch(Actions.setTileProperties(pos, { sprite = tileImage }))
end
if tile.isWall then
local sequence = { "n", "s", "e", "w" }
local index = ""

store.dispatch(Actions.setTileProperties(Position(x, y, z), { sprite = Walls[index] }))
for _, v in ipairs(sequence) do
if neighbors[v] and neighbors[v].isWall then
index = index .. v
end
end

store.dispatch(Actions.setTileProperties(pos, { sprite = Walls[index] }))
end
end
end
end

function generator.getRandomLocation(outline)
local r = tables.pickRandom(outline.rooms)
local x = math.random(r.x, r.x + r.width)
local y = math.random(r.y, r.y + r.height)
return x, y, r.level
end

function generator.addFeatures(outline, map)
for _, r in ipairs(outline.rooms) do
function generator.addFeatures()
local rooms = Selectors.getRooms(store.getState())
for _, r in ipairs(rooms) do
if not tables.isEmpty(r.features) then
for _, f in ipairs(r.features) do
if f.type == "LADDER_UP" then
Expand All @@ -242,34 +189,35 @@ function generator.addFeatures(outline, map)
end

-- search parameter to find where corridor joins room and add a door

local top, bottom = r.y - 1, r.y + r.height + 1
for x = r.x, r.x + r.width do
local top, bottom = r.y - 1, r.y + r.height
local t = map:getTile(Position(x, top, r.level))
local b = map:getTile(Position(x, bottom, r.level))
local t = Selectors.getTile(store.getState(), Position(x, top, r.level))
local b = Selectors.getTile(store.getState(), Position(x, bottom, r.level))

generator.addDoorMaybe(t, Orientation.northSouth, map:getNeighbors(Position(x, top, r.level)))
generator.addDoorMaybe(b, Orientation.northSouth, map:getNeighbors(Position(x, bottom, r.level)))
generator.addDoorMaybe(t, Orientation.northSouth,
Selectors.getNeighbors(store.getState(), Position(x, top, r.level)))
generator.addDoorMaybe(b, Orientation.northSouth,
Selectors.getNeighbors(store.getState(), Position(x, bottom, r.level)))
end

local left, right = r.x - 1, r.x + r.width + 1
for y = r.y, r.y + r.height do
local left, right = r.x - 1, r.x + r.width

local ld = map:getTile(Position(left, y, r.level))
local rd = map:getTile(Position(right, y, r.level))
local ld = Selectors.getTile(store.getState(), Position(left, y, r.level))
local rd = Selectors.getTile(store.getState(), Position(right, y, r.level))

generator.addDoorMaybe(ld, Orientation.eastWest, map:getNeighbors(Position(left, y, r.level)))
generator.addDoorMaybe(rd, Orientation.eastWest, map:getNeighbors(Position(right, y, r.level)))
generator.addDoorMaybe(ld, Orientation.eastWest,
Selectors.getNeighbors(store.getState(), Position(left, y, r.level)))
generator.addDoorMaybe(rd, Orientation.eastWest,
Selectors.getNeighbors(store.getState(), Position(right, y, r.level)))
end

end
end

function generator.addDoorMaybe(tile, orientation, neighbors)
local Door = require "game.rules.map.furniture.door"

local asWalls = function(n1, n2)
return n1 and n2 and n1.terrain == terrain.list.wall and n2.terrain == terrain.list.wall
return n1 and n2 and n1.isWall and n2.isWall
end

if tile and tile.terrain == terrain.list.corridor then
Expand All @@ -293,9 +241,10 @@ function generator.addDoorMaybe(tile, orientation, neighbors)
end
end

function generator.connectLevels(outline, start, dest)
local roomsOnSourceLevel = tables.select(outline.rooms, function(r) return r.level == start end)
local roomsOnDestLevel = tables.select(outline.rooms, function(r) return r.level == dest end)
function generator.connectLevels(start, dest)
local rooms = Selectors.getRooms(store.getState())
local roomsOnSourceLevel = tables.select(rooms, function(r) return r.level == start end)
local roomsOnDestLevel = tables.select(rooms, function(r) return r.level == dest end)

-- find an overlapping room
local startRoom, destRoom, startRect
Expand Down
21 changes: 1 addition & 20 deletions game/rules/map/generators/dungeon_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

describe("game.rules.map.generators.dungeon", function()
local dungeon = require "game.rules.map.generators.dungeon"
local Outline = require "game.rules.map.outline"

it("can create a node for the tree", function()
local node = dungeon.create_node(1, 1, 100, 100)
Expand Down Expand Up @@ -61,8 +60,7 @@ describe("game.rules.map.generators.dungeon", function()

it("builds a room within the boundaries of the node", function()
local node = dungeon.create_node(15, 18, 23, 27)
local outline = Outline:new(100, 100)
dungeon.create_rooms(node, outline)
dungeon.create_rooms(node)

assert.not_nil(node.room)
assert.is_true(node.room.x >= node.x)
Expand All @@ -73,21 +71,4 @@ describe("game.rules.map.generators.dungeon", function()
assert.is_true(node.room.x + node.room.width <= node.x + node.width)
assert.is_true(node.room.y + node.room.height <= node.y + node.height)
end)

it("generates an outline and tilemap for the dungeon", function()
local outline, tileMap = dungeon.generate(50, 50, 1)
assert.not_nil(outline)
assert.not_nil(tileMap)

assert.greater_than(0, #outline.rooms)
assert.greater_than(0, #outline.corridors)
assert.greater_than(0, tileMap.width)
assert.greater_than(0, tileMap.height)
end)

it("can create a multi-level dungeon", function()
local outline, tileMap = dungeon.generate(50, 50, 10)
assert.equals(10, outline.levels)
assert.equals(10, tileMap.levels)
end)
end)
5 changes: 3 additions & 2 deletions game/rules/map/generators/place_items.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ local tables = require "moonpie.tables"
local Store = require "game.store"
local Items = require "game.rules.items"
local Position = require "game.rules.world.position"
local Selectors = require "game.rules.map.selectors"


return function(outline)
local rooms = outline.rooms
return function()
local rooms = Selectors.getRooms(Store.getState())

for _=1,40 do
local r = tables.pickRandom(rooms)
Expand Down
2 changes: 0 additions & 2 deletions game/rules/map/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ return {
dungeon = require "game.rules.map.generators.dungeon"
},
selectors = require "game.rules.map.selectors",
tileMap = require "game.rules.map.tile_map",
outline = require "game.rules.map.outline"
}
25 changes: 0 additions & 25 deletions game/rules/map/outline.lua

This file was deleted.

29 changes: 0 additions & 29 deletions game/rules/map/outline_spec.lua

This file was deleted.

Loading

0 comments on commit e7d9b11

Please sign in to comment.