Skip to content

feat(ai): runtime cvars for stalker rank-dispersion curve#544

Closed
damiansirbu wants to merge 2 commits into
themrdemonized:all-in-one-vs2022-wpofrom
damiansirbu:feat-ai-rank-dispersion-cvars
Closed

feat(ai): runtime cvars for stalker rank-dispersion curve#544
damiansirbu wants to merge 2 commits into
themrdemonized:all-in-one-vs2022-wpofrom
damiansirbu:feat-ai-rank-dispersion-cvars

Conversation

@damiansirbu
Copy link
Copy Markdown
Contributor

@damiansirbu damiansirbu commented May 27, 2026

Summary

Adds ai_dispersion_novice_k and ai_dispersion_experienced_k CCC_Float console variables that scale the per-rank weapon-dispersion multiplier on top of vanilla's rank curve in CAI_Stalker::GetWeaponAccuracy. Defaults 1.0/1.0 produce identity scaling; vanilla behavior is bit-identical without any cvar override. A cvar write from console, user.ltx, the in-game options menu, MCM, or exec_console_cmd takes effect on every stalker NPC's next shot.

The PR is purely additive. Vanilla m_fRankDisperison, its net_Spawn assignment, and the pSettings->r_float("ranks_properties", "dispersion_*_k") LTX reads are untouched. The new code adds one block after the existing base *= m_fRankDisperison; line that applies the cvar-driven scale factor interpolated by NPC rank. DLTX patches to those LTX keys continue to work normally; the cvars compose multiplicatively on top.

The PR also wires the cvars into the "Stalkers" section of the modded exes options menu introduced by PR #523, with English and Russian translation strings.

The pattern matches the existing ai_aim_* cvar family (g_ai_aim_min_speed, g_ai_aim_min_angle, g_ai_aim_max_angle, g_aim_predict_time): file-scope globals exposed via CMD4(CCC_Float, ...) and read in per-frame AI ticks.

Use cases

Any combat-AI mod that wants runtime control over the rank-dispersion curve.

  • MCM difficulty presets in modpacks that swap cvar pairs without engine knowledge.
  • Per-scenario Lua tuning (e.g. a boss fight that tightens NPC aim, then restores defaults).
  • Replacing the runtime-tuning use case behind Dynamic AI Aim Settings, GAMMA NPCs Faster Reactions, ReDone Combat AI, DLTX_JURASZKA. DLTX patches to those mods' LTX keys still work after this PR; the cvars apply on top.
  • Difficulty scaling tied to player rank or story progression from Lua.

Cvar semantics

The cvars are SCALE factors applied on top of vanilla's rank curve:

final_factor = vanilla_curve(R) * cvar_curve(R)

cvar_curve(R) interpolates between g_ai_dispersion_novice_k (at rank 0) and g_ai_dispersion_experienced_k (at rank 100) by NPC rank. To widen low-rank dispersion, set ai_dispersion_novice_k 2.0. To tighten high-rank, set ai_dispersion_experienced_k 0.5.

Cvar naming

The cvar names match the vanilla LTX key names in game_relations.ltx [ranks_properties]. The "novice_k" name is accurate (rank 0 / novice tier) but "experienced_k" is misleading: vanilla applies that value at rank 100, which is the legend tier in Anomaly's rank scale. The cvar names preserve the LTX convention for engine-side consistency; the menu description strings clarify the actual rank tier.

Mid-session rank changes

The cvar scale layer reads Rank() per shot, so mid-session rank promotions are reflected immediately. Vanilla m_fRankDisperison stays frozen at spawn. At default cvar values this is invisible; with non-default cvars the cvar curve responds to rank changes live while the vanilla curve does not. Composition is intentional.

Files changed

Six files, 57 lines added, 0 removed.

  • src/xrGame/ai/stalker/ai_stalker_fire.cpp — two new file-scope globals, 5 new lines in GetWeaponAccuracy after the vanilla base *= m_fRankDisperison;.
  • src/xrGame/console_commands.cpp — two CMD4(CCC_Float, ...) entries placed next to the ai_aim_* block.
  • gamedata/scripts/lua_help_ex.script — two cvar manifest entries.
  • gamedata/scripts/options_modded_exes_stalkers.script — two track sliders (def 1.0, min 0.0, max 10.0, step 0.1).
  • gamedata/configs/text/eng/ui_mm_modded_exes.xml — four translation strings.
  • gamedata/configs/text/rus/ui_mm_modded_exes.xml — four translation strings (windows-1251 preserved).

