Skip to content

Commit

Permalink
WIP: Work on Lua cave map generator
Browse files Browse the repository at this point in the history
  • Loading branch information
CelticMinstrel committed Oct 20, 2016
1 parent cde408f commit ffe356f
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 197 deletions.
2 changes: 1 addition & 1 deletion RELEASE_NOTES
Expand Up @@ -41,7 +41,7 @@ Tunnel functionality was expanded and the default behavior was altered in order


[rasection="scenario_generation=cave deprecated"]
scenario_generation=cave is now deprecated and will be removed in 1.14 or 1.15, scenarios that previously used scenario_generation=cave shoudl use map_generation=lua with ´create_map = << params = ...; return wesnoth.dofile("lua/cave_map_generator.lua") >>´ instead
[c]scenario_generation=cave[/c] is now deprecated and will be removed in 1.14 or 1.15; scenarios that previously used scenario_generation=cave should use map_generation=lua with ´create_map = << return wesnoth.require("lua/cave_map_generator.lua").generate_map(...) >>´ instead.
[/rasection]


Expand Down
23 changes: 11 additions & 12 deletions data/campaigns/Heir_To_The_Throne/scenarios/17_Scepter_of_Fire.cfg
Expand Up @@ -7,7 +7,7 @@
[generator]
id="cavegen"
config_name="Lua Cave Generator"
create_map = << params = ...; return wesnoth.dofile("lua/cave_map_generator.lua") >>
create_map = << return wesnoth.require("lua/cave_map_generator.lua").generate_map(...) >>


map_width=50
Expand Down Expand Up @@ -426,7 +426,7 @@
#ifdef HARD
#else
{VARIABLE_OP side_kill rand "4..7"}
{ERASE_CASTLE $side_kill Uu}
#{ERASE_CASTLE $side_kill Uu}
[kill]
side=$side_kill
[/kill]
Expand All @@ -436,7 +436,7 @@
[/modify_side]
#endif
{VARIABLE_OP side_kill rand "2..3"}
{ERASE_CASTLE $side_kill Uu}
#{ERASE_CASTLE $side_kill Uu}
[kill]
side=$side_kill
[/kill]
Expand Down Expand Up @@ -464,15 +464,14 @@
variable=adjacent_to_starting_loc
[/store_locations]

[foreach]
array=adjacent_to_starting_loc
[do]
[terrain]
x,y=$this_item.x,$this_item.y
terrain=Cud
[/terrain]
[/do]
[/foreach]
#[foreach]
# array=adjacent_to_starting_loc
# [do]
# [terrain]
# x,y=$this_item.x,$this_item.y
# terrain=Cud
# [/do]
#[/foreach]

{CLEAR_VARIABLE adjacent_to_starting_loc}
[/event]
Expand Down
Expand Up @@ -19,7 +19,7 @@
[generator]
id="cavegen"
config_name="Lua Cave Generator"
create_map = << params = ...; return wesnoth.dofile("lua/cave_map_generator.lua") >>
create_map = << return wesnoth.require("lua/cave_map_generator.lua").generate_map(...) >>

map_width=45
map_height=45
Expand Down
289 changes: 123 additions & 166 deletions data/lua/cave_map_generator.lua
@@ -1,200 +1,157 @@
local helper = wesnoth.require "lua/helper.lua"
local MG = wesnoth.require "lua/mapgen_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"
local T = helper.set_wml_tag_metatable {}
local random = wesnoth.random

local params = _G.params
local config_dialog = {}

local map = {}
local callbacks = {}

local function loc_to_index(x,y)
return x + 1 + y * params.map_width
end

local function index_to_loc(index)
return (index -1) % params.map_width, math.floor((index -1) / params.map_width)
end
function callbacks.generate_map(params)
local map = MG.create_map(params.map_width, params.map_height, params.terrain_wall)

for i = 1, params.map_width * params.map_height do
table.insert(map, params.terrain_wall)
end
--positions are 0-based to match the ingame locations.
local function set_tile_index(index, val)
if index < 1 or index > params.map_width * params.map_height then
return
end
if map[index] == params.terrain_castle or map[index] == params.terrain_keep then
return
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
if val == params.terrain_clear then

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[index] = params.terrain_village
else
map[index] = params.terrain_clear
end
map:set_tile(x, y, params.terrain_village)
else
map[index] = val
end
end

local function set_tile(x, y, val)
set_tile_index(loc_to_index(x, y), val)
end

local function get_tile(x, y, val)
return map[loc_to_index(x,y)]
end

local function on_board(x, y)
return x >= 0 and y >= 0 and x < params.map_width and y < params.map_height
end

local function on_inner_board(x, y)
return x >= 1 and y >= 1 and x < params.map_width - 1 and y < params.map_height - 1
end

