diff --git a/game/engines/default/engine/generator/map/FromCustom.lua b/game/engines/default/engine/generator/map/MapScript.lua similarity index 86% rename from game/engines/default/engine/generator/map/FromCustom.lua rename to game/engines/default/engine/generator/map/MapScript.lua index 4ab6f89fcc34cf2badf1fef4fb26217204cdd9a7..5dbb2e1a0a69a787e02e9092a7a925a2e7670cb4 100644 --- a/game/engines/default/engine/generator/map/FromCustom.lua +++ b/game/engines/default/engine/generator/map/MapScript.lua @@ -30,7 +30,7 @@ function _M:init(zone, map, level, data) self.data = data self.grid_list = zone.grid_list self.spots = {} - self.mapsize = {self.map.w, self.map.h} + self.mapsize = {self.map.w, self.map.h, w=self.map.w, h=self.map.h} RoomsLoader.init(self, data) end @@ -55,7 +55,21 @@ function _M:regenerate() end function _M:custom(lev, old_lev) - if self.data.custom then return self.data.custom(self, lev, old_lev) end + if self.data.mapscript then + local file = self:getFile(self.data.mapscript..".lua", "mapscripts") + local f, err = loadfile(file) + if not f and err then error(err) end + setfenv(f, setmetatable(env or { + self = self, + lev = lev, + old_lev = old_lev, + Tilemap = require "engine.tilemaps.Tilemap", + }, {__index=_G})) + return f() + end + if self.data.custom then + return self.data.custom(self, lev, old_lev) + end error("Generator FromCustom called without customization!") end diff --git a/game/engines/default/engine/WaveFunctionCollapse.lua b/game/engines/default/engine/tilemaps/Tilemap.lua similarity index 59% rename from game/engines/default/engine/WaveFunctionCollapse.lua rename to game/engines/default/engine/tilemaps/Tilemap.lua index 72da351aede5f5b5312fa20395a616ca76f866c1..b9432f076f74606c6d3c6067c72f16428a619eea 100644 --- a/game/engines/default/engine/WaveFunctionCollapse.lua +++ b/game/engines/default/engine/tilemaps/Tilemap.lua @@ -21,28 +21,41 @@ require "engine.class" local lom = require "lxp.lom" local mime = require "mime" ---- Generate map-like data from samples using the WaveFunctionCollapse algorithm (in C++) --- @classmod engine.WaveFunctionCollapse +--- Base class to generate map-like +-- @classmod engine.tilemaps.Tilemap module(..., package.seeall, class.make) ---- Run the algorithm --- It will produce internal results which this class can then manipulate --- If async is true in the parameters the generator will run in an asynchronous thread and you must call :waitCompute() --- before using the results, this allows you to run multiple WFCs for later merging wihtout taking more time (if the user have enoguh CPUs obviously) -function _M:init(t) - assert(t.mode == "overlapping", "bad WaveFunctionCollapse mode") - assert(t.size, "WaveFunctionCollapse has no size") - self.data_w = t.size[1] - self.data_h = t.size[2] - if t.mode == "overlapping" then - if type(t.sample) == "string" then - t.sample = self:tmxLoad(t.sample) +function _M:init(size, fill_with) + if size then + self.data_w = size[1] + self.data_h = size[2] + if self.data_w and self.data_h then + self.data = {} + for y = 1, self.data_h do + self.data[y] = {} + for x = 1, self.data_w do + self.data[y][x] = fill_with or ' ' + end + end end - self:run(t) end end ---- Used internally to load a sample from a tmx file +--- Find all empty spaces (defaults to ' ') and fill them with a give char +function _M:fillAll(fill_with, empty_char) + if not self.data then return end + empty_char = empty_char or ' ' + fill_with = fill_with or '#' + for y = 1, self.data_h do + for x = 1, self.data_w do + if self.data[y][x] == empty_char then + self.data[y][x] = fill_with + end + end + end +end + +--- Used internally to load a tilemap from a tmx file function _M:tmxLoad(file) local f = fs.open(file, "r") local data = f:read(10485760) f:close() local map = lom.parse(data) @@ -118,36 +131,14 @@ function _M:tmxLoad(file) end end end - for y = 1, h do data[y] = table.concat(data[y]) end - return data -end - ---- Used internally to parse the results -function _M:parseResult(data) - if not data then return end - self.data = {} - for y = 1, #data do - local x = 1 - self.data[y] = {} - for c in data[y]:gmatch('.') do - self.data[y][x] = c - x = x + 1 - end - end + return data, w, h end ---- Called by the constructor to actaully start doing stuff -function _M:run(t) - print("[WaveFunctionCollapse] running with parameter table:") - table.print(t) - if not t.async then - local data = core.generator.wfc.overlapping(t.sample, t.size[1], t.size[2], t.n, t.symmetry, t.periodic_out, t.periodic_in, t.has_foundation) - self:parseResult(data) - return false - else - self.async_data = core.generator.wfc.asyncOverlapping(t.sample, t.size[1], t.size[2], t.n, t.symmetry, t.periodic_out, t.periodic_in, t.has_foundation) - return true - end +function _M:collapseToLineFormat(data) + if not data then return nil end + local ndata = {} + for y = 1, #data do ndata[y] = table.concat(data[y]) end + return ndata end --- Do we have results, or did we fail? @@ -155,31 +146,9 @@ function _M:hasResult() return self.data and true or false end ---- Wait for computation to finish if in async mode, if not it just returns immediately -function _M:waitCompute() - if not self.async_data then return end - local data = self.async_data:wait() - self.async_data = nil - - self:parseResult(data) - return self:hasResult() -end - ---- Wait for multiple WaveFunctionCollapse at once --- Static -function _M:waitAll(...) - local all_have_data = true - for _, wfcasync in ipairs{...} do - wfcasync:waitCompute() - if not wfcasync:hasResult() then all_have_data = false end -- We cant break, we need to wait all the threads to not leave them dangling in the wind - end - return all_have_data -end - ---- Return a list of groups of tiles representing each of the connected areas -function _M:findFloodfillGroups(wall) - if type(wall) == "table" then local first = wall[1] wall = table.reverse(wall) wall.__first = first - else wall = {[wall] = true, __first=wall} end +--- Return a list of groups of tiles that matches the given cond function +function _M:findGroups(cond) + if not self.data then return {} end local fills = {} local opens = {} @@ -187,7 +156,7 @@ function _M:findFloodfillGroups(wall) for i = 1, self.data_w do opens[i] = {} for j = 1, self.data_h do - if not wall[self.data[j][i]] then + if cond(self.data[j][i]) then opens[i][j] = #list+1 list[#list+1] = {x=i, y=j} end @@ -226,28 +195,40 @@ function _M:findFloodfillGroups(wall) local i, l = next(list) local closed = floodFill(l.x, l.y) groups[#groups+1] = {id=id, list=closed} - print("[WaveFunctionCollapse] Floodfill group", i, #closed) + print("[Tilemap] Floodfill group", i, #closed) end - return groups, wall + return groups +end + +--- Return a list of groups of tiles representing each of the connected areas +function _M:findGroupsNotOf(wall) + wall = table.reverse(wall) + return self:findGroups(function(c) return not wall[c] end) end ---- Find groups by floodfill and apply a custom function over them +--- Return a list of groups of tiles representing each of the connected areas +function _M:findGroupsOf(floor) + floor = table.reverse(floor) + return self:findGroups(function(c) return floor[c] end) +end + +--- Apply a custom method over the given groups, sorting them from bigger to smaller -- It gives the groups in order of bigger to smaller -function _M:applyOnFloodfillGroups(wall, fct) +function _M:applyOnGroups(groups, fct) if not self.data then return end - local groups = self:findFloodfillGroups(wall) table.sort(groups, function(a,b) return #a.list > #b.list end) - for _, group in ipairs(groups) do - fct(self.data_w, self.data_h, self.data, group) + for id, group in ipairs(groups) do + fct(self.data_w, self.data_h, self.data, group, id) end end --- Given a list of groups, eliminate them all function _M:eliminateGroups(wall, groups) - print("[WaveFunctionCollapse] Eleminating groups", #groups) + if not self.data then return end + print("[Tilemap] Eleminating groups", #groups) for i = 1, #groups do - print("[WaveFunctionCollapse] Eleminating group "..i.." of", #groups[i].list) + print("[Tilemap] Eleminating group "..i.." of", #groups[i].list) for j = 1, #groups[i].list do local jn = groups[i].list[j] self.data[jn.y][jn.x] = wall @@ -256,12 +237,13 @@ function _M:eliminateGroups(wall, groups) end --- Simply destroy all connected groups except the biggest one -function _M:eliminateByFloodfill(wall) - local groups, wall = self:findFloodfillGroups(wall) +function _M:eliminateByFloodfill(walls) + if not self.data then return 0 end + local groups = self:findGroupsNotOf(walls) -- If nothing exists, regen if #groups == 0 then - print("[WaveFunctionCollapse] Floodfill found nothing") + print("[Tilemap] Floodfill found nothing") return 0 end @@ -269,20 +251,64 @@ function _M:eliminateByFloodfill(wall) table.sort(groups, function(a,b) return #a.list < #b.list end) local g = table.remove(groups) if g and #g.list > 0 then - print("[WaveFunctionCollapse] Ok floodfill with main group size", #g.list) - self:eliminateGroups(wall.__first, groups) + print("[Tilemap] Ok floodfill with main group size", #g.list) + self:eliminateGroups(walls[1], groups) return #g.list else - print("[WaveFunctionCollapse] Floodfill left nothing") + print("[Tilemap] Floodfill left nothing") return 0 end end +function _M:isInGroup(group, x, y) + if not group.reverse then + group.reverse = {} + for j = 1, #group.list do + local jn = group.list[j] + group.reverse[jn.x] = group.reverse[jn.x] or {} + group.reverse[jn.x][jn.y] = true + end + end + return group.reverse[x] and group.reverse[x][y] +end + +--- Find the biggest rectangle that can fit fully in the given group +function _M:groupInnerRectangle(group) + +end + +--- Find the smallest rectangle that can fit around in the given group +function _M:groupOuterRectangle(group) + local n = group.list[1] + if not n then return end -- wtf? + local x1, x2 = n.x, n.x + local y1, y2 = n.y, n.y + + for j = 1, #group.list do + local jn = group.list[j] + if jn.x < x1 then x1 = jn.x end + if jn.x > x2 then x2 = jn.x end + if jn.y < y1 then y1 = jn.y end + if jn.y > y2 then y2 = jn.y end + end + + -- Debug + -- for i = x1, x2 do for j = y1, y2 do + -- if not self:isInGroup(group, i, j) then + -- if self.data[j][i] == '#' then + -- self.data[j][i] = 'T' + -- end + -- end + -- end end + + return {x1=x1, y1=y1, x2=x2, y2=y2} +end + --- Get the results -- @param is_array if true returns a table[][] of characters, if false a table[] of string lines function _M:getResult(is_array) - if is_array then return self.data end if not self.data then return nil end + if is_array then return self.data end local data = {} for y = 1, self.data_h do data[y] = table.concat(self.data[y]) end return data @@ -290,8 +316,13 @@ end --- Debug function to print the result to the log function _M:printResult() + if not self.data then + print("-------------") + print("------------- Tilemap result") + return + end print("-------------") - print("------------- WaveFunctionCollapse result") + print("------------- Tilemap result") print("-----------[[") for _, line in ipairs(self:getResult()) do print(line) @@ -301,22 +332,28 @@ function _M:printResult() print("-------------") end ---- Merge and other WaveFunctionCollapse's data -function _M:merge(wfc, empty_char, char_order) +--- Merge and other Tilemap's data +function _M:merge(x, y, tm, char_order, empty_char) + if not self.data or not tm.data then return end + x = math.floor(x) + y = math.floor(y) char_order = table.reverse(char_order or {}) empty_char = empty_char or ' ' - if not wfc.data then return end - - for i = 1, math.min(self.data_w, wfc.data_w) do - for j = 1, math.min(self.data_h, wfc.data_h) do - local c = wfc.data[j][i] - if c ~= empty_char then - local sc = self.data[j][i] - local sc_o = char_order[sc] or 0 - local c_o = char_order[c] or 0 - - if c_o >= sc_o then - self.data[j][i] = wfc.data[j][i] + if not tm.data then return end + + for i = 1, tm.data_w do + for j = 1, tm.data_h do + local si, sj = i + x - 1, j + y - 1 + if si >= 1 and si <= self.data_w and sj >= 1 and sj <= self.data_h then + local c = tm.data[j][i] + if c ~= empty_char then + local sc = self.data[sj][si] + local sc_o = char_order[sc] or 0 + local c_o = char_order[c] or 0 + + if c_o >= sc_o then + self.data[sj][si] = tm.data[j][i] + end end end end diff --git a/game/engines/default/engine/tilemaps/WaveFunctionCollapse.lua b/game/engines/default/engine/tilemaps/WaveFunctionCollapse.lua new file mode 100644 index 0000000000000000000000000000000000000000..0b65a151fd0af64409fd9577cc0416a41a70b2b7 --- /dev/null +++ b/game/engines/default/engine/tilemaps/WaveFunctionCollapse.lua @@ -0,0 +1,94 @@ +-- TE4 - T-Engine 4 +-- Copyright (C) 2009 - 2017 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +require "engine.class" +local lom = require "lxp.lom" +local mime = require "mime" +local Tilemap = require "engine.tilemaps.Tilemap" + +--- Generate map-like data from samples using the WaveFunctionCollapse algorithm (in C++) +-- @classmod engine.tilemaps.WaveFunctionCollapse +module(..., package.seeall, class.inherit(Tilemap)) + +--- Run the algorithm +-- It will produce internal results which this class can then manipulate +-- If async is true in the parameters the generator will run in an asynchronous thread and you must call :waitCompute() +-- before using the results, this allows you to run multiple WFCs for later merging wihtout taking more time (if the user have enoguh CPUs obviously) +function _M:init(t) + assert(t.mode == "overlapping", "bad WaveFunctionCollapse mode") + assert(t.size, "WaveFunctionCollapse has no size") + self.data_w = t.size[1] + self.data_h = t.size[2] + if t.mode == "overlapping" then + if type(t.sample) == "string" then + t.sample = self:collapseToLineFormat(self:tmxLoad(t.sample)) + end + self:run(t) + end +end + +--- Used internally to parse the results +function _M:parseResult(data) + print("[WaveFunctionCollapse] compute done", data) + if not data then return end + self.data = {} + for y = 1, #data do + local x = 1 + self.data[y] = {} + for c in data[y]:gmatch('.') do + self.data[y][x] = c + x = x + 1 + end + end +end + +--- Called by the constructor to actaully start doing stuff +function _M:run(t) + print("[WaveFunctionCollapse] running with parameter table:") + table.print(t) + if not t.async then + local data = core.generator.wfc.overlapping(t.sample, t.size[1], t.size[2], t.n, t.symmetry, t.periodic_out, t.periodic_in, t.has_foundation) + self:parseResult(data) + return false + else + self.async_data = core.generator.wfc.asyncOverlapping(t.sample, t.size[1], t.size[2], t.n, t.symmetry, t.periodic_out, t.periodic_in, t.has_foundation) + return true + end +end + +--- Wait for computation to finish if in async mode, if not it just returns immediately +function _M:waitCompute() + if not self.async_data then return end + local data = self.async_data:wait() + self.async_data = nil + + self:parseResult(data) + return self:hasResult() +end + +--- Wait for multiple WaveFunctionCollapse at once +-- Static +function _M:waitAll(...) + local all_have_data = true + for _, wfcasync in ipairs{...} do + wfcasync:waitCompute() + if not wfcasync:hasResult() then all_have_data = false end -- We cant break, we need to wait all the threads to not leave them dangling in the wind + end + return all_have_data +end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 76840edbd60995cf0c65d5caf2c1bfdb7bb7a177..6640730f5e2486fb745bf27860bdff8cee6ccb3d 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -1845,7 +1845,11 @@ function _M:setupCommands() print("===============") end end, [{"_g","ctrl"}] = function() if config.settings.cheat then - self:changeLevel(game.level.level + 1) + if self.zone.short_name ~= "test" then + self:changeLevel(1, "test") + else + self:changeLevel(game.level.level + 1) + end do return end local m = game.zone:makeEntity(game.level, "actor", {name="elven mage"}, nil, true) local x, y = util.findFreeGrid(game.player.x, game.player.y, 20, true, {[Map.ACTOR]=true}) diff --git a/game/modules/tome/data/zones/test/grids.lua b/game/modules/tome/data/zones/test/grids.lua index e1d255e1f3d4dec1434b5c4c006e954a119f9d32..f332848dbbd888a77bf1fa3485bb586480f97b0d 100644 --- a/game/modules/tome/data/zones/test/grids.lua +++ b/game/modules/tome/data/zones/test/grids.lua @@ -20,3 +20,4 @@ load("/data/general/grids/basic.lua") load("/data/general/grids/forest.lua") load("/data/general/grids/water.lua") +load("/data/general/grids/jungle_hut.lua") diff --git a/game/modules/tome/data/zones/test/mapscripts/inner_outer.lua b/game/modules/tome/data/zones/test/mapscripts/inner_outer.lua new file mode 100644 index 0000000000000000000000000000000000000000..09963d311f863f89adc941478a10617a7a6892e2 --- /dev/null +++ b/game/modules/tome/data/zones/test/mapscripts/inner_outer.lua @@ -0,0 +1,72 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009 - 2017 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +local Tilemap = require "engine.tilemaps.Tilemap" +local WaveFunctionCollapse = require "engine.tilemaps.WaveFunctionCollapse" +local merge_order = {'.', '_', 'r', '+', '#', 'O', '=', ';', 'T'} + +-- Water & trees layer +local wfcwater = WaveFunctionCollapse.new{ + mode="overlapping", async=true, + sample=self:getFile("!wfctest2.tmx", "samples"), + size={self.mapsize.w/3, self.mapsize.h}, + n=3, symmetry=8, periodic_out=true, periodic_in=true, has_foundation=false +} +-- Outer buildings +local wfcouter = WaveFunctionCollapse.new{ + mode="overlapping", async=true, + sample=self:getFile("!wfctest.tmx", "samples"), + size={self.mapsize.w/3, self.mapsize.h}, + n=3, symmetry=8, periodic_out=true, periodic_in=true, has_foundation=false +} +-- Inner buildings +local wfcinner = WaveFunctionCollapse.new{ + mode="overlapping", async=true, + sample=self:getFile("!wfctest4.tmx", "samples"), + size={self.mapsize.w*2/3, self.mapsize.h}, + n=3, symmetry=8, periodic_out=false, periodic_in=false, has_foundation=false +} + +-- Wait for all generators to finish +if not WaveFunctionCollapse:waitAll(wfcinner, wfcwater, wfcouter) then print("[inner_outer] a WFC failed") return self:regenerate() end + +-- Merge them all +local tm = Tilemap.new(self.mapsize) +wfcouter:merge(1, 1, wfcwater, self.data.merge_order) +if wfcouter:eliminateByFloodfill{'#', 'T'} < 400 then print("[inner_outer] outer is too small") return self:regenerate() end +if wfcinner:eliminateByFloodfill{'#', 'T'} < 400 then print("[inner_outer] inner is too small") return self:regenerate() end +tm:merge(1, 1, wfcouter, self.data.merge_order) +tm:merge(self.mapsize.w - wfcinner.data_w, 1, wfcinner, self.data.merge_order) + +-- Find rooms +local rooms = tm:findGroupsOf{'r'} +tm:applyOnGroups(rooms, function(w, h, data, room, idx) + print("ROOM", idx, "::" , unpack(tm:groupOuterRectangle(room))) + for j = 1, #room.list do + local jn = room.list[j] + -- data[jn.y][jn.x] = tostring(idx) + end +end) +tm:fillAll('.', 'r') +tm:fillAll() + +-- Elimitate the rest +if tm:eliminateByFloodfill{'#', 'T'} < 400 then return self:regenerate() end +tm:printResult() +return tm:getResult(true) diff --git a/game/modules/tome/data/zones/test/samples/wfctest.tmx b/game/modules/tome/data/zones/test/samples/wfctest.tmx index 45b1429d266ce44a30fec29ce1d9832b023448a2..74dd827bb4a776ffd9cd68121612c545b06be781 100644 --- a/game/modules/tome/data/zones/test/samples/wfctest.tmx +++ b/game/modules/tome/data/zones/test/samples/wfctest.tmx @@ -17,7 +17,7 @@ </tile> <tile id="51"> <properties> - <property name="id" value="."/> + <property name="id" value="_"/> </properties> </tile> <tile id="54"> @@ -25,16 +25,26 @@ <property name="id" value="*"/> </properties> </tile> + <tile id="63"> + <properties> + <property name="id" value="O"/> + </properties> + </tile> </tileset> <tileset firstgid="91" name="tome-terrains" tilewidth="32" tileheight="32" tilecount="144"> <image source="../../../../../../../tiled-maps/gfx/tome-terrains.png" width="256" height="576"/> + <tile id="22"> + <properties> + <property name="id" value=";"/> + </properties> + </tile> </tileset> <tileset firstgid="235" name="numbers" tilewidth="32" tileheight="32" tilecount="36"> <image source="../../../../../../../tiled-maps/gfx/numbers.png" width="192" height="192"/> </tileset> <layer name="Terrain" width="16" height="16"> <data encoding="base64" compression="zlib"> - eJxjZGBgYARiFiiNjLGJYRM3QcPYxHCJk6KfWDNZaGQ/LrWEwoucsCInLMjRPxTkSU1/g818fPK40iq94hcA4S4l9A== + eJxzYGBgcADiQiiNjLGJYRMvRMPYxHCJk6KfWDNJUUsN9xMKL3LCihz/kaN/KMhjC0N8YTrYzKck/mgdvwBZdmTy </data> </layer> </map> diff --git a/game/modules/tome/data/zones/test/samples/wfctest2.tmx b/game/modules/tome/data/zones/test/samples/wfctest2.tmx index db0047375b96423ceccdb5ddb0b73e611f8d4a49..a5cb3f469c36a022c86b5b655b41235ea2e4855c 100644 --- a/game/modules/tome/data/zones/test/samples/wfctest2.tmx +++ b/game/modules/tome/data/zones/test/samples/wfctest2.tmx @@ -49,7 +49,7 @@ </tileset> <layer name="Terrain" width="16" height="16"> <data encoding="base64" compression="zlib"> - eJxjYBgFwwEUomFy9NZDMTb9+MxE1otPPzb3odtdj0dNPxQjy2PTj+4GZL3IZuByPyn6kf1Eqf5CBvz+JxSG+NIALnEAH5QrWQ== + eJxjYKAPKKSCfmRMjt5+KCbVDGS9yGYMJv34wgddDl0NjF8Pxdjchi/skfXi0o8LoNtdz0Ba/GDTT44byNWPHC6U6oeZQU76xBe/+AAAWvQrWQ== </data> </layer> </map> diff --git a/game/modules/tome/data/zones/test/samples/wfctest4.tmx b/game/modules/tome/data/zones/test/samples/wfctest4.tmx index e18428543abc9cd85a9cebc1e6e1753dd4aff51b..f9102f03c811ba48aede35903f3d82fbc9fe2042 100644 --- a/game/modules/tome/data/zones/test/samples/wfctest4.tmx +++ b/game/modules/tome/data/zones/test/samples/wfctest4.tmx @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<map version="1.0" orientation="orthogonal" renderorder="right-down" width="16" height="16" tilewidth="32" tileheight="32" nextobjectid="31"> +<map version="1.0" orientation="orthogonal" renderorder="right-down" width="20" height="20" tilewidth="32" tileheight="32" nextobjectid="31"> <properties> <property name="status_all" value="{no_teleport=true}"/> </properties> @@ -22,7 +22,12 @@ </tile> <tile id="54"> <properties> - <property name="id" value="*"/> + <property name="id" value="_"/> + </properties> + </tile> + <tile id="58"> + <properties> + <property name="id" value="r"/> </properties> </tile> </tileset> @@ -32,9 +37,9 @@ <tileset firstgid="235" name="numbers" tilewidth="32" tileheight="32" tilecount="36"> <image source="../../../../../../../tiled-maps/gfx/numbers.png" width="192" height="192"/> </tileset> - <layer name="Terrain" width="16" height="16"> + <layer name="Terrain" width="20" height="20"> <data encoding="base64" compression="zlib"> - eJxjZGBgYMSBTfDIoatDxoTEidVPrFvw6UeXI0YNvfXj8yc5+onBtLafmHRDaboj1e/DXT85GABHnxWG + eJytkzEOwDAIAxOJJ3Xj///qVCmywLiEwVPQQbDZa62d6CFvTH4Ieac6PGR2ZmU8pdcNr8OseCoz2tME75MRnhHfWS6q+bAeGX+zptTaIC/7Wzfn2b4iXuU3Y3lRF3lyw3NgKfNZ0TfKmnoTyr1M87pZmMw+6gVVviXl </data> </layer> </map> diff --git a/game/modules/tome/data/zones/test/zone.lua b/game/modules/tome/data/zones/test/zone.lua index a293566aa4d089d46ad18271cbcb47816381012e..3f8ff466e76072a0c5be83e8dc613bae274beefb 100644 --- a/game/modules/tome/data/zones/test/zone.lua +++ b/game/modules/tome/data/zones/test/zone.lua @@ -24,8 +24,8 @@ return { max_level = 4, decay = {300, 800}, actor_adjust_level = function(zone, level, e) return zone.base_level + e:getRankLevelAdjust() + level.level-1 + rng.range(-1,2) end, - width = 50, height = 50, - -- all_remembered = true, + width = 80, height = 50, + all_remembered = true, all_lited = true, no_level_connectivity = true, @@ -35,37 +35,13 @@ return { generator = { map = { -- [[ - class = "engine.generator.map.FromCustom", + class = "engine.generator.map.MapScript", ['<'] = "UP", ['>'] = "DOWN", ['.'] = "FLOOR", ['+'] = "DOOR", ['#'] = "WALL", + ['_'] = "OLD_FLOOR", ['O'] = "OLD_WALL", [';'] = "GRASS", ['T'] = "TREE", ['='] = "DEEP_WATER", - custom = function(self, lev, old_lev) - local WaveFunctionCollapse = require "engine.WaveFunctionCollapse" - -- Water & trees layer - local wfcwater = WaveFunctionCollapse.new{ - mode="overlapping", async=true, - sample=self:getFile("!wfctest2.tmx", "samples"), - size=self.mapsize, - n=3, symmetry=8, periodic_out=true, periodic_in=true, has_foundation=false - } - - -- Base buildings - local wfc = WaveFunctionCollapse.new{ - mode="overlapping", async=true, - sample=self:getFile("!wfctest4.tmx", "samples"), - size=self.mapsize, - n=3, symmetry=8, periodic_out=false, periodic_in=false, has_foundation=false - } - -- Wait for all generators to finish - if not WaveFunctionCollapse:waitAll(wfc, wfcwater) then return self:regenerate() end - -- Merge water in - wfc:merge(wfcwater, ' ', {'.', '+', '#', '=', ';', 'T'}) - -- Elimitate the rest - if wfc:eliminateByFloodfill{'#', 'T'} < 800 then return self:regenerate() end - wfc:printResult() - return wfc:getResult(true) - end, + mapscript = "!inner_outer", --]] --[[ class = "engine.generator.map.Hexacle",