Cover re-pick veto callback (npc_on_best_cover_repick)#607
Open
damiansirbu wants to merge 1 commit into
Open
Conversation
damiansirbu
force-pushed
the
feat-cover-stable
branch
from
July 15, 2026 10:51
8db1891 to
35e2a8f
Compare
damiansirbu
force-pushed
the
feat-cover-stable
branch
from
July 15, 2026 14:07
35e2a8f to
2723884
Compare
CStalkerCombatPlanner::on_best_cover_changed clears InCover, LookedOut and PositionHolded on every best-cover change, which drives the in-combat cover strafe and restarts detour_enemy flanks. best_cover() now calls _G.CAI_Stalker__AllowCoverRepick before that reset; a subscriber returning false keeps the current cover. No subscriber, or no cover held, is vanilla. Mirrors the themrdemonized#595 action-switch veto.
damiansirbu
force-pushed
the
feat-cover-stable
branch
from
July 18, 2026 21:35
2723884 to
2656e84
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Lua veto for best-cover re-picks, matching the action-switch veto in #595. CStalkerCombatPlanner::on_best_cover_changed clears InCover, LookedOut and PositionHolded whenever the NPC's best cover point changes. That reset is the in-combat cover strafe (NPCs sliding between near-equal cover) and it restarts flanks, since detour_enemy requires LookedOut and PositionHolded.
on_best_cover_changed has one call site, in best_cover(), reached when find_best_cover returns a point different from the one held. The engine now calls _G.CAI_Stalker__AllowCoverRepick(npc) there first; returning false keeps the current cover and skips the reset. With no subscriber, or no cover currently held, behaviour is identical to vanilla. callbacks_gameobject.script registers npc_on_best_cover_repick and forwards it with a flags table, the same shape as AllowCombatActionSwitch.
The engine sets no policy on which re-picks to keep; the subscribing mod decides, as in #595.
Use cases
A combat-AI mod keeps an NPC on its current cover while it is winning and firing, and allows a re-pick when the spot is compromised. Removes the lateral cover strafe and stops flanks restarting mid-move.
Tested
Built locally on all-in-one-vs2022-wpo (DX11, 0 errors). Run in-game with a Lua subscriber that vetoes re-picks while the NPC keeps a clear shot: it holds the cover as intended and cut about 70% of the useless in-combat cover shuffles. With no subscriber, behaviour is unchanged.
Cost
The functor runs only when find_best_cover returns a different point than the one held. For the event invalidators (enemy re-select, danger add/remove, the held cover's value degrading) m_best_cover_actual stays true after a denial, so a denied NPC is re-asked on its next invalidation; the value invalidator also stabilizes because the denial path refreshes m_best_cover_value for the held cover. Two invalidators are standing state rather than events: an enemy within MIN_SUITABLE_ENEMY_DISTANCE (3m) of the held cover, and a smart cover whose loophole is gone, re-invalidate on each combat-action execute, so a subscriber that keeps denying through one of those is re-asked at that rate. Subscribers should stay cheap and cap a continuous denial; with no subscriber the added cost is one functor lookup on the change path.
Files changed
Lua usage