local adjacent_offset = {
{ {0,-1}, {1,-1}, {1,0}, {0,1}, {-1,0}, {-1,-1} },
{ {0,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0} }
}
local function adjacent_tiles(x, y)
local offset = adjacent_offset[2 - (x % 2)]
local i = 0
return function()
i = i + 1
if i <= 6 then
return offset[i][1] + x, offset[i][2] + y
else
return nil
map:set_tile(x, y, params.terrain_clear)
end
end
end

local function build_chamber(x, y, locs_set, size, jagged)
local index = loc_to_index(x, y)
if locs_set[index] or not on_board(x, y) or size == 0 then
return
end
locs_set[index] = {x, y}
for xn, yn in adjacent_tiles(x, y) do
if random(100) <= 100 - jagged then
build_chamber(xn, yn, locs_set, size - 1, jagged)
local chambers = {}
local chambers_by_id = {}
local passages = {}

for chamber in helper.child_range(params, "chamber") do
local x = chamber.x
local y = chamber.y
local id = chamber.id
if type(x) == "string" then
local x_min, x_max = x:match("(%d+)-(%d+)")
x = random(tonumber(x_min), tonumber(x_max))
end
end
end

local chambers = {}
local chambers_by_id = {}
local passages = {}
local starting_positions = {}

for chamber in helper.child_range(params, "chamber") do
local x = chamber.x
local y = chamber.y
local id = chamber.id
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 = {}
build_chamber(x, y, locs_set, chambers.size or 3, chambers.size or 0)
local items = {}
for item in helper.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,
--items = helper.get_child(v, "items")
})
chambers_by_id[id] = chambers[#chambers]
for passage in helper.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,
})
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, chambers.size or 3, chambers.size or 0)
local items = {}
for item in helper.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 helper.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
end
end

for i,v in ipairs(chambers) do
local locs_list = {}
for k2,v2 in pairs(v.locs_set) do
set_tile_index(k2, params.terrain_clear)
if on_inner_board (v2[1], v2[2]) then
table.insert(locs_list, k2)
for i,v in ipairs(chambers) do
local locs_list = {}
for k2,loc in ipairs(v.locs_set:to_pairs()) do
local x, y = table.unpack(loc)
clear_tile(x, y)
if map:on_inner_board(x, y) then
table.insert(locs_list, loc)
end
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 = index_to_loc(loc)
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)

starting_positions[loc] = item.id
if item.id then
map:add_location(x, y, item.id)
end

if item.place_castle then
set_tile_index(loc, params.terrain_keep)
for x2, y2 in adjacent_tiles(x, y) do
set_tile(x2, y2, params.terrain_castle)
if item.place_castle then
std_print("Placing keep at " .. x .. "," .. y)
map:set_tile(x, y, params.terrain_keep)
for x2, y2 in MG.adjacent_tiles(x, y) do
std_print("Placing castle at " .. x2 .. "," .. y2)
map:set_tile(x2, y2, params.terrain_castle)
end
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, current_cost)
local res = 1.0
if get_tile(x, y) == params.terrain_wall then
res = laziness
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, current_cost)
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
if windiness > 1 then
res = res * random(windiness)
end
return res
end
local path, cost = wesnoth.find_path(v.start_x, v.start_y, v.dest_x, v.dest_y, calc, params.map_width, params.map_height)
for i, loc in ipairs(path) do
local locs_set = {}
build_chamber(loc[1], loc[2], locs_set, width, jagged)
for k,v in pairs(locs_set) do
set_tile_index(k, params.terrain_clear)
local path, cost = wesnoth.find_path(v.start_x, v.start_y, v.dest_x, v.dest_y, calc, params.map_width, params.map_height)
for i, loc in ipairs(path) do
local locs_set = LS.create()
build_chamber(loc[1], loc[2], locs_set, width, jagged)
for k,v in ipairs(locs_set:to_pairs()) do
map:set_tile(v[1], v[2], params.terrain_clear)
end
end
end

end

std_print("Map generation complete!")

return tostring(map)
end

local stringbuilder = {}
function callbacks.generate_scenario(params)

end

for y = 0, params.map_height - 1 do
local stringbuilder_row = {}
for x = 0, params.map_width - 1 do
local index = x + 1 + y * params.map_width
if starting_positions[index] ~= nil then
table.insert(stringbuilder_row, tostring(starting_positions[index]) .. " " .. map[index])
else
table.insert(stringbuilder_row, map[index])
end
end
table.insert(stringbuilder, table.concat(stringbuilder_row, ","))
function callbacks.user_config(params)
return params
end
return table.concat(stringbuilder, "\n")

return callbacks

0 comments on commit ffe356f

Please sign in to comment.