wesnoth/data/lua/wml/animate_unit.lua
2024-02-13 19:29:21 -05:00

113 lines
3.4 KiB
Lua

local T = wml.tag
local function add_animation(anim, cfg)
cfg = wml.shallow_parsed(cfg)
local flag = cfg.flag or wml.error("[animate_unit] is missing flag")
local filter = wml.get_child(cfg, "filter")
local unit
if filter then
unit = wesnoth.units.find_on_map{
limit = 1,
T["and"](filter)
}[1]
else
unit = wesnoth.units.get(
wesnoth.current.event_context.x1,
wesnoth.current.event_context.y1
)
end
if unit and not wesnoth.sides.is_fogged(wesnoth.current.side, unit.x, unit.y) then
local primary = wml.get_child(cfg, "primary_attack")
local secondary = wml.get_child(cfg, "secondary_attack")
-- We don't have access to the secondary unit at this point.
-- Thus, for the secondary attack, we just create a dummy attack
-- which exactly matches the filter.
-- TODO: Is there a way to fix this? Does it even need fixing?
if cfg.flag == "death" or cfg.flag == "victory" then
-- death and victory animations have their weapons swapped
-- The primary weapon in a death animation is the weapon that killed the unit.
-- In other words, it's the weapon of the attacker, the secondary unit.
-- The secondary weapon is the weapon of the defender, the primary unit.
-- In a victory animation, these are reversed, so the primary weapon is
-- the weapon of the defender, who is now the secondary unit.
-- Similarly, the secondary weapon in a victory animation is the weapon
-- of the attacker, who is now the primary unit.
if primary then
primary = wesnoth.units.create_weapon(primary)
end
if secondary then
secondary = unit:find_attack(secondary)
end
else
if primary then
primary = unit:find_attack(primary)
end
if secondary then
secondary = wesnoth.units.create_weapon(secondary)
end
end
local hits = cfg.hits
if hits == true or hits == nil then
hits = 'hit'
elseif hits == false then
hits = 'miss'
end
local color = {0xff, 0xff, 0xff}
if cfg.red or cfg.green or cfg.blue then
-- This tonumber() or 0 is to ensure they're all definitely numbers
-- It works because tonumber() returns nil if its argument is not a number
color = {
tonumber(cfg.red) or 0,
tonumber(cfg.green) or 0,
tonumber(cfg.blue) or 0
}
end
-- TODO: The last argument is currently unused
-- (should make the game not scroll if view locked or prefs disables it)
---@diagnostic disable-next-line: redundant-parameter
wesnoth.interface.scroll_to_hex(unit.x, unit.y, true, false, true, false)
local facing = wml.get_child(cfg, "facing")
if facing then
local facing_loc = wesnoth.map.find(facing)[1]
if facing_loc then
local dir = wesnoth.map.get_relative_dir(unit.x, unit.y, facing_loc[1], facing_loc[2])
unit.facing = dir
facing = wesnoth.map.get_direction(unit.x, unit.y, dir)
else
facing = nil
end
end
local text = cfg.text
if cfg.female_text and unit.gender == 'female' then
text = cfg.female_text
elseif cfg.male_text and unit.gender == 'male' then
text = cfg.male_text
end
anim:add(unit, flag, hits, {
target = facing,
value = {tonumber(cfg.value) or 0, tonumber(cfg.value_second) or 0},
with_bars = not not cfg.with_bars,
text = text,
color = color,
primary = primary,
secondary = secondary
})
end
for c in wml.child_range(cfg, "animate") do
add_animation(anim, c)
end
end
function wesnoth.wml_actions.animate_unit(cfg)
local anim = wesnoth.units.create_animator()
add_animation(anim, cfg)
anim:run()
end