Commit 07924bdd6461d347a737dc45b3df05d125ecfb1a

Authored by dg
1 parent bd8c270f

New "Building" map generator


git-svn-id: http://svn.net-core.org/repos/t-engine4@3327 51575b47-30f0-44d4-a5cc-537603b46e54
... ... @@ -53,7 +53,7 @@ function _M:partition(store)
53 53 -- print("[BSP] vertical split", s)
54 54 store.nodes[1] = {depth=store.depth+1, x=0, y=0, rx=store.rx, ry=store.ry, w=store.w, h=s, nodes={}, id=self.node_id} self.node_id = self.node_id + 1
55 55 store.nodes[2] = {depth=store.depth+1, x=0, y=s, rx=store.rx, ry=store.ry + s, w=store.w, h=store.h - s, nodes={}, id=self.node_id} self.node_id = self.node_id + 1
56   - self.splits.vert[store.ry + s] = true
  56 + self.splits.vert[store.ry + s] = {min=store.rx, max=store.rx+store.w}
57 57 self:partition(store.nodes[1])
58 58 self:partition(store.nodes[2])
59 59
... ... @@ -62,7 +62,7 @@ function _M:partition(store)
62 62 -- print("[BSP] horizontal split", s)
63 63 store.nodes[1] = {depth=store.depth+1, x=0, y=0, rx=store.rx, ry=store.ry, w=s, h=store.h, nodes={}, id=self.node_id} self.node_id = self.node_id + 1
64 64 store.nodes[2] = {depth=store.depth+1, x=s, y=0, rx=store.rx + s, ry=store.ry, w=store.w -s , h=store.h, nodes={}, id=self.node_id} self.node_id = self.node_id + 1
65   - self.splits.hor[store.rx + s] = true
  65 + self.splits.hor[store.rx + s] = {min=store.ry, max=store.ry+store.h}
