Compare commits

...
Sign in to create a new pull request.

10 commits

Author SHA1 Message Date
Celtic Minstrel
231a908601 [LuaDoc] WIP Partially validate unit WML when creating units from Lua 2024-08-13 08:53:02 -04:00
Celtic Minstrel
1089884c07 [LuaDoc] Mark filesystem.asset_type as an enumerator 2024-08-13 08:53:02 -04:00
Celtic Minstrel
b060f06a12 [Lua] Read campaign ID from scenario settings instead of mp_settings. 2024-08-13 08:53:01 -04:00
Celtic Minstrel
fd97d37c41 [Lua] Add some TODO notes on things to come back to later. 2024-08-13 08:53:01 -04:00
Celtic Minstrel
d9073e01fb [Lua] Remove some internal implementation functions from the external ai_helper interface.
There are no callers in mainline. The functions are not meant to be called directly at all – for each, there are wrapper functions that are intended to be called instead, which are still exposed.
2024-08-13 08:53:01 -04:00
Celtic Minstrel
6dd8622ab8 [Lua] Avoid missing field warning by reversing the order of the check 2024-08-13 08:53:01 -04:00
Celtic Minstrel
f082ce89f7 [Lua] Fix some accidental global warnings 2024-08-13 08:53:01 -04:00
Celtic Minstrel
d1bab92d4f [Lua] Mark location_set.values as private 2024-08-13 08:53:00 -04:00
Celtic Minstrel
a5537dba4f [Lua] Avoid variable reuse as a different type 2024-08-13 08:53:00 -04:00
Celtic Minstrel
310c43a4c4 [Lua] Suppress some diagnostics and also recommend suppressing certain diagnostics globally 2024-08-13 08:53:00 -04:00
14 changed files with 54 additions and 38 deletions

View file

