MSB Enemy part (model, NpcParam row, NpcThinkParam row)
NpcParam → HP, capsule, turn speed, display masks, whose clips it borrows, its attack rows
NpcThinkParam → which Lua battle goal, eye range and angles, smell, how far it chases
AI (Lua 5.0) → weighted roll of an "act" by distance → subgoals (approach, attack, combo, strafe, back off, turn)
→ requests an action id each tick (3000 = W_Attack3000)
NPC script (HKS common_npc) → behaviour events → shared graph c9997 → clip a00X_NNNNNN
clip TAE → AI cancel windows, turn speed, AttackBehavior, Bullet1Anatomy of a hollow

c1430) in our engine, from behind. Its lantern and cape run DS3's Havok Cloth.m40 places 41 c1430, more than any other model. Their NpcParam rows differ in HP (59-183) and display masks; all share
behaviorVariationId 11000, turnVellocity 180, hitRadius 0.4, and no poise at all. Four kinds:
| NpcParam | Weapon (mask) | SpEffect → clip prefix | Battle goal | Script name |
|---|---|---|---|---|
| 143000 | sword (0) | none → a000 | 110005 / 110050 | MoujaSoldier_Sword |
| 143020 | sword and shield (1, 5) | 5404 → a001 | 110010 | MoujaSoldier_LanceShiled |
| 143030 | crossbow (2) | 5405 → a002 | 143030 | MoujaSoldier_bow |
| 143040 | broken sword (3) | 5406 → a003 | 110050 | MoujaSoldier_BrokenSword |
Borrowed clips and a shared graph
c1430.anibndholds only a skeleton. The clips and TAE are the Hollow Soldier's (c1100), named by NpcParam'snormalChangeAnimChrId, and the skeletons match bone for bone.- c1100's own graph is a stub. The states are in
c9997.hkx, the common humanoid-enemy graph (2,329 clip generators). - Every selector picks a clip prefix a000-a005 by the SpEffect's
animIdOffset÷ 1,000,000. The prefixes hold only what differs:a002(crossbow) is just its shots; anything missing falls back toa000guess.
2The NPC script
c1100's own HKS handles only event animations. The logic is the shared common_npc.hks data:
- AI requests arrive as an action id,
env(106): 3000-4499 →W_Attack<id>, 9910 raise the guard, 6000-6109 steps, 700-799 unique idles. - Movement by
MoveAngle: within ±45° walk forward (run above level 0.75), 45-135° right, beyond 135° back, else left. Turns of 45° or more play ±90° or ±180° clips. - Damage by level: 1 small, 2 middle, 3 large… Any level above 0 calls
Replanning(): getting hit makes the AI throw away its plan.
Inside an attack clip, the AI may cut in only in its windows: TAE flags 23 "Cancel – AI Combo Attack", 86 "AI Attack", 78 "AI Movement", 79 "AI Dodge".
In a000_003000 (3.37 s): 23 from 1.17 s, 79 and 86 from 1.9 s, 78 from 2.07 s. TAE 224 sets the turn speed through the swing (90, 120, 0, 0, 45, 0 °/s), which is how an attack aims itself.
3The battle AI: Lua goals and weighted dice
The AI scripts are Lua 5.0 bytecode (not HKS): script/aicommon.luabnd (209 shared goals and helpers) and
script/m40_00_00_00.luabnd (the area's battle goals). NpcThinkParam.battleGoalId names the file. Goals form a stack: a goal's
Activate pushes subgoals, its Update reports success when they're done, and the battle goal replans every time its subgoals run out.
Interrupt handlers can clear them early.
Battle goal 110005, the sword hollow
If the target is more than 60° off its front, it turns. Otherwise it weighs its acts by distance:
| Distance | Act 1 | Act 2 | Act 4 | Act 7 | Act 8 | Act 14 |
|---|---|---|---|---|---|---|
| ≥ 10 m | 15 | 40 | 5 | 10 | 15 | 15 |
| ≥ 5.5 m | 20 | 30 | 10 | 15 | 10 | 15 |
| ≥ 3 m | 15 | 15 | 10 | 20 | 20 | 20 |
| ≥ 1 m | 20 | — | 10 | 30 | 20 | 20 |
| < 1 m | 20 | — | 15 | 25 | 20 | 20 |
| Act | Reach | Attacks (roll %) | Then |
|---|---|---|---|
| 1 | 3.2 m | 35: 3000 · 40: 3000 → 3001 · 25: 3000 → 3001 → 3002 | after-act |
| 2 | 7 m | 90: 3003 (the dash thrust) · 10: 3003 → 3001 | — |
| 4 | 3.5 m | 3005 | after-act |
| 7 | 3.5 m | 30: 3008 · 70: 3008 → 3005 | after-act |
| 8 | 2.2 m | 30: 3009 · 70: 3009 → 3005 | after-act |
| 14 | 3.2 m | 20: 3000 · 80: 3000 → 3009 | after-act |
Each act first approaches to its reach less its own radius: it runs when at least reach + 10 m away (or half the time at reach + 1), giving up after 4 s walking or 8 s running. The after-attack act then rolls again by distance: strafe 2.5-4.5 s at 30-45°, back off 2.5-4.5 m, or run back in.
110010 · sword and shield
Its first act always keeps its distance behind the shield. Every approach, strafe and retreat raises the guard (action 9910). Its weights grow 1.5-5× when it's behind you. On a blocked hit within 3 m: 80 % counter.
110050 · broken sword
Swings from whichever side you stand on within 2 m, turns if you're behind it, runs in, and backs off less.
143030 · crossbow
Shoots from up to 44 m (75 % the long shot beyond 10 m), turning up to 3 s to face within 45°. The bolt is Bullet 1100801: 20 m/s accelerating to 60, light gravity, homing 5°/s.
Attack goals are C++ (GOAL_COMMON_CommonAttack). The Lua wrappers show only their parameters: success distance, turn time, front angle.
Our engine ports all four battle goals act by act, with their lives, weights and after-acts, and lets AI requests in only where the HKS would. Our readings: a combo continues only if the target is within its success distance; an approach that times out fails the plan. No navmesh (they walk straight at you), no team roles or platoons, no unique idles (sitting hollows getting up).
4Noticing you
The Lua only reads states that C++ sets (IsBattleState, IsFindState, IsCautionState). The inputs are in the data:
- Sight:
eye_dist15 m,eye_angY30° (a half-angle),eye_angX25°. Crossbow rows see 30 m at 60°. Gundyr sees 65 m, 120° each way. - Hearing: the player's clips fire TAE 237 SpawnAISound with an
AiSoundParamradius: walk 0.4 m, run 5 m, dash and roll 7 m, landings 1-7 m. The hollows' own clips fire none, so fighting one doesn't draw the others. - Smell:
nose_dist, all round. One hollow is an ambusher: eyes 2 m, nose 1 m. ear_distis mislabelled: 0 in 698 of 749 rows, else 9910, the guard request. It's on exactly the shield users.
Our engine uses these with a line-of-sight ray, eyes 1.5 m up. Played with DS3's numbers, the hollows were too easy to walk up to, so we added three adjustments (noticed within 3 m all round, eyes at least 50° each way, hearing 1.5× as far). Turned off, they leave DS3's own numbers.
5How DS3 makes enemies customisable
Almost nothing about an enemy is hard-coded. A designer composes it from data:
| Lever | Where | Changes |
|---|---|---|
| Which body and stats | MSB part → NpcParam row | HP, defence, capsule, poise, weight, regen, outfit and weapon (display masks) |
| Which moves | normalChangeAnimChrId + a SpEffect's animIdOffset | Borrow another character's clips; switch the whole clip set (the crossbow hollow, Gundyr's phase 2) |
| Which attacks hit how | behaviorVariationId → BehaviorParam → AtkParam_Npc | Damage, shapes, damage level, knockback, bullets |
| How it thinks | MSB part → NpcThinkParam → battle goal Lua | The same model can be a swordsman, an ambusher or a sniper |
| Per-row special cases | Inside the Lua: if thinkId == 110054 … | Firebomb throwers, spectators, surrounders; Gundyr's file also holds Champion Gundyr's branches |
| What it does in the story | Event scripts (.emevd) by entity id | AI on and off, invincibility, forced animations, boss bars |
6Iudex Gundyr


ForceAnimationPlayback(30002, loop), AI off, invincible, lock-on point offa000_060750; he plays 20003. The sword is his mesh on bone SealWeapon01, and the two clips are made to fit: the knight's hand stays 9 cm from itGOAL_Gunda_511000_Battle; he always walks; HP 1037, super armour 185a001_* and the switch goal picks …_HU_Battle. TAE 233 shows the pus at 0.4 s and swaps his arm meshes at 2.13 s; message 10 moves the lock-on point to the pusHandleBossDefeat, flag 14000800 → his bonfire appears and the door can openHis AI: phase 1 acts by side and distance (within 3 m on his right: 55 % act 4, 45 % act 5), with cool-downs (3000 not again for 10 s). Phase 2 adds rolls back and to the side after attacks. Small and middle hits don't flinch him: his only damage clips are Large. After a death, he rises again when you come back through the courtyard's gateway (region 4002800, a 6 × 3.8 × 6 m box 36 m from him), not when you walk up to him.
His clips, both battle goals, super armour, cloth and the event scripts are ported. Not done: the fog walls, camera 5110, his weak point, the grab and ripostes, and the pus's hurt capsules being there in phase 1 too.