Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions gamedata/scripts/callbacks_gameobject.script
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,20 @@ _G.CAI_Stalker__AllowCombatActionSwitch = function(npc, from_op, to_op)
return flags.allow ~= false
end

-- NPC best-cover re-pick veto. Fires BEFORE the NPC replaces its current best cover
-- (on_best_cover_changed, which clears InCover/LookedOut/PositionHolded, runs after an
-- allowed change). Set flags.allow = false to keep the current cover. Only fires when a
-- cover is already held; a change to a different point and losing the cover entirely both count.
-- Re-asked on the next invalidation while denied; two invalidators are standing state (enemy
-- within 3m of the held cover, smart cover without a loophole) and re-ask every combat action
-- update, so keep subscribers cheap and cap a continuous denial.
AddScriptCallback("npc_on_best_cover_repick")
_G.CAI_Stalker__AllowCoverRepick = function(npc)
local flags = { allow = true }
SendScriptCallback("npc_on_best_cover_repick", npc, flags)
return flags.allow ~= false
end

-- NPC TakeCover destination callback. Only fires when a real cover point is found, not on fallback paths
AddScriptCallback("npc_on_take_cover_destination")
_G.CAI_Stalker__OnTakeCoverDestination = function(npc, cover_pos, enemy)
Expand Down
20 changes: 16 additions & 4 deletions src/xrGame/ai/stalker/ai_stalker_cover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,22 @@ const CCoverPoint* CAI_Stalker::best_cover(const Fvector& position_to_cover_from
const CCoverPoint* best_cover = find_best_cover(position_to_cover_from);
if (best_cover != m_best_cover)
{
on_best_cover_changed(best_cover, m_best_cover);
m_best_cover = best_cover;
m_best_cover_advance_cover = 0;
m_best_cover_can_try_advance = false;
// Let Lua veto replacing the held cover before on_best_cover_changed clears the cover props.
// allow = false keeps m_best_cover. Only when a cover is already held; no functor means allow.
bool allow = true;
if (m_best_cover)
{
luabind::functor<bool> repick_funct;
if (ai().script_engine().functor("_G.CAI_Stalker__AllowCoverRepick", repick_funct))
allow = repick_funct(lua_game_object());
}
if (allow)
{
on_best_cover_changed(best_cover, m_best_cover);
m_best_cover = best_cover;
m_best_cover_advance_cover = 0;
m_best_cover_can_try_advance = false;
}
}

m_best_cover_value = m_best_cover ? best_cover_value(position_to_cover_from) : flt_max;
Expand Down
Loading