@ -252,7 +252,7 @@ end
---@param y integer
---@param move_type string
---@return ai_result
function ai_helper.checked_move_core(ai, unit, x, y, move_type)
local function checked_move_core(ai, unit, x, y, move_type)
local check = ai.check_move(unit, x, y)
if (not check.ok) then
@ -278,7 +278,7 @@ end
---@param y integer
---@return ai_result
function ai_helper.checked_move_full(ai, unit, x, y)
return ai_helper.checked_move_core(ai, unit, x, y, 'ai.move_full')
return checked_move_core(ai, unit, x, y, 'ai.move_full')
end
---Check if a move is viable, and execute it if it is.
@ -289,7 +289,7 @@ end
---@param y integer
---@return ai_result
function ai_helper.checked_move(ai, unit, x, y)
return ai_helper.checked_move_core(ai, unit, x, y, 'ai.move')
return checked_move_core(ai, unit, x, y, 'ai.move')
end
---Check if a recruit is viable, and execute it if it is.
@ -602,11 +602,10 @@ ai_helper.split = wesnoth.deprecate_api('ai_helper.split', 'stringx.split', 3, '
---@return integer
---@return integer
function ai_helper.get_LS_xy(index)
local tmp_set = LS.create()
tmp_set.values[index] = 1
local tmp_set = LS.of_raw{[index] = true}
local xy = tmp_set:to_pairs()[1]
return xy[1], xy[2]
return xy.x, xy.y
end
--------- Location, position or hex related helper functions ----------
@ -1156,6 +1155,8 @@ function ai_helper.get_units_with_moves(filter, exclude_guardians)
exclude_status = exclude_status .. ',guardian'
end
return wesnoth.units.find_on_map {
-- TODO: Should this also check for a case where the unit can't move because of terrain?
-- That is, all adjacent terrains have a movement cost higher than the unit's moves left.
wml.tag["and"] { formula = "moves > 0" },
wml.tag["not"] { status = exclude_status },
wml.tag["and"] ( filter )
@ -2088,6 +2089,7 @@ function ai_helper.movefull_stopunit(ai, unit, x, y)
x, y = x.x, x.y
end
end
-- TODO: Use read_location above (and in many other places as well)
local next_hop = ai_helper.next_hop(unit, x, y)
if next_hop and ((next_hop[1] ~= unit.x) or (next_hop[2] ~= unit.y)) then
@ -2306,7 +2308,7 @@ end
---@param combos table?
---@param attacks ai_attack[]
---@return table<integer, integer>[]
function add_next_attack_combo_level(combos, attacks)
local function add_next_attack_combo_level(combos, attacks)
-- Important: function needs to make a copy of the input array, otherwise original is changed
-- Set up the array, if this is the first recursion level
@ -2345,7 +2347,7 @@ function add_next_attack_combo_level(combos, attacks)
local combos_next_level = {}
if combos_this_level[1] then -- If moves were found for this level, also find those for the next level
combos_next_level = ai_helper.add_next_attack_combo_level(combos_this_level, attacks)
combos_next_level = add_next_attack_combo_level(combos_this_level, attacks)
end
-- Finally, combine this level and next level combos
@ -2374,7 +2376,7 @@ function ai_helper.get_attack_combos_full(units, enemy, cfg)
if (not attacks[1]) then return {} end
-- This recursive function does all the work:
local combos = ai_helper.add_next_attack_combo_level(nil, attacks)
local combos = add_next_attack_combo_level(nil, attacks)
return combos
end
@ -2535,6 +2537,7 @@ function ai_helper.get_unit_time_of_day_bonus(alignment, lawful_bonus)
elseif (alignment == 'chaotic') then
multiplier = (1 - lawful_bonus / 100.)
elseif (alignment == 'liminal') then
-- TODO: I think this is wrong?
multiplier = (1 - math.abs(lawful_bonus) / 100.)
end
end

View file

@ -878,7 +878,7 @@ function battle_calcs.attack_rating(attacker, defender, dst, cfg, cache)
-- If defender is on a healing location, count that as slightly more than the healing amount
def_damage = def_damage - 1.25 * wesnoth.terrain_types[map[defender]].healing
if (def_damage < 0) then damage = 0. end
if (def_damage < 0) then def_damage = 0. end
-- Fraction damage (= fractional value of the unit)
local def_value_fraction = def_damage / defender.max_hitpoints

View file

@ -447,6 +447,7 @@ function ca_bottleneck_move:evaluation(cfg, data)
local unit_in_way = wesnoth.units.find_on_map { x = best_hex[1], y = best_hex[2],
wml.tag["not"] { id = best_unit.id }
}[1]
--- TODO: best_hex should be indexed as x and y!
if (not AH.is_visible_unit(wesnoth.current.side, unit_in_way)) then
unit_in_way = nil
end

View file

@ -21,7 +21,7 @@ local function is_number(value, check_int, ai_type, name)
if (number ~= math.floor(number)) then
return false
elseif (math.type(number) ~= 'integer') then
str = "[micro_ai] tag (" .. ai_type .. ") parameter '" .. name .. "' must be an integer. It has an integer representation, but is provided in floating-point format."
local str = "[micro_ai] tag (" .. ai_type .. ") parameter '" .. name .. "' must be an integer. It has an integer representation, but is provided in floating-point format."
warn(str)
std_print(str .. ' (see Lua console for stack trace)')
end
@ -365,7 +365,7 @@ function micro_ai_helper.micro_ai_setup(cfg, CA_parms, required_keys, optional_k
end
end
if is_invalid then
str = "[micro_ai] tag (" .. cfg.ai_type .. ") contains invalid parameter: [" .. t[1] .. "]"
local str = "[micro_ai] tag (" .. cfg.ai_type .. ") contains invalid parameter: [" .. t.tag .. "]"
warn(str)
std_print(str .. ' (see Lua console for stack trace)')
end

View file

@ -2,6 +2,7 @@
--[========[File Handling]========]
print("Loading filesystem module...")
---@enum asset_type
---Valid asset types, used as the type argument for have_asset and resolve_asset
filesystem.asset_type = {
IMAGE = 'images',

View file

@ -274,6 +274,7 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
---@type location
local loc, n = wesnoth.map.read_location(x, y)
if n == 0 then error('Missing or invalid coordinate') end
---@diagnostic disable-next-line: return-type-mismatch
return setmetatable({x = loc.x, y = loc.y}, hex_mt)
end
@ -282,7 +283,7 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
---@param cfg WML
---@param ref_unit? unit
---@return terrain_hex[]
function wesnoth.map.find(cfg, ref_unit)
function wesnoth.map.find(cfg, ref_unit) ---@diagnostic disable-line: duplicate-set-field
local hexes = find_locations(cfg, ref_unit)
for i = 1, #hexes do
hexes[i] = wesnoth.map.get(hexes[i][1], hexes[i][2])

View file

@ -1,4 +1,5 @@
--[========[Config Manipulation Functions]========]
---@diagnostic disable: deprecated
print("Loading WML module...")
local function ensure_config(cfg)
@ -187,10 +188,10 @@ wml.tag = setmetatable({}, create_tag_mt)
---@param cfg WML
---@return WMLTable
function wml.literal(cfg)
if type(cfg) == "userdata" then
return cfg.__literal
else
if type(cfg) == "table" then
return cfg or {}
else
return cfg.__literal
end
end
@ -200,10 +201,10 @@ end
---@param cfg WML
---@return WMLTable
function wml.parsed(cfg)
if type(cfg) == "userdata" then
return cfg.__parsed
else
if type(cfg) == "table" then
return cfg or {}
else
return cfg.__parsed
end
end
@ -213,10 +214,10 @@ end
---@param cfg WML
---@return WMLTable
function wml.shallow_literal(cfg)
if type(cfg) == "userdata" then
return cfg.__shallow_literal
else
if type(cfg) == "table" then
return cfg or {}
else
return cfg.__shallow_literal
end
end
@ -227,10 +228,10 @@ end
---@param cfg WML
---@return WMLTable
function wml.shallow_parsed(cfg)
if type(cfg) == "userdata" then
return cfg.__shallow_parsed
else
if type(cfg) == "table" then
return cfg or {}
else
return cfg.__shallow_parsed
end
end

View file

@ -16,7 +16,7 @@ end
---A set of locations, with an optional associated value for each one.
---@class location_set : { [location]: any }
---@field values table<integer, any>
---@field private values table<integer, any>
---@operator bnot:location_set
---@operator band:location_set
---@operator bor:location_set

View file

@ -31,7 +31,7 @@ return function(eventname, priority, fcn)
priority = priority,
first_time_only = false,
action = function()
context = wesnoth.current.event_context
local context = wesnoth.current.event_context
wesnoth.experimental.game_events.set_undoable(true)
fcn(context)
end

View file

@ -3,8 +3,8 @@ local function path_locs(path)
if path.location_id then
local function special_locations()
return function()
for _,loc in ipairs(tostring(path.location_id):split()) do
loc = wesnoth.current.map.special_locations[loc]
for _,loc_id in ipairs(tostring(path.location_id):split()) do
local loc = wesnoth.current.map.special_locations[loc_id]
if loc then coroutine.yield(loc.x, loc.y) end
end
end

View file

@ -5,7 +5,7 @@ local res = {}
res.quick_4mp_leaders = function(args)
local make_4mp_leaders_quick = wml.variables["make_4mp_leaders_quick"]
if make_4mp_leaders_quick == nil then
make_4mp_leaders_quick = wesnoth.scenario.mp_settings and (wesnoth.scenario.mp_settings.mp_campaign == "")
make_4mp_leaders_quick = wesnoth.scenario.mp_settings and (wesnoth.scenario.campaign == "")
end
if not make_4mp_leaders_quick then
return
@ -24,7 +24,7 @@ end
function res.turns_over_advantage()
local show_turns_over_advantage = wml.variables["show_turns_over_advantage"]
if show_turns_over_advantage == nil then
show_turns_over_advantage = wesnoth.scenario.mp_settings and (wesnoth.scenario.mp_settings.mp_campaign == "")
show_turns_over_advantage = wesnoth.scenario.campaign == ""
end
if not show_turns_over_advantage then
return

View file

@ -6,6 +6,8 @@ To enable in Visual Studio Code, install [this Lua plugin](https://marketplace.v
```json
"Lua.runtime.version": "Lua 5.4",
"Lua.type.weakNilCheck": true,
"Lua.type.weakUnionCheck": true,
"Lua.workspace.library": [
"./utils/emmylua"
],

View file

@ -28,13 +28,13 @@ function filesystem.canonical_path(path) end
function filesystem.image_size(path) end
---Check if an asset exists in the current binary path
---@param type string
---@param type asset_type
---@param path string
---@return boolean
function filesystem.have_asset(type, path) end
---Resolve an asset path against the current binary path
---@param type string
---@param type asset_type
---@param path string
---@return string
function filesystem.resolve_asset(type, path) end

View file

@ -103,7 +103,12 @@
---@field traits string[]
---@field abilities string[]
---@field animations string[]
---@field __cfg WMLTable
---@field __cfg unit_wml
---Defines an individual unit in contexts where units can be created
---@class unit_wml : WMLTag[]
---@field type string
---@field side integer
---@class wesnoth.units
wesnoth.units = {}
@ -136,14 +141,16 @@ function wesnoth.units.extract(unit) end
function wesnoth.units.matches(unit, filter, context) end
---Place or move a unit on the map
---@param unit unit|WML
---@param unit unit_wml|unit
---@param loc? location
---@param fire_event? boolean
---@overload fun(unit:unit|WML, x:integer, y:integer)
---@overload fun(unit:unit|WML, x:integer, y:integer, fire_event:boolean)
---@overload fun(unit:unit|WML, fire_event:boolean)
---@overload fun(unit:unit_wml|unit, x:integer, y:integer)
---@overload fun(unit:unit_wml|unit, x:integer, y:integer, fire_event:boolean)
---@overload fun(unit:unit_wml|unit, fire_event:boolean)
function wesnoth.units.to_map(unit, loc, fire_event) end
wesnoth.units.to_map{type = 'a', side = 1}
---Place a unit on a recall lists
---@param unit unit|WML
---@param side? integer