mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-15 17:19:59 +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
|
||||
end
|
||||
--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 {
|
||||
terrain="C" .. castle,
|
||||
wml.tag["and"] {
|
||||
|
|
|
@ -34,7 +34,7 @@ function set_terrain_impl(data)
|
|||
for j = 1, num_tiles do
|
||||
local loc = locs[i][j]
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,32 +5,65 @@ 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 map = wesnoth.map.create(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
|
||||
if locs_set:get(x,y) or not map:on_board(x, y, true) or size == 0 then
|
||||
return
|
||||
end
|
||||
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
|
||||
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
|
||||
local function clear_tile(x, y, terrain_clear)
|
||||
if not map:on_board(x,y,true) then
|
||||
return
|
||||
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
|
||||
end
|
||||
local tile = mathx.random_choice(terrain_clear or params.terrain_clear)
|
||||
map[{x, y}] = wesnoth.map.replace.both(tile)
|
||||
local r = random(1000)
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -39,25 +72,43 @@ function callbacks.generate_map(params)
|
|||
local passages = {}
|
||||
|
||||
for chamber in wml.child_range(params, "chamber") do
|
||||
if chamber.ignore then goto continue end
|
||||
local chance = tonumber(chamber.chance) or 100
|
||||
local x = chamber.x
|
||||
local y = chamber.y
|
||||
local x, y = MG.random_location(chamber.x, 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
|
||||
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
|
||||
if type(chamber.require_player) == "number" and chamber.require_player > params.nplayers then
|
||||
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 = {}
|
||||
|
@ -71,19 +122,29 @@ function callbacks.generate_map(params)
|
|||
locs_set = locs_set,
|
||||
id = id,
|
||||
items = items,
|
||||
data = chamber,
|
||||
})
|
||||
chambers_by_id[id] = chambers[#chambers]
|
||||
for passage in wml.child_range(chamber, "passage") do
|
||||
if passage.ignore then goto continue end
|
||||
local dst = chambers_by_id[passage.destination]
|
||||
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, {
|
||||
start_x = x,
|
||||
start_y = y,
|
||||
dest_x = dst.center_x,
|
||||
dest_y = dst.center_y,
|
||||
data = passage,
|
||||
costs = road_costs,
|
||||
roads = road_ops,
|
||||
})
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
|
@ -91,8 +152,8 @@ function callbacks.generate_map(params)
|
|||
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
|
||||
clear_tile(x, y, v.data.terrain_clear)
|
||||
if map:on_board(x, y, false) then
|
||||
table.insert(locs_list, {x,y})
|
||||
end
|
||||
end
|
||||
|
@ -103,13 +164,13 @@ function callbacks.generate_map(params)
|
|||
local x, y = table.unpack(loc)
|
||||
|
||||
if item.id then
|
||||
map:add_location(x, y, item.id)
|
||||
map.special_locations[item.id] = {x, y}
|
||||
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)
|
||||
map[{x, y}] = wesnoth.map.replace.both(params.terrain_keep)
|
||||
for x2, y2 in map:iter_adjacent(x, y) do
|
||||
map[{x2, y2}] = wesnoth.map.replace.both(params.terrain_castle)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -127,8 +188,10 @@ function callbacks.generate_map(params)
|
|||
return math.huge
|
||||
end
|
||||
local res = 1.0
|
||||
if map:get_tile(x, y) == params.terrain_wall then
|
||||
res = laziness
|
||||
local tile = map[{x, y}]
|
||||
res = v.costs[tile] or 1.0
|
||||
if tile == params.terrain_wall then
|
||||
res = laziness * res
|
||||
end
|
||||
if windiness > 1 then
|
||||
res = res * random(windiness)
|
||||
|
@ -140,8 +203,18 @@ function callbacks.generate_map(params)
|
|||
for j, loc in ipairs(path) do
|
||||
local locs_set = LS.create()
|
||||
build_chamber(loc[1], loc[2], locs_set, width, jagged)
|
||||
local prev_x, prev_y
|
||||
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
|
||||
|
@ -159,11 +232,11 @@ function callbacks.generate_map(params)
|
|||
wml.error("Unknown transformation '" .. t .. "'")
|
||||
end
|
||||
end
|
||||
map[transforms[random(#transforms)]](map)
|
||||
MG[transforms[random(#transforms)]](map)
|
||||
end
|
||||
end
|
||||
|
||||
return tostring(map)
|
||||
return map.data
|
||||
end
|
||||
|
||||
function callbacks.generate_scenario(params)
|
||||
|
@ -172,9 +245,16 @@ function callbacks.generate_scenario(params)
|
|||
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?
|
||||
if (chamber.chance or 100) == 100 and chamber_items then
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,6 +34,13 @@ function wesnoth.map.read_location(...)
|
|||
return nil, 0
|
||||
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
|
||||
-- possible terrain string inputs:
|
||||
-- A A^ A^B ^ ^B
|
||||
|
@ -79,7 +86,7 @@ if wesnoth.kernel_type() ~= "Application Lua Kernel" then
|
|||
if base == '' then -- ^ or ^B
|
||||
-- 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?
|
||||
error('replace_both: no base terrain specified')
|
||||
error('replace.both: no base terrain specified')
|
||||
elseif overlay == '' then -- A^
|
||||
-- This would normally mean replace base while preserving 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
|
||||
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.
|
||||
---@param map terrain_map
|
||||
|
@ -195,9 +209,9 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
|
|||
elseif key == 'terrain' then
|
||||
wesnoth.current.map[self] = val
|
||||
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
|
||||
wesnoth.current.map[self] = wesnoth.map.replace_overlay(val)
|
||||
wesnoth.current.map[self] = wesnoth.map.replace.overlay(val)
|
||||
elseif key == 1 then
|
||||
self.x = val
|
||||
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 replace_if_failed then
|
||||
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
|
||||
new_ter = wesnoth.map['replace_' .. mode](new_ter)
|
||||
new_ter = wesnoth.map.replace[mode](new_ter)
|
||||
elseif mode ~= nil then
|
||||
error('set_terrain: invalid mode')
|
||||
end
|
||||
|
|
|
@ -1,13 +1,37 @@
|
|||
local LS = wesnoth.require "location_set"
|
||||
|
||||
---@class mapgen_helper
|
||||
local mapgen_helper, map_mt = {}, {__index = {}}
|
||||
|
||||
function mapgen_helper.create_map(width,height,default_terrain)
|
||||
local map = setmetatable({w = width, h = height}, map_mt)
|
||||
for i = 1, width * height do
|
||||
table.insert(map, default_terrain or 'Gg')
|
||||
---@class map_wrapper
|
||||
---@field __map terrain_map
|
||||
|
||||
---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
|
||||
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
|
||||
|
||||
local valid_transforms = {
|
||||
|
@ -16,91 +40,120 @@ local valid_transforms = {
|
|||
flip_xy = true,
|
||||
}
|
||||
|
||||
---Test whether a string is a valid transform
|
||||
---@param t string
|
||||
---@return boolean
|
||||
function mapgen_helper.is_valid_transform(t)
|
||||
return valid_transforms[t]
|
||||
end
|
||||
|
||||
local function loc_to_index(map,x,y)
|
||||
return x + 1 + y * map.w
|
||||
end
|
||||
|
||||
---Set the tile at the specified location
|
||||
---@param map map_wrapper
|
||||
---@param x integer
|
||||
---@param y integer
|
||||
---@param val string
|
||||
function map_mt.__index.set_tile(map, x, y, val)
|
||||
map[loc_to_index(map, x, y)] = val
|
||||
map.__map[{x, y}] = val
|
||||
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)
|
||||
return map[loc_to_index(map,x,y)]
|
||||
return map.__map[{x, y}]
|
||||
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)
|
||||
return x >= 0 and y >= 0 and x < map.w and y < map.h
|
||||
return map.__map:on_board(x, y, true)
|
||||
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)
|
||||
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
|
||||
|
||||
---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)
|
||||
if not map.locations then
|
||||
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
|
||||
map.__map.special_locations[name] = {x, y}
|
||||
end
|
||||
|
||||
function map_mt.__index.flip_x(map)
|
||||
for y = 0, map.h - 1 do
|
||||
for x = 0, map.w - 1 do
|
||||
local i = loc_to_index(map, x, y)
|
||||
local j = loc_to_index(map, map.w - x - 1, y)
|
||||
map[i], map[j] = map[j], map[i]
|
||||
----Flip the map horizontally
|
||||
---@param map terrain_map
|
||||
function mapgen_helper.flip_x(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
|
||||
map[{x,y}], map[{x_opp,y}] = map[{x_opp,y}], map[{x,y}]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function map_mt.__index.flip_y(map)
|
||||
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
|
||||
for id, loc in map.special_locations do
|
||||
loc.x = map.width - loc.x - 1
|
||||
map.special_locations[id] = loc
|
||||
end
|
||||
end
|
||||
|
||||
function map_mt.__index.flip_xy(map)
|
||||
map:flip_x()
|
||||
map:flip_y()
|
||||
---Flip the map vertically
|
||||
---@param map terrain_map
|
||||
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
|
||||
|
||||
---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)
|
||||
local map_builder = {}
|
||||
-- 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')
|
||||
return map.__map.data
|
||||
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} }
|
||||
}
|
||||
---Iterates over adjacent tiles
|
||||
---@param x integer
|
||||
---@param y integer
|
||||
---@return fun():integer,integer
|
||||
function mapgen_helper.adjacent_tiles(x, y)
|
||||
local offset = adjacent_offset[2 - (x % 2)]
|
||||
local i = 0
|
||||
|
@ -114,4 +167,84 @@ function mapgen_helper.adjacent_tiles(x, y)
|
|||
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
|
||||
|
|
|
@ -476,8 +476,8 @@ function wml_actions.terrain(cfg)
|
|||
cfg.terrain = nil
|
||||
for i, loc in ipairs(wesnoth.map.find(cfg)) do
|
||||
local replacement = cfg.replace_if_failed
|
||||
and wesnoth.map.replace_if_failed(terrain, layer)
|
||||
or wesnoth.map['replace_' .. layer](terrain)
|
||||
and wesnoth.map.replace.if_failed(terrain, layer)
|
||||
or wesnoth.map.replace[layer](terrain)
|
||||
wesnoth.current.map[loc] = replacement
|
||||
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
|
||||
max=infinite
|
||||
{DEFAULT_KEY ignore bool no}
|
||||
{SIMPLE_KEY id string}
|
||||
{SIMPLE_KEY x unsigned_range_list}
|
||||
{SIMPLE_KEY y unsigned_range_list}
|
||||
{SIMPLE_KEY terrain_clear terrain_list}
|
||||
{SIMPLE_KEY size unsigned}
|
||||
{SIMPLE_KEY jagged unsigned}
|
||||
{DEFAULT_KEY chance unsigned 100}
|
||||
{SIMPLE_KEY side unsigned}
|
||||
{SIMPLE_KEY relative_to relative_anchor}
|
||||
{SIMPLE_KEY require_player unsigned}
|
||||
[tag]
|
||||
name="passage"
|
||||
max=infinite
|
||||
{DEFAULT_KEY ignore bool no}
|
||||
{SIMPLE_KEY id string}
|
||||
{SIMPLE_KEY place_villages bool}
|
||||
{SIMPLE_KEY destination string}
|
||||
{SIMPLE_KEY terrain_clear terrain_list}
|
||||
{SIMPLE_KEY windiness unsigned}
|
||||
{SIMPLE_KEY laziness unsigned}
|
||||
{SIMPLE_KEY width unsigned}
|
||||
{SIMPLE_KEY jagged unsigned}
|
||||
{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]
|
||||
name="item_location"
|
||||
|
@ -47,13 +64,20 @@
|
|||
{SIMPLE_KEY map_width unsigned}
|
||||
{SIMPLE_KEY map_height unsigned}
|
||||
{SIMPLE_KEY village_density unsigned}
|
||||
{SIMPLE_KEY nplayers unsigned}
|
||||
{SIMPLE_KEY transform map_transform}
|
||||
{SIMPLE_KEY transform_chance unsigned}
|
||||
{SIMPLE_KEY terrain_wall terrain_code}
|
||||
{SIMPLE_KEY terrain_castle terrain_code}
|
||||
{SIMPLE_KEY terrain_keep terrain_code}
|
||||
{SIMPLE_KEY terrain_village terrain_code}
|
||||
{SIMPLE_KEY terrain_clear terrain_code}
|
||||
{SIMPLE_KEY terrain_village terrain_list}
|
||||
{SIMPLE_KEY terrain_clear terrain_list}
|
||||
{LINK_TAG "scenario"}
|
||||
[/then]
|
||||
[/if]
|
||||
[if]
|
||||
glob_on_create_map=*cave_map_generator*
|
||||
[then]
|
||||
[tag]
|
||||
name="chamber"
|
||||
{CHAMBER_TAG_CONTENTS}
|
||||
|
@ -70,6 +94,11 @@
|
|||
[tag]
|
||||
name="items"
|
||||
super="scenario"
|
||||
[tag]
|
||||
name="event"
|
||||
super="event"
|
||||
{SIMPLE_KEY same_location_as_previous bool}
|
||||
[/tag]
|
||||
[/tag]
|
||||
[/tag]
|
||||
[tag]
|
||||
|
|
|
@ -508,6 +508,10 @@
|
|||
name="theme_action"
|
||||
value="checkbox|radiobox|image|turbo"
|
||||
[/type]
|
||||
[type]
|
||||
name="relative_anchor"
|
||||
value="center|top-(left|middle|right)|bottom-(left|middle|right)|middle-(left|right)"
|
||||
[/type]
|
||||
[tag]
|
||||
name="root"
|
||||
min=1
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "gui/widgets/slider.hpp"
|
||||
#include "gui/widgets/status_label_helper.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -67,7 +68,12 @@ void generator_settings::pre_show()
|
|||
// Do this *after* assigning the 'update_*_label_` functions or the game will crash!
|
||||
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, "landform", [](const slider& s) {
|
||||
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);
|
||||
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)) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -253,11 +253,16 @@ mapgen_lua_kernel::mapgen_lua_kernel(const config* vars)
|
|||
// Map methods
|
||||
{ "find", &intf_mg_get_locations },
|
||||
{ "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
|
||||
{ "filter", &intf_terrainfilter_create },
|
||||
{ "create", &intf_terrainmap_create },
|
||||
{ "generate_height_map", &intf_default_generate_height_map },
|
||||
{ "generate", &intf_default_generate },
|
||||
{ "replace_if_failed", &intf_replace_if_failed },
|
||||
{ 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));
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user