66 66 self:partition(store.nodes[1])
67 67 self:partition(store.nodes[2])
68 68 end
... ...
  1 +-- TE4 - T-Engine 4
  2 +-- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
  3 +--
  4 +-- This program is free software: you can redistribute it and/or modify
  5 +-- it under the terms of the GNU General Public License as published by
  6 +-- the Free Software Foundation, either version 3 of the License, or
  7 +-- (at your option) any later version.
  8 +--
  9 +-- This program is distributed in the hope that it will be useful,
  10 +-- but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 +-- GNU General Public License for more details.
  13 +--
  14 +-- You should have received a copy of the GNU General Public License
  15 +-- along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 +--
  17 +-- Nicolas Casalini "DarkGod"
  18 +-- darkgod@te4.org
  19 +
  20 +require "engine.class"
  21 +local Map = require "engine.Map"
  22 +local BSP = require "engine.BSP"
  23 +require "engine.Generator"
  24 +local RoomsLoader = require "engine.generator.map.RoomsLoader"
  25 +module(..., package.seeall, class.inherit(engine.Generator, RoomsLoader))
  26 +
  27 +function _M:init(zone, map, level, data)
  28 + engine.Generator.init(self, zone, map, level)
  29 + self.data = data
  30 + self.grid_list = self.zone.grid_list
  31 + self.max_block_w = data.max_block_w or 20
  32 + self.max_block_h = data.max_block_h or 20
  33 + self.max_building_w = data.max_building_w or 7
  34 + self.max_building_h = data.max_building_h or 7
  35 +
  36 + RoomsLoader.init(self, data)
  37 +end
  38 +
  39 +function _M:building(leaf, spots)
  40 +-- local x1, x2 = leaf.rx + rng.range(2, math.max(2, math.floor(leaf.w / 2 - 3))), leaf.rx + leaf.w - rng.range(2, math.max(2, math.floor(leaf.w / 2 - 3)))
  41 +-- local y1, y2 = leaf.ry + rng.range(2, math.max(2, math.floor(leaf.h / 2 - 3))), leaf.ry + leaf.h - rng.range(2, math.max(2, math.floor(leaf.h / 2 - 3)))
  42 + local x1, x2 = leaf.rx, leaf.rx + leaf.w
  43 + local y1, y2 = leaf.ry, leaf.ry + leaf.h
  44 + local ix1, ix2, iy1, iy2 = x1 + 2, x2 - 1, y1 + 2, y2 - 1
  45 + local inner_grids = {}
  46 + local door_grids = {}
  47 + local is_lit = rng.percent(self.data.lite_room_chance or 70)
  48 +
  49 + for i = leaf.rx, leaf.rx + leaf.w do for j = leaf.ry, leaf.ry + leaf.h do
  50 + -- Abort if there is something already
  51 + if self.map:isBound(i, j) and self.map.room_map[i][j].room then return end
  52 + end end
  53 +
  54 + for i = x1, x2 do for j = y1, y2 do
  55 + if i == x1 or i == x2 or j == y1 or j == y2 then
  56 + if not self.map.room_map[i][j].walled then self.map(i, j, Map.TERRAIN, self:resolve("wall")) end
  57 + self.map.room_map[i][j].walled = true
  58 + if not (i == x1 and j == y1) and not (i == x1 and j == y2) and not (i == x2 and j == y1) and not (i == x2 and j == y2) then
  59 + door_grids[#door_grids+1] = {x=i,y=j}
  60 + end
  61 + else
  62 + self.map(i, j, Map.TERRAIN, self:resolve("floor"))
  63 + if is_lit then self.map.lites(i, j, true) end
  64 + if i >= ix1 and i <= ix2 and j >= iy1 and j <= iy2 then
  65 + inner_grids[#inner_grids+1] = {x=i,y=j}
  66 + end
  67 + end
  68 + end end
  69 +
  70 + -- Door
  71 + local door = rng.table(door_grids)
  72 + self.map(door.x, door.y, Map.TERRAIN, self:resolve("door"))
  73 + -- Eliminate inner grids that face the door
  74 + for i = #inner_grids, 1, -1 do
  75 + local g = inner_grids[i]
  76 + if g.x == door.x or g.y == door.y then table.remove(inner_grids, i) end
  77 + end
  78 +
  79 + spots[#spots+1] = {x=math.floor((x1+x2)/2), y=math.floor((y1+y2)/2), type="building", subtype="building"}
  80 +end
  81 +
  82 +function _M:block(leaf, spots)
  83 + local x1, x2 = leaf.rx, leaf.rx + leaf.w
  84 + local y1, y2 = leaf.ry, leaf.ry + leaf.h
  85 + local ix1, ix2, iy1, iy2 = x1 + 2, x2 - 1, y1 + 2, y2 - 1
  86 + local inner_grids = {}
  87 + local door_grids = {}
  88 +
  89 + for i = leaf.rx, leaf.rx + leaf.w do for j = leaf.ry, leaf.ry + leaf.h do
  90 + -- Abort if there is something already
  91 + if self.map:isBound(i, j) and self.map.room_map[i][j].room then return end
  92 + end end
  93 +
  94 + local door_grids = {}
  95 + for i = x1, x2 do for j = y1, y2 do
  96 + if i == x1 or i == x2 or j == y1 or j == y2 then
  97 + self.map(i, j, Map.TERRAIN, self:resolve("floor"))
  98 + elseif (i == x1+1 or i == x2-1 or j == y1+1 or j == y2-1) and
  99 + not (i == x1+1 and j == y1+1) and not (i == x1+1 and j == y2-1) and not (i == x2-1 and j == y1+1) and not (i == x2-1 and j == y2-1) then
  100 + door_grids[#door_grids+1] = {x=i,y=j}
  101 + end
  102 + end end
  103 +
  104 + -- Door
  105 + local door = rng.table(door_grids)
  106 + self.map(door.x, door.y, Map.TERRAIN, self:resolve("door"))
  107 +
  108 + local bsp = BSP.new(leaf.w-2, leaf.h-2, self.max_building_w, self.max_building_h)
  109 + bsp:partition()
  110 +
  111 + print("Building gen made ", #bsp.leafs, "building BSP leafs")
  112 + for z, sleaf in ipairs(bsp.leafs) do
  113 + sleaf.rx = sleaf.rx + leaf.rx + 1
  114 + sleaf.ry = sleaf.ry + leaf.ry + 1
  115 + self:building(sleaf, spots)
  116 + end
  117 +end
  118 +
  119 +function _M:generate(lev, old_lev)
  120 + for i = 0, self.map.w - 1 do for j = 0, self.map.h - 1 do
  121 + self.map(i, j, Map.TERRAIN, self:resolve("wall"))
  122 + end end
  123 +
  124 + local spots = {}
  125 + self.spots = spots
  126 +
  127 + local bsp = BSP.new(self.map.w, self.map.h, self.max_block_w, self.max_block_h)
  128 + bsp:partition()
  129 +
  130 + print("Building gen made ", #bsp.leafs, "blocks BSP leafs")
  131 + for z, leaf in ipairs(bsp.leafs) do
  132 + self:block(leaf, spots)
  133 + end
  134 +
  135 + local ux, uy, dx, dy
  136 + if self.data.edge_entrances then
  137 + ux, uy, dx, dy, spots = self:makeStairsSides(lev, old_lev, self.data.edge_entrances, spots)
  138 + else
  139 + ux, uy, dx, dy, spots = self:makeStairsInside(lev, old_lev, spots)
  140 + end
  141 +
  142 + return ux, uy, dx, dy, spots
  143 +end
  144 +
  145 +--- Create the stairs inside the level
  146 +function _M:makeStairsInside(lev, old_lev, spots)
  147 + -- Put down stairs
  148 + local dx, dy
  149 + if lev < self.zone.max_level or self.data.force_last_stair then
  150 + while true do
  151 + dx, dy = rng.range(1, self.map.w - 1), rng.range(1, self.map.h - 1)
  152 + if not self.map:checkEntity(dx, dy, Map.TERRAIN, "block_move") and not self.map.room_map[dx][dy].special then
  153 + self.map(dx, dy, Map.TERRAIN, self:resolve("down"))
  154 + self.map.room_map[dx][dy].special = "exit"
  155 + break
  156 + end
  157 + end
  158 + end
  159 +
  160 + -- Put up stairs
  161 + local ux, uy
  162 + while true do
  163 + ux, uy = rng.range(1, self.map.w - 1), rng.range(1, self.map.h - 1)
  164 + if not self.map:checkEntity(ux, uy, Map.TERRAIN, "block_move") and not self.map.room_map[ux][uy].special then
  165 + self.map(ux, uy, Map.TERRAIN, self:resolve("up"))
  166 + self.map.room_map[ux][uy].special = "exit"
  167 + break
  168 + end
  169 + end
  170 +
  171 + return ux, uy, dx, dy, spots
  172 +end
  173 +
  174 +--- Create the stairs on the sides
  175 +function _M:makeStairsSides(lev, old_lev, sides, spots)
  176 + -- Put down stairs
  177 + local dx, dy
  178 + if lev < self.zone.max_level or self.data.force_last_stair then
  179 + while true do
  180 + if sides[2] == 4 then dx, dy = 0, rng.range(0, self.map.h - 1)
  181 + elseif sides[2] == 6 then dx, dy = self.map.w - 1, rng.range(0, self.map.h - 1)
  182 + elseif sides[2] == 8 then dx, dy = rng.range(0, self.map.w - 1), 0
  183 + elseif sides[2] == 2 then dx, dy = rng.range(0, self.map.w - 1), self.map.h - 1
  184 + end
  185 +
  186 + if not self.map.room_map[dx][dy].special then
  187 + self.map(dx, dy, Map.TERRAIN, self:resolve("down"))
  188 + self.map.room_map[dx][dy].special = "exit"
  189 + break
  190 + end
  191 + end
  192 + end
  193 +
  194 + -- Put up stairs
  195 + local ux, uy
  196 + while true do
  197 + if sides[1] == 4 then ux, uy = 0, rng.range(0, self.map.h - 1)
  198 + elseif sides[1] == 6 then ux, uy = self.map.w - 1, rng.range(0, self.map.h - 1)
  199 + elseif sides[1] == 8 then ux, uy = rng.range(0, self.map.w - 1), 0
  200 + elseif sides[1] == 2 then ux, uy = rng.range(0, self.map.w - 1), self.map.h - 1
  201 + end
  202 +
  203 + if not self.map.room_map[ux][uy].special then
  204 + self.map(ux, uy, Map.TERRAIN, self:resolve("up"))
  205 + self.map.room_map[ux][uy].special = "exit"
  206 + break
  207 + end
  208 + end
  209 +
  210 + return ux, uy, dx, dy, spots
  211 +end
... ...
... ... @@ -27,10 +27,13 @@ local ActorAI = require "engine.interface.ActorAI"
27 27 local ActorLevel = require "engine.interface.ActorLevel"
28 28 local ActorTemporaryEffects = require "engine.interface.ActorTemporaryEffects"
29 29 local Birther = require "engine.Birther"
  30 +local UIBase = require "engine.ui.Base"
30 31
31 32 local n = core.noise.new(2)
32 33 _2DNoise = n:makeTexture2D(64, 64)
33 34
  35 +UIBase:setTextShadow(0.6)
  36 +
34 37 -- Usefull keybinds
35 38 KeyBind:load("move,hotkeys,inventory,actions,interface,debug")
36 39
... ...
... ... @@ -934,10 +934,10 @@ function _M:setupCommands()
934 934 print((" [ [[\n%d%d%d\n%d %d\n%d%d%d]] ] = '',"):format(g7,g8,g9,g4,g6,g1,g2,g3))
935 935 end end,
936 936 [{"_g","ctrl"}] = function() if config.settings.cheat then
937   --- self.state:debugRandomZone()
  937 + self.state:debugRandomZone()
938 938 -- local m = game.zone:makeEntity(game.level, "actor", {random_boss=true}, nil, true)
939 939 -- if m then game.zone:addEntity(game.level, m, "actor", game.player.x, game.player.y + 1) end
940   - self:changeLevel(1, "test")
  940 +-- self:changeLevel(1, "test")
941 941 end end,
942 942 }
943 943
... ...
... ... @@ -1049,6 +1049,19 @@ local random_zone_layouts = {
1049 1049 door = data:getDoor(),
1050 1050 ["'"] = data:getDoor(),
1051 1051 } end },
  1052 + -- Building
  1053 + { name="building", rarity=1, gen=function(data)
  1054 + return {
  1055 + class = "engine.generator.map.Building",
  1056 + lite_room_chance = rng.range(0, 100),
  1057 + max_block_w = rng.range(14, 20), max_block_h = rng.range(14, 20),
  1058 + max_building_w = rng.range(4, 8), max_building_h = rng.range(4, 8),
  1059 + floor = data:getFloor(),
  1060 + wall = data:getWall(),
  1061 + up = data:getUp(),
  1062 + down = data:getDown(),
  1063 + door = data:getDoor(),
  1064 + } end },
1052 1065 }
1053 1066
1054 1067 local random_zone_themes = {
... ... @@ -1169,7 +1182,7 @@ function _M:createRandomZone(zbase)
1169 1182 end
1170 1183 end
1171 1184 local base = rng.table(list)
1172   - local boss, boss_id = self:createRandomBoss(base, data.min_lev + data.depth + rng.range(2, 4))
  1185 + local boss, boss_id = self:createRandomBoss(base, {level=data.min_lev + data.depth + rng.range(2, 4)})
1173 1186 npcs[boss_id] = boss
1174 1187
1175 1188 ------------------------------------------------------------
... ... @@ -1379,15 +1392,15 @@ function _M:debugRandomZone()
1379 1392 local zone = self:createRandomZone()
1380 1393 game:changeLevel(zone.max_level, zone)
1381 1394
1382   - game.level.map:liteAll(0, 0, game.level.map.w, game.level.map.h)
1383   - game.level.map:rememberAll(0, 0, game.level.map.w, game.level.map.h)
1384   - for i = 0, game.level.map.w - 1 do
1385   - for j = 0, game.level.map.h - 1 do
1386   - local trap = game.level.map(i, j, game.level.map.TRAP)
1387   - if trap then
1388   - trap:setKnown(game.player, true)
1389   - game.level.map:updateMap(i, j)
1390   - end
  1395 + game.level.map:liteAll(0, 0, game.level.map.w, game.level.map.h)
  1396 + game.level.map:rememberAll(0, 0, game.level.map.w, game.level.map.h)
  1397 + for i = 0, game.level.map.w - 1 do
  1398 + for j = 0, game.level.map.h - 1 do
  1399 + local trap = game.level.map(i, j, game.level.map.TRAP)
  1400 + if trap then
  1401 + trap:setKnown(game.player, true)
  1402 + game.level.map:updateMap(i, j)
1391 1403 end
1392 1404 end
  1405 + end
1393 1406 end
... ...
... ... @@ -32,6 +32,7 @@ return {
32 32 generator = {
33 33 map = {
34 34 class = "engine.generator.map.Building",
  35 + max_block_w = 15, max_block_h = 15,
35 36 max_building_w = 5, max_building_h = 5,
36 37 floor = "FLOOR",
37 38 external_floor = "FLOOR",
... ...