Skip to content

Characters (humans)

Verified against: SLUS_212.15 (NTSC-U, SHA1 e9cb2cc49aa046b9e494313dce2f5038ed17b2f4). Runtime claims were made in PCSX2 2.9.94 (2026-10-04) by reading memory over PINE in level99, checkpoint 1, and say so; those about sprint, jumps and climbs (2026-10-05) in a street ("the street"), from save states made at test spots, with pad input patched in through a copy of the state; the street is in level99's world (its spots, ground and objects are where level99's collision mesh has them, Feel comparison). The disc survey read the NTSC-U disc's WAD with throwaway scripts outside the repository and reports counts and hashes only.

Purpose

Every person in the game, the player included, is a human: one object of a single class with a skinned model, an animation player and a brain. The player is a human whose controller is a pad instead of the AI. This page covers what the first playable milestone needs: how a level script creates the player, which files make a character, the object's layout as far as it is known, how pad input becomes movement, how a speed picks idle, walk or run, and the player's sprint, stamina, jump and climbs. The animation format is on Animation; the camera that follows the player on Camera.

In one paragraph: a level script calls HuCreate(name, type, position, heading, ..., player, gang). The game takes a free slot among 60 static humans, remaps the type to a behaviour class, finds the character's model by name in the Character List of warriors.glr, snaps the position to the ground with a short ray cast and, for player 1, binds pad 0 and the camera. The character's files are three resources named by CRC: the model (an RW clump with a 32-bone HAnim skeleton and a PS2 skin), its texture dictionary, and its character data (its animations and an anim id → animation table). Each update (30 per second) the pad's stick, already turned into camera space, gives a direction and a magnitude; the magnitude chooses walk (from 0.12) or run (above 0.95), the speed ramps towards it at 24 m/s², and the heading turns towards the stick at a limited rate. Holding L2 at a run sprints while stamina lasts; Triangle climbs a fence or wall in front of the player or, at a run, jumps.

Original structure

