dayz-ai-patterns
Skill20 starsChanged 41 days agoMITView on GitHub
Use this skill when working with DayZ Expansion AI (eAI module): FSM states (Dormant, Fighting), combat hysteresis, threat/targeting, LOS/FOV, pathfinding, group formation, squad target distribution, or the NoiseSystem. Also trigger when a user asks why AI bots are not attacking, not patrolling, walking through doors, ignoring sounds, all focusing the same enemy, not spreading into formation, or when debugging eAIBase, eAIGroup, eAIState, or ExpansionPathHandler. Trigger on: eAI, DayZ AI, AI FSM, FSM pathfinding, group AI, squad AI, threat targeting, LOS FOV AI, Expansion AI, AI bots. Also 1.30: sandstorm, MINDSTATE_COWER, AIParams, GetEnvironmentNoiseReduction, animal group AI, DZMouflonGroupBeh, DZDogGroupBeh.
In this repository47 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- 3d-generation-harnessSkill
- ai-3d-to-dayzSkill
- ardy-motion-generationSkill
- blender-animationSkill
- blender-assemblySkill
- blender-visual-reviewSkill
- dayz-3d-viewerSkill
- dayz-animation-pipelineSkill
- dayz-aviationSkill
- dayz-basebuildingSkill
- dayz-charactersSkill
- dayz-clothingSkill
- dayz-doorsSkill
- dayz-environment-hazardsSkill
- dayz-feature-specSkill
- dayz-mcp-verifySkill
- dayz-model-pipelineSkill
- dayz-mod-workflowSkill
- dayz-motorbikesSkill
- dayz-p3d-auditSkill
- dayz-p3d-inspectorSkill
- dayz-particlesSkill
- dayz-pbo-buildSkill
- dayz-pbo-reverse-engineeringSkill
- dayz-persistenceSkill
- dayz-physics-engineSkill
- dayz-preflightSkill
- dayz-proxy-alignSkill
- dayz-realistic-animation-directorSkill
- dayz-sound-systemSkill
- dayz-test-ingameSkill
- dayz-texture-pipelineSkill
- dayz-ui-developmentSkill
- dayz-undergroundSkill
- dayz-vehiclesSkill
- dayz-weaponsSkill
- enforce-script-referenceSkill
- mixamo-retargetSkill
- ovh-cloudSkill
- rigorous-data-auditSkill
- rip-vehicle-importSkill
- systematic-debuggingSkill
- task-observerSkill
- uv-clean-atlasSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 61
Do not scatter DisableSimulation calls across logic — let the FSM state own that toggle.
- Distinctive: line 164
When no player is within the AI's visibility range, its update interval degrades from ~50 ms to ~250 ms.
- Very specific: line 205
If all bots are chasing the same player, check whether num_ai_in_group_not_tracking logic is intact and AddTarget is being called rather …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
DayZ Expansion AI Patterns (eAI)
Material source: salutesh/DayZ-Expansion-Scripts @ 8f75d554fda209b257c00deb8f01c181e67c980a Research: dual-arm (Claude + Codex), adversarially verified. All path:line cites are confirmed.
Overview
12 patterns covering the irreducible AI architecture of Expansion eAI:
| ID | Pattern | File reference |
| PC-5 | Dormant state: DisableSimulation via FSM | eaistate_dormant.c:1-17 |
| PC-11 | Fighting FSM: hysteresis + guard clauses | eaistate_fighting.c:18-38 |
| PC-13 | FSM loaded from XML + sub-FSM composition | eAIBase.c:661-666, Master.xml:3-8 |
| PC-9a | FOV pre-filter before LOS raycast | eAIBase.c:8156-8168 |
| PC-9b | LOS throttle adaptive to update interval | eAIBase.c:8089-8097 |
| PC-14 | Threat cache with jitter 250-300 ms | eAITargetInformationState.c:58-67 |
| PC-7 | Staggered target scan + jitter 0.1-0.2 s | eAIBase.c:2962-2966 |
| PC-2 | Backoff 5x: no players in visibility | ExpansionWorld.c:247-250 |
| PC-15 | Pathfinding: recalc thresholds + cost | ExpansionPathHandler.c:581-592 |
| PC-16 | Path filters: navmesh costs (door=10000) | expansionpathfilters.c:131-147 |
| PC-17 | Group targets: distribution by tracking | eAIGroup.c:726, eAIBase.c:3497-3505 |
| PC-18 | Formation positions: cached + jitter 2-4s | eAIGroup.c:822-830 |
Server-side scheduling/throttling principles (budget-per-frame, FPS-adaptive interval, rolling average, modulo-gating): canonical server-perf write-up: enforce-script-reference/references/server-performance.md (PC-2/PC-7/PC-9b in THIS skill are the eAI-specific instances). For #ifdef SERVER vs IsServer() side checks and ScriptInvoker lifecycle, enforce-script-reference does apply (hard rules 17-20, 28).
FSM Architecture
PC-13 — FSM loaded from XML; sub-FSM composition
eAIBase.c:661-666 + Scripts/FSM/Master.xml:3-8
LoadFSM() calls ExpansionFSMType.LoadXML(...), then Spawn(...) and StartDefault(). Master.xml includes sub-FSMs for Vehicles, Fighting, and Reloading. Dormant is a state in the master.
Key implication: state composition changes via XML, not Enforce code. Adding or removing states does not require a code recompile.
Full detail: references/eai-fsm-combat.md — PC-13.
PC-5 — Dormant state: DisableSimulation managed by FSM
eaistate_dormant.c:1-17
On enter: unit.DisableSimulation(true). On exit: unit.DisableSimulation(false). Entry conditions checked by FSM transitions: no combat, no players within visibility range, no pending waypoints, no active movement, leader is an AI unit.
Do not scatter DisableSimulation calls across logic — let the FSM state own that toggle. The FSM exit restores simulation; no caller needs to remember to re-enable it.
Full detail: references/eai-fsm-combat.md — PC-5.
Vanilla infected mind-state: MINDSTATE_COWER (since 1.30 Exp)
This is not Expansion eAI. Vanilla DayZInfected gained DayZInfectedConstants.MINDSTATE_COWER after MINDSTATE_FIGHT (exp\scripts\scripts\3_Game\Entities\DayZInfected.c:18). ZombieBase syncs m_MindState with range -1..5 (ZombieBase.c:54). On the sandstorm cower state the infected holds the calm idle pose (SetIdleState(0)); native AI already stopped movement (ZombieBase.c:474-478). [EXACT] blocks: references/dayz-1-30-ai.md.
Combat FSM
PC-11 — Fighting FSM: hysteresis thresholds and guard clause chain
eaistate_fighting.c:18-38 (enter/exit logic)
eaistate_fighting_fireweapon.c:78 (fire sub-FSM guards)
Enter combat when GetThreatToSelf() >= 0.4. Exit when it drops below 0.2. The gap prevents oscillation when threat hovers around a single value.
Guard clauses before enter: IsRestrained, IsUnconscious, IsInTransport, GetRunningAction. The fire-weapon sub-FSM has its own chain: IsRestrained -> GetTarget -> IsFighting. IsFightingFSM flag is set so external systems can query combat state without inspecting the FSM directly.
Hysteresis rule: always set enter > exit. A single threshold creates a flip-flop bug in practice.
Full detail: references/eai-fsm-combat.md — PC-11.
Threat & Targeting
PC-14 — Threat cache with jitter 250-300 ms
eAITargetInformationState.c:58-67
if (force || diff > Math.RandomIntInclusive(250, 300))
{
m_ThreatLevelUpdateTimestamp = time;
m_ThreatLevel = m_Info.CalculateThreat(m_AI, this);Each target information state carries its own timestamp and a per-call random cooldown. CalculateThreat runs at most once per ~275 ms on average. The jitter means AIs do not all recalculate threat on the same server tick.
Full detail: references/eai-pathfinding-groups.md — PC-14.
PC-7 — Staggered target scan: persistent index + jitter 0.1-0.2 s
eAIBase.c:2962-2966
m_eAI_UpdateTargetsTick += pDt;
if (m_eAI_CurrentPotentialTargetIndex >= m_eAI_PotentialTargetEntities.Count()
&& m_eAI_UpdateTargetsTick > Math.RandomFloat(0.1, 0.2))
{
m_eAI_UpdateTargetsTick = 0;
m_eAI_CurrentPotentialTargetIndex = 0;UpdateTargets advances one index per tick rather than scanning the entire list. A full refresh only happens when the index is exhausted AND the random interval has passed. Prevents all AIs from finishing their scan simultaneously.
Full detail: references/eai-pathfinding-groups.md — PC-7.
LOS / FOV
PC-9a — FOV pre-filter before LOS raycast
eAIBase.c:8156-8168
eAI_CalculateFOVHalfAngleH produces the effective half-angle (stance-adjusted). If angleDiffH > threshAngleH, the candidate is discarded before a raycast is issued. Angle comparison costs nanoseconds; a raycast costs microseconds to milliseconds depending on scene complexity.
Apply cheap spatial tests (angle, range band) before expensive ones (raycast, physics query).
Full detail: references/eai-fsm-combat.md — PC-9 (Codex angle).
PC-9b — LOS throttle adaptive to current update interval
eAIBase.c:8089-8097
if (s_eAI_FTO < 2)
interval = LOS_CHECK_INTERVAL;
else
interval = LOS_CHECK_INTERVAL * (pDt / ExpansionWorld.AI_UPDATE_INTERVAL);
if (m_eAI_LOSCheckDT < interval && !m_eAI_TargetChanged)
return state.m_LOS;In scheduler mode (s_eAI_FTO >= 2) the LOS interval scales with pDt. An AI updated at 5x the base interval does not get 5x the LOS check rate — the effective check frequency remains constant. Setting m_eAI_TargetChanged = true forces a fresh check, bypassing the cache.
Full detail: references/eai-pathfinding-groups.md — PC-9 (Claude angle).
PC-2 — Backoff 5x when no players within visibility distance (AI-specific)
ExpansionWorld.c:247-250
if (eAIBase.s_eAI_FTO >= 2 && ai.m_eAI_PlayersWithinVisibilityDistanceLimit.Count() == 0)
updateIntervalCurrent = AI_UPDATE_INTERVAL * 5;
else
updateIntervalCurrent = updateInterval;When no player is within the AI's visibility range, its update interval degrades from ~50 ms to ~250 ms. Logic is not disabled — it runs at one-fifth frequency. Condition is AI-local: each unit decides its own backoff independently.
This is the AI-specific implementation of the backoff principle (degrade frequency by relevance). Canonical server-perf write-up: enforce-script-reference/references/server-performance.md (PC-2/PC-7/PC-9b are the eAI-specific instances).
Pathfinding
PC-15 — Path recalculation with thresholds and measured cost
ExpansionPathHandler.c:581-592
ExpansionPathHandler does not recalculate on every target update. Three guards:
PATH_RECALCULATE_THRESHOLD: minimum positional delta before path is stalem_MinTimeUntilNextUpdate: cooldown between recalcsm_TimeIt.GetElapsed(): actual cost measurement per recalc (feedback for adaptive scheduling)
Legacy path: eAIPathFinding, activated with #define EAI_USE_LEGACY_PATHFINDING. Default is ExpansionPathHandler.
Full detail: references/eai-pathfinding-groups.md — PC-15.
PC-16 — Path filters with navmesh costs; DOOR_OPENED = 10 000
expansionpathfilters.c:131-147
SetFilterCost per area type: CRAWL, CROUCH, JUMP, DEEP_WATER = 10. DOOR_OPENED = 10 000. Cost 10 000 is effectively prohibitive — the pathfinder routes around an open door rather than through it (avoids collision with door physics geometry).
Filters encode behavioral preferences, not just include/exclude flags. A cost of 10 000 is a soft prohibition without a hard constraint.
Full detail: references/eai-pathfinding-groups.md — PC-16.
Group & Formation
PC-17 — Group target distribution: prevents squad over-concentration
eAIGroup.c:726 + eAIBase.c:3497-3505
eAIGroup.AddTarget distributes target data to members. Before assigning target X to a member, eAIBase checks num_ai_in_group_not_tracking: if it reaches 0 (everyone already tracks X), returns false. The squad naturally distributes across multiple enemies without explicit assignment logic.
If all bots are chasing the same player, check whether num_ai_in_group_not_tracking logic is intact and AddTarget is being called rather than bypassed.
Full detail: references/eai-pathfinding-groups.md — PC-17.
PC-18 — Formation positions cached with per-AI jitter 2-4 s
eAIGroup.c:822-830
GetFormationPosition checks m_eAI_FormationPositionUpdateTime with Math.RandomFloat(2.0, 4.0). Each member has its own jitter window. When the leader moves, members do not all recalculate simultaneously — they spread the recalc over a 2 s window.
Formation recalc is per-AI, not per-group. The group does not broadcast "recalculate now" to all members.
Full detail: references/eai-pathfinding-groups.md — PC-18.
Animal & Group AI Templates (vanilla, since 1.30 Exp)
Nasdara ships native group-behaviour templates in GroupBehaviourTemplates (exp\nasdara__data_nasdara\DZ\data_takistan\aiconfigs\config.cpp:14-132). These are not Expansion eAI FSMs.
DZMouflonGroupBeh—type = "DomesticHerbivores": graze/rest lifecycle,safeKeeperIntervalMin/Max, catch-up radii (:16-67).DZDogGroupBeh—type = "Predators":zoneType = "HuntingGround",siegeAttackCountdownMin/Max,huntAttackCountdownMin/Max,safeKeeperIntervalMin/Max(:68-127).
[DESIGN] Custom maps that want the same packs copy these classes (or inherit them) in their own aiconfigs rather than reimplementing predator/herbivore FSMs in script. [EXACT] blocks: references/dayz-1-30-ai.md.
References
references/eai-fsm-combat.md— PC-5, PC-11, PC-13, PC-9areferences/eai-pathfinding-groups.md— PC-14, PC-7, PC-2, PC-9b, PC-15, PC-16, PC-17, PC-18references/dayz-1-30-ai.md— 1.30 Exp: native noise attenuation,MINDSTATE_COWER,AIParams, animal group templates
NoiseSystem — feeding noise the AI can hear (added 2026-06-06)
Source-verified vs vanilla v1.24 (3_game/noise.c:1-23):
- Server-side API:
g_Game.GetNoiseSystem().AddNoise(entity, params, mult)/AddNoisePos(entity, pos, params, mult)/AddNoiseTarget(pos, lifetimeSec, params, mult). AddNoiseTargetcreates a positional decoy with a duration — infected/AI investigate a position with no entity attached (distraction devices, impacts).NoiseParams.Load("CfgNoises_entry")orLoadFromPath(path).- (hasta 1.29: Rain/wind reduce effective noise:
NoiseAIEvaluate.GetNoiseReduction(g_Game.GetWeather())(player steps use it,dayzplayerimplement.c:3204-3208).) (desde 1.30 Exp: weather dampening is native. Query the factor the AI uses withNoiseSystem.GetEnvironmentNoiseReduction(vector pos)—exp\scripts\scripts\3_Game\Noise.c:13.NoiseAIEvaluate.GetNoiseReductionandWeather.GetNoiseReductionByWeatherare[Obsolete](SensesAIEvaluate.c:92-93,Weather.c:454-455). Player steps no longer pass a weather multiplier:noiseMultiplier = NoiseAIEvaluate.GetNoiseMultiplier(this)thenAddNoise(noiseParams, noiseMultiplier)(DayZPlayerImplement.c:3472-3474). Infected voice noise isAddNoise(this, sound_event.m_NoiseParams)with no climate multiplier (ZombieBase.c:597-600). Tune rain/snow/fog/wind/sandstorm inclass AIParams(exp\dz\DZ\data\aiconfigs\config.cpp:19-27). Do not also multiplyAddNoiseby a script weather factor — the engine applies native attenuation on the coordinate and you would double-dampen.) - Weapon shots are config-side:
class NoiseShoot { strength = 82; type = "shot"; }in the weapon config (real mod example: IMPWMODPart2 MCXSpearconfig.cpp:73-77).
DayZ 1.30 Exp (build 1.30.164014)
What changes, what breaks, and the migration checklist. [EXACT] blocks: references/dayz-1-30-ai.md.
What changes
- Native C++ noise attenuation. New proto
GetEnvironmentNoiseReduction(vector pos)onNoiseSystem(Noise.c:12-13). HUD/debug reads it viaPluginPresenceNotifier.c:155-158. class AIParamsgainedsnowfallToNoiseMultiplier = 5.0,fogToNoiseMultiplier = 10.0,windToNoiseMultiplier = 10.0,sandstormToNoiseMultiplier = 10.0(1.29 had rain + sea only).[CHANGELOG]official text says weather handling is native and'Weather.GetNoiseReductionByWeather'was removed; the method still exists as[Obsolete](Weather.c:454-467) plusGetNoiseReductionByWeatherEx(object)(Weather.c:407-419).- Vanilla infected:
MINDSTATE_COWERfor sandstorm; net-sync range ofm_MindStateis 5. - Nasdara animal group templates
DZMouflonGroupBeh/DZDogGroupBeh. [CHANGELOG]navmesh file version has no backwards compatibility — regenerate navmesh for custom terrains (matters to eAI PC-15/PC-16). Navmesh can use a hide animation source via EntityType Navmesh config.
What breaks for a 1.29 AI / stealth mod
- Compile warning
[Obsolete("Use Weather.GetNoiseReductionByWeatherEx instead!")]if you still callGetNoiseReductionByWeather/NoiseAIEvaluate.GetNoiseReduction. - Overrides of
GetNoiseReductionByWeatherno longer change what native infected/animal AI actually hear — they hear the nativeAIParamscurve. - Passing a weather-derived multiplier into
AddNoiseand letting the engine apply native reduction double-damps the event. - Custom terrains: old navmesh files will not load.
[CHANGELOG]
Migration checklist
- For the factor AI actually uses:
GetGame().GetNoiseSystem().GetEnvironmentNoiseReduction(pos). - For HUD / old script math on a specific object:
weather.GetNoiseReductionByWeatherEx(object). - To change how rain/snow/fog/wind/sandstorm dampen zombie hearing: edit
class AIParamsinDZ\data\aiconfigs\config.cpp(rainToNoiseMultiplier,snowfallToNoiseMultiplier,sandstormToNoiseMultiplier, …). - Call
AddNoise(entity, params)without folding climate intoexternal_strenght_multiplier. - If you spawn custom infected, keep
m_MindStatesync range coveringMINDSTATE_COWER(5). - Custom maps: regenerate navmesh. Copy/inherit
DZMouflonGroupBeh/DZDogGroupBehif you want those packs. - Expansion eAI PC-5..PC-18 in this extract were not re-verified (Expansion scripts are not in
exp\). Treat those cites as 1.29 Expansion research.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

