Split some utility functions from wml-tags.lua into a new file
This commit is contained in:
parent
91ac90db11
commit
6200f60c79
2 changed files with 209 additions and 203 deletions
|
@ -16,66 +16,9 @@ wesnoth.require "lua/wml/items.lua"
|
|||
|
||||
local helper = wesnoth.require "lua/helper.lua"
|
||||
local location_set = wesnoth.require "lua/location_set.lua"
|
||||
local utils = wesnoth.require "lua/wml-utils.lua"
|
||||
local wml_actions = wesnoth.wml_actions
|
||||
|
||||
local function trim(s)
|
||||
-- use (f(a)) to get first argument
|
||||
return (tostring(s):gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
local function split(s)
|
||||
return tostring(s):gmatch("[^%s,][^,]*")
|
||||
end
|
||||
|
||||
local function vwriter_init(cfg, default_variable)
|
||||
local variable = cfg.variable or default_variable
|
||||
local is_explicit_index = string.sub(variable, string.len(variable)) == "]"
|
||||
local mode = cfg.mode or "always_clear"
|
||||
local index = 0
|
||||
if is_explicit_index then
|
||||
-- explicit indexes behave always like "replace"
|
||||
elseif mode == "append" then
|
||||
index = wesnoth.get_variable(variable .. ".length")
|
||||
elseif mode ~= "replace" then
|
||||
wesnoth.set_variable(variable)
|
||||
end
|
||||
return {
|
||||
variable = variable,
|
||||
is_explicit_index = is_explicit_index,
|
||||
index = index,
|
||||
}
|
||||
end
|
||||
|
||||
local function vwriter_write(self, container)
|
||||
if self.is_explicit_index then
|
||||
wesnoth.set_variable(self.variable, container)
|
||||
else
|
||||
wesnoth.set_variable(string.format("%s[%u]", self.variable, self.index), container)
|
||||
end
|
||||
self.index = self.index + 1
|
||||
end
|
||||
|
||||
local function optional_side_filter(cfg, key_name, filter_name)
|
||||
local key_name = key_name or "side"
|
||||
local sides = cfg[key_name]
|
||||
local filter_name = filter_name or "filter_side"
|
||||
local filter_side = helper.get_child(cfg, filter_name)
|
||||
if filter_side then
|
||||
sides = wesnoth.get_sides(filter_side)
|
||||
elseif sides then
|
||||
local dummy_cfg = {side=sides}
|
||||
sides = wesnoth.get_sides(dummy_cfg)
|
||||
else
|
||||
return true
|
||||
end
|
||||
for index,side in ipairs(sides) do
|
||||
if side.controller == "human" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local engine_message = wml_actions.message
|
||||
|
||||
function wml_actions.sync_variable(cfg)
|
||||
|
@ -83,8 +26,8 @@ function wml_actions.sync_variable(cfg)
|
|||
local result = wesnoth.synchronize_choice(
|
||||
function()
|
||||
local res = {}
|
||||
for name_raw in split(names) do
|
||||
local name = trim(name_raw)
|
||||
for name_raw in utils.split(names) do
|
||||
local name = utils.trim(name_raw)
|
||||
local variable_type = string.sub(name, string.len(name)) == "]" and "indexed" or ( wesnoth.get_variable(name .. ".length") > 0 and "array" or "attribute")
|
||||
local variable_info = { name = name, type = variable_type }
|
||||
table.insert(res, { "variable", variable_info })
|
||||
|
@ -157,8 +100,8 @@ end
|
|||
function wml_actions.clear_variable(cfg)
|
||||
local names = cfg.name or
|
||||
helper.wml_error "[clear_variable] missing required name= attribute."
|
||||
for w in split(names) do
|
||||
wesnoth.set_variable(trim(w))
|
||||
for w in utils.split(names) do
|
||||
wesnoth.set_variable(utils.trim(w))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -175,11 +118,11 @@ end
|
|||
function wml_actions.store_unit_type(cfg)
|
||||
local types = cfg.type or
|
||||
helper.wml_error "[store_unit_type] missing required type= attribute."
|
||||
local writer = vwriter_init(cfg, "unit_type")
|
||||
for w in split(types) do
|
||||
local writer = utils.vwriter.init(cfg, "unit_type")
|
||||
for w in utils.split(types) do
|
||||
local unit_type = wesnoth.unit_types[w] or
|
||||
helper.wml_error(string.format("Attempt to store nonexistent unit type '%s'.", w))
|
||||
vwriter_write(writer, unit_type.__cfg)
|
||||
utils.vwriter.write(writer, unit_type.__cfg)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -205,7 +148,7 @@ function wml_actions.allow_recruit(cfg)
|
|||
local unit_types = cfg.type or helper.wml_error("[allow_recruit] missing required type= attribute")
|
||||
for index, team in ipairs(wesnoth.get_sides(cfg)) do
|
||||
local v = team.recruit
|
||||
for type in split(unit_types) do
|
||||
for type in utils.split(unit_types) do
|
||||
table.insert(v, type)
|
||||
wesnoth.add_known_unit(type)
|
||||
end
|
||||
|
@ -217,7 +160,7 @@ function wml_actions.allow_extra_recruit(cfg)
|
|||
local recruits = cfg.extra_recruit or helper.wml_error("[allow_extra_recruit] missing required extra_recruit= attribute")
|
||||
for index, unit in ipairs(wesnoth.get_units(cfg)) do
|
||||
local v = unit.extra_recruit
|
||||
for recruit in split(recruits) do
|
||||
for recruit in utils.split(recruits) do
|
||||
table.insert(v, recruit)
|
||||
wesnoth.add_known_unit(recruit)
|
||||
end
|
||||
|
@ -230,7 +173,7 @@ function wml_actions.disallow_recruit(cfg)
|
|||
for index, team in ipairs(wesnoth.get_sides(cfg)) do
|
||||
if unit_types then
|
||||
local v = team.recruit
|
||||
for w in split(unit_types) do
|
||||
for w in utils.split(unit_types) do
|
||||
for i, r in ipairs(v) do
|
||||
if r == w then
|
||||
table.remove(v, i)
|
||||
|
@ -249,7 +192,7 @@ function wml_actions.disallow_extra_recruit(cfg)
|
|||
local recruits = cfg.extra_recruit or helper.wml_error("[disallow_extra_recruit] missing required extra_recruit= attribute")
|
||||
for index, unit in ipairs(wesnoth.get_units(cfg)) do
|
||||
local v = unit.extra_recruit
|
||||
for w in split(recruits) do
|
||||
for w in utils.split(recruits) do
|
||||
for i, r in ipairs(v) do
|
||||
if r == w then
|
||||
table.remove(v, i)
|
||||
|
@ -265,7 +208,7 @@ function wml_actions.set_recruit(cfg)
|
|||
local recruit = cfg.recruit or helper.wml_error("[set_recruit] missing required recruit= attribute")
|
||||
for index, team in ipairs(wesnoth.get_sides(cfg)) do
|
||||
local v = {}
|
||||
for w in split(recruit) do
|
||||
for w in utils.split(recruit) do
|
||||
table.insert(v, w)
|
||||
end
|
||||
team.recruit = v
|
||||
|
@ -276,7 +219,7 @@ function wml_actions.set_extra_recruit(cfg)
|
|||
local recruits = cfg.extra_recruit or helper.wml_error("[set_extra_recruit] missing required extra_recruit= attribute")
|
||||
local v = {}
|
||||
|
||||
for w in split(recruits) do
|
||||
for w in utils.split(recruits) do
|
||||
table.insert(v, w)
|
||||
end
|
||||
|
||||
|
@ -300,7 +243,7 @@ function wml_actions.unit_worth(cfg)
|
|||
local hp = u.hitpoints / u.max_hitpoints
|
||||
local xp = u.experience / u.max_experience
|
||||
local best_adv = ut.cost
|
||||
for w in split(ut.__cfg.advances_to) do
|
||||
for w in utils.split(ut.__cfg.advances_to) do
|
||||
local uta = wesnoth.unit_types[w]
|
||||
if uta and uta.cost > best_adv then best_adv = uta.cost end
|
||||
end
|
||||
|
@ -339,53 +282,7 @@ function wml_actions.music(cfg)
|
|||
wesnoth.set_music(cfg)
|
||||
end
|
||||
|
||||
local function handle_event_commands(cfg)
|
||||
-- The WML might be modifying the currently executed WML by mixing
|
||||
-- [insert_tag] with [set_variables] and [clear_variable], so we
|
||||
-- have to be careful not to get confused by tags vanishing during
|
||||
-- the execution, hence the manual handling of [insert_tag].
|
||||
local cmds = helper.shallow_literal(cfg)
|
||||
for i = 1,#cmds do
|
||||
local v = cmds[i]
|
||||
local cmd = v[1]
|
||||
local arg = v[2]
|
||||
local insert_from
|
||||
if cmd == "insert_tag" then
|
||||
cmd = arg.name
|
||||
local from = arg.variable or
|
||||
helper.wml_error("[insert_tag] found with no variable= field")
|
||||
|
||||
arg = wesnoth.get_variable(from)
|
||||
if type(arg) ~= "table" then
|
||||
-- Corner case: A missing variable is replaced
|
||||
-- by an empty container rather than being ignored.
|
||||
arg = {}
|
||||
elseif string.sub(from, -1) ~= ']' then
|
||||
insert_from = from
|
||||
end
|
||||
arg = wesnoth.tovconfig(arg)
|
||||
end
|
||||
if not string.find(cmd, "^filter") then
|
||||
cmd = wml_actions[cmd] or
|
||||
helper.wml_error(string.format("[%s] not supported", cmd))
|
||||
if insert_from then
|
||||
local j = 0
|
||||
repeat
|
||||
cmd(arg)
|
||||
j = j + 1
|
||||
if j >= wesnoth.get_variable(insert_from .. ".length") then break end
|
||||
arg = wesnoth.tovconfig(wesnoth.get_variable(string.format("%s[%d]", insert_from, j)))
|
||||
until false
|
||||
else
|
||||
cmd(arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Apply music alterations once all the commands have been processed.
|
||||
wesnoth.set_music()
|
||||
end
|
||||
|
||||
wml_actions.command = handle_event_commands
|
||||
wml_actions.command = utils.handle_event_commands
|
||||
|
||||
-- since if and while are Lua keywords, we can't create functions with such names
|
||||
-- instead, we store the following anonymous functions directly into
|
||||
|
@ -398,7 +295,7 @@ wml_actions["if"] = function(cfg)
|
|||
|
||||
if wesnoth.eval_conditional(cfg) then -- evaluate [if] tag
|
||||
for then_child in helper.child_range(cfg, "then") do
|
||||
handle_event_commands(then_child)
|
||||
utils.handle_event_commands(then_child)
|
||||
end
|
||||
return -- stop after executing [then] tags
|
||||
end
|
||||
|
@ -406,7 +303,7 @@ wml_actions["if"] = function(cfg)
|
|||
for elseif_child in helper.child_range(cfg, "elseif") do
|
||||
if wesnoth.eval_conditional(elseif_child) then -- we'll evaluate the [elseif] tags one by one
|
||||
for then_tag in helper.child_range(elseif_child, "then") do
|
||||
handle_event_commands(then_tag)
|
||||
utils.handle_event_commands(then_tag)
|
||||
end
|
||||
return -- stop on first matched condition
|
||||
end
|
||||
|
@ -414,7 +311,7 @@ wml_actions["if"] = function(cfg)
|
|||
|
||||
-- no matched condition, try the [else] tags
|
||||
for else_child in helper.child_range(cfg, "else") do
|
||||
handle_event_commands(else_child)
|
||||
utils.handle_event_commands(else_child)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -423,7 +320,7 @@ wml_actions["while"] = function( cfg )
|
|||
for i = 1, 65536 do
|
||||
if wesnoth.eval_conditional( cfg ) then
|
||||
for do_child in helper.child_range( cfg, "do" ) do
|
||||
handle_event_commands( do_child )
|
||||
utils.handle_event_commands( do_child )
|
||||
end
|
||||
else return end
|
||||
end
|
||||
|
@ -435,9 +332,9 @@ function wml_actions.switch(cfg)
|
|||
|
||||
-- Execute all the [case]s where the value matches.
|
||||
for v in helper.child_range(cfg, "case") do
|
||||
for w in split(v.value) do
|
||||
for w in utils.split(v.value) do
|
||||
if w == tostring(var_value) then
|
||||
handle_event_commands(v)
|
||||
utils.handle_event_commands(v)
|
||||
found = true
|
||||
break
|
||||
end
|
||||
|
@ -447,7 +344,7 @@ function wml_actions.switch(cfg)
|
|||
-- Otherwise execute [else] statements.
|
||||
if not found then
|
||||
for v in helper.child_range(cfg, "else") do
|
||||
handle_event_commands(v)
|
||||
utils.handle_event_commands(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -455,14 +352,14 @@ end
|
|||
function wml_actions.scroll_to(cfg)
|
||||
local loc = wesnoth.get_locations( cfg )[1]
|
||||
if not loc then return end
|
||||
if not optional_side_filter(cfg) then return end
|
||||
if not utils.optional_side_filter(cfg) then return end
|
||||
wesnoth.scroll_to_tile(loc[1], loc[2], cfg.check_fogged, cfg.immediate)
|
||||
end
|
||||
|
||||
function wml_actions.scroll_to_unit(cfg)
|
||||
local u = wesnoth.get_units(cfg)[1]
|
||||
if not u then return end
|
||||
if not optional_side_filter(cfg, "for_side", "for_side") then return end
|
||||
if not utils.optional_side_filter(cfg, "for_side", "for_side") then return end
|
||||
wesnoth.scroll_to_tile(u.x, u.y, cfg.check_fogged, cfg.immediate)
|
||||
end
|
||||
|
||||
|
@ -484,7 +381,7 @@ function wml_actions.unit_overlay(cfg)
|
|||
local img = cfg.image or helper.wml_error( "[unit_overlay] missing required image= attribute" )
|
||||
for i,u in ipairs(wesnoth.get_units(cfg)) do
|
||||
local ucfg = u.__cfg
|
||||
for w in split(ucfg.overlays) do
|
||||
for w in utils.split(ucfg.overlays) do
|
||||
if w == img then ucfg = nil end
|
||||
end
|
||||
if ucfg then
|
||||
|
@ -497,43 +394,10 @@ end
|
|||
function wml_actions.remove_unit_overlay(cfg)
|
||||
local img = cfg.image or helper.wml_error( "[remove_unit_overlay] missing required image= attribute" )
|
||||
|
||||
-- Splits the string argument on commas, excepting those commas that occur
|
||||
-- within paired parentheses. The result is returned as a (non-empty) table.
|
||||
-- (The table might have a single entry that is an empty string, though.)
|
||||
-- Spaces around splitting commas are stripped (as in the C++ version).
|
||||
-- Empty strings are not removed (unlike the C++ version).
|
||||
local function parenthetical_split(str)
|
||||
local t = {""}
|
||||
-- To simplify some logic, end the string with paired parentheses.
|
||||
local formatted = (str or "") .. ",()"
|
||||
|
||||
-- Isolate paired parentheses.
|
||||
for prefix,paren in string.gmatch(formatted, "(.-)(%b())") do
|
||||
-- Separate on commas
|
||||
for comma,text in string.gmatch(prefix, "(,?)([^,]*)") do
|
||||
if comma == "" then
|
||||
-- We are continuing the last string found.
|
||||
t[#t] = t[#t] .. text
|
||||
else
|
||||
-- We are starting the next string.
|
||||
-- (Now that we know the last string is complete,
|
||||
-- strip leading and trailing spaces from it.)
|
||||
t[#t] = string.match(t[#t], "^%s*(.-)%s*$")
|
||||
table.insert(t, text)
|
||||
end
|
||||
end
|
||||
-- Add the parenthetical part to the last string found.
|
||||
t[#t] = t[#t] .. paren
|
||||
end
|
||||
-- Remove the empty parentheses we had added to the end.
|
||||
table.remove(t)
|
||||
return t
|
||||
end
|
||||
|
||||
-- Loop through all matching units.
|
||||
for i,u in ipairs(wesnoth.get_units(cfg)) do
|
||||
local ucfg = u.__cfg
|
||||
local t = parenthetical_split(ucfg.overlays)
|
||||
local t = utils.parenthetical_split(ucfg.overlays)
|
||||
-- Remove the specified image from the overlays.
|
||||
for i = #t,1,-1 do
|
||||
if t[i] == img then table.remove(t, i) end
|
||||
|
@ -558,10 +422,10 @@ function wml_actions.store_unit(cfg)
|
|||
local units = wesnoth.get_units(filter)
|
||||
local recall_units = wesnoth.get_recall_units(filter)
|
||||
|
||||
local writer = vwriter_init(cfg, "unit")
|
||||
local writer = utils.vwriter.init(cfg, "unit")
|
||||
|
||||
for i,u in ipairs(units) do
|
||||
vwriter_write(writer, u.__cfg)
|
||||
utils.vwriter.write(writer, u.__cfg)
|
||||
if kill_units then wesnoth.put_unit(u.x, u.y) end
|
||||
end
|
||||
|
||||
|
@ -570,7 +434,7 @@ function wml_actions.store_unit(cfg)
|
|||
local ucfg = u.__cfg
|
||||
ucfg.x = "recall"
|
||||
ucfg.y = "recall"
|
||||
vwriter_write(writer, ucfg)
|
||||
utils.vwriter.write(writer, ucfg)
|
||||
if kill_units then wesnoth.extract_unit(u) end
|
||||
end
|
||||
end
|
||||
|
@ -585,7 +449,7 @@ function wml_actions.store_locations(cfg)
|
|||
-- the variable can be mentioned in a [find_in] subtag, so it
|
||||
-- cannot be cleared before the locations are recovered
|
||||
local locs = wesnoth.get_locations(cfg)
|
||||
local writer = vwriter_init(cfg, "location")
|
||||
local writer = utils.vwriter.init(cfg, "location")
|
||||
for i, loc in ipairs(locs) do
|
||||
local x, y = loc[1], loc[2]
|
||||
local t = wesnoth.get_terrain(x, y)
|
||||
|
@ -593,7 +457,7 @@ function wml_actions.store_locations(cfg)
|
|||
if wesnoth.get_terrain_info(t).village then
|
||||
res.owner_side = wesnoth.get_village_owner(x, y) or 0
|
||||
end
|
||||
vwriter_write(writer, res)
|
||||
utils.vwriter.write(writer, res)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -657,23 +521,6 @@ function wml_actions.unhide_unit(cfg)
|
|||
wml_actions.redraw {}
|
||||
end
|
||||
|
||||
--note: when using these, make sure that nothing can throw over the call to end_var_scope
|
||||
local function start_var_scope(name)
|
||||
local var = helper.get_variable_array(name) --containers and arrays
|
||||
if #var == 0 then var = wesnoth.get_variable(name) end --scalars (and nil/empty)
|
||||
wesnoth.set_variable(name)
|
||||
return var
|
||||
end
|
||||
|
||||
local function end_var_scope(name, var)
|
||||
wesnoth.set_variable(name)
|
||||
if type(var) == "table" then
|
||||
helper.set_variable_array(name, var)
|
||||
else
|
||||
wesnoth.set_variable(name, var)
|
||||
end
|
||||
end
|
||||
|
||||
function wml_actions.modify_unit(cfg)
|
||||
local unit_variable = "LUA_modify_unit"
|
||||
|
||||
|
@ -736,11 +583,11 @@ function wml_actions.modify_unit(cfg)
|
|||
wml_actions.store_unit { {"filter", filter}, variable = unit_variable }
|
||||
local max_index = wesnoth.get_variable(unit_variable .. ".length") - 1
|
||||
|
||||
local this_unit = start_var_scope("this_unit")
|
||||
local this_unit = utils.start_var_scope("this_unit")
|
||||
for current_unit = 0, max_index do
|
||||
handle_unit(current_unit)
|
||||
end
|
||||
end_var_scope("this_unit", this_unit)
|
||||
utils.end_var_scope("this_unit", this_unit)
|
||||
|
||||
wesnoth.set_variable(unit_variable)
|
||||
end
|
||||
|
@ -891,7 +738,7 @@ function wml_actions.harm_unit(cfg)
|
|||
else return false end
|
||||
end
|
||||
|
||||
local this_unit = start_var_scope("this_unit")
|
||||
local this_unit = utils.start_var_scope("this_unit")
|
||||
|
||||
for index, unit_to_harm in ipairs(wesnoth.get_units(filter)) do
|
||||
if unit_to_harm.valid then
|
||||
|
@ -922,7 +769,7 @@ function wml_actions.harm_unit(cfg)
|
|||
wesnoth.scroll_to_tile(unit_to_harm.x, unit_to_harm.y, true)
|
||||
end
|
||||
|
||||
-- the two functions below are taken straight from the C++ engine, util.cpp and actions.cpp, with a few unuseful parts removed
|
||||
-- the two functions below are taken straight from the C++ engine, utils.cpp and actions.cpp, with a few unuseful parts removed
|
||||
-- may be moved in helper.lua in 1.11
|
||||
local function round_damage( base_damage, bonus, divisor )
|
||||
local rounding
|
||||
|
@ -1071,7 +918,7 @@ function wml_actions.harm_unit(cfg)
|
|||
end
|
||||
|
||||
wesnoth.set_variable ( "this_unit" ) -- clearing this_unit
|
||||
end_var_scope("this_unit", this_unit)
|
||||
utils.end_var_scope("this_unit", this_unit)
|
||||
end
|
||||
|
||||
function wml_actions.heal_unit(cfg)
|
||||
|
@ -1107,7 +954,7 @@ function wml_actions.transform_unit(cfg)
|
|||
end
|
||||
|
||||
function wml_actions.store_side(cfg)
|
||||
local writer = vwriter_init(cfg, "side")
|
||||
local writer = utils.vwriter.init(cfg, "side")
|
||||
for t, side_number in helper.get_sides(cfg) do
|
||||
local container = {
|
||||
controller = t.controller,
|
||||
|
@ -1128,7 +975,7 @@ function wml_actions.store_side(cfg)
|
|||
flag_icon = t.flag_icon,
|
||||
side = side_number
|
||||
}
|
||||
vwriter_write(writer, container)
|
||||
utils.vwriter.write(writer, container)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1189,7 +1036,7 @@ function wml_actions.find_path(cfg)
|
|||
local unit = wesnoth.get_units(filter_unit)[1] or helper.wml_error("[find_path]'s filter didn't match any unit")
|
||||
local filter_location = (helper.get_child(cfg, "destination")) or helper.wml_error( "[find_path] missing required [destination] tag" )
|
||||
-- support for $this_unit
|
||||
local this_unit = start_var_scope("this_unit")
|
||||
local this_unit = utils.start_var_scope("this_unit")
|
||||
|
||||
wesnoth.set_variable ( "this_unit" ) -- clearing this_unit
|
||||
wesnoth.set_variable("this_unit", unit.__cfg) -- cfg field needed
|
||||
|
@ -1249,14 +1096,14 @@ function wml_actions.find_path(cfg)
|
|||
wesnoth.set_variable ( string.format("%s", variable), { hexes = 0 } ) -- set only length, nil all other values
|
||||
-- support for $this_unit
|
||||
wesnoth.set_variable ( "this_unit" ) -- clearing this_unit
|
||||
end_var_scope("this_unit", this_unit)
|
||||
utils.end_var_scope("this_unit", this_unit)
|
||||
return end
|
||||
|
||||
if not allow_multiple_turns and turns > 1 then -- location cannot be reached in one turn
|
||||
wesnoth.set_variable ( string.format("%s", variable), { hexes = 0 } )
|
||||
-- support for $this_unit
|
||||
wesnoth.set_variable ( "this_unit" ) -- clearing this_unit
|
||||
end_var_scope("this_unit", this_unit)
|
||||
utils.end_var_scope("this_unit", this_unit)
|
||||
return end -- skip the cycles below
|
||||
|
||||
wesnoth.set_variable ( string.format( "%s", variable ), { hexes = current_distance, from_x = unit.x, from_y = unit.y, to_x = current_location[1], to_y = current_location[2], movement_cost = cost, required_turns = turns } )
|
||||
|
@ -1277,11 +1124,11 @@ function wml_actions.find_path(cfg)
|
|||
|
||||
-- support for $this_unit
|
||||
wesnoth.set_variable ( "this_unit" ) -- clearing this_unit
|
||||
end_var_scope("this_unit", this_unit)
|
||||
utils.end_var_scope("this_unit", this_unit)
|
||||
end
|
||||
|
||||
function wml_actions.store_starting_location(cfg)
|
||||
local writer = vwriter_init(cfg, "location")
|
||||
local writer = utils.vwriter.init(cfg, "location")
|
||||
for possibly_wrong_index, side in ipairs(wesnoth.get_sides(cfg)) do
|
||||
local loc = wesnoth.get_starting_location(side.side)
|
||||
if loc then
|
||||
|
@ -1290,16 +1137,16 @@ function wml_actions.store_starting_location(cfg)
|
|||
if wesnoth.get_terrain_info(terrain).village then
|
||||
result.owner_side = wesnoth.get_village_owner(loc[1], loc[2]) or 0
|
||||
end
|
||||
vwriter_write(writer, result)
|
||||
utils.vwriter.write(writer, result)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function wml_actions.store_villages( cfg )
|
||||
local villages = wesnoth.get_villages( cfg )
|
||||
local writer = vwriter_init(cfg, "location")
|
||||
local writer = utils.vwriter.init(cfg, "location")
|
||||
for index, village in ipairs( villages ) do
|
||||
vwriter_write(writer, {
|
||||
utils.vwriter.write(writer, {
|
||||
x = village[1],
|
||||
y = village[2],
|
||||
terrain = wesnoth.get_terrain( village[1], village[2] ),
|
||||
|
@ -1417,7 +1264,7 @@ end
|
|||
function wml_actions.remove_event(cfg)
|
||||
local id = cfg.id or helper.wml_error("[remove_event] missing required id= key")
|
||||
|
||||
for w in split(id) do
|
||||
for w in utils.split(id) do
|
||||
wesnoth.remove_event_handler(w)
|
||||
end
|
||||
end
|
||||
|
@ -1468,8 +1315,8 @@ function wml_actions.role(cfg)
|
|||
local filter = helper.shallow_literal(cfg)
|
||||
|
||||
local types = {}
|
||||
for value in split(cfg.type) do
|
||||
table.insert(types, trim(value))
|
||||
for value in utils.split(cfg.type) do
|
||||
table.insert(types, utils.trim(value))
|
||||
end
|
||||
|
||||
filter.role, filter.type = nil, nil
|
||||
|
|
159
data/lua/wml-utils.lua
Normal file
159
data/lua/wml-utils.lua
Normal file
|
@ -0,0 +1,159 @@
|
|||
|
||||
local helper = wesnoth.require "lua/helper.lua"
|
||||
local utils = {vwriter = {}}
|
||||
|
||||
function utils.trim(s)
|
||||
-- use (f(a)) to get first argument
|
||||
return (tostring(s):gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
function utils.split(s)
|
||||
return tostring(s):gmatch("[^%s,][^,]*")
|
||||
end
|
||||
|
||||
function utils.vwriter.init(cfg, default_variable)
|
||||
local variable = cfg.variable or default_variable
|
||||
local is_explicit_index = string.sub(variable, string.len(variable)) == "]"
|
||||
local mode = cfg.mode or "always_clear"
|
||||
local index = 0
|
||||
if is_explicit_index then
|
||||
-- explicit indexes behave always like "replace"
|
||||
elseif mode == "append" then
|
||||
index = wesnoth.get_variable(variable .. ".length")
|
||||
elseif mode ~= "replace" then
|
||||
wesnoth.set_variable(variable)
|
||||
end
|
||||
return {
|
||||
variable = variable,
|
||||
is_explicit_index = is_explicit_index,
|
||||
index = index,
|
||||
}
|
||||
end
|
||||
|
||||
function utils.vwriter.write(self, container)
|
||||
if self.is_explicit_index then
|
||||
wesnoth.set_variable(self.variable, container)
|
||||
else
|
||||
wesnoth.set_variable(string.format("%s[%u]", self.variable, self.index), container)
|
||||
end
|
||||
self.index = self.index + 1
|
||||
end
|
||||
|
||||
function utils.optional_side_filter(cfg, key_name, filter_name)
|
||||
local key_name = key_name or "side"
|
||||
local sides = cfg[key_name]
|
||||
local filter_name = filter_name or "filter_side"
|
||||
local filter_side = helper.get_child(cfg, filter_name)
|
||||
if filter_side then
|
||||
sides = wesnoth.get_sides(filter_side)
|
||||
elseif sides then
|
||||
local dummy_cfg = {side=sides}
|
||||
sides = wesnoth.get_sides(dummy_cfg)
|
||||
else
|
||||
return true
|
||||
end
|
||||
for index,side in ipairs(sides) do
|
||||
if side.controller == "human" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function utils.handle_event_commands(cfg)
|
||||
-- The WML might be modifying the currently executed WML by mixing
|
||||
-- [insert_tag] with [set_variables] and [clear_variable], so we
|
||||
-- have to be careful not to get confused by tags vanishing during
|
||||
-- the execution, hence the manual handling of [insert_tag].
|
||||
local cmds = helper.shallow_literal(cfg)
|
||||
for i = 1,#cmds do
|
||||
local v = cmds[i]
|
||||
local cmd = v[1]
|
||||
local arg = v[2]
|
||||
local insert_from
|
||||
if cmd == "insert_tag" then
|
||||
cmd = arg.name
|
||||
local from = arg.variable or
|
||||
helper.wml_error("[insert_tag] found with no variable= field")
|
||||
|
||||
arg = wesnoth.get_variable(from)
|
||||
if type(arg) ~= "table" then
|
||||
-- Corner case: A missing variable is replaced
|
||||
-- by an empty container rather than being ignored.
|
||||
arg = {}
|
||||
elseif string.sub(from, -1) ~= ']' then
|
||||
insert_from = from
|
||||
end
|
||||
arg = wesnoth.tovconfig(arg)
|
||||
end
|
||||
if not string.find(cmd, "^filter") then
|
||||
cmd = wesnoth.wml_actions[cmd] or
|
||||
helper.wml_error(string.format("[%s] not supported", cmd))
|
||||
if insert_from then
|
||||
local j = 0
|
||||
repeat
|
||||
cmd(arg)
|
||||
j = j + 1
|
||||
if j >= wesnoth.get_variable(insert_from .. ".length") then break end
|
||||
arg = wesnoth.tovconfig(wesnoth.get_variable(string.format("%s[%d]", insert_from, j)))
|
||||
until false
|
||||
else
|
||||
cmd(arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Apply music alterations once all the commands have been processed.
|
||||
wesnoth.set_music()
|
||||
end
|
||||
|
||||
-- Splits the string argument on commas, excepting those commas that occur
|
||||
-- within paired parentheses. The result is returned as a (non-empty) table.
|
||||
-- (The table might have a single entry that is an empty string, though.)
|
||||
-- Spaces around splitting commas are stripped (as in the C++ version).
|
||||
-- Empty strings are not removed (unlike the C++ version).
|
||||
function utils.parenthetical_split(str)
|
||||
local t = {""}
|
||||
-- To simplify some logic, end the string with paired parentheses.
|
||||
local formatted = (str or "") .. ",()"
|
||||
|
||||
-- Isolate paired parentheses.
|
||||
for prefix,paren in string.gmatch(formatted, "(.-)(%b())") do
|
||||
-- Separate on commas
|
||||
for comma,text in string.gmatch(prefix, "(,?)([^,]*)") do
|
||||
if comma == "" then
|
||||
-- We are continuing the last string found.
|
||||
t[#t] = t[#t] .. text
|
||||
else
|
||||
-- We are starting the next string.
|
||||
-- (Now that we know the last string is complete,
|
||||
-- strip leading and trailing spaces from it.)
|
||||
t[#t] = string.match(t[#t], "^%s*(.-)%s*$")
|
||||
table.insert(t, text)
|
||||
end
|
||||
end
|
||||
-- Add the parenthetical part to the last string found.
|
||||
t[#t] = t[#t] .. paren
|
||||
end
|
||||
-- Remove the empty parentheses we had added to the end.
|
||||
table.remove(t)
|
||||
return t
|
||||
end
|
||||
|
||||
--note: when using these, make sure that nothing can throw over the call to end_var_scope
|
||||
function utils.start_var_scope(name)
|
||||
local var = helper.get_variable_array(name) --containers and arrays
|
||||
if #var == 0 then var = wesnoth.get_variable(name) end --scalars (and nil/empty)
|
||||
wesnoth.set_variable(name)
|
||||
return var
|
||||
end
|
||||
|
||||
function utils.end_var_scope(name, var)
|
||||
wesnoth.set_variable(name)
|
||||
if type(var) == "table" then
|
||||
helper.set_variable_array(name, var)
|
||||
else
|
||||
wesnoth.set_variable(name, var)
|
||||
end
|
||||
end
|
||||
|
||||
return utils
|
Loading…
Add table
Reference in a new issue