mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-18 20:20:31 +00:00
Merge 2df5336549
into 9b4f4aba3c
This commit is contained in:
commit
2813779e94
|
@ -31,7 +31,7 @@ local function wct_map_enemy_themed(race, pet, castle, village, chance)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
--give themed castle
|
--give themed castle
|
||||||
wesnoth.current.map[boss] = wesnoth.map.replace_base("K" .. castle)
|
wesnoth.current.map[boss] = wesnoth.map.replace.base("K" .. castle)
|
||||||
wesnoth.wml_actions.terrain {
|
wesnoth.wml_actions.terrain {
|
||||||
terrain="C" .. castle,
|
terrain="C" .. castle,
|
||||||
wml.tag["and"] {
|
wml.tag["and"] {
|
||||||
|
|
|
@ -34,7 +34,7 @@ function set_terrain_impl(data)
|
||||||
for j = 1, num_tiles do
|
for j = 1, num_tiles do
|
||||||
local loc = locs[i][j]
|
local loc = locs[i][j]
|
||||||
if chance >= 1000 or chance >= mathx.random(1000) then
|
if chance >= 1000 or chance >= mathx.random(1000) then
|
||||||
map[loc] = wesnoth.map['replace_' .. layer](mathx.random_choice(terrains))
|
map[loc] = wesnoth.map.replace[layer](mathx.random_choice(terrains))
|
||||||
nlocs_changed = nlocs_changed + 1
|
nlocs_changed = nlocs_changed + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,32 +5,65 @@ local random = mathx.random
|
||||||
local callbacks = {}
|
local callbacks = {}
|
||||||
|
|
||||||
function callbacks.generate_map(params)
|
function callbacks.generate_map(params)
|
||||||
local map = MG.create_map(params.map_width, params.map_height, params.terrain_wall)
|
local map = wesnoth.map.create(params.map_width, params.map_height, params.terrain_wall)
|
||||||
|
|
||||||
local function build_chamber(x, y, locs_set, size, jagged)
|
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
|
if locs_set:get(x,y) or not map:on_board(x, y, true) or size == 0 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
locs_set:insert(x,y)
|
locs_set:insert(x,y)
|
||||||
for xn, yn in MG.adjacent_tiles(x, y) do
|
for xn, yn in map:iter_adjacent(x, y) do
|
||||||
if random(100) <= 100 - jagged then
|
if random(100) <= 100 - jagged then
|
||||||
build_chamber(xn, yn, locs_set, size - 1, jagged)
|
build_chamber(xn, yn, locs_set, size - 1, jagged)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clear_tile(x, y)
|
local function clear_tile(x, y, terrain_clear)
|
||||||
if not map:on_board(x,y) then
|
if not map:on_board(x,y,true) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if map:get_tile(x,y) == params.terrain_castle or map:get_tile(x,y) == params.terrain_keep then
|
if map[{x,y}] == params.terrain_castle or map[{x,y}] == params.terrain_keep then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local tile = mathx.random_choice(terrain_clear or params.terrain_clear)
|
||||||
|
map[{x, y}] = wesnoth.map.replace.both(tile)
|
||||||
local r = random(1000)
|
local r = random(1000)
|
||||||
if r <= params.village_density then
|
if r <= params.village_density then
|
||||||
map:set_tile(x, y, params.terrain_village)
|
local village = mathx.random_choice(params.terrain_village)
|
||||||
|
map[{x, y}] = wesnoth.map.replace.if_failed(village, 'overlay')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function place_road(to_x, to_y, from_x, from_y, road_ops, terrain_clear)
|
||||||
|
if not map:on_board(to_x, to_y, true) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if map[{to_x, to_y}] == params.terrain_castle or map[{to_x, to_y}] == params.terrain_keep then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local tile_op = road_ops[map[{to_x, to_y}]]
|
||||||
|
if tile_op then
|
||||||
|
if tile_op.convert_to_bridge and from_x and from_y then
|
||||||
|
local bridges = {}
|
||||||
|
for elem in tile_op.convert_to_bridge:gmatch("[^%s,][^,]*") do
|
||||||
|
table.insert(bridges, elem)
|
||||||
|
end
|
||||||
|
local dir = wesnoth.map.get_relative_dir(from_x, from_y, to_x, to_y)
|
||||||
|
if dir == 'n' or dir == 's' then
|
||||||
|
map[{to_x, to_y}] = wesnoth.map.replace.if_failed(bridges[1], 'overlay')
|
||||||
|
elseif dir == 'sw' or dir == 'ne' then
|
||||||
|
map[{to_x, to_y}] = wesnoth.map.replace.if_failed(bridges[2], 'overlay')
|
||||||
|
elseif dir == 'se' or dir == 'nw' then
|
||||||
|
map[{to_x, to_y}] = wesnoth.map.replace.if_failed(bridges[3], 'overlay')
|
||||||
|
end
|
||||||
|
elseif tile_op.convert_to then
|
||||||
|
local tile = mathx.random_choice(tile_op.convert_to)
|
||||||
|
map[{to_x, to_y}] = wesnoth.map.replace.both(tile)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
map:set_tile(x, y, params.terrain_clear)
|
local tile = mathx.random_choice(terrain_clear or params.terrain_clear)
|
||||||
|
map[{to_x, to_y}] = wesnoth.map.replace.both(tile)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,25 +72,43 @@ function callbacks.generate_map(params)
|
||||||
local passages = {}
|
local passages = {}
|
||||||
|
|
||||||
for chamber in wml.child_range(params, "chamber") do
|
for chamber in wml.child_range(params, "chamber") do
|
||||||
|
if chamber.ignore then goto continue end
|
||||||
local chance = tonumber(chamber.chance) or 100
|
local chance = tonumber(chamber.chance) or 100
|
||||||
local x = chamber.x
|
local x, y = MG.random_location(chamber.x, chamber.y)
|
||||||
local y = chamber.y
|
-- Note: x,y run from (0,0) to (w+1,h+1)
|
||||||
|
if chamber.relative_to == "top-right" then
|
||||||
|
x = map.width - x - 1
|
||||||
|
elseif chamber.relative_to == "bottom-right" then
|
||||||
|
x = map.width - x - 1
|
||||||
|
y = map.height - y - 1
|
||||||
|
elseif chamber.relative_to == "bottom-left" then
|
||||||
|
y = map.height - y - 1
|
||||||
|
elseif chamber.relative_to == "top-middle" then
|
||||||
|
x = math.ceil(map.width / 2) + x
|
||||||
|
elseif chamber.relative_to == "bottom-middle" then
|
||||||
|
x = math.ceil(map.width / 2) + x
|
||||||
|
y = map.height - y - 1
|
||||||
|
elseif chamber.relative_to == "middle-left" then
|
||||||
|
y = math.ceil(map.height / 2) + y
|
||||||
|
elseif chamber.relative_to == "middle-right" then
|
||||||
|
y = math.ceil(map.height / 2) + y
|
||||||
|
x = map.width - x - 1
|
||||||
|
elseif chamber.relative_to == "center" then
|
||||||
|
x = math.ceil(map.width / 2) + x
|
||||||
|
y = math.ceil(map.height / 2) + y
|
||||||
|
end -- Default is "top-left" which means no adjustments needed
|
||||||
local id = chamber.id
|
local id = chamber.id
|
||||||
if chance == 0 or random(100) > chance then
|
if chance == 0 or random(100) > chance then
|
||||||
-- Set chance to 0 so that the scenario generator can tell which chambers were used
|
-- Set chance to 0 so that the scenario generator can tell which chambers were used
|
||||||
params.chance = 0
|
params.chance = 0
|
||||||
goto continue
|
goto continue
|
||||||
end
|
end
|
||||||
|
if type(chamber.require_player) == "number" and chamber.require_player > params.nplayers then
|
||||||
|
params.chance = 0
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
-- Ditto, set it to 100
|
-- Ditto, set it to 100
|
||||||
params.chance = 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()
|
local locs_set = LS.create()
|
||||||
build_chamber(x, y, locs_set, chamber.size or 3, chamber.jagged or 0)
|
build_chamber(x, y, locs_set, chamber.size or 3, chamber.jagged or 0)
|
||||||
local items = {}
|
local items = {}
|
||||||
|
@ -71,19 +122,29 @@ function callbacks.generate_map(params)
|
||||||
locs_set = locs_set,
|
locs_set = locs_set,
|
||||||
id = id,
|
id = id,
|
||||||
items = items,
|
items = items,
|
||||||
|
data = chamber,
|
||||||
})
|
})
|
||||||
chambers_by_id[id] = chambers[#chambers]
|
chambers_by_id[id] = chambers[#chambers]
|
||||||
for passage in wml.child_range(chamber, "passage") do
|
for passage in wml.child_range(chamber, "passage") do
|
||||||
|
if passage.ignore then goto continue end
|
||||||
local dst = chambers_by_id[passage.destination]
|
local dst = chambers_by_id[passage.destination]
|
||||||
if dst ~= nil then
|
if dst ~= nil then
|
||||||
|
local road_costs, road_ops = {}, {}
|
||||||
|
for road in wml.child_range(passage, "road_cost") do
|
||||||
|
road_costs[road.terrain] = road.cost
|
||||||
|
road_ops[road.terrain] = road
|
||||||
|
end
|
||||||
table.insert(passages, {
|
table.insert(passages, {
|
||||||
start_x = x,
|
start_x = x,
|
||||||
start_y = y,
|
start_y = y,
|
||||||
dest_x = dst.center_x,
|
dest_x = dst.center_x,
|
||||||
dest_y = dst.center_y,
|
dest_y = dst.center_y,
|
||||||
data = passage,
|
data = passage,
|
||||||
|
costs = road_costs,
|
||||||
|
roads = road_ops,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
::continue::
|
||||||
end
|
end
|
||||||
::continue::
|
::continue::
|
||||||
end
|
end
|
||||||
|
@ -91,8 +152,8 @@ function callbacks.generate_map(params)
|
||||||
for i,v in ipairs(chambers) do
|
for i,v in ipairs(chambers) do
|
||||||
local locs_list = {}
|
local locs_list = {}
|
||||||
for x, y in v.locs_set:stable_iter() do
|
for x, y in v.locs_set:stable_iter() do
|
||||||
clear_tile(x, y)
|
clear_tile(x, y, v.data.terrain_clear)
|
||||||
if map:on_inner_board(x, y) then
|
if map:on_board(x, y, false) then
|
||||||
table.insert(locs_list, {x,y})
|
table.insert(locs_list, {x,y})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -103,13 +164,13 @@ function callbacks.generate_map(params)
|
||||||
local x, y = table.unpack(loc)
|
local x, y = table.unpack(loc)
|
||||||
|
|
||||||
if item.id then
|
if item.id then
|
||||||
map:add_location(x, y, item.id)
|
map.special_locations[item.id] = {x, y}
|
||||||
end
|
end
|
||||||
|
|
||||||
if item.place_castle then
|
if item.place_castle then
|
||||||
map:set_tile(x, y, params.terrain_keep)
|
map[{x, y}] = wesnoth.map.replace.both(params.terrain_keep)
|
||||||
for x2, y2 in MG.adjacent_tiles(x, y) do
|
for x2, y2 in map:iter_adjacent(x, y) do
|
||||||
map:set_tile(x2, y2, params.terrain_castle)
|
map[{x2, y2}] = wesnoth.map.replace.both(params.terrain_castle)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -127,8 +188,10 @@ function callbacks.generate_map(params)
|
||||||
return math.huge
|
return math.huge
|
||||||
end
|
end
|
||||||
local res = 1.0
|
local res = 1.0
|
||||||
if map:get_tile(x, y) == params.terrain_wall then
|
local tile = map[{x, y}]
|
||||||
res = laziness
|
res = v.costs[tile] or 1.0
|
||||||
|
if tile == params.terrain_wall then
|
||||||
|
res = laziness * res
|
||||||
end
|
end
|
||||||
if windiness > 1 then
|
if windiness > 1 then
|
||||||
res = res * random(windiness)
|
res = res * random(windiness)
|
||||||
|
@ -140,8 +203,18 @@ function callbacks.generate_map(params)
|
||||||
for j, loc in ipairs(path) do
|
for j, loc in ipairs(path) do
|
||||||
local locs_set = LS.create()
|
local locs_set = LS.create()
|
||||||
build_chamber(loc[1], loc[2], locs_set, width, jagged)
|
build_chamber(loc[1], loc[2], locs_set, width, jagged)
|
||||||
|
local prev_x, prev_y
|
||||||
for x,y in locs_set:stable_iter() do
|
for x,y in locs_set:stable_iter() do
|
||||||
clear_tile(x, y)
|
local r = 1000
|
||||||
|
local ter_to_place
|
||||||
|
if v.data.place_villages then r = random(1000) end
|
||||||
|
if r <= params.village_density then
|
||||||
|
ter_to_place = v.data.terrain_village or params.terrain_village
|
||||||
|
else
|
||||||
|
ter_to_place = v.data.terrain_clear or params.terrain_clear
|
||||||
|
end
|
||||||
|
place_road(x, y, prev_x, prev_y, v.roads, ter_to_place)
|
||||||
|
prev_x, prev_y = x, y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -159,11 +232,11 @@ function callbacks.generate_map(params)
|
||||||
wml.error("Unknown transformation '" .. t .. "'")
|
wml.error("Unknown transformation '" .. t .. "'")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
map[transforms[random(#transforms)]](map)
|
MG[transforms[random(#transforms)]](map)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return tostring(map)
|
return map.data
|
||||||
end
|
end
|
||||||
|
|
||||||
function callbacks.generate_scenario(params)
|
function callbacks.generate_scenario(params)
|
||||||
|
@ -172,9 +245,16 @@ function callbacks.generate_scenario(params)
|
||||||
scenario.map_data = callbacks.generate_map(params)
|
scenario.map_data = callbacks.generate_map(params)
|
||||||
for chamber in wml.child_range(params, "chamber") do
|
for chamber in wml.child_range(params, "chamber") do
|
||||||
local chamber_items = wml.get_child(chamber, "items")
|
local chamber_items = wml.get_child(chamber, "items")
|
||||||
if chamber.chance == 100 and chamber_items then
|
if (chamber.chance or 100) == 100 and chamber_items then
|
||||||
-- TODO: Should we support [event]same_location_as_previous=yes?
|
|
||||||
for i,tag in ipairs(chamber_items) do
|
for i,tag in ipairs(chamber_items) do
|
||||||
|
if tag.tag == 'event' and tag.contents.same_location_as_previous then
|
||||||
|
local evt_data = tag.contents;
|
||||||
|
evt_data.same_location_as_previous = nil
|
||||||
|
table.insert(evt_data, wml.tag.filter{
|
||||||
|
x = chamber.x,
|
||||||
|
y = chamber.y
|
||||||
|
})
|
||||||
|
end
|
||||||
table.insert(scenario, tag)
|
table.insert(scenario, tag)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -34,6 +34,13 @@ function wesnoth.map.read_location(...)
|
||||||
return nil, 0
|
return nil, 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function wesnoth.map.nearest_loc(to, candidates)
|
||||||
|
local F = wesnoth.require "functional"
|
||||||
|
return F.choose(candidates, function(loc)
|
||||||
|
return -wesnoth.map.distance_between(to, loc)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
if wesnoth.kernel_type() ~= "Application Lua Kernel" then
|
if wesnoth.kernel_type() ~= "Application Lua Kernel" then
|
||||||
-- possible terrain string inputs:
|
-- possible terrain string inputs:
|
||||||
-- A A^ A^B ^ ^B
|
-- A A^ A^B ^ ^B
|
||||||
|
@ -79,7 +86,7 @@ if wesnoth.kernel_type() ~= "Application Lua Kernel" then
|
||||||
if base == '' then -- ^ or ^B
|
if base == '' then -- ^ or ^B
|
||||||
-- There's no way to find a base to replace with in this case.
|
-- There's no way to find a base to replace with in this case.
|
||||||
-- Could use the existing base, but that's not really replacing both, is it?
|
-- Could use the existing base, but that's not really replacing both, is it?
|
||||||
error('replace_both: no base terrain specified')
|
error('replace.both: no base terrain specified')
|
||||||
elseif overlay == '' then -- A^
|
elseif overlay == '' then -- A^
|
||||||
-- This would normally mean replace base while preserving overlay,
|
-- This would normally mean replace base while preserving overlay,
|
||||||
-- but we actually want to replace base and clear overlay.
|
-- but we actually want to replace base and clear overlay.
|
||||||
|
@ -89,6 +96,13 @@ if wesnoth.kernel_type() ~= "Application Lua Kernel" then
|
||||||
return code
|
return code
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
wesnoth.map.replace = {
|
||||||
|
both = wesnoth.map.replace_both,
|
||||||
|
base = wesnoth.map.replace_base,
|
||||||
|
overlay = wesnoth.map.replace_overlay,
|
||||||
|
if_failed = wesnoth.map.replace_if_failed,
|
||||||
|
}
|
||||||
|
|
||||||
---Iterate over on-map hexes adjacent to a given hex.
|
---Iterate over on-map hexes adjacent to a given hex.
|
||||||
---@param map terrain_map
|
---@param map terrain_map
|
||||||
|
@ -195,9 +209,9 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
|
||||||
elseif key == 'terrain' then
|
elseif key == 'terrain' then
|
||||||
wesnoth.current.map[self] = val
|
wesnoth.current.map[self] = val
|
||||||
elseif key == 'base_terrain' then
|
elseif key == 'base_terrain' then
|
||||||
wesnoth.current.map[self] = wesnoth.map.replace_base(val)
|
wesnoth.current.map[self] = wesnoth.map.replace.base(val)
|
||||||
elseif key == 'overlay_terrain' then
|
elseif key == 'overlay_terrain' then
|
||||||
wesnoth.current.map[self] = wesnoth.map.replace_overlay(val)
|
wesnoth.current.map[self] = wesnoth.map.replace.overlay(val)
|
||||||
elseif key == 1 then
|
elseif key == 1 then
|
||||||
self.x = val
|
self.x = val
|
||||||
elseif key == 2 then
|
elseif key == 2 then
|
||||||
|
@ -306,9 +320,9 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
|
||||||
if new_ter == '' or type(new_ter) ~= 'string' then error('set_terrain: expected terrain string') end
|
if new_ter == '' or type(new_ter) ~= 'string' then error('set_terrain: expected terrain string') end
|
||||||
if replace_if_failed then
|
if replace_if_failed then
|
||||||
mode = mode or 'both'
|
mode = mode or 'both'
|
||||||
new_ter = wesnoth.map.replace_if_failed(new_ter, mode)
|
new_ter = wesnoth.map.replace.if_failed(new_ter, mode)
|
||||||
elseif mode == 'both' or mode == 'base' or mode == 'overlay' then
|
elseif mode == 'both' or mode == 'base' or mode == 'overlay' then
|
||||||
new_ter = wesnoth.map['replace_' .. mode](new_ter)
|
new_ter = wesnoth.map.replace[mode](new_ter)
|
||||||
elseif mode ~= nil then
|
elseif mode ~= nil then
|
||||||
error('set_terrain: invalid mode')
|
error('set_terrain: invalid mode')
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,37 @@
|
||||||
local LS = wesnoth.require "location_set"
|
local LS = wesnoth.require "location_set"
|
||||||
|
|
||||||
|
---@class mapgen_helper
|
||||||
local mapgen_helper, map_mt = {}, {__index = {}}
|
local mapgen_helper, map_mt = {}, {__index = {}}
|
||||||
|
|
||||||
function mapgen_helper.create_map(width,height,default_terrain)
|
---@class map_wrapper
|
||||||
local map = setmetatable({w = width, h = height}, map_mt)
|
---@field __map terrain_map
|
||||||
for i = 1, width * height do
|
|
||||||
table.insert(map, default_terrain or 'Gg')
|
---Create a map.
|
||||||
|
---@deprecated Use wesnoth.map.create instead
|
||||||
|
---@param width integer
|
||||||
|
---@param height integer
|
||||||
|
---@param default_terrain string
|
||||||
|
---@return map_wrapper
|
||||||
|
local function create_map(width,height,default_terrain)
|
||||||
|
return setmetatable({__map = wesnoth.map.create(width, height, default_terrain)}, map_mt)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function rand_from_ranges(list)
|
||||||
|
if type(list) == 'number' then return math.tointeger(list) end
|
||||||
|
local choices = {}
|
||||||
|
for n in stringx.iter_ranges(list) do
|
||||||
|
table.insert(choices, n)
|
||||||
end
|
end
|
||||||
return map
|
return math.tointeger(mathx.random_choice(choices)) or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
---Select a random location from lists of coordinates.
|
||||||
|
---@param x_list string
|
||||||
|
---@param y_list string
|
||||||
|
---@return integer
|
||||||
|
---@return integer
|
||||||
|
function mapgen_helper.random_location(x_list, y_list)
|
||||||
|
return rand_from_ranges(x_list), rand_from_ranges(y_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
local valid_transforms = {
|
local valid_transforms = {
|
||||||
|
@ -16,91 +40,120 @@ local valid_transforms = {
|
||||||
flip_xy = true,
|
flip_xy = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---Test whether a string is a valid transform
|
||||||
|
---@param t string
|
||||||
|
---@return boolean
|
||||||
function mapgen_helper.is_valid_transform(t)
|
function mapgen_helper.is_valid_transform(t)
|
||||||
return valid_transforms[t]
|
return valid_transforms[t]
|
||||||
end
|
end
|
||||||
|
|
||||||
local function loc_to_index(map,x,y)
|
---Set the tile at the specified location
|
||||||
return x + 1 + y * map.w
|
---@param map map_wrapper
|
||||||
end
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@param val string
|
||||||
function map_mt.__index.set_tile(map, x, y, val)
|
function map_mt.__index.set_tile(map, x, y, val)
|
||||||
map[loc_to_index(map, x, y)] = val
|
map.__map[{x, y}] = val
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Set the tile at the specified location
|
||||||
|
---@param map map_wrapper
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@return string
|
||||||
function map_mt.__index.get_tile(map, x, y)
|
function map_mt.__index.get_tile(map, x, y)
|
||||||
return map[loc_to_index(map,x,y)]
|
return map.__map[{x, y}]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Test if a tile is on the board (including the border)
|
||||||
|
---@param map map_wrapper
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@return boolean
|
||||||
function map_mt.__index.on_board(map, x, y)
|
function map_mt.__index.on_board(map, x, y)
|
||||||
return x >= 0 and y >= 0 and x < map.w and y < map.h
|
return map.__map:on_board(x, y, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Test if a tile is on the board (excluding the border)
|
||||||
|
---@param map map_wrapper
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@return boolean
|
||||||
function map_mt.__index.on_inner_board(map, x, y)
|
function map_mt.__index.on_inner_board(map, x, y)
|
||||||
return x >= 1 and y >= 1 and x < map.w - 1 and y < map.h - 1
|
return map.__map:on_board(x, y, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Add a named location at the given coordinates
|
||||||
|
---@param map map_wrapper
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@param name string
|
||||||
function map_mt.__index.add_location(map, x, y, name)
|
function map_mt.__index.add_location(map, x, y, name)
|
||||||
if not map.locations then
|
map.__map.special_locations[name] = {x, y}
|
||||||
map.locations = LS.create()
|
|
||||||
end
|
|
||||||
if map.locations:get(x, y) then
|
|
||||||
table.insert(map.locations:get(x, y), name)
|
|
||||||
else
|
|
||||||
map.locations:insert(x, y, {name})
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function map_mt.__index.flip_x(map)
|
----Flip the map horizontally
|
||||||
for y = 0, map.h - 1 do
|
---@param map terrain_map
|
||||||
for x = 0, map.w - 1 do
|
function mapgen_helper.flip_x(map)
|
||||||
local i = loc_to_index(map, x, y)
|
for x, y in map:iter(true) do
|
||||||
local j = loc_to_index(map, map.w - x - 1, y)
|
if x <= map.width / 2 or y <= map.height / 2 then
|
||||||
map[i], map[j] = map[j], map[i]
|
local x_opp = map.width - x - 1
|
||||||
|
map[{x,y}], map[{x_opp,y}] = map[{x_opp,y}], map[{x,y}]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
for id, loc in map.special_locations do
|
||||||
|
loc.x = map.width - loc.x - 1
|
||||||
function map_mt.__index.flip_y(map)
|
map.special_locations[id] = loc
|
||||||
for x = 0, map.w - 1 do
|
|
||||||
for y = 0, map.h - 1 do
|
|
||||||
local i = loc_to_index(map, x, y)
|
|
||||||
local j = loc_to_index(map, x, map.h - y - 1)
|
|
||||||
map[i], map[j] = map[j], map[i]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function map_mt.__index.flip_xy(map)
|
---Flip the map vertically
|
||||||
map:flip_x()
|
---@param map terrain_map
|
||||||
map:flip_y()
|
function mapgen_helper.flip_y(map)
|
||||||
|
for x, y in map:iter(true) do
|
||||||
|
if x <= map.width / 2 or y <= map.height / 2 then
|
||||||
|
local y_opp = map.height - y - 1
|
||||||
|
map[{x,y}], map[{x,y_opp}] = map[{x,y_opp}], map[{x,y}]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for id, loc in map.special_locations do
|
||||||
|
loc.y = map.height - loc.y - 1
|
||||||
|
map.special_locations[id] = loc
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Flip the map diagonally
|
||||||
|
---@param map terrain_map
|
||||||
|
function mapgen_helper.flip_xy(map)
|
||||||
|
for x, y in map:iter(true) do
|
||||||
|
if x <= map.width / 2 or y <= map.height / 2 then
|
||||||
|
local x_opp = map.width - x - 1
|
||||||
|
local y_opp = map.height - y - 1
|
||||||
|
map[{x,y}], map[{x_opp,y_opp}] = map[{x_opp,y_opp}], map[{x,y}]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for id, loc in map.special_locations do
|
||||||
|
loc.x = map.width - loc.x - 1
|
||||||
|
loc.y = map.height - loc.y - 1
|
||||||
|
map.special_locations[id] = loc
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Convert to string
|
||||||
|
---@param map map_wrapper
|
||||||
|
---@return string
|
||||||
function map_mt.__tostring(map)
|
function map_mt.__tostring(map)
|
||||||
local map_builder = {}
|
return map.__map.data
|
||||||
-- The coordinates are 0-based to match the in-game coordinates
|
|
||||||
for y = 0, map.h - 1 do
|
|
||||||
local string_builder = {}
|
|
||||||
for x = 0, map.w - 1 do
|
|
||||||
local tile_string = map:get_tile(x, y)
|
|
||||||
if map.locations and map.locations:get(x,y) then
|
|
||||||
for i,v in ipairs(map.locations:get(x,y)) do
|
|
||||||
tile_string = v .. ' ' .. tile_string
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(string_builder, tile_string)
|
|
||||||
end
|
|
||||||
assert(#string_builder == map.w)
|
|
||||||
table.insert(map_builder, table.concat(string_builder, ', '))
|
|
||||||
end
|
|
||||||
assert(#map_builder == map.h)
|
|
||||||
return table.concat(map_builder, '\n')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local adjacent_offset = {
|
local adjacent_offset = {
|
||||||
{ {0,-1}, {1,-1}, {1,0}, {0,1}, {-1,0}, {-1,-1} },
|
{ {0,-1}, {1,-1}, {1,0}, {0,1}, {-1,0}, {-1,-1} },
|
||||||
{ {0,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0} }
|
{ {0,-1}, {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0} }
|
||||||
}
|
}
|
||||||
|
---Iterates over adjacent tiles
|
||||||
|
---@param x integer
|
||||||
|
---@param y integer
|
||||||
|
---@return fun():integer,integer
|
||||||
function mapgen_helper.adjacent_tiles(x, y)
|
function mapgen_helper.adjacent_tiles(x, y)
|
||||||
local offset = adjacent_offset[2 - (x % 2)]
|
local offset = adjacent_offset[2 - (x % 2)]
|
||||||
local i = 0
|
local i = 0
|
||||||
|
@ -114,4 +167,84 @@ function mapgen_helper.adjacent_tiles(x, y)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@alias relative_anchor
|
||||||
|
---|'center'
|
||||||
|
---|'top-left'
|
||||||
|
---|'top-middle'
|
||||||
|
---|'top-right'
|
||||||
|
---|'bottom-left'
|
||||||
|
---|'bottom-middle'
|
||||||
|
---|'bottom-right'
|
||||||
|
---|'middle-left'
|
||||||
|
---|'middle-right'
|
||||||
|
|
||||||
|
---@class map_chamber : WMLTable
|
||||||
|
---@field ignore boolean
|
||||||
|
---@field id string
|
||||||
|
---@field x string
|
||||||
|
---@field y string
|
||||||
|
---@field terrain_clear string
|
||||||
|
---@field size integer
|
||||||
|
---@field jagged integer
|
||||||
|
---@field chance integer
|
||||||
|
---@field side integer
|
||||||
|
---@field relative_to relative_anchor
|
||||||
|
---@field require_player integer
|
||||||
|
|
||||||
|
---@class map_passage : WMLTable
|
||||||
|
---@field ignore boolean
|
||||||
|
---@field id string
|
||||||
|
---@field place_villages boolean
|
||||||
|
---@field destination string
|
||||||
|
---@field terrain_clear string
|
||||||
|
---@field windiness integer
|
||||||
|
---@field laziness integer
|
||||||
|
---@field width integer
|
||||||
|
---@field jagged integer
|
||||||
|
---@field chance integer
|
||||||
|
|
||||||
|
---Get a chamber by ID or index from the map generator settings.
|
||||||
|
---@param params WMLTable
|
||||||
|
---@param id_or_idx string|integer
|
||||||
|
---@return map_chamber?
|
||||||
|
function mapgen_helper.get_chamber(params, id_or_idx)
|
||||||
|
if type(id_or_idx) == 'number' then
|
||||||
|
local cfg, i = wml.get_nth_child(params, 'chamber', id_or_idx)
|
||||||
|
if not cfg then return nil end
|
||||||
|
return params[i].contents
|
||||||
|
elseif type(id_or_idx) == 'string' then
|
||||||
|
local cfg, i = wml.get_child(params, 'chamber', id_or_idx)
|
||||||
|
if not cfg then return nil end
|
||||||
|
return params[i].contents
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
---Get a passage by ID or index from the map generator settings.
|
||||||
|
---@param chamber map_chamber
|
||||||
|
---@param id_or_idx string|integer
|
||||||
|
---@return map_passage?
|
||||||
|
function mapgen_helper.get_passage(chamber, id_or_idx)
|
||||||
|
if type(id_or_idx) == 'number' then
|
||||||
|
local cfg, i = wml.get_nth_child(chamber, 'passage', id_or_idx)
|
||||||
|
if not cfg then return nil end
|
||||||
|
return chamber[i].contents
|
||||||
|
elseif type(id_or_idx) == 'string' then
|
||||||
|
local cfg, i = wml.get_child(chamber, 'passage', id_or_idx)
|
||||||
|
if not cfg then return nil end
|
||||||
|
return chamber[i].contents
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mapgen_helper.create_map = wesnoth.deprecate_api('mapgen_helper.create_map', 'wesnoth.map.create', 1, nil, create_map)
|
||||||
|
mapgen_helper.adjacent_tiles = wesnoth.deprecate_api('mapgen_helper.adjacent_tiles', 'wesnoth.map.iter_adjacent', 1, nil, mapgen_helper.adjacent_tiles)
|
||||||
|
map_mt.__index.set_tile = wesnoth.deprecate_api('oldmap:set_tile(x,y,ter)', 'map[{x,y}]=ter', 1, nil, map_mt.__index.set_tile)
|
||||||
|
map_mt.__index.get_tile = wesnoth.deprecate_api('oldmap:get_tile(x,y)', 'map[{x,y}]', 1, nil, map_mt.__index.get_tile)
|
||||||
|
map_mt.__index.on_board = wesnoth.deprecate_api('oldmap:on_board(x,y)', 'map:on_board(x,y,true)', 1, nil, map_mt.__index.on_board)
|
||||||
|
map_mt.__index.on_inner_board = wesnoth.deprecate_api('oldmap:on_inner_board(x,y)', 'map:on_board(x,y,false)', 1, nil, map_mt.__index.on_inner_board)
|
||||||
|
map_mt.__index.add_location = wesnoth.deprecate_api('oldmap:add_location(x,y,name)', 'map.special_locations[name]={x,y}', 1, nil, map_mt.__index.add_location)
|
||||||
|
map_mt.__index.flip_x = wesnoth.deprecate_api('oldmap:flip_x()', 'mapgen_helper.flip_x(map)', 1, nil, function(m) mapgen_helper.flip_x(m) end)
|
||||||
|
map_mt.__index.flip_y = wesnoth.deprecate_api('oldmap:flip_y()', 'mapgen_helper.flip_y(map)', 1, nil, function(m) mapgen_helper.flip_y(m) end)
|
||||||
|
map_mt.__index.flip_xy = wesnoth.deprecate_api('oldmap:flip_xy()', 'mapgen_helper.flip_xy(map)', 1, nil, function(m) mapgen_helper.flip_xy(m) end)
|
||||||
|
map_mt.__tostring = wesnoth.deprecate_api('tostring(map)', 'map.data', 1, nil, map_mt.__tostring)
|
||||||
|
|
||||||
return mapgen_helper
|
return mapgen_helper
|
||||||
|
|
|
@ -476,8 +476,8 @@ function wml_actions.terrain(cfg)
|
||||||
cfg.terrain = nil
|
cfg.terrain = nil
|
||||||
for i, loc in ipairs(wesnoth.map.find(cfg)) do
|
for i, loc in ipairs(wesnoth.map.find(cfg)) do
|
||||||
local replacement = cfg.replace_if_failed
|
local replacement = cfg.replace_if_failed
|
||||||
and wesnoth.map.replace_if_failed(terrain, layer)
|
and wesnoth.map.replace.if_failed(terrain, layer)
|
||||||
or wesnoth.map['replace_' .. layer](terrain)
|
or wesnoth.map.replace[layer](terrain)
|
||||||
wesnoth.current.map[loc] = replacement
|
wesnoth.current.map[loc] = replacement
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
141
data/multiplayer/gui/cave_map_settings.cfg
Normal file
141
data/multiplayer/gui/cave_map_settings.cfg
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
#textdomain wesnoth-lib
|
||||||
|
|
||||||
|
{gui/macros}
|
||||||
|
|
||||||
|
#define MAP_OPTION_CONTROL ID LABEL TYPE WML
|
||||||
|
[row]
|
||||||
|
[column]
|
||||||
|
grow_factor=0
|
||||||
|
horizontal_grow=true
|
||||||
|
border=all
|
||||||
|
border_size=5
|
||||||
|
[label]
|
||||||
|
definition=default
|
||||||
|
label={LABEL}
|
||||||
|
text_alignment=right
|
||||||
|
[/label]
|
||||||
|
[/column]
|
||||||
|
[column]
|
||||||
|
grow_factor=1
|
||||||
|
horizontal_grow=true
|
||||||
|
border=all
|
||||||
|
border_size=10
|
||||||
|
[{TYPE}]
|
||||||
|
id={ID}
|
||||||
|
{WML}
|
||||||
|
[/{TYPE}]
|
||||||
|
[/column]
|
||||||
|
[column]
|
||||||
|
grow_factor=0
|
||||||
|
horizontal_grow=true
|
||||||
|
border=all
|
||||||
|
border_size=5
|
||||||
|
{GUI_FORCE_WIDGET_MINIMUM_SIZE 100 0 (
|
||||||
|
[label]
|
||||||
|
id={ID}_label
|
||||||
|
definition=default
|
||||||
|
[/label]
|
||||||
|
)}
|
||||||
|
[/column]
|
||||||
|
[/row]
|
||||||
|
#enddef
|
||||||
|
|
||||||
|
[resolution]
|
||||||
|
definition = "default"
|
||||||
|
automatic_placement = true
|
||||||
|
vertical_placement = "center"
|
||||||
|
horizontal_placement = "center"
|
||||||
|
maximum_height = 600
|
||||||
|
[tooltip]
|
||||||
|
id=tooltip
|
||||||
|
[/tooltip]
|
||||||
|
[helptip]
|
||||||
|
id=tooltip
|
||||||
|
[/helptip]
|
||||||
|
[grid]
|
||||||
|
[row]
|
||||||
|
grow_factor=0
|
||||||
|
[column]
|
||||||
|
grow_factor=1
|
||||||
|
border=all
|
||||||
|
border_size=5
|
||||||
|
horizontal_alignment=left
|
||||||
|
[label]
|
||||||
|
definition=title
|
||||||
|
label=_"Map Generator Settings"
|
||||||
|
[/label]
|
||||||
|
[/column]
|
||||||
|
[/row]
|
||||||
|
[row]
|
||||||
|
grow_factor=1
|
||||||
|
[column]
|
||||||
|
horizontal_grow=true
|
||||||
|
vertical_grow=true
|
||||||
|
[grid]
|
||||||
|
{MAP_OPTION_CONTROL players _"Players:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=2
|
||||||
|
maximum_value=8
|
||||||
|
step_size=1
|
||||||
|
)}
|
||||||
|
{MAP_OPTION_CONTROL width _"Width:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=20
|
||||||
|
maximum_value=100
|
||||||
|
step_size=1
|
||||||
|
)}
|
||||||
|
{MAP_OPTION_CONTROL height _"Height:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=20
|
||||||
|
maximum_value=100
|
||||||
|
step_size=1
|
||||||
|
)}
|
||||||
|
{MAP_OPTION_CONTROL village_density _"Villages:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=0
|
||||||
|
maximum_value=50
|
||||||
|
step_size=1
|
||||||
|
)}
|
||||||
|
#textdomain wesnoth-multiplayer
|
||||||
|
{MAP_OPTION_CONTROL jagged _"Chamber Jaggedness:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=10
|
||||||
|
maximum_value=50
|
||||||
|
step_size=5
|
||||||
|
)}
|
||||||
|
{MAP_OPTION_CONTROL lake_size _"Lake Size:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=5
|
||||||
|
maximum_value=50
|
||||||
|
step_size=5
|
||||||
|
)}
|
||||||
|
{MAP_OPTION_CONTROL windiness _"Passage Windiness:" slider (
|
||||||
|
definition=minimal
|
||||||
|
minimum_value=1
|
||||||
|
maximum_value=20
|
||||||
|
step_size=1
|
||||||
|
)}
|
||||||
|
#textdomain wesnoth-lib
|
||||||
|
{MAP_OPTION_CONTROL roads "" toggle_button (
|
||||||
|
definition=checkbox
|
||||||
|
label=_"Roads Between Castles"
|
||||||
|
)}
|
||||||
|
[/grid]
|
||||||
|
[/column]
|
||||||
|
[/row]
|
||||||
|
[row]
|
||||||
|
grow_factor=0
|
||||||
|
[column]
|
||||||
|
border=all
|
||||||
|
border_size=5
|
||||||
|
horizontal_alignment=right
|
||||||
|
#textdomain wesnoth-lib
|
||||||
|
[button]
|
||||||
|
definition=default
|
||||||
|
id=ok
|
||||||
|
label=_"Close"
|
||||||
|
[/button]
|
||||||
|
[/column]
|
||||||
|
[/row]
|
||||||
|
[/grid]
|
||||||
|
[/resolution]
|
119
data/multiplayer/gui/cave_map_settings.lua
Normal file
119
data/multiplayer/gui/cave_map_settings.lua
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
local params = ...
|
||||||
|
local MG = wesnoth.require "mapgen_helper"
|
||||||
|
|
||||||
|
local function pre_show(window)
|
||||||
|
window.players.value = params.nplayers
|
||||||
|
window.width.value = params.map_width
|
||||||
|
window.height.value = params.map_height
|
||||||
|
window.village_density.value = params.village_density
|
||||||
|
|
||||||
|
local central_chamber = MG.get_chamber(params, 'central_chamber')
|
||||||
|
if central_chamber then
|
||||||
|
window.jagged.value = central_chamber.jagged
|
||||||
|
else
|
||||||
|
error('cave_map_settings requires a [chamber] with id=central_chamber')
|
||||||
|
end
|
||||||
|
|
||||||
|
local lake = MG.get_chamber(params, 'lake')
|
||||||
|
if lake then
|
||||||
|
window.lake_size.value = lake.size
|
||||||
|
else
|
||||||
|
error('cave_map_settings requires a [chamber] with id=lake')
|
||||||
|
end
|
||||||
|
|
||||||
|
local first_player = MG.get_chamber(params, 'player_1')
|
||||||
|
if first_player then
|
||||||
|
local tunnel = MG.get_passage(first_player, 1)
|
||||||
|
if tunnel then
|
||||||
|
window.windiness.value = tunnel.windiness
|
||||||
|
else
|
||||||
|
error('cave_map_settings requires that each player [chamber] contains at least two [passage] tags')
|
||||||
|
end
|
||||||
|
|
||||||
|
local road = MG.get_passage(first_player, 2)
|
||||||
|
if road then
|
||||||
|
window.roads.selected = not road.ignore
|
||||||
|
else
|
||||||
|
error('cave_map_settings requires that each player [chamber] contains at least two [passage] tags')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
error('cave_map_settings requires a [chamber] for each player with id=player_n where n is the player number')
|
||||||
|
end
|
||||||
|
|
||||||
|
local all_players = {first_player}
|
||||||
|
for i = 2, #params do
|
||||||
|
local next_player = MG.get_chamber(params, 'player_' .. i)
|
||||||
|
if next_player then
|
||||||
|
table.insert(all_players, next_player)
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Init labels
|
||||||
|
window.players_label.label = window.players.value
|
||||||
|
window.width_label.label = window.width.value
|
||||||
|
window.height_label.label = window.height.value
|
||||||
|
window.village_density_label.label = window.village_density.value
|
||||||
|
window.jagged_label.label = window.jagged.value
|
||||||
|
window.lake_size_label.label = window.lake_size.value
|
||||||
|
window.windiness_label.label = window.windiness.value
|
||||||
|
|
||||||
|
-- Callbacks...
|
||||||
|
function window.players.on_modified()
|
||||||
|
params.nplayers = window.players.value
|
||||||
|
window.players_label.label = params.nplayers
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.width.on_modified()
|
||||||
|
params.map_width = window.width.value
|
||||||
|
window.width_label.label = params.map_width
|
||||||
|
central_chamber.size = mathx.round((params.map_height + params.map_width) / 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.height.on_modified()
|
||||||
|
params.map_height = window.height.value
|
||||||
|
window.height_label.label = params.map_height
|
||||||
|
central_chamber.size = mathx.round((params.map_height + params.map_width) / 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.village_density.on_modified()
|
||||||
|
params.village_density = window.village_density.value
|
||||||
|
-- Need wesnoth-lib for the village density label
|
||||||
|
local _ = wesnoth.textdomain "wesnoth-lib"
|
||||||
|
window.village_density_label.label = (_"$villages/1000 tiles"):vformat{villages = params.village_density}
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.jagged.on_modified()
|
||||||
|
local val = window.jagged.value
|
||||||
|
central_chamber.jagged = val
|
||||||
|
window.jagged_label.label = val
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.lake_size.on_modified()
|
||||||
|
local val = window.lake_size.value
|
||||||
|
lake.size = val
|
||||||
|
window.lake_size_label.label = val
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.windiness.on_modified()
|
||||||
|
local val = window.windiness.value
|
||||||
|
for i = 1, #all_players do
|
||||||
|
local tunnel = MG.get_passage(all_players[i], 1)
|
||||||
|
tunnel.windiness = val
|
||||||
|
end
|
||||||
|
window.windiness_label.label = val
|
||||||
|
end
|
||||||
|
|
||||||
|
function window.roads.on_modified()
|
||||||
|
local val = not window.roads.selected
|
||||||
|
for i = 1, #all_players do
|
||||||
|
local road = MG.get_passage(all_players[i], 2)
|
||||||
|
road.ignore = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local dialog = wml.load "multiplayer/gui/cave_map_settings.cfg"
|
||||||
|
gui.show_dialog(wml.get_child(dialog, 'resolution'), pre_show)
|
||||||
|
return params
|
212
data/multiplayer/scenarios/Random_Scenario_Cave.cfg
Normal file
212
data/multiplayer/scenarios/Random_Scenario_Cave.cfg
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
#textdomain wesnoth-multiplayer
|
||||||
|
|
||||||
|
#define CLEAR_TERRAINS
|
||||||
|
Rb,Rb,Rb,Rb,Rb,Rb,Rb,Rb^Tf,Rb^Ii,Sm,Sm,Uue,Rb^Fetd,Rb^Fdw#enddef
|
||||||
|
|
||||||
|
#define ROAD_COSTS
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb
|
||||||
|
cost=2
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Tf
|
||||||
|
cost=20
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Fdw
|
||||||
|
cost=20
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Uue
|
||||||
|
cost=10
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Ii
|
||||||
|
cost=2
|
||||||
|
convert_to=Ur^Ii
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Uue
|
||||||
|
cost=50
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Sm
|
||||||
|
cost=75
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Fetd
|
||||||
|
cost=75
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Fdw
|
||||||
|
cost=75
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Wwg
|
||||||
|
cost=100
|
||||||
|
convert_to_bridge=Wwg^Bw|,Wwg^Bw/,Wwg^Bw\
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Wwf
|
||||||
|
cost=100
|
||||||
|
convert_to_bridge=Wwf^Bw|,Wwf^Bw/,Wwf^Bw\
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Ur
|
||||||
|
cost=2
|
||||||
|
convert_to=Ur
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Ur^Ii
|
||||||
|
cost=2
|
||||||
|
convert_to=Ur^Ii
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Vu
|
||||||
|
cost=5
|
||||||
|
convert_to=Ur^Vu
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Rb^Vud
|
||||||
|
cost=5
|
||||||
|
convert_to=Ur^Vud
|
||||||
|
[/road_cost]
|
||||||
|
[road_cost]
|
||||||
|
terrain=Uue^Vud
|
||||||
|
cost=55
|
||||||
|
convert_to=Ur^Vud
|
||||||
|
[/road_cost]
|
||||||
|
# We don't want to carve a new tunnel now,
|
||||||
|
# so give walls a ridiculously high cost.
|
||||||
|
[road_cost]
|
||||||
|
terrain=Xue
|
||||||
|
cost=1000
|
||||||
|
convert_to=Uue
|
||||||
|
[/road_cost]
|
||||||
|
#enddef
|
||||||
|
|
||||||
|
#define PLAYER_CHAMBER NUMBER X Y REL
|
||||||
|
[chamber]
|
||||||
|
id=player_{NUMBER}
|
||||||
|
require_player={NUMBER}
|
||||||
|
x={X}
|
||||||
|
y={Y}
|
||||||
|
relative_to={REL}
|
||||||
|
size=5
|
||||||
|
jagged=2
|
||||||
|
[item_location]
|
||||||
|
id={NUMBER}
|
||||||
|
place_castle=yes
|
||||||
|
[/item_location]
|
||||||
|
[items]
|
||||||
|
[side]
|
||||||
|
side={NUMBER}
|
||||||
|
[/side]
|
||||||
|
[/items]
|
||||||
|
[passage]
|
||||||
|
destination=central_chamber
|
||||||
|
windiness=3
|
||||||
|
laziness=2
|
||||||
|
jagged=3
|
||||||
|
width=3
|
||||||
|
terrain_clear={CLEAR_TERRAINS}
|
||||||
|
place_villages=yes
|
||||||
|
# Try not to plow thru the lake, but if we must, use ford
|
||||||
|
[road_cost]
|
||||||
|
terrain=Wwg
|
||||||
|
cost=100
|
||||||
|
convert_to=Wwf
|
||||||
|
[/road_cost]
|
||||||
|
[/passage]
|
||||||
|
[passage]
|
||||||
|
ignore=no
|
||||||
|
destination=central_chamber
|
||||||
|
windiness=2
|
||||||
|
jagged=2
|
||||||
|
width=2
|
||||||
|
{ROAD_COSTS}
|
||||||
|
[/passage]
|
||||||
|
[/chamber]
|
||||||
|
#enddef
|
||||||
|
|
||||||
|
[multiplayer]
|
||||||
|
# This id is currently hardcoded by the random map generator of the editor
|
||||||
|
id=multiplayer_Random_Map_Cave
|
||||||
|
name= _ "Random map (Cave)"
|
||||||
|
description= _ "A random map set in a cave. Note: random maps are often unbalanced, but if you have time, you can regenerate them until you get a good one."
|
||||||
|
scenario_generation=lua
|
||||||
|
[generator]
|
||||||
|
id="cavegen"
|
||||||
|
config_name=_"Lua Cave Generator"
|
||||||
|
create_scenario=<<
|
||||||
|
return wesnoth.require("lua/cave_map_generator.lua").generate_scenario(...)
|
||||||
|
>>
|
||||||
|
user_config=<<
|
||||||
|
return wesnoth.dofile("multiplayer/gui/cave_map_settings.lua", ...)
|
||||||
|
>>
|
||||||
|
[scenario]
|
||||||
|
name= _ "Random map (Cave)"
|
||||||
|
id=multiplayer_Random_Map_Cave
|
||||||
|
{DEFAULT_MUSIC_PLAYLIST}
|
||||||
|
{DEFAULT_SCHEDULE}
|
||||||
|
[/scenario]
|
||||||
|
terrain_clear={CLEAR_TERRAINS}
|
||||||
|
terrain_wall=Xue
|
||||||
|
terrain_castle=Co
|
||||||
|
terrain_keep=Ko
|
||||||
|
terrain_village=Rb^Vu,Rb^Vu,Rb^Vu,Rb^Vu,Rb^Vu,Rb^Vud,Rb^Vud,Uue^Vud
|
||||||
|
|
||||||
|
map_width=40
|
||||||
|
map_height=40
|
||||||
|
village_density=25
|
||||||
|
nplayers=4
|
||||||
|
|
||||||
|
[chamber]
|
||||||
|
id=central_chamber
|
||||||
|
x=14-26
|
||||||
|
y=14-26
|
||||||
|
size=20
|
||||||
|
jagged=30
|
||||||
|
[/chamber]
|
||||||
|
[chamber]
|
||||||
|
id=lake
|
||||||
|
x=14-26
|
||||||
|
y=14-26
|
||||||
|
size=5
|
||||||
|
jagged=12
|
||||||
|
terrain_clear=Wwg
|
||||||
|
# Without this, there is a chance that the lake is entirely disconnected from everything else
|
||||||
|
[passage]
|
||||||
|
destination=central_chamber
|
||||||
|
windiness=5
|
||||||
|
laziness=3
|
||||||
|
jagged=4
|
||||||
|
width=1
|
||||||
|
terrain_clear=Wwg
|
||||||
|
[/passage]
|
||||||
|
[/chamber]
|
||||||
|
{PLAYER_CHAMBER 1 3-10 3-10 top-left}
|
||||||
|
{PLAYER_CHAMBER 2 3-10 3-10 bottom-right}
|
||||||
|
{PLAYER_CHAMBER 3 3-10 3-10 bottom-left}
|
||||||
|
{PLAYER_CHAMBER 4 3-10 3-10 top-right}
|
||||||
|
{PLAYER_CHAMBER 5 3-10 3-10 top-middle}
|
||||||
|
{PLAYER_CHAMBER 6 3-10 3-10 bottom-middle}
|
||||||
|
{PLAYER_CHAMBER 7 3-10 3-10 middle-left}
|
||||||
|
{PLAYER_CHAMBER 8 3-10 3-10 middle-right}
|
||||||
|
[/generator]
|
||||||
|
[/multiplayer]
|
||||||
|
|
||||||
|
#undef CLEAR_TERRAINS
|
||||||
|
#undef ROAD_COSTS
|
||||||
|
#undef PLAYER_CHAMBER
|
||||||
|
#undef MAP_OPTION_CONTROL
|
|
@ -1,22 +1,39 @@
|
||||||
|
|
||||||
#define CHAMBER_TAG_CONTENTS
|
#define CHAMBER_TAG_CONTENTS
|
||||||
max=infinite
|
max=infinite
|
||||||
|
{DEFAULT_KEY ignore bool no}
|
||||||
{SIMPLE_KEY id string}
|
{SIMPLE_KEY id string}
|
||||||
{SIMPLE_KEY x unsigned_range_list}
|
{SIMPLE_KEY x unsigned_range_list}
|
||||||
{SIMPLE_KEY y unsigned_range_list}
|
{SIMPLE_KEY y unsigned_range_list}
|
||||||
|
{SIMPLE_KEY terrain_clear terrain_list}
|
||||||
{SIMPLE_KEY size unsigned}
|
{SIMPLE_KEY size unsigned}
|
||||||
{SIMPLE_KEY jagged unsigned}
|
{SIMPLE_KEY jagged unsigned}
|
||||||
{DEFAULT_KEY chance unsigned 100}
|
{DEFAULT_KEY chance unsigned 100}
|
||||||
{SIMPLE_KEY side unsigned}
|
{SIMPLE_KEY side unsigned}
|
||||||
|
{SIMPLE_KEY relative_to relative_anchor}
|
||||||
|
{SIMPLE_KEY require_player unsigned}
|
||||||
[tag]
|
[tag]
|
||||||
name="passage"
|
name="passage"
|
||||||
max=infinite
|
max=infinite
|
||||||
|
{DEFAULT_KEY ignore bool no}
|
||||||
|
{SIMPLE_KEY id string}
|
||||||
|
{SIMPLE_KEY place_villages bool}
|
||||||
{SIMPLE_KEY destination string}
|
{SIMPLE_KEY destination string}
|
||||||
|
{SIMPLE_KEY terrain_clear terrain_list}
|
||||||
{SIMPLE_KEY windiness unsigned}
|
{SIMPLE_KEY windiness unsigned}
|
||||||
{SIMPLE_KEY laziness unsigned}
|
{SIMPLE_KEY laziness unsigned}
|
||||||
{SIMPLE_KEY width unsigned}
|
{SIMPLE_KEY width unsigned}
|
||||||
{SIMPLE_KEY jagged unsigned}
|
{SIMPLE_KEY jagged unsigned}
|
||||||
{DEFAULT_KEY chance unsigned 100}
|
{DEFAULT_KEY chance unsigned 100}
|
||||||
|
[tag]
|
||||||
|
name="road_cost"
|
||||||
|
max=infinite
|
||||||
|
{REQUIRED_KEY terrain terrain_code}
|
||||||
|
{SIMPLE_KEY cost unsigned}
|
||||||
|
{SIMPLE_KEY convert_to terrain_code}
|
||||||
|
# TODO: This is not quite right, it has to be exactly 3 terrain codes (but default generator schema also gets that wrong)
|
||||||
|
{SIMPLE_KEY convert_to_bridge terrain_list}
|
||||||
|
[/tag]
|
||||||
[/tag]
|
[/tag]
|
||||||
[tag]
|
[tag]
|
||||||
name="item_location"
|
name="item_location"
|
||||||
|
@ -47,13 +64,20 @@
|
||||||
{SIMPLE_KEY map_width unsigned}
|
{SIMPLE_KEY map_width unsigned}
|
||||||
{SIMPLE_KEY map_height unsigned}
|
{SIMPLE_KEY map_height unsigned}
|
||||||
{SIMPLE_KEY village_density unsigned}
|
{SIMPLE_KEY village_density unsigned}
|
||||||
|
{SIMPLE_KEY nplayers unsigned}
|
||||||
{SIMPLE_KEY transform map_transform}
|
{SIMPLE_KEY transform map_transform}
|
||||||
{SIMPLE_KEY transform_chance unsigned}
|
{SIMPLE_KEY transform_chance unsigned}
|
||||||
{SIMPLE_KEY terrain_wall terrain_code}
|
{SIMPLE_KEY terrain_wall terrain_code}
|
||||||
{SIMPLE_KEY terrain_castle terrain_code}
|
{SIMPLE_KEY terrain_castle terrain_code}
|
||||||
{SIMPLE_KEY terrain_keep terrain_code}
|
{SIMPLE_KEY terrain_keep terrain_code}
|
||||||
{SIMPLE_KEY terrain_village terrain_code}
|
{SIMPLE_KEY terrain_village terrain_list}
|
||||||
{SIMPLE_KEY terrain_clear terrain_code}
|
{SIMPLE_KEY terrain_clear terrain_list}
|
||||||
|
{LINK_TAG "scenario"}
|
||||||
|
[/then]
|
||||||
|
[/if]
|
||||||
|
[if]
|
||||||
|
glob_on_create_map=*cave_map_generator*
|
||||||
|
[then]
|
||||||
[tag]
|
[tag]
|
||||||
name="chamber"
|
name="chamber"
|
||||||
{CHAMBER_TAG_CONTENTS}
|
{CHAMBER_TAG_CONTENTS}
|
||||||
|
@ -70,6 +94,11 @@
|
||||||
[tag]
|
[tag]
|
||||||
name="items"
|
name="items"
|
||||||
super="scenario"
|
super="scenario"
|
||||||
|
[tag]
|
||||||
|
name="event"
|
||||||
|
super="event"
|
||||||
|
{SIMPLE_KEY same_location_as_previous bool}
|
||||||
|
[/tag]
|
||||||
[/tag]
|
[/tag]
|
||||||
[/tag]
|
[/tag]
|
||||||
[tag]
|
[tag]
|
||||||
|
|
|
@ -508,6 +508,10 @@
|
||||||
name="theme_action"
|
name="theme_action"
|
||||||
value="checkbox|radiobox|image|turbo"
|
value="checkbox|radiobox|image|turbo"
|
||||||
[/type]
|
[/type]
|
||||||
|
[type]
|
||||||
|
name="relative_anchor"
|
||||||
|
value="center|top-(left|middle|right)|bottom-(left|middle|right)|middle-(left|right)"
|
||||||
|
[/type]
|
||||||
[tag]
|
[tag]
|
||||||
name="root"
|
name="root"
|
||||||
min=1
|
min=1
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "gui/widgets/slider.hpp"
|
#include "gui/widgets/slider.hpp"
|
||||||
#include "gui/widgets/status_label_helper.hpp"
|
#include "gui/widgets/status_label_helper.hpp"
|
||||||
#include "gettext.hpp"
|
#include "gettext.hpp"
|
||||||
|
#include "formula/string_utils.hpp"
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
@ -67,7 +68,12 @@ void generator_settings::pre_show()
|
||||||
// Do this *after* assigning the 'update_*_label_` functions or the game will crash!
|
// Do this *after* assigning the 'update_*_label_` functions or the game will crash!
|
||||||
adjust_minimum_size_by_players();
|
adjust_minimum_size_by_players();
|
||||||
|
|
||||||
gui2::bind_status_label<slider>(this, "villages", [](const slider& s) { return t_string(formatter() << s.get_value() << _("/1000 tiles")); });
|
gui2::bind_status_label<slider>(this, "villages", [](const slider& s) {
|
||||||
|
std::string val = std::to_string(s.get_value());
|
||||||
|
utils::string_map args;
|
||||||
|
args["villages"] = val;
|
||||||
|
return t_string(VGETTEXT("$villages/1000 tiles", args));
|
||||||
|
});
|
||||||
gui2::bind_status_label<slider>(this, "castle_size");
|
gui2::bind_status_label<slider>(this, "castle_size");
|
||||||
gui2::bind_status_label<slider>(this, "landform", [](const slider& s) {
|
gui2::bind_status_label<slider>(this, "landform", [](const slider& s) {
|
||||||
return s.get_value() == 0 ? _("Inland") : (s.get_value() < max_coastal ? _("Coastal") : _("Island")); });
|
return s.get_value() == 0 ? _("Inland") : (s.get_value() < max_coastal ? _("Coastal") : _("Island")); });
|
||||||
|
|
|
@ -298,6 +298,18 @@ static int impl_terrainmap_get(lua_State *L)
|
||||||
luaL_setmetatable(L, maplocationKey);
|
luaL_setmetatable(L, maplocationKey);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if(strcmp(m, "size") == 0) {
|
||||||
|
lua_pushinteger(L, tm.total_width());
|
||||||
|
lua_pushinteger(L, tm.total_height());
|
||||||
|
lua_pushinteger(L, tm.border_size());
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if(strcmp(m, "playable_size") == 0) {
|
||||||
|
lua_pushinteger(L, tm.w());
|
||||||
|
lua_pushinteger(L, tm.h());
|
||||||
|
lua_pushinteger(L, tm.border_size());
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
if(luaW_getglobal(L, "wesnoth", "map", m)) {
|
if(luaW_getglobal(L, "wesnoth", "map", m)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,11 +253,16 @@ mapgen_lua_kernel::mapgen_lua_kernel(const config* vars)
|
||||||
// Map methods
|
// Map methods
|
||||||
{ "find", &intf_mg_get_locations },
|
{ "find", &intf_mg_get_locations },
|
||||||
{ "find_in_radius", &intf_mg_get_tiles_radius },
|
{ "find_in_radius", &intf_mg_get_tiles_radius },
|
||||||
|
{ "on_board", &intf_on_board },
|
||||||
|
{ "on_border", &intf_on_border },
|
||||||
|
{ "iter", &intf_terrainmap_iter },
|
||||||
|
{ "terrain_mask", &intf_terrain_mask },
|
||||||
// Static functions
|
// Static functions
|
||||||
{ "filter", &intf_terrainfilter_create },
|
{ "filter", &intf_terrainfilter_create },
|
||||||
{ "create", &intf_terrainmap_create },
|
{ "create", &intf_terrainmap_create },
|
||||||
{ "generate_height_map", &intf_default_generate_height_map },
|
{ "generate_height_map", &intf_default_generate_height_map },
|
||||||
{ "generate", &intf_default_generate },
|
{ "generate", &intf_default_generate },
|
||||||
|
{ "replace_if_failed", &intf_replace_if_failed },
|
||||||
{ nullptr, nullptr }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -302,9 +307,15 @@ void mapgen_lua_kernel::run_generator(const char * prog, const config & generato
|
||||||
protected_call(1, 1, std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2));
|
protected_call(1, 1, std::bind(&lua_kernel_base::throw_exception, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mapgen_lua_kernel::user_config(const char * prog, const config & generator)
|
void mapgen_lua_kernel::user_config(const char * prog, config & generator)
|
||||||
{
|
{
|
||||||
run_generator(prog, generator);
|
run_generator(prog, generator);
|
||||||
|
if(!lua_isnoneornil(mState, -1) && !luaW_toconfig(mState, -1, generator)) {
|
||||||
|
std::string msg = "expected a string, found a ";
|
||||||
|
msg += lua_typename(mState, lua_type(mState, -1));
|
||||||
|
lua_pop(mState, 1);
|
||||||
|
throw game::lua_error(msg.c_str(),"bad return value");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mapgen_lua_kernel::intf_get_variable(lua_State *L)
|
int mapgen_lua_kernel::intf_get_variable(lua_State *L)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user