wesnoth/data/lua/wml/kill.lua
Celtic Minstrel 7d5fa80180
WML: Adjust the weapon selection logic for [kill] (#7196)
* WML: Adjust the weapon selection logic for [kill]

The previous logic simply did not make sense, especially for the secondary weapon.
For example, it would ignore the secondary weapon specification if the primary weapon was not found on the secondary unit, which does not make any sense.

The cases that this changes are:
- There is a secondary unit and a primary attack, but no matching attack was found. Previously it would use the default, now it pretends that attack exists.
- There is a secondary attack specified, but no primary attack, either because it was unspecified or because it didn't match any attack on the secondary unit

In both these cases, the animation runs as if a matching attack exists, rather than using no attack and choosing the default animation.

Adjust the log level too.
2022-12-24 16:52:57 +01:00

112 lines
3.9 KiB
Lua

local location_set = wesnoth.require "location_set"
local kill_recursion_preventer = location_set.create()
function wesnoth.wml_actions.kill(cfg)
local number_killed = 0
local secondary_unit = wml.get_child(cfg, "secondary_unit")
local killer_loc = {0, 0}
if secondary_unit then
secondary_unit = wesnoth.units.find_on_map(secondary_unit)[1]
if cfg.fire_event then
if secondary_unit then
killer_loc = { x = tonumber(secondary_unit.x) or 0, y = tonumber(secondary_unit.y) or 0 }
else
wesnoth.log("warn", "failed to match [secondary_unit] in [kill] with a single on-board unit")
end
end
end
local dead_men_walking = wesnoth.units.find_on_map(cfg)
for i,unit in ipairs(dead_men_walking) do
local death_loc = {x = tonumber(unit.x) or 0, y = tonumber(unit.y) or 0}
if not secondary_unit then killer_loc = death_loc end
local can_fire = false
local recursion = (kill_recursion_preventer:get(death_loc.x, death_loc.y) or 0) + 1
if cfg.fire_event then
kill_recursion_preventer:insert(death_loc.x, death_loc.y, recursion)
can_fire = true
if death_loc.x == wesnoth.current.event_context.x1 and death_loc.y == wesnoth.current.event_context.y1 then
if wesnoth.current.event_context.name == "die" or wesnoth.current.event_context.name == "last breath" then
if recursion >= 10 then
can_fire = false;
wesnoth.log("error", "tried to fire 'die' or 'last breath' event "
.. "on unit from the unit's 'die' or 'last breath' event "
.. "with first_time_only=no!")
end
end
end
end
if can_fire then
wesnoth.game_events.fire("last breath", death_loc, killer_loc)
end
if cfg.animate and unit.valid == "map" then
wesnoth.interface.scroll_to_hex(death_loc, true)
local anim = wesnoth.units.create_animator()
local primary = wml.get_child(cfg, "primary_attack")
local secondary = wml.get_child(cfg, "secondary_attack")
-- Yes, we get the primary attack from the secondary unit and vice versa
-- The primary attack in a death animation is the weapon that caused the death
-- In other words, the attacker's weapon. The attacker is the secondary unit.
-- In the victory animation, this is simply swapped.
if primary then
local found_attack = nil
if secondary_unit then
found_attack = secondary_unit:find_attack(primary)
end
if found_attack then
primary = found_attack
else
primary = wesnoth.units.create_weapon(primary)
end
wesnoth.log('info', "Primary weapon:\n" .. wml.tostring(primary.__cfg))
end
if secondary then
local found_weapon = nil
if primary then
found_weapon = unit:find_attack(secondary)
end
if found_weapon then
secondary = found_weapon
else
secondary = wesnoth.units.create_weapon(secondary)
end
wesnoth.log('info', "Secondary weapon:\n" .. wml.tostring(secondary.__cfg))
end
anim:add(unit, "death", "kill", {primary = primary, secondary = secondary})
if secondary_unit then
anim:add(secondary_unit, "victory", "kill", {primary = secondary, secondary = primary})
end
anim:run()
end
-- wesnoth.wml_actions.redraw{}
if can_fire then
wesnoth.game_events.fire("die", death_loc, killer_loc)
end
if cfg.fire_event then
if recursion <= 1 then
kill_recursion_preventer:remove(death_loc.x, death_loc.y)
else
kill_recursion_preventer:insert(death_loc.x, death_loc.y, recursion)
end
end
-- Test that it's valid (and still on the map) first, in case the event erased (or extracted) it.
if unit.valid == "map" then unit:erase() end
-- wesnoth.wml_actions.redraw{}
number_killed = number_killed + 1
end
if (cfg.x == "recall" or cfg.x == nil) and (cfg.y == "recall" or cfg.y == nil) then
local dead_men_sleeping = wesnoth.units.find_on_recall(cfg)
for i,unit in ipairs(dead_men_sleeping) do
unit:erase()
end
number_killed = number_killed + #dead_men_sleeping
end
return number_killed
end