Crimes and context actions¶
Verified against: SLUS_212.15 (NTSC-U, SHA1 e9cb2cc49aa046b9e494313dce2f5038ed17b2f4), static analysis only
(Ghidra), with the disc's compiled scripts read through coney-tools' Lua walker for string ids. Runtime reads (the
mugging's starting money) are over PINE in PCSX2 2.9.94.
Purpose¶
What the player does with triangle besides grabbing: the context actions (pick a lock, steal a car stereo, uncuff a partner, mug, tag a wall, take an item), the timed mini-games behind them, what each one gives and what it costs, and how the game turns these into crimes, wanted time and police. The pieces already documented are linked rather than repeated: the mugging's stick game and the stereo's stick rotation are on Combat: mugging and Combat: the stereo theft; the crime report and the police response on AI: crimes with the types in Crime types; breakable glass and doors on World objects; store flags on World flags; the inventory and the scores on Inventory, unlockables and statistics and Statistics.
Original structure¶
No source file names this code; it sits with the combat code after Human/cns/cnsplayertag.cpp (Source
map). Names are ours.
| Address | Name | Role | Evidence |
|---|---|---|---|
0x002811f0 |
Player_TriangleAction |
triangle pressed: a key for a cuffed partner, a tag in progress, then the context action, then a pick-up | confirmed (code) |
0x0024d530 |
ContextAction_Use |
starts the action of the human's current context record (+0x660) |
confirmed (code) |
0x00417ca0 / 0x00418150 |
ContextActions_Register / ContextActions_Pick |
the registry of context records; the per-update choice | confirmed (code) |
0x0022dc40 / 0x0022e400 / 0x0022d628 |
MiniGame_Start / MiniGame_End / MiniGame_Abort |
dispatch by mini-game mode | confirmed (code) |
0x0022ec18 / 0x0022ef58 |
Human_Arrest / Human_Unarrest |
HuSetArrested 1 / 0: the cuffed state, its style, record and icon (Arrest) |
confirmed (code) |
0x0028c5d8 |
Brain_OnArrested |
the brain's reset and event 17 | confirmed (code) |
0x002271f0 / 0x00227388 |
Human_ShowOverheadIcon / Human_RemoveOverheadIcon |
the icon over a human (dyn_cuffs, dyn_cross) |
confirmed (code) |
0x00260ca8 / 0x0022d3f8 |
Uncuff_Start / Uncuff_BeginMash |
the uncuff mash's start (Uncuffing) | confirmed (code) |
0x00260fd0 |
Uncuff_WithKey |
freeing at once with a key | confirmed (code) |
0x002606e8 / 0x00260a70 |
Uncuff_MashSuccess / Uncuff_MashFail |
the mash's outcome | confirmed (code) |
0x0027bcd8 / 0x0027bc48 |
Mash_IsAlternation / Mash_IsQuitCommand |
the mash's input tests | confirmed (code) |
0x00278018 |
Tag_StartSprayClips |
the spray clips and the turn to the tag | confirmed (code) |
0x00255f08 |
MiniGame_Update |
each update: success, failure or the meter | confirmed (code) |
0x0027e6d8 |
Player_UpdateTheft |
each update: the mode's input (Combat) | confirmed (code) |
0x0022d790 / 0x0022d908 |
LockPick_Start / LockPick_End |
the lock-picking set-up and outcome | confirmed (code) |
0x002878b8 |
LockPick_JudgePress |
a cross press against the dial | confirmed (code) |
0x001b8d38 / 0x001b8530 / 0x001b7a18 |
LockPickDial_Judge / _Draw / _SetDifficulty |
the HUD dial (HUD +0xf420 + player × 0x540) |
confirmed (code) |
0x0022dd98 / 0x0022e020 |
StereoTheft_Start / StereoTheft_End |
the stereo's set-up and outcome | confirmed (code) |
0x00225ff0 |
Mug_CanMugVictim |
whether the held human can be mugged | confirmed (code) |
0x002856b8 |
Player_UpdateMugging |
the mugging (Combat) and its payout | confirmed (code) |
0x00238db0 |
Human_Tag |
HuTag: starts tagging |
confirmed (code) |
0x00273c60 / 0x0022e848 |
Tag_UpdatePlayer / Tag_End |
the player's tag each update; its end | confirmed (code) |
0x002741d8 / 0x002748a8 / 0x00274710 |
TagGame_Init / _Update / _SpendPaint |
the tag's stick game | confirmed (code) |
0x00412dc8 |
Item_TakeOwned |
taking an owned item: witnesses, the shoplifting score | confirmed (code) |
0x001698f0 / 0x00169878 |
Gang_UpdateWanted / Gang_SetWantedTimer |
the gang's wanted timer | confirmed (code) |
0x0041c028 |
Crime_UpdateLevel |
the crime level's decay | confirmed (code) |
Data¶
Context records¶
The registry (0x0059719c, made at 0x00417b10) keeps six lists, one per kind; a record is {+0x00 object,
+0x04 kind, +0x08 next, +0x0c previous, +0x10 prompt text, +0x14 a second value, +0x18 user}. Objects, flags and
humans register through a virtual slot (objects keep the record at +0x130, flags at +0xe0, humans at +0x664).
Confirmed (code) at 0x00417ca0:
| Kind | What | Prompt (GSTRING.HUD id) |
Reach (CfgActionDistance) |
Evidence |
|---|---|---|---|---|
| 0 | a handcuffed human | 2 (uncuff), or 3 (uncuff yourself) for a player who owns upgrade (6, 15) and holds a key | 2 m in global.lua |
confirmed (code) |
| 1 | an object or flag with its own text: SetMsgHandlerEx with message 0 on a world object (Scripts) |
the caller's text, and a second value at +0x14 |
1.1 m | confirmed (code), runtime |
| 2 | a pickable lock (a door) | 15 (pick lock) | 2 m | confirmed (code) |
| 3 | a car stereo | 16 (steal) | 2 m | confirmed (code) |
| 4, 5 | objects with their own text: kind 4 a dealer's offer (AI: GoalDealer) | the caller's text | 1.75 m, 1.5 m | confirmed (code); kind 5's registrar is not traced |
The reaches are stored squared at 0x00514878 + kind × 4 (CfgActionDistance); the executable's defaults are
2, 1.1, 2, 1.5, 1.5, 1.5 m. The prompt texts are GSTRING.HUD strings (Text labels),
fetched by number through 0x0019ee70.
The mini-game record¶
The fields +0x40-+0x4c of the per-player record that 0x00222b18 returns (Combat
gives its address), shared by every timed action; confirmed (code):
| Offset | Meaning |
|---|---|
+0x40 |
s16 meter: the mash meter (modes 1, 4) or the stereo's |
+0x42 |
s16 lock picking: good presses in a row; −1 asks to abandon |
+0x44 |
s16 lock picking: perfect presses in a row |
+0x46 |
u16 mode: 0 none, 1 uncuff mash, 2 lock picking, 3 car stereo, 4 a mash on an object, 5 HuButtonMiniGame |
+0x48, +0x4c |
the stereo's angle and stage (Combat) |
While a mode runs, human state 0x4000000 is set (state flags). Combat's "theft mode 1"
is the uncuff mash and "mode 2" is lock picking. No code was found that sets mode 4 (its start
0x0022df88 and end 0x0022e330, which marks the object 0x8000 and calls 0x0024c560, are reached only through
the dispatch).
Human fields¶
| Where | Meaning | Evidence |
|---|---|---|
state 0x2000000 |
tagging (HuIsTagging); the other state bits are on Combat |
confirmed (code) at 0x002238c0 |
+0x250 / +0x254 |
the pocket: item id and count (HuPutItemInPocket) |
confirmed (code) |
+0x257 |
the carried object's name; anything but none counts as something to give (starting values) |
confirmed (code) at 0x00225ff0 |
+0x278 |
the carried object's drop chance (CfgChar +0xb4; 100 after HuSetCarriedItem), inferred a percentage |
confirmed (code) at 0x00218850 |
+0x36c |
the tag object being sprayed | confirmed (code) at 0x00238db0 |
+0x370 |
money carried (0-999); rolled at creation (Starting money) | confirmed (code) at 0x00218a90 |
+0x3ba |
1 once the current tag is finished | confirmed (code) |
+0x590-+0x59c |
the four interrogation lines; +0x5a0 the interrogation callback (HuSetInterrogation; Interrogation) |
confirmed (code) |
+0x5a4 |
the mug callback (HuSetMugCallback) |
confirmed (code) |
+0x5b0 |
may be mugged (HuSetMug) |
confirmed (code) |
+0x660 |
the current context record | confirmed (code) at 0x00240888 |
+0x19a / +0x19c |
may comment on a tag (HuEnableTagDone) / the tagger's crew comments (HuEnableTagCheer) |
confirmed (code) |
Behaviour¶
Triangle and the prompt¶
Each update, for a player human, the context record nearest by kind is chosen (ContextActions_Pick,
0x00418150, from 0x0023fea8): the current record is kept while it still passes, otherwise the lists are tried in
kind order 0-5 and the first record that passes wins. A record passes when its object is within the kind's reach in
the ground plane and its height is within 1.5 m of the human's waist (feet + 1.0), it has no other user, and for a
stereo (kind 3) the stereo is not below the human's feet. Confirmed (code) at 0x00417ed0, 0x004180b0.
Triangle pressed (command 0xa, Commands) runs Player_TriangleAction after a climb
is tried for a pad-controlled human (an AI's triangle runs it alone), and before the jump and the drop
(Triangle with something in hand); an earlier reading here had it before the climb.
Confirmed (code) at 0x0027c120, 0x002811f0:
- Nothing while a move or a state blocks it (state mask
0x7bf9e9f7ff0, record+0x08mask0x2fefefff). - A human with no player number standing by a cuffed player uses a key (item 6) if either holds one
(
0x00260fd0). - A tag in progress (a tag spot, a particle object with class bit
0x10, at+0x36c) keeps the press. ContextAction_Use(0x0024d530) by the record's kind: 0 frees the cuffed human (Uncuffing: the mash of mode 1; with a key, at once); 2 sets mode 2 and plays 687ANIM_LOCKPICK_INTRO; 3 sets mode 3 and plays 683STEREO_STEAL_INTRO(both through0x002789d0, which turns the human to the object and starts the mini-game); any other kind hands the press to the object's message handler (its+0x44, message 0 with the human as the subject); a true result ends the press. Confirmed (code), and at runtime for a kind-1 bat.- Otherwise the pick-up search (
0x0024d810, objects within 1.5 m; only while0x005109a0is set). It too sends message 0 to every object it gathers, before its filters, and a true result ends it; then it takes one (Breakables, A bat in hand). With something in hand and an object to take, it drops what is held (0x00257f38) and sets human+0x5b8, so the triangle hold takes the new one. With nothing to take, only an AI drops here; a pad-controlled human gets 0 and the dispatcher goes on to the jump, then the drop (0x0024d810, confirmed (code); an earlier reading had every human drop here).
The prompt (two text widgets per player at HUD +0x6b40, 0x590 each;
HUD) is chosen every frame by HUD_Update (0x001af010), confirmed
(code): nothing while the player is mugging, mugged, tagging, in a mini-game of mode 2 or 3, in a hold
(0x18000000000), uncuffing (action 0x15) or a few other states, or when command 0xa is not available
(0x00147738). Otherwise, in order: holding a human who can be mugged → GSTRING.HUD 1 (mug), or 0 (interrogate) when
the human has an interrogation set; a revivable friend or gang member knocked out within 3 m and in sight, while the
player or (in co-op) the downed player carries a flash → 4 (revive, HUD: the revive
test); a context record → its text (+0x10; the second text +0x14 goes in the hint
box at priority 0, HUD); else a nearby human's own talk prompt (0x001acd60). The
panel's activity test then matches the prompt's text against the dealer prompts (HUD). The
prompt sits 0.04 above its place in the default video mode (0.02 in the others) and rises with a scroll-in message
(0x0019f430).
Arrest¶
HuSetArrested(h, on) (Human_SetArrested) runs Human_Arrest (0x0022ec18) or Human_Unarrest (0x0022ef58),
then sets state 0x20000000. Confirmed (code) at the cited addresses.
Arrest, for a human not already cuffed:
- The human leaves its fight stance and drops a held weapon of kind 4 or 6, or anything held without human flag
0x2000. A stun ends. - Its push weight (attribute 7, vtable
+0xe4) becomes 1e9, so nothing shoves it. State0x8000(block) is cleared and0x20000(cuffed) set. - Movement style
0x11is pushed (Human_PushMoveStyle,0x00253ed0), which puts 320ANIM_ARRESTED_IDLEin anim slots 0 and 11 (Anim slots). The action (record+0x14) becomes 0. Brain_OnArrested(brain, 1)(0x0028c5d8): the brain's actions are cleared, its target dropped and its goals popped down to a goal of type0x41if it has one. Then the human gets event 17{+0x00 the other human of a grab (record +0xc4), +0x04 1}, which a script handler receives as(self, other, 1)(ScriptHandler_MarshalMessagecase0x11,0x00384ce0).- Brain
+0x288= 0. - The kind-0 record (
Human_RegisterContextAction, human vtable0x0053f088slot+0x124, args kind 0, no text) is registered for one of two humans: - an AI human friendly to player 1 (
Human_IsFriendly,0x00222a90). An AI Warrior in the player's crew is one; - a player, when two players are in or when he owns upgrade (6, 15) and holds a key.
That human says 25 arrested (Speech). Unless it is a player with a
key, it also gets the dyn_cuffs icon over its head (Human_ShowOverheadIcon, 0x002271f0, handle at human
+0x360; dyn_p_one and dyn_p_two names become dyn_play_one and dyn_play_two, with _euro when game state
+0x120 is set).
7. For a type-3 brain, the player whose gang it is gets Stats_AddHarmony(…, player, 0, 1) (0x004de250), a
statistics tally, not a HUD call (confirmed (code) at 0x004de250).
On the HUD, a cuffed member of the player's gang is listed by the crew status
list for as long as state 0x20000 holds: his portrait with a pulsing blue badge,
and for 2.5 s a caption with his name and the arrested text (GSTRING.HUD 226). No interface sound plays. The list
tests the state, not the arrest call, so a scripted HuSetArrested shows the same. Confirmed (code) at 0x001a0420;
confirmed (runtime) by setting the state over PINE. He keeps his mark in the gang
tally, which counts only members not down.
A human with no AI brain component (vtable +0xf4 null) gets only state 0x20000, the style and action 0.
Unarrest (Human_Unarrest), for a cuffed human:
- Brain
+0x40gets0x80000004, and the kind-0 record is removed (slot+0x12c). 0x0024ce40is called and the icon removed (message0x15,Human_RemoveOverheadIcon,0x00227388). Style0x11is removed (0x00253f78), state0x20000is cleared, and the push weight returns to 1.- A member of a leaderless gang (gang
+0x40= 0) with a leader other than itself and a type-3 brain clears its actions and goals and follows the leader (Goal_FollowPlayer, 2.0, mode 3). - Event 17 goes out as above with
+0x04= 0:SetMsgHandler(h, 17, "SnowUnarrested")gets(self, other, 0), andotheris the null handle unless the human was in a grab.
Uncuffing¶
Triangle by a cuffed human's kind-0 record (ContextAction_Use, Triangle, step 4) needs two things:
the cuffed human is not already being freed (+0x08 0x10000), and nothing stands between the two
(0x0021c0a8, a 0.2 m capsule collision test from the freer to him). The record's user (+0x18) becomes the
freer. Then the press goes one of two ways. Confirmed (code) at the cited addresses.
With a key (item 6 held by either), Uncuff_WithKey (0x00260fd0):
- Interface cue 24 plays and one key is spent: the freer's, or else the cuffed human's.
- The freer turns to face the cuffed human (
Attack_SteerToTarget, 0.1, over clip 325). He plays 325ANIM_ARREST_RELEASE_INTRO_FRONT(holding+0x080x2000), then 332ANIM_ARREST_RELEASE_END(end hook0x002605f0), then his idle. - The cuffed human gets
Human_Unarrest,Human_ClearPartnerand a heal (below). He plays 326 (paired, holding0x10000), then 333ANIM_ARREST_RELEASE_END_REACT(end hook0x00260670), then his idle.
When a player frees himself with his own key, he plays only his half.
Without a key, the mash (Uncuff_Start, 0x00260ca8):
- The freer says 68
unarrest_reasureand turns to face the cuffed human over clip 325. His action (record+0x14) becomes0x15. Uncuff_BeginMash(0x0022d3f8):- leaves the fight stance; mode 1, meter 0;
- the cuffed human becomes the freer's partner (
+0xc8); - both bodies share a new group (body
+0x3c, from a counter atIPhysics+0x10), so they never touch; - both get push weight 1e9;
- a held weapon of kind 3 or 4 is dropped;
- state
0x8000is cleared on both and0x4000000set on the freer.
For the triangle press it also shows the player's mash meter (HUD_MashMeterShow: HUD +0xebc0 + player ×
0x430, button id 1 and sprite word 0x171). Hint 19 is queued when in-game hints are on, the level is not an
Armies level, hint 19 is unlocked and the hint's shown count (game state bits 24-25) is below 2.
3. The freer plays 325, holding +0x08 0x2000000, which keeps the mash's input closed until it ends. He then loops
329 ANIM_ARREST_RELEASE_LOOP.
4. The cuffed human plays 326 ANIM_ARREST_RELEASE_INTRO_FRONT_REACT paired to the freer, then loops 330, holding
0x10000 throughout. He gets the freer as his partner too.
The cuffed human's kind-0 record stays registered during the mash; only Human_Unarrest removes it.
Each update (Player_UpdateTheft mode 1, 0x0027e6d8, while +0x08 has none of 0x7c7eee0):
- An alternation between commands 6 (L1 held) and 4 (R1 held) adds the gain.
Mash_IsAlternation(0x0027bcd8) counts the first of either and then each switch. The gain is half ofCfgButtonMash's press gain, × 1.5 for a Warrior of class byte+0x08= 1 and × 0.7 for 3, rounded. Each gain also restarts the decay. - A quit command, 10 (triangle), 17, 18 (cross) or 30 (circle) (
Mash_IsQuitCommand,0x0027bc48), sets the meter to −1. - Otherwise the meter decays by
CfgButtonMash's decay each update. The decay stops once a step takes the meter to 0 or below, and it does not run before the first alternation: the flag0x005109a8starts at 1.
The executable's defaults are a target of 1000, a decay of 10 and a press gain of 100 (0x005102b8-0x005102c0).
The script values in force are on Combat.
The outcome (MiniGame_Update mode 1, 0x00255f08, each update):
- Success: meter ≥ target.
Uncuff_MashSuccess(0x002606e8):- the mini-game ends (
MiniGame_Abort: mode 0, meter hidden, record user cleared, state0x4000000cleared, action 1, partner cleared); - the cuffed human says 67
unarrest_thank; the hint's shown count rises by one; - the freer plays 332 (blend 1/6 s, end hook
0x002605f0), then his idle; - the cuffed human gets
Human_Unarrest, then a heal when he is knocked out (Human_IsKnockedOut, state0x40000) and has human flag0x4; - the cuffed human plays 333 paired (end hook
0x00260670), then his idle.
- the mini-game ends (
0x00280fd8(freer, 3000) sets the per-player record's +0x4d and +0x50 = now + 3 s (their reader is not
traced).
- Failure: the meter is below 0 (a quit command, or a decay step that ends below 0), or the cuffed human is gone
(Object_AsHuman, 0x00229868, null). Uncuff_MashFail (0x00260a70):
- the mini-game ends;
- the freer plays 332, then his idle;
- the cuffed human returns to his idle loop (still 320, since he is still cuffed). His 0x10000 and his partner
are cleared.
- A hit on the freer: Human_ApplyPendingDamage sends a human in a mini-game other than lock picking to
0x00268c50. That function ends the mini-game and plays 331 ANIM_ARREST_RELEASE_HIT_REACT (holding 0x2000).
The cuffed human's clips are not reset there (not traced further).
- A human leaving normal mode (0x002325e0, from Human_SetNormalMode and scenes) also ends it.
While the mash runs, the meter's fill is meter ÷ target each update (HUD_MashMeterUpdate), and the action prompt
is hidden (action 0x15).
Lock picking¶
A door made pickable by SetDoorPickable (message 0x22 value 10; Doors) registers a kind-2
record. Triangle at it starts the game, confirmed (code) at 0x0022d790:
- Mode 2, both counters 0; state
0x4000000; the human's target is the door; the first time (tutorial hints on), hint0x14; the start callback (CfgSetLockPickHandler's first name) runs with the human's and the door's handles; the HUD dial is shown at the difficulty of the Warrior class's byte+0x0aless 1 (0-2). - The dial (
LockPickDial_Draw): three pins, all starting at 3.14 (not π, HUD). Each frame the current pin turns by 0.1 rad × its speed and wraps in 0-2π; the speeds are 1, 2 and 3, and the directions by difficulty are (+, +, +), (+, −, +) and (−, +, −). The step runs once per character update, 30 times a second, so a pin turns once in 62.8 steps (2.09 s), 31.4 (1.05 s) and 20.9 (0.70 s). Confirmed (runtime), PCSX2 2.9.94: with the dial shown on a copy of quick-save slot 3 (player 0's dial0x0060fc60,+0x478written 1), the angle+0x454of pin 0 (speed 1) grew by exactly 0.1 every second 60 Hz tick (0x005104f4), 90 steps in 180 ticks, wrapping 6.24 → 0.0568. - Cross pressed (
0x12) judges the current pin's angle θ (LockPickDial_Judge): good when θ is at least the upper bound or at most the lower one, perfect inside the narrower bands, otherwise a miss:
| Difficulty | Good | Perfect |
|---|---|---|
| 0 | θ ≥ 5.45 or θ ≤ 0.80 (312°-46°) | θ ≥ 5.90 or θ ≤ 0.20 (338°-11°) |
| 1 | θ ≥ 5.70 or θ ≤ 0.57 (327°-33°) | θ ≥ 5.95 or θ ≤ 0.12 (341°-7°) |
| 2 | θ ≥ 5.90 or θ ≤ 0.35 (338°-20°) | θ ≥ 6.05 (347°-0°) |
A good press adds 1 to +0x42 (a perfect one also to +0x44) and moves on to the next pin; a miss resets both
counters, puts every pin back at 3.14, plays a click and runs the stage-fail callback with the human and the door.
Confirmed (code) at 0x002878b8, 0x001b8d38; the band values are set by 0x001b7a18.
4. Triangle, or any command outside cross, L1, R2, the d-pad and SELECT's combinations, sets +0x42 to −1:
the pick is abandoned.
5. Three good presses in a row succeed (MiniGame_Update), then 689 ANIM_LOCKPICK_END; an abandoned pick ends
with 690 ANIM_LOCKPICK_FAIL (0x00278628).
The outcome (LockPick_End, 0x0022d908), confirmed (code):
- Success: the success callback (human, door); the door is unlocked (message
0x22value 0) and swung open (Door_OpenAnimated). Three perfect presses score bonus event 1-3 and raise no crime; otherwise a break-in (crime type 1) is reported at the human, with responders. - Abandoned: the stop callback (human, door). A
dyn_door_swingingdoor counts abandoned attempts (its record+0x29), and the third reports a break-in. - Either way the dial is hidden; the hint counter (game-state bits 26-27) counts successful picks up to 2.
No inventory item is spent: there is no lockpick item; the inventory has none (Inventory items).
The car stereo¶
CarSpawnRadio puts a dyn_carstereo in a car; breaking the car window (glass type 12, panes)
frees it and it registers a kind-3 record. The game itself is Combat: the stereo theft;
its set-up and end, confirmed (code) at 0x0022dd98, 0x0022e020:
- Start: mode 3, meter at twice
CfgButtonMash's gain, stage and angle 0; a camera change on the player's camera (0x001361a8, inferred); hint0x12the first times; the stereo HUD widget (HUD+0xfea0+ player ×0xb10). - Success: the player gets $15 (item 2) and one car stereo (item 11); the stereo is taken as an owned item
(below);
CfgSetSteroTheftHandler's callback runs with the human and the car. - The hint counter (game-state bits 22-23) counts thefts up to 2.
Mugging¶
The stick game and its timings are on Combat: mugging. Who can be mugged
(Mug_CanMugVictim, 0x00225ff0), confirmed (code): the player must be holding the human from the front or the rear
with no move playing, and either the human has an interrogation set (+0x5a0, below), or it may
be mugged (+0x5b0, HuSetMug; Human_Init sets it to 1 at 0x002180ec, so every new human may be) and:
- a human no player controls must not carry the ledger (pocket item 12) and must have something: a carried object
(
+0x257notnone), money (+0x370), or a pocket count (+0x254); - a player human (the other player) only while
CfgPlayerMuggingis on (game state+0x5708) and he holds any of items 0-6.
A human made by HuCreate with no HuSetMoney carries the money Human_Init rolled
(below); for the street civilian (PoizoCiv, type 417) that is never less than $5, so he can
always be mugged.
What happens, confirmed (code) at 0x002856b8:
- The mugger says speech command 19
mug, or 39mugcopwhen the victim's brain is a cop's; an interrogation plays the victim's set lines instead. Hint 0 (a mugging) or 1 (an interrogation) the first times. - Half-way to the required time the victim says 28
resist(103dirty_resistfor ped type 5, inferred a dirty dealer). A victim with nothing (no money,+0x257none, pocket item 0, no interrogation) says 31no_itemat that point and the mugging stops; it still ends through the success clips (the result flag, mugger+0x5b4, is set to 1), so the mug callback runs with true although nothing was taken. - Success is decided in the update that reaches the required time, before any end clip: the victim says 30
item(104dirty_item). With pocket item 0 and+0x257none, all its money (+0x370; ped type 5 gives 1.5 times, at most 999) goes to the mugger's player in one call,Inventory_AddItem(inv, player, 2, money, 1)(0x0041e5b0, notify on), the victim's money is set to 0 and item 2's pick-up sound plays (0x0010fcd8with the hash at inventory entry+0x24). A victim with a pocket item or object hands that over first (0x002334d0: pocket items 1 and 3 are added to the inventory with notify, item 4 equips the switchblade, a named object goes to the mugger); its money follows with the same call once the object handed over no longer resolves (state 5). A player victim hands over all of items 0-6 (0x00285520). An interrogation instead plays the fourth line and pays nothing (below). - Then (state 5)
0x00273110(mugger, result)plays the end clips, mugger 344 and victim 345 on success, 346 and 347 on failure, and gives the mugger's clip the end callback0x00273090(success) or0x00273038(failure). A player mugger who succeeds also counts a statistic by the victim's brain kind (1 → 6, 2 → 7, 4 or 5 → 5, others none;0x004ed948on0x006fe490). - Any command outside the game's own ends it; so does, for a mugger no player controls, its time limit.
Adding the money notifies, synchronously and in this order (Player state): the
CfgMoneyCallback function with (player, amount), the CfgInventoryCallback one with (2), then the
CfgHuInventoryCallback one with (player, 2). The mugging calls nothing for the HUD; the HUD shows the inventory
count. Confirmed (code).
The mug callback (HuSetMugCallback, human +0x5a4). Every end of a mugging goes through 0x0022ceb8(mugger,
victim, success): the end clips' callbacks above, when the mugger's clip ends, not at the decision; a let-go
(0x00258a88); a hit and the other aborts (0x002325e0, 0x00267e48, 0x00268df8, 0x00268e50,
Player_UpdateActions). It clears the mugging states (0x100, 0x200), puts the pair back in a rear hold (0x80
/ 0x20), withdraws hint 0 or 1, and then:
- a victim with no interrogation that is not a player: the mugger's callback (
0x002262f0) is called with (mugger, success), so it also runs, with false, for a failed or broken-off mugging; - a victim with an interrogation: on success only, the interrogation callback (below);
- a player victim: no callback.
Confirmed (code). By the time the callback runs the money has already moved.
Starting money and the carried object¶
Human_Init (0x00218008, from HuCreate through Human_Create 0x00233d60) sets the money (+0x370), the
carried object (+0x257) and its drop chance (+0x278); the pocket (+0x250, +0x254) starts empty. Afterwards
only HuSetMoney (0x00238100), GangSetMoney (0x0016bd38), a mugging, a drop (0x00233494) and the shopkeeper
goal (0x002e74c0) write a human's money. Confirmed (code).
The inputs are the type's CfgChar record (0x00684620 + type × 0x1ac): its category byte +0x11b (category 4
with byte +0x14b = 1 uses record 16 instead), the integer +0xb4 (v16; -1 means "use the class range",
otherwise it is a drop chance and a money cap) and the name +0x16c (str15: an object, a grp_ object group, or
none); and that category's CfgCharClassAttribs record (game state + category × 16): min (byte +0x08), max
(+0x09), noObject (byte +0x10, percent), bonusChance (byte +0x11, percent) and bonus (float +0x14).
Every draw uses the game's generator (0x006eb880, Scripting); rand(a, b) (0x003353f0) is a
to b inclusive. Confirmed (code) at 0x002187e4-0x00218a90:
roll = rand(0, 100).- The object:
nonewhenroll <= noObject. Otherwise+0x278 = v16, and astr15containinggrp_gives a random member of that object group (drawn from another generator,0x006eb8a8;nonefor an unknown group), while any otherstr15is the object whenroll <= v16andnoneotherwise. - The money starts at 0. If
v16is -1 or the object is notnone:m = rand(min, max). Else, whenroll <= noObject:m = rand(min, v16)ifmin < v16, elsem = v16. Else the money stays 0 and step 4 is skipped. - When
rand(0, 100) <= bonusChance,m = (int)(m × bonus). The money ismclamped to 0-999. - Categories 4 and 6 then set the brain's
+0x26cto 1, or 2 when+0x14bis 1 or the money is 21 or more; category 4 first drawsRandom_Int(100)(0x003353b8, 0 to 100) and takes 2 when it is below 10. Categories 5 and 7 set 3.
The CfgCharClassAttribs records, confirmed (runtime) over PINE in level99 (a copy of the user's slot 6; game
state 0x01fd8400):
| Category | min-max |
+0x0c |
noObject |
bonusChance |
bonus |
|---|---|---|---|---|---|
| 1 | 10-20 | 0.25 | 100 | 1 | 5 |
| 2 | 10-15 | 0.2 | 100 | 1 | 5 |
| 3 | 10-20 | 0.2 | 100 | 1 | 5 |
| 4 | 5-20 | 0.1 | 100 | 1 | 5 |
| 5 | 7-20 | 0.1 | 100 | 0 | 1 |
| 6 | 1-4 | 0.1 | 100 | 0 | 1 |
| 7 | 2-6 | 0.1 | 100 | 0 | 1 |
| 8 | 5-10 | 0.1 | 100 | 0 | 1 |
| 9, 10 | 5-10 | 0.1 | 0 | 0 | 1 |
| 11 | 5-10 | 0.1 | 20 | 0 | 1 |
| 12 | 10-20 | 0.1 | 20 | 0 | 1 |
| 15 | 10-20 | (not read) | 100 | 0 | 1 |
Category 15 was read in level87 (below), the same game state; its +0x0c was not read.
PoizoCiv (type 417), confirmed (runtime) from the same state: category 4, +0x14b 0, v16 -1, str15
grp_male_ped. Step 2 always gives none (noObject is 100), and the money is rand(5, 20), times 5 when the
second roll is 0 or 1 (2 in 101): $5-$20, rarely $25-$100. The $18 seen at runtime (Combat)
is in range. His pocket is empty (item 0, count 0), so the mugging pays money only. A seeded reimplementation draws, in
this order: the object roll, the money, the bonus roll, then Random_Int(100) for +0x26c.
level87's sellers and Destroyer soldiers (issue #354). Their CfgChar records, confirmed (runtime) over PINE
in PCSX2 2.9.94 on 2026-10-13 (a copy of the user's slot 7, level87 checkpoints 3 and then 2 loaded through mode 8
as on Scripts: level index 3 to 0x005e5db0, the checkpoint to W_GameState + 0x33a,
3 to +0x14c; game state 0x01fd8400); categories 11 and 15 are in the table above:
| Type | Humans seen | Category | v16 |
str15 |
|---|---|---|---|---|
| 428 | drugsSpawner0 (a seller) |
15 | 0 | none |
| 431 | spraySpawner0-2 (the paint sellers) |
15 | 0 | none |
| 197 | WS1, liqD_01 (Destroyer soldiers) |
11 | 5 | none |
Through the steps above (confirmed (code) at 0x002187e4-0x00218a90):
- The sellers always carry $0.
noObjectis 100, so step 2 givesnoneand step 3 takes theroll <= noObjectbranch withv16= 0, which is not abovemin: the money isv16, 0, and the bonus (1.0) leaves it 0. - A type 197 soldier carries $5 or $0. When
roll(0-100) is 20 or less (21 in 101), step 3 givesv16= 5 (min5 is not below it) and the bonus (1.0) keeps 5. Otherwise step 2 writes+0x278= 5, the object staysnone(rollis abovev16) and the money stays 0. The class range 5-10 is never used, becausev16is not -1 and the object is alwaysnone. Types 192, 194 and 199, the level's other Destroyers, have the same record (category 11,v165,none), so the same $5-or-$0 unless a script sets their money.
At runtime (confirmed (runtime), the same method, the live humans' +0x370 polled over PINE for about four minutes in
checkpoint 3 and five in checkpoint 2, each human's money logged when first seen; log kept in the track's scratch
folder): every seller held $0 (spraySpawner0-2, type 431, and drugsSpawner0, type 428, in both checkpoints).
The type 197 soldiers held $5 (WS1, checkpoint 3) and $0 (liqD_01, checkpoint 2). The other category 11
Destroyers gave the same two values: a later WS1 (192) $5, and WS0 (194, then 199) and liqD_02 (194) $0; the
CfgChar record of type 199 is the same as 197's. Boozer (194) and Knockout (192) held $5 in both checkpoints;
most likely the script's EDConstructor set it with HuSetMoney (Scripts, fix 4;
inferred), and the roll's $5 branch is the alternative. Boozer, Knockout and WS1 (197) later went to $0 while
fighting the Warriors (inferred: dropped when down, below). The civilians (type 395) held $5-$19 and the
bums (types 272-278) $1-$4, which fit category 4 for the civilians and 6 ($1-$4) for the bums (inferred: their
categories were not logged).
Human_Init writes +0x278 only on step 2's object branch (stores at 0x00218850 and 0x00218888); the only other
writer of that field is HuSetCarriedItem (0x00238230), which stores 100 (sw at 0x00238270). Confirmed (code).
So a human whose roll skips step 2's object branch keeps an older value. drugsSpawner0 (type 428, whose noObject
of 100 always skips it) read 100 in checkpoint 3 and 5 in checkpoint 2, confirmed (runtime). The 5 can only be left
in the slot by an earlier human. The 100 is either such a leftover or an earlier HuSetCarriedItem; against the
script, his logged object (+0x257) was none while HuSetCarriedItem sets it (inferred: a leftover). So +0x278
is no sign of which branch ran.
So the $0 sellers and the $0 soldier seen in Coney's level87 run (issue #354) match the original, and Coney needs no
fix for them (Coney's implementation, the starting money).
Dropped when down¶
A human whose health runs out drops what he carries: Human_OnHealthOut (0x002674c0, Defeat)
calls Human_DropCarried(human, 1, 1) (0x00232c60) when he is wounded or knocked out, unless he has human flag
0x4 (the players and the crew, Human flags). Every human goes through it, so a spawner's
human drops his money as a scripted one does (Starting money). Confirmed (code) at 0x00232c60; the
order of the steps:
- No brain: nothing.
- The pocket (
+0x250, an item):+0x254pickups of that item's object, at his feet 0.5 m up. Unless the brain's kind (+0x04) or its+0x26cis 5, nothing more is dropped. (For brain kind 5 the pickups go round him instead, 1 m out in his free sectors, AI: neighbour sectors.) - Power cuffs: a human with cuffs (
Human_GetCuffCount) dropsdyn_powercuffswhenRandom_Int(100)is below 51 and game state+0x158is set or unlock (6, 14) is; then nothing else. - The carried object (
+0x257, notnone): an AI human drops it unless+0x278is -1, and carriesnonefrom then on. A player keeps it whenrand(0, 100)is below 51; otherwise he drops it and loses money: the object type's+0x5a× game state+0x380. - Money (the carried object is
none; a human of brain kind 1 whose class has+0xb4= 0 dropsdyn_keyinstead once unlock (6, 13) is set):- brain kind 4: his money × his category's
+0x0cfactor (0.1-0.25 in the table above), at least 1 when he has any; - any other AI human: all his money (
+0x370); - a player:
rand(min, max)of his category, at most what his inventory holds, taken from it.
- brain kind 4: his money × his category's
One dollar or more makes a dyn_money pickup holding the amount (+0x124) at his feet, 0.5 m up, with the
respawn timer of item 2, and his money becomes 0.
So level87 chapter 3's early Destroyers, given $5 each by their constructor, leave $5 each when beaten: the price
of one can of paint (GoalDealer). Coney drops nothing yet (level87's
fixes, fix 4). Fix: on health out (wounded or knocked out), run steps 1-5 with the game's
random numbers. Tests: an AI human of a brain kind other than 4 with $5 and no object, knocked out, leaves one
dyn_money of $5 and has $0; a civilian of brain kind 4 with $15 and factor 0.1 leaves $1; a human whose object is
none and money 0 leaves nothing.
Interrogation¶
+0x5a0 holds a reference to a Lua function, confirmed (code). Its only writers: HuSetInterrogation (0x00239f20:
clears the four lines and +0x5a0, then stores the lines and the callback; a nil callback leaves 0), Human_Init
and Human_Destroy (0), and the interrogation's success (0x00226168: calls the function with (victim, mugger,
true), the mugger an invalid handle when there is none, then clears +0x5a0 and the lines, so an interrogation
succeeds once). Non-zero means "can be interrogated": Mug_CanMugVictim accepts the human whatever it carries and
whatever +0x5b0 says, the prompt reads "interrogate", and the mugging plays the set lines and pays nothing.
SetInterrogateParam does not touch it: it only overrides the stick game's tuning for every mugging
(Combat: mugging). No level99 script calls HuSetInterrogation (levels 2, 11 and 83 do), so
the lesson's mugging of PoizoCiv is a plain mugging.
The scores (crime events 4-5 to 4-7) are on Statistics. The mugging itself reports
no crime; type 8 (Mugging) comes from scripts or from the witnesses' goals, which report a type from their own
records (AI: crimes).
Tagging¶
A level's tag spots are part_spray_tag particle objects (class bit 0x10 marks a particle system; configured by
CfgTagSettings) with flags of activity 12
(World flags); global.lua's helper loads a pattern (HuTagPattern) and calls HuTag.
Circle + triangle (0x24) also sprays where the player has paint (Combat).
HuTag (0x00238db0), confirmed (code): a player with no spray paint (item 3) says 37 nopaint and the
human himself gets event 0xe with the tag and 0 (not finished; the record goes through the human's own vtable
+0x44, so a script's event-14 handler also runs for a refusal, below); otherwise the human's
target (+0x33c) becomes the flag, +0x36c the tag, its action 0x17, and a player occupies the flag. HuTag
calls no script itself.
The stick game, confirmed (code) at 0x002741d8, 0x002748a8, 0x00274710:
- The pattern's points (
0x00510914count n, float (x, y) pairs at0x006cd978) are sampled along a uniform Catmull-Rom curve (0x00273ff0): segment i runs from point i to i + 1 with weights (−t³/2 + t² − t/2, 3t³/2 − 5t²/2 + 1, −3t³/2 + 2t² + t/2, t³/2 − t²/2) on points i − 1, i, i + 1, i + 2, the indices clamped to the first and last point (so the last segment stays on the last point). Each segment, i = 0 to n − 1, takes ⌊300 / n⌋ samples at t = k · n / 300 (k = 0, 1, ...). A sample's x and y are truncated to integers and their low byte kept, so pattern values are grid cells 0-255 directly (no scaling; larger values wrap). A sample joins the path when its squared distance from the last one kept is more than 6 (the first is compared with (0, 0)); at most 300 samples, so at most 300 path points. The tag's painted fraction (its+0xc8, tag spots) × the path length, truncated, is the start index s (0 for a fresh tag). Every path point is also copied into the painted list, whose count is set to s, so a half-sprayed tag shows its first s points already painted. The cursor starts on point s. - The cursor moves with the left stick when its squared length is at least 0.04 (0.2): by stick × elapsed ms ×
the speed, the elapsed time being the game clock since the last unpaused update, at most 30 ms. The speed ramps
linearly from 0 over 2 s from the ramp start (
+0x51c: the first update, and again at each new charge, see 4; a slip does not restart it). The cursor stays inside 0-255 on both axes. The stick is the per-player record's+0x00/+0x04floats (the pad's raw stick, not turned by the camera). The cell under the cursor (both floats truncated) is painted when its squared distance from every painted cell is at least 4 (+0x04); a 301st cell ends the game (5). - Tracking (
+0x500,TagGame_IsOnTrack), with p the progress index and the cursor's truncated cell; "near" is a squared distance below 36 (within 6 cells):- near any of the 4 points behind (p − 4 to p − 1): on track, p unchanged (progress never goes back);
- else the first of p, p + 1, p + 2, p + 3 (not beyond the last point) that is near: on track, and p becomes that index. Point p itself is tried first, so p stays put while the cursor is within 6 cells of it and moves on only once the cursor has left that circle (not to the nearest point: to the first one in order);
- else off track: the off-track count (
+0x510) goes up by one if the stick moved this update.
The count is not reset by coming back on track: it is cleared only by a slip or a new charge. At the start
of a moving update, after painting and before tracking, a count above 4 is a slip: the cursor snaps to point
p, the count is cleared, the game pauses for the pause time (+0x514 = clock + pause), the pad rumbles (per-player
+0x1d = 1, +0x1c = 255) and a crew member may comment (speech 80 tagcheer, when the tagger's +0x19c is
set; who speaks). So five off-track moving updates since the last slip (30 Hz: about
a sixth of a second in all, not necessarily in a row) make the sixth moving update slip.
4. Paint (TagGame_SpendPaint, 0x00274710, run first in every update, paused ones included, so the charge
keeps draining through a pause): the first update stamps the charge start (+0x518); when the charge time has
passed, a new charge starts: the cursor snaps to point p, the off-track count is cleared, the game pauses and
the ramp restarts from the end of the pause; then one can is taken (item 3 − 1) if there is one, else the game is
over (+0x4fc = 1, progress set to the path count). The first charge takes no can when it starts, but
Tag_UpdatePlayer ends the game once the can count is 0, so n cans give n charges.
5. Finished (Tag_IsComplete, Tag_GetProgress 0x00274e38) when the path count < p + 4, that is
p ≥ count − 3: the third point from the end, which is where the drawn guide ends (the panel leaves the last 3
points out, HUD). The progress is then 1.0; below it is p / count, the
value sent to the tag each update. Painting a 301st cell or running out of cans also makes it 1.0 but sets +0x4fc,
which Tag_UpdatePlayer treats as unfinished.
6. Any command outside the game's own (PlayerCmd_IsOtherInput), no cans left, or the action becoming 0x18 ends
it. A paused update (before +0x514) runs only step 4.
The tuning, by the Warrior class's byte +0x09 (1-3, 0 counting as 1), from the table at 0x00510918, unless
HuTagDifficulty sets its own (no script does):
| Difficulty | Charge time | Pause | Speed (cells per ms) |
|---|---|---|---|
| 1 | 13,000 ms | 500 ms | 0.05 |
| 2 | 11,000 ms | 600 ms | 0.07 |
| 3 | 9,500 ms | 500 ms | 0.073 |
HuTagDifficulty defaults |
15,000 ms | 1,000 ms | 0.06 |
The end, confirmed (code): on a finish the player's update (Tag_UpdatePlayer) marks the tag sprayed (+0x3ba,
messages 0x41 1.0 and 0x19 3) and a crew member says 83 tagdone (who speaks); then
Tag_End (0x0022e848): a clean finish scores bonus event 1-3; unfinished with less than 30 %
of the current charge left, one more charge is spent. The tagger's flag is freed, the tagger gets event 0xe
(the tag's handle and whether it was finished, through its own vtable +0x44) and the tag object (human
+0x36c) gets message 0x13. Hint 0x10 in level 0x57.
Tagging is crime type 10, which sends no responders (Crime types).
What the player sees: body, paint, mist and the wall¶
The body. Tag_StartSprayClips (0x00278018, from Tag_UpdatePlayer on the first update in action 0x17)
drops the held object only when its type's anim set (+0x87) is 4 (OVERHEAD_WEAPON_SET) or 6 (GHETTO_SET)
(Human_HoldsKind4Or6). A pipe (dyn_pipe_a), a bat or a crowbar is set 3 (CLUB_WEAPON_SET, disc check of
CfgObj's 20th argument) and stays in the hand; what 334/335 do with it is not traced. It queues 334
ANIM_TAGGING_INTRO (end hook Tag_OnIntroEnd), then the loop 335 (loop hook Tag_StartSprayEffect), sets held
flag 0x400 (meaning not traced) and calls Human_TurnToFacePoint(0.5 × the play time of 334, human, the tag's
point): the turn to the tag object's position is spread over the first half of the intro. Confirmed (code). When a
pause begins (a slip or a new charge; TagGame_IsPaused 0x002745e8 turns on during the update),
Tag_RestartSprayClips (0x00278210) plays 337 and then the loop 335 again, with the same hooks.
The end (issue #407). Confirmed (code) at the addresses unless marked. Tag_EndSprayClips (0x002783b0) plays
336 ANIM_TAGGING_END, whose event 0x31 at frame 7 removes the can that 334's event 0x30 made at frame 10
(props of a clip, human +0x348). Its callers:
Tag_UpdatePlayer(0x00273c60, a player's spray, after the stick game's update), at0x00273f10: a finished tag (Tag_IsComplete), any other command (PlayerCmd_IsOtherInput: the player lets go), or no cans left; after it the action is set to 0. At0x00273dc0: the action became0x18while tagging.MiniGame_Update(0x00255fd8, a human that is not a pad player,+0x1b0= −1, so an AI tagger): action0x18while tagging (0x00256004), or any other command while tagging (0x00256034, then action 0). The AI'sTagaction presses command 10 each update (AI code), so the end comes from0x18.- Who sets
0x18: the human's message0x13(case0x00245978ofHuman_HandleMessage, jump table0x0055c980indexed by message − 1): while tagging, action0x18; a human that is not a pad player (player record+0x1b= 0) also gets+0x3ba= 1, a finished tag. The tag spot sends the tagger0x13when its fade reaches 1 or 0 or when it is hidden. So an AI tag ends with 336 when the wall is painted, and a player's ends with 336 if his spot is hidden. Message0x17with state 4 while tagging also sets0x18(0x00245a94; who sends it is not traced). Tag_OnIntroEnd(0x00277f10) calls it only when the tag object no longer resolves, and then it does nothing: its first step returns when+0x36cdoes not resolve (0x002783e8). No 336 and noTag_Endthere; what then ends that spray is not traced.
What it does, in order:
- Takes three tasks. Makes a fade (type 9) of 0.05 s (
0x3d4ccccd), no flags, no owner. - Cuts off the current top task (vtable
+0x84; the bottom one when the top is a fade): the loop 335, or 337. A clip task clears its held flags as it is cut off (Task fields). - Push sphere call with 0, as
Tag_StartSprayClipsmakes (Human_SetPushSphere,0x0021c058). - Picks the clips by
Human_IsInFightStance(0x00228340, state word0x00any of0x3):- Not in the stance: anim state (record
+0x18) = 0; the idle loop (type 1) of record+0x28(anim slot 0, the idle), no callback; then 336 as a type 3 task with blend time 0 into that loop, holding0x800000, owner the human, end hookTag_OnEndClipEnd(0x002783a8, an empty function). - In the stance: held flag
0x80000set now; the loop of record+0x54(anim slot 11, the fight idle, 358 for Rembrandt); anim state =0xb; a type 3 task of the id record+0x54+ 1 (359ANIM_FIGHT_TRANSITION_FROM_NORMALwhen the fight idle is 358) with blend 0 into the fight idle, holding0x80000, no hook; then 336 with blend 0 into that clip, holding0x800000, hook0x002783a8. So 336, then the neutral-to-fight transition, then the fight idle.
- Not in the stance: anim state (record
- Inserts 336 at the bottom of the task stack and pushes the fade on top: the usual change of animation (Task stack), a 0.05 s blend from the spray pose into 336.
- Sets held flag
0x800000(cleared by 336's task when 336 ends or is cut off). - Calls
Tag_Endat once (0x002785ec), in the same update, not when 336 ends: action 0, state0x2000000cleared, the stick game freed, the bonus or the extra charge, the flag freed, the tagger's event 14 (the tag, finished+0x3ba),+0x36cemptied, message0x13to the tag object, the voice stopped (The end). So event 14 comes on 336's first update, about 7 frames before the can goes.
It sets no turn and no velocity, and it does not clear 0x400 (that flag is held by 334's task and goes when 334
ends). 336 is not muted (no task flag 0x10), so its events fire. While 0x800000 is held, MiniGame_Update
skips the tag (any held flag) and Human_ApplyPendingDamage gives a hit no reaction (0x1c16a40 includes
0x800000, 0x0026668c; the props are released before that test).
Ends without 336. Tag_End alone, with no clip: the update with the action no longer 0x17 / 0x18, not
tagging, while the tag still exists (Tag_UpdatePlayer 0x00273f6c, MiniGame_Update 0x00255fa8: the cut-short
intro of issue #330); a hit (Human_ApplyPendingDamage, 0x002667ac, while tagging or while the tag exists),
a death (Human_PlayLethalReaction, 0x00268068), a grab or mount (Grab_Link 0x0022c8dc, Pair_LinkMount
0x0022c178, Grab_BreakOnHit 0x0022ba5c), a broken pair (Human_BreakPair 0x00258af8) and a mode reset
(Human_ResetForMode 0x00232740). Tag_End itself never touches the can or the clips. On those paths the can goes
another way: Human_ReleaseCarriedProps (0x0024ce40) runs, unless the human is cuffed, from every damage dealt
(Human_DealDamage 0x0021d81c), every attack warning (Human_WarnOfAttack 0x0021d658), the pending damage of a
non-lethal hit (0x002664a8, before the reaction), a death (0x00267ee4) and a mode reset such as a scene start
(0x00232954); and for an AI human each update that asks for a gait above 0 or is in a scene state
(Human_UpdateControl, 0x002439f4, 0x00243a0c). So a hit removes the can on the hit's update. Whether a grab
always passes a warning or damage first, and so drops the can, is not traced. Runtime: not run (the prop at +0x348
around 336's frame 7 has not been watched in PCSX2).
The paint colour is the tagger's human +0x640, four bytes. Human_Init (0x00218770) stores bytes
50 07 05 20 (in memory order) for everyone; a human whose class has brain kind 4 (+0x11a, after the +0x19d
remap) and +0x3b8 = 1 gets ff ef ef ef instead (0x002187b0). HuTagColor(h, {t1, t2, t3, t4}) writes
t4, t3, t2, t1 in that byte order (0x00239080: f12 = t4 to byte 0 in Colour_PackFloat 0x0017aca8). The
two readers take the bytes in opposite orders:
- the HUD (
TagHud_Render0x001cb798) keeps bytes 0-2 and puts its own alpha in byte 3 (sprite colours are r, g, b, a in memory: the path's grey isCONCAT13(0xff, c c c)): painted cells (rgb, 205), the charge bar (rgb, 255). So the HUD shows (t4, t3, t2); the default is (80, 7, 5), a dark maroon; - the particles read the word as
0xRRGGBBAAwith alpha in the low byte (SprayMist_Init0x003aad68keepscolour & 0xffffff00as the previous colour, fading in from alpha 0): the mist is (t1, t2, t3) at alpha t4, the scripts'{r, g, b, a}read as written; the default is (32, 5, 7) at alpha 80.
Confirmed (code) at the addresses; the default confirmed (runtime) (PCSX2 2.9.94, PINE, a copy of quick-save slot
6, level99): every human in use, the player included, had bytes 50 07 05 20 at +0x640. The scripts' values
(disc check, counts only): level 34's Moon tagger {0, 0, 40, 200}, level 93's Destroyer tagger
{121, 155, 213, 75}, a level 2 dancer {75, 175, 0, 25}; level 87 colours only sguy (DEST_SPRAY), never the
player, so the player's paint is the default in mission 3.
The spray mist, confirmed (code):
Tag_StartSpray(0x0022e610) andTag_StartSprayEffect(0x00277f28, each time the loop 335 starts) create asub_spr(0x003aa900) and playvags/character/spray_loopx28on the tagger. Thesub_spris attached to the tagger at attach point0x13(the arguments, popped in reverse: the mode 1, the rotation, the position, the attach point0x13, the human, the colour+0x640). Every 2 ticks for 3 updates (0x003aaa40) it makes twospray_mistat the attach point, each with a random velocity of −0.025 to 0.025 on each axis, in the colour above.spray_mist(0x003aad68, update0x003aaf28):part_page1(batch 4) rectangle 42-44 at random, size 0.05, random spin ±90°, an update every 2 ticks; it grows 0.015-0.03 a step, fades and slows at step 5, is done at 6.- On the wall: each update's progress message
0x41(below) makes the tag spawn mist at the paint's leading edge while the progress is between 0.03 and 0.95 (SprayTag_SpawnMist,0x003fbe98): with (w, h) the tag's extent (particle+0xa0,+0xa4; where it is set is not traced), x = (progress + a random 0-0.03) × w − w/2 along the tag's own axis, a column of max(1, ⌊h / r⌋ − 1) puffs from the bottom (−h/2) up in steps of r = a random 0.6-0.7, each aspray_mistin the tagger's colour, flagged to start at step 4 at size 0.45 (a quick big puff). It stops when the particle pool is full or the point failsEffects_CanSpawnAt(25 m, 20 m).
The paint on the wall is not drawn stroke by stroke: the tag object is one pre-made image whose opacity is the progress. Confirmed (code) unless marked:
SprayTag_Init(0x003fc600): the spot is placed 0.5 m along its own +y from the spawn point, then a ray of 10 m back along −y (0x003a36e0) finds the wall; on a hit it moves to the hit point + 0.05 × its +y and its rotation is built from the wall's normal (inferred: the global vectors 1 and 2 read after the ray are the hit point and normal). Its sprite batch (SprayTag_SetSprite0x003fc218) isPTank_New(depth 10, sprite, position, 1, flags, 255)with the sprite word0x50000untilCfgTagSettingssets one, and the task's flags0x00508001; bit 0 of the flags makes the batch format 2 where the camera-facing fog uses 0 (0x003a4e88; inferred: an oriented quad lying on the wall).CfgTagSettings' third argument (+0xc0, 0.5 by default; 0.8-3.5 in the scripts) is the task's size field (Particles), so it is the image's size (inferred).- The drawn opacity is
+0xc8, set from the painted fraction+0x10(Task_SetFieldC8). During the stick gameTag_UpdatePlayer(0x00273c60) sends the tag message0x41withTag_GetProgressevery update, so the image fades in evenly as the progress goes (0 to 1 over the path; 1.0 at the finish, then0x19state 3 keeps it). A spot not finished keeps its fraction, and the next spray starts at that point of the path (step 1). - The image's own colours are drawn with the task colour (white by default,
0x005fd268=0xffffffffat runtime), so the wall tag does not take the paint colour: a Warriors' tag is its texture. Level 87's club wall is three layered tags (CfgTagSettingssheet records0x1fe,0x200,0x202, size 3.5; prompts "base", "fill", "detail"); its earlier spots use the default sprite.
Coney status and fixes¶
The checklist items (2026-10-10): the paint is black, no mist, no paint on the wall, a short near-black smear on the HUD, a dark charge bar, the Warrior not turned to the wall and still holding a pipe, and the tag ending just before the W is complete. Causes and fixes, for the implementer.
Done (2026-10-11): 1-5, and 8 but the turn with no intro clip, which Coney makes at once (Coney's reading: a
missing clip plays for 0 s); 9 for player 1 (2026-10-12, HumanAnimator::playTagEnd; an AI tagger's end still plays
no 336). Not yet: 6 (the mist) and 7 (the wall tag).
- Ends early (
TagGame::update,repo:src/warriors/tag_game.cpp): Coney finishes atprogress + 4 >= size − 1(p ≥ count − 5), two points early, and its tracking picks the nearest point in ±4, so the progress can jump up to four points ahead at once. Use step 5's p ≥ count − 3 and step 3's tracking (back 4 without moving p, forward first match from p, squared distance < 36 on the truncated cell). - Off-track count: cumulative until a slip or a new charge (step 3), not reset when back on track; the slip is tested at the start of the next moving update after painting.
- Charge during a pause: the charge time keeps running through slip and charge pauses (step 4); the ramp restarts at each new charge, measured on the game clock from the end of its pause.
- Paint colour: give every human the
Human_Initdefault (bytes50 07 05 20;ff ef ef effor the brain-kind 4 case) instead of 0, and keep+0x640as the four bytesHuTagColorwrites (t4, t3, t2, t1). The HUD's painted cells and charge bar use bytes 0-2 (default (80, 7, 5)); the mist uses0xRRGGBBAAwith alpha in byte 0 (default (32, 5, 7, 80)). Coney'sHuTagColornow packs t1 into the red byte of both, which is right for the mist only (repo:src/scripting/story_bindings.cpp,repo:src/gamemodes/gameplay_tag.cpp). - Cursor colour (
TagHud::cursorColour,repo:src/hud/tag_hud.cpp): plain white while on track (+0x500), flashing white and black while off track; the pause does not choose it (Coney passespauseLeftMs > 0). During a slip pause the flag keeps its last value (off track), so the cursor flashes. - Mist: the
sub_sprburst at attach point0x13when the spray starts and each time the loop 335 starts, and the wall's leading-edge column on every progress message, as above;spray_mist's numbers are in Script types. - The wall tag: draw each
part_spray_tagas its sprite (theCfgTagSettingssheet and rectangle,0x50000by default) on a quad on the wall after the ray snap, sized by+0xc0, at opacity = its painted fraction; feed it the progress each update (Coney'sTagSessionalready sends0x41). - Turn and weapon: the turn to the tag over half of 334 should be checked with a test (the play-tester saw
none); when 334 is missing Coney skips the clips and so the turn too (
GameplayMode::startTag), where the original still turns. A held pipe staying in the hand is faithful; drop only anim sets 4 and 6. Restart the clips with 337 when a pause begins. - The end clip (issue #407): Coney never plays 336, so the can 334 made stays in the hand. End every spray
that
Tag_EndSprayClipsends as The end says: 336 after a 0.05 s fade, then the idle (or the transition and the fight idle),Tag_Endon the same update; the can goes at 336's event0x31. A hit, death, grab or reset ends the spray without 336, and the hit or reset releases the can itself.
Tests (synthetic, no game data): a straight 20-point path finishes when p reaches 17 and not at 15 or 16; a
cursor within 6 cells of point p and of p + 1 leaves p unchanged; a cursor near p − 2 keeps p; five off-track moving
updates split by on-track ones make the next moving update slip; a charge that ends inside a slip pause starts the
next charge on time; the ramp restarts after a new charge but not after a slip; HuTagColor(h, {1, 2, 3, 4}) gives
HUD rgb (4, 3, 2) and mist 0x01020304; a human never given a colour draws HUD cells (80, 7, 5, 205); the cursor is
white on track and flashes off track and during a slip pause; the wall tag's opacity equals the progress after each
update and stays 1.0 after a finish; a human holding a set-3 object keeps it at the spray's start, one holding a
set-4 object drops it.
The script callbacks¶
The engine calls a script at two points of a tag, and nowhere else (no progress, layer or cancel callback: the only
reader of the start callback's name 0x006b6870 is 0x00238f50, and Tag_UpdatePlayer, TagGame_* and Tag_End
call no script). Confirmed (code) at the addresses cited.
The start callback (CfgTagStartCallback), called by
0x00238f50:
- When. Not at
HuTag. Once the human is in action0x17and not yet tagging, the update (Tag_UpdatePlayerfor a player, which first makes the stick game; alsoMiniGame_Update,0x00255fd8) callsTag_StartSprayClips(0x00278018), which queues 334ANIM_TAGGING_INTRO(with the end hook0x00277ed8) and then the loop 335. Nothing walks the human to the flag or places him: he stays where he pressed triangle (within the flag's kind-1 reach, 1.1 m) and turns to face the tag object (its vtable+0xacpoint) over half of 334's length (Human_TurnToFacePoint,0x00221c20). A held weapon of kind 4 or 6 is dropped first. When that hook runs and the tag still exists,0x0022e610starts the spray: it sets the tagging state0x2000000, sends the tag message0(the tagger, Tag spots), and last calls0x00238f50. So the callback runs once per spray, at the moment the stick game goes live;0x00238f50does not check for a player. - Arguments: three object handles, in this order (each pushed with the script system's handle slot
+0x5c,0x00356fc8, as the same number a script gets from any binding returning a handle): - the tagger (the human's own handle, its vtable
+0x2c); - the tag object being sprayed (human
+0x36c, thetaggiven toHuTag); - the flag sprayed from (the human's target
+0x33c, resolved by0x00227060: theflaggiven toHuTag).
Snippet (0x00238fdc-0x00239058): ori a1,sp,0x4 / lw v0,0x36c(s2) ... jal 0x00227060 ...
li a1,0x3 / move a2,zero / jalr slot +0x8c.
3. Result: none asked: slot +0x8c (0x00357188) is lua_call with 3 arguments and 0 results, so a return
value is dropped. The call is immediate (not scheduled). Nothing happens when no name is set (global.lua sets
nil) or the human is gone.
The end event: Tag_End (and HuTag's refusal) give the tagger event 0xe (record +0x00 the tag object,
+0x04 1 finished or 0, +0x24 the human). The message marshaller (0x00384ce0, case 0xe) calls the human's
message handler as (self, tag, finished): three handles/numbers, finished the number 1 or 0 (unsigned, not a
boolean), and it asks one result; a non-zero number means the event was consumed
(Message handlers). That a human's vtable +0x44 reaches its handler component is
inferred from the event-14 handlers the scripts set (Script events).
What the scripts do with the start callback (our summary): every one takes three parameters. Level 87's and level
9's look the third (the flag) up in their own list of tag spots to find which spray it is, lock the first
(the tagger's) pad movement and turn on that spot's tag camera; level 3's first checks that the first is a
player, then has a crew member comment and switches cameras. A callback called with no arguments therefore indexes a
table with nil. None returns a value.
Tag spots¶
A part_spray_tag (init 0x003fc600, handler 0x003fc8d8, update 0x003fca68 every second frame) keeps a small
record: its sprite batch, a fade mode (+0x04: 0 still, 1 fading out, 2 fading in), the sprite word, a spray
mode (+0x0c: 7 the next spray paints the tag in, 5 it wipes the tag out; 7 at start), the painted fraction
(+0x10, copied to object +0xc8, the drawn opacity and where the stick game starts; 0 at start), the fade step
(+0x14, 0.005), the depth (+0x18) and the tagger (+0x1c, a human). Confirmed (code) at the addresses.
| Message | Effect |
|---|---|
0x00 (tagger) |
stores the tagger, then as 0x12 |
0x12 (shown) |
sets path flag 8 on the path polygon at the tag (AI); if the spray mode is 7 with fraction < 1, or 5 with fraction > 0, and there is a tagger: the tagger gets message 0x17 (state 1, the tag's position) and the tag sends itself 0x19 with the spray mode (7 starts the fade in, 5 the fade out); otherwise the tagger, if any, gets 0x13 |
0x13 (hidden) |
clears path flag 8 there, the tagger (if any) gets 0x13, the fade stops (mode 0) |
0x15 |
frees the sprite batch and removes the object |
0x19 state 3 |
fade stops; the tagger (if any) gets 0x13 (sent by the update when a fade reaches 1 or 0) |
0x19 state 4 |
fraction 0 (blank), spray mode 7 |
0x19 state 5 / 7 |
fade out / fade in starts |
0x19 state 6 |
fraction 1 (fully painted) |
0x27, 0x37, 0x38, 0x3b |
CfgTagSettings: sprite, +0xc0, fade step, depth |
0x39 / 0x3a |
spray mode 7 / 5; the look is unchanged |
0x41 (fraction) |
sets the painted fraction; while it is between 0.03 and 0.95 a few spray particles are emitted across the tag (0x003fbe98) |
0x0e and any other |
ignored by the tag's handler |
The fade: each update in mode 2 adds the step to the fraction; reaching 1 it sends itself 0x19 state 3. Mode 1
subtracts it down to 0 the same way. ProcessTag sends 0x19 4 or
6, or 0x39 / 0x3a. Confirmed (code).
Taking owned items¶
An item with its owned byte (+0x109) set, from a store or a stolen stereo, is cleared of it when taken
(0x00395d98) and Item_TakeOwned(taker, object) (0x00412dc8) runs, confirmed (code):
- Message 7 goes to volume boxes only, as message 6 does (Scripts: triggers): every
box (handles
0x26c-0x2eb) that is enabled (+0x68), of kind 0 (slot+0x64), has a Lua handler for 7 and whose inside test (0x00412a18) holds for the object's position (not the taker's). The Lua handler gets (taker, object) (marshaller case 7,0x00384ce0). No human is sent message 7. - Humans within 30 m of the object are alerted (
AI_AlertNearby,0x00293768) with the message and the spot. - A player taker scores statistic 4-8 (
Stats_AddCrime(..., 8, 1)); an AI taker of brain type 3 (a Warrior) whose gang leader is a player scores it for every player (Stats_AddCrimeAllPlayers). - An AI taker then says line 128
stealitem(30 %) or 143 himself (not a witness), only when he may gesture (Ambient_MayGesture) and the shared 8 s timer allows (AI_Every8s).
When it runs: the pick-up search (Human_PickUpSearch, 0x0024d810) calls it at the press, for the player and an AI
alike; for any object but a TYPE_SPECIAL it then clears the owned byte (0x00395d98). A TYPE_SPECIAL keeps the
byte, and Human_PickUpObject (0x0023bf00) calls Item_TakeOwned again only on its path for a human with none of
record flags 0x5c7eae0 (not during a pick-up clip, which holds 0x4000), followed by a turn to the object and
overlay clip 667. Confirmed (code).
What a take of a TYPE_SPECIAL gives (Human_PickUpObject, the store items' case: model hash not one of the
named mission items, during the pick-up clip, type class name pickup_item), confirmed (code) at 0x0023bf00:
nothing for brain types 2 and 4 (gangs, civilians); for a player, item 10 ×1 (notify) and the money (the type's
value × game state +0x380) to his own panel; for a Warrior (type 3), item 10 to his own panel, which an AI
crew member does not have (+0x380 = −1, which Inventory_AddItem ignores), and the money to his gang leader's
panel (the player's, without notify), with item 10's pick-up sound played in 2D. So a crew member's theft pays the
player and adds no loot item.
Stores¶
A store is a set of flags (World flags: groups) with a store front (activity 14), browsers and
buyers. A break-in (crime type 1) comes from an alarmed pane (panes), a lock pick that was not
perfect, or a third abandoned pick. The report (AI: crimes), confirmed (code) at 0x0041b8b0: within
10 m the store front is marked robbed (bit 16 of its group word, the offender's gang in bits 18-22), the store's
buyers and browsers are switched off, the nearest strobe within 6 m gets message 0x12, and responders are queued
with a delay of CfgBreakAndEnterDelay (15, 10 or 7 by difficulty). The first gang to rob a store scores crime event
4-1 for its leader when he is a player. ResetStore (0x0041ddd8) clears the robbed bit, sets the group word's bits
8-15 to 0xff and the gang bits to 31, and restocks the store; its 7 m test (squared distance under 49, message
0x13) is a strobe's distance from the store's flag, not the player's (confirmed (code)). The two strobe distances
differ in the code: a break-in reaches a strobe within 6 m of the store's flag, a reset one within 7 m. EnterStore /
ExitStore only change the screen colour.
Which break-ins call the police¶
GameState_ReportCrime (0x0041b8b0) handles type 1 differently from every other type (its case 1), confirmed
(code) at 0x0041b8b0, 0x0016df68 and 0x0016dc70:
- It looks for the nearest flag of activity
0xe(a store front) to the report's position (Flag_FindNearestByActivity) and goes on only when one exists and lies within 10 m (squared distance under 100). No store front within 10 m: no police, no strobe, nothing robbed. The wanted timer, hostility and crime callback run before this, but only with an offender (step 2 of AI: crimes). - Only when that store is not yet robbed (bit 16 of the flag's word
+0xd8clear) and the call asked for responders (mode1):Responders_Queue(1, kind 1, count = CfgCrimeResponders(1) (game state +0x295), delay = CfgBreakAndEnterDelay (0x005148a4) seconds, the crime scene, no target, no offender). Then the strobe's message0x12and the store's buyers switched off (above). A store already robbed only fills in the robbing gang (when the bits hold 31) and scores its leader's crime event; a second break-in at the same store brings no police untilResetStore. Responders_Queue(0x0016df68) does nothing for a count of 0. Otherwise it takes, over all 32 gangs' four spawners, the one in state 4 (police dispatch) or 6 (dispatching) nearest the crime scene whose queue is not full (+0xb0< 4), andSpawner_QueueCall(0x0016dc70) appends the entry: due at now + delay × 1,000 ms, the type, kind and count. No spawner in state 4 or 6 anywhere: no police. The spawner then makes aResponder<n>gang of type 1 when the entry is due, while the police count is under its limit, and places the squad out of sight (AI: spawners, steps 4-6).
Who reports a break-in and with what, confirmed (code):
| Reporter | Position | Offender | Mode |
|---|---|---|---|
A lock pick that was not all perfect, or a third abandoned pick (LockPick_End 0x0022d908, both calls) |
the picker's position | none (0x006ebd30), so no wanted time, no police hostility, no callback |
1 |
| An alarmed pane (panes) and the others in AI: crimes | their own | their own | their own |
So a lock-picked store door brings CfgCrimeResponders(1) police after CfgBreakAndEnterDelay seconds (15, 10 or 7
by difficulty), from the nearest police dispatch spawner, only when the door is within 10 m of a store front that
was not yet robbed; the picker himself is not made wanted by the pick. The counts the scripts set for type 1:
config_easy 2, level14 2, level87 1, level95_robinhood 1 (Crime types).
Whether the responders then attack the player's gang when the pick reported no offender (no police hostility was
set) is not traced: the dispatch goal's target is the crime scene (inferred from the queued entry, which carries no
target).
User item 13 (no police on a break-in): Coney's report (repo:src/warriors/crime_reports.cpp, checked
2026-10-11) calls CrimeServices::queueResponders, whose only implementation is the interface's empty default, so
nothing is ever queued; Coney also has no dispatch queue on its spawners (GameplayMode's scout hook logs its call
only). Coney fixes:
- Build the spawner dispatch queue (AI: spawners steps 1, 4-6, Spawner
states 4 and 6): four entries per spawner (time due, type, kind, count, target,
point, offender gang), served when due; state 4 makes a
Responder<n>gang of type 1 while the game's police count is under its limit and goes to 6, which places the squad out of sight and returns to 4 when it is complete. - Implement
queueRespondersin the level's crime services asResponders_Queue: nearest spawner in state 4 or 6 to the crime scene with a free queue slot, delay in seconds. - Gate type 1 as the original does: responders, the strobe and the buyers only when a store front (activity
0xe) lies within 10 m of the report and is not yet robbed; today Coney asks for responders before and regardless of the store test. - Report a lock pick's break-in with no offender (Coney passes the picker), so the pick sets no wanted time, no hostility and no callback.
- Test (pad-driven, a level with a police dispatch spawner and a pickable store door, e.g.
level87's stores): pick the door with a non-perfect press, assert aRespondergang appears afterCfgBreakAndEnterDelayseconds withCfgCrimeResponders(1)members; a second pick at the same store queues nothing; a pick away from any store front queues nothing.
Wanted and the crime level¶
Wanted is per gang, confirmed (code): every crime report with an offender sets the offender's gang wanted for
10 s (gang +0x5e8 = now + 10,000 ms, 0x00169878), after making the police hostile to it. Gang_UpdateWanted
(0x001698f0) holds it at 10 s from now while ForceCrimeLevel is on (game state +0x28c); otherwise, once it
passes, GangClearWanted's work runs (0x00169a20): the police are neutral again and, for the player's gang, the HUD
is told (0x001b2520 message 0xb) and the last crime type becomes 14 (NoCrime). While wanted, the HUD shows
CfgCrimeMessage of the last crime type (a plain assault: 0) and the first report of each wanted spell sounds the
hudalarm cue (HUD: the crime message). The HUD shows the time left as a
fraction of 10 s (0x001aa9b0; full above 0.9). Gang +0x5f0 is a second timer drawn the same way, and
GangIsWanted(gang, false) tests it. GangRespond and GoalCallGang set it (Gang_SetSecondWantedTimer,
0x001698c8); when it runs out, Gang_UpdateWanted (0x001698f0) calls the all-clear callback at game state
+0x2bc. Confirmed (code). The first time the player's gang is wanted, hint 6
(Humans_Update).
The crime level (game state +0x291, 0-3) is set only by InitLevel and SetCrimeLevel, which no script calls.
While set with a time, it steps down one level at each expiry (Crime_UpdateLevel, 0x0041c028): to 2 the HUD gets
message 8 and the next step waits +0x2a5 seconds; to 1, message 7 and +0x2a4 seconds; to 0, message 0xb and the
police reset (0x0016c5b8). The police guard goal reads the level to pick a station's settings (SetCopStation's
values, 0x002c0ca8). So in the shipped game the level stays 0 (inferred) and wanted time is the heat.
Severity does nothing: CrimeIsHappening's fourth argument and the report's severity argument are never read
(confirmed (code) at 0x0037a2f8, 0x0041b6e0, 0x0041b8b0); its radius and flags are not read either.
Code index¶
Every crime function of the human code (0x002176b8-0x00288000) 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. The rest of the human code is indexed on Characters.
Mini-games, mugging and tags¶
The start and end of each mode of the mini-game record, the mug and the tag spray.
| Address | Name | What it does | Evidence |
|---|---|---|---|
0x00228588 |
Human_IsInButtonMiniGame |
A player whose mini-game record mode (+0x46) is 5, HuButtonMiniGame. |
confirmed (code) |
0x002285c0 |
Human_IsStealingStereo |
A player whose mini-game record mode is 3, the car stereo. | confirmed (code) |
0x002285f8 |
Human_IsPickingLock |
A player whose mini-game record mode is 2, lock picking. | confirmed (code) |
0x0022ceb8 |
Mug_End |
Turns a mugging back into a rear grab, withdraws the hint and calls the mug callback. | confirmed (code) |
0x0022df88 |
ObjectMash_Start |
Starts mini-game mode 4 (a mash on an object): meter 2 x 0x005102c0, immovable, blocking cleared. | confirmed (code) |
0x0022e330 |
ObjectMash_End |
Ends mode 4: clears the meter, hides it and marks the object 0x8000 (0x0024c560). | confirmed (code) |
0x0022e4c0 |
ButtonMiniGame_Start |
Starts mini-game mode 5 (HuButtonMiniGame). |
confirmed (code) |
0x0022e558 |
ButtonMiniGame_End |
Ends mode 5 and releases the object target. | confirmed (code) |
0x0022e610 |
Tag_StartSpray |
Starts spraying a tag: state 0x2000000, action, voice, particle and the script's start callback. | confirmed (code) |
0x00236508 |
Cfg_SetStereoTheftHandler |
CfgSetSteroTheftHandler: interns the stereo theft's Lua handler (0x0051027c). |
confirmed (code) |
0x00236548 |
StereoTheft_CallHandler |
Calls the stereo theft handler with two values; StereoTheft_End uses it. | confirmed (code) |
0x002365f0 |
Cfg_SetLockPickHandlers |
CfgSetLockPickHandler: interns the lock picking's start handler (0x00510288) and its two end handlers (0x00510284, 0x00510280). |
confirmed (code) |
0x00236698 |
Cfg_SetLockPickStageFailHandler |
CfgSetLockPickStageFailHandler: interns the handler 0x0051028c. |
confirmed (code) |
0x002366d8 |
LockPick_CallStageFail |
Calls the stage-fail handler; LockPick_JudgePress uses it. | confirmed (code) |
0x00236780 |
LockPick_CallStart |
Calls the start handler; LockPick_Start uses it. | confirmed (code) |
0x00236828 |
LockPick_CallEndA |
Calls the first end handler (0x00510284); LockPick_End uses it. | confirmed (code) |
0x002368d0 |
LockPick_CallEndB |
Calls the second end handler (0x00510280); LockPick_End uses it. | confirmed (code) |
0x00272878 |
Mug_OnStartEnd |
End hook of the mug start: starts the mug proper, or with no victim left resets a player's mug camera. | confirmed (code) |
0x002729a8 |
Mug_Start |
Starts a mugging: the paired clips, the mug camera (CamMug_Start) and the mug meter (HUD_MugMeterStart). | confirmed (code) |
0x00273668 |
Mug_PlayVictimLoop343 |
Player_UpdateMugging: the victim loops 343 after a 1/6 s fade. | confirmed (code) |
0x00273820 |
Mug_PlayVictimLoop341 |
Player_UpdateMugging: the victim loops 341 after a 1/6 s fade. | confirmed (code) |
0x002739d8 |
TagGame_Difficulty |
The stick game's difficulty record from the Warrior's class byte +9. | confirmed (code) |
0x00273a68 |
Tag_SayNearbyLine |
Has a random nearby gang member say a line while a player tags. | confirmed (code) |
0x00273fa0 |
Vec2_Scale |
A 2D vector times a scalar. | confirmed (code) |
0x00273fc0 |
Vec2_Add |
The sum of two 2D vectors. | confirmed (code) |
0x00273ff0 |
Tag_CatmullRomPoint |
A point on the uniform Catmull-Rom curve through the pattern points (Tagging). | confirmed (code) |
0x00274188 |
Tag_SetPatternPoints |
Copies the pattern's count and 64 (x, y) points to 0x00510914 / 0x006cd978. | confirmed (code) |
0x002741d8 |
TagGame_Init |
Builds the stick game: the path from the pattern, the painted list, the start index from the tag's painted fraction, window 4, paint spacing 4 (Tagging). | confirmed (code) |
0x002745e8 |
TagGame_IsPaused |
Whether the stick game is paused (+0x514, the clock until which it waits after a slip or a new charge, is set). | confirmed (code) |
0x002745f8 |
Tag_IsComplete |
Whether the tag's progress has reached 1.0. | confirmed (code) |
0x00274638 |
Tag_GetChargeLeft |
The charge left: 1 - elapsed / the difficulty's time, from +0x518. | confirmed (code) |
0x00274710 |
TagGame_SpendPaint |
Every update: the share of the charge left; at its end a new charge (snap, pause, ramp restart) and one can, or the end with none left. | confirmed (code) |
0x002748a0 |
TagGame_IsOnTrack |
The stick game's on-track flag (+0x500); the HUD cursor is plain white while it is set. | confirmed (code) |
0x002748a8 |
TagGame_Update |
One update of the stick game: charge, pause, cursor, painting, slip, tracking (Tagging). | confirmed (code) |
0x00274e38 |
Tag_GetProgress |
The painted fraction +0x508 / +0x268 (1.0 once +0x508 + +0x264 exceeds +0x268). | confirmed (code) |
0x00277ed8 |
Tag_OnIntroEnd |
End hook of 334 ANIM_TAGGING_INTRO: starts the spray when the tag still exists, else ends the spray clips. | confirmed (code) |
0x00277f28 |
Tag_StartSprayEffect |
Loop hook of 335: while tagging, a sub_spr mist burst at attach point 0x13 in the tagger's colour and the spray voice (What the player sees). |
confirmed (code) |
0x00278210 |
Tag_RestartSprayClips |
Requeues the spray clips (the spray effect hook) when the tag still exists, dropping a kind 4 or 6 weapon. | confirmed (code) |
0x002783a8 |
Tag_OnEndClipEnd |
End hook of 336 ANIM_TAGGING_END: an empty function. | confirmed (code) |
0x002783b0 |
Tag_EndSprayClips |
Unless the tag is gone: a 0.05 s fade into 336 (held 0x800000), then the idle loop (anim state 0) or, in the fight stance, the fight idle + 1 transition (held 0x80000) and the fight idle (state 0xb); then Tag_End at once (The end). |
confirmed (code) |
Game-state functions¶
Functions of the game-state module (0x00417af0-0x00424e50: inventory, statistics, flags, configuration
workers) that belong to this page, by address.
| Address | Name | What it does | Evidence |
|---|---|---|---|
0x00417af0 |
Cfg_SetActionDistance |
CfgActionDistance(d, kind): stores d² at 0x00514878 + kind × 4 (Context records) |
confirmed (code) |
0x00417b88 / 0x00417be8 |
ContextActions_Construct / ContextActions_Reset |
the registry's constructor zeroes its 256 records of 0x1c bytes (from +0x18) and resets: the six kind lists at +0x00-+0x14 emptied, every record chained into the free list (head +0x1c18) |
confirmed (code) |
0x00417c48 / 0x00417c58 |
ContextActions_TakeFree / ContextActions_Release |
pops the free list's head (from ContextActions_Register) / unlinks a record from its kind list, clears its object and user and pushes it back on the free list |
confirmed (code) |
0x0041ad90 |
GameState_SetCrimeLevel(level, s) |
the crime level +0x291 and its expiry +0x2a8 (now + s × 1000 ms, 0 for none); from Crime_UpdateLevel, InitLevel and SetCrimeLevel |
confirmed (code) |
0x0041add0 |
Script_SetAllClearCallback |
the worker of SetAllClearCallBack |
confirmed (code) |
0x0041adf8 / 0x0041ae30 |
GameState_SetAllClearCallback / GameState_SetCrimeCallback |
store a Lua function name (31 characters) at +0x2bc / +0x2dc, or clear it; from the game state's set-up and the SetAllClearCallBack / CfgSetCrimeCallback workers |
confirmed (code) |
0x0041b6a8 / 0x0041b6c8 / 0x0041b6b8 |
Script_EnableCrimeReports / Script_SetCrimeSceneTime / Script_SetCopGuardArrestedRange |
the workers of ReportCrime (+0x288), SetCrimeSceneTimeLength (+0x2b0) and SetCopGuardArrestedRange (+0x320) |
confirmed (code) |
0x0041b888 |
GameState_SetCrimeLevelTimes |
the bytes +0x2a3-+0x2a6 (10, 15, 20, 25 at set-up): the seconds each crime level lasts |
confirmed (code) |
0x0041b8a0 |
GameState_SetCrimeResponders(type, n) |
byte +0x294 + type; CfgCrimeResponders's worker |
confirmed (code) |
0x0041c1f8 |
GameState_SetCrimeTimer(s) |
+0x2ac = now + s × 1000 ms, or 0 |
confirmed (code) |
0x0041c230 / 0x0041c2a0 |
GameState_AddGuardingCop / GameState_RemoveGuardingCop |
count +0x322 up (the cop says command 0x16 when his brain's +0x28f is set) / down; from a police goal's start and end (0x002c0430, 0x002c0548) |
confirmed (code); role inferred |
0x0041cf80 |
GameState_CanReportCrime(human) |
true when no one is reporting a crime now (+0x280 empty), reports are on (+0x288 = 1) and the human's role (character type +0x11b) is not 6 or 7; from the civilian and cop brains |
confirmed (code) |
0x0041cfe8 / 0x0041cff0 |
GameState_SetCrimeReporter / GameState_CancelCrimeReport |
the reporter's handle +0x280; dropping the report pops the reporter's goal when it is type 0x6d (from Gang_MakeNeutralWithType) |
confirmed (code) |
0x0041d0a8 |
GameState_SetDispatcherVoice |
+0x328, −1 giving the default 125 |
confirmed (code) |
0x0041d0d0 / 0x0041d0e8 |
GameState_SetCrimeTypeEnabled / GameState_IsCrimeTypeEnabled |
the bytes +0x32b + type for types 0-14; read by the cop and civilian brains |
confirmed (code) |
0x0041d108 |
GameState_DamageHook |
empty; called by LockPick_End, Strike_Contact, Glass_Break and WorldObject_ReportDamage |
confirmed (code) |
0x0041d8a0 |
Cfg_SetCrimeResponders |
CfgCrimeResponders(type, n) |
confirmed (code) |
0x0041d8d0 |
GameState_SetForceCrimeLevel |
ForceCrimeLevel: +0x28c |
confirmed (code) |
0x0041d8e0 |
GameState_EnableDispatcher |
CfgEnableDispatcher(on, voice): byte +0x32a and the dispatcher voice |
confirmed (code) |
0x0041d910 |
Cfg_SetBreakAndEnterDelay |
CfgBreakAndEnterDelay: 0x005148a4 |
confirmed (code) |
0x0041da80 / 0x0041dab0 |
Cfg_EnableCrimeType / Script_SetCrimeCallback |
CfgEnableCrimeType(type, on) for types 0-14 / CfgSetCrimeCallback |
confirmed (code) |
Coney's implementation¶
Lock picking (repo:src/world_objects/lock_pick.h, 2026-10-06): LockPickDial turns the current pin 0.1 rad ×
its speed per step in the difficulty's direction and judges a press against the difficulty's bands (a miss resets
both counters and every pin); LockPick runs the start, stage-fail, success and stop callbacks, plays the click on a
miss, unlocks and opens the door on success (a break-in unless all three presses were perfect, which score bonus event
1-3) and counts an abandoned pick at the door (the third reports a break-in). The door side is on
World objects. In play (repo:src/platform/play_level_objects.cpp), triangle
within 1.5 m of a pickable door (Coney's stand-in for the kind-2 record's reach, not traced) starts a pick at the
difficulty of the player's CfgWarriorClass byte +0x0a less 1; the pick takes the pad until it ends, the dial
turning each step, cross judging and any button but cross, L1, R2, the d-pad and SELECT abandoning. Not yet: the
lock-pick animations (689, 690), the hint and the HUD dial.
Crime reports (repo:src/warriors/crime_reports.h, CrimeReports in GameState::player), written from AI:
crimes and Wanted (2026-10-06): report() follows steps 1-6 there, reaching gangs, spawners,
stores, statistics, the script callback and the HUD through a CrimeServices interface the play mode implements as
those systems arrive; update() clears a gang's wanted state 10 s after its last report (held while forced).
setSecondWanted() starts a gang's second timer (10 s, not held by ForceCrimeLevel; the all-clear callback at its end
is not built), which GangIsWanted(gang, false) reads; a second argument passed as nil reads as false, as level87's
CheckIfWanted relies on. In play the objects' break-ins report through it
(repo:src/gamemodes/level_crime_services.h: the crime callback, the CrimeScene flag, which humans are players, and
the offender's gang and player 1's through the level's brains, so a report makes the gang wanted, and player 1's HUD
messages, 7 for a report and 0xb when the wanted time runs out, to the HUD's crime message;
the police's hostility and the spawners are not wired to it yet). A break-in marks the nearest store flag within 10 m robbed
(the gang in bits 18-22) and switches on the alarm strobe (a part_strobe_red of the level's objects file) within 6 m
of it (LevelObjectServices::robStore): its strober, a red light pulsing on a 40-tick cycle,
and its alarmbell_loop emitter, heard within 30 m (Particles); ResetStore
switches the one within 7 m off. Coney's stand-in: the store's buyers are not done yet. ReportCrime switches
reporting. EnterStore / ExitStore switch the screen tint, and CfgSetSteroTheftHandler keeps
its callback's name.
Tagging (repo:src/warriors/tag_game.h, repo:src/warriors/tag_session.h, repo:src/world_objects/tag_spots.h,
2026-10-06): tagPath() samples HuTagPattern's points along the Catmull-Rom curve into grid cells and
TagGame is the stick game on it, tuned by tagTuning() from the Warrior class's byte +0x09
(script::tagDifficulty()), in the steps' order (2026-10-11): the paint first in every update, paused or not, so
the charge drains through pauses; the cursor past a squared stick of 0.04, its ramp restarted from the end of each
new charge's pause (not a slip's); tracking on the truncated cell, near a point behind (the progress kept) or at the
first near one from the progress on; the off-track count kept until a slip or a new charge, a count above 4 slipping
at the next moving update before tracking; the finish at p ≥ count − 3 and the fraction p / count. TagSpots
keeps each spot's record and answers its messages (Tag spots): CfgTagSettings and ProcessTag reach
it for a particle system's handle only, the fade runs every second 60 Hz tick, and spray() is a CPU tagger's step
(Rumble's Tag battle). TagSession is one player's spray: the paint from inventory item 3 (taking the last can ends
it, so n cans give n charges), the fraction sent to the spot (message 0x41) as the game goes, and Tag_End's spot
side and wasted charge. In gameplay (repo:src/gamemodes/gameplay_tag.cpp) HuTag for player 1 with paint locks
his movement where he stands, drops a held object of anim set 4 or 6 (a club stays in the hand, tagDropsHeld())
and plays 334, turning him to the tag over half its length, then the loop 335, and 337 then 335 again when a pause
begins (Human::startTagSpray()). 334 holds the busy bit 0x400, and while any of the three plays the player's
stance, commands, triangle actions and anim-state choice do not run and the stick step is skipped, as the original's
Human_UpdateActions (0x00254e78) returns after the spray's update (issue #353; a player in the fight stance used
to have the fight idle put back over 334). When the loop starts, the session runs on pad 1's left stick, the spot gets its
tagger (message 0x00, which starts its own fade in) and CfgTagStartCallback's function is called with (tagger,
tag, flag) and no result asked (above); an AI tagger's starts at once. A body something else takes
during the intro ends it unsprayed (Coney's reading), and the tagger still gets event 14 with the tag and 0, as
Tag_End (0x0022e848) always gives it, so the script puts the spot's prompt back (level87's fix
1). Without paint he says 37 nopaint and gets event 14 with
the tag and 0. At the end the pad is freed, a finish has a crew mate say 83 tagdone and the tagger gets event 14
(the tag and whether it was finished); a snap-back off the pattern has one say 80 tagcheer while the tagger's tag
cheer is on (HuEnableTagCheer). The crew mate is picked as Tag_SayNearbyLine does:
only while player 1 (Coney's war chief) last ordered defend, from his gang's members in slot order that are not the
leader or a player, are free to act, have no actions queued and stand within his far melee range, each later one
replacing the pick on a roll of 50 or more; the pick speaks only when his HuEnableTagDone switch is on. The story
reaches HuTag through the spot's flag: the script gives the flag (activity 12) a message-0 handler and a prompt
with SetMsgHandlerEx, a kind-1 context record. Coney locates such a record's object whether
it is a spawn record, a flag or a particle system (LevelPickups::actionObject()), shows its text as player 1's
action prompt and hands it triangle, whose handler calls HuTag. Coney's stand-ins:
any picked crew mate may gesture (the gesture slots are not kept), and the busy test is the actions-blocked one;
the spray clips stop at the end (back to the idle); an AI human given HuTag becomes the spot's tagger at once
(its fade in) without walking to the flag (GoalTag walks him there first, AI). A spot telling
an AI tagger he is done (message 0x13, at the end of its fade or when hidden) ends his spray as Tag_End does:
he gets event 14 with the tag and whether it is fully painted (Coney's reading: the human's handling of 0x13
is not traced). Each human's tag colour (repo:src/human/tag_colour.h, 2026-10-11) is the four bytes of +0x640:
Human_Init's 50 07 05 20 (a civilian woman's ff ef ef ef; Coney's reading: the brain kind before the +0x19d
remap), which HuTagColor overwrites with t4, t3, t2, t1; the HUD draws bytes 0-2 and the mist will read the word with
alpha in byte 0 (above). An unfinished end (no cans, a 301st cell) leaves the spot at p / count, not
Tag_GetProgress's 1.0 (Coney's reading: whether 0x41 carries that 1.0 before the end is not on the page). A
finished or abandoned spray of player 1 ends through 336, holding 0x800000, then the idle, or 359 and the fight idle
when he is locked onto a target (Coney's reading of the state word's 0x3); a spray cut short plays no end clip.
Not yet: the slip's rumble, the bonus event on a clean finish, the spray particles and the tag's drawing, hint 0x10,
and buttons other than the stick ending a session.
Car stereos (repo:src/world_objects/cars.h, 2026-10-06): CarSpawnRadio puts a stereo in a parked car;
breaking window 15 (Cars), or a type-12 pane within 2 m (ObjectServices::freeCarStereos), frees
it, and Cars::takeStereo takes it once. The theft (PlayLevelMode's context action,
repo:src/platform/play_level_objects.cpp): with no kind-1 prompt in reach, triangle within 2 m in plan of a freed
stereo not below the feet starts it (Human::startStereoTheft: the player turns to the stereo, 683 then the loop
684, mode 3 with 3 turns a stage, the player's class byte 2); success calls LevelPickups::stereoStolen ($15 and
item 11, then the CfgSetSteroTheftHandler callback with the human and the car). Coney's readings: the turn to
the stereo is at once, not spread over the intro; both gifts notify the inventory callback; the success and failure
clips (685, 686), the hint and the owned byte are not played or set yet. The HUD panel and its cues follow the theft
(HUD: Coney's implementation), as does the action prompt for kinds 2-4. A hit with a
reaction ends the theft at once (as 0x00268c50 does) and plays its reaction; anything else that takes the body (a
death, a knock-down, a scene) ends it at the next update (Human::stereoTheftPlaying()); either way there is no
outcome, the car is forgotten and the panel goes. Coney's reading: the clip 0x00268c50 plays for a theft is not
traced, so the hit's own reaction plays.
The mugging and the starting money (2026-10-07): HuCreate rolls each new human's carry as
Starting money gives (characters::rollStartingCarry(), repo:src/characters/starting_money.h)
from its recorded CfgChar and CfgCharClassAttribs calls with the game's random numbers, and sets the money
(HuSetMoney later overrides it). A gang spawner makes its human through the same HuCreate
(ScriptSpawnerWorld::spawn), as Spawner_MakeHuman (0x0016d860) calls Human_Init, so a spawner's human rolls
the same draws in the same order (repo:tests/ai/spawner_money_test.cpp). It takes the same branches for a capped
record (v16 not -1), so level87's sellers get $0 and a type 197 soldier $5 in 21 of 101 rolls and $0 otherwise,
as in the original (level87's sellers and soldiers; inferred from reading
repo:src/characters/starting_money.cpp, not rerun for these types). Player 1's won mugging
(PlayLevelMode::stepMugging()) moves all the victim's money in the deciding update (LevelPickups::mugPaid():
item 2 with the money and inventory callbacks, then item 2's pick-up sound); his
HuSetMugCallback callback runs with (mugger, 1 or nil) when his end clip (344 or 346) finishes, or at once for a
let-go or a hit (LevelPickups::mugEnded()). Coney's stand-ins: a grp_ object group carries nothing and a
rolled object is not given to the human; HuSetInterrogation keeps the lines and callback
(ScriptState::interrogationLines, interrogationCallback) and the prompt reads "interrogate", but not yet its
mugging (the set lines, no pay, the callback once); not yet: the pocket items, the half-way no_item stop, ped
type 5's 1.5 times and the statistic. While he mugs, the HUD's mug meter shows
(PlayLevelMode::stepMugMeter(), HUD: the mug meter).
The arrest and the uncuffing (2026-10-07): HuSetArrested (ai::ScriptedHumans::setArrested()) cuffs the human
(Human::setArrested(): stopped, its fighting ended, 320 looping), resets its brain as Brain_OnArrested does
(actions, target, goals down to a FindEnemy goal), sends it event 17 with 1 and has a friendly AI human say 25
arrested; the release sends event 17 with 0 after the cuffs come off. In gameplay
(repo:src/gamemodes/gameplay_uncuff.cpp) the kind-0 record is a cuffed AI human friendly to player 1 within
CfgActionDistance 0 in plan and 1.5 m of his waist, not being freed: its prompt is GSTRING.HUD 2, chosen before the
action object and hidden while a mash runs, and triangle tries it before the level's own records. The start has the
freer say 68, turn to the cuffed human over 325 (holding 0x2000000, so the mash's input waits) then loop 329, and
runs the mash (above, combat::ButtonMash) with his class's byte +0x08 (script::warriorMashByte(),
combat::mashFactor()); the cuffed human plays 326 paired, then 330. Success: he says 67 and is released (and revived
when knocked out and revivable), the freer plays 332 and he 333; failure (a quit command, the decay below 0, the cuffed
human gone or released some other way): 332 and back to 320. A body something else takes before the outcome (a hit)
plays 331. Player 1's mash meter (hud::MashMeter) shows from the press to
the outcome, filled by the meter over its target, and hides the prompt, the hint box and the scroll-in messages
meanwhile. A disc test ([disc][uncuff], repo:tests/platform/disc_level80_test.cpp) frees Snow and Cowboy at
level80 checkpoint 2 and reaches checkpoint 3; a cuffed friendly AI human wears the dyn_cuffs icon until his
release, which removes whatever icon he wears. Coney's stand-ins and readings: friendly is the gangs' friendship
(Human_IsFriendly, 0x00222a90, is not on the page); event 17's other human is none; the push weight, the partner and
the shared body group are not kept; after a hit the cuffed human goes back to 320; the cuffs icon stays attached over
his feet rather than detached where it appeared (he does not move while cuffed). Not yet: hint 19, the key path, the 0.2
m capsule test, players in cuffs, the leaderless gang's follow after a release and 0x00280fd8.
Coney's choices: a break-in and a custom crime queue kind-1 responders (the break-in after CfgBreakAndEnterDelay);
the assault statistic is scored once per victim through the service.
Owned items (repo:src/world_objects/spawn_records.h, repo:src/gamemodes/level_pickups.h, 2026-10-11): a spawn
record made with ObjSpawn flag 2 (record bit 0x80000, WorldObject_SetOwnedFromFlags 0x00392510) is owned; in
level80 that is the pharmacy's stock, the 23 objects of zone 24 with flags 2 in its placed-objects list (disc check,
NTSC-U, counts only). Whoever takes one, the player with triangle or a Warrior fetching it, clears it and the theft goes
to every enabled kind-0 volume box round the object's spot as message 7, (taker, object)
(VolumeBoxes::sendTheft, repo:src/world_objects/volume_boxes.h); an AI's take of a TYPE_SPECIAL removes it with
nothing given. Coney's readings: the page names the inside test (0x00412a18) but not which boxes are asked nor
whether the point is the object's or the taker's, so they are the boxes message 6 asks and the object's spot. Not yet:
the witnesses' message 7 and alert, the crime score 4-8 and the lines 128 / 143.
Open questions¶
-
GetItem's swing at glass (AI: GetItem): at level80's pharmacy (scenario
steal_store) two Warriors reached the glass branch 23 times each in 60 s and no pane broke. Whether the queued kind 0 played at all (the anim-dispatch log of that run was not read), whether its strike reaches the pane's body from the standing point, and whether the pharmacy's panes are alarmed or otherwise special are not known. The run was staged (checkpoint 1 state, the crew teleported inside, the order given through the dispatcher), so the mission's own path (the front lock picked, the order given by the script) should be run before an implementer copies "they never break it". -
Which objects register context records of kinds 1, 4 and 5, and with what second value.
- Who sets mini-game mode 4.
- The prompt widgets' base position and text style.
- The lock-picking dial's rate at runtime (one step per drawn frame is inferred).
- Whether the police a lock-picked break-in calls attack the picker's gang (the pick reports no offender; Which break-ins call the police). Both a break-in and a custom crime queue kind 1.
- Wiring the report's police hostility, responders and HUD messages to Coney's gangs, spawners and HUD.
- Whether
Tag_UpdatePlayersends the tag0x41withTag_GetProgress's 1.0 when the game ends unfinished (+0x4fc: out of paint, or a 301st cell), which would show the wall tag whole though it is not marked sprayed.