Human/ (0x00217a70-0x00323298, inferred from the path strings and calls on Source map; the four functions before Human_GetClump at 0x00217a70 belong to GameStatsSubItem.cpp, inferred from the vtable 0x0053ef48 they share with that file's anchor) holds the human; the model side is in Graphics/Character.cpp, CharacterModel.cpp and Animations.cpp. Names are ours unless a path or class string gives them.

Address Name Role Evidence
0x00358428 HuCreate binding reads the Lua arguments, calls Human_Create confirmed (code)
0x00233d60 Human_Create heading quaternion, slot, init, name, player; returns the handle confirmed (code)
0x00217f08 / 0x00217ec8 Human_AllocSlot / Human_FreeSlot a free index below 60 in the object table confirmed (code)
0x00218008 Human_Init type remap, model, ground snap, defaults confirmed (code)
0x0021cda8 Human_SetName 15 characters at +0x80 confirmed (code)
0x00229c40 Human_MakePlayer joins the player list, takes a pad and a HUD panel, brain type 0 (Players) confirmed (code)
0x0022a2a8 Human_ReleasePlayer the reverse: frees the pad and panel, leaves the player list, AI again confirmed (code)
0x00419b10 / 0x00419c68 PlayerList_Add / PlayerList_Remove the game state's list of at most two players confirmed (code)
0x0022a770 Gang_PickNextPlayer the gang member a player hand-over chooses confirmed (code)
0x0021c7c8 Human_Destroy takes a human out of the world at once (Destroying a human) confirmed (code)
0x00228730 / 0x0021cb78 static initialiser / constructor builds the 60 humans at start-up confirmed (code)
0x00228800 CharClass_Get(id) 0x00684620 + id × 0x1ac confirmed (code)
0x00383f38 → 0x00228af8 CfgChar fills a character class confirmed (code)
0x003842c0 → 0x00228888 CfgSpeedClass fills a speed class confirmed (code)
0x00221710, 0x002215d0, 0x00221620, 0x00221670, 0x002216c0 speed getters base, walk, jog, run, sprint confirmed (code)
0x00221760 Human_GaitForSpeed a speed to gait 0, 2, 3, 4 or 5 confirmed (code)
0x002213d8 Human_MaxTurn the turn limit per update confirmed (code)
0x00146078 PlayerRecord_Update pad → stick angle and magnitude confirmed (code)
0x00240e38 Human_PlayerLocomotion stick → velocity and heading confirmed (code)
0x00248df0 Human_Lean a lean from the turn rate confirmed (code)
0x00259578 Human_ChooseAnimState picks the anim state, calls its builder from 0x005106e0 confirmed (code)
0x0025b200, 0x0025b9f8, 0x0025f770 move, run-start and idle task builders see Clip selection confirmed (code)
0x0025ec28 Gait_BlendForSpeed speed → gait blend target 0-3 confirmed (code)
0x0023fea8 Human_StateUpdate (vtable +0x13c) per update: state function, gravity, out-of-world, move confirmed (code)
0x0023d8c8 Human_Move slope factor, physics sweep, ground snap confirmed (code)
0x0023eab8 Human_SnapToGround 1.5 m ray down from 1 m above the feet confirmed (code)
0x0023dc58 Human_StartFall (vtable +0x154) airborne flag, fall target, camera ledge hint confirmed (code)
0x0023e408 Human_LandingTest the airborne sweep's floor test (n.z > 0.65) confirmed (code)
0x0023e090 Human_Land clears airborne, fall damage, vz = 0 confirmed (code)
0x003a2158 / 0x003a21c0 Object_SetAirborne / Object_SetGrounded flag 0x4000000 / 0x2000000 in +0x54 confirmed (code)
0x0021b0b8 Object_SetPosition writes the transform table 0x00714b00 confirmed (code)
0x0033e278 PhysicsBody_Sweep moves a body by v × dt, up to three sliding passes confirmed (code) for the steps listed
0x00347c08 PhysicsMesh_SweepCapsule the walking body's sphere swept against the mesh's walls, with the 0.25 m step rule confirmed (code)
0x003477c0 PhysicsBody_PushOutOfWalls sphere against the collision mesh's walls (n.z within ±0.65) confirmed (code)
0x0021a490 Human_PushOutInAir the push-out sphere (or a bone segment) while airborne and in some states confirmed (code)
0x00219d50 Human_OnContact the body's contact handler: landings, fences while climbing, objects confirmed (code) for the parts cited
0x0027c120 Player_UpdateActions the player's commands each update: climb, jump, block, sprint confirmed (code) for the parts cited
0x0027ce90 Player_UpdateSprint clears the sprint flag and sets it again while L2 is held confirmed (code), runtime
0x00223188 Human_StaminaMax stamina maximum from the power class confirmed (code)
0x002562d0 Human_DrainMeters stamina drain while sprinting (and a second meter) confirmed (code)
0x00256a60 Human_RefillMeters stamina refill (and the second meter) confirmed (code)
0x002829e8 / 0x0023db48 Player_TryJump / Human_BeginJump the jump's checks; take-off gait and height confirmed (code)
0x002217f0 Human_LaunchJump the jump's velocity, then airborne confirmed (code)
0x00240898 Human_AirControl the jump's state function: steering in the air confirmed (code)
0x002826f0 Climb_TryStart the two forward probes; fence, wall and their short forms confirmed (code)
0x00282370 Climb_ProbeTop finds the obstacle's top and picks fence or wall confirmed (code)
0x00281c20 Climb_Start reach window, start point, the three-clip chain confirmed (code)
0x00281450 / 0x00281838 climb callbacks end of the first clip, from a run / from standing confirmed (code)
0x00249108 Humans_Update the characters' update, every second task-manager tick confirmed (code)
0x00249b98 Humans_MarkSkeletons marks every skeleton for an update, from mode 1 confirmed (code)
0x001783d0, 0x0018e9e0, 0x0016e8f0 resource loaders model (type 3), textures (type 4), character data (type 5) confirmed (code)
0x0016e258 chunk 0x08 handler the character data's anim table confirmed (code)
0x00177b80 / 0x00174d00 CharacterInstance create / constructor the model instance (0x330 bytes, vtable 0x00538a78) confirmed (code)
0x00217a98 Human_AttachInstance gives the human its instance (+0xd8) confirmed (code)
0x00175080 CharacterInstance_GetAnim(id) an anim id to an animation confirmed (code)
0x0023ac50 AnimCallback_Dispatch(human, id) runs the script's anim callback (Animation callbacks) confirmed (code)
0x001897a8 resource manager update loads missing characters and dynamic animations later confirmed (code)

Data

The human object (0x6d0 bytes)

Sixty humans live in one static array at 0x00640c80 (human i at 0x00640c80 + i × 0x6d0), built at start-up by 0x00228730 with the constructor 0x0021cb78. A human in use has an entry in the handle table (0x006ebd38, 0xb00 entries of {pointer, u16 serial}; a handle is serial | index << 16, resolved by 0x00390180 / 0x00390268). Vtables: 0x0053f088 at +0x00, 0x0053f020 at +0x70, 0x00544b98 at +0xe8. Confirmed (code); offsets with "runtime" were checked on Rembrandt.

Offset Type Meaning Evidence
+0x10 vec4 position, game axes (z up), metres confirmed (code), runtime
+0x20 quat rotation (x, y, z, w); a heading is a rotation about z confirmed (code), runtime
+0x80 char[16] name (Rembrandt) confirmed (code), runtime
+0x90 / +0x92 u16 own handle's serial / index confirmed (code)
+0xcc int behaviour class (0x1e for Rembrandt): selects the class record for speeds confirmed (code), runtime
+0xd0 int the type passed to HuCreate (0x20) confirmed (code), runtime
+0x54 u32 object flags: 0x4000000 airborne, 0x2000000 on the ground (Ground) confirmed (code)
+0xd4 pointer the human's 0x180-byte record (0x0065a540 + i × 0x180, below) confirmed (code), runtime
+0xe0 u64 human flags. Human_Init starts them by brain type (Combat: human flags: a Warrior gets 0x2 and the revivable 0x4). Human_MakePlayer sets 0x2 (may start a climb from a run), 0x4 and 0x2000000 and clears 0x8; 0x4000000 keeps stamina full; 0x10000000 forbids a jump; 0x20000000 forces the anim state and forbids a climb. Rembrandt: 0x24004440407 confirmed (code), runtime
+0xd8 pointer the CharacterInstance (model, skeleton, animation) confirmed (code)
+0x1a0 pointer the physics body (0 for none) confirmed (code)
+0x1a8 int the gait for the current speed (0, 1-5; 0x0022aeb0), used by the lean confirmed (code)
+0x1ac float current speed (length of the velocity, written with it) confirmed (code)
+0x1b0 s8 player slot: the human's place in the game state's player list (0 or 1), -1 for a human that is not a player; set only by the list (Players) confirmed (code)
+0x1b1 s8 hand-over priority: HuCreate's player argument, stored as given (1 Rembrandt, 2 Ash); the lowest non-zero value is the member a hand-over picks (Players) confirmed (code)
+0x1b8 / +0x1b9 u8 power class of a non-player / of a player (64 for Rembrandt) confirmed (code), runtime
+0x1d8 int material of the ground under the feet (5 when none) confirmed (code)
+0x230 vec4 ground normal from the last snap (+0x238 its z) confirmed (code)
+0x280 int an attachment: −1 normally; otherwise the human moves without the physics sweep confirmed (code) for the tests
+0x298 / +0x29c float turn this update / smoothed lean (radians) confirmed (code)
+0x2c0 vec4 where a fall will end (Human_StartFall); a climb's start point (Climb_Start) confirmed (code)
+0x2f0 vec4 external push velocity, added to the velocity when moving confirmed (code)
+0x338 handle the object in the hand (Nil when none); pose bone 25 is the right hand (runtime), 19 the left (inferred from the left-hand pick-up clips) (World objects: objects in a human's hand) confirmed (code), runtime
+0x33c handle the object being picked up, from the pick-up's message 0x14 until its clip event attaches it confirmed (code), runtime
+0x348 / +0x34c handle the carried prop a clip makes (event 0x30) and removes (event 0x31), attached at point 0x13 and moved by event 0x37: both hold the same handle once attached; Rembrandt's power move 59 uses it (Combat: props of a power move) confirmed (code), runtime
+0x37c (+0xdf as a word index) int model index in the Character List confirmed (code)
+0x380 int HUD player panel (0 or 1), -1 for none (Players) confirmed (code)
+0x384 int airborne updates so far confirmed (code)
+0x390 vec4 last ground position confirmed (code)
+0x3a0 float vertical velocity, kept by the locomotion, integrated by gravity while airborne, 0 on landing confirmed (code)
+0x3a4 float speed multiplier, set to 1.0 by Human_Init (0x002180c8); Rembrandt's speeds match his clips exactly, so 1.0 at runtime confirmed (code); runtime inferred
+0x3c0 int the gait at a jump's take-off (picks the launch speed) confirmed (code)
+0x3c8 7 × 0x28 dynamic animation slots confirmed (code)
+0x560 float the height (z) at a jump's take-off confirmed (code)
+0x5b9 u8 1 while a climb clip (437-460) plays, set by Human_StateUpdate confirmed (code)
+0x5d8 / +0x5dc float last stick angle / magnitude confirmed (code)
+0x5e0 / +0x5e4 float last turn step / last heading error (turn smoothing) confirmed (code)
+0x65c float body scale: 1.0, then a random size and a per-type override (Body scale); read by Human_GetScale (0x0021d020). 0.97 for Rembrandt confirmed (code), runtime

Per-player record (0x00660f50 + i × 0x2c, 60 of them, one per human index), confirmed (code) at 0x00146078:

Offset Meaning
+0x00 8 bytes copied from the pad record's +0x08 (Front end): the left stick's x and y as two floats (y up), not turned by the camera (the tagging stick game reads them so, 0x002748a8)
+0x1c, +0x1d the rumble: a slip in the tagging game writes 255 and 1, an on-track update 0 and 0 (inferred from Tagging)
+0x08, +0x0c stick angle, two buffers (radians, atan2 of the camera-turned stick)
+0x10, +0x14 stick magnitude, two buffers, clamped to 1
+0x18 which buffer is current (toggles 0/1 each update; the other is the previous update's)
+0x19 pad index, -1 for none (0 for the player at runtime)
+0x1b 1 while the human is pad-controlled; 0 hands it to the AI
+0x1e when not 0, Player_UpdateActions is skipped (0x00254e78 via 0x001480e0); 0 for every human in the street, so AI humans act on +0x20 too (confirmed (runtime))
+0x1f input locked: angle π/2, magnitude 0
+0x20 this update's command id (Buttons), read by 0x00147ef8; cleared each update for a human without a pad (0x00146000)
+0x24 a pending command (from table entries whose mask is 0xfe)

A second per-human record of 0x2f0 bytes at 0x006d53f0 + i × 0x2f0 is the human's brain (AI); confirmed (code) at Human_GetBrain (0x0021d408).

The 0x180 record

Each human's record (+0xd4), as far as this page uses it. Confirmed (code) at the accessors named; runtime values are Rembrandt's.

Offset Type Meaning
+0x00 u64 state flags: test 0x002265f0, set 0x002265d0, clear 0x00226620; bits below
+0x08 u32 more flags: test 0x00226660, set 0x00226640, clear 0x00226688. 0x10 forbids a sprint, 0x40 is set while climbing over, 0x400000 slows a body in the air (velocity × 0.95 per update); any of 0x84240 refuses a climb and any of 0x41a420 stops the stamina refill. Seen at runtime: 0x10000000 while a start clip plays, 0x80000 during a run stop and the first and last clips of a climb, 0x1000000 while landing from a jump
+0x14 int state code (setter 0x002266a8)
+0x18 int anim state (Clip selection)
+0x20 int anim id playing (getter 0x002266b8)
+0x28-+0xb3 int[35] anim slots
+0x144 / +0x146 s16 health / its maximum (Combat)
+0x148 s16 the power meter that grabs spend, refilled at the power class's +0x2a per second to the maximum 0x00223068 returns (+0x28, Combat)
+0x14a s16 stamina (Sprint)
+0x14c / +0x154 u32 game time (ms, *(0x0050b734) + 0x48) of the last update of the second meter / of stamina
+0x150 / +0x158 float the fractions carried between updates of the two meters
+0x164-+0x17c float the speeds (Speed classes)

State flag bits used on this page:

Bit Meaning
0x1000000 sprint asked for (L2 held, Sprint)
0x1-0x8000, 0x4000000 fight stance, grabs, mugging, tackles, throwing, blocking, theft (Combat)
0x200000000 dead
0x400000000 jumping (set at launch)
0x800000000 falling (a drop)
0x1000000000 a long fall
0x2000000000 landing

The three airborne bits (0x1c00000000) are cleared on landing.

Power classes

CfgPowerClass fills records of 0x44 bytes at 0x006619a0 + class × 0x44. A human's class is byte +0x1b9 for a player and +0x1b8 otherwise (0x00222b78). Confirmed (code) for the reads at the cited addresses; Rembrandt's values confirmed (runtime). A street civilian (class 2) had a 0.35 hurt threshold, stun 750 ms, ground time 2000 ms, power 200, byte +0x36 4 (confirmed (runtime)). The AI's fields +0x08 (block chance), +0x0c (block chance while hurt), +0x24 (counter chance) and +0x37 (the pattern-reading threshold) are on AI; +0x32 and the bytes after +0x37 are below the table. The sparring Warriors' class 40 is on AI:

Field Rembrandt (class 64) Use
+0x00 1.3 as the attacker, scales the victim's stun for weapon hits of 20-49 damage (0x0022f658)
+0x04 0.3 the hurt threshold: below this fraction of maximum health the human is hurt (0x00222ff8)
+0x10 / +0x14 1.0 / 1.0 the stun time's / the ground time's factor while hurt (Combat)
+0x1c / +0x20 3.0 / 3.0 AI only: the factor on CfgAttackDelay, the second when the target is down (0x00223800)
+0x28 400 the power meter's maximum (Combat)
+0x2a 60 the power meter's refill per second
+0x2c 135 stamina maximum
+0x2e 40 stamina refill per second
+0x30 200 a stun's length, ms (0x0022f658)
+0x34 2750 the time a knocked-down human stays down, ms (0x0022f100)
+0x36 3 in a grab struggle, the grabbed human's strike costs the grabber 1 / this of its power (0x0027fd68)

The remaining power class fields

Each confirmed (code) at the reader named (the class is the one Human_GetClassRecord picks, 0x00222b78):

Field Reader What it does
s16 +0x32 Human_ApplyPendingDamage (0x00265f70) after a hit lands on an AI human (brain kind not 0), its record +0x108 = game time + +0x32 ms; until then Human_IsBusy (0x00228258) says busy, which about 40 AI routines test (spotting, reporting a crime, joining a fight, grabbing). A player is never marked
s8 +0x38 Human_GetClassReactFlag (0x002233c8) in Human_PlayReaction (0x0026a6d0) the most ground strikes a downed human reacts to: while a reaction clip plays (Human_IsInReactionClip 0x00228488: held 0x8000, a clip with flag 0x80, or 199) and his record +0xbe is at least this, a new reaction is skipped. +0xbe counts the ground-strike reactions 195 played (Human_PlayReaction, Hit_PlayBegReaction 0x00269b80) and is cleared when he gets up (Human_EndDownState 0x0025e250)
bytes +0x3a-+0x3f Human_ApplyClassFlags (0x00222c98), from Human_Init, Human_MakePlayer and Human_ReleasePlayer switches copied into the human flags +0xe0 (Combat: human flags): +0x3a = 1 sets 0x80 (reaction strength at most 1), else clears it; +0x3b 0x1000000000 (hard to stun, below); +0x3c 0x2000000000 (never escapes when the grabber's power runs out); +0x3d 0x800000000 (reader not traced; HuSetBlockFromReact sets the same bit); +0x3e = 1 sets 0x200000 and clears 0x400000, −1 sets 0x400000 and clears 0x200000, 0 clears both; +0x3f = 1 sets 0x400 and clears 0x200, −1 sets 0x200 and clears 0x400, 0 clears both
byte +0x41 Human_ClassCanFlee (0x00224ea0) in Brain_Think (0x0028f6c0) an AI with a fight goal and nothing in hand draws a weapon: when free, it clears its actions and plays 477 ANIM_ONE_HANDED_OBJECT_DRAW (GenToIdleAnimAction). A cop (brain kind 1) does so in or out of a fight, unless his type's weapon (CfgChar +0x18c) is none. The clip's object event named random (Anim_FireFrameEvents 0x00101dd8) calls Brain_GiveHandObject (0x0028c780), which puts the type's weapon in his hand, or dyn_swhbld (a switchblade) when it is none. The name "can flee" is an old guess: the byte is "draws a weapon"
byte +0x42 Human_ShouldFleeHurt (0x00224ec8) in Brain_Think an AI with a fight goal whose health is under 30 % plays 665 ANIM_SPECIAL_FLASH (blend 0.1 s in and out) when free, after clearing its actions: an AI's flash. The name is likewise a guess the code does not bear out

Human flag 0x1000000000 (power class +0x3b, or HuSetHardToStun) changes the stun rule of Human_PlayReaction: without it a hit stuns when its Anim Range List flag 0x400 is set or the caller asks; with it neither counts, and the hit stuns only a human already stunned on his feet (Human_IsStunnedStanding). Flag 0x100 (never stunned) is tested first. Confirmed (code) at 0x0026a6d0. Who reads 0x400000 and 0x800000000 in the human flags was not found (the state and held flags of the same values are other words).

Human_StaminaMax (0x00223188) returns +0x2c; for a player, when unlockable (6, 12) is unlocked, it returns +0x2c × (1 + b × 0.01) rounded, where b is byte 3 of CfgWarriorUpgrade's record (0x006b6650). The power meter's maximum (0x00223068) is +0x28, likewise raised by byte 2 with (6, 11), then times +0x18 while the human is hurt. Confirmed (code); the unlocks: Unlockables.

Which class a human has (Human_Init, 0x00218008; confirmed (code)): +0x1b8 and +0x1b9 both take the type's CfgChar byte +0x11d; for a type of category 14 (the Warriors) +0x1b9, the class it plays with as a player, is then replaced by 0x00222ba8's by type: 58 Ajax (types 11-14), 59 Cleon (1-4, 189), 60 Cochise (15-17), 61 Cowboy (18-20, 188), 62 Fox (21-25), 63 Vermin (26-29, 191), 64 Rembrandt and Ash (30-32, 38-40), 65 Snow (33-37, 190), 66 Swan (5-10), 7 for any other. The Warrior class (+0x1ba, 0x00222c20) follows the same groups: 0 Ajax, 1 Cleon, 2 Cochise, 3 Cowboy, 4 Fox, 5 Vermin, 6 Rembrandt and Ash, 7 Snow, 8 Swan, 9 anyone else. Each difficulty script sets every class again and re-runs CfgChar for 63 types. Every value: Power classes, Warrior classes.

Character classes

CfgChar (in config_preload2.lua) fills a 0x1ac-byte record per type at 0x00684620 + id × 0x1ac: 45 floats from +0x00, 16-bit values from +0xb8, the model index by name at +0x112 and by "<name>_a" at +0x114 (used in levels 60-64), the speed class byte at +0x11c, and four strings (32 bytes each) from +0x14c. Rembrandt's call is CfgChar(32, ..., 1800, DamageFox, Att_Warrior, 1, "warr_re_cv", "none", 7, 0, RangeNormal, "none", 0, "none"); type 40 (Ash) uses warr_ty_cv. Confirmed (code) for the layout; the arguments inferred from the disassembly.

Human_Init remaps the type: 32 becomes behaviour class 30 (0x1e) with a variant flag (confirmed (code) at 0x00218008, runtime +0xcc = 0x1e, +0xd0 = 0x20).

The fields with a known reader besides the tables above, confirmed (code) at the addresses given:

  • The range table (45 floats at +0x00, the script's numbers ÷ 100, so metres): read once per human by Human_AttachInstance (0x00217a98) when its model is attached, beside the damage table. For each attack kind k (the index of the damage and attack tables) whose value is above 0, Attack_CallKindHandler (0x002545e0, jump table 0x0055d640, kinds 0-41) writes it as the far range (value × 1000, mm; Anim Range List +0x08) of that kind's anim ids with AnimRange_SetFarRange (0x002545a8). A 0 leaves the anims' own far range. The ids per kind: 0 → 11; 1 → 12; 2 → 13; 3 → 15; 4 → 14; 5 → 16; 6 → 17; 7 → 19; 8 → 18; 9 → 20; 10 → 25-30; 11 → 21; 12 → 193; 13 → 194; 14 → 237-240; 16 → 653, 655; 17 → 657, 659; 19 and 20 → 0; 21 → 3, 4; 22 → 70, 71; 15, 18 and 23-44 none. The far range is what Human_CanStartAttack and the steer use (Combat); kind 22's ids 70, 71 are the grab's search and kind 21's 3, 4 the tackle's. The list written is the character data's (record +0x160 points at the model's own list, HumanRecord_SetAttackTable 0x00254568), so every human with that model shares the values the last one attached wrote (inferred from the pointer; the damage table has the same reach).
  • The voice (s16 +0x118): human +0x3b0, the folder vags/character/voices/<n>/ (format string at 0x0055a548, l<level>_c<checkpoint>_idle_<nn>); type 259 instead takes a random 120-125. Human_Init counts the type's idle lines 1-3 there (+0x197, +0x196 set when any exists). +0x3b4 is the level's variant (Anim_LevelVariant) or the voice. So the binding page's "Warrior index" was a misreading: Rembrandt's 7 is his voice folder.
  • The weapon (string +0x18c): when it is not none, Human_Init puts that object type in the new human's hand (Human_PlaceItemInHand(h, name, 1, 1) 0x0024c280, confirmed (code): made by name, recorded as a pinned object, refused when the hand is already busy with held flag 0x4000). The police types carry dyn_baton. A cop who later has nothing in hand draws it again, and an AI of a power class with byte +0x41 draws it, or a switchblade when it is none (Power class fields).

Body scale

Human_Init ends by sizing the human (confirmed (code), 0x00219040-0x002191fc), stored by Human_StoreScale (0x00219608, which also rescales the physics body):

  1. A random size, only for a human whose brain type is not 3 (a Warrior), whose class category (+0x11b) is not 12 or 13, and whose type (+0xcc) is none of 122, 221, 222, 303-305, 307, 351, 414-416, 425, 458, 459. With r = Random_Int(99) (0-99, stream 0x006eb880) and "hat" = the type's hat (+0x14c) is not none:
  2. a woman (flag_14b, human +0x3b8, set): 1 − 0.01 × (r / 25), so 1.0, 0.99, 0.98 or 0.97, a quarter each; with a hat at least 0.99;
  3. anyone else: r 0-30 → 1.0; 31-54 without a hat → 1.02 for a cop (brain type 1) or a gang member (brain type 2) whose brain +0x20c record's +0x2c is below 23, else 0.98; otherwise (31-54 with a hat, or 55-89) → 1.01 when r < 90, else 1.0.
  4. The type's fixed size (Human_ApplyTypeScale, 0x00219638, also run by Human_AttachInstance; confirmed (code)) replaces it for these types (+0xcc): 5 → 1.02; 18, 30 → 0.97 (so Rembrandt's 0.97, as seen at runtime); 21, 23, 24 → 0.98; 33 → 1.03; 89 → 1.16; 119, 120, 135 → 1.2; 128 → 1.175; 161 → 1.11. With game state +0x158 set (co-op), 89, 119, 120, 128 and 161 take 1.1 and 135 takes 1.03.

Human_GetScale (0x0021d020) returns it, except 1.0 in a scene for a scale under 1.1. Confirmed (code).

Stats

Everything that makes one character stronger, tougher or faster than another comes from four configuration tables, all set by the configuration scripts and again by each difficulty's (the boot set equals normal's). The sections above and the pages they link hold the detail; this is the one list. "Human" is the field the value lands in when a human is made or becomes a player; the evidence is as the cited page gives it. Every type's values on normal: Characters (its Stats (normal) column joins the four tables).

1. The character type (CfgChar, record 0x00684620 + type × 0x1ac, Character classes; confirmed (code) at CharClass_Get, 0x00228800); Human_Init (0x00218008) reads it at creation, +0x11b and +0x11d from the type's own record and the rest after the remap from the class's:

Stat Field Human What it does Evidence
Behaviour byte +0x11a brain type the AI's brain kind (AI: types) confirmed (code)
Category byte +0x11b (read from the record) 14 the Warriors: a player takes his Warrior's power class; 13 the bosses and big fighters; the money class and the civilian reactions (Starting money) confirmed (code)
Speed class byte +0x11c record +0x164-+0x17c the speed class, a fallback the clips' own speeds replace in play confirmed (code)
Power class byte +0x11d +0x1b8, +0x1b9 below; a Warriors player's +0x1b9 is his Warrior's confirmed (code)
Health s16 +0x116 record +0x144 / +0x146 health and its maximum (1800 for every Warrior, 600 for the street civilian) confirmed (runtime) (Combat: damage)
Damage table × damage scale s16 × 45 at +0xb8 the human's Anim Range List written over the list's damages when the model is attached (0x00217a98); a player's first times his Warrior class's damage % (Damage) confirmed (code), confirmed (runtime)
Attack table byte × 45 at +0x11e brain +0x298 an AI's weight for each attack kind (AI) confirmed (code)
Range table float × 45 at +0x00 (÷ 100) not traced no reader found not traced
Hat string +0x14c the hat object worn from creation (Hats) confirmed (code)
Voice s16 +0x118 voice set the folder of the type's speech (Characters reference; the binding page calls it a Warrior index) inferred
flag_14b byte +0x14b +0x3b8 a civilian woman's tag colour (Tagging), the _female animation sounds (Sound events), the money record 16 for category 4 (Starting money); the body scale +0x65c = 1 − 0.01 × n is read beside it, n not traced confirmed (code); the scale not traced
Drop group, drop chance string +0x16c, int +0xb4 +0x257, +0x278, money +0x370 the carried object and its drop chance, and the starting money (Starting money) confirmed (code)
Weapon string +0x18c not traced read by Human_Init; what it gives is not traced not traced

2. The power class (CfgPowerClass, record 0x006619a0 + class × 0x44, Power classes), by +0x1b9 for a player and +0x1b8 otherwise (0x00222b78). A player of a Warriors type plays with 58-66 by Warrior (7 without one); everyone else with the type's own class. Confirmed (code) at each reader:

Stat Field What it does
Power meter s16 +0x28, +0x2a maximum and refill per second (record +0x148); × +0x18 while hurt (0x00223068); with the gym's power upgrade a player's maximum × (1 + byte 2 / 100)
Stamina s16 +0x2c, +0x2e maximum and refill per second (record +0x14a, Human_StaminaMax 0x00223188); with the gym's stamina upgrade a player's maximum × (1 + byte 3 / 100)
Hurt threshold float +0x04 below this share of maximum health the human is hurt (0x00222ff8)
Stun, down s16 +0x30, +0x34; floats +0x10, +0x14 a stun's and a knockdown's length, ms, and their factors while hurt (Reactions)
Weapon stun float +0x00 as the attacker, scales the victim's stun for weapon hits of 20-49 damage (0x0022f658)
Grab struggle byte +0x36 the grabbed human's strike costs the grabber 1 / n of its power (0x0027fd68)
AI: block, counter, attack delay floats +0x08, +0x0c, +0x24, +0x1c, +0x20; bytes +0x37, +0x39 the AI's block chances, counter chance, attack delay factors, pattern-reading threshold and throws at walls (AI)
Health bar byte +0x40 the pause Stats screen's Health bar (+0x40 / 100, Stats screen); the health rings' span (HUD)
Not traced +0x32, +0x38, +0x3a-+0x3f, +0x41, +0x42 stored; no reader found

3. The Warrior class (CfgWarriorClass, record 0x006b65c0 + class × 14, human +0x1ba by type: 0-8 the nine Warriors, 9 everyone else), read through 0x00222b58. Confirmed (code) at each reader (Warrior classes):

Stat Field What it does
Rage s16 +0x00; bytes +0x02-+0x04 the rage maximum, the gain percentage, and the idle decay and the drain while raging, percent of the maximum per 20 s (Rage)
Health % byte +0x05 when the human becomes a player (Human_MakePlayer 0x00229c40) his health and maximum are times n %, rounded; divided back when he stops being one (0x0022a2a8). Rembrandt: 1800 × 50 % = 900
Damage % (Strength) byte +0x06 a player's attack damages times n % (Damage); the Stats screen's Strength bar
Context games bytes +0x07-+0x0c the cuffing hold, the uncuff mash, tagging, lock picking, the stereo theft and mugging

4. The gym upgrades (CfgWarriorUpgrade, bytes 0x006b6650-0x006b6653; 10, 20, 10, 20), each only while its unlockable is unlocked (Unlockables): punch damage + 10 % (6, 5), kick damage + 20 % (6, 6), the power maximum + 10 % (6, 11), the stamina maximum + 20 % (6, 12). Confirmed (code) (CfgWarriorUpgrade).

The pause Stats screen's bars read these: Strength from the damage %, Stamina from the power and stamina maxima (upgrades included), Health from the power class's +0x40, Rage from the rage maximum / 150. The formulas are on Pause: Stats screen. "Strength" is not a field of its own: it is the Warrior class's damage %.

Coney's implementation

Coney reads the four tables from the configuration calls the scripts make (characters::CharacterTypes, ai::aiConfigFrom()), on the one difficulty it runs: the boot set, which is normal's. A human gets its type's stats when it is made (ai::AiHumans::spawn(), from the cast of a level's scripts) and a player when he is made or changes type (human::playerClassOf(), human::playerProfileOf()):

Stat Applied? Where Test
Behaviour yes, AI ai::aiConfigFrom() → brain type tests/ai/disc_ai_config_test.cpp
Category yes: boss class, a Warriors player's power class, the money class ai::FighterClass::category, characters::powerClassOf(), characters::moneyCategory() tests/characters/character_types_test.cpp, tests/characters/starting_money_test.cpp
Speed class no (a fallback; Coney uses the clips' speeds as the original does in play)
Power class (AI and player) yes play_level_cast.cpp (the type's +0x11d), characters::CharacterTypes::playerTraitsOf() tests/characters/character_types_test.cpp, tests/platform/disc_change_character_test.cpp
Health (AI) yes ai::FighterClass::health tests/ai/brain_test.cpp
Health (player) × Health % yes characters::PlayerTraits::health, human::playerProfileOf() tests/characters/character_types_test.cpp, tests/platform/disc_change_character_test.cpp
Damage table × scale; player × Damage % yes characters::parseCfgChar(), human::Human (its own Anim Range List) tests/characters/character_types_test.cpp, tests/combat/anim_ranges_test.cpp
Attack table yes, AI ai::FightSettings::attackWeights tests/ai/fight_goal_test.cpp
Range table no: not traced
Hat yes platform/play_level_hats.cpp tests/world_objects/hats_test.cpp (the fittings; the creation path has none)
Voice yes script::voiceSetOfType() tests/audio/game_sound_test.cpp
flag_14b the tag colour and the female sounds; not the body scale (every human has the player's 0.97) play_level_cast.cpp, the sound events tests/audio/human_sound_events_test.cpp
Drop group, drop chance, money yes characters::rollStartingCarry() at HuCreate tests/characters/starting_money_test.cpp
Weapon no: not traced
Power meter (+0x28, +0x2a) yes, every human (was the player's 400 and 60 for all before) combat::PlayerCombat from human::FighterProfile::powerClass tests/human/human_test.cpp, tests/platform/disc_change_character_test.cpp
Hurt power factor (+0x18) yes combat::PowerMeter::setHurt() tests/combat/meters_test.cpp
Stamina (+0x2c, +0x2e) yes, every human (was the player's 135 and 40 for all) human::Stamina, human::Human::spawn() tests/human/stamina_test.cpp, tests/human/human_test.cpp, tests/platform/disc_change_character_test.cpp
Hurt threshold, stun, down times yes human::Victim, human::Fighter::hurt() tests/human/being_hit_test.cpp
Stun and down factors while hurt (+0x10, +0x14), weapon stun (+0x00) no
Grab struggle (+0x36) yes human::Fighter tests/combat/grabbed_test.cpp
AI block, counter, delays, walls (+0x08, +0x0c, +0x1c, +0x20, +0x24, +0x39) yes combat::PowerClass, the brains tests/ai/fight_reactions_test.cpp, tests/ai/brain_test.cpp
AI pattern-reading threshold (+0x37) no
+0x40 (health rings) yes: read from the configuration now (was Rembrandt's 35 for every class) characters::parseCfgPowerClass(), play_level_world.cpp tests/characters/character_types_test.cpp, tests/hud/health_rings_test.cpp
Rage (max, gain, decay, drain) yes, the player's Warrior class (was class 6's for every player) combat::RageClass, combat::RageMeter tests/combat/meters_test.cpp, tests/human/human_test.cpp, tests/platform/disc_change_character_test.cpp
Health % given back on release no: Coney's hand-over is a stand-in that keeps one player human (hand-over)
Lock pick, tagging, mash bytes yes scripting/object_bindings.cpp tests/scripting/object_bindings_test.cpp
Cuffing, stereo, mugging bytes no: those games are not implemented for a player
Gym upgrades no
Stats screen no: the pause menu's Stats item is not implemented

Coney's readings: the player's health is read from the type's own +0x116 (the page does not say which record Human_Init takes it from; every Warriors alias has its class's value), rounded to the nearest; a configuration with no CfgWarriorClass leaves the health unscaled and the rage at class 6's.

Hats

CfgHat(set, type, hat, {x, y, z}, {i, j, k, r}) (Cfg_AddHatFit, 0x00228d70) fills a hat-fit set: a record of 0xa90 bytes at 0x00662b70 + set × 0xa90 with 48 slots of a 32-byte transform (the offset with w = 1, then the rotation) from +0x00, the 48 hat names (24 bytes each) from +0x600, and the owning character type at +0xa80; a hat goes into the first slot still named none. Placing a worn hat (0x003a3ba0): for a human whose class has brain kind 3 (+0x11a, the Warriors), the set owned by the type it was created as (+0xd0) if there is one, else by its class (+0xcc), and in it the slot named as the hat's object type (0x00228f40 for the offset, 0x00229028 for the rotation); a hat in no slot of the set gets a default transform (0x005116c0). Every other human uses the hat model's own attach point (0x00391828, 0x00391880). Confirmed (code). The 908 fittings: Hat fittings.

Where a hat comes from. The character class's string at +0x14c (CfgChar's argument 11, none for most classes) is the hat object's type name: when the human's character instance is attached (Human_AttachInstance 0x00217a98, at creation or when the model streams in later) and that name is not none, Human_SpawnHat (0x0024bfc0) creates the object by name at the human, adds it to the world's object list pinned, stores its handle at +0x364 and sends it message 0x32 (wear) with attach point 6, a zero offset, an identity rotation and whether the human is in a scene. HuPlaceHatOnHead (0x002385f8) goes through the same function. Confirmed (code). So a dealer with no script hat still wears his class's hat when his class names one.

On the head. The hat's 0x32 handler (HatObject_Wear, 0x003e77c0, Script types) zeroes its velocity and spin, attaches it (Obj_Attach) to bone 6, the head (the head strike sphere's bone, Combat), clears its flags 0x6000000, and writes its local transform in that bone's frame: the position is the fit offset (Human_PlaceHat(…, 0xb), the set's or the model's, above) times the human's scale (Human_GetScale), the rotation the fit rotation (Human_PlaceHat(…, 0xc)), unscaled; then it tells the human (message 3). Confirmed (code). That the attach composes the head bone's matrix with this local translation and then rotation (bone × T × R), as every attached object does, is inferred.

Knocked off (Human_KnockOffHat, 0x00258330), confirmed (code):

  • Never while human flag 0x10000000000 is set (HuSetKeepHat), without a hat, or when the hat's object kind (+0x86) is 27.
  • Who calls it: every knockdown reaction (Human_PlayReaction 0x0026a6d0), except for a brain of type 1, class 0x80 and class 13; health running out (0x002677c8); being mounted (Pair_LinkMount 0x0022c0a0); the human's messages 3 and 0xc2 (not for brain type 1); Human_ResetToOneHealth, Human_ScriptDrop, the hat object's destruction (Obj_Destroy), class 0x80 going down (0x00257ef0), and picking up another hat (kind 24) in the pick-up search (0x0024d810). Ordinary hits that do not knock down leave it on.
  • The throw: by human +0x668 & 3 (inferred: the side the blow came from) it picks a direction d and a spin axis a from the unit x and y axes (0: d = +y, a = +x; 1: +x, −y; 2: −y, −x; 3: −x, +y), sets the hat's spin (vtable +0x7c) to a × 8 rad/s and sends it message 0x1c (drop) with d × 2 m/s. The drop (HatObject_Drop 0x003e7958) turns that velocity by the wearer's orientation (inferred from the cross products), detaches the hat at its world pose (Obj_Detach), gives it flag 0x4000000 (and 0x80 for three models) and state 2, updated every 2 ticks: from here it is a loose physics object that falls and lands (Script types). +0x364 is cleared.
  • Afterwards it stays where it lands, and may be picked up again. Only when the game state's +0x35c is 1 (a mode flag, not traced) does it get a respawn timer, by model hash (+0xc4): none for the Warriors' hat 0xbbbef927; 8000 ms for a player's 0x50e8de39 or 0x17d7194b; none for the other 0x331fd29, 0x50e8de39, 0x17d7194b and a player's 0x1d5ee290; the game state's +0x26c for every other hat. A wearer of brain type 1 or 2 marks the hat's +0x10b with its type.

From a type to a model

How HuCreate's type picks what is drawn and animated, confirmed (code) at 0x00218008 (Human_Init), 0x00228af8 (Cfg_SetCharacterClass, CfgChar's writer) and 0x001780e8:

  1. CfgChar resolves the model name once, when config_preload2.lua runs: its model-name argument (warr_re_cv for type 32) is hashed (CRC-32 of the lower-case name, Name hashing) and looked up in the Character List (the resource manager's +0x88, the chunk 0x44 records of Files); the record's index is stored at +0x112 (0xffff when the name is not in the list). The same is done for "<name>_a" into +0x114.
  2. Human_Init maps the type to a class with a fixed switch. Types not in it are their own class. A type marked variant below sets a flag; the others are plain aliases of their class:

    Class Plain aliases Variants
    1 2 3, 4
    5 6 7, 8, 9, 10
    11 (0xb) 12 13, 14
    15 (0xf) 16
    18 (0x12) 19 20
    21 (0x15) 22 25
    26 (0x1a) 27 28, 29
    30 (0x1e) 31 32
    33 (0x21) 34 35, 36, 37
    38 (0x26) 39, 40
    41 (0x29) 42
    43 (0x2b) 44
    45 (0x2d) 46, 47, 48
    221 (0xdd) 222
  3. The model index (kept at +0x37c): the type's own record when the human is not a player (player index below 1) or the type is a variant; otherwise (a player created as a plain alias) the class's record. Of that record it reads +0x114 (the _a model) when the current level's number is 60-64 (the Armies of the Night bonus levels), else +0x112. So a player made as type 2 (warr_cl_gen) is drawn as type 1's warr_cl, while type 32 keeps warr_re_cv.

  4. The rest of Human_Init reads the class record: +0xcc holds the class from here on, and the fields read after the remap (+0x118, +0x11a, +0x14b, +0xb4, the strings at +0x14c and +0x18c) come from it; only +0x11b and +0x11d are first read from the type's own record. +0xd0 keeps the type as given. Whether the later systems (combat, health) read the class or the type is not traced here.
  5. The files: the Character List record at the model index names the three resources (character data with the animations, model, texture dictionary, Files); Human_Init makes the instance at once when they are resident (0x001774d0, 0x00177b80, then Human_AttachInstance 0x00217a98; confirmed (code)), else the resource manager loads them later (Creation). The anim set is that character data over the generic defaults (its 722 slots, Files) and the anim slots, the same for every type until a movement style changes them.

For an implementer with Coney's recorded CfgChar calls and its CharacterList: find the type's call, apply the alias rule for a player, take the model-name argument (or <name>_a in levels 60-64) and look it up by name. The character reference lists every type's model name.

Speed classes

CfgSpeedClass(class, ...) writes six floats at 0x006b6548 + class × 0x18. The getters read entry +0x00 (base), +0x08 (walk), +0x0c (jog), +0x10 (run) and +0x14 (sprint); +0x04 has no getter found. Values from config_preload2.lua (inferred from the disassembly):

Class +0x00 +0x04 walk jog run sprint
0 3 0.8 1.6 4.1 6.5 8
1 3 0.8 1.6 4.1 7.5 9
2 3 0.8 1.6 1.6 1.6 9.75
3 3 0.8 1.6 4.1 7.5 7.5
4 3 0.964 0.964 0.965 2.723 2.723

But these are not used in play. When 0x005101e0 is set (it is 1 at runtime), each getter returns the human's own value from its 0x180-byte record times +0x3a4 instead (confirmed (code) at 0x00221710, 0x002215d0): +0x164 for the base, +0x170 for walk, +0x174, +0x178, +0x17c for jog, run and sprint.

The speeds come from the clips. 0x00254078 (called when the character is attached, Human_AttachInstance 0x00217a98, and after a movement-style change, 0x00243848, 0x00253688) computes each one from the clip in an anim slot as the clip's horizontal root displacement over its playing time: sqrt(dx² + dy²) / (duration / rate), with the displacement from the clip's descriptor (0x00101950), the duration from 0x00101a00 and the rate from 0x00104a38. Confirmed (code). It writes, in the 0x180 record:

Record field Speed From slot Rembrandt (runtime)
+0x164 base (combat walk) 14 3.429 (clip 380)
+0x16c sneak walk 3 1.585 (407)
+0x170 walk 4 1.629 (408)
+0x174 jog 5 4.857 (409)
+0x178 run 6 7.801 (410)
+0x17c sprint 7 10.245 (411)

Each runtime value equals the clip's displacement divided by its duration as read from the disc, confirmed (runtime). The speed class table is therefore only a fallback.

Gait from speed (0x0022aeb0, the gait stored with the velocity): below 0.5 m/s gait 0; otherwise the gait 1-5 whose speed (+0x16c, +0x170, +0x174, +0x178, +0x17c) is nearest. Confirmed (code); a jump table at 0x0055bec0. It scans from gait 5 down and stops at the first gait whose next lower one is strictly farther, so a tie goes to the lower gait. With Rembrandt's speeds (above, +0x3a4 = 1.0) the bounds are the midpoints: gait 0 below 0.5, 1 below 1.607, 2 below 3.243, 3 below 6.329, 4 below 9.023, 5 above. So the combat walk at 3.429 m/s is gait 3 (1.428 from the jog, 1.800 from the walk), the free walk at 1.629 is gait 2 and the run at 7.801 gait 4. Confirmed (code) at 0x0022aeb0; the bounds follow from the runtime speeds.

Anim slots

The 0x180 record holds the human's anim slots: 35 anim ids at +0x28-+0xb3, copied from the default table at 0x005105d8 (0x00253608) and changed one by one by 0x002535f0(human, slot, id). A player gets slot 14 = 380 (player combat walk). 0x00253688(human, style) swaps in a movement style's ids (cases 1-20, a jump table) and then recomputes the speeds. Record +0x20 is the anim id playing (getter 0x002266b8). Confirmed (code); Rembrandt's ids were read at runtime and named from the clips on the disc (confirmed (runtime)).

Slots count from 0, with no offset or remapping: 0x00253608 copies the table's 0x8c bytes (35 words) to record +0x28 as they are, and 0x002535f0 stores slot s at +0x28 + 4s. The player's slot 14 is the table's fifteenth word (372 replaced by 380), and the movement styles write by the same numbers: styles 4 and 6 put their own "run stop" ids (523 ANIM_BARREL_MOVEMENT_RUN_STOP, 569 ANIM_GHETTO_MOVEMENT_RUN_STOP) in slot 33, where the default is 417 ANIM_MOVEMENT_RUN_STOP. Confirmed (code) at 0x00253608, 0x002535f0 and 0x00253688. The last slot, 34, holds 0 in the table and no style writes it; whether 0 there means anim id 0 (ANIM_RUNNING_ATTACK_CHARGE) or "no clip" is not traced (the anim id reference treats it as unset).

Slot Id Clip Slot Id Clip
0 388 neutral idle 18 212 mounting strike
1 401 step forward 19 193 grounded strike
2 403 dash forward 20 104 grab front attack
3 407 sneak walk 21 605 block start
4 408 walk 22 608 block high front
5 409 jog 23 606 block sustain
6 410 run 24 607 block shuffle
7 411 sprint 25 427 jump start
8 390 slow turn right 26 428 drop cycle
9 412 sneak walk start 27 429 drop land
10 413 walk start 28 388 neutral idle (again)
11 358 combat idle 29 653 special attack 1 front
12 366 combat shuffle forward 30 434 jump loop
13 368 combat dash forward 31 668 special action (missing_anim_filler in the generic data)
14 372 (player 380) combat walk forward 32 317 fire idle
15 360 combat turn 33 417 run to neutral (run stop)
16 12 attack S1 34 0 none, or id 0 (above)
17 11 attack X1

Slots 16-24 and 28-33 are named from the ids' ANIM_* constants in royal.lua and their generic clips (inferred: what each slot is used for has not been traced, only its default id). The full table, with every id's clips, is the anim id reference.

Other locomotion ids seen at runtime outside the slots: 414 run start, 418 run 180° turn, 421-426 fall front / back begin, cycle and land.

Files of a character

A character is three resources, each a file named by the decimal CRC of a hash ("%u", 0x00551ed8) and loaded by the resource manager (Chunk system). The resource types and their loaders are confirmed (code); the chunks each file holds are inferred from the chunk handlers on that page:

  • the model (resource type 3, loader 0x001783d0, confirmed (code)): chunk 0x47 with the RenderWare clump, then chunk 0x28 with the bones' bind offsets (34 × float4, 544 bytes);
  • the texture dictionary (type 4, 0x0018e9e0, confirmed (code)): one chunk 0x2a;
  • the character data (type 5, 0x0016e8f0, confirmed (code)): the animations (a 0x00 keyframe chunk and a 0x02 descriptor for each, Animation), one Anim Range List (0x45) and one Character Data chunk (0x08).

The Character List (chunk 0x44 in warriors.glr, 543 records of 32 bytes) finds them by model name:

Offset Meaning
+0x00 CRC-32 of the model name, lower case, no path prefix (Name hashing)
+0x04 hash naming the character data resource
+0x08 hash naming the model resource
+0x0c hash naming the texture dictionary
+0x10 the character data's size
+0x14 the model's size
+0x18 a size close to the model's (+0x14 plus 0x1df in the cases checked; meaning not traced)
+0x1c the texture dictionary's size

Confirmed (code) for +0x00-+0x0c (the loaders' lookups); the sizes are inferred from matching the WAD entries.

The clump, the same for every skinned character on the disc: one atomic, 33 frames, an HAnim hierarchy (0x11E) of 32 bones with key size 36 and flags 0, geometry in PS2 native format (0x010200f3, two texture coordinate sets) with the extensions 0x50e, 0x510 (native data) and 0x116 (Skin, PS2 platform 4). Plugins: Graphics. Corroboration (disc survey).

Character Data (0x08, 2,912 bytes for Rembrandt; handler 0x0016e258, vtable 0x005389a0): a placeholder vtable word, then 722 slots at +0x08, one per anim id, then 16 bytes. A slot of 0xffffffff means "use the default", taken from the table at resource manager +0x70; a slot value n picks the n-th animation loaded with this resource, counted on the stack of objects the chunk system pops last-in first-out. CharacterInstance_GetAnim (0x00175080) answers an id with this table. For Rembrandt, id 408 is walk and 413 walk-start; ids 11 and 12 are combo attacks (inferred from the clip names). The handler keeps the Anim Range List at +0xb50 / +0xb54. Confirmed (code) for the slot rule; the id meanings inferred.

Anim Range List (0x45, 11,568 bytes): a count word, then 722 records of 16 bytes, one per anim id, of the form (s16, s16 = 1000, f32, s16, s16, s16, u16): offsets, reach, ranges and rate flags (Animation).

Example, Rembrandt (warr_re_cv): character data 0xe72f9fb5 (200,640 bytes, shared with warr_re: 36 animations, one 0x45, one 0x08), model 0xdb1cdf36, textures 0x46af47d8. Corroboration (disc).

Disc survey (counts only): 153 distinct skinned models, all with 33 frames, 32 HAnim bones, key size 36, a PS2 skin and a 544-byte bone offset chunk; 1,209 Character Data and Anim Range List chunks.

Character geometry

What the model's bytes hold beyond the clump's sections, found by Coney's decoder and its disc test over the 128 models the Character List names (no code was read for this subsection, so it is corroboration (disc) unless marked).

  • The native geometry is the world's PS2 layout (Graphics) with a fifth slot: STCYCL 5,1 and five UNPACKs per batch, slot 0 positions (V4_16), slot 1 texture coordinates (V4_16, two sets), slot 2 colours (V4_8 unsigned, all zero in the characters checked), slot 3 normals (V4_8) and slot 4 the bone weights (V4_32, format 0x6c). Vertex counts match the mesh plugin's in every model.
  • A weight is a float whose low 10 bits are replaced by (node index + 1) << 2, or 0 for an unused slot; the weight is the float with those bits cleared. The same encoding as librw's PS2 skin reader.
  • One mesh, one material, colour 0x969696ff, and the material is not textured (no texture section): every character's texture dictionary holds exactly one texture (507 dictionaries), named after the character in 427 of them. The game binds it to the material at each draw (Drawing a human).
  • The skin's inverse bind matrices are the inverses of the HAnim frames' world matrices (checked to float precision for every model).
  • Frames to pose bones: frame 0 is the clump's root, frame 1 carries HAnim id 0 and the hierarchy; node index equals id on the disc, and the pose bone of HAnim id n is n + 2 (Animation), so pose bones 0 and 1 have no frame. Inferred, from the next point.
  • Pose axes are the clump's turned +90° about x, (x, y, z) → (x, −z, y): the bone offset chunk's entries are the frames' translations turned so (bone n + 2 against frame of id n), and of the 24 axis rotations this one gives the smallest mismatch between clip-posed joints and the bind skeleton (0.022 m for Rembrandt's walk, 0.054 m for the next best). In pose space z is up and a character faces +y (the walk's root velocity is +y). Inferred.
  • The parent table differs from the frames in one place: pose bone 3's parent is 1 in Skeleton_InitParents (0x00101120), while its frame's parent is HAnim id 0 (pose bone 2). Inferred (Coney follows the table).
  • The float at +4 of the bone offset chunk (entry 0's y) is 0 in every model.

Movement constants

Confirmed (code) at the readers; values from .data.

Address Value Use
0x005102cc 1/30 s the characters' step (Humans_Update runs at 30 Hz)
0x005102e8 0.95 stick magnitude above which a run is allowed
(code) 0.12 stick dead zone
(code) 24 speed change per second of step (m/s²), so 0.8 m/s per update
0x005101b0-0x005101dc pairs (player, other): 11° / 1.5°, 16° / 2.5°, 18° / 4°, 18° / 6°, 20° / 12°, 24° / 24° in play turn limits per update; .data holds 1.5°-24° in both words, and config_preload2.lua's CfgSetTurnRates(11, 16, 18, 18, 20, 24) sets the player's
0x00510308 / 0x00510304 1 / 0 turn smoothing on (eased)
0x0051030c 0.8 turn step carried over from the last update
0x00510310 2.0 rad in play (CfgTurnRate(true, false, 2.0, 0.8)) heading error at which the turn reaches its full rate

The values "in play" were read in the street save's RAM and match every measured turn (confirmed (runtime), Feel comparison); the setters are confirmed (code) on CfgSetTurnRates.

Behaviour

Creation

HuCreate(name, type, {x, y, z}, headingDegrees, str, playerIndex, gang, flag) (0x00358428 → 0x00233d60), confirmed (code):

  1. Build the rotation about z from the heading (degrees × 0.0174533, half-angle quaternion with the axis at 0x00511740).
  2. Take a free slot (0x00217f08); on failure free it again (0x00217ec8) and return NilHandle (0x006ebd30). Confirmed (code).
  3. Human_Init (0x00218008, confirmed (code)): remap the type to the behaviour class; take the model index from the class record (+0x112, or +0x114 in levels 60-64); load or find the character; snap to the ground: cast a ray from the position plus (0, 0, 1) straight down for 2.5 m through WorldManager_RayCast (Collision) and, on a hit, put the human on it 0.01 above (skipped in game modes 0xb and 0x11).
  4. Name (+0x80); the player argument goes to the hand-over priority +0x1b1 as given; only the value 1 calls Human_MakePlayer (0x00229c40, Players), whose result is ignored (confirmed (code)). Human_Init has already set the player slot +0x1b0 to -1 and added the human to its gang (Gang_AddMember).
  5. Return the handle (+0x2c of the slot) and write the snapped position back into the Lua table.

The fifth argument ("warr_sw" in level99.lua) is not read by 0x00233d60. At runtime Rembrandt was created at (-284.4, 120.4, 0.3) and stood at (-289.03, 120.29, 0.25) once the intro scene ended (confirmed (runtime)).

Loading the files. When the character's resources are already resident (the level's dependency list or the section's pack holds them), the instance is made at once (0x00177b80) and attached (0x00217a98). Otherwise the resource manager's update (0x001897a8) loads them later and attaches them then; the dynamic animations a script asks for (SetDynamicAnimation) go the same way into the slots at +0x3c8. Confirmed (code) for both paths.

Players: making one and giving one back

A player is a human in the game state's player list, confirmed (code) at 0x00419b10 and 0x00419c68: W_GameState + 0x224 (s16) counts the players, +0x228 holds their handles (two at most), and each player's slot number is kept in the human at +0x1b0. Adding a player (0x00419b10) does nothing when two are already listed; with no slot asked for it appends, otherwise it shifts the later players up. Removing one (0x00419c68) sets that human's +0x1b0 to -1, empties the entry and shifts the later players down, rewriting their +0x1b0, so player 2 becomes player 1 when player 1 goes. What the engine calls "the player" (the rings, Warrior commands, the HuChangePlayerGang test) is slot 0, the handle at +0x228.

Human_MakePlayer(human, pad, panel, slot) (0x00229c40; HuCreate passes -1 for all three), confirmed (code):

  1. Pick a pad. A given pad is used when that pad record (Front end) is connected (+0x4c) and has no owner (+0x42 = -1). Otherwise: the pad the front end assigned to the slot this human will take (byte +0x19 of one of the two profiles at 0x00600840 / 0x00600844, one per player slot), else the first of the 8 pad records that is connected and unowned.
  2. No pad while someone is already player 1: give up. When no pad was found and the list's slot 0 holds a human, the function returns 0 having changed nothing: the human stays an AI. With an empty list it goes on without a pad.
  3. Clear every current player's brain enemy list; add the human to the player list (+0x1b0 = its slot).
  4. HUD panel: attach the first free panel of the two (or the one asked for) through HUD_AttachPlayer (HUD); a panel still attached to another human is not free. The panel index goes to +0x380; the game state's per-panel record (+0x168 + panel × 0x5c) is reset.
  5. Pad ownership: the pad record's +0x42 = the player slot; the human's per-player record +0x19 = the pad.
  6. Brain: goals and actions cleared, type 0 (player, AI).
  7. War chief: +0x3ac = 1 unless another listed player is already chief (with W_GameState + 0x158 set, only one of the same gang kind counts); a chief becomes its gang's leader (gang +0x44).
  8. Difficulty scaling: health (record +0x144, +0x146) times a percentage, power maxima reloaded, attack damage times another percentage (bytes +5 and +6 of the record 0x00222b58 returns, confirmed (code); Human_ReleasePlayer divides back).
  9. The war chief's default Warrior command 0 to its gang (WarriorCommand_Dispatch, 0x0041c4e0, confirmed (code), AI), the gang's cached player data (0x00166708), physics body flag 0x400 and a wider body, the human flags of the table above. Returns 1.

Human_MakePlayer does not touch the camera: the follow camera keeps the human it was made with, and the hand-over below puts the new player on the camera target list.

Human_ReleasePlayer(human, stats, releaseGrab) (0x0022a2a8), the reverse, confirmed (code): (with releaseGrab) end a grab between it and another player; free its pad (+0x42 = -1); clear the players' enemy lists; brain type back to its class's (as Human_Init chose it), goals and actions cleared; the per-panel record reset; (with stats) the stats side; links between it and the players cleared (0x00226e60, 0x00226f70, not traced); remove it from the player list (the others shift down); hide and detach its HUD panel, +0x380 = -1; per-player record +0x19 = -1 and +0x1b = 0 (AI-controlled); Gang_AddMember with its own gang; difficulty scaling undone, the AI flags back. The human stays in the world as an AI member of its gang.

HuChangePlayerGang(gang) (Players_ChangeGang, 0x00239b80), confirmed (code):

  1. When player 1 already belongs to gang, return at once.
  2. Every listed player of player 1's gang is released (Human_ReleasePlayer(h, 0, 1)), its pad remembered, and taken off the camera target list (Camera). Their count is the number of players to hand over (at least 1).
  3. A listed player already in gang is released and made a player again with a remembered pad, and put on the camera target list.
  4. For each player still owed: Gang_PickNextPlayer(gang) (0x0022a770, confirmed (code)) takes the gang's member that is not a player with the lowest non-zero +0x1b1, else the first such member (with no member at all, outside level 99 and with +0x158 clear, a non-player human of a kind-0 gang); Human_MakePlayer(h, -1, -1, -1) on it; on success it joins the camera target list.

Gang_PickNextPlayer is what makes +0x1b1 matter: in the Warriors' gang Rembrandt (1) is chosen before Ash (2), and members created with 0 come last.

The level 99 checkpoint 2 hand-over

P2.SetupLesson1 creates a new Warriors gang, a new Rembrandt (HuCreate(..., 1, gang)) and a new Ash (HuCreate(..., 2, gang)), calls HuChangePlayerGang on the new gang, then GangBrFlush and GangDelete on the old Warriors2 gang (gang 0) that still holds the old Rembrandt and Ash. The script order is inferred from the disassembly; each step is confirmed (code) as above:

  1. The new Rembrandt's HuCreate: the old Rembrandt is still player 1 and owns pad 0. With one controller there is no other connected unowned pad, so Human_MakePlayer gives up at step 2: the new Rembrandt is an AI Warrior with priority 1, and nothing about the player changes. (With a second controller in port 2 it would briefly become player 2 on that pad; the next step makes the outcome the same.)
  2. The new Ash (player argument 2): never a player; an AI Warrior with priority 2.
  3. HuChangePlayerGang(new gang): the old Rembrandt (gang 0) is released and taken off the camera targets; the list is now empty; Gang_PickNextPlayer picks the new Rembrandt (priority 1), which becomes player 1 on pad 0 (the front end's pad for slot 0), takes HUD panel 0 (just freed) and is added to the camera targets.
  4. GangBrFlush(0) clears the old pair's goals and actions.
  5. GangDelete(0) destroys the old Rembrandt and the old Ash at once (Destroying a human, AI: deleting a gang).

So the player moves with HuChangePlayerGang, not with HuCreate: an implementation that binds the player on any HuCreate(..., 1, ...) while a player exists diverges here, and one that ignores HuChangePlayerGang leaves the pad on a human that is then deleted.

Destroying a human

Human_Destroy(human, fromGangCleanup) (0x0021c7c8) removes a human at once, inside the call; nothing is deferred to a later update. Confirmed (code); in order:

  1. Its vtable +0x12c (not traced); for a non-player of a kind-0 gang that is down or dead, its entry in a HUD list of eight (HUD +0x10, 0x001a07f0) is removed.
  2. Two effect handles (+0x168, +0x180) are stopped; the object at +0x364 is destroyed (vtable +0x4c).
  3. With fromGangCleanup (0 from GangDelete): its gang's message handlers cleared and the gang's tactic told.
  4. The held object (+0x338) is dropped and then destroyed (vtable +0x4c, as ObjDestroy), so a weapon in the hand does not stay on the ground; the two bone objects +0x348 / +0x34c are destroyed; for a player, the objects its per-panel record holds are destroyed; the object at +0x358 is let go with a 120 s lifetime.
  5. A human that still has its instance is knocked out first (Human_KnockOut) and marked.
  6. The spinning icon (+0x360) is sent message 0x15 and the handle cleared (Human_RemoveOverheadIcon, 0x00227388, confirmed (code)).
  7. Radar: a blip of the human is removed from both radars (HUD +0x15d0 and +0x3f10, HUD_RadarRemoveHandle, 0x001b2b58, confirmed (code), HUD).
  8. A spawner that made it is told (GangSpawner_OnHumanGone); the instance is released (Human_ReleaseInstance, 0x00217dd8, confirmed (code)); its script handlers and its brain are cleared.
  9. A player: the per-panel record is reset, the HUD panel detached (HUD_DetachPlayer, 0x001b22f0, confirmed (code)) and +0x380 = -1; +0x1b1 = 0; its pad freed (+0x42 = -1) and it is removed from the player list (0x00419c68, the others shift down).
  10. The 0x180 record's attachment freed, +0xd4 = 0, the handle freed (the slot can be reused), the physics body released.

It does not take the human off the camera target list (the list holds handles, and a freed one no longer resolves: inferred from 0x00122248), and it does not choose a new player: destroying the only player leaves the list empty. HuDelete is a different path (HuDelete).

Where a level puts the player

No data file holds a player start. The .lev file's 18 chunks (Level loading) and the level record (the record) carry none, and nothing in InitLevel places a player (confirmed (code) for those readers). The level script creates player 1 with HuCreate while InitLevel runs it, before the preload (Level loading); the values are in the Level starts reference list, one entry per checkpoint (inferred from the disassembly of the 29 level scripts that create a player; the list's values are read from the disc).

The checkpoint is W_GameState + 0x33a (16 bits), confirmed (code):

  • the game state's constructor (0x00418588) sets it to 1;
  • SetCheckPoint(n) (0x0037b760 → 0x0041abc0 → 0x0041ce98) stores n and tells the inventory, the stats and the world objects (0x0041e0b8, 0x00422c60, 0x00397e88); scripts call it before MenuLoadLevel to enter a level at a checkpoint, and during a mission to mark progress, so a retry restarts there;
  • 0x0041cef0(gameState, 1) puts it back to 1 without the bookkeeping: on the paths that restart a mission or leave it (the failure menu 0x00155408, 0x00155648, 0x001557f8, the mission-complete mode's Update 0x0015d160, and 0x00160d38, which also selects level index 0, the front end);
  • GetCheckPoint (0x0037b798 → 0x0041abe8) reads it. InitLevel uses it as the section: the pack <level>_<checkpoint>.pak and the intro movie only at 1 (Level loading).

So a level loaded without a SetCheckPoint starts at checkpoint 1, or at whatever the last one left (inferred).

The pattern of a story level's script (inferred from the disassembly; 28 story levels follow it):

  1. The main chunk defines the helpers, the flags (AddFlagsBoxesPaths), the objects, then runs Main.
  2. Main reads GetCheckPoint() into a global (checkpoint, CHAPTER or mState; level84 turns 0 into 1) and indexes a list with it. The list holds either the creator functions themselves (PlayerGang = {AddWarriors1, AddWarriors2, ...}, sometimes a local) or rows {creator, start function, chapter script} (tMission, as in level99, Scripts).
  3. The creator makes the Warriors' gang (GangCreate(0, "Warriors...", 0, 0)) and its humans, player 1 among them: HuCreate(name, type, {x, y, z}, heading, model, 1, gang), the position and heading literal numbers. It returns the table of humans and the gang; Main then sets player = Warriors.<name> (the name differs by checkpoint: level3 plays Rembrandt for checkpoints 1-2 and Snow for 3-5).
  4. preLoadFile(chapter script, start function) loads the checkpoint's own script; when it arrives the game runs it and calls the start function by name (0x00356d00, confirmed (code)). A start function may move the player again: in five checkpoints it, or a function it calls, teleports the player (Teleport or TeleportToFlag, noted in the list).

Teleport(object, {x, y, z}, heading) (0x00385bb8) sets the transform; a heading of −1 keeps the rotation. Its TeleportToFlag(object, flag, heading) sibling (0x00385db0) takes the flag's position and, with −1, the flag's heading (0x00416258), and for a human also calls its vtable slot +0x14c. Confirmed (code). Neither places the object on the ground as HuCreate does (above), but a human not in a scene (+0x280 = −1) is lowered onto whatever a short ray (0.5) straight down hits (0x0023d440; confirmed (code)). A human in a grab, mount or mugging is first let go, its partner playing a reaction clip (Combat).

Interiors are below the street. Starts with z near −195 to −215 (level5 checkpoint 2, level11 1 and 2, level20 1 and 3, the hub ...) are rooms placed about 200 m under the city in the same world (inferred from the values and the hub's clubhouse at z −194.3).

The hub (level95, Scripts): AddWarchief creates the player at the flag fWchiefStart_1 (−188.6, 95, −194.3), heading 222, as the type the chapter script's WarchiefTable names (Cleon, Rembrandt, Ajax, Cochise, Cowboy or Swan by chapter). StartLevel then either opens the quick map (when unlockable (6, 3) is unlocked, or LoadLight is set) or makes the door walk: TeleportToFlag(player, fWchiefStart_<n>) and a walk to fWchiefEnd_<n>, where n = WCLoc, random(1, 5) from the main chunk (1 to 5 inclusive, from the game's table generator), or 5 while unlockable (6, 4) (the tutorial) is still locked, in any chapter. The five start flags: 1 (−188.6, 95, −194.3) 89°; 2 (−188.6, 102.7, −197.5) 89°; 3 (−163.7, 80.7, −197.5) 358°; 4 (−174.4, 80.5, −194.3) 358°; 5 (−185.2, 112.7, −193.7) 182°. Inferred from the disassembly; how flags work, the generator and the order of StartLevel's steps are on World flags.

A Rumble arena (level101-level137): the level script runs doFile("level" .. Level .. "_" .. RumbleInfo[Rumble.gameType] .. "_init"), which adds the mode's flags, among them the list fP1 (player 1's gang) and fP2. AddRumbleGang1 creates P11 with HuCreate("P11", Rumble.gang1[1], FlagPos(fP1[1]), 270, nil, 1, gang, true) and teleports it to fP1[1] with heading −1, so it stands on the first flag facing the flag's heading (inferred from the disassembly). The gang, and so the type, comes from the Rumble menu (GetRumbleModeData); the steps are on World flags.

No player: level100 (the front end), level1 (its script only calls MenuLoadLevel("menu")), and the levels without a .lev file.

The characters' update

The task manager's play tick (0x003a3148 → 0x003a2ea0, called first in mode 1's frame, Level loading) calls Humans_Update (0x00249108) on each 60 Hz tick, once 0x4b0000 ticks (about 16.7 ms) have passed, and runs two ticks when it fell behind. Humans_Update does its work on every second call, so the characters step at 30 Hz with dt = 1/30. In order, confirmed (code), each step behind a debug switch that is on in play (0x005e5350-0x005e5368); the full list is on Tasks:

  1. The litter, ground fog and rain splashes (0x00170c88, 0x00171d38, 0x00184568, Graphics); Pads_Update; the formations; the 60 player records (0x00146078, below).
  2. The gangs, then the brains (Brains_Update, 0x00293b28, confirmed (code), AI), which write an AI human's command into its player record as a pad would.
  3. For every human with an instance, 0x0023bd78 (the instance's animation step, 0x00175610), then 0x00105570.
  4. Per human: a position 1.3 above the human handed to 0x0019c3f0 for humans with flag 0x4000 (an effect or sound, inferred), and checks against the player's gang.
  5. Per human: vtable slot +0x13c (its state update: the locomotion) or a flag when it is idle.
  6. The actions, alternating the order (0 → 59, then 59 → 0) on each update: Human_UpdateActions (0x00254e78, confirmed (code)), which runs the command dispatcher (Player_UpdateActions, 0x0027c120) for player and AI humans alike; a dead or knocked-out human runs 0x00221108, 0x00256f28 and 0x00265f70 instead. An earlier reading of this page called this step the brains.
  7. The cameras' update (0x0011e878) with dt, at least 1/30 (confirmed (code)).

From pad to intent

PlayerRecord_Update (0x00146078), each update, for a record with a pad and control on: flip the buffer; copy the buttons; take the pad record's camera-turned left stick (+0x00, +0x04, Front end), store its angle (atan2, 0x003357a8) and its length clamped to 1. With +0x1f set the angle is π/2 and the length 0. Confirmed (code). The stick is thus already relative to the camera: pushing up moves away from it, which is what the game does at runtime (confirmed (runtime)).

Locomotion

Human_PlayerLocomotion (0x00240e38) for a pad-controlled human; an AI human moves by its brain instead (An AI's locomotion). Confirmed (code) for the steps; the state predicates are named by what they test where known.

  1. Current speed = the length of the velocity (vtable slot +0x94).
  2. Target speed. With the stick above the dead zone (0.12): walk by default; run when the magnitude is above 0.95 (0x00225c10); jog instead of run when the human carries an object of class 4 or 6 (0x00225a50, 0x00224000); sprint when the state flag 0x1000000 is set and the human has stamina (0x00225dc0, record +0x14a ≠ 0). Three state tests override this: one (0x00223ad0) keeps the target at 0, one (0x00227d98) uses the record's walk speed +0x170 unscaled, and two others (0x00228340, or the global 0x0051031c) the base speed. With 0x00510258 set, run and sprint come from an analog button's pressure instead (more than 100 sprints); it is 0 in play. Below the dead zone the target is 0.
  3. Skid (the test at 0x00241300). When the stored gait +0x1a8 is 4 or 5, the current speed is at least the run speed (0x00221670: human +0x3a4 × record +0x178, compared as floats, c.le.S) and the previous update's stick (the per-player record's other buffer) was over 0.95 (0x005102e8), then a stick now under 0.2, or one pointing more than 120° away from the velocity (dot product below -0.5; the dot is worked out only for some camera modes, 0x0011f9b0), zeroes the velocity and sets the state code to 9 (the call at 0x00241530), unless the human is airborne (0x00227f90) or 0x00227f68 holds. Code 9 is what plays the run stop: the idle builder (Human_BuildIdleTasks, 0x0025f770) builds the run stop (0x0025c0e8: slot 33, 417, holding 0x80000, the idle after it, a 0.1 s fade) instead of the idle when the code is 9, and the anim state choice (0x00259578) picks state 0 for code 9. Confirmed (code); the code 9 and its caller confirmed (runtime).
  4. Turn. Target heading = stick angle − π/2; current heading = the facing from the rotation. The error is wrapped to (−π, π]. The limit per update comes from Human_MaxTurn (0x002213d8) through the gait lookup 0x002212d0, which reads the table's player word for a pad-controlled human: in play 20° walking or standing, 18° jogging and running, 16° sprinting (600, 540 and 480 degrees per second); 4° and 6° in two special states (0x00227f68, 0x00227f40), 11° in two others, 24° in a combat stance (Movement constants). With smoothing on, the step is the limit times an ease (1 − cos(π · error / E)) / 2 with E = 2.0 rad in play (full from 2.0 rad), plus 0.8 times the previous step (−0.5 times it when the error changed sign), clamped to [0, limit]. When the error is smaller than the step, the heading snaps to the target. The new heading becomes the rotation (unless +0x3bb locks it) and the velocity's direction. Confirmed (code) and confirmed (runtime): a 90° turn at a run went 16.0°, then 18° per update (the facing reached in 6 updates); at a walk 17.9°, then 20°; in a sprint 14.3°, then 16°; 45° at a run 6.3°, 9.8°, 10.8°, 10.0°, 8.4°, 4.5° (Feel comparison). The .data values (12°, 6°, 4°, 2.5°, 1.5 rad), which an earlier reading of this page gave, are what the scripts replace.
  5. Accelerate. Speeding up adds 0.8 m/s per update (24 m/s²) until the target; slowing down either drops to the target at once or, in some states (0x00223db8), at the same rate.
  6. Velocity = facing × speed, with z = +0x3a0 (the vertical velocity is kept); some states zero it.
  7. Lean (0x00248df0): the heading change times a factor (0.4 × +0x1ac, or 8 × +0x1ac when walking) is clamped to 2°, 3°, 5° or 7° by gait and stored at +0x298; the lean at +0x29c follows it by 0.625 of the difference per update, at most 1°, 1.2°, 1.3° or 1.8° per update. What +0x1ac holds is not traced.

Idle, walk, run. Human_GaitForSpeed (0x00221760) maps a speed to a gait: 5 (sprint) at or above the sprint speed, else 4 (run) at or above the run speed, 3 (jog), 2 (walk), else 0 (idle). Confirmed (code). The gait does not pick a clip: one gait blend covers walk to sprint (Clip selection), and what happens at runtime is below.

Gaits at runtime (PCSX2 2.9.94, level99 checkpoint 1, Rembrandt standing; the left stick held straight up at the magnitude given, by the stick-table method in Driving PCSX2; speed is +0x1ac sampled every 5 ms, the clip is record +0x20). Confirmed (runtime):

Stick magnitude What happens
0.10 nothing (inside the 0.12 dead zone)
0.13, 0.5, 0.94 walk start (413) at a steady 0.76 m/s for about 0.45 s, then walk (408) at 1.63 m/s, gait 2: the walk speed does not depend on how far the stick is pushed
0.96, 1.0 run start (414) for about 0.36 s, the speed following the clip (2.77, 2.49, 2.56, 2.63, 2.84, 3.35, 3.90, 4.54, 5.11, 5.40, 5.61, 5.69 m/s, one value per update), then run (410), gaining 0.8 m/s per update up to 7.80
released from a walk speed 0 at once and idle (388)
released from a sprint (10.245 m/s) run stop (417) for 24 updates (0.8 s), moved by the clip 1.63 m with the facing held, then the idle (Sprint)
released from a run (7.80 m/s) the run stop only when the speed that update is not below the run speed by a rounding error, about one release in ten; otherwise the idle (388) at once, at 0 m/s (The run stop)
reversed (180°) at a run one turn step (18°), then the same skid and run stop, sliding 1.63 m the old way; then the walk or run start toward the stick

So the start clips drive the speed while they play (their root motion, Animation), and the gait clip's speed is the target afterwards. The walk start's "about 0.45 s" is its 0.333 s played at rate 0.75 (0.444 s). The run start's shorter 0.36 s is not explained; it may begin part-way through, as the walk-start-to-run-start swap does (speculative). A jog was not reached from the stick alone (it needs a carried object, see the locomotion steps above).

Per update (the feel pass, slot 1, read every update; confirmed (runtime)): on the update the stick is first seen the start clip begins and the body does not move; the walk start then moves it at a steady 0.762 m/s and the run start at 2.77, 2.49, 2.56, 2.63, 2.84, 3.35, 3.90, 4.54, 5.11, 5.40, 5.61, 5.69 m/s; both last 13 updates, and the gait blend then gains 0.8 m/s per update. The walk start's clip speed from the disc is 0.786 m/s: the body moves at the clip's speed × the body scale (0.97), as does the landing clip 436 (4.230 m/s against the clip's 4.361) and, inferred, every clip that moves the body. The gait speeds (walk, run, sprint) are not scaled.

The first updates in detail (the second feel pass, 2026-10-05, slot 1; speed +0x1ac and the position's change agree to 0.003 m/s; the stored gait +0x1a8 in brackets). Confirmed (runtime):

Stick, straight up Update the stick is seen Then, one value per update
35 % or 60 % walk start 413 begins, 0 m/s (gait 0) 0.762 (1) for 12 updates, then the walk 408 at 1.562 (1), 1.629 (2)
100 % run start 414 begins, 0 m/s (0) 2.773, 2.486, 2.558, 2.629, 2.844 (2); 3.346, 3.895, 4.540, 5.112, 5.399, 5.614, 5.686 (3); then the run 410 at 6.486, 7.286, 7.801 (4)
released after a run run stop 417 begins, 0 m/s (0) 2.244 (2), 4.996, 5.101, 5.229, 5.382, 4.193 (3), 3.190, 2.490, 2.163, 2.124, 2.056, 1.928, 1.740 (2), 1.434, 1.143, 0.886, 0.753, 0.645, 0.552 (1), 0.469, 0.390, 0.296, 0.198 (0); the idle 388 on the 25th

The 35 % and 60 % runs were identical update for update. There is no ramp on the first moving update of any of the three clips: it is the clip's own root speed (times 0.97). A walk released stops at once (the idle on the next update, 0 m/s). The gaits matter to the camera, whose auto-follow runs only at gait 2, 4 or 5 (Camera).

The run stop at a run

Whether a run released plays the run stop is decided by the skid's speed test (Locomotion step 3), and at a steady run that test compares two floats that are equal to within a few units in the last place. Confirmed (runtime), scenario run_stop (slot 1, a straight run released, then a run circling behind the camera released, as run_circle), with hooks on the state-code setter and on the skid test logging the gait, both stick buffers, the run speed and the speed register f28 as raw words:

  • The run speed is 0x40f9a3ad (7.8012300). The speed the locomotion measures at a steady run (the length of the velocity, 0x0023fea8's vtable +0x94) jitters between 0x40f9a3aa and 0x40f9a3ae: of 93 updates at the run in one recording, 10 were at or above the run speed and 83 one to three units below it.
  • On every release seen the gait was 4, the previous stick 1.0 and the stick 0. Where the speed on the release update was below (0x40f9a3ab, 0x40f9a3ac, straight and circling alike, three recordings) no code 9 was set and the idle 388 began on the release update itself at 0 m/s (the skid test's call re-labelled one update later after the recorder fix, Recording a trace), holding 0x10000000 for 5 updates; where it was not (one circling release), the state code went to 9 from 0x00241538, the idle builder set it back to 0 (0x0025fa2c) and the run stop 417 played for 24 updates with 0x80000, at the speeds in the table above.
  • So turning has nothing to do with it: the circling run of run_circle (step 192) and a straight run both go either way. After a sprint (10.245 m/s) the speed is far above the run speed, so a sprint always ends in the run stop; a jog or walk (gait 3 or less) never does.

In the idle that follows a release without the run stop, the stick's last angle and magnitude (+0x5d8, +0x5dc) keep turning the body: while the idle's fade holds 0x10000000, the locomotion turns toward the last stick angle with a magnitude × 0.8 each update (0x002411cc onward), which is the 0.7°, 1.1°, 1.4°, 1.5° seen after run_circle's release.

An AI's locomotion

An AI human has no stick: its goals and actions write the brain's heading +0x110, speed +0x114 (from a gait, Brain_SetMoveGait 0x0028aac0), aim point +0x90 and radius +0x118 (AI, Moving), and its control function, Human_UpdateControl (0x00243848, the default +0x1bc), turns them into a velocity and a rotation each update. For a pad-controlled human the same function only picks the player's control (locomotion, air, fight stance, button tap or wheelchair) and runs it. Confirmed (code) at 0x00243848 unless marked.

The gaits an AI asks for. Human_SpeedForGait (0x0022ae40, jump table 0x0055bec0) returns the human's own clip speeds from its 0x180 record, unscaled by +0x3a4: gait 1 the sneak walk +0x16c, 2 the walk +0x170, 3 the jog +0x174, 4 the run +0x178, 5 the sprint +0x17c (Speed classes; Rembrandt 1.585, 1.629, 4.857, 7.801, 10.245 m/s), 0 and anything else 0. An AI's sprint drains stamina as a player's does (Sprint, Human_UpdateMeters runs for every human), but nothing in this control reads stamina, so an AI keeps sprinting at 0 (inferred: no reader found).

The speed this update. Start from the brain's speed, then, in order:

  1. Stopped (zero velocity, the rotation kept, the lean cleared) while the human is busy (Human_IsBusy, 0x00223cb0, confirmed (code)), its +0x280 is not −1, or it is blocking or ducking (0x00223ad0).
  2. Caps by state: hurt (state 0x10000, Human_IsWounded, 0x00227d98, confirmed (code)) → the record's walk speed +0x170 when asked for more than 0.1; in a fight stance (state 0x3) → the base speed (+0x164 × +0x3a4, the combat walk) when asked for more than 0.1, else 0; carrying an object of kind 4 or 6 and asked for more than the run speed → it drops the object (0x00257f38) unless its type's +0x87 is 6 and +0x5a is 0; otherwise at most 25 m/s. With brain +0x0b (the turn boost, AI) above 0, a human (+0x1b0 = −1) in a fight stance gets anim slot 14 = 380 (the player's combat walk) and its speeds recomputed; at 0 or below, slot 14 goes back to 372.
  3. Speeding up from rest (current speed exactly 0): unless the state code is 3 or 7 or the anim state is 4, the state code becomes 6 (run start) when asked for at least the run speed (8 instead when brain +0x0c is above 0), or 5 when asked for exactly the walk speed; the clip selection plays the run or walk start from those. The speed this update is min(asked, 2.0).
  4. Speeding up while moving: + 8 m/s² × 1/30 (0.267 m/s per update); when that still leaves more than 2 m/s to go, + 32 m/s² (1.067 per update) instead; never past the asked speed. So an AI ramps 0.267 per update for the last 2 m/s and faster before, where a player gains 0.8 (Locomotion step 5).
  5. Slowing down: − 32 m/s² (1.067 per update), not below the asked speed. Except for Diego and Vargas (classes 0x78, 0x77) running or sprinting and asked for 0 with no held flag 0x110c0880: velocity 0 and state code 9, the run stop.

The direction. With human +0x333 (the detail level, 0-4, from the distance to the nearest camera, Human_UpdateLod 0x0023d660) below 2, or any held flag 0x310c0880, the AI moves toward the brain's point +0x90; at detail 2 or more it simply moves along the heading +0x110 at the speed and the rotation is set to that heading at once: far from the camera there is no turn limit and none of the clips below. Close up (confirmed (code)):

  • Turning happens only while the brain asks for a speed above 0 (or the human is hurt): the facing turns toward the heading +0x110 by at most Human_MaxTurn (0x002213d8) per update, at a constant step, no easing (the player's turn eases, Locomotion step 4). For an AI the limit is the table's second word (Movement constants): 12° walking or standing, 6° jogging, 4° running, 2.5° sprinting, 24° in a fight stance, 1.5° grabbing, blocking or ducking, a quarter of 1.5° hurt and of 2.5° with a held flag 0x1000080, and 4° / 6° in the two special states (0x00227f68, 0x00227f40); the gait words are multiplied by brain +0x0b + 1 (divided by 1 − +0x0b when it is negative, 0x002212d0). The turn decides the facing; the velocity is the new facing × the speed, so an AI runs wide arcs (a run turns 120° per second).
    • Which word. Each pair is (player, AI); Human_MaxTurn takes the AI word, the pair's second (+4), for a human with no player slot (+0x1b0 = −1) or whose brain is dead (+0x09). The stance's AI word is 0x005101dc (24° in .data); nothing in the executable stores to it. CfgSetTurnRates (0x0023a7a0, script 0x0035e140) writes only the six player words 0x005101b0, 0x005101b8, ... 0x005101d8 (degrees in [0, 90), × π/180), so its sixth argument (24 in config_preload2.lua) sets the player's stance turn, 0x005101d8, and never an AI's. The two are equal in play only because both are 24. Confirmed (code) at 0x00221520 and 0x0023a964.
    • Wounded first. The hurt test (state 0x10000) comes before the stance test, so a hurt AI in a fight stance turns a quarter of 0x005101b4 (1.5°): 0.375° per update, not 24°. While hurt it also turns with the brain's speed at 0, and never starts a turn on the spot. Confirmed (code) at 0x002213d8, 0x00243848.
  • In a fight stance the velocity is instead along the line to the point (it strafes: the facing follows +0x110, the feet go to +0x90), and record +0xdc gets the direction of the movement relative to the facing, 0 to 2π (0x002726d8), which drives the eight-direction blend (Clip selection). In detail (confirmed (code) at 0x00243848): the speed is the stance walk when the brain's +0x114 is above 0.1 and 0 otherwise (step 2 above), the direction is the unit vector from the human's position to +0x90 (speed 0 when the point is on him), and the turn toward +0x110 runs whenever +0x114 is above 0, so an ask between 0 and 0.1 turns him without moving him. Wounded comes first: a hurt human in a stance gets the walk speed, not the stance walk.

The move request is rebuilt every update (confirmed (code)). Brain_UpdateGoals (0x0028fbb0, every brain, every character step) begins with Brain_StopMove (0x0028ac18): +0x114 = 0 and +0x110 = the human's current facing (from his rotation). It leaves +0x90 and +0x118 alone. The brains run before this control in the same step (Tasks, steps 5 and 8), so the control sees only what a goal or action wrote in this update; nothing a finished goal or action wrote survives into the next update. With nothing written, the AI asks for speed 0 along its own facing: no velocity, no turn, and no turn on the spot (the heading error is 0). A stale +0x90 does nothing then, because the speed is 0. The only writers of +0x110 are the reset, the movement actions (move 0x002fc5c0, move-to-human 0x002fd4e8 and its abort 0x002fd0a8, 0x002fe740, the shuffle 0x002feb48, the turn 0x002fdd08, the step 0x002fe3a8), the route legs (0x0029b848, 0x0029baa8, 0x0029bca0) and a few goals that are not fights (pedestrian reaction, avoid enemies, the ledge thrower, run from the train, the phone, the parlay) and the player's brain (0x003035d8); found by a scan of every store to +0x110.

  • Held flag 0x20000000 (a turn clip playing, below) or any of 0x110c0880, or the state code 5 or 6 (a start clip): no velocity; the clip moves the body.
  • The vertical velocity is kept (+0x3a0), and the lean (0x00248df0) gets the heading change, as for a player.

Turning on the spot (0x0025c240): with a speed of 0 this update, the heading more than 15° off the facing and no held flag, the AI plays a turn clip and turns the rest of the way over the clip's length (Human_TurnToOver, 0x0023cf88: a constant rate on top of the clip's own turn, which is taken as 60° or 120°, inferred from the subtraction). Positive angles turn left. Confirmed (code):

Heading off by Clip (most AI) Clip (brain +0x0b below 0, or move style 4 or 6) In a fight stance
15°-90° left 396 ANIM_FAST_TURN_LEFT slot 8 + 1 (391, slow left) slot 15 + 1
15°-90° right 395 ANIM_FAST_TURN_RIGHT slot 8 (390, slow right) slot 15
over 90° left 398 ANIM_FAST_TURN_QUICK_LEFT slot 8 + 3 (393) slot 15 + 3
over 90° right 397 ANIM_FAST_TURN_QUICK_RIGHT slot 8 + 2 (392) slot 15 + 2

The clip is played by 0x0025cb90: a fade of 0.1 s, the clip, then the idle (slot 0, or slot 11 in a fight stance) looping, holding the given flag (0x20000000 here) while it plays, state code 0. This is the turn (398) seen at runtime before an AI's run-in (AI, Moving).

Arriving with one clip (0x0025c5b8, the global 0x005104e8 = 1): while the brain asks for more than the jog speed, its +0x11c is 0, the human is not down, not hurt and holds no flag, and its point is at least 0.1 m beyond the radius (d = the distance in plan − +0x118), the AI may cover d with a single clip instead of the gait. Confirmed (code):

  • From rest (stored gait +0x1a8 0): for an asked gait below 4 a step, slot 1 + (0 ahead within 45°, 1 behind beyond 135°, −1 right, −2 left: 401, 402, 400, 399); for 4 or more a dash, slot 2 + (0, 1, 3 right, 2 left: 403, 404, 406, 405); in a fight stance slots 12 and 13 instead of 1 and 2.
  • At a run or sprint (gait 4 or 5) with the point within 45° ahead: the run stop, slot 33 (417).
  • With L the clip's root displacement: the clip plays when L ≥ d, or from rest when L × 1.25 ≥ d. When L < d + the radius it plays as it is; otherwise the body is turned so the clip's displacement points at the point and moved over the clip's time so it ends there (Human_MoveToOver). The clip holds 0x80000, and the control sets no velocity that update.

So an AI running at its point stops with the run stop once the point is closer than the run stop's slide (about 1.6 m for Rembrandt), and one starting near its point takes a step or dash. Whether a given goal's move reaches this test is the move action's business (AI, The move action).

Other effects: when the brain asks for any gait above 0 (Brain_UpdateGait, 0x0028ab08, tested in Human_UpdateControl; confirmed (code)), the human lets go of carried props (Human_ReleaseCarriedProps, 0x0024ce40) and, after a state 18 or with held flag 0x20000, its animation is rebuilt (0x0025f450); a human in a scene state also lets go of its props.

Step control

The TakeStep and GiveWay actions (AI code) move an AI one step by swapping its control function for the step control (Human_StepControl, 0x00243420) for a single update. Confirmed (code) at the addresses cited.

Starting a step. TakeStepAction_Start (0x002fe3a8) writes the action's one argument, a heading in radians, into the brain's heading +0x110, then calls Human_EnterStepControl (0x002432b0). The step has no distance argument: the clip decides how far the body goes. Human_EnterStepControl does nothing when either of these holds:

  • the human has any of state bits 0x180f3ff0. That is 0x10-0x2000: grabbed or grabbing, mugging or mugged, the tackle and mount, and a paired power move (Combat: State flags). It is also 0x10000-0x80000 (0x10000 is hurt) and 0x8000000 and 0x10000000, whose meanings are not traced;
  • the step control is already installed.

Otherwise it saves the current control (Human_SaveControl: +0x1bc copied to +0x1c4) and installs the step control (the 8-byte member-function pointer at +0x1bc = 0x00243420ffff0000: +0x1be = −1 and the function 0x00243420 at +0x1c0), confirmed (code).

One update of the step control, for an AI. The per-player record's +0x1b is 0 for an AI.

  1. No move from the control. The two outputs are the zero vector (0x005116c0) and the human's current rotation (transform table 0x00714b10). Any displacement comes from the clip's root motion; inferred from the one-clip arrival, which uses the same clips and measures their root displacement.
  2. Wait while not free. The control returns at once, still installed, while any of these holds:
  3. Human_IsBusy: state 0x79b9e1e0f30, airborne, state 0x100000000, the per-player +0x1e, or a held flag of 0xaeebf7ff;
  4. grabbing;
  5. +0x280 is not −1;
  6. wounded;
  7. state 0xe0000;
  8. any held flag.

The step then starts on the first free update. 3. Pick the clip. Let d be the brain's heading +0x110 minus the facing, wrapped to −π..π. The turn boost is brain +0x0b (AI). The facing to end on is the heading, offset so that the clip's own direction points along the heading:

d End facing Fight stance Boost 0 or below Boost above 0
within ±22.5° (π/8) heading 366 ANIM_FIGHT_MOVEMENT_STEP_FORWARD 401 ANIM_MOVEMENT_STEP_FORWARD 403 ANIM_MOVEMENT_DASH_FORWARD
112.5° (5π/8) or more either way heading − π 367 ..._STEP_BACKWARD 402 ANIM_MOVEMENT_STEP_BACKWARD 404 ANIM_MOVEMENT_DASH_BACKWARD
22.5° to 112.5°, positive heading − π/2 365 ..._STEP_RIGHT 400 ANIM_MOVEMENT_STEP_RIGHT 406 ANIM_MOVEMENT_DASH_RIGHT
22.5° to 112.5°, negative heading + π/2 364 ..._STEP_LEFT 399 ANIM_MOVEMENT_STEP_LEFT 405 ANIM_MOVEMENT_DASH_LEFT

In a fight stance the boost is ignored. The clip ids are the anim ids.

Which way is positive. Both angles are the game's headings (Quat_Heading, Maths): a heading h faces (sin h, cos h) in the ground plane, so it grows from +y toward +x, clockwise seen from above (+z up). A positive d therefore means the heading lies to the human's right: from the facing f, his right (forward × up) is (cos f, −sin f), the heading f + π/2. Confirmed (code): Quat_AxisY (0x003363b0) gives the forward (−sin θ, cos θ) for a turn θ about +z, Vec_Heading (0x00335d98) is atan2(x, y), so the heading is −θ. The clips agree: the generic gen_step_right clip's root moves along body +x (root velocity +0.98 m/s on x at its first key; gen_step_left −0.86; gen_step_forward +1.23 on y; read from the disc as numbers), and body +x turned by the end facing h − π/2 points along h. So the human always steps toward the heading: STEP_RIGHT with a positive d, ending side-on with his right toward it; with d = +90° the end facing is his current one and he does not turn. Runtime was not needed: the code and the clip data leave no other reading. A port whose headings grow anticlockwise (the turn θ, minus the game's heading) sees every sign flipped: there a negative d picks STEP_RIGHT, and the end facings are heading + π/2 for the right step and heading − π/2 for the left. 4. Play it. Human_PlayOneShotClip (0x0025cb90) plays the clip: - a blend-out of the current pose over 0.1 s, then the clip chained in over 0.2 s; - after the clip, the idle loops (slot 0, or slot 11 in a fight stance); - while the clip plays it holds held flag 0x80000, with state code 0 and the push sphere off.

The clip-end callback (0x0025c5b0) is an empty function (jr ra, confirmed (code)). 5. Turn during the clip. The human is not turned first. Human_TurnToOver (0x0023cf88, called from Human_StepControl; confirmed (code)) turns it to the end facing at a constant rate over half the clip's play time (Anim_GetPlayTime × 0.5), while the clip plays. The angle is negated before the call, the same convention as turning on the spot: Human_TurnToOver takes the turn θ about +z (anticlockwise seen from above), which is minus the heading. A turn under 0.01 rad is skipped. 6. Leave. Human_LeaveStepControl (0x00243360, confirmed (code)) runs in the same update. It restores the saved control (Human_RestoreControl), then sets +0x1bc to Human_UpdateControl (0x00243848), or to Human_MoveAttached (0x00244e78) while grabbed or being mugged. So the step control is installed for a single update, unless step 2 held it.

For a pad player (+0x1b set) the step control restores the saved control. It then picks the player's control and runs it in the same update: air when turn-limited (state 0x400000000), the fight stance with a target, button tap, the wheelchair, or else PlayerLocomotion (0x00240e38). Confirmed (code).

How the action ends.

  • Update (TakeStepAction_Update, 0x002fe428, confirmed (code)) returns running (0) while held flags 0x20080000 (Human_HasHeld20080000, 0x00228448: 0x80000 the step clip, 0x20000000 a turn clip) are set, or while the step control is still installed. Otherwise it returns done (2). The step lasts as long as its clip.
  • Abort (TakeStepAction_Abort, 0x002fe3d8, confirmed (code)) always calls Human_LeaveStepControl. With argument 0 it agrees; with a non-zero argument it refuses while 0x20080000 is held.

GiveWay. GiveWayAction_Start (0x002fe5d8) runs these steps in order (confirmed (code)):

  1. The AI looks at the other human for 2000 ms (Brain_LookAtTarget, weight 0.5).
  2. With the action's boost flag (+0x14), it saves the turn boost +0x0b and raises it by 1. A boost of 0 therefore becomes 1, which selects the dash clips.
  3. It runs TakeStepAction_Start.

Abort (GiveWayAction_Abort, 0x002fe658) restores the saved boost once TakeStepAction_Abort agrees. It also runs when the step ends normally: a finished action is popped through Action_AbortAndDestroy, which calls Abort with argument 0 (always agreed) for any started action (AI: Actions). So the boost goes back however the GiveWay ends; nothing else restores it. The destroy (GiveWayAction_Destroy, 0x002fe6a8) then clears brain +0xcc bit 1. Confirmed (code). Brain_GiveWayTo (0x00289ed0) sets the boost flag when the mover is a pad player (+0x1b0 ≠ −1) whose stored gait +0x1a8 is 3 (jog) or more, so an AI dashes out of a running player's way and steps out of a walker's.

Who may give way (Brain_GiveWayTo, before its free-sector search, which is in AI: Giving way). All of these must hold:

  • the stander's brain has a task (+0x04 ≠ 0) or its +0x09 is set;
  • neither human is a threat to the other: Human_IsThreatTo (0x00222a48, confirmed (code)) is false both ways. It is Brain_IsThreat on the two brains: the gangs are enemies (Gang_IsEnemyOf on brain +0x20c), or both are pad players, with a Warrior's (type 3) +0x2e5 mode able to force it either way. It tests only; nothing is changed;
  • the stander is idle under its control: Human_IsIdleUnderControl (0x00225390, confirmed (code)). Its control is Human_UpdateControl or the step control, it has no state bit of 0x7bf9e1f3ff0, and it has no held flag at all.

Then a free sector gives a GiveWay action on the sector's heading (the stander's facing + sector × 45°), started after a random 0-124 ms.

Wheelchair control

HuSetWheelchairControl (0x00234188), confirmed (code):

  • On: look-behind switch 11 (0x0050b23c) = 0 (Camera); unless the human already runs it: state flag 0x80000000000, the current control saved (0x00221038: +0x1bc copied to +0x1c4), the control set to wheelchairControl (0x002427e8, 0x00244620), every player command off for the human, and commands 46 and 47 added (kind 7, pad bits 0x4 L1 and 0x8 R1).
  • Off: switch 11 = 1, the flag cleared; if the human runs wheelchairControl, the saved control comes back (0x00221080), commands 46 and 47 are removed and all commands are on again.

wheelchairControl (0x002427e8), each update. A human whose per-player record +0x1b is 0 (inferred: not pad-driven) or without the flag goes back to its normal control and runs that instead, so the Rumble CPU drives its path with its usual locomotion. Otherwise it reads only L1 (0x4), R1 (0x8) and cross (0x40) from the pad; the sticks are not read.

  • speed = the length of the velocity; max = the sprint speed (0x002216c0: human +0x3a4 × record +0x17c).
  • L1 and R1: speed + 0.5, at most max, no turn. From a standstill (and anim state not 4) it instead sets the record's state code (+0x14) to 5, and while the code is 5 or 6 the control asks for no velocity (inferred: a start clip plays first).
  • L1 alone: speed − 0.04 (not below 0) and a turn of +(0.03 + 0.05 × (1 − speed / max)) rad; R1 alone: the same turn negated. So one wheel turns 0.08 rad an update at a standstill and 0.03 at top speed. Positive turns raise the heading (counter-clockwise from above), so L1 (the right wheel) turns left and R1 right.
  • Neither: speed − 0.04 (not below 0). Cross (the brake) then takes 0.5 more off, not below 0, whatever the shoulders do; with neither shoulder held it replaces the 0.04 decay.
  • The new heading is the old one plus the turn (written as a rotation about z); the velocity is speed along it, zero while any of state flags 0x110c0880 is set or the state code is 5 or 6. Above 4.5 the human's animation layer gets flag 2 and event groups 3, 6, 18, 19, 24, 25, 29, 30, 32 and 33 (Human_StrikeAllOn, 0x00248170, confirmed (code)); at or below 4.5 they are cleared (0x00248270). The pending turn fields +0x298 / +0x29c are zeroed.

The constants, confirmed (code) in Human_MoveWheelchair, are at 0x005104d4 (0.5 push), 0x005104d8 (0.04 decay), 0x005104dc (0.5 brake), 0x005104e0 (0.03) and 0x005104e4 (0.08). Changes are per update; whether the update is 1/30 s or 1/60 s here is not traced.

Buttons

The pad's buttons become command ids through tables of 12-byte entries {u16 mask, u32 command, u16 buttons, u16 extra} that AddCommand fills. Each update 0x00147940 matches them and stores the command in the per-player record's +0x20, or in the pending +0x24 when the entry's mask is 0xfe (0xff enables it for pad 0). The buttons are the pad word's bits (Pad record). The nine tables, what each trigger means, the order in which they are matched and every command they make are on Combat, Commands (confirmed (code) and (runtime)). An earlier reading here took square (0x80) for d-pad left and cross (0x40) for down: the combinations are L2 + square (0x21), L2 + cross (0x20), cross + square (0x22) and circle + triangle (0x24), and the d-pad combinations 0x29-0x2c and L3's 9 need select held as well.

Traversal uses two buttons: triangle pressed (command 10) starts a climb, a context action or a jump (Jumping, Climbing), and L2 sprints. The sprint reads the button itself (0x00147f98(record, 1), "is the button of mask 1 held") rather than command 5. Confirmed (code) at 0x0027c120 and 0x0027ce90.

Sprint and stamina

Sprint is held, not toggled. Every update Player_UpdateSprint (0x0027ce90, called from 0x0027d5a0, which Player_UpdateActions calls) first clears state flag 0x1000000, then sets it again (and calls 0x00230140, and clears state flags 0x8008) only when all of these hold. Confirmed (code):

  1. L2 is held;
  2. stamina (record +0x14a) is not 0;
  3. record +0x08 bit 0x10 is clear.

So the sprint lasts exactly as long as L2 is held and stamina lasts: letting go of L2 ends it on the next update, and nothing latches it. It also ends when stamina reaches 0 (below) and when Player_UpdateActions takes its block branch (0x0027c6b0): R1 held in a fight, or L1 released or L1 + R1 while already blocking (Combat, Dispatcher), which clears the flag and sets state flags 0x8001. At runtime (level99 and a street, stick 1.0 straight up and L2 held through patched pad input, Driving PCSX2) the flag was set every update, the command was 5, and the speed rose by 0.8 m/s per update from 7.80 to 10.245 m/s (gait 5). Confirmed (runtime).

The stick still decides. The flag only asks for a sprint: the locomotion's sprint test (0x00225dc0) also needs the stick above 0.95 and stamina, as for a run (Locomotion). With 0x00510258 set (CfgPlayerRunButton), L2's pressure decides instead (pressure byte 10 above 100 sprints, otherwise a run); it is 0 in play. Confirmed (code).

Stamina is the s16 at record +0x14a. Its maximum is Human_StaminaMax (Power classes): 135 for Rembrandt (confirmed (runtime)). Confirmed (code) unless marked:

  • Drain (0x002562d0, called from the brain 0x00254e78): while the gait stored with the velocity (+0x1a8) is 5 and record +0x08 is 0 (0x00223a98), stamina loses 20 per second of game time (0x005101f4, CfgBurnRates rate 5; 0 when 0x005102a8 is set, which it is not in play), with the fraction carried at +0x158 and the time at +0x154. When it reaches 0 or below it is set to 0 and the sprint flag is cleared. Gait 5 is the speed nearest the sprint speed, above 9.02 m/s for Rembrandt, so the drain starts on the third update of the speed-up.
  • Refill (0x00256a60, every update, from Human_UpdateActions; confirmed (code)): stamina gains the power class's +0x2e, 40 per second for Rembrandt, up to the maximum. It gains nothing (and the time is not carried over) while any of these holds: gait 5 (0x00223a98); state flags 0x1c18003ff0 (the airborne bits among them); a jump or fall (0x00227f90, flags 0x1c00000000); gait 4 (run) with L2 held (0x00223a60 and the button); record +0x08 flags 0x41a420. Human flag 0x4000000 fills stamina and the second meter every update. In three states (0x00223b98, 0x00223bc0, 0x00223b70) the function returns before taking the time, so the time spent in them is refilled at once afterwards.
  • No delay and no threshold: the refill starts on the first update the blocks are gone, and the sprint test is only "not 0", so one point of stamina sprints again.

At runtime (the street, Rembrandt, stamina 135 of 135; stick and L2 through patched pad input; stamina, speed and flags read every update). Confirmed (runtime):

  • From a standstill with stick 1.0 and L2 held, stamina still refilled through the run start (gait 2-3), stood still at gait 4 (the "run with L2" block), and fell by 1 every 1.5 updates (20 per second) from the update the speed reached 9.686 m/s (gait 5, the third update of the speed-up from 6.486).
  • When it reached 0 the sprint flag cleared and the speed dropped from 10.245 to 7.801 m/s in one update; with L2 still held for 1.5 s more, stamina stayed at 0.
  • With L2 let go and the stick still at 1.0 (a run), stamina refilled at 40 per second (0 to 39 in about 1 s); L2 pressed again sprinted at once.
  • Standing, it refilled by 4 every 3 updates (40 per second) to 135.
  • Letting go of the stick in a sprint played the run stop (417) for about 0.8 s with record +0x08 = 0x80000, the body moved by the clip (about 1.6 m) while stamina refilled, then the idle: the skid of Locomotion step 3.
  • Stamina also drains in a jump from a run (135 to 132): the gait is taken from the whole velocity, and the jump's vertical speed puts it above 9.02 m/s (Jumping).

What a player sees, from the code and the runs above:

Stick L2 Result
0.5 or 0.8 held walk at 1.63 m/s; the flag is set but there is no sprint and no drain; stamina refills (inferred)
1.0, or a full diagonal held run, then sprint at 10.245 m/s after 4 updates; stamina drains from the third, 135 lasts 6.75 s
1.0 released run at 7.80 m/s; stamina refills at 40 per second, 3.4 s from empty to full
1.0 held at 0 stamina run at 7.80 m/s, and stamina stays at 0 until L2 is let go

In an input script: stick left 0 100 and press l2 to sprint, release l2 to refill.

Measured (PCSX2 2.9.94, the stick held fully forward from a standstill by the W key, magnitude 1.0, positions read over PINE): 4.10 m after a 0.75 s hold, 10.08 m after 1.5 s: 5.98 m in the second 0.75 s, 8.0 m/s, close to Rembrandt's run speed of 7.80 m/s (confirmed (runtime); the hold times are those of the key presses, so about ±1 frame).

Clip selection

Each update the human's animation controller Human_ChooseAnimState (0x00259578, called from the characters' update at 0x00255510 and 0x00256c34) picks an anim state and, when it differs from the one in record +0x18 (or human flag 0x20000000 forces it), calls that state's builder from the table at 0x005106e0 (one function per state; most entries are an empty stub 0x0025f4c8). The builders make animation tasks and change animation by "fade over d, new task at the bottom" (Task stack). Confirmed (code) at the cited addresses unless marked.

Choosing the state (the plain locomotion case; grabs, combat, carried objects and scripted moves test their own flags first and are not described here), confirmed (code) with the builders read from the table at 0x005106e0:

State When Builder
0, idle speed below a quarter of the speed 0x00221580 returns 0x0025f770
4, move speed at or above that, or record +0x14 is 5, 6 or 8 0x0025f4d0
11 a combat stance (0x00228340) at speed 0.01 or less 0x0025fa48
14 a combat stance while moving 0x0025f4d0
21, 24 human flag 0x8000: 24 when the pending turn +0x5e4 exceeds Human_MaxTurn, else 21 (turns in place, inferred) 0x0025fc30, 0x0025fc70

Move (state 4). 0x0025f4d0 calls Human_BuildMoveTasks (0x0025b200) with a fade time of 1/15 s (1/6 s when record +0x14 is 18 or human flag 0x40000000 is set), which builds one of:

  • From standing (the top task is not a gait blend, task flag 0x80 clear): a gait blend of slots 4, 5, 6, 7, 7 (walk, jog, run, sprint, sprint) at value 0, flags 0x2c1; then a clip-then-next task (type 3) that plays slot 10, the walk start (413), with a blend time of 0, and hands over to the gait blend. The fade before it has a duration of 0: the start clip replaces the idle at once. Human flag 0x10000000 is set while the start clip plays (it is what stops the locomotion setting a velocity, Root motion).
  • Run start (0x0025b9f8, confirmed (code) in Human_BuildMoveTasks: outside a shadow, when the stick asks for a run and record +0x14 is 6, 7 or 8, or for a jog with state flag 0x1000000, Human_WantsJog being what tests a carried object of class 4 or 6): the same, but the gait blend starts at 2 (run) and the start clip is slot 10's id + 1 (414, run start).
  • Already moving (the top task is a gait blend): a fade of 0.1333 s and a new gait blend that starts at the old one's value (0x0025ff50 rounds it down to 0, 1, 2 or 3; confirmed (code)) and the old one's normalised time, so the cycle carries on.
  • Other cases: a looping single clip of slot 14 (combat walk) when the global 0x0051031c is set (for a player, in 0x0025f4d0; confirmed (code)); a four-clip task of slot 0 and slot 4 under 0x00227d98; a two-clip mix of 633 STEALTH_WALK and 636 STEALTH_READY_WALK while stalking a target (Human_IsStalkingTarget, 0x00228188, Combat moves).

Walk start to run start. While the walk start plays (flag 0x10000000), if the stick asks for a run or sprint (Human_WantsRun, 0x00225c10; Human_WantsSprint, 0x00225dc0) above the magnitude at 0x005102e8 (0.95), and less than half of the clip has played, the controller swaps it for the run start: a fade of min(0.1333 s, the clip's duration), a gait blend at 2, and the run start begun at the walk start's normalised time (0x00259578, confirmed (code)).

Gait value from the speed. In states 4 and 14, every update, 0x0025eee0 sets the top gait blend's target to Gait_BlendForSpeed (0x0025ec28), a piecewise-linear map through the speed getters:

speed > run          → 2 + (speed − run) / (sprint − run)
jog < speed ≤ run    → 1 + (speed − jog) / (run − jog)
walk < speed ≤ jog   → (speed − walk) / (jog − walk)
otherwise            → 0                                  (clamped to 0-3)

So the walk clip plays alone up to the walk speed, the blend reaches the run clip at the run speed and the sprint at the sprint speed; the fifth slot (sprint again) is never more than a neighbour. The blend's value then eases toward the target at 10 units per second. When the top task is the eight-direction blend (type 13), the target is instead record +0xdc × 4/π (a direction, inferred); for the four-clip task, speed / walk speed clamped to 0-1.

Idle (state 0). Human_BuildIdleTasks (0x0025f770) calls 0x0025f1b8 with slot 0 (388) as a looping clip with no task flags, after a fade of 0.15 s; if a start clip is still playing (flag 0x10000000) the fade is 1/15 s when less than 0.1333 s of it has played and 0.2 s otherwise. Some ids replace slot 0 in special cases (355, 357, 394, 634). With the state code 9 (the skid) it builds the run stop instead (0x0025c0e8, slot 33, 417); otherwise releasing the stick fades straight to the idle, which matches the runtime samples below. This corrects the earlier reading that slot 33 is not used.

At runtime (PCSX2 2.9.94, level99 checkpoint 1, Rembrandt; the task stack read from the instance every 50 ms). Confirmed (runtime):

  • Standing: one looping task, idle 388, rate 0.75, no flags.
  • Stick 0.5 straight up: a fade of 0 s and a type-3 task playing the walk start (413, 0.333 s) at rate 0.75 with human flag 0x10000000; at its end a gait blend (flags 0x2c1, rate 1.0, speed 10) with target and value 0, the walk clip leading and the jog clip muted.
  • Stick 1.0: the run start (414) the same way, then the gait blend at 2. The first update after the start clip ran at 6.49 m/s, so the target was 1.553 and the value fell to 1.825 (jog and run mixed) before going back to 2.0 at 7.80 m/s: the target follows the speed every update.

Animation callbacks (AddAnimCallback)

Scripts register Lua functions to run when a human starts an animation (AddAnimCallback, AddAllAnimCallback, DelAnimCallback). Confirmed (code) at the addresses given:

  • The table (0x006b6710): 16 slots of 16 bytes, {human handle, anim id, all-humans flag, interned Lua name}. AddAnimCallback (0x0023a9f8) takes the first slot whose handle no longer resolves; AddAllAnimCallback (0x0023aab0) the first whose handle does not resolve and whose flag is 0, and sets the flag. A full table returns nil. AddAnimCallback does not test the flag, so it can take (overwrite) an all-humans slot, whose handle never resolves. InitLevel (0x0015fe90) empties every slot (0x0023a9b8); an entry of a deleted human becomes free by itself.
  • When it fires: CharacterInstance_GetAnim(id) (0x00175080), called with its third argument 0, runs the dispatch (AnimCallback_Dispatch, 0x0023ac50) for the instance's human (instance +0x2b8) when the id resolves to a clip. The animation-task code calls it that way each time it takes a clip for an id: every task constructor (a clip started, 0x00105678, 0x00105990, 0x00106140, ..., the gait blend 0x0010a310) and the blend tasks' advance when they move to another clip (0x0010a5b8, 0x00109588). So the callback fires when the human starts playing that anim id, not at the clip's end, and again every time it is started (inferred for the advance cases: they re-resolve when the blend crosses to a new clip). Lookups for other uses (0x00221bf0, third argument 1) do not fire it.
  • The match: slots in order; a slot matches when its anim id equals the id and either its all-humans flag is set or its handle resolves to this human. Only the first match fires; the dispatch then returns.
  • The call: synchronous, inside the animation code: the name is looked up (script slot +0x4c, Scripting), then called with two arguments, the human's handle and the anim id (slots +0x5c and +0x6c, call +0x8c with 2).
  • Not one-shot: the slot stays until DelAnimCallback(human, anim) (0x0023ab80; the first slot whose id matches and whose flag is set or whose handle is the human's) or the next InitLevel.
  • A paired task (0x00108450, 0x00108a78) looks the id up in the other human's instance, so the dispatch runs for that human. Confirmed (runtime): at a strong grapple's connect the victim's 658, started by PairedTask_Init (0x00108a78, caller 0x00108af4), was dispatched for the player (the grabber, whose set holds 658).
  • A follow-on task fires when it is built, not when it starts playing. At a grab's connect, Grab_Connect (Combat) builds the connecting clip and, under it, the hold's four-clip mix (type 11, AnimTaskFourMix_Construct, 0x00106f50) on both stacks in the same update; the four-mix's constructor takes its clips (82 and 86 for the grabber, 83 and 87 for the victim) and so fires the callbacks of the hold ids at the connect, the length of the connecting clip before the hold plays. Confirmed (runtime), PCSX2 2.9.94, level99 checkpoint 1 (hooks anim-dispatch and anim-callback-match, the queue at runtime): for each grab the dispatch of 82 for the player (from 0x00106fe0) and of 83 for the victim came in the tick the connecting clip started (657 from AnimTaskChained_Construct, 0x00105990); in the strong grapple the hold played and the tutorial callback received 82 34 updates later, and no second dispatch of 82 came when the hold began. So level99's PlayerState (registered on the player's 82 and 84) runs at the connect, and lesson 5's P1.Power (the hit scored with 82, Strong grapple) 34 updates after it, never in the same update. A plain grab fires 82 at its connect the same way (lessons 2, 6 and 8).
  • Coney's implementation (ScriptedBrains::runAnimCallbacks): the starts are gathered over the characters' step and the callbacks called after it. A human that starts the same id more than once in one step gets one call (Coney's reading). Coney hands a chain over to its loop in every layer, the fading ones too, so two attack chains ending in the fight idle 358 started it twice in one update. level99's PlayerState then ran twice: each time HUDSetTutorialText(nil) and a hint, and the second nil found nothing showing yet, so one hint stayed queued per double start. The box backed up behind them, and the Targeting and Light Combos hints never showed (Hints). A grab's hold ids (82 / 83, 84 / 85 from the rear) fire at the connect, as above: Fighter::connect reports the start of the hold its chain and the victim's end in (AnimTaskStack::announceFollowOn), and the hold does not report again when it begins, so PlayerState's grab hint and P1.Power's TT_24d come the connecting clip's length apart. Coney's reading: the four-clip mix's second clips (86 / 87) are not reported, since Coney's hold plays the one clip; the paired reaction (658 for the strong grapple) is still dispatched for the victim, not for the grabber as above.
  • Coney's order in a step (inferred from the original's frame, A frame of play): the animation callbacks run before the tutorial callback, since the original calls that one when the victim applies the damage, with the id the attacker has already started; then the hint box steps, once a frame, where the original's HUD_Update stands; then the scheduled calls. A text set on a free box shows within the call that set it (The queue at runtime), so texts set by a callback and a scheduled call in one step never back up (before, from level99's lesson 6 on, the box showed each grab hint TT_19* one text late, in place of the lesson's: user checklist item 33b).

Moving, standing on the ground and falling

The locomotion above only sets a velocity. Moving the human, keeping it on the ground and making it fall happen in the human's state update (vtable slot +0x13c, 0x0023fea8) and its move step (0x0023d8c8), with the physics world (0x00597198, Physics/) doing the sweep against walls. Confirmed (code) unless marked.

Where the transform lives. The authoritative position and rotation of every task-manager object are in a table at 0x00714b00, 32 bytes per object (position vec4, then rotation quat), indexed by the object's handle index (+0x92). SetPosition (0x0021b0b8) writes the table; the human copies it into +0x10 / +0x20 at the start of each update (vtable +0xac, 0x004ed828). The velocity is at +0x30 (vec4), read through 0x003a1f00 (zero while flag 0x600 is set in +0x54); writing it (vtable +0x74, 0x0023cf00) also stores its length at +0x1ac and the gait for that speed (0x0022aeb0) at +0x1a8. So +0x1ac (used by the lean) is the current speed.

Airborne flag. Bit 0x4000000 of the object flags at +0x54 means "in the air". 0x003a2158 sets it (and clears 0x2000000, "on the ground"); 0x003a21c0 does the reverse. Confirmed (code).

One update, in order (the parts that move the body; the human's other duties are left out):

  1. Copy the transform from the table; run the current state's function (for the player, the locomotion, above), which sets the velocity.
  2. Speed sanity check: a velocity longer than 50 × the human's scale (+0x65c, 1.0 normally; Human_GetScale, 0x0021d020; confirmed (code)) is zeroed.
  3. Gravity, only while airborne: from the second airborne update on (the counter +0x384 counts airborne updates), vz -= 15.68 × dt (0.5227 m/s per 1/30 s update; 15.68 m/s² is 1.6 g), clamped at −50 m/s. The result is written back with the velocity. On the ground +0x384 is reset to 0.
  4. Fell out of the world: if the position is more than 20 m below the collision mesh's lowest vertex (mesh header +0x98, Collision), the human is flagged dead (0x200000000), its velocity zeroed, and for a player in a mission whose game-state flags +0x150 have bit 1, W_GameState + 0x14c is set to 1 and +0x152 to 2 (a mission failure, Level loading).
  5. Stuck in the air: after 60 airborne updates, if the physics body's "could not move" counter (body +0x70) is also above 59, the human is put back at its last ground position (+0x390) and landed (Human_Land, 0x0023e090). Confirmed (code).
  6. Move (Human_Move, 0x0023d8c8, below; confirmed (code)).

The move. With velocity v (and an external push +0x2f0 added, which knock-backs use):

  • A human without a physics body (+0x1a0 = 0), riding something (+0x280 ≠ −1) or in state 0x40 simply moves: position += (v + push) × dt.
  • Otherwise, on the ground, v.z is set to 0 first: walking never climbs by velocity, only by the ground snap below. On a slope (ground normal z, +0x238, below 0.95) and outside some states (0x00227f68; confirmed (code)), the velocity is scaled by clamp(0.6 + 0.3 × (n.z − 0.5), 0.5, 1.0): 0.735 just below the threshold, 0.71 on a 30° slope (n.z = 0.87), 0.5 from n.z ≤ 0.17. (The code also computes the facing just before, but the scale does not depend on it, so it slows uphill and downhill alike; and there is a step from 1.0 to 0.735 at n.z = 0.95.)
  • The physics world then sweeps the body (PhysicsBody_Sweep, 0x0033e278(dt, world, body, &v, &out), confirmed (code)): the body's pending push-out (body +0x50, divided by dt) is added to the displacement v × dt, which is swept up to three times, sliding along what it hits. If it is still blocked after three passes, the body stays where it is, its horizontal velocity is zeroed and its "could not move" counter (+0x70) goes up; otherwise the counter is reset. Walls come from the level's collision mesh through the body's shape: a sphere swept along the move, below (Walls and steps).
  • Ground snap, on the ground only (and not in game modes 8, 0xb or 0x11, 0x00221950), 0x0023eab8: cast a ray straight down from 1.0 m above the feet, 1.5 m long (the 1.0 is vtable +0x5c, 0x004ed818, a constant).
    • Hit: put the feet exactly on the hit point (no gap), whatever the hit triangle's normal: the snap has no floor test (Slopes), remember it as the last ground position (+0x390 before the snap, +0x240 after), store the ground normal at +0x230 (its z at +0x238, used by the slope rule) and the material at +0x1d8. The triangle's flag bits 4 and 5 are passed on (bit 4 to a per-player "under cover" state, 0x0028ef00; bit 5 to 0x002195e0; meanings inferred from what the callees touch).
    • Miss (nothing within 0.5 m below the feet): the human starts to fall through vtable +0x154 (0x0023dc58) unless it is in state 0x800. So a step or kerb up to 1.0 m high is climbed in one update when the sweep lets the body over it, and a drop of up to 0.5 m is followed without falling; anything deeper is a fall. The sweep lets the body over a step only when the step's wall triangles are under 0.25 m tall (Walls and steps).

Walls and steps

The physics body of a human holds a capsule shape (type 3, shape +0x30; radius 0.35 at shape +0x40, 1.886 at +0x44; read at runtime), and the physics world handles a shape through a table of functions by type (world +0xe0, 0x0033d2d8, which passes −0.65). For type 3 that is PhysicsMesh_SweepCapsule (0x00347c08), which treats the body as one sphere for walls. Confirmed (code):

  1. The sphere: radius r = shape +0x40 × body +0x60 × the human's scale (Human_GetScale 0x0021d020: +0x65c, or 1.0 in a scene state when it is under 1.1), centre r + 0.05 above the feet (0x00347c98-0x00347cd8). The shape's +0x40 is itself 0.35 × the scale (Human_GetCapsuleRadius 0x00219860, written by PhysicsBody_ApplyHumanScale 0x00341f28), so the scale counts twice: r = 0.35 × scale² × body +0x60. Confirmed (code). For the player, body +0x60 (and +0x64) is 1.4286 (0.5 / 0.35), so r = 0.5 × scale²: Rembrandt (scale 0.97) has r = 0.3395 × 1.4286 × 0.97 = 0.4705 m, and the sphere spans 0.05 to 0.99 m above the feet. Confirmed (runtime), PCSX2 2.9.94, the sweep-radius hook at 0x00347cbc in the sweep60 scenario (a copy of slot 1, level99's street, stick 60 % up for 80 updates): all 39 calls logged the player's body with shape +0x40 × body +0x60 = 0.4850, body +0x60 = 1.4286 and Human_GetScale = 0.9700, and the hooked mul.s multiplies the two. A measured 0.485 m is that product before the second scale; the radius the walls see is 0.4705 m. The stops measured before (0.476-0.480 m from a full wall, a wall at an angle and the fence of slot 7; the step faces below) sit 0.006-0.010 m beyond where a 0.4705 m sphere touches, which fits a small clearance left by the sweep (inferred; where it comes from is not traced). Only a player's body has +0x60 = 1.4286 (Human_CreatePhysicsBody 0x0021ce08 for a brain of type 0, Human_MakePlayer 0x00229c40; Human_ReleasePlayer 0x0022a2a8 puts back 1.0, Physics). Every AI human's is 1.0, so its sphere is shape +0x40 (0.35 × its class scale) × its scale: 0.350 m for Vermin, 0.357 m for level99's bums and civilians of scale 1.01 (fields read in slot 6). Confirmed (code), values confirmed (runtime).
  2. For each enabled triangle of the grid cells it covers that is a wall (|n.z| ≤ 0.65) and that the sphere is in front of (a two-sided triangle is turned to face it), and that the move goes into (n · move < −0.001):
  3. Skip low and thin triangles: take the edge whose unit vector is steepest; if its two ends differ in height by less than 0.25 m, skip the triangle. Then take the longest edge; unless it is nearly vertical (|unit z| ≥ 0.8), skip the triangle when the third corner lies less than 0.25 m from that edge's line within the triangle's plane.
  4. Sweep the sphere along the move against the triangle (Sweep_SphereTriangle, 0x0034ee60; confirmed (code)); a hit at a fraction from 0 to 1 is a contact. The contacts go to the body's contact handler (Human_OnContact, 0x00219d50), which for the level's triangles slides (code 0x20001), lands on a floor contact (flag 0x80), and during a climb (record +0x08 0x40) ignores triangles of materials 30 (LOW_FENCE), 31 (OPAQUE_FENCE) and 122 (RAILING), so the body passes through the fence it climbs. No other material has a rule here: a glass pane's GLASS triangles are a wall like any other until the pane breaks (Moving into a pane).

So on the ground the original has no step height of its own: a wall face shorter than 0.25 m is not a wall, and the ground snap (1.0 m up, above) then lifts the feet onto it; any face 0.25 m or taller that reaches into the sphere (0.05-0.99 m above the feet for the player) stops the body. A kerb of 0.2 m is walked onto; a ledge of 0.5 m or 0.75 m is a wall to walk into and needs a climb (a short wall from 0.7 m, Climbing) or a jump.

The step at runtime (confirmed (runtime), PCSX2 2.9.94, a copy of slot 1 in level99's world, 2026-10-05). The street there has no kerb (no wall face under 0.35 m rises from the street level), so a box of the level's collision mesh (material 41, 2.62 × 0.62 m, against a wall; its eight vertices are used by its own ten triangles only) was made into a step by writing its vertices' heights in RAM: bottom at the floor (0.213), top 0.10 to 0.30 m higher. The player was put 1.26 m in front of it, facing it, and walked in with the stick at 35 %, 50 % or 100 %, turned by the camera so that the move pointed straight at the face:

Step height Stick Result
0.100, 0.200, 0.240 m 35 %, 50 % (walk 1.63 m/s) walked on: the feet rose by the step's height in one update, on the update the body's centre passed over the edge, with no change of speed or clip
0.245 m 100 % (run start, 5.6 m/s) walked on, the same way
0.255 m 100 % stopped 0.395 m short of the face, idle with the stick held
0.260, 0.300 m 50 % stopped 0.399 m and 0.423 m short of the face

So the 0.25 m test is exact, and the stopping distances are those of the 0.4705 m sphere centred 0.5205 m above the feet touching the face's top edge with about 0.006 m to spare: sqrt(0.4765² − (0.5205 − h)²) gives 0.396, 0.399 and 0.422 m for h = 0.255, 0.26 and 0.30, and against a full-height wall the same walk stopped 0.476 m from it (0.4705 + 0.006). The clearance is fitted to these four stops (inferred). An earlier reading fitted the three step stops to a 0.485 m sphere without clearance, but that missed the full wall by 0.009 m, and the radius is 0.4705 m (step 1).

Sliding along a wall (confirmed (runtime), slot 1): the velocity the sweep leaves after sliding is the human's velocity, so the next update's current speed is its length and the 0.8 m/s gain starts from there. Running into a wall 20° off its normal, the speed fell from 7.80 to 4.00, 1.55, 0.86, 0.65 and 0.56 m/s (every second update) and settled near 0.8 k / (1 − k) (k = sin 20°: 0.42 m/s measured, 0.416 predicted), until it fell under the idle threshold (a quarter of the sneak-walk speed, 0.396 m/s) and the idle played with the stick still pushed. A walk does the same. So the player brakes against a wall met at a steep angle instead of sliding along it at speed.

Slopes between floor and wall

A face too steep to be floor and not steep enough to be a sheer wall (n.z between 0.65 and about 0.5) is a wall the body slides up, not a wall that stops it. Confirmed (code) unless marked.

The thresholds. Only two tests read a normal, and the ground snap reads none:

Test Rule Where
The walking sweep's walls n.z from −0.65 to 0.65, the move going into the face, 0.25 m tall or more PhysicsMesh_SweepCapsule 0x00347c08 (the −0.65 comes from 0x0033d2d8), above
An airborne body's landing n.z > 0.65 0x0023e408 (Falling and landing)
The ground snap none: the feet go onto the first triangle the ray meets (mask 0) Human_SnapToGround 0x0023eab8; confirmed (runtime) below, walking at full speed down a face with n.z 0.54
The slope's speed n.z < 0.95: × clamp(0.6 + 0.3 × (n.z − 0.5), 0.5, 1.0) the move 0x0023d8c8 (above); confirmed (runtime) below

Nothing else changes them:

  • The material. Human_OnContact (0x00219d50) answers 0x20001 (slide) for every level triangle; its only material rule is the climb's pass-through of 30, 31 and 122. GRAVEL (106) and the rest have no movement rule.
  • The triangle's bits 14-15. The sweep reads them as the edge of a corner slide; 3 names none, and the gravel faces below hold 3.
  • The route. A leg of kind 1 is walked with no handler of its own (AI: link kinds). The sweep, the contact handler and the snap read neither the brain nor its route, and an AI's body moves through the same move as the player's. Two things differ: the sphere's radius (body +0x60, about 0.35 m for an AI, above), and the slid velocity, which is written back only to a player's body (body flag 0x400, Physics). An AI asks for its full speed again each update, so a slide never brakes it.

How the sweep slides up such a face:

  1. A face the sphere already reaches (start distance to the plane at most r) is sorted by where the centre lies (Sweep_SphereTriangle 0x0034ee60; edge k runs from corner k to k + 1, and the centre is inside it when (e_k × n) · c ≤ (e_k × n) · v_k):
    • inside all three edges (case 7): a contact at fraction 0;
    • outside one edge (cases 3, 5, 6): that edge alone (SphereSweep_Edge 0x0034e3b8). When the edge segment already passes within r of the centre (Segment_SphereIntersect 0x0034e120: the segment's roots against the sphere overlap 0 to 1) the contact is at fraction 0; otherwise the move is swept against the edge as a cylinder and the first root from 0 to 1 is the contact;
    • outside two edges, past a corner (cases 1, 2, 4; SphereSweep_VertexRegion 0x0034e5d0): a corner already inside the sphere (|v − c| < r) gives no contact at all, nor does a move going away from it (move · (v − c) ≤ 0); otherwise one of the corner's two edges is swept as above.

A sphere not yet at the plane is sorted the same way at the point where it first touches the plane. Every case hands back only a fraction: there is no edge or corner normal and no push-out. Nothing pushes a walking sphere out of a face it overlaps: PhysicsBody_PushOutOfWalls runs only in the air (below). 2. The contact carries the triangle's own unit normal, turned to the sphere for a two-sided one (contact +0x50, copied in 0x00347c08), with its z, in every case of step 1: a sphere that touches the face only past its edge slides along the face's plane exactly as one inside it. 3. The slide (PhysicsBody_ResolveContacts 0x0033d9d8, code 1) removes from what is left of the move, and from the velocity, the part that goes into that normal: v −= (v · n) n on x, y and z, only when v · n < 0 (Vec_RemoveNormalPart 0x0033d870). The move then goes along the face, rising. 4. On the next pass the slid move no longer goes into the face (n · move ≥ −0.001), so the face is skipped. There are up to three passes. 5. The velocity keeps the slid z, but the next update sets v.z to 0 before its sweep (The move). The snap then puts the feet on whatever is under them.

So walking at a face of n.z 0.53 at 20° off its normal, the move keeps its part along the face. The snap holds the feet on the floor triangle in front of the face, and the body climbs that floor along the face's foot until it rises past the face. The sphere sinks steadily into the face, and nothing corrects that. The body has no step height of its own: it relies on the 0.25 m wall rule and the snap's 1.0 m reach, above.

At runtime (confirmed (runtime), PCSX2 2.9.94, a copy of slot 1, 2026-10-08). The test used level99's gravel heap, where the path data routes a kind-1 walk from (−271.7, 129.4, 0.3) up to the lesson-2 platform at (−277.7, 132.0, 3.1). The faces on that line:

  • triangle 679: GRAVEL, flags 0xc001, n (0.736, −0.134, 0.664), a floor;
  • triangle 680: GRAVEL, flags 0xf001, n (0.849, −0.055, 0.526), a wall to the sweep: 1.77 m tall, its steepest edge rising 1.77 m.

Rembrandt was put at the walk's start facing its end. The stick was pushed straight up from update 60, and the camera put the move about 64° from north toward the west. Every run took the line onto 679 first:

Run What happened
walk, stick 60 % 1.63 m/s on the street. On 679 the walk was turned about 30° north along 680's foot, at 0.41 m/s across the ground and 0.29 m/s up: the feet followed 679's surface (ground normal 0.664 every update) while the slid velocity held z 0.36. The sphere's distance to 680 fell from 0.48 to 0.33 m (radius 0.4705). After 3.5 s at z 1.44 the body passed 680 onto faces with n.z 0.77 at 1.107 m/s across the ground (1.63 × 0.6797, the slope rule), crested at z 2.01 and walked down the far side, including a face with n.z 0.54 at full walk, onto the street
run, stick 100 % the same: stopped for an update at 679's foot, then 0.55 m/s up 679 along 680, then a run at 7.80 m/s over the crest at z 2.28
walk, stick 60 %, body +0x60 set to 1.0 (radius 0.34, an AI's size if its +0x60 is 1.0) the same path: up 679 along 680 (distance to 680 0.32 down to 0.20 m), over at z 2.36, down the other side

So a human on that leg does climb the heap in the original: by sliding along 680, not by walking up it. The lesson's walk reaching the platform itself was not run (the stick's line passed 1 m north of it).

An AI on the same leg (confirmed (runtime), PCSX2 2.9.94, a copy of slot 6, 2026-10-08, scenario repo:research/traces/scenarios/heap_ai.toml). Vermin (dead brain, radius 0.350) was put at (−271.7, 129.4, 0.3) with the player standing 4 m behind, and his own GoalMoveToFlag was re-aimed at (−285.2, 124.2, 0.3), gait 2 (walk, his 1.654 m/s), radius 2, and his actions cleared. The planner gave him the same route as Coney's: (−277.71, 132.00, 3.12), (−280.76, 130.48, 3.76), a drop leg, the target. Each update, read over PINE:

Stretch What happened
street, updates 1-81 1.654 m/s straight at the first waypoint, 20° off 680's normal in plan
679, along 680's foot, 82-110 the centre's projection 0.36 to 0.02 m outside the crease edge (679-680) with the edge 0.50 down to 0.27 m from the centre (radius 0.35): the edge case of step 1. He moved 0.013-0.015 m across the ground (0.42 m/s) and 0.012 m up per update, turned 20-30° north of his aim, while his asked speed (+0x1ac) and velocity stayed 1.654 m/s; the "could not move" counter stayed 0
inside 680, 111-155 the projection inside the face (step 1's first case), the centre sinking to 0.21 m from its plane; feet still on 679 until update 140, then on 680 itself (n.z 0.526): 0.33 m/s across and 0.45 m/s up
crest the route moved on to (−280.76, 130.48) at update 160, before he reached the first waypoint (the route's straight-line skip, AI); he crested at z 3.7, took the drop leg and stopped 1.9 m from the target at update 487

The same run with his body +0x60 raised to 1.3429 (radius 0.470, Coney's) was alike: the crease edge 0.49 down to 0.35 m from the centre, the projection 0.27 to 0.05 m outside it, 0.013-0.015 m across and 0.012 m up per update, never blocked; this passes within 0.5 m of the point where Coney's bum stalled before 2026-10-11. Neither run tripped the move action's stuck test (0.2 m in 60 updates, AI): about 1.1 m was covered in each 60 updates on the heap. The waypoint was not skipped to get round the heap, and nothing warped him.

The push-out PhysicsBody_PushOutOfWalls (0x003477c0, a sphere out of the nearest wall by n × (r − distance)) is not the walking case: its only caller Human_PushOutInAir (0x0021a490) runs while the human is airborne (object flag 0x4000000), in a few states (0x00227ef8, 0x00223b48, record +0x08 0x400000, anim id 2 or 4), and not in states 0x00223920 / 0x00223980. Its sphere has radius 0.35, or 0.5 for a player, times the scale, centred r + 0.05 above the feet (at bone 2 in states 0x00227ef8 / 0x00223b48). In a long fall (state flag 0x1000000000) and some states it instead pushes out a 0.2 m capsule between bones 6 and 3 (0x0033e7f0, the average of the contacts). Confirmed (code).

Falling and landing

Starting to fall (0x0023dc58): march a ray along the velocity (Collision_MarchRay, steps of 0.1 m, up to 5 m) to find where the fall will end (kept at +0x2c0; the current position if nothing is hit), set the airborne flag (0x003a2158) and switch the body to its falling mode (body slot +0x2c with 2). For a player whose follow camera is in its normal mode, a ray 2.5 m down from 0.75 m ahead of the feet checks for a drop and, if there is no ground, tells the camera (0x0012da20 with the heading, −1.0): the camera reacts to a ledge.

Landing. While airborne, the sweep tests the segment from the body's upper point (feet + +0x4e8 − 0.16 × scale) to the moved feet against the collision mesh (0x0023e408, through WorldManager_RayCast); a hit on a triangle with n.z > 0.65 is a landing contact. The contact handler (0x00219d50) then calls Land(human, 1, 1) (0x0023e090): clear the airborne flag, apply fall damage by the vertical speed at impact (vz ≥ −14.9 m/s: none; between −14.9 and −20.5: a share of the maximum health, (vz + 14.9) / −5.6, at least the class's minimum +0x118; below −20.5 m/s: the maximum health, so a fall that fast kills), tell a player's camera when vz < −1.5 (camera slot +0x15c with the landing kind 1-3), set +0x3a0 (the vertical velocity) to 0 and write the velocity back. The thresholds are 0x00510674 (−14.9) and 0x00510678 (−20.5). Free fall from rest reaches 14.9 m/s after about 7.1 m and 20.5 m/s after 13.4 m (inferred from the gravity above).

When the landing happens (the feel pass's second runtime run, 2026-10-05, PCSX2 2.9.94, slot 1, a run jump with stick 100 % and triangle tapped 35 updates in; the arc's phase shifted by adding 0.015 to 0.15 m, or taking 0.05 or 0.12 m, to the feet's height at the 7th update in the air; ground at 0.2231). Confirmed (runtime):

Feet at the start of an airborne update, below the ground That update
above it, or 0.041, 0.091, 0.111, 0.141 or 0.161 m below still airborne: the body falls a whole step (0.20-0.22 m) more
0.176 or 0.191 m below (and 0.241-0.379 m) lands: Land, the feet snapped up onto the ground, full horizontal speed

So the feet are not stopped at the ground on the update they pass it: the jump lands on the first update that starts with the feet about 0.17 m (between 0.161 and 0.176 m) or more below the ground, and until then the body keeps falling through it, up to 0.38 m below in one phase. The unshifted jump (the street's arc) crosses with the feet 0.009 m above the ground, ends that update 0.191 m below and lands on the next: the 0.19 m dip of the per-update trace is this, not a sampling artefact. The code path is the sweep's landing contact (0x0023e408, run from 0x0033d340 when body flag 0x40 is set; segment from feet + +0x4e8 − 0.16 × scale, 0.880 m for the player, to the moved feet), which records the contact's fraction as (hit − 1.0) / (length − 1.0), or 0 when the hit is nearer than 1.0 m (the human's vtable +0x5c, the constant 1.0 at 0x004ed818); why the hit is not taken until the feet are about 0.17 m under is not traced. What the code shows (confirmed (code)):

  • the segment's upper point is 0x00226a20: the feet + +0x4e8 − 0.16 × the scale;
  • only a hit with a normal z above 0.65 records a landing contact;
  • 0x0033d340 marks the contact (+0xb0 = 0x80) and its handler 0x00219d50 calls Land(1, 1) (confirmed (code));
  • contacts are kept sorted by fraction (0x0033d718), and the resolution 0x0033d9d8 acts on the first contact whose handler returns a code that is not 0, then returns (confirmed (code));
  • the body's move loop 0x0033e278 runs the sweep up to 3 times (confirmed (code)).

Read alone, this lands on the update the moved feet pass the ground, which the runtime contradicts; the 0.17 m does not follow from the 0.88 / 1.0 m geometry either. A log of the contacts (a code patch that copies each contact's fraction and handler code to free memory) would settle it.

A fall at runtime (PCSX2 2.9.94, level99, no stick input; Rembrandt raised 10 m by writing the transform table's z). Confirmed (runtime):

  • vz changes by −0.5227 m/s per update from the second airborne update, and z(n+1) = z(n) + vz(n+1) × dt: the velocity is updated before the move.
  • Clip 428 (drop cycle) plays while falling.
  • Landing after 34 updates at vz = −17.25 m/s, inside the damage band; then 429 (drop land), 294 (a hit reaction) and 198 (a ground roll).

Anim states in the air. Human_ChooseAnimState (0x00259578) checks the state flags first: 0x2000000000 → anim state 27 (landing), 0x800000000 or 0x1000000000 → 26 (falling), 0x400000000 → 25 (jump). Confirmed (code). The builders, confirmed (code):

  • 25 (0x0025fba0 → 0x0025cf30): the jump loop (434) after a 0.1 s fade, then the launch (Jumping).
  • 26 (0x0025d020, confirmed (code)): the drop cycle (428), or the long-fall cycles 422 / 425 in a long fall (0x400000, 0x00223b48, 0x00227e60). After a jump the jump loop keeps playing (runtime).
  • 27 (0x0025d390): after a jump, 436 (jump end running) handing over to a gait blend when the stick is above 0.12, else 435 (jump end) and then the idle; after a drop, 429 (drop land); after a long fall (0x1000000000), the clip after the current one, or 198 (ground roll).

Walking off an edge at runtime (the roof of a car, 1.48 m up; stick 0.5). Confirmed (runtime): state 26 with 428 and record +0x08 0x400000 for the first two updates, gravity as above, then state 27 with 429 for about 0.5 s and the idle.

Jumping

The button. On command 10 (triangle pressed), Player_UpdateActions (0x0027c120) tries, in order, and stops at the first that succeeds. Confirmed (code):

  1. a climb (Climb_TryStart, below), if human flag 0x20000000 is clear and the stick is above 0.12;
  2. a context action (Player_TriangleAction, 0x002811f0, confirmed (code)), if L2 is not held;
  3. a jump (Player_TryJump, 0x002829e8, confirmed (code)), if human flag 0x10000000 is clear and the stick is above 0.95;
  4. the drop of what is in hand (Human_DropHeld, 0x00257f38), if L2 is not held (Triangle with something in hand).

The object action is the drop: 0x00226ff0 is Human_GetHeldObject (+0x338) and 0x00257f38 is Human_DropHeld, which gives the held object back its physics body and clears the hand. Confirmed (code). There is no jump buffer in this order: triangle is acted on in the update it is pressed. So, inferred from the order and the jump's refusal while carrying a class 4 or 6 object: triangle with a weapon in hand and the stick pushed toward a climbable wall that is still out of the climb's reach (the climb fails, the jump is refused) drops the weapon, as checklist item 2 reports of Coney; whether that is what the original does at runtime is not checked.

Nothing happens while state flags 0x7bf9e9f7ff0 or record +0x08 flags 0x5cfeafb are set.

Checks (Player_TryJump, then Human_BeginJump 0x0023db48). Confirmed (code). The jump is refused when the human carries an object of class 4 or 6 (0x00224000), is in a combat stance (0x00228340), moves at 3.3 m/s or less (0x0051018c, speed +0x1ac), is not a player, or a ray from 1.7 m above the feet, 5.5 m long in the stick's direction (0x0021d228), hits a climbable triangle (the rule of Climbing): near a climbable wall the button climbs or does nothing. Human_BeginJump then needs the gait for the speed (Human_GaitForSpeed) to be 3 or more and |v| at least 3.3; it keeps the gait at +0x3c0 and the height at +0x560 and sets state flag 0x400000000.

Launch (Human_LaunchJump, 0x002217f0, called by the state 25 builder). Confirmed (code):

  • horizontal velocity: the current direction times the run speed for a take-off gait of 3 or 4, the sprint speed for gait 5 (the jog speed below 3);
  • vertical velocity 5.5 m/s (0x00510188, read by Human_LaunchJump; confirmed (code));
  • Human_StartFall (vtable +0x154), then the state function Human_AirControl (0x00240898, set through 0x00227c28) and anim state 26.

In the air (Human_AirControl). The horizontal speed is kept. With the stick above 0.12 the heading turns toward it at the Human_MaxTurn limit with the same ease as on the ground, and the velocity turns with it; with the stick centred nothing changes. Gravity, the airborne counter and the landing are those of a fall. Confirmed (code).

At runtime (the street, Rembrandt on flat ground, triangle tapped for one update). Confirmed (runtime):

Case What happened
stick 0.8 (walk at 1.63 m/s), triangle nothing
stick 1.0, run at 7.80 m/s, triangle state 26 and clip 434 at once, state flags 0xc00000000; vz 5.5 then −0.5227 per update; apex 1.06 m above the take-off; horizontal speed 7.80 throughout; landed after about 25 updates (0.83 s), 6.4 m further
stick 1.0 and L2, sprint at 10.245 m/s, triangle the same arc at 10.24 m/s horizontal, about 23 updates in the air
the same, stick turned 90° right just after take-off the heading turned by about 4° per update toward the stick, the horizontal speed staying 10.24; that is the run's limit, not the sprint's 2.5° (which gait the air turn uses is not traced)
landing state 27, 436 for about 0.4 s at its own 4.23 m/s, record +0x08 0x1000000, then the gait blend from a jog back to the run
per update (the feel pass, slot 1) 24 updates in the air from a run: the last airborne update leaves the feet 0.19 m below the ground and the next one lands them (the landing rule); that landing update still moves at the full 7.80 m/s, then 436 holds 4.23 m/s for 10 more updates (11 in all) and the gait blend gains 0.8 m/s per update from there; take-off to landing 6.24 m
triangle during the run start (414), at 3.35 m/s a jump at once: the run start does not block it, only the 3.3 m/s and gait tests do (slot 7)

Clips 427 (slot 25) and 430-433 (jump from idle, walk or either foot) did not play in the player's jump, nor in Vermin's route jump in level99 (clip 434 at take-off, 435 on landing; runtime): what plays them is not traced.

An AI's jump. Human_BeginJump's gait and speed tests apply only to the player's brain (type 0): an AI may jump from any gait, standing too, and its +0x3c0 is not written. Human_LaunchJump gives a human whose per-player record +0x1b is 0 the velocity of the route follower's arc instead (0x0029ade0): the lowest of the vertical speeds 0.5, 1.25, 2.0, ... m/s whose arc lands on the route's landing point at no more than 10 m/s in plan. Confirmed (code), and at runtime for Vermin (3.5 m/s up, 9.55 m/s across a 4.1 m gap); the rest is in AI: Jump legs.

In an input script: stick left 0 100, wait until the run start is over and the speed is above 3.3 m/s, then tap triangle; add press l2 beforehand for a sprint jump.

Triangle with something in hand

User checklist item 2 (an early press at a wall drops the weapon instead of climbing). The four tries above, read again for a held object; confirmed (code) at Player_UpdateActions (0x0027c120, both its triangle blocks), Climb_TryStart (0x002826f0), Climb_Start (0x00281c20), Player_TriangleAction (0x002811f0), ContextAction_Use (0x0024d530) and Human_PickUpSearch (0x0024d810):

  1. There is no buffer. Command 10 is one sample (Commands) and each try runs once, on that update. An "early" climb is only the long ray: 4.5 m ahead for a player (human flag 0x2) at gait 4 or 5, else 1.5 m.
  2. The climb comes first and ignores what is in hand. Climb_TryStart refuses only on record +0x08 0x84240; nothing about a held object. When the climb starts, Climb_Start drops an object of held set 4 (overhead: barrels, crates) always, and one of set 6 (the ghetto blaster) unless CfgClimbWithGhetto (0x00510250) is set (confirmed (code) in Climb_Start); a weapon (sets 1-3) or a one-handed throwable (5) stays in hand through the climb.
  3. A press slightly out of reach is swallowed. Climb_Start returns "done" for a player (per-player +0x1b not 0), without climbing, when the face is beyond the clip's maximum distance but closer than twice a clip's reach (which clip's reach the decompiler hides; open question), and when the space at the top is not clear (Climb_IsSpaceClear). The dispatcher then returns with nothing more: no jump and no drop. An AI gets "not done".
  4. The context action never drops for a player with nothing to take. Player_TriangleAction → ContextAction_Use → (no context record) the pick-up search. With an object found and something in hand (not kind 12 or 24), it drops what is held and sets human +0x5b8; the history-hold triangle (0xb, 7 samples) then takes the new one (Player_TriangleAction again, +0x5b8 cleared). With nothing found, a pad-controlled human gets 0 (no drop); only an AI (+0x1b = 0) drops here.
  5. The jump: refused while carrying held set 4 or 6 (Human_HoldsKind4Or6), in a fight stance, at 3.3 m/s or less, or with a climbable face within 5.5 m (above). A weapon does not refuse it.
  6. Only then the drop: with L2 not held and an object in hand, Human_DropHeld (0x00257f38) and +0x5b8 = 1 (confirmed (code)).

So with a bat at a run toward a climbable wall: within 4.5 m (and inside the clips' distances) he climbs with the bat; just beyond the clips' distance the press may be swallowed; farther but within 5.5 m nothing climbs or jumps and the bat drops (the original does this too); beyond 5.5 m, at a run, he jumps with the bat. Empty-handed, the last two cases do nothing and jump.

Coney fixes (item 2; today PlayLevelMode's context action returns TriangleResult::Drop at try 2, before the jump, src/platform/play_level_objects.cpp):

  1. Remove the drop from the context action for the player: with nothing to take it returns "nothing" (an AI keeps the drop there). With an object to take and something in hand, drop and remember the swap (+0x5b8); the triangle history hold (7 samples) picks the new object up.
  2. Add try 4 in Human::tryActions (src/human/human.cpp): after a refused jump, with L2 not held and an object in hand, drop it.
  3. The climb with an object: keep weapons and set-5 objects in hand; drop set 4, and set 6 unless CfgClimbWithGhetto. Check that a player carrying a weapon at a run is gait 4 or 5 for the 4.5 m ray (a slower armed run speed must not shorten the reach to 1.5 m).
  4. Add the swallow of try 3 when Coney's climb distances say "too far by less than twice the reach": the press ends there.
  5. Tests: with a bat, at a run, triangle 3 m before a climbable fence climbs and keeps the bat; 5 m before it drops the bat; 8 m before in the open it jumps and keeps the bat; with a barrel (set 4) the climb drops it.

Climbing

Climb_TryStart (0x002826f0) runs on triangle with the stick above 0.12 (Jumping). Confirmed (code):

  1. Refused while record +0x08 has any of 0x84240.
  2. Direction d: the stick's direction when its magnitude is above 0.01, else the facing (Player_GetStickDirection, 0x0021d228; confirmed (code)).
  3. Two horizontal rays along d from 1.7 m and 0.69 m above the feet, 1.5 m long, or 4.5 m when human flag 0x2 is set (players) and the gait (+0x1a8) is 4 or 5.
  4. If both hit and their distances differ by less than 0.1, the obstacle is tall (the high hit is used); otherwise it is short (the low hit is used; a hit by the high ray alone is not a climb).
  5. The hit must be climbable: material 30 (MATERIAL_LOW_FENCE), or triangle flag 0x4 for a player, or triangle flag 0x80 (Collision). Both probes are WorldManager_RayCast, the level's static mesh only, so a parked car is climbed through its shell in that mesh (every triangle with flag 0x4, material 0, never 0x80, so only players climb cars; below). On level99_2's sedan shells the 0.69 m ray meets a side (0xf00d or 0x700d) and the 1.7 m one passes the 1.71 m roof or meets the sloped screen at another distance, so the car is short. The down probe from 1.8 m finds the sill or bonnet at 1.18-1.30 m above the ground, inside 0.7-1.7 m: a short wall climb (455 / 458). Inferred from the code and the disc's mesh; not run.
  6. Climb_ProbeTop (0x00282370) with, for a tall obstacle, H = 3.0, a window of 1.7-2.91 m and the fence ids 437 / 440; for a short one H = 1.8, a window of 0.7-1.7 m and the short-fence ids 443 / 446.

Climb_ProbeTop, confirmed (code):

  1. The face must look at the player: n · d < −0.7 (within about 45°).
  2. A ray straight down from H above the point 0.4 m beyond the face (pos + d·t − 0.4·n), H + 0.5 long, finds what lies just behind the face; its top is H minus the hit distance, a height above the feet.
  3. A top inside the window is a wall climb: the ids + 12 (449 / 452 wall, 455 / 458 short wall).
  4. Otherwise a top of 0.25 m or more refuses the climb.
  5. Otherwise (no floor just behind the face, or one near the feet' height: a fence), for a tall obstacle a ray along d from 2.5 m above the feet must miss (the fence is lower than 2.5 m), and the fence ids are kept.

Climb_Start (0x00281c20), confirmed (code):

  • The first id is the standing clip; the running one (+3) is used when human flag 0x2 is set and the gait is 4 or 5. Each clip's reach is the length of its type-8 event vector (0x00101558, through the Anim Range List, 0x002544a0). A running climb needs the face between (r1 + r2) × 0.4 and r2 × 2.2 away (the reaches of the first and second clips); a standing one at most (r1 + r2) × 0.4. CfgClimbWithGhetto (0x00510250) is also read here.
  • The start point is the hit at the feet' height plus n × 0.9 × reach, kept at +0x2c0; the human is turned to face the wall and moved there over 1/60 s or 1/15 s.
  • The three clips play in turn (P1, P2 = id + 1, P3 = id + 2). At P1's end (0x00281450 running, 0x00281838 standing; confirmed (code)) the forward probe is made again from 0.69 m (2.5 m long running, 1.5 m standing). On success the body is moved at once by P2's root displacement turned to the facing, body +0x40 gets 0x80000000 | 0x4000, and record +0x08 gets 0x40 (the fences stop blocking, Walls and steps); on failure the climb ends in the idle or the combat idle. A running climb ends in a gait blend, a standing one in the idle.
  • While clips 437-460 play, +0x5b9 is 1 (Human_StateUpdate).
  • From P2 on nothing collides. While record +0x08 has 0x40, Human_Move (0x0023d8c8) skips the wall sweep (PhysicsBody_Sweep) and the ground snap and adds the velocity and the clip's root motion (+0x2f0), height included, straight to the position (Object_SetPosition); the other path zeroes the height and leaves it to the snap. The teleport at P1's end goes through body vtable +0x1c with no sweep, 0x4000 stops the body re-posing (0x003422d0), and Human_GetPosition returns +0x2c0 while 0x40 is set. So a climbed face of any material (a parapet of material 107 with triangle flag 0x80, say) stops the body only during P1; the skip of materials 30, 31 and 122 in Human_OnContact covers only contacts that still reach it. Confirmed (code): the branch is Human_HasHeld40 (0x0023d8c8, the test before Vec4_Add(..., +0x2f0) and Object_SetPosition); the sweep and Human_SnapToGround sit only on the other branch. Confirmed (runtime) on a railing of material 7, below.
  • Over a drop there is no third clip. When P2 ends with nothing under the feet (a railing above a lower floor), the next update's ground snap misses and the human falls: the fall clip 428 (record +0x08 0x400000) in place of P3, gravity from the third update, the landing (436) on the floor below. Confirmed (runtime), the hangout railing below; that the switch is Human_SnapToGround's miss starting the fall is inferred.
  • The first clip runs during the move. The same call sets the move to the start point (0x0023d2b8: over 1/60 s, or 1/15 s when the turn 0x0023cf88 takes 1/30 s) and installs the three clip tasks (0x00105990, 0x001754e8), so P1's clock starts on the climb's first update, not after the move. Confirmed (code). At runtime (the slot 7 fence from a run, Feel comparison) 440 lasted 11 updates: the start update still at run speed, the two snap updates (1.11 and 1.17 m), then 8 updates of the clip's root motion at full speed from the first (5.79 m/s falling to 0.36 m/s), with no fade-in. The first update of 441 and of 442 moved the body 0 m. Confirmed (runtime).

What gets climbed, from the rules above (heights above the feet; inferred from the code, the three rows marked runtime were seen):

The obstacle Just behind it (0.4 m past the face) Climb
reaches 0.69 m but not 1.7 m ground lower than 0.25 m short fence (443-448)
reaches 0.69 m but not 1.7 m a top at 0.7-1.7 m short wall (455-460); runtime: a trash can (1.28 m) and a car (1.48 m)
reaches 1.7 m a top at 1.7-2.91 m wall (449-454); runtime: a roof 2.64 m above the trash can
reaches 1.7 m, lower than 2.5 m ground lower than 0.25 m fence (437-442); runtime: a street fence, from a run
lower than 0.69 m, or a top outside the windows, or a fence of 2.5 m or more no climb

At runtime (the street; stick and triangle through patched pad input). Confirmed (runtime):

Climb Input What happened
fence from a run (440, 441, 442) stick 1.0, triangle tapped every 0.1 s the tap 4.9 m from the face did nothing (no climb, and no jump: the 5.5 m climbable check); the one about 4.4 m away started 440. The body was snapped 2.5 m forward in two updates (37-39 m/s), then 440 moved it at 5.4 to 4.5 m/s to the start point (0.34 m before the face, 0.3 s); 441 (0.47 s, record +0x08 0x40) carried it through the fence at 2.4-3.4 m/s with the feet at ground height; 442 (0.43 s, 0x80000) and the run went on; 1.27 s in all
the same, per update (the feel pass, slot 7, the tap 4.5 m from the face) stick 1.0, triangle every 2 updates 440 for 11 updates: the snap moved 1.11 m and 1.17 m, then the clip carried the body until it stopped against the fence, 0.48 m from its face (its walking sphere); 441 for 15 updates through the fence at 2.4-3.6 m/s; 442 for 13; the run's gait blend 39 updates after the tap
short wall and wall, per update (slot 8) stick 0.5, triangle the rise at 456's start took 2 updates (1.12 m, then 0.17 m by the ground snap); at 450's start 2.30 m, then 0.097 m per update for 4 updates to the roof (2.64 m in all)
short wall, standing (455, 456, 457) stick 0.5, triangle 455 for 0.3 s (0x80000); at 456's start the feet jumped 1.06 m forward and 1.29 m up in one update onto the trash can; 456 for 0.6 s (0x40), 457 for about 0.6 s, then the walk
wall, standing (449, 450, 451) stick 0.5, triangle, on the trash can 449 for 0.37 s; at 450's start the feet jumped 0.98 m forward and 2.4 m up, and the ground snap settled them on the roof (2.64 m above the start) over the next updates; 450 for 1.4 s, 451 for 0.37 s
short wall onto a car stick 0.5, triangle as the trash can, 1.48 m up
short fence over the hangout railing (443, 444, then the fall), per update stick 0.5, triangle every 2 updates below

The hangout railing (confirmed (runtime), PCSX2 2.9.94, 2026-10-10, scenario railing_vault: level95, Cleon put on the clubhouse balcony at (−172.0, 98.3, −194.38) facing +y, 0.63 m from the railing's face, stick 0.5 straight up from update 60, triangle every 2 updates from 66). The railing is 0.90 m tall, material 7 (LAMPOST) with triangle flag 0x80, its face at y ≈ 98.93, and the floor behind it is 3.20 m lower (Collision):

Updates Clip, record +0x08 The body
61-66 413, 0x10000000 the walk start stops against the railing at y 98.44 (0.49 m from the face)
67-79 (13) 443, 0x80000 0.04 m back toward the start point, then forward to 98.443
80-98 (19) 444, 0x40 through the railing at up to 1.64 m/s, y 98.443 to 99.326 (0.40 m past the face), the feet at the balcony's height all the way (z −194.378) over the drop
99-118 (20) 428, 0x400000 the fall: z held for 2 updates, then vz −0.5227 per update; at 102 pushed 0.17 m on to y 99.50, clear of the railing's back; 445 never plays
119 436 landed on the floor below (z −197.576), 3.20 m down, 0.57 m past the face; then the landing and the walk

So the railing's triangles do not stop the body during 444, though material 7 is not among the materials Human_OnContact skips: the wall sweep is not run at all (above).

The vertical part of a climb is the single move at P2's start: the feet do not rise during P1 or P2.

In an input script: standing, stick left 0 50 toward the obstacle and tap triangle within reach; from a run, stick left 0 100 and tap triangle when the face is 4.5 m away or less.

Parked cars are shells in the level mesh

Nothing builds collision triangles from a car: Car_MakeBodies (0x00387d50) gives a car one body with two boxes sized from its model's record (0x0057e4c0 + model × 0x5f0), and the only code that switches mesh triangles is the script's ChangeCollision (0x00379c20 → CollisionMesh_SetEnabledInVolume). Confirmed (code). The level files carry the shells. level99_2's mesh has three closed car-shaped boxes, the number of cars SetupCars spawns (car_coupe, car_osedan, car_osedan01), so they are inferred to be these cars. Two are 5.74 × 2.2 m, with the sill at 1.18-1.30 m, the roof at 1.71 m and sloped screens; one is 5.11 × 2.3 m with the roof at 1.67 m. All are material 0. Every triangle has bits 0, 2 and 3 (low bits 0x00d) and a top value of 3-15: the long sides 0xf00d / 0x700d, the ends 0x400d / 0x700d, the roof and bonnet 0xc00d / 0xd00d. No triangle has bit 7 (0x80). Read from the disc. Across the disc's levels, 2,530 triangles with these low bits and material 0 sit in 19 levels. So a car's climbable surface is wherever the level put a shell, not where the car is: a car that CreateCar or CarSpawn places away from a shell, or one moved off its shell, has no mesh surface for a walker, a climb probe or a ray (rays and climbs test the level mesh only, WorldManager_RayCast 0x0040db88). Bit 2 is the player-climbable bit (Collision, and what stops a walker at a car is on Physics); the climb itself is above.

The spinning icon

The marker over a human's head (a mission target's star, a dealer's sign, the co-op player markers, the crown in Rumble) is a 3D world object of class dyn_icon, attached to the human; it is not a HUD sprite. One per human, its handle at human +0x360. Confirmed (code) at the cited addresses unless marked; not checked at run time. The dealer's case is also on AI: the dealer's icon.

Making one (Human_ShowOverheadIcon, 0x002271f0; reached from HuAttachSpinningIcon 0x00238a88, GangAttachSpinningIcon 0x0016b2c8 for each of the gang's 16 member slots, and the game's own callers):

  1. The name is the object type to spawn (any dyn_icon type: dyn_rockstar, dyn_crown, dyn_exclamation, dyn_gangrat, dyn_weapdeal, ...; the object list). A name whose first 9 characters are dyn_p_one becomes dyn_play_one, and dyn_p_two becomes dyn_play_two, each with _euro appended when game state +0x120 is set (inferred: a European language).
  2. When the human already has an icon of that type nothing happens; another icon is removed first (message 0x15).
  3. Task_CreateObjectByName spawns it with two message arguments, the human's handle and the attach bone (the script's third argument; every script and every game caller passes 0, the human's own transform).

The script arguments (from the bindings 0x0035aeb0, 0x0035f128, 0x0035af80):

Function Arguments
HuAttachSpinningIcon(human, name, bone) the human's handle; the type name; the pose bone the icon hangs from, 0 = the human
GangAttachSpinningIcon(gang, name, bone) as above, for every current member; gang −1 does nothing
HuSetSpinningIconColor(human, steps, colour) a fade: the step count, then the target colour word; the colour defaults to 0xFFFFFF00 (white, alpha 0)
HuRemoveSpinningIcon(human) message 0x15, the handle cleared (0x00227388)

HuSetSpinningIconColor's two numbers are not two colours, as its argument names in the binding reference suggest: the message's argument stack is last in, first out, so DynIcon_SetColourFade (0x003e93d0) pops the second script argument as the step count and the third as the target colour. The game's own call, (human, 3, 0xFFFFFF00) in 0x0024b2a8, fades an icon out in 3 steps. No level script calls it.

Init (DynIcon_Init, 0x003e8fa0):

  • Model: the object type's own model (Obj_SetModel(obj, 0)), at its own size: no scale is applied.
  • Attachment: Obj_Attach(obj, human, bone); its world pose is the human's transform (position and rotation) ∘ the bone's (none for bone 0) ∘ the icon's local pose (World objects: the attachment). Flags +0x54 = 0x91. Update every 2 ticks.
  • Local position: (0, 0, 2.25) m; (0, 0, 2.5) for dyn_weapdeal, dyn_flashdeal and dyn_spraydeal (model hashes 0x30f09efb, 0x51d27ab6, 0xd939c21d); the type record's offset (property 11) for dyn_cross (0xe3f92003). The human's transform is at his feet (inferred), so the icon floats 2.25 m above the ground. There is no bob: nothing moves the local position afterwards.
  • Local rotation: the quaternion (0, 0, 1, 0) (0x00511700), a half turn about z.
  • Spin: angular velocity (0, 0, π) rad/s (π × (0, 0, 1), 0x00511740): a half turn a second about the local z axis, which is the human's up axis, one turn in 2 s. The attached pose advances the local rotation by it (World objects: the attachment).
  • No spin for model hashes 0x8b7fe995, 0x7644ee5d, 0x1de2e2ca, 0x1a72a32d, 0x687e742b: the angular velocity is zeroed and flag bit 1 cleared. These are the player markers (dyn_play_one, dyn_play_two and their _euro forms) and dyn_lizziestarget (AI); they keep the half-turn local rotation, so they turn with the human.
  • dyn_cuffs (0x464ac521) takes the type record's offset and rotation (properties 11 and 12), turns at π/2 rad/s, and is detached at once, so it stays where it appeared (Crimes: arrest).
  • Colour state (5 words): not fading, colour 0xFFFFFFFF (white, opaque), the rest 0.

Colour (DynIcon_Update, 0x003e92e0, every 2 ticks). The colour is the world object's tint word (+0xcc, copied to +0xc8 at the next update; 0xRRGGBBAA), which multiplies the model's colours and its alpha its opacity (World objects: the tint):

  • Not fading: +0xcc := the stored colour, each update.
  • A fade (message 0x34, DynIcon_SetColourFade): steps 0 sets +0xcc := 0xFFFFFFFF and stores the colour, which the next update writes (not fading, above). Otherwise step := (+0xc8 − target) ÷ steps, an unsigned division of the whole 32-bit word, not per channel; each update the counter goes up, and +0xcc := +0xc8 − step until the counter reaches the step count, when +0xcc := the target and the fade ends. The game only fades the alpha byte, where the word arithmetic is a plain linear fade; a port that fades other channels must keep the word arithmetic to match. Because the step is truncated, the alpha jumps to the target at the end: from 255 to 0 in 80 steps it falls by 3 an update to 18, then to 0.

Hidden (confirmed (code); the visible result inferred from the tint rule, an alpha under 10 is not drawn):

  • While the letterbox is up: when not fading and player 1's screen-effects record (0x005fdeb8) has the letterbox state (+0x1e8) set or its level (+0x1ec) non-zero (Screen effects), +0xcc := 0xFFFFFF00 and +0xc8 := 0xFFFFFF01: alpha 0. Not for dyn_cross; not during a fade.
  • Message 0x0a (argument 0 hides, non-zero shows) sets or clears the hidden flag (+0x54 bit 4); 0x20 sets it and also clears the attached bit (0x10); 8 detaches; 0x15 removes the icon (DynIcon_OnMessage, 0x003e9470).
  • Distance: an attached object uses its parent's ObjShow distance and is not drawn beyond it (World objects: the tint).
  • Removal: when the human is beaten (Human_CreditDefeat, 0x00230740) or destroyed (Destroying a human, message 0x15 to +0x360), by the death sequence's camera (which removes the players' icons, Camera), and by the goals that made it.

Drawing: as any world object (ObjectRender_Draw 0x0017fd78, World objects: the tint): the model with its own materials, lit and Z-tested like the other world objects, the tint multiplying it, alpha scaled by the distance and fade-in rules there (inferred: nothing in dyn_icon changes the draw).

The co-op player markers (0x0024b2a8 at a respawn, Reticules_UpdateTarget 0x0024b3d8 at the hints): with two players on one screen, not in Rumble and not during the letterbox, dyn_p_one / dyn_p_two (so dyn_play_one / dyn_play_two) on the players, then a fade to 0xFFFFFF00: from alpha 255 over 80 updates (160 on an armies level, GameState_IsArmiesLevel 0x0041d110), or at a respawn from the alpha byte passed in over 3 updates (+0xc8 and +0xcc set to 0xFFFFFF00 | alpha first). HUD has the context.

Code index

Every function of the human code in 0x00217a70-0x00288000 (inferred: the range is our grouping, and each row is graded) that the sections above do not walk through, in address order, with what it does. Names are ours, as in the local Ghidra project, where each function also carries a plate comment. Combat functions are indexed on Combat and the crimes' on Crimes.

The human core

0x00217a70-0x00233ef0, around Human.cpp's path string (0x0021c7c8; the range inferred, each row graded): pose writes, fire and hit effects, the grab sound, voice lines and anim sounds, the record's accessors and state-flag tests, the class tables, targets, getting up and the overlay clips. Field offsets are on the human object (above) and the record (above); the pose slot is the human's entry (+0x92) in the task pose table at 0x00714b00, 0x20 bytes each. A human flag is a bit of +0xe0, a state flag one of record +0x00, a held flag one of record +0x08.

Address Name What it does Evidence
0x00217a70 Human_GetClump The human's clump from its render instance (+0xd8), or 0 without one. confirmed (code)
0x00217dd8 Human_ReleaseInstance Knocks the human out, clears state bit 0, releases its dynamic anim slots (+0x3c8) and gives its character instance back to the resource manager. confirmed (code)
0x00219238 Human_StartBurning Sets the burn end time, sets state 0x4000 (burning), starts the fire effect (0x0021adf8), deals health + 1 damage, drops a held kind 4 or 6 object, breaks any pair and says the burning command. confirmed (code)
0x00219320 Human_FindPickupNear Overlap test around the human for world objects it may pick up: skips door leaves and objects it cannot see, then picks up the first that fits. confirmed (code)
0x00219638 Human_ApplyTypeScale Per character type (+0xcc) model scale (for example 1.03 for type 0x21, 0.98 for 0x15); stores it with Human_StoreScale. confirmed (code)
0x00219a28 HazardSphere_Contains True when the human is inside any active fire hazard sphere of the table at 0x0065ff50 (gated by 0x00510170). confirmed (code)
0x00219ad0 Human_IgniteInHazard Sets the human on fire when HazardSphere_Contains says it stands in a fire hazard. confirmed (code)
0x0021ada0 Human_EmptyStub1 Empty function (returns at once); a vtable placeholder. confirmed (code)
0x0021ada8 Human_EmptyStub2 Empty function (returns at once); a vtable placeholder. confirmed (code)
0x0021adb0 Human_StopHeatEffect Stops the heat-distortion effect +0x6c4 and resets it to -1. confirmed (code)
0x0021adf8 Human_StartFireEffect Spawns fire particles on random bones (eight tries) and starts the heat-distortion effect stored in +0x6c4. confirmed (code)
0x0021b048 Human_SetPosition Writes the position into the human's pose slot (0x00714b00 + slot x 0x20) and pushes the pose to the task. confirmed (code)
0x0021b100 Human_SetRotation Writes the quaternion into the pose slot (+0x10) and pushes the pose to the task. confirmed (code)
0x0021b148 Human_PrepareGrabSound Prepares anim sound 0x3c (the grab sound) at the human for the partner's sound handle +0x180, when not already prepared. confirmed (code)
0x0021b1f0 Human_StopGrabSound Stops the prepared grab sound +0x180. confirmed (code)
0x0021b228 Human_StartGrabSound Starts the prepared grab sound +0x180; when it was not prepared plays anim sound 0x3c at the human instead. confirmed (code)
0x0021c080 Human_ClearStrikeContacts Clears the physics body's struck-body contact list when the body exists. confirmed (code)
0x0021c418 Human_CapsuleOverlaps Builds a capsule of the human's height at a pose and asks physics whether it collides with anything; used by a placement check (0x002b8ad8). confirmed (code)
0x0021cce8 Human_Destruct Human destructor: releases speech, effects, the body and the record before the base object destructor. confirmed (code)
0x0021cf20 Human_FreePhysicsBody Destroys the human's physics body +0x1a0 and clears the pointer. confirmed (code)
0x0021cf80 Human_GetHeadLookOffset Rotates the offset +0x500 by the human's orientation; Human_UpdateHeadLook uses it as the look origin. confirmed (code)
0x0021d080 Human_GetPosition The human's position: the carried pose +0x2c0 while grabbed or carried, else the pose slot. confirmed (code)
0x0021d0e0 Human_GetHeading The heading angle of the human's orientation (Quat_Heading on the pose slot). confirmed (code)
0x0021d118 Player_GetMoveHeading The player's stick heading when the stick is pushed past 0.01, else the human's facing (0x00254310). confirmed (code)
0x0021d310 Human_ResetStats Resets the brain, then health, power and stamina from the character class and reapplies the class damage ranges. confirmed (code)
0x0021d530 Human_GetScriptPrompt Returns the prompt of the human's script handler (+0xe8). confirmed (code)
0x0021d550 Human_GetScriptValue Returns the value of the human's script handler (+0xe8). confirmed (code)
0x0021d570 Human_HasScriptHandler True when the script handler (+0xe8) has a handler or the force flag +0x1b2 is set. confirmed (code)
0x0021d848 Human_SetPushable Clears (on) or sets (off) body flag 0x200 and stores the choice in +0x3bf. confirmed (code)
0x0021d880 Human_SpawnParticleAbove Spawns a named particle at the human's feet plus 1 m. confirmed (code)
0x0021d928 Human_SpawnHitEffect A hit on a human: a sub_punch_flash whose blood count comes from the attacker's weapon and the victim's hurt and blocking state; a kind-39 object queues a blur pulse and hint 26 instead (Combat: hit blood). confirmed (code)
0x0021de48 Human_SpawnAnimEffect A clip's type-0x21 effect event: spawns sub_ + its code at the human's bone (bld blood, pch blood or sweat by hurt, blo blood and a decal, and the non-blood codes) (Combat: hit blood). confirmed (code)
0x0021e3a8 Human_GetSoundVolumeScale 1.0, or the combat-framing volume (game state +0x24c) for a player while the camera frames a fight. confirmed (code)
0x0021e940 Human_UpdateSpeech Per update speech: when the line ends, clears speaking state and runs the end callback once; while it plays, moves the stream to the head and faces the partner. confirmed (code)
0x0021ec30 Human_GetSpeechHandle Returns the current speech line handle +0x178. confirmed (code)
0x0021ec38 Human_StopSpeech (human, force): stops the current line when it is alive and either forced or cut-able (+0x194 set); ends the speaking pose, sets +0x194 and +0x195 and drops the queued follow-up (+0x184); never touches the Lua callback, which runs at the next Human_UpdateSpeech (Sound). confirmed (code)
0x0021ed28 Human_SayCopLine Says a cop command line; on success stores a callback hash so the script hears when it ends. confirmed (code)
0x0021ede0 Human_PlayNextVoiceLine Plays the next line of voice bank 0x29 at the human when the shared voice slot 0x005e6d80 is free, and takes that slot. confirmed (code)
0x0021ee50 Human_PlayVoiceByName Hashes a fixed name (0x005d91e0) and plays it through Human_PlayVoiceAt. confirmed (code)
0x0021ee88 Human_PlayVoiceAt Plays a voice line by hash at the human's position into +0x168 unless one is already playing. confirmed (code)
0x0021efb0 Human_UpdateVoicePosition Moves the voice line +0x168 to the human's position; false when none plays. confirmed (code)
0x0021f058 Human_StopVoice Stops the voice line +0x168 when it plays. confirmed (code)
0x0021f0a0 Player_PrepareLine For a player: prepares a line by hash at the human into +0x17c, reusing it when the same hash is already prepared. confirmed (code)
0x0021f1d0 Player_StopPreparedLine For a player: stops the prepared line +0x17c. confirmed (code)
0x0021f208 Player_StartPreparedLine For a player: stops other speech and starts the prepared line +0x17c as the current line +0x178. confirmed (code)
0x0021f290 Human_PlayFootstep Plays the material pair of a material and the ground under the human (+0x1d8, remapped): twice as loud for a player, half when hidden in shadow (Sound). confirmed (code)
0x0021f410 Human_SayAnimLine An anim entry's first sound as a speech line, only when the human may speak; over a playing line only when asked, cutting it when asked (Sound). confirmed (code)
0x0021f548 Human_PlayAnimSound Plays an anim entry of the sound matrix at a point, owned by the human; a player's louder, with extra columns under combat framing (Sound). confirmed (code)
0x0021f700 Human_OnAnimSoundEvent Clip event 11 (message 0x8b): by the anim sound id plays the matrix entry, a footstep or material pair, a speech line or a command (Sound). confirmed (code)
0x00220360 Human_HasIdleDialogLine True when the idle dialogue line for the human's voice, level and line counter exists. confirmed (code)
0x00220430 Human_PlayIdleDialogLine Plays the human's next idle dialogue line and advances its counter. confirmed (code)
0x002207d0 Human_SayObjectLine Says a command about an object unless the game mode is 0xb or the object is one of three types (by hash). confirmed (code)
0x002208f0 Human_SayStateResponse Plays a state response line when the human can speak and the listener is within the line's range less 20 m. confirmed (code)
0x00220df0 Hit_ResolveBlock Decides a hit's outcome: blocking or ducking (or class 13 with flag 4) blocks; else picks a reaction from the attack flags and height difference and plays the impact sound. confirmed (code)
0x00221080 Human_RestoreControl Restores the control function +0x1bc (a member-function pointer: +0x1be -1, +0x1c0 the function) from the copy saved at +0x1c4; with none saved, a human without a brain task gets Human_PlayerLocomotion, others Human_UpdateControl (0x00227c48). Ends the wheelchair's control. confirmed (code)
0x00221a00 Human_GetDynamicAnim Clip for an anim id: an override slot (+0x3c8, 7 x 0x28) else the gang clip table entry of the variant +0x3c4. confirmed (code)
0x00221aa0 Human_SetAnimOverride Puts a clip into one of the seven override slots (+0x3c8) for an anim id, or releases the slot when the clip is 0; marks the state when the current anim is overridden. confirmed (code)
0x00221c20 Human_TurnToFacePoint Heading from the human to a point (Math_Atan2), then Human_TurnToOver over the given time. confirmed (code)
0x00221dd8 Human_FaceHuman Turns the human toward another (or away with the flag) through Human_TurnToOver. confirmed (code)
0x00221ed0 Human_SetCarryMoveStyle Pushes the move style for a carried object kind; on a wheelchair (style 0x14) kinds 4 and 6 go through 0x00253e68; 0 pops it. confirmed (code)
0x002221b0 Human_CanWalkStraightToHuman Human_CanWalkStraightTo on another human's position. confirmed (code)
0x00222370 Human_HasClearRayTo Ray_IsClear from the human's position (eye height added) to a point. confirmed (code)
0x00222508 Human_CanSeePoint A point within range, in the field of view and with a clear ray. confirmed (code)
0x002225d8 Human_MaySpectate For the spectate goal: true unless the brain is a cop; gang members (class type 10) with fewer than three fights, and AI watching a player standing lower than 1.9 m above, may spectate. confirmed (code)
0x002226e0 Human_IsHumanInFieldOfView Human_IsInFieldOfView on another human's position. confirmed (code)
0x00222710 Human_IsInFieldOfView Whether a point is within the human's field of view (cosine of half the angle). confirmed (code)
0x00222868 Human_AddSprayPaint Adds spray cans: an AI keeps its own count +0x374 (0-9); a player's goes to inventory item 4. confirmed (code)
0x00222908 Human_GetCuffCount Handcuffs held: a player's from inventory item 5; an AI with brain type 1 always has one; other AI use +0x378. confirmed (code)
0x00222980 Human_AddCuffs Adds handcuffs: inventory item 5 for a player, else +0x378 clamped at 0. confirmed (code)
0x00222a48 Human_IsThreatTo Whether human b is a threat to human a: Brain_IsThreat on their two brains (gangs enemies, or both pad players; a Warrior's +0x2e5 mode overrides). A test only; Brain_GiveWayTo needs it false both ways (Step control). confirmed (code)
0x00222ad8 Human_GetPadRecord The human's per-player record in the game state (+0x168 + player x 0x5c), or player 0's for an AI. confirmed (code)
0x00222c98 Human_ApplyClassFlags Copies the class record's switches (+0x3a-+0x3f) into the human flags +0xe0 (bits 0x80, 0x1000000000, 0x2000000000, 0x800000000, and the paired bits 0x200000/0x400000 and 0x400/0x200). confirmed (code)
0x00222e40 Human_GetHealth Health, record +0x144 (100 without a record). confirmed (code)
0x00222e60 Human_GetMaxHealth Maximum health, record +0x146 (100 without a record). confirmed (code)
0x00222e80 Human_SetHealthPercentRaw Sets health to a percentage of the maximum, rounded. confirmed (code)
0x00222f48 Human_GetPowerPercent Power +0x148 as a percentage of the maximum power. confirmed (code)
0x00223280 Human_GetStaminaDrain Stamina cost of the current state: blocking, tackling, grabbing with a hold timer, or grabbing (globals 0x005101e4-0x005101f0); 0 for a brainless human when 0x005102a8 is set. confirmed (code)
0x00223348 Human_GetSprintDrain Stamina cost of sprinting (0x005101f4), else 0. confirmed (code)
0x002233a8 Human_GetClassChainDelay Class record byte +0x36 (used by the chain and grab timings). confirmed (code)
0x002233c8 Human_GetClassReactFlag Class record byte +0x38 (read by Human_PlayReaction). confirmed (code)
0x002233e8 Human_ClearPower Sets power +0x148 to 0. confirmed (code)
0x00223400 Human_FillPower Sets power +0x148 to the maximum. confirmed (code)
0x002234f8 Human_BeginTalkPose Moves the talk state +0x1c from an even value to the odd "talking" value when a line starts. confirmed (code)
0x00223548 Human_EndTalkPose Moves the talk state +0x1c back to the even value when a line ends. confirmed (code)
0x002235a0 Human_SetTalkState Sets the talk state +0x1c unless a line is playing (odd value). confirmed (code)
0x00223720 Human_GetStunTime Class stun time +0x30, scaled by +0x10 while hurt. confirmed (code)
0x00223790 Human_GetDownTime Class down time +0x34, scaled by +0x14 while hurt. confirmed (code)
0x002238e0 Human_IsTackled State flag 0x800 (the tackled victim). confirmed (code)
0x00223900 Human_IsTackling State flag 0x400 (tackling, mounted). confirmed (code)
0x00223940 Human_IsGrabbedFromFront State flag 0x10. confirmed (code)
0x00223960 Human_IsGrabbedFromRear State flag 0x20. confirmed (code)
0x002239a0 Human_IsGrabbingFront State flag 0x40. confirmed (code)
0x002239c0 Human_IsGrabbingRear State flag 0x80. confirmed (code)
0x00223a00 Human_HasState2000 State flag 0x2000 (paired attacks and the camera power read it). confirmed (code)
0x00223b98 Human_IsKnockedDown State flag 0x80000, with a record. confirmed (code)
0x00223bc0 Human_IsStunnedStanding Stunned (0x100000) and not knocked down (0x80000). confirmed (code)
0x00223c30 Human_HasHeld300000 Held flags 0x300000 (the taunt and spectate code test it). confirmed (code)
0x00223c50 Human_IsHiddenFromBrain With the player record flag +0x1b set: hidden in shadow and the brain flag +0x2d5 clear. confirmed (code)
0x00223d38 Human_IsBusyForScriptAnim Holds a kind 4 or 6 object, is busy, or has any of the action state flags 0x7bf9e9f7ff0. confirmed (code)
0x00223e48 Human_IsClassType12 Character class type +0x11b is 12. confirmed (code)
0x00223e78 Human_HoldsSet6 The held object's anim set is 6. confirmed (code)
0x00223ea0 Human_HeldIsThrowable Held object anim set 5; set 1 with type 11 (knife); or sets 1-3 for a player or when asked. confirmed (code)
0x00223f58 Human_HeldCanBeThrown Like Human_HeldIsThrowable for the throw velocity: set 5, a knife, or sets 1-3 for a player. confirmed (code)
0x00224080 Human_HeldIsHeavy The held object's anim set is neither 1 nor 5. confirmed (code)
0x002240e8 Human_CanUseAttackKind Whether the human can start attack kind n on a target now: per-kind checks of its own and the target's state flags, held objects, spray paint, cuffs, and the brain's targets for kind 10. confirmed (code)
0x00224ea0 Human_ClassCanFlee Class record byte +0x41 set (read by Brain_Think). confirmed (code)
0x00224ec8 Human_ShouldFleeHurt Class record byte +0x42 set and health under 30 %. confirmed (code)
0x00224fd0 Human_IsFreeForCommand None of the state flags 0x2c01c0f0c00 or held flags 0xc08000. confirmed (code)
0x00225030 Human_IsFreeForSnap Not in a high or mid busy state and neither grabbed from the front nor grabbing. confirmed (code)
0x002250a0 Human_IsMidOrBusy The other is 0.7-1.3 m above (or under -0.7 m), or the human is in an attack phase that blocks a mid attack. confirmed (code)
0x00225200 Human_IsHighOrBusy The other is 1.3-1.8 m above (or under -0.7 m), or the human is in a grab or attack phase that blocks a new attack. confirmed (code)
0x00225390 Human_IsIdleUnderControl Under Human_UpdateControl or the step control with no state 0x7bf9e1f3ff0 and no held flag; the stander test of Brain_GiveWayTo (Step control). confirmed (code)
0x00225500 Human_IsNotDown Not in states 0xe0000. confirmed (code)
0x002256a0 Human_CanBeGrabbed Whether the human may be grabbed or tackled by another: not down or in a scene, within 0.25 m of height, and none of the blocking state or held flags. confirmed (code)
0x00225998 Human_IsAtRunSpeed Running or sprinting and moving at the run speed (less 0.01). confirmed (code)
0x00225f58 Human_IsFreeForFidget No held flags, no action state flags and nothing held: the fidget and taunt actions may start. confirmed (code)
0x00225fc8 Human_SetCarriedItemName Copies an item name into the human's 31-character buffer +0x257 and clears +0x276. confirmed (code)
0x002262f0 Human_CallMugCallback Calls the script's mug callback (HuSetMugCallback, +0x5a4) with the human's handle and the outcome, through the script system 0x00512b04. confirmed (code)
0x002265d0 Human_SetStateFlag Record +0x00 |= bits. confirmed (code)
0x00226620 Human_ClearStateFlag Record +0x00 &= ~bits. confirmed (code)
0x00226688 Human_ClearHeldFlag Record +0x08 &= ~bits. confirmed (code)
0x002266d8 Human_GetAttackerHandle Writes the attacker handle for the attack table: record +0xc0 when it resolves, else the human's own handle. confirmed (code)
0x002267c8 Human_ClearFoe Record +0xcc = null. confirmed (code)
0x002267e8 Human_SetLastHitObject Records the world object that hit the human (record +0xd0 handle, +0x124 type, +0x11c position); an object of kind 8 sets it on fire and gives the foe player combat statistic 6. confirmed (code)
0x00226910 Human_SetPartner Record +0xc8 = another human's handle. confirmed (code)
0x00226950 Human_GetPartner Record +0xc8 resolved. confirmed (code)
0x00226978 Human_ClearPartner Record +0xc8 = null. confirmed (code)
0x00226998 Human_SetGrabOther Record +0xc4 = the other human of a grab. confirmed (code)
0x002269d8 Human_GetGrabOther Record +0xc4 resolved, the other human of a grab. confirmed (code)
0x00226a00 Human_ClearGrabOther Record +0xc4 = null. confirmed (code)
0x00226a20 Human_GetHeadPoint The upper point of the human's capsule segment: feet + +0x4e8 - 0.16 x scale. confirmed (code)
0x00226aa0 Human_GetLedSlotPoint Aim point n (+0x1e0 + n x 0x10) after refreshing them (0x0023cd30); point 0, the head, is the led attack steer's target (Combat: the led steer). Not a formation. confirmed (code)
0x00226af8 Human_SetTargetFromHandle Sets the target from a handle: a player sets its own human or object target; an AI sets the brain's target and +0x128; skipped while a player with record flag +0x1b is locked on. confirmed (code)
0x00226e20 Human_GetTargetHandle The target handle +0xc8, refreshed from the brain first for an AI. confirmed (code)
0x00226ea8 Human_GetTargetResolved The target +0xc8 resolved, refreshed from the brain first for an AI. confirmed (code)
0x00226ee8 Human_SyncTargetFromBrain Copies the brain's object target (+0x128) and human target into the human's targets. confirmed (code)
0x00227010 Human_SetHeldObject Stores the held object's handle in +0x338 (null for none). confirmed (code)
0x00227060 Human_GetObjectTarget +0x33c resolved (door, flag, lock). confirmed (code)
0x002270d0 Human_CanPickUpType For class kind 3, false for types 0x29, 0x2b, 0x2d and 0x31-0x36; other classes may pick up an item unless their class list (+0x14c) excludes it. confirmed (code)
0x002271c0 Human_ResetRenderState Clears the render instance's flag +0x2b and resets it (0x004df008); used when a preview or flag human is shown again. confirmed (code)
0x00227408 Human_HasOverheadIcon The overhead icon +0x360 resolves. confirmed (code)
0x00227428 Human_HasOverheadIconType True when the overhead icon +0x360 is a world object of the given type. confirmed (code)
0x002274a0 Human_EmptyStub3 Empty function called by Human_StateUpdate. confirmed (code)
0x00227738 Humans_FindNear Collects up to n humans of the game state's list (+0x224, +0x228) within a radius of a point, skipping one human and an optional filter; distances squared go beside each. confirmed (code)
0x002278a8 Humans_FindNearSegment Finds humans whose pose slot lies near a segment (Segment_ClosestPoint), skipping one; used by Route_IsJumpLegClear (AI: Giving way). confirmed (code)
0x00227a38 Human_IsButtonTapControl State flag 0x100000000000 (button-tap movement, Human_SetButtonTapControl). confirmed (code)
0x00227a60 Human_IsInWheelchair State flag 0x80000000000 (wheelchair control). confirmed (code)
0x00227b78 Human_SetFightStanceControl Control function +0x1bc = Human_FightStanceMove (lock-on). confirmed (code)
0x00227c28 Human_SetAirControl Control function +0x1bc = Human_AirControl (jumps). confirmed (code)
0x00227c48 Human_SetUpdateControl Control function +0x1bc = Human_UpdateControl, the default. confirmed (code)
0x00227c68 Human_HasTarget State flag 0x4. confirmed (code)
0x00227c88 Human_IsLocked State flags 0x8 and 0x4 (the L1 lock). confirmed (code)
0x00227e18 Human_HasStateFlag80000000 State flag 0x80000000 (true without a record). confirmed (code)
0x00227fb8 Human_IsOnFire State flag 0x4000. confirmed (code)
0x00228000 Human_IsWorkingOut State flag 0x20000000000 (the workout). confirmed (code)
0x00228028 Human_IsInSpecial State flag 0x40000000000 (a special move, Human_StopSpecial). confirmed (code)
0x00228070 Human_IsMugging State flag 0x100. confirmed (code)
0x00228090 Human_IsBeingMugged State flag 0x200. confirmed (code)
0x002280b0 Human_HasState8000000 State flag 0x8000000 (read by the death and lethal reactions). confirmed (code)
0x002280d0 Human_HasState10000000 State flag 0x10000000 (read by the lethal reaction and AI). confirmed (code)
0x002280f0 Human_IsInMugMeter State flags 0x18000000000 (the mug meter shows). confirmed (code)
0x00228118 Human_HasState8000000000 State flag 0x8000000000 (read with holds and pair breaks). confirmed (code)
0x00228140 Human_HasState10000000000 State flag 0x10000000000 (read with pair breaks). confirmed (code)
0x00228188 Human_IsStalkingTarget State flags 0x8 and 0x200000. confirmed (code)
0x002281d8 Human_IsThrowingAt State flags 0x1000 (throwing) and 0x200000; brains treat it as an attack warning. confirmed (code)
0x00228258 Human_IsBusy State flags 0x1f80974000, or record +0x108 still ahead of the game time. confirmed (code)
0x002282d8 Human_IsFree No held flags 0x2fefefff and no state flags 0x7bf9e9f7ff0. confirmed (code)
0x00228360 Human_HasState800000 State flag 0x800000 (read when pending damage applies). confirmed (code)
0x002283a8 Human_ClearDownLatch Clears state flag 0x40000000. confirmed (code)
0x002283c8 Human_HasDownLatch State flag 0x40000000 (down; read by the corpse cull). confirmed (code)
0x002283e8 Human_HasHeld400000 Held flag 0x400000 (an airborne body; car and thrown hits read it). confirmed (code)
0x00228408 Human_HasHeld4000 Held flag 0x4000 (picking up an item). confirmed (code)
0x00228448 Human_HasHeld20080000 Held flags 0x20080000: a turn clip (0x20000000) or a step clip (0x80000) plays; TakeStep waits on it and refuses an abort (Step control). confirmed (code)
0x00228468 Human_HasHeld8000000 Held flag 0x8000000 (reviving). confirmed (code)
0x00228500 Human_HasHeld20000000 Held flag 0x20000000 (turning). confirmed (code)
0x00228520 Human_HasHeld100 Held flag 0x100 (a fidget plays). confirmed (code)
0x00228540 Human_HasHeld20000 Held flag 0x20000. confirmed (code)
0x00228630 Human_SetState20000000 Sets state flag 0x20000000 (the victim just before a tackle hit). confirmed (code)
0x00228658 Human_GetLastHitObject Record +0xd0 resolved: the world object that last hit the human. confirmed (code)
0x00228680 Human_GetLastHitObjectHandle Record +0xd0 as a handle (null without a record). confirmed (code)
0x002286a0 Human_IsSwingingHeld Held flag 0x800000, or 0x1000010 while holding an object and playing one of the eleven object throw clips (467, 471, 472, 491, 502, 505-507, 551-553; a throw wind-up, not a melee swing). A hit drops the held object while it is true (Combat: dropping what is held). confirmed (code)
0x002287e0 Humans_StaticInitAll Static initialiser: Humans_StaticInit(1, 0xffff). confirmed (code)
0x00228818 SpeedClass_Get Speed class record 0x006b6548 + class x 0x18. confirmed (code)
0x00228830 PowerClass_Get Power class record 0x006619a0 + class x 0x44. confirmed (code)
0x00228848 WarriorClass_Get Warrior class record 0x006b65c0 + class x 14. confirmed (code)
0x002288c0 Cfg_SetPowerClass CfgPowerClass: fills a power class record. confirmed (code)
0x00228a70 Cfg_SetWarriorClass CfgWarriorClass: fills a Warrior class record. confirmed (code)
0x00228ad8 Cfg_SetWarriorUpgrade CfgWarriorUpgrade: four bytes at 0x006b6650. confirmed (code)
0x00228ca8 Cfg_SetAttackDelay CfgAttackDelay: one word per attack at 0x006b6658. confirmed (code)
0x00228cc0 HatSet_Reset Clears a hat-fit set's owner and names its 48 slots none. confirmed (code)
0x00228e68 HatSet_FindSlot Index of the slot named as an object type in a hat-fit set, or -1. confirmed (code)
0x00228ed0 HatSet_SetSlotName Writes a slot's 23-character name in a hat-fit set. confirmed (code)
0x00228f08 HatSet_HasOwner True when one of the 51 hat-fit sets is owned by the character type. confirmed (code)
0x00229110 Anim_LevelVariant Maps an anim id to a level's own variant for ten levels (by the current level id), else 0. confirmed (code)
0x002294c8 Humans_ResetClassTables At start-up: clears the power classes' in-use bytes (+0x43) and resets all hat-fit sets. confirmed (code)
0x00229550 Humans_StaticInit Humans_ResetClassTables(1, 0xffff). confirmed (code)
0x00229570 Human_GetPortraitKind The crew-portrait kind for the character id +0xcc (kinds 0-11). confirmed (code)
0x00229620 Human_DropOverlayTask Removes a type-5 top task, turns every strike shape off and clears the combo count +0xbc. confirmed (code)
0x002296c0 Task_SendMessage28 Sends message 28 (a handle and a point) to a task, stamping a type-2 object's time +0x50 one frame back. confirmed (code)
0x00229770 Task_SendMessage4 Sends message 4 (int, float, int, int) to a task. confirmed (code)
0x00229820 Object_AsKind40 The object when its kind flags (vtable +0x24) include 0x40, else 0. confirmed (code)
0x002298b8 Human_DistanceSq Squared distance between two objects' positions (0 if either is null). confirmed (code)
0x00229aa8 Human_DistSqToLedSlot Squared distance from an object to a led formation's slot point. confirmed (code)
0x0022a980 Player_UnbindPad Unbinds a player's pad slot from the HUD and raises the pad-error message. confirmed (code)
0x0022aa78 Player_BindPad Binds the human as a player on a pad: player record +0x19 = pad, +0x1b set when asked. confirmed (code)
0x0022aae8 Human_SimulateMove Simulates a walk toward a heading at a trial speed (gait turn rates), giving the end point; route tests use it. confirmed (code)
0x0022ae30 Human_ScaleTurnRate Multiplies by the turn-rate factor 0x005102cc. confirmed (code)
0x0022c618 Human_ClearState8000000 Clears state 0x8000000, restores push weight and puts the human down when knocked down. confirmed (code)
0x0022d2d8 Human_BeginSpecialState Sets state 0x40000000000 and starts the special (0x002349a0). confirmed (code)
0x0022d310 Human_EndSpecialState Clears state 0x40000000000 and ends the special (0x00234b30). confirmed (code)
0x0022d348 Human_StartWorkout Sets state 0x20000000000 and calls the workout start callback. confirmed (code)
0x0022d380 Human_EndWorkout Clears state 0x20000000000, stops the workout clip and calls the end callback. confirmed (code)
0x0022dd08 Human_GetClassSpinAngle 2 pi, or (n - 1) x 6 pi for a Warrior class byte +0xb above 1. confirmed (code)
0x0022f3c8 Human_GetUp Ends being down unless dead or knocked out: restores push weight, pops the down styles (0xe, 0xf); a stunned human (0x100000) goes to style 0xe with a fresh stun timer, else into the fight stance; clears 0x4000080000. confirmed (code)
0x0022f4f8 Human_SetDownTimers Sets the down end time (record +0x104, class down time, doubled by an attack with anim flag 0x100, +2 s from a class-13 attacker) and the stun end +0x100 (doubled by anim flag 0x200); stuns when asked and not already stunned. confirmed (code)
0x0022f9e0 Human_SetStunTimer Sets the stun end time record +0x100 from the class stun time, doubled by an attack with anim flag 0x200. confirmed (code)
0x0022fa78 Human_StartWounded Clears the fight states, drops what is held, pushes the wounded style and tells the brain the human is knocked out. confirmed (code)
0x0022fc00 Human_EndWounded Clears state 0x10000, restores push weight and pops the wounded style (0xd). confirmed (code)
0x0022fce8 Human_Ignite Sets the human burning (Human_StartBurning) unless fireproof, down, in a scene or busy; AI catch fire only when walking, jogging or running. confirmed (code)
0x0022fe10 Human_Extinguish Clears state 0x4000, the burn time and the heat effect. confirmed (code)
0x0022fe48 Human_EnterFightStance Starts the stance timer and sets state 0x1. confirmed (code)
0x0022fed0 Human_LeaveFightStanceThunk Calls Human_LeaveFightStance. confirmed (code)
0x002300c0 Human_LeaveShadow When hidden (0x200000), not running and with a target, clears the hidden state. confirmed (code)
0x002301f0 Player_UpdateHiddenLoopSound For a player: prepares the hidden-in-shadow loop line when hidden, stops it when not. confirmed (code)
0x002302a8 Human_ResetToOneHealth Unless dead: knocks off the hat, clears flag 0x10, sets the counters +0x118 and +0x5d2 to 100, clears the foe and sets health to 1. confirmed (code)
0x00230598 Human_WakeUp Wakes a knocked-out human: body back on, state cleared, styles popped, the cuffs icon removed, brain resumed. confirmed (code)
0x002306e8 Human_ReleaseBody Stops speech, clears the brain's enemies, clears the pose-slot entry at 0x00715390 and frees the physics body. confirmed (code)
0x00230740 Human_CreditDefeat When a human is beaten: credits the foe player (combat statistic 7 for a gang brain, crime statistics for others), tears down the brain, removes it from the radar and its overhead icon. confirmed (code)
0x00231ac8 Human_PlayHeldIdle Plays a held-object idle clip (0x25a for a knife, 0x25c when asked) when no held flags are set. confirmed (code)
0x00231b60 Human_StopFidget With a fidget playing (held 0x100): drops the overlay while moving, else rebuilds the idle tasks. confirmed (code)
0x00231bd8 Human_PlayLookAround Pushes overlay clip 0x29e with held flag 0x20000 when free. confirmed (code)
0x00231c20 Human_StopLookAround Drops the overlay while held flag 0x20000 is set. confirmed (code)
0x00231c58 Human_StopTaunt With held flags 0x300000: drops the overlay while moving, else rebuilds the idle tasks. confirmed (code)
0x002320a0 Human_CanPush Whether one human pushes another on contact, by their stances and states (from Human_OnPushContact). confirmed (code)
0x002323d0 Humans_DestroyAll At level unload: flushes deferred anim tasks and destroys every human handle. confirmed (code)
0x00232430 Human_GetClipTimeLeft Time left in the top clip, or in the one under it (at least 0.1 s) when the top has ended. confirmed (code)
0x00232538 Humans_EndAllRage Ends rage mode for every human in rage (flag 0x80000). confirmed (code)
0x00232b78 Human_CancelThrowAim Leaves throw aiming when the control function is Human_MoveThrowAim. confirmed (code)
0x00233830 Human_CopRadioChatter For a cop brain, every 360 updates plays the next radio voice line. confirmed (code)
0x00233890 Human_SayGoalLine Speaks the line for an AI goal event: commands or cop lines chosen by the event and the level. confirmed (code)
0x00233b08 Human_SwapHeldObjects Swaps two humans' held objects, each picking up the other's with its pickup clip. confirmed (code)
0x00233c40 Cfg_SetAutoCloseMode CfgAutoCloseMode: sets 0x00510228. confirmed (code)

Script functions

The engine side of the Hu* and Cfg* script functions (0x00233ef0-0x0023b838, inferred from where the rows lie; each row is graded); each row names its script function. A setter with a flag turns that bit of the human flags +0xe0 on or off; a Cfg* setter writes one global the human code reads.

Address Name What it does Evidence
0x00233ef0 Human_Delete Marks the human dead (0x200000000), clears its foe and its script handlers. confirmed (code)
0x00233f60 Human_SwapPlayerControl Moves player control from one human to another, swapping their camera targets. confirmed (code)
0x00234038 Human_SetNoTarget Human flag 0x100000000000 on or off: the human cannot be targeted. confirmed (code)
0x002340a8 Human_SetNoAutoLock Human flag 0x8000000000 on or off: no automatic lock-on. confirmed (code)
0x00234118 Human_SetAutoCombat Human flag 0x200000000000 on or off. confirmed (code)
0x00234318 Human_SetButtonTapControl Puts the human under button-tap movement (or back): saves control, swaps the commands and sets the state. confirmed (code)
0x00234530 Cfg_SetWorkoutParams Fills the workout parameter tables at 0x00510690-0x005106b0. confirmed (code)
0x002345d8 Human_SetWorkoutParams Sets three workout values at 0x00510680. confirmed (code)
0x002345f8 Human_SetWorkoutCallbacks Interns the workout start, rep and end Lua callbacks. confirmed (code)
0x002346a0 Workout_CallStart Calls the workout start callback with the human. confirmed (code)
0x00234768 Workout_CallRep Calls the workout repetition callback with the human. confirmed (code)
0x00234830 Workout_CallEnd Calls the workout end callback with the human. confirmed (code)
0x002348f8 Human_SetSpecialCallbacks Interns the special-move start, step and end Lua callbacks. confirmed (code)
0x002349a0 Special_CallStart Calls the special start callback with the human. confirmed (code)
0x00234a68 Special_CallStep Calls the special step callback with the human. confirmed (code)
0x00234b30 Special_CallEnd Calls the special end callback with the human. confirmed (code)
0x00234bf8 Human_StartSpecial Script: puts a clip on anim 0x2a0 and starts the special action. confirmed (code)
0x00234cb0 Human_StopSpecial Script: ends a running special with action 0x1e. confirmed (code)
0x00234d08 Human_SetAccurate HuSetAccurate: human flag 0x40000 on or off. confirmed (code)
0x00234d70 Human_MakeBeatUp Script: holds the brain and knocks the human down lying, dropping what it holds. confirmed (code)
0x00234e58 Human_MakeGrounded Script: lays the human down, or lifts the down latch. confirmed (code)
0x00234ef8 Human_SetLockMovement HuLockMovement: human flag 0x200000000 on or off; the rumble menus use it on preview fighters. confirmed (code)
0x00234f68 Human_GetHandleByIndex HuGet: the handle of human n, or null. confirmed (code)
0x00234fb8 Human_GetPlayerHandle HuGetPlayer: the handle of the game state's human n. confirmed (code)
0x00235010 Human_FindByName HuFind: the first human whose name matches. confirmed (code)
0x002350c8 Human_SetTireless Human flag 0x4000000 on or off. confirmed (code)
0x00235130 Human_SetManualStun Human flag 0x8000000 on or off. confirmed (code)
0x00235198 Human_SetNoReact Human flag 0x800 on or off. confirmed (code)
0x00235200 Human_SetAutoEscape HuSetAutoEscape: human flag 0x20000 on or off. confirmed (code)
0x00235268 Human_SetPushable HuSetPushable: resolves the handle and calls the human's pushable setter (0x0021d848). confirmed (code)
0x002352b0 Human_GetPositionRef HuGetPosition: the human's position, or the zero vector 0x005116c0. confirmed (code)
0x002352f8 Human_GetHeadingDegrees HuGetHeading: the heading of the pose-slot rotation, from an arctangent approximation. confirmed (code)
0x00235478 Human_GetGangType HuGetGangType: the brain's gang (+0x20c), -1 without a human. confirmed (code)
0x002354b8 Human_SetStunned HuSetStunned: stuns the human or ends the stun. confirmed (code)
0x00235530 Human_GetHat HuHasHat: the handle of the worn hat +0x364, or null. confirmed (code)
0x002355a0 Human_SetStrong HuSetStrong: byte +0x3b9. confirmed (code)
0x002355e0 Human_IsGrabbed HuIsGrabbed: any of state flags 0x830 (grabbed from the front or rear, tackled). confirmed (code)
0x00235628 Human_IsAlive HuIsAlive: not down or dead and up. confirmed (code)
0x00235688 Human_IsDead HuIsDead: dead (true without a human). confirmed (code)
0x002356c8 Human_IsInScene HuIsInScene: in a scene state. confirmed (code)
0x00235718 Human_IsArrested HuIsArrested: cuffed. confirmed (code)
0x00235758 Human_IsPlayer HuIsAPlayer: player index +0x1b0 is not -1. confirmed (code)
0x00235798 Human_IsHidden HuIsHidden: the brain's hidden byte +0x2d4. confirmed (code)
0x002357d8 Human_IsMuggedByHandle HuIsMugged: being mugged. confirmed (code)
0x00235818 Human_IsProne HuIsProne: in states 0xe0000 or 0x2000. confirmed (code)
0x00235890 Human_GetCharType HuGetCharType: the character type +0xcc. confirmed (code)
0x002358c8 Human_SetDamage HuSetDamage: queues pending damage from an attacker's held object. confirmed (code)
0x002359a0 Human_SetDemiGodMode HuSetDemiGodMode: human flag 0x20000000000 and the minimum health 0x0051024c. confirmed (code)
0x00235a28 Human_SetGodMode HuSetGodMode: human flag 0x10; the tired goal also uses it. confirmed (code)
0x00235a88 Human_SetKillerMode HuSetKillerMode: human flag 0x20. confirmed (code)
0x00235ae8 Human_SetUntouchable AI only (two goal functions): human flags 0x2c0 together (ungrabbable, ungroundable, reduced reactions). confirmed (code)
0x00235b68 Human_SetFastClimber HuSetFastClimber: a human flag on or off. confirmed (code)
0x00235bc8 Human_SetUngrabbable HuSetUngrabbable: human flag 0x40. confirmed (code)
0x00235c28 Human_SetUngroundable HuSetUngroundable: human flag 0x80. confirmed (code)
0x00235c88 Human_SetUnstunnable HuSetUnstunnable: human flag 0x100. confirmed (code)
0x00235ce8 Human_SetIncreasedReact HuSetIncreasedReact: human flag 0x200000. confirmed (code)
0x00235d50 Human_SetReducedReact HuSetReducedReact: human flag 0x200. confirmed (code)
0x00235db0 Human_SetRevivable HuSetRevivable: a human flag on or off. confirmed (code)
0x00235e10 Human_SetDoubleDamage HuSetDoubleDamage: human flag 0x4000. confirmed (code)
0x00235e70 Human_SetUnarrestable HuSetUnarrestable: human flag 0x8000, removing a pending arrest prompt. confirmed (code)
0x00235f10 Cfg_SetClimbWithGhetto CfgClimbWithGhetto: sets 0x00510250. confirmed (code)
0x00235f20 Human_SetOnFire HuSetOnFire: ignites or extinguishes the human. confirmed (code)
0x00235f80 HumanHandle_IsOnFire HuIsOnFire: state 0x4000. confirmed (code)
0x00235fc0 Human_SetFireProof HuSetFireProof: human flag 0x800000, extinguishing when set. confirmed (code)
0x002360f8 Human_ScriptDrop HuDrop: knocks off the hat, drops the held object and gear as asked. confirmed (code)
0x00236188 Human_SetUnlockedGear HuAttachGear: attaches or removes the unlocked gear. confirmed (code)
0x002361e8 Cfg_SetGearData CfgGearData: fills the gear transforms at 0x00715480. confirmed (code)
0x00236420 Cfg_SetButtonHeldFrames CfgButtonHeldFrames: frames for a held button, clamped to 2-7 (0x0050b708). confirmed (code)
0x00236450 Cfg_SetGrabCounterWithAttack CfgGrabCounterWithAttack: sets 0x00510254. confirmed (code)
0x00236460 Cfg_SetPlayerRunButton CfgPlayerRunButton: sets 0x00510258. confirmed (code)
0x00236470 Cfg_SetStickDeflection CfgStickDeflection: sets 0x005102e8. confirmed (code)
0x00236480 Cfg_SetPlayerCombatWalkOnly CfgPlayerCombatWalkOnly: sets 0x0051031c. confirmed (code)
0x00236490 Cfg_SetQueueGrappleCombos CfgQueueGrappleCombos: sets 0x0051025c. confirmed (code)
0x002364d8 Cfg_SetAttackFromIdle CfgAttackFromIdle: sets 0x00510270. confirmed (code)
0x002364e8 Cfg_SetDamageEndurance CfgDamageEndurance: sets 0x00510274. confirmed (code)
0x002364f8 Cfg_SetPowerEndurance CfgPowerEndurance: sets 0x00510278. confirmed (code)
0x00236978 Human_ForceEnableReticule HuForceEnableReticule: sets 0x005104f8. confirmed (code)
0x002369b8 Human_SetRageFrac HuSetRageFrac: sets the rage meter to a fraction of its maximum. confirmed (code)
0x00236a68 Human_SetFullRage HuSetFullRage: fills the rage meter. confirmed (code)
0x00236ad0 Human_SetPreventRage HuSetPreventRage: human flag 0x2000000. confirmed (code)
0x00236b38 Human_SetLockedRage HuSetLockedRage: human flag 0x100000 and the rage meter held where it is. confirmed (code)
0x00236be0 Rage_ResetConfig At level unload: clears the stereo, lock-pick and rage handlers and the rage handler table 0x006b6810. confirmed (code)
0x00236c28 Cfg_SetRagePoints CfgRagePoints: three values at 0x005108d8-0x005108e4. confirmed (code)
0x00236c48 Cfg_SetRagePowerMode CfgRagePowerMode: sets 0x00510298. confirmed (code)
0x00236c58 Cfg_SetRageHandlers CfgRageHandlers: interns the rage Lua handlers (0x00510290, 0x00510294, table 0x006b6810). confirmed (code)
0x00237128 Human_SetRageMode HuSetRageMode: starts or ends rage (human flag 0x80000) for a player. confirmed (code)
0x002371d8 Human_SetBlurMode HuSetBlurMode: a player's screen blur (0x0051029c). confirmed (code)
0x002372a8 Human_GiveCuffs HuGiveCuffs: adds handcuffs (inventory item 5 for a player). confirmed (code)
0x00237328 Human_SetKeepWeapon HuSetKeepWeapon: human flag 0x2000; Diego's boss goal uses it. confirmed (code)
0x00237388 Human_SetKeepHat HuSetKeepHat: human flag 0x10000000000. confirmed (code)
0x002373f8 Human_SetHardToStun HuSetHardToStun: human flag 0x1000000000. confirmed (code)
0x00237468 Human_SetNoThrowWeapon HuSetNoThrowWeapon: human flag 0x4000000000. confirmed (code)
0x002374d8 Human_SetNoEscape HuSetNoEscape: human flag 0x2000000000. confirmed (code)
0x00237548 Human_SetCanBlockKD HuSetCanBlockKD: human flag 0x400000000. confirmed (code)
0x002375b8 Human_SetBlockFromReact HuSetBlockFromReact: human flag 0x800000000. confirmed (code)
0x00237628 Human_SetWounded HuSetWounded: starts or ends the wounded state. confirmed (code)
0x002376a0 Human_SetWoundable HuSetWoundable: a human flag on or off. confirmed (code)
0x00237700 Human_SetArrested HuSetArrested: arrests or frees the human (Crimes); the bum goal uses it too. confirmed (code)
0x00237778 Human_SetConscious HuSetConscious: knocks out or wakes the human. confirmed (code)
0x002377f8 Human_Revive HuRevive: revives the human. confirmed (code)
0x00237848 Human_SetHealth HuSetHealth: health +0x144, at most the maximum. confirmed (code)
0x002378a8 Human_SetHealthPercent HuSetHealthPercent: health as a percentage of the maximum. confirmed (code)
0x00237958 Human_SetBlockJump HuBlockJump: human flag 0x10000000. confirmed (code)
0x002379c0 Human_SetBlockClimb HuBlockClimb: human flag 0x20000000. confirmed (code)
0x00237a28 Human_BlockGrab HuBlockGrab: human flags 0xc0000000 (both grabs). confirmed (code)
0x00237a98 Human_SetBlockFrontGrab HuBlockFrontGrab: human flag 0x40000000. confirmed (code)
0x00237b00 Human_SetBlockRearGrab HuBlockRearGrab: human flag 0x80000000. confirmed (code)
0x00237b70 Human_SetBlockTackle HuBlockTackle: human flag 0x100000000. confirmed (code)
0x00237be0 Human_SetMaxHealth HuSetMaxHealth: maximum health +0x146, and health with it. confirmed (code)
0x00237c38 Human_GetHealthPercent HuGetHealthPercent: health as a percentage of the maximum. confirmed (code)
0x00237c78 Human_SetMass HuSetMass: the body's mass. confirmed (code)
0x00237d08 Human_GetHeldObjectType HuWhatAmIHolding: the held object's type. confirmed (code)
0x00237d48 Human_GetHeldObject HuGetHeldObject: the held object's handle, or null. confirmed (code)
0x00237db8 Human_IsInCombat HuInCombat: whether the human fights. confirmed (code)
0x00237e00 Human_SetIdleAnim HuSetIdleAnim: overrides the idle clip. confirmed (code)
0x00237e70 Human_Kill HuKill: kills the human. confirmed (code)
0x00238030 Human_SetShadow HuShadow: the render instance's shadow switch (+0x2b4). confirmed (code)
0x00238078 Human_SetName HuSetName: the human's name. confirmed (code)
0x002380c0 Human_GetControlName HuGetControlName: the name of the control the human is under. confirmed (code)
0x00238158 Human_GetMoney HuGetMoney: money +0x370. confirmed (code)
0x002381f0 Human_RemoveItemInPocket HuRemoveItemInPocket: clears the pocket item (+0x250, +0x254). confirmed (code)
0x00238230 Human_SetCarriedItemName HuSetCarriedItem: the carried item name (+0x278). confirmed (code)
0x00238288 Human_CanSee HuCanSee: whether the human sees another. confirmed (code)
0x002383a0 Human_SetLOSRange HuSetLOSRange: sight range +0x130. confirmed (code)
0x002383e8 Human_SetHearRange HuSetHearRange: hearing range +0x134. confirmed (code)
0x00238430 Human_SetHelpHearRange HuSetHelpHearRange: the range for hearing calls for help +0x138. confirmed (code)
0x00238478 Human_ExitWorld HuExitWorld: takes the human out of the world. confirmed (code)
0x002384f8 Human_EnableController HuEnableController: the player record flag +0x1b (pad control on or off). confirmed (code)
0x002385f8 Human_PlaceHatOnHead HuPlaceHatOnHead: puts a hat object on the human's head. confirmed (code)
0x00238640 Human_SetPedReaction HuSetPedReaction: the pedestrian reaction +0x270. confirmed (code)
0x00238690 Human_UseAnim Plays an anim by id on the human (scripts and many AI goals). confirmed (code)
0x00238748 Human_UseAnyAnim HuUseAnyAnim: plays any clip by name. confirmed (code)
0x002387a8 Human_AreActionsBlocked HuAreActionsBlocked: whether the human cannot act. confirmed (code)
0x002387e8 Human_IsTagging HuIsTagging: state 0x2000000. confirmed (code)
0x00238828 Human_PlayDynPair HuPlayDynPair: a paired dynamic clip on two humans; the dealer goal uses it to sell. confirmed (code)
0x00238948 Human_PlayDynAnim HuPlayDynAnim: a dynamic clip on the human. confirmed (code)
0x002389e8 Human_PlayDynamicAnim HuPlayDynamicAnim: a dynamic clip by name. confirmed (code)
0x00238a88 Human_AttachSpinningIcon HuAttachSpinningIcon: the spinning icon over the human (+0x360); AI crime and dealer goals use it. confirmed (code)
0x00238ae0 Human_RemoveSpinningIcon HuRemoveSpinningIcon: removes it. confirmed (code)
0x00238b18 Human_SetSpinningIconColor HuSetSpinningIconColor: messages the icon's colour. confirmed (code)
0x00238bd8 Human_StartWorkout HuWorkout: starts a workout on the human (Human_StartWorkout state, start callback). confirmed (code)
0x00238cd8 Human_SetWorkoutBlend HuSetWorkoutBlend: the workout blend +0x670. confirmed (code)
0x00238d30 Human_StopWorkout HuStopWorkout: ends the workout and its clip. confirmed (code)
0x00238f10 Cfg_SetTagStartCallback CfgTagStartCallback: interns the tag-start Lua callback (0x006b6870). confirmed (code)
0x00239080 Human_SetTagColour HuTagColor: the tag colour +0x640. confirmed (code)
0x00239188 Tag_SetPattern HuTagPattern: the tag's button pattern. confirmed (code)
0x002391a8 Human_SetTagDifficulty HuTagDifficulty: the three tag difficulty values 0x0051093c-0x00510944. confirmed (code)
0x002391c0 Human_SetIdleDialogMaxIter HuSetIdleDialogMaxIter: the idle-dialogue line count +0x197. confirmed (code)
0x00239200 Human_EnableSpeaking HuEnableSpeaking: switch +0x198. confirmed (code)
0x00239240 Human_EnableSoundCommands HuEnableSoundCommands: switch +0x199, which every speech path checks. confirmed (code)
0x00239280 Human_EnableOnFireSpeech HuEnableOnFire: the on-fire speech switch +0x19b. confirmed (code)
0x002392c0 Human_EnableTagDoneSpeech HuEnableTagDone: the tag-done speech switch +0x19a. confirmed (code)
0x00239300 Human_EnableTagCheer HuEnableTagCheer: the tag-cheer switch +0x19c. confirmed (code)
0x00239340 Human_Say HuSay: Human_Speak with the default arguments. confirmed (code)
0x00239370 Human_Speak HuSpeak: plays a named speech line on the human with an optional Lua end callback (interned through the script system). confirmed (code)
0x00239558 Human_ShutUp HuShutUp: stops the human's line; the roof boss banter uses it. confirmed (code)
0x002395a0 Human_SpeakInterrupt HuSpeakNI: the variant of HuSpeak that Human_ActionDialog and AI dialogue call. confirmed (code)
0x00239788 Human_ActionDialog HuActionDialog: a line spoken to a partner (+0x18c), whom the speaker faces. confirmed (code)
0x00239850 Human_GetHUD HuGetHUD: the HUD slot of the human's player (+0x380). confirmed (code)
0x00239888 GameState_SetWarChiefHUD HuSetWarChiefHUD: the game state's war-chief HUD switch. confirmed (code)
0x002398b0 Human_SetWarChief HuSetWarChief: makes the human the war chief (the commanding player), re-binding player slots; GameState_SyncPlayers uses it. confirmed (code)
0x00239e08 GameState_SwitchPlayer HuSwitchPlayer: switches the controlled player in the game state. confirmed (code)
0x00239e30 Human_MarkReachable HuMarkReachable: byte +0x11e. confirmed (code)
0x00239e78 Human_SetMugCallback HuSetMugCallback: interns the mug Lua callback into +0x5a4 (Crimes). confirmed (code)
0x00239ee0 Human_SetMug HuSetMug: the mug settings +0x5b0. confirmed (code)
0x0023a058 Human_TeleportFollowers HuTeleportFollowers: moves the human's gang followers (brain +0x20c) to it. confirmed (code)
0x0023a210 Human_SetNormalMode HuSetNormalMode: clears the special modes; AI goals use it. confirmed (code)
0x0023a258 Human_SetRubberNeck HuRubberNeck: human flag 0x1000000 on or off. confirmed (code)
0x0023a2c0 Human_SetBlockLook HuBlockLook: human flag 0x1000 on or off. confirmed (code)
0x0023a328 Human_SetForceLook HuForceLook: human flag 0x10000 on or off. confirmed (code)
0x0023a390 Human_SetLookPos HuSetLookPos: a point for the head to look at. confirmed (code)
0x0023a3b8 Human_SetLookTarget HuSetLookTarget: an object for the head to look at. confirmed (code)
0x0023a460 Human_ClearLook_Stub HuClearLook: empty in this build. confirmed (code)
0x0023a468 Human_IsAimingAt HuIsAimingAt: a player's aim target +0x634 is the given object. confirmed (code)
0x0023a4e0 SetDeathTimer SetDeathTimer: three death-timer values at 0x0051078c-0x00510794. confirmed (code)
0x0023a540 Cfg_SetCombo CfgCombo: sets 0x005102b0. confirmed (code)
0x0023a550 Cfg_SetSnap CfgSnap: sets 0x005102b4. confirmed (code)
0x0023a560 Cfg_SetButtonMash CfgButtonMash: the mash target, decay and gain (Crimes). confirmed (code)
0x0023a588 Cfg_SetStrafe CfgStrafe: sets 0x005104a8. confirmed (code)
0x0023a598 Cfg_SetAutoLock CfgAutoLock: sets 0x005104b4. confirmed (code)
0x0023a5a8 Cfg_SetAutoLockAndCombat CfgAutoLockAndCombat: sets 0x005104b8. confirmed (code)
0x0023a5b8 Cfg_SetAutoCombat CfgAutoCombat: sets 0x005104b0. confirmed (code)
0x0023a5c8 Cfg_SetLockOn CfgLockOn: sets 0x005104ac. confirmed (code)
0x0023a5d8 Cfg_SetCombatTimeout CfgCombatTimeout: sets 0x00510994. confirmed (code)
0x0023a5e8 Cfg_SetStrafeRStick CfgStrafeRStick: sets 0x005104d0. confirmed (code)
0x0023a5f8 Cfg_SetTurnRate CfgTurnRate: sets 0x00510304, 0x00510308, 0x0051030c, 0x00510310, 0x00510314, 0x00510318. confirmed (code)
0x0023a630 Cfg_SetCombatDistances CfgDistances: sets 0x005104bc, 0x005104c0, 0x005104c4. confirmed (code)
0x0023a658 Cfg_SetBurnRates CfgBurnRates: sets 0x005101e4, 0x005101e8, 0x005101ec, 0x005101f0, 0x005101f4. confirmed (code)
0x0023a7a0 Cfg_SetTurnRates CfgSetTurnRates: sets 0x005101b0, 0x005101b8, 0x005101c0, 0x005101c8, 0x005101d0, 0x005101d8. confirmed (code)
0x0023a970 Cfg_SetJumpIsAction CfgJumpIsAction: sets 0x0051099c. confirmed (code)
0x0023a980 Cfg_SetPickupIsAction CfgPickupIsAction: sets 0x005109a0. confirmed (code)
0x0023a990 Cfg_SetPickupIsGrab CfgPickupIsGrab: sets 0x005109a4. confirmed (code)
0x0023a9a0 Cfg_SetBurnTime CfgBurnTime: sets 0x00510220. confirmed (code)
0x0023ad88 Human_SetVoiceIndex HuSetVoiceIndex: the voice +0x3b0. confirmed (code)
0x0023adc8 Human_GetVoiceIndex HuGetVoiceIndex: the voice +0x3b0. confirmed (code)
0x0023ae00 Human_SetStateRespVoiceIndex HuSetStateRespVoiceIndex: the state-response voice +0x3b4. confirmed (code)
0x0023ae40 Human_LockPad HuLockPad: the player record's pad lock +0x1e. confirmed (code)
0x0023ae90 Human_LockPadMovement HuLockPadMovement: the player record's movement lock +0x1f. confirmed (code)
0x0023aee0 Human_StartButtonMiniGame HuButtonMiniGame: starts mode 5 of the mini-game record with its buttons, times and Lua callback. confirmed (code)
0x0023b0e0 Human_SetScale HuSetScale: the human's model scale. confirmed (code)
0x0023b128 CNS_SetMissionInfoEnabled CNSEnableMissionInfo: sets 0x005109ac. confirmed (code)
0x0023b138 Human_TeleportNear HuTeleportNearHuman: puts the human at a free point near another human, facing it. confirmed (code)
0x0023b778 Human_SetSlowMo HuSetSlowMo: a player's slow motion (+0x3bb, the time factor 0x005102cc). confirmed (code)

The update, controls and carried props

0x0023b838-0x0024e1f8 (inferred from where the rows lie; each row is graded): anim handles, the state update and its control functions (the member-function pointer at +0x1bc, An AI's locomotion), falling and landing, the look-at, the reticules and carried props.

Address Name What it does Evidence
0x0023b838 Humans_InitAnimHandles Static initialiser: fills the handle records at 0x006b6710 with null handles and clip 0x2d2. confirmed (code)
0x0023bc80 Humans_StaticInitAnimHandles Humans_InitAnimHandles(1, 0xffff). confirmed (code)
0x0023bcf0 Human_ClearVelocity Zeroes the task velocity and +0x3a0, clears the bone cache's +0x460 and marks the move dirty (+0x255). confirmed (code)
0x0023be98 Task_SendHandleMessage0 Sends message 0 with a handle to a task (Human_PickUpObject). confirmed (code)
0x0023cd30 Human_UpdateLedSlots When the move is dirty (+0x255), recomputes four aim points in world space: +0x1e0 = the world transform composed with +0x500 (bone 6, the head), +0x1f0 with +0x540 (bone 3), +0x200 with +0x4e0 (bone 2, the hips), +0x210 = the position + 0.3 m up (Combat: the led steer). confirmed (code)
0x0023ceb8 Task_SetVelocityXYZ Sets a task's velocity from three floats (w = 1). confirmed (code)
0x0023cf00 Human_SetMoveVelocity Sets the velocity +0x30, its speed +0x1ac and the gait for that speed +0x1a8, and marks the move dirty. confirmed (code)
0x0023cf70 Human_ClearTurn Clears the turn state +0x300, +0x304, +0x331, +0x332; attacks and climbs call it before steering. confirmed (code)
0x0023d630 Human_SetRotationThunk Calls Human_SetRotation. confirmed (code)
0x0023d660 Human_UpdateLod Distance to the nearest camera (+0x334), told to the resource manager; the detail level +0x333 (0-4) from the thresholds at 0x005102f0, raised by time since the last update. confirmed (code)
0x0023dc50 Human_EmptyStub4 Empty function (Player_TryJump calls it). confirmed (code)
0x0023e7e0 Player_UpdateHideOrder Orders the player's Warriors to hide when the player hides (brain +0x2d5), from Human_SnapToGround. confirmed (code)
0x0023f9d0 Brain_CheckMoveArrival Whether an AI's move reached its target point (from Human_StateUpdate). confirmed (code)
0x0023fb00 Human_ControlHandlerName The name of the control function +0x1bc for HuGetControlName. confirmed (code)
0x00240800 Human_RegisterContextAction Human vtable +0x124: registers a context action with the actionable manager (+0x664). confirmed (code)
0x00240850 Human_UnregisterContextAction Human vtable +0x12c: unregisters it. confirmed (code)
0x00240890 Human_SetContextRecord Sets the context record +0x660. confirmed (code)
0x00242ce0 Human_ButtonTapMove The button-tap control function: steps the human forward by tapped buttons. confirmed (code)
0x002432b0 Human_EnterStepControl Saves the control (+0x1bc to +0x1c4) and installs the step control (0x00243420) unless state 0x180f3ff0 or already installed; from TakeStepAction_Start (Step control). confirmed (code)
0x00243360 Human_LeaveStepControl Leaves the step control: Human_UpdateControl, or Human_MoveAttached while grabbed or mugged. confirmed (code)
0x00243420 Human_StepControl The step control function (+0x1bc while a TakeStep runs): for an AI, one step clip by the angle between brain +0x110 and the facing (step, dash or fight shuffle), turned over half the clip, then leaves at once; waits while busy (Step control). confirmed (code)
0x002445f8 Human_SetButtonTapMoveControl Control function = Human_ButtonTapMove and clears its counters +0x670, +0x674. confirmed (code)
0x00244620 Human_SetWheelchairMoveControl Control function = Human_MoveWheelchair. confirmed (code)
0x00244640 Human_SetButtonTapSequence Copies up to 16 button ids (null-terminated) into +0x67c and resets the index +0x678. confirmed (code)
0x002446a8 Human_SetButtonTapParam Sets +0x6bc for the button-tap control. confirmed (code)
0x002446b0 Human_SetThrowAimState Enters throw aiming: the control function and the aim point. confirmed (code)
0x00247a08 Human_SetFallStartPoint +0x2c0 = the given point when it is on the nav mesh, else +0x2b0. confirmed (code)
0x00247a50 Nav_WalkDistanceTo The straight distance to a point a walkable line reaches, else the length of a route planned to it (AI); 0 with no area or no route. confirmed (code)
0x00247fc0 Human_StrikeShapeOn Turns a strike shape on (message 0x8f). confirmed (code)
0x00248110 Human_StrikeShapeOff Turns a strike shape off (message 0x90). confirmed (code)
0x002482e0 Human_CanHeadLook Whether the head may turn to look. confirmed (code)
0x00248428 Human_UpdateHeadLook Turns the head toward the look target each update. confirmed (code)
0x00248980 Human_GetLookPoint The point the head looks at: for AI the brain's target point (+0x90) when within 90 degrees of its heading +0x110, else ahead; for a player from the target. confirmed (code)
0x00249050 Ground_ProbeBelow A ray straight down from 0.1 m above a point; true when it hits the level. confirmed (code)
0x00249bf8 Brain_InstallTypeHandlers Installs the handlers for a brain's type (17 types, table 0x0055ce40), using the owner's type for type 5. confirmed (code)
0x0024b190 Reticule_FindRecentFadeIn A reticule that started fading in recently. confirmed (code)
0x0024b3d8 Reticules_UpdateTarget Updates the target reticule over the player's target and the timed hints (0x0051054c). confirmed (code)
0x0024bf78 Reticules_ResetStatic Static initialiser: 0x006c7310 = -1. confirmed (code)
0x0024bfa0 Reticules_StaticInit Reticules_ResetStatic(1, 0xffff). confirmed (code)
0x0024bfc0 Human_SpawnHat Creates the hat object by name at the human, pins it and stores its handle +0x364. confirmed (code)
0x0024c1a0 Human_SendHatScene Sends the hat message 0x32 (attach 6, the scene state) at a scene's start and end. confirmed (code)
0x0024c560 Human_PlaceObjectInHand Puts a world object into the hand by its type record, unless picking up already (held 0x4000). confirmed (code)
0x0024c7b0 Human_StickThrownKnife Sticks a thrown knife into the human. confirmed (code)
0x0024cac8 Human_DetachProp Detaches the object +0x358, marks its body dirty and drops it (message 0x3e). confirmed (code)
0x0024cbb0 Human_CreateCarriedProp Destroys the prop at +0x348, creates the named object at the human, keeps it in +0x34c and attaches it at point 0x13 (Human_AttachCarriedProp); clip event 0x30 (Combat: props of a power move). confirmed (code)
0x0024cd30 Human_AttachCarriedProp Attaches the prop +0x34c to attach point 0x13 with its type's offset. confirmed (code)
0x0024ce40 Human_ReleaseCarriedProps Drops a held kind-0x27 object and clears the carried props +0x348, +0x34c. confirmed (code)
0x0024cef0 Player_AttachGear For a player with the unlocked gear (unlockables 6/5, 6/6): spawns the gear pieces on its bones from the transforms at 0x00715480. confirmed (code)
0x0024d340 Player_RemoveGear Destroys a player's gear objects. confirmed (code)
0x0024d420 Player_MessageGear Sends message 10 with a value to each gear object. confirmed (code)

Navigation

0x0024e1f8-0x00250e00 (inferred from where the rows lie; each row is graded): the human's side of the navigation mesh (on-mesh tests, path polygons, links); the planner is on AI.

Address Name What it does Evidence
0x0024e1f8 Nav_IsOnMesh True when a point lies in a nav area. confirmed (code)
0x0024e478 Nav_GetWalkingDistance WalkingDistance: the length of the path between two points. confirmed (code)
0x0024e608 Path_LengthFrom The length of a path from a point through its corners. confirmed (code)
0x00250398 Seg_ClosestPoint The closest point of a segment to a point, and its distance. confirmed (code)
0x00250b10 NavLink_ClearAvoidByKind Clears the avoid mark of links of a kind (glass broken, doors opened). confirmed (code)
0x00250bb8 NavLink_SetKindNearest Sets the kind of the nearest link pair to a point. confirmed (code)
0x00250db0 NavLink_ConvertJumpToDoor ConvertJumpToDoor: turns a jump link into a door link. confirmed (code)

Movement styles, clips and actions

From 0x00250e00 (inferred from where the rows lie; each row is graded): movement styles and anim slots, the clip builders (Clip selection), the turn and arrival clips of an AI, and the per-human actions.

Address Name What it does Evidence
0x00250e00 NavLink_DisableDoor Marks the door links near a point to be avoided (kind 0x10), as when a door shuts. confirmed (code)
0x00250e48 NavLink_EnableDoor Clears the avoid mark of the door links near a point (kind 0x10). confirmed (code)
0x002510a8 NavNode_IsLinkBlocked Whether a node's link list holds a link to the given node with a negative cost (a blocked edge). confirmed (code)
0x00251188 PathRequests_Clear Clears the 32 path-request slots (0x110 bytes each, at 0x006cc340 downward). confirmed (code)
0x002516d0 PathNode_SetIndex Stores a node pointer as its index (offset from the node array 0x006ca21c / 32) at slot i of a list. confirmed (code)
0x002516f0 PathNode_GetAt The node pointer at slot i of a list (the node array 0x006ca21c + index x 32). confirmed (code)
0x00251710 Ptr_Set Writes a word: a one-line setter. confirmed (code)
0x00251718 PathNode_IsEdgeBlocked Whether the edge between list slots i and i+1 is blocked (NavNode_IsLinkBlocked). confirmed (code)
0x00251768 PathNodes_ResetParents Sets every path node's parent (+0x1c) to none (0xffff) before a search. confirmed (code)
0x00251820 Path_DistanceCost The A* cost of a distance: length x 16, as a u16. confirmed (code)
0x00251a00 PathNodes_ClearOpenMarks Clears the +0x18 mark of every node on the open list after a search. confirmed (code)
0x00252108 Nav_NearestEdgePoint The nearest point on a nav polygon's edges (within 1.5 m of its box, at or above the point's height less 0.1) to a point; only when closer than 1.5 m, then dropped to the ground. confirmed (code)
0x00252ae0 Nav_FindPolygonUnderThunk Nav_FindPolygonUnder with a height of 1.0. confirmed (code)
0x00252b08 Nav_ClampMoveToRange Limits a move to a range: beyond it the point is kept only when the nav mesh connects the two (Nav_IsConnected), else the start. confirmed (code)
0x00252c28 NavLink_SetBlocked Sets or clears a path polygon's blocked flag 8 (+0x48) at a point. confirmed (code)
0x00253068 PathSearch_ResetCount Global 0x005105b0 = 0. confirmed (code)
0x00253118 PathSearch_InitLists Static initialiser: the open heap, the closed list and two small lists of the path search. confirmed (code)
0x00253170 PathSearch_StaticInit Calls PathSearch_InitLists(1, 0xffff). confirmed (code)
0x00253190 PathHeap_Construct Constructs the open heap (count 0). confirmed (code)
0x002531b8 PathHeap_Clear Count = 0. confirmed (code)
0x002531c0 PathHeap_Push Pushes a node on the binary min-heap keyed by the node's cost (+0x16), at most 1000. confirmed (code)
0x00253268 PathHeap_PopMin Removes and returns the cheapest node of the heap. confirmed (code)
0x00253350 PathHeap_Find The heap position of a node, or 0xffff. confirmed (code)
0x00253398 PathHeap_IsEmpty Count is 0. confirmed (code)
0x002533b8 PathHeap_SiftUp Moves a node whose cost dropped up the heap. confirmed (code)
0x00253480 PathList_Construct Constructs the closed list. confirmed (code)
0x002534a8 PathList_Get Entry i of the closed list. confirmed (code)
0x002534c0 PathList_Clear Count (+6000) = 0, last (+0x1772) = -1. confirmed (code)
0x002534d0 PathList_Add Appends a node to the closed list, at most 3000. confirmed (code)
0x00253528 PathList_Count The closed list's count. confirmed (code)
0x00253538 PathPair_Construct Constructs a three-short record (zeroed). confirmed (code)
0x00253560 PathPair_Clear Zeroes the three shorts. confirmed (code)
0x00253598 PathCursor_Construct Constructs a two-short record (zeroed). confirmed (code)
0x002535c0 PathCursor_Clear Zeroes the two shorts. confirmed (code)
0x00253e68 Human_SetMoveStyle Replaces the top movement style (pop then push), or applies style 0 when none is stacked. confirmed (code)
0x00253f78 Human_RemoveMoveStyle Removes a movement style from the human's stack and re-applies the top one (Anim slots). confirmed (code)
0x00254060 Human_GetMoveStyle The movement style byte of the human's record (styles 4 and 6 use the slow turns). confirmed (code)
0x002541c8 Human_CheckMoveStyles Drops a held-object movement style (1-6) that no longer matches what is held, style 14 without state 0x100000, and an object held with no style. confirmed (code)
0x002544b8 Human_GetAttackerReach The reach (attack table +0x4) of the move the human's attacker is playing on it. confirmed (code)
0x002545a8 AnimRange_SetFarRange Writes an anim id's far range (seconds x 1000, mm) into the human's Anim Range List (+0x160). confirmed (code)
0x002548c8 AnimRange_SetDamage Writes an anim id's damage (+0x0a) into the human's Anim Range List. confirmed (code)
0x00254e20 AnimRange_GetHitFlags The Anim Range List's u16 +0x0e for an anim (-1: the current one); Hit_ResolveBlock tests 0x600. confirmed (code)
0x00255540 Human_UpdateWorkout State code 0x1b: the workout on gym equipment (start, repetitions with the pad's pumps, end), its clips and rate. confirmed (code)
0x00255cf8 Human_UpdateSpecialIdle State code 0x1d: the special idle (672 start, then 671 looping) from the script's clips; ends the special state. confirmed (code)
0x002570e8 Human_ComputeThrowVelocity The launch velocity of a thrown held object: aimed at the target (led by its speed) or along the facing, scaled by the object's weight and the human's scale. confirmed (code)
0x00257ce8 Human_EndThrowAim Cancels the throw aim and drops what cannot stay in hand (kinds 4 and 6; any but sets 1 and 2 without human flag 0x2000). confirmed (code)
0x00257d70 Human_EndThrowAimDropHeavy Ends the throw aim: drops a held object of kind 4 or 6, then (no human flag 0x2000) drops any other when the human is hurt or holds set 3, unless a cop (brain type 1) holds set 1 or 2 (Combat: dropping what is held). confirmed (code)
0x00257e38 Human_EndThrowAimIfHurt Ends the throw aim and drops a held object of kind 4 or 6; a hurt human (no human flag 0x2000) also drops any other, unless a cop (brain type 1) holds set 1 or 2 (Combat: dropping what is held). confirmed (code)
0x00257ef0 Human_KnockOffHatIfDown Class 0x80 down or dead: knocks the hat off (Hats). confirmed (code)
0x00258330 Human_KnockOffHat Throws the worn hat off (unless HuSetKeepHat or kind 27): spin 8 rad/s, drop at 2 m/s, +0x364 cleared (Hats). confirmed (code)
0x00258968 Human_ReleaseAll Lets go of everything: breaks a pair, ends a mini-game, drops the held object, clears the object target, ends rage, clears state 0x18800f, empties the move-style stack and sets style 0x12. confirmed (code)
0x00259368 Human_UpdateFaceClip Queues the face clip 698 + 3 x the record's +0x1c (and its pair 700 + 3n), fading out the old one over at most 1/30 s; record +0x24 holds the current face clip. confirmed (code)
0x0025a178 Human_BuildCombatIdle Anim state 11: the fight-stance idle (slot 11) looping after a fade; from state 2 the fade holds 0x80000. confirmed (code)
0x0025a310 Human_PushRecordOverlay Sets the anim state and a held flag and pushes the record's +0x20 clip as a 0.05 s overlay holding that flag. confirmed (code)
0x0025aeb8 Human_TryIdleFidget With nothing held and record +0x3bc set, a 30% chance to play the fidget 601 as an overlay holding 0x200000. confirmed (code)
0x0025af90 Human_BuildPairedFourMix Builds the four-way gait mix (slot 4, anim state 4, action 3) for the human and for its pair partner (+0xc4), after a fade (0.1 s longer with held flag 0x40000000). confirmed (code)
0x0025c240 Human_StartTurnOnSpot An AI's turn on the spot: a turn clip (395-398, slot 8 or 15 variants) and the rest of the angle over the clip (An AI's locomotion). confirmed (code)
0x0025c5b8 Human_TryArriveClip An AI covering the last metres to its point with one clip: a step or dash from rest, the run stop at a run (An AI's locomotion). confirmed (code)
0x0025cb90 Human_PlayOneShotClip Plays a clip once over a 0.1 s fade, then the idle (or combat idle) looping, holding the given flag; state code 0. confirmed (code)
0x0025cd58 Human_BuildStanceEightDir Anim state 14: the fight-stance eight-direction blend (slot 14) driven by record +0xdc x 4/pi, after a fade of 0.15 s (none from state 2). confirmed (code)
0x0025cf10 Human_LaunchJumpThunk Calls Human_LaunchJump. confirmed (code)
0x0025cf30 Human_BuildJumpLoop Anim state 25: the jump loop 434 after a 0.1 s fade, then the launch (Anim states in the air). confirmed (code)
0x0025d020 Human_BuildFallClip Anim state 26: the drop cycle 428, or the long-fall cycle 422 / 425; a long fall from a grab gives the grabber style points and rage. confirmed (code)
0x0025d2d0 Human_ResetToIdleState Anim state 0 unless state 0x1c00000000; clears landing 0x2000000000 and the down and stun timers. confirmed (code)
0x0025d348 Human_ResetToMoveState Anim state 4 unless state 0x1c00000000; clears landing 0x2000000000. confirmed (code)
0x0025d390 Human_BuildLandingClip Anim state 27: the jump end 435 / 436, the drop land 429 or a long-fall clip, then the idle or a gait blend (Anim states in the air). confirmed (code)
0x0025e0e0 Human_BuildSlotLoopWithIntro Loops the record's +0x88 clip, after the +0x7c clip (holding 0x20000000) unless asked not to. confirmed (code)
0x0025e250 Human_EndDownState Clears record +0xbe and gets the human back up: wakes it (0x40000), unarrests it (0x20000), gets it up (0x80000), else back to the fight stance. confirmed (code)
0x0025e900 Human_EndObjectSteer End hook of the steer clip: clears the object target and sets push weight back to 1.0. confirmed (code)
0x0025e948 Human_StartObjectSteer Plays clip 666 then the idle, holding 0x4000, push weight 1e9, steering onto the object target over 0.1 s. confirmed (code)
0x0025eee0 Human_UpdateGaitBlendTarget Sets the top gait blend's target from the speed (Clip selection). confirmed (code)
0x0025ef58 Human_PushScriptOverlay Pushes a script clip as a 0.1 s overlay holding 0x100, unless the human is busy. confirmed (code)
0x0025f028 Human_BuildAnimState Calls the builder for anim state 0-7 from the table at 0x0055db50. confirmed (code)
0x0025f1b8 Human_BuildIdleClip Builds the idle (or a given loop) with stealth and stalking variants (Clip selection). confirmed (code)
0x0025f450 Human_RebuildAnimOnMove Forces the anim state to be rebuilt (flag 0x20000000) after state code 18 or while holding 0x20000 (clearing it). confirmed (code)
0x0025f4d0 Human_BuildMoveState Anim state 4: the gait blend via Human_BuildMoveTasks, or the stance eight-direction blend (Clip selection). confirmed (code)
0x0025fba0 Human_BuildState25 Builds the jump loop and sets anim state 0x1a. confirmed (code)
0x0025fbd0 Human_BuildState26 Builds the fall clip and sets anim state 0x1a. confirmed (code)
0x0025fc00 Human_BuildState27 Builds the landing clip and sets anim state 0x1b. confirmed (code)
0x0025fcb0 Human_UpdateDealerPair The paired clip 668 between two humans: within 1.875 m, a clear way and grabbable, aligns both and plays it on both; otherwise idles both. confirmed (code)
0x0025ff18 Human_StartObjectSteerIdle Starts the object steer, then anim state 0 and action 0. confirmed (code)
0x0025ff50 Human_BuildGaitBlendFromValue Builds a gait blend from a gait value, rounded down to 0-3 (Clip selection). confirmed (code)
0x002726d8 Human_SetStrafeDirection In a fight stance with a brain: record +0xdc = the movement direction relative to the facing (0-2π), for the eight-direction blend. confirmed (code)

Game-state functions

Functions of the game-state module (0x00417af0-0x00424e50, a range inferred from where its functions lie: inventory, statistics, flags, configuration workers) that belong to this page, by address.

Address Name What it does Evidence
0x004197a8 GameState_CheckGameOver each update, when enabled (+0x155), outside Rumble (+0x158) and not already over (+0x14c): over when a player has state flag 0x100000000; when every player is knocked out or cuffed, not over while player 1 is cuffed, awake and can uncuff himself (upgrade (6, 15) and item 6); over when no gang member can help (Gang_NoneAbleToHelp); over at once when player 1 is out with no flash (item 1) or byte +0x414 + player is set; otherwise every 37th update asks Gang_CanReachToHelp and is over after 4 failures in a row (+0x56e6). The mission-failed reason is GSTRING 21 when cuffed (+0x118 = 1), else 20 confirmed (code)
0x00419a68 GameState_SetWarChiefPlayer +0x222 = the war chief's player number (0 or 1; larger values ignored); from GameState_SetWarChiefHUD confirmed (code)
0x00419e10 GameState_SwapPlayerSlots(a, b) from Human_SetWarChief: swaps two players' entries in the player list (+0x228), their player numbers (human +0x1b0) and the pads' player numbers (pad record +0x42) confirmed (code)
0x0041a9c0 GameState_SetLeadPlayer from Human_SetWarChief: puts player 1's camera target first (CameraTargets_Swap) and moves the old leader's pad bit in +0x456 to the new one confirmed (code)
0x0041cf78 GameState_AnimEventHook empty; called by Anim_FireFrameEvents confirmed (code)
0x0041d428 Cfg_SetCharClassAttribs CfgCharClassAttribs's worker: a 16-byte record per class at W_GameState + 8 + class × 16 (two floats at +0x0c, +0x14 and four bytes) confirmed (code)
0x0041d890 GameState_EnableGameOverCheck EnableGameOverCheck: byte +0x155 (1 at set-up) confirmed (code)
0x0041ddb8 GameState_IsLevelEnding whether +0x14c (game over or complete) is set confirmed (code)

Coney's implementation

Coney loads a character's three resources, plays its clips, and plays Rembrandt as player 1 with the human's locomotion and the follow camera (Camera):

  • src/characters/character_list.* reads the Character List from warriors.glr and finds a record by model name; character_assets.* loads the three resources by the records' hashes ("%u" file names).
  • src/characters/clump_reader.* and character_model.* decode the clump (frames, HAnim, skin, material) and the native geometry, with the shared PS2 decoder in src/graphics/ps2_world_mesh.*, into merged skinned vertices and triangles; no librw outside src/platform/.
  • src/characters/character_data.* resolves the 722 anim ids to clips (Animation): the distinct slot values, smallest first, each take the next clip popped off the object stack, which gives Rembrandt's 408 walk and 413 walk-start as above.
  • src/characters/character_rig.* builds the skeleton and the skinning matrices (pose bone n + 2 · the pose turn · the inverse bind matrix) and skins on the CPU.
  • src/platform/character_mesh.* holds the skinned model as two librw atomics: the first texture-coordinate set with the character's texture, and the second set for the material's dual layer. In play (src/platform/play_lighting.*) every human is drawn in the two passes of Drawing a human: the second pass blends the blood texture (src/graphics/human_blood.*, the three charblood textures of global.pak) by its alpha below 90% health.
  • --view-character [NAME] [--anim CLIP] (Running Coney) shows a skinned character playing a clip in place on the fixed 30 Hz step, with a pad-driven orbit camera.
  • --render-references DIR (Running Coney) writes a 256x256 transparent PNG of every character, posed at its default clip's first frame (and of every object, Level loading), from a fixed three-quarter camera (src/characters/reference_render.* frames and reduces; src/platform/reference_renderer.* draws offscreen).
  • src/characters/anim_set.* answers an anim id from the character's own data, then from the generic character data 0x9da2e531 (594 gen_* clips) in place of the default table, with the clip's rate from the Anim Range List flags (CfgAnimSpeeds) and its speed (root displacement × rate / duration).
  • src/scripting/anim_callbacks.* is the animation callbacks' 16-slot table and its three bindings; a human's task stack reports each anim id it starts (AnimTaskStack::setStartHook: a change, a clip handing over to its next, a gait blend moving to another clip), and the scripts' brains run the first matching callback with (human, anim id). Coney choice: the callbacks run after the characters' step, in order, not inside the animation code.
  • src/human/locomotion.* is the pure maths: the camera-relative stick, dead zone and run threshold (PlayerRecord_Update), the target speed and gait, the per-gait turn limit with its ease and carry, acceleration, the skid rule, the slope factor and the gait blend's target (0x0025ec28); the sprint's target speed; and the body's lean (Human_Lean, 0x00248df0). The turn limits and ease are the values in play (20°, 18°, 18°, 16°, 24° in a combat stance, full at 2.0 rad): the defaults, and for a level --play-level runs, what the preload's CfgSetTurnRates and CfgTurnRate calls recorded.
  • src/human/stamina.* is the stamina meter (Sprint and stamina): the drain at the sprint gait, the refill (the maximum and the refill each human's power class's, Stats) and the gait, airborne and "run with L2" blocks, and Player_UpdateSprint's rule (L2 held and stamina not 0, asked again every update).
  • src/human/body.* holds the walking body's sizes for Walls and steps: the sphere of 0.35 × scale² (× 1.4286 for the player: 0.4705 m) centred 0.05 above its radius, the 0.25 m wall height, the fence materials passed through while climbing over, and the airborne push-out sphere (0.5 × scale for a player). An AI human's sphere is 0.35 × scale × scale (human::aiWalkingRadius, its body +0x60 being 1.0). The walls themselves are the physics world's sweep (src/physics/, Physics), run by Human::sweep: wall triangles |n.z| ≤ 0.65 that the move goes into, the 0.25 m low-and-thin rule, the sphere swept from where the move starts and met where it first touches (face, edge or corner), advanced to 0.01 m short of it along the normal, then the slid move swept again, up to three passes. So a face lower than the sphere's centre stops it where it meets the face's top edge, and a face under 0.25 m is walked onto in one update with no change of speed or clip. Only a player's slid velocity is written back (v −= (v · n) n, the slide response), so a wall met at a steep angle brakes him; an AI's velocity is never braked by a slide. Nothing pushes a walking sphere out of a face it overlaps, so a move into a face leaning back rises along it (Slopes). The corner slide (flag bits 14-15) is added to the move on the ground unless the human is in a pair or blocking. While airborne the same sweep takes the move across the ground, and the air sphere's push out of the nearest wall waits for the next move.
  • src/human/jump.* is the jump's checks and launch (Jumping): faster than 3.3 m/s and the stored gait at jog or above, refused when a climbable face lies within 5.5 m; the run or sprint speed forward and 5.5 m/s up. A start clip does not stop it.
  • src/human/climb.* is the climb choice (Climbing): the two forward rays, the climbable test, the probe 0.4 m behind the face with its windows, the 2.5 m fence ray, the clip ids, each clip's reach (its type-8 event vector) and the reach window.
  • src/human/human_animator.* is the anim state and its builders: idle, move, the jump loop (25), the drop cycle (26), the landing (27: 436 handing over to a gait blend, or 435 and the idle), the run stop and the climb's three clips (Coney's states 101 and 102); the walk or run start played at once and handed to the five-clip gait blend, the 0.1333 s fade between moves, the idle's fade by how much of a start clip has played, and the walk start swapped for the run start in its first half (Clip selection). Its clips hold their record +0x08 bits while they play (Tasks): a start clip 0x10000000, the landing 0x1000000, the run stop and the climb's first and last clips 0x80000, the combat moves theirs (Combat).
  • Dynamic animation slots (Animation): human::ScriptState holds the seven slots that HuUseAnim and HuUseAnyAnim both fill. An id already in a slot reuses that slot, a new id takes the first free one, and an eighth id is refused. The play mode hands the idle's clip (0x184) to Human::setIdleClip() and every other one to HumanAnimator::setOverride(), which all of the human's own clip lookups go through (a paired clip taken from another human's set does not). Stand-ins: a clip already playing is not restarted when its slot changes (the original's state flag 0x20000000), and a dynamic clip plays at the rate of the id it replaces.
  • Hats (Hats; src/world_objects/hats.*, src/platform/play_level_hats.cpp): the class's hat when the human is made, and HuPlaceHatOnHead's, each a pinned world object on bone 6. A Warrior wears it at his set's fitting; anyone else at the hat type's own pose (CfgObj arguments 21 and 22). The offset is multiplied by the wearer's scale. A hat comes off when a knockdown grounds its wearer (not a cop's, nor class 0x80's or 13's unless he is out of health), when he is mounted, or when a new hat replaces it, unless he has HuSetKeepHat or the hat is kind 27. It is thrown at 2 m/s spinning at 8 rad/s, then falls until it rests on the ground. HuHasHat gives the handle of the hat worn. Stand-ins: the side of the blow is not modelled, so every hat leaves behind its wearer (side 2); the fall is Coney's own (gravity 9.81 m/s², stopping where it meets the ground); a deleted human's hat goes with him; the respawn timers are not applied.
  • src/human/locomotion_gate.* is the locomotion gate (Tasks): stickBusy() (Human_IsBusy's mask 0xaeebf7ff, in the air or held: no stick step) and stickVelocityGated() (0x110c0880, or state code 5 or 6: the stick turns the human but sets no velocity).
  • src/human/human.* is the human: spawn (a 2.5 m ray from 1 m above, feet 0.01 above the hit), its per-player record (the stick, the camera's forward, the command and the buttons, written by the pad or a brain) and its update in three passes (Tasks): animate() (the animation), updateState() (root motion of the clips that move the body, locomotion through the gate, air control or a climb's move, gravity, move or fall, the meters, the lean) and updateActions() (the dispatcher from the record, triangle's actions, then the anim state); the ground snap, the fall and landing, the walking body, the airborne push-out, and the climb from its probe to its last clip (the move to the start point, the re-probe at the first clip's end, the rise onto a wall). A pad-driven human with the wheelchair flag runs wheelchair control in place of the locomotion, its constants per 1/30 s step; stand-ins: its sticks are ignored so no locomotion clip starts, and no start or wheelchair clip plays.
  • src/human/humans.* is the characters' step (Humans_Update): every human's record (the commands of those no pad drives cleared), the brains' hook (empty until the AI lands), then the animation of all, the locomotion of all and the actions of all, walked forward and backward on alternate steps. It runs on Coney's fixed 1/30 s step.
  • src/human/player.* is player 1 (the character at scale 0.97, the human, the follow camera; L2 held sprints, triangle pressed acts): it writes the pad into its human's record and steps the characters, and keeps the snapshot drawing reads: the previous and current feet, heading, lean, pose (each bone slerped) and camera, interpolated for a renderer that draws between steps.
  • The debug menu's tunables (Debug menu) expose the body, sprint, jump, climb and lean values above, each defaulting to the original's.
  • --play-level NAME (Running Coney) plays it: src/platform/play_level_mode.* steps the player, streams the level and runs the visibility pass in its update, and draws from the snapshots of the last two steps, blended by the frame's alpha, in its render (Update and render). A disc test ([frame_rate]) plays both scripts at 30, 60, 144, 240 and 1000 frames a second and with irregular frames and checks the player, the camera and the streaming come out bit for bit as in lockstep.

Disc test ([characters], counts only): all 543 records load (128 models, 52 character data resources, 507 dictionaries); 150,509 vertices and 155,493 triangles; 1,692 clips and 2,843 resolved ids; the joint mismatch of a clip's first pose over the reference pose averages 0.045 m (worst 0.098 m); the skinned heights run from -0.07 to 4.06 m (2.29 m at most over the bind rotations; which first clips reach higher is not looked at yet); every model's bind rotation for bone 2 is 120° from the reference pose's, and 292 of the bones 2-33 over the models are more than 10° from it.

Disc test ([player], counts only): Rembrandt's speeds from his clips are the runtime values (walk 1.629, jog 4.857, run 7.801, sprint 10.245 m/s); at level99's start he lands at z 0.25, idles in 388, takes the walk start 413 at a 30 % stick (not moving on its first update, then 0.762 m/s: the clip's root motion × 0.97), walks in 408 at 1.629 m/s, gains 0.8 m/s per update to the run (410), skids into the run stop (417) on release and then idles, and never leaves the ground or passes through the scenery he is run into; the same script gives the same path twice. On the default sandbox's ledges he walks onto the 10 and 25 cm blocks (the 25 cm block's 3 m wide face is two slivers the 0.25 m rule skips) and stops at the 50 cm one, 0.484 m short of its face, where the sphere meets its top edge.

Disc test ([traversal], positions and hashes only; Rembrandt on the sandbox's parkour course), each run against the runtime values above:

  • Sprint (L2 held, stick 0.8 then 0.96): a walk at 1.629 m/s and no drain at 0.8; 10.245 m/s at 0.96 for about 6.75 s until stamina is empty, then 7.801 m/s in one update; stamina held at 0 while L2 stays down and refilled at 40 per second once it is let go; letting go of the stick at the run plays the run stop (417) for about 24 updates.
  • Jumps: a run jump at 7.801 m/s and a sprint jump at 10.245 m/s, both 5.5 m/s up, rising 1.06 m and landing in 436; the sprint jump carries about 8.5 m (24 updates in the air and the landing update); letting go of the stick in the sprint plays the run stop (417). A run jump clears a 5 m gap between two 2 m platforms, the feet ending one update below the far platform's top before they land on it.
  • Fences of material 30, from a run: the 1 m short fence (446) and the 2 m fence (440) are climbed with the feet at ground height, through the fence; the 2.6 m fence is neither climbed nor jumped, and stops the body at its face.
  • Walls and blocks with flag 0x80, standing: the 0.75 and 1.0 m walls are short-wall climbs (455) onto their tops; the 2.0 m block is a wall climb (449) onto its top; the 3.0 m block is not climbed.
  • Kerbs and ledges: a 20 cm kerb is walked onto; 30, 50 and 65 cm ledges stop the body at their face.

Coney choices where the research is silent: the material takes its dictionary's only texture; bones 0 and 1 rest at the identity; weights are used as stored, not renormalised; the viewer's lights, camera and clip keys, and the reference images' pose, camera and lights, are Coney's own. For the human:

  • The default anim table: slots set to the default (0xffffffff) are answered by the generic character data 0x9da2e531, whose clip speeds match the runtime-confirmed ones exactly (380, 407, 409, 410, 411); the table at resource manager +0x70 is not decoded.
  • Standing: a human not asked to move counts as moving while faster than a quarter of the walk speed. The original's getter 0x00221580 is the sneak-walk speed (record +0x16c × +0x3a4, 1.585 for Rembrandt; confirmed (code)), so the original's threshold is 0.396 m/s against Coney's 0.407. Coney's reading: a start clip no longer asked for gives way to the idle at once, whatever its root motion's speed: the idle builder fades over a start clip still playing (0x0025f770, above), which the speed test alone would never reach.
  • Falling: state 26's builder loops the drop cycle (slot 26, 428) with the idle's 0.15 s fade; a drop lands straight into the idle or the move, without the drop land (429), the long-fall cycles or the ground roll.
  • Locomotion while a start clip plays keeps turning (only the horizontal velocity waits for the clip), as the locomotion gate gives it (confirmed (code)): the start clip holds 0x10000000, which zeroes the stick's velocity but is outside Human_IsBusy's mask, so the turn still runs (Tasks). In the air only a jump steers; a fall keeps its velocity, and no clip's root motion moves the body while airborne. Standing (no gait blend yet), the update the start clip begins sets no velocity, as at runtime.
  • The start clips hand over early: the walk and run starts give way to the gait blend on the update after which less than an update of them is left, so they last 13 updates as at runtime (playing to the end would take 14). From their first moving update they move at the clip's root speed × 0.97, as at runtime (0.762 m/s for the walk start, 2.773, 2.486, … for the run start), through the sampler's reading of the clip's keys (Animation).
  • Root motion of every clip that moves the body on the ground is scaled by the body scale (0.97 for Rembrandt); a wall or short wall climb's rise at its second clip is not (it matched the runtime unscaled).
  • The jump's gait test reads the stored gait (+0x1a8, the nearest) where the code reading names the "reached" gait: the runtime jump 7 updates into the run start, at 3.35 m/s, passes only with the stored gait.
  • The body is the original's walking sphere (Walls and steps), but pushed out of the nearest wall triangle by the distance to the triangle's closest point rather than swept along the move; the push tries 3 passes, then stops. The low-and-thin rule takes the triangle as given, so a 0.25 m face exactly (a sliver) does not stop the body, and a face from 0.26 m does.
  • Landing probes from 1.0 m above the feet, as the ground snap does. A floor found on that segment is landed on by the first update that starts with the feet 0.17 m or more below it (When the landing happens); until then the body falls on through it (0.19 m after a run jump, as at runtime). The landing is at that update's position across the ground, so the landing update keeps the full horizontal speed.
  • Stamina carries one fraction of a point between updates, started again when the meter changes direction.
  • The run stop (417) plays after a skid, after the 0.1333 s move fade, which blends only the pose: the gait blend it fades from has no root velocity, so the body moves at the clip's 2.244, 4.996, 5.101, … m/s from its first update, as at runtime. The skid's own update still turns one step and the run stop then holds the facing. The skid needs the run speed ≤ the speed, compared exactly (The run stop at a run): a sprint always skids, a steady run only when its speed lands on or above the run speed. Coney's reading of the speed: the velocity's length with each multiply, add and the square root rounded toward zero, as the PS2's floating-point unit rounds (core/ps2_float.h); the velocity itself is Coney's, so a steady run reaches the run speed on about 6 % of updates against the original's 10 of 93. What builds the run stop is not traced. It holds 0x80000, which the locomotion gate reads (busy and no stick velocity). The skid sets no state code (the original's 9): the run stop's own bits gate the same updates.
  • The idle's fade (0.15 s, 5 updates) holds 0x10000000, so after a stop, a release or a block the stick turns the human but the walk start waits for the fade to end (Tasks). Over those updates the last stick held turns him on, its magnitude × 0.8 each update, eased from rest at the standing turn's 20° limit; Coney's reading of the ease (after run_circle's release it turns 0.666°, 1.136°, 1.409°, 1.515°, within 0.004° of the original's). Coney never sets state code 5 (turning in place): nothing reads it apart from the gate, and the fade holds the same updates.
  • The landing has no fade, so 436 moves the body at its 4.23 m/s from its first update as at runtime, and hands over to a gait blend at the jog (1.0).
  • The air turn is limited to 4° an update, what a sprint jump turned at runtime; which gait's limit the original uses is not traced.
  • Climb reach: r1 and r2 are read as the reaches of the standing and the running first clips (for the fence, 437 and 440). Rembrandt's type-8 vectors are 0.77 / 2.31 m (fence), 0.64 / 1.39 m (short fence), 0.65 / 2.30 m (wall) and 0.78 / 1.55 m (short wall), which give a running fence climb from 1.23 to 5.09 m: the runtime tap at about 4.4 m started one and the one at 4.9 m did not (the 4.5 m ray). The chain's first two clips would give about 1.2 m and no running climb from 4.4 m.
  • The climb's move to its start point takes 2 updates from a run and 1 standing; the first clip's clock runs through it, as the original installs the clips with the move, but its root motion moves the body only once the move is done. On the sandbox's 2 m fence 440 lasts 11 updates from the tap's, as at runtime.
  • The rise: walls and short walls move at once at the second clip's start, by its root displacement (450 and 456 carry none in section A; their whole displacement, 0.98 and 1.06 m, as at runtime) and up to the top the probe found; fences go by the second clip's own root motion, as the runtime's 441 carried the body through.
  • Climbing over lasts the second clip: from the re-probe at the first clip's end to the third clip's start (at runtime 441 had record +0x08 0x40 and 442 did not). Meanwhile the fence materials (30, 31, 122) are not walls, and not ground for the snap and the landing, so a low fence's top does not lift the feet. This differs from the original and breaks the hangout railing (checklist item 46): the original runs no wall sweep and no ground snap while 0x40 is set, so a climbed face of any material lets the body through, but Coney still sweeps the walking sphere with only 30, 31 and 122 left out. The hangout's railings are material 7 with flag 0x80 (Collision), so 443 and 444 play and the sweep holds the body 0.48 m in front of the face: the vault ends on the same side. A climbed face that is any other material with flag 0x80 or 0x4 (car shells are material 0) does the same. And had the body passed, Coney's snap would find no ground over the 3.2 m drop part-way through 444, so the climb would end in the idle at once (followClimb's airborne end) instead of the fall at 444's end. Fix: while climbing over, skip sweep and snapToGround and move the feet by the velocity and the clip's root motion, height included (Human_Move's 0x40 branch); from the third clip on, move as now, and when the snap then finds no ground start the fall (anim state 26, the fall clip, 428 at runtime) in place of the idle and the third clip. Test: a synthetic railing of material 7 with flag 0x80, 0.9 m tall and one-sided toward the player, on the edge of a floor with another 3.2 m lower behind it: the player standing 0.6 m from it, the stick at 50 % toward it and triangle, plays 443 and 444, is past the railing's back at 444's end with the feet still at the upper floor's height, never plays 445, then falls and lands on the lower floor beyond the railing; the same railing over level ground ends on the far side with 445 played.
  • The re-probe at the first clip's end accepts any triangle, not only a climbable one.
  • The climb's fade: none; the first clip moves the body at its full root speed from its first update after the move (5.79 m/s on the 2 m fence, as at runtime). The update the chain goes on to its second or third clip moves nothing, as the first update of 441 and of 442 did at runtime; why is not traced.
  • The lean: the four limits go with walk (and standing), jog, run and sprint; the drawing rolls the body by the lean about its forward axis through the feet.
  • Context and object actions (triangle's second and fourth tries) are hooks that never succeed yet, so triangle goes on from a refused climb to the jump.
  • Camera through a fence: the follow camera's ray passes through material 30 (Camera), so it keeps its distance through a fence climb as the original's does.
  • Out of the world (20 m below the mesh's lowest point): the human is put back at the start instead of failing the mission.
  • The gait blend's leading clip uses a tolerance of 0.001 when it compares the value with its target.
  • Level starts: the start comes from the level's own script at run time: its HuCreate for player 1 at the checkpoint (GetCheckPoint), kept by Coney's HuCreate binding (Level loading); the story's way in and --play-level NAME [--checkpoint N] both run it. A level that places player 1 at a flag (the hub, the Rumble arenas) starts him on the flag (World flags). The character's lights (ambient 0.45, one directional 0.7) stand in for the LightManager, and he is drawn between the level's two worlds.
  • Handing the player over (ScriptedBrains::changePlayerGang, PlayLevelMode::takePlace, from Players): a later HuCreate with player argument 1 makes an AI human (the argument is kept as its priority), and HuChangePlayerGang picks the gang's member as Gang_PickNextPlayer does. Coney's stand-in: Coney has one player human, so instead of making the chosen human the player and leaving the old one in the world until its gang is deleted, the player's human takes the chosen one's place (spawned where it stands, drawn as its model, named by its handle, in its gang) and the chosen human leaves the world; the old handle names no one. The scripts' record of player 1 (CreatedHumans::player(1), which the play mode's thefts, pick-ups and muggings, the crew's chief and the teleports read) names the chosen human from then on (CreatedHumans::setPlayer). The end state after level 99's GangDelete(0) (the hand-over) is the original's; tests/platform/disc_level99_handover_test.cpp plays checkpoint 1 into 2 and steals the first stereo as the new player 1 (before, the theft named the old handle, HuIsAPlayer said no and the lesson stalled). GangDelete deletes the gang's members at once (AI); player 1, with no other human to go to, is only taken out of the gang. tests/platform/disc_level99_street_test.cpp plays the end of the combat course into the street with the disc.
  • The model (src/characters/character_class.h, from From a type to a model): characterClassOf is Human_Init's switch, modelRecordType the player's plain-alias rule (a player made as a plain alias is drawn as the class's own type; a variant keeps its own), and modelNameFor takes the model name from that type's recorded CfgChar call (its tenth argument), with _a added in levels 60 to 64; HuCreate keeps it and the play mode loads it from the Character List. Disc check: level2 checkpoint 3 is drawn as warr_cl (Cleon), level3 checkpoint 4 as warr_sn (Snow), level99 checkpoint 1 as warr_re_cv. Coney's choice: a type with no CfgChar call or a model the Character List lacks is drawn as Rembrandt, with a log line.
  • The scripts' hold on a human (character bindings): the flag word +0xe0 is human::flag (src/human/human_flags.h), kept by the fighter and across a respawn; combat reads the bits Combat lists, 0x2 gates the running climb and 0x4000000 keeps stamina full. A player starts with 0x2, 0x4, 0x400, 0x2000000 and (Coney choice, for scenes with no level script) 0x20000000000. The rest of what the scripts set (arrest, pad lock, disabled commands, money, carried item, callbacks, icon, held object, head-look, animation overrides) is human::ScriptState (src/human/script_state.h); the bindings are src/scripting/human_bindings.*, acting through ai::ScriptedHumans. Stand-ins: an arrested human only stands still; the icon, the object in the hand, the head-look and HuUseAnim's clips other than the idle's (slot 0, which plays: Rumble) are kept, not drawn or played; HuSetPushable is kept (bodies do not push each other); HuDropWeapon lets go of any object; HuChangePlayerGang and WCIssueCommand only note the gang and command. LoadBumAnims requests or releases the bum animations' table, in order, as SetDynamicAnimation does each: the file listed twice is one entry, so twelve files are listed.
  • The hub's hold on a human (level95; src/scripting/hub_bindings.*, acting through ai::ScriptedHub): money, death, character class and voice set are read; the scale, name, cuffs, muggable, pedestrian reaction, unarrestable, combat mode, gear and tackle block are set. Workouts (HuWorkout): the enter clip into a loop blend of the three workout clips, the effort pumped with cross and decaying by CfgWorkoutParams' tables, a repetition each wrap of the loop, the end on triangle or when worn down, then the exit clip (Workouts, human::WorkoutEffort). Stand-ins: another human's equipment is reached within 1.5 m; no dynamic clip plays; combat mode and the gear are kept, their context actions not built.
  • Names: @orig names for addresses the research describes but does not name (such as Human_SnapToGround, GaitBlend_Advance, PhysicsBody_PushOutOfWalls) are Coney's.

Notes for implementers

  • Make the player first. For level99, checkpoint 1: one human named Rembrandt, model warr_re_cv (found through the Character List), at (-284.4, 120.4, 0.3) heading 0°, snapped to the ground with a 2.5 m ray from 1 m above; pad 0; the follow camera targeting it (Camera). Any other level: its entry for the checkpoint in Level starts (checkpoint 1 by default, the first mode's flag in a Rumble arena, fWchiefStart_1 in the hub), with that entry's character type.
  • Step at 30 Hz. Movement, turning and the animation step all use dt = 1/30 and per-update limits; a PC build that runs faster should keep a fixed 30 Hz step (or scale every limit) so speeds and turn rates match.
  • Speeds per human come from the clips: for each locomotion slot, the clip's horizontal root displacement over its duration (Speed classes). For Rembrandt walk 1.63, jog 4.86, run 7.80, sprint 10.25 m/s.
  • Gaits: a walk up to 0.95 stick magnitude (any amount above 0.12 gives the same walk), a run above it; the start clips (413, 414) first, then the gait clip; idle at once on release.
  • Ground: no vertical velocity on the ground; snap the feet with a ray from 1.0 m above, 1.5 m long, each update; a miss starts a fall with gravity 15.68 m/s² (from the second airborne update), capped at 50 m/s; land on floors with n.z > 0.65; fall damage from 14.9 m/s, a kill from 20.5 m/s (above). A fall or jump lands on the first update that starts with the feet about 0.17 m or more below the floor: keep moving the full step until then (feet up to 0.38 m under), then land at that update's position with the horizontal speed kept (When the landing happens).
  • Clips that move the body move it at the clip's root speed × the body scale from their first moving update, with no fade-in of that speed: the walk start 0.762 m/s on every one of its 12 moving updates, the run start 2.77, 2.49, 2.56, … and the run stop 2.24, 5.00, 5.10, … (Per update). A first update slower by 0.75 (the start clips' playback rate) or a stop that ramps from 0.31 m/s is a difference to remove.
  • Walls: a sphere of radius 0.35 × scale² × body +0x60 (1.4286 for the player: 0.4705 m), centred that radius plus 0.05 above the feet, swept along the move; the slid velocity is kept, so a steep wall brakes the player; wall triangles less than 0.25 m tall are not walls, which is all the step-up there is (Walls and steps).
  • Sprint is L2 held with the stick above 0.95: cleared every update and set again while L2 is down and stamina is not 0. Stamina drains 20 per second at the sprint gait and refills 40 per second (Rembrandt: 135), not while running with L2 held (Sprint).
  • Triangle tries a climb (stick above 0.12), then a context action, then a jump (stick above 0.95, faster than 3.3 m/s): 5.5 m/s up, the run or sprint speed forward, steering in the air (Jumping).
  • Climbs are chosen by two forward rays at 0.69 and 1.7 m and a downward probe 0.4 m behind the face; the feet rise in one move at the second clip's start (Climbing).
  • The stick is camera-relative before the human sees it: turn the stick by the camera's heading first, then apply the dead zone (0.12) and the run threshold (0.95) to its length.
  • Turn with a limit and an ease, not instantly: in play 20° per update walking, 18° jogging and running, 16° sprinting, eased below 2.0 rad (the values config_preload2.lua sets, Locomotion).
  • Characters are skinned with 32 bones (34 pose entries, Animation); every character on the disc has the same skeleton layout, so one bone mapping serves all.
  • A disc test: every Character List record resolves to three resources that load, and every model is the clump described above (counts only).

The fifth and sixth missions' switches (2026-10-06): HuBlockJump sets flag 0x10000000, which makes Human::tryJump refuse (a climb or a context action still takes triangle); HuSetNoReact sets 0x800, the same bit the AI's block goal sets (Fighter::hitReactionsOff() now reads the flag word); HuSetAutoCombat keeps 0x200000000000 with no reader. HuApplyDamageModifier rewrites a human's attack damages from its class table × the factor, rounded, then a player's Warrior class percentage (Human::applyDamageModifier; an entry that rounds to 0 keeps its damage). Coney's stand-ins: HuEnableTagCheer, HuSetInterrogation and HuUseAnyAnim are kept on the human's ScriptState (no crew comment on a slip, no interrogation shake-down, no clip played; HuUseAnyAnim keeps up to seven overrides apart from HuUseAnim's four and answers whether the file was requested); HuHasHat answers NilHandle, as Coney's humans wear no hat objects; HuClearLook and KillHumans do nothing, as in the original. CfgSetMaxThrowError keeps its two errors in radians (CharacterRules::maxThrowError); Coney's AI throws do not read them yet.

Open questions

  • The workout's reach and timing (answered): the scripts make the player his own target, so the reach always passes, and a repetition is each wrap of the loop blend's leading clip (Workouts).
  • Where god mode (0x10) is tested: Coney drops the damage and still plays the reaction.
  • What the arrest (state 0x20000) plays and allows, and which human states HuIsAlive's mask 0x180050000 names.

  • Clip selection (answered): Clip selection, with the task system on Animation; the playback rate is never scaled with the speed. Still open: the anim states other than idle and move (11, 21, 24 and the combat ones) and the special idle ids.

  • Jog: when a pad-controlled human jogs other than when carrying (a movement style, a script).
  • What slots 16-24 and 28-34 are used for (16-24 are the attacks and the block, Combat) (their default ids are known, Anim slots), and the movement styles of 0x00253688 beyond the ids they write.
  • The +0x65c scale's source: what the division in Human_Init takes.
  • How the texture reaches the material, which names none (Character geometry).
  • The rest rotations of pose bones 0-2 and why bone 3's parent in the table differs from its frame's.
  • The vertex colour slot (zeros in every character checked): what the renderer does with it. The second texture-coordinate set is the blood layer's (Graphics).
  • The default anim table at resource manager +0x70, which answers the slots set to 0xffffffff; Coney uses the generic data 0x9da2e531, which matches every speed checked, but whether the table is that resource is open.
  • The idle threshold's getter (answered): the sneak-walk speed (Coney's implementation).
  • The body's shape (answered): a capsule shape whose walls are a swept sphere (Walls and steps). Still open: what the capsule's 1.886 (shape +0x44) and the human's +0x4e8 are used for.
  • The airborne anim state (answered): states 25-27 (Falling and landing); air control (Jumping). Whether locomotion turns the human while a start clip plays (answered: it does, Tasks).
  • Step height at runtime (answered): steps up to 0.245 m are walked onto in one update, from 0.255 m they stop the body (Walls and steps), measured on a test step made in the mesh. Still open: a real kerb in a later level, as corroboration.
  • The context action (0x002811f0) and the object action that triangle also starts (partly answered, Triangle with something in hand): the object action is the drop of what is in hand; the context action is the context records and the pick-up search (Crimes). Doors and which objects are still open.
  • The air turn's gait (partly answered): 4° per update from a run and a sprint alike, which is the non-player column's run value at 0x005101c4 (inferred: Human_AirControl reads the other column); not read in the code.
  • Climb reaches (partly answered): Coney reads Rembrandt's type-8 vectors (Coney's implementation); still open: which two clips r1 and r2 belong to (Coney's reading: the standing and running first clips), and which clip's reach Climb_Start's "too far by less than twice the reach" swallow uses (Triangle with something in hand). Answered: CfgClimbWithGhetto keeps the ghetto blaster (held set 6) in hand through a climb; without it the climb drops it, and always drops a set-4 object (Climb_Start, 0x00281c20, confirmed (code)).
  • The landing's threshold: why the landing contact is taken only once the feet start an update about 0.17 m below the floor (When the landing happens). The contact path is traced (the resolution 0x0033d9d8 acts on the first contact by fraction) and does not explain it; a runtime log of the contacts is needed.
  • The landing's fade and the gait blend value 436 hands over to; the drop land (429) and the long falls are not built in Coney.
  • The climb's details (the first clip's timing answered: it runs during the move to the start point, with no fade, Climbing): when record +0x08 0x40 is cleared; whether the re-probe needs a climbable triangle; how a fence climb's second clip moves the body (Coney: its root motion).
  • The camera during a fence climb (answered: the camera's rays exclude materials 30, 122 and 107, Camera).
  • Triangle flags 0x4 and 0x80: why two climbable flags (one for players only), and which surfaces carry them.
  • The sprint's other clear (answered: the block, Combat). Still open: what 0x00230140, called when the sprint is set, does, and the fight test 0x00224f28.
  • The rest of the human: the 0x180 record (the 0x2f0 record is the brain, AI), the state flags tested by 0x002265f0 / 0x00226660, and Human_MakePlayer's steps.
  • Level starts at runtime: the list is read from the scripts; a runtime check would confirm a few. For each of level2 checkpoint 1, level95 chapter 1 and level102 brawl, read player 1's transform (the table at 0x00714b00, index +0x92 of the human whose +0x1b0 is 1) on the first frame of play, and again after the checkpoint script's start function has run (the hub's door walk, the arena's teleport).
  • Start functions that move the player later: the list notes only teleports made directly by a checkpoint's start function (or one function down). Scene callbacks and chapter steps teleport the player too (99 Teleport / TeleportToFlag calls on player in the story scripts in all); which of them run before the first frame the player controls is not traced.
  • Four Rumble arenas without a known mode script: their level<N>_<mode>_init.lua names are not recovered, so they have no entry (Levels lists the modes found per arena).
  • A steady run's velocity in floats: the original's run measures at or above the run speed on 10 of 93 updates, Coney's on about 6 %; how its velocity is built (the order of the multiplies) is not traced.
  • The run start's speed on its 7th and 11th updates in run_circle (3.35 and 5.40 m/s against Coney's 3.25 and 5.54): which key the original samples there.
  • The trace's clip id in the gait blend (record +0x20): 410 where Coney reports the blend's leading clip (411, 409) in run_circle's steps 54-56; which clip of the blend the original stores.
  • The circling run's turn: on run_circle's step 75 Coney turns 16.92° against the original's 16.44°, which the camera's auto-follow then grows to 6.6°; whether the stick is turned by the camera of this update or the last.