wesnoth/data/lua/cave_map_generator.lua
Pentarctagon 370d03ccb7 Fix luacheck warnings and add to CI.
Note the `exclude_files` in .luacheckrc should be deleted once the eventual Ubuntu 22.04 base image has an updated luacheck that supports lua 5.4.
2021-11-28 14:26:02 -06:00

186 lines
4.9 KiB
Lua

local MG = wesnoth.require "mapgen_helper"
local LS = wesnoth.require "location_set"
local random = mathx.random
local callbacks = {}
function callbacks.generate_map(params)
local map = MG.create_map(params.map_width, params.map_height, params.terrain_wall)
local function build_chamber(x, y, locs_set, size, jagged)
if locs_set:get(x,y) or not map:on_board(x, y) or size == 0 then
return
end
locs_set:insert(x,y)
for xn, yn in MG.adjacent_tiles(x, y) do
if random(100) <= 100 - jagged then
build_chamber(xn, yn, locs_set, size - 1, jagged)
end
end
end
local function clear_tile(x, y)
if not map:on_board(x,y) then
return
end
if map:get_tile(x,y) == params.terrain_castle or map:get_tile(x,y) == params.terrain_keep then
return
end
local r = random(1000)
if r <= params.village_density then
map:set_tile(x, y, params.terrain_village)
else
map:set_tile(x, y, params.terrain_clear)
end
end
local chambers = {}
local chambers_by_id = {}
local passages = {}
for chamber in wml.child_range(params, "chamber") do
local chance = tonumber(chamber.chance) or 100
local x = chamber.x
local y = chamber.y
local id = chamber.id
if chance == 0 or random(100) > chance then
-- Set chance to 0 so that the scenario generator can tell which chambers were used
params.chance = 0
goto continue
end
-- Ditto, set it to 100
params.chance = 100
if type(x) == "string" then
local x_min, x_max = x:match("(%d+)-(%d+)")
x = random(tonumber(x_min), tonumber(x_max))
end
if type(y) == "string" then
local y_min, y_max = y:match("(%d+)-(%d+)")
y = random(tonumber(y_min), tonumber(y_max))
end
local locs_set = LS.create()
build_chamber(x, y, locs_set, chamber.size or 3, chamber.jagged or 0)
local items = {}
for item in wml.child_range(chamber, "item_location") do
table.insert(items, item)
end
table.insert(chambers, {
center_x = x,
center_y = y,
side_num = chamber.side,
locs_set = locs_set,
id = id,
items = items,
})
chambers_by_id[id] = chambers[#chambers]
for passage in wml.child_range(chamber, "passage") do
local dst = chambers_by_id[passage.destination]
if dst ~= nil then
table.insert(passages, {
start_x = x,
start_y = y,
dest_x = dst.center_x,
dest_y = dst.center_y,
data = passage,
})
end
end
::continue::
end
for i,v in ipairs(chambers) do
local locs_list = {}
for x, y in v.locs_set:stable_iter() do
clear_tile(x, y)
if map:on_inner_board(x, y) then
table.insert(locs_list, {x,y})
end
end
for i1, item in ipairs(v.items or {}) do
local index = random(#locs_list)
local loc = locs_list[index]
table.remove(locs_list, index)
local x, y = table.unpack(loc)
if item.id then
map:add_location(x, y, item.id)
end
if item.place_castle then
map:set_tile(x, y, params.terrain_keep)
for x2, y2 in MG.adjacent_tiles(x, y) do
map:set_tile(x2, y2, params.terrain_castle)
end
end
end
end
for i,v in ipairs(passages) do
if random(100) <= (v.data.chance or 100) then
local windiness = v.data.windiness or 0
local laziness = math.max(v.data.laziness or 1, 1)
local width = math.max(v.data.width or 1, 1)
local jagged = v.data.jagged or 0
local calc = function(x, y)
if x == 0 or x == params.map_width - 1 or y == 0 or y == params.map_height - 1 then
-- Map borders are impassable
return math.huge
end
local res = 1.0
if map:get_tile(x, y) == params.terrain_wall then
res = laziness
end
if windiness > 1 then
res = res * random(windiness)
end
return res
end
local path = wesnoth.paths.find_path(
v.start_x, v.start_y, v.dest_x, v.dest_y, calc, params.map_width, params.map_height)
for j, loc in ipairs(path) do
local locs_set = LS.create()
build_chamber(loc[1], loc[2], locs_set, width, jagged)
for x,y in locs_set:stable_iter() do
clear_tile(x, y)
end
end
end
end
if type(params.transform) == "string" then
local chance = params.transform_chance or 100
if random(100) <= chance then
local transforms = {}
for t in params.transform:gmatch("[^%s,][^,]*") do
if MG.is_valid_transform(t) then
table.insert(transforms, t)
else
wml.error("Unknown transformation '" .. t .. "'")
end
end
map[transforms[random(#transforms)]](map)
end
end
return tostring(map)
end
function callbacks.generate_scenario(params)
-- This is more or less backwards compatible with the cave generator syntax
local scenario = wml.get_child(params, "scenario")
scenario.map_data = callbacks.generate_map(params)
for chamber in wml.child_range(params, "chamber") do
local chamber_items = wml.get_child(chamber, "items")
if chamber.chance == 100 and chamber_items then
-- TODO: Should we support [event]same_location_as_previous=yes?
for i,tag in ipairs(chamber_items) do
table.insert(scenario, tag)
end
end
end
return scenario
end
return callbacks