Console usage

ai_dispersion_novice_k 1.5
ai_dispersion_experienced_k 0.5

Lua usage

function actor_on_first_update()
    exec_console_cmd("ai_dispersion_novice_k 1.5")
    exec_console_cmd("ai_dispersion_experienced_k 0.5")
end

Adds ai_dispersion_novice_k and ai_dispersion_experienced_k as
CCC_Float cvars that scale the per-rank weapon-dispersion
multiplier on top of vanilla's rank curve.

CAI_Stalker::GetWeaponAccuracy keeps the existing
base *= m_fRankDisperison line (vanilla rank curve baked at
net_Spawn). One new block right after applies the cvar-driven
scale factor, interpolated by NPC rank. Defaults
g_ai_dispersion_novice_k = 1.0f and g_ai_dispersion_experienced_k
= 1.0f produce identity scaling; vanilla behavior is bit-identical
without any cvar override.

A cvar write from console, user.ltx, MCM, or exec_console_cmd
takes effect on every stalker NPC's next shot.

Pure addition; no vanilla code is removed or modified. The
m_fRankDisperison field, its net_Spawn assignment, and the
pSettings->r_float reads of [ranks_properties] dispersion keys
are all preserved untouched. DLTX patches to those LTX keys
continue to work and compose multiplicatively with cvar
overrides.

Manifest entry added to gamedata/scripts/lua_help_ex.script
console commands block per modded-exes PR standard.
Wires the two cvars added in the preceding commit
(ai_dispersion_novice_k, ai_dispersion_experienced_k) into the
Stalkers section of the modded exes options menu introduced by
PR themrdemonized#523. Adds track sliders (def 1.0, min 0.0, max 10.0, step
0.1) to options_modded_exes_stalkers.script. Adds English and
Russian translation strings to ui_mm_modded_exes.xml in both
text/eng and text/rus, following the existing entry pattern.

Russian XML round-tripped through iconv (windows-1251 -> UTF-8
-> windows-1251) so the Edit tool could insert UTF-8 Cyrillic
strings while preserving the file's declared encoding and tab
indentation. Direct xmlstarlet ed reformatted the file
whitespace; the iconv path keeps the diff to the four new
elements only.

Cvar names follow the vanilla LTX naming convention in
game_relations.ltx [ranks_properties] (novice_k applies at
rank 0, experienced_k applies at rank 100); the description
strings correctly identify the actual rank tiers (novice at
rank 0, legend at rank 100).
@themrdemonized
Copy link
Copy Markdown
Owner

themrdemonized commented May 27, 2026

I dont think Rank is used normally in the engine. values per character_id is all over the place (a lot more than 100, in 10000s, some have ranges ie <rank min="1000" max="6000" />)

game_relations.ltx for ranks_propertis mentions this

; Section is not used by the game.
; However it is directly referenced in-engine.
; Removing this or its contents will crash the game.
[ranks_properties]
immunities_novice_k			= 1.0
immunities_experienced_k	= 1.0
visibility_novice_k			= 1.0
visibility_experienced_k	= 1.0
dispersion_novice_k			= 1.0
dispersion_experienced_k	= 0.8

so effectively everyone have dispersion_experienced_k = 0.8

m_fRankDisperison is ultimately used only in GetWeaponAccuracy. At the end it calls lua function which fires npc_shot_dispersion callback, there you can adjust accuracy hovewer you like. I dont see a point in this PR.

@damiansirbu
Copy link
Copy Markdown
Contributor Author

You're right. Modded ranks in the thousands all collapse to rank_k = 1.0 and ai_dispersion_novice_k ends up dead. Closing.

@damiansirbu damiansirbu deleted the feat-ai-rank-dispersion-cvars branch May 27, 2026 21:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants