AI and the world: objects, cars, doors and climbs¶
Verified against: SLUS_212.15 (NTSC-U, SHA1 e9cb2cc49aa046b9e494313dce2f5038ed17b2f4). Static reading in Ghidra
(2026-10-07); each claim states its evidence level.
Purpose¶
How an AI human touches the world, seen from the Human side. It covers which world uses an AI reaches, through which of the player's own functions, and which it never reaches. AI humans explains the brains, goals and actions; this page fills the gaps between that page and the Human pages (Characters, Combat, Combat moves). Where another page already covers a topic, it is linked here, not repeated.
| Topic | Where it is covered |
|---|---|
| Which goal fetches an object, the object search, letting go | AI: Fetching an object, Objects in an AI's hands |
| World flags (activities) | AI: World flags; reinforcements spawned on them: below |
| Hiding, cars and trains in brief | AI: Cover, cars and trains |
| Route links: climbs, jumps, doors, charges | AI: Following a route, Jump legs |
| How the scripts drive the AI | AI: How the scripts drive the AI |
| An AI's attacks and the held object's effect | Combat: An AI's attacks |
| Each weapon set's swings, throws and blocks | Combat moves: Weapons |
| Steps and giving way | Characters: Step control, AI: Giving way |
Behaviour¶
An AI presses the player's buttons¶
An AI human uses the world through the same functions as a player. Its actions write a command into its
per-player record (PlayerRecord_SetCommand, 0x00147ef0), and Player_UpdateActions (0x0027c120) runs that
command for every human whose per-player +0x1e is 0, AI humans included (Combat: The dispatcher).
So the world use is the player's code, and Coney needs no second copy of it. Confirmed (code) at the
addresses cited.
| World use | How the AI asks | What runs | Commands |
|---|---|---|---|
| Pick an object up | PickUpItem action (below) |
Player_OnCommand33 → Human_PickUpSearch |
0x33 |
| Swing a held weapon | an attack kind with a set 1-3 object in hand | square or cross, armed branch | 0xf, 0x10 |
| Throw a held object | cross with a set 4-6 object, aim at human +0x128 |
Player_CrossWithWeapon (0x002880d8) |
0x10 |
| Throw a melee weapon | kind with command 0x39 |
Player_ArmedSpecial |
0x39 |
| Hit a car part | kind 11 or 12 with the car record in +0xe0 (below) |
the push or the grounded strike | 0x36, 0x37 |
| Smash a breakable on a route | kind 19 at a run (below) | the running charge | 0x20 |
| Climb a fence or wall | the route follower calls the player's climb directly | Climb_TryStart (0x002826f0) |
none |
The commands and their handlers are listed in Combat moves: Commands only scripts and the AI send.
What an AI never does¶
Confirmed (code) unless marked:
- No mini-game.
MiniGame_Start(0x0022dc40) returns at once for a human that is not a pad player (human+0x1b0= −1). So an AI never steals a car stereo, picks a lock, mashes an object or plays a button mini-game. For a player, the mode in the player state's+0x46picks the game: 3 the stereo theft, 2 the lock pick, 4 the object mash, 5 the button game (Crimes). Before that, the held object is dropped. - No car. No function in the Human or AI range puts a human into a car or drives one, and cars run on their own paths (Cars). An AI meets a car only by hitting it (Smashing a car), by investigating a crime at one (AI) or by being hit by it. Inferred from the absence of any such caller.
- No block. An AI never starts a block, because the block reads the pad (Combat: The dispatcher).
- No cover. No goal seeks cover or shadow on its own (AI: Cover, cars and trains).
- No closed door. An AI never opens a closed door by itself (Doors).
Picking up¶
The PickUpItem action (vtable 0x00542ea0) is the AI's press of the pick-up button. Confirmed (code) at the
addresses cited.
- Init (
0x002faf98) keeps the object's handle (−1 when none). - Start (
0x002fb000) makes the object the human's object target (Human_SetObjectTarget,0x00227080) and writes command0x33. - The dispatcher runs
Player_OnCommand33(0x00281188). It does nothing while the human holds any flag of0x2fefefffor has any state bit of0x7bf9e9f7ff0; otherwise it runs the player's pick-up search (Human_PickUpSearch,0x0024d810; Combat: Breakables, World objects: Pickable objects). - Update (
0x002fb0a8) reports running on its first update, then while held flag0x4000(a pick-up playing) is set, then done.
The pick-up itself is the player's. PickUpItemAction writes command 0x33, which runs Human_PickUpSearch
(0x0024d810) as for a player; but a human with an object target (the action's Start sets it) skips the 1.5 m
search and its sight rays and takes that object at once, so the only glass test on an AI's take is GetItem's ray
above. The object then gets message 0 and plays the player's clip by height (463 at or below 0.8 m above the feet,
464 above; Combat: breakables), and Human_PickUpObject runs at the clip's event. Confirmed
(code) at 0x0024d810, 0x002faf98.
Two goals look for a weapon themselves, besides those listed in AI: Objects in an AI's hands.
Both push GetItem with gait 4 and use Ai_FindObject with a line of sight, a claim and a reach test
(AI: The object search):
| Goal | Helper | When | Radius | Filter mask | Extra test |
|---|---|---|---|---|---|
| Hostile | Hostile_GrabWeapon (0x002d5668) |
no queued action, the goal's taunt count +0x1e still 0, human +0x3b8 not 1, nothing held |
5 m | 0x20000 (weapons) |
the object's type class +0x87 is not 4 |
| DestroyCar | DestroyCar_GetWeapon (0x002ddd48) |
actions not blocked, nothing held, no spot yet | 10 m | 0x10000 |
WorldObject_CanBePickedBy (0x00395148) |
The masks are the filter's (0x0053f2d0) type bits; 0x10000 is the throwable bit, inferred from Melee asking for
both as 0x30000 (AI).
Hostile, when it does not fetch (HostileGoal_Process, 0x002d58b8, with no action queued):
- with the target more than 22.5° off (15° when the target stands still), turn to him;
- else, holding a throwable (
Human_HeldIsThrowable), queue cross (kind 0) at him; - else, at most every 3.0-3.5 s, say line
0xafand, unless holding a kind 4 or 6 object, play clip 595 (a random variant 0-3, after 0-249 ms; the argument meanings are inferred), and count the taunt in+0x1e; - once that count is above 0, the next free update attacks him instead (
Hostile_Attack) and the goal ends.
When it pushes GetItem, Hostile_GrabWeapon also sets the goal's +0x1c and drops what is held.
Smashing a car¶
DestroyCar (type 0x2e, its rows): the AI takes a spot round the car and
strikes the car part at that spot. Confirmed (code) at 0x002dde50 and the car functions cited.
The spots. Each car keeps 10 spot owners at +0x12da (one byte each, a human index or −1).
- Reserve (
Car_ReserveSpot,0x0038d810): the first spot that meets all of these:- it is free;
- it is not blocked:
Car_IsSpotBlocked(0x0038da88) says a spot is blocked when every part of its mask is already off (car+0x11f8, Cars); - no player is within 1 m of the spot;
- a ray (mask 8) from the spot to its part is clear;
- the human can reach the spot on the nav mesh (
Nav_CanReach).
- On a coupe (type index 1, Cars: Types) spots 6 and 7 are skipped, and count as blocked.
- Each spot's part comes from
Car_GetSpotPartMask(0x0038da08) and its position fromCar_GetSpotPosition(0x0038db40), both a switch on the spot (jump tables0x0057e410and0x0057e440). The table below gives them. Car_FindSpotOfHuman(0x0038d7d8) andCar_ReleaseSpot(0x0038d998) find and free a human's spot; 10 means none.
Where each spot is. Every part keeps its world matrix in its 0xa0-byte record at car +0x1a0 + 0xa0 × p:
rows at +0x00, +0x10, +0x20 and the position at +0x30 (Car_CachePartTransforms, 0x00387780, through
CarInstance_GetPartLtm). A spot is the part's position moved 0.8 m along one of its rows, then its height set
to the car's height (+0x18) less 0.6 m (0.95 m for a van, type 4). The part's position (+0x30) is also
the point the AI turns to and strikes at. Confirmed (code) at 0x0038da08 and 0x0038db40:
| Spot | Part (mask) | Position, any type but the van | Position, van |
|---|---|---|---|
| 0 | 2, front bumper (0x4) |
position − 0.8 × row 1 | position + 0.8 × row 2 |
| 1 | 3, back bumper (0x8) |
position − 0.8 × row 1 | position + 0.8 × row 2 |
| 2 | 11, front side panel (0x800) |
position + 0.8 × row 2 | same |
| 3 | 10, front side panel (0x400) |
position + 0.8 × row 2 | same |
| 4 | 16, door (0x10000) |
position + 0.8 × row 2 | same |
| 5 | 14, door (0x4000) |
position + 0.8 × row 2 | same |
| 6 | 20, door (0x100000) |
position + 0.8 × row 2 | position + 0.8 × (row 2 − row 1) |
| 7 | 18, door (0x40000) |
position + 0.8 × row 2 | position + 0.8 × (row 2 − row 1) |
| 8 | 13, back side panel (0x2000) |
position + 0.8 × row 2 | same |
| 9 | 12, back side panel (0x1000) |
position + 0.8 × row 2 | same |
The part names are Cars' reading of the part ids. Read from three parked cars in a state file (a coupe and two sedans; the user's quick-save 5, read from a copy), confirmed (runtime):
- each bumper's row 1 points into the car, so spots 0 and 1 stand 0.8 m beyond the bumpers;
- each side part's row 2 points straight out of its side, so spots 2-9 stand 0.8 m out from the side;
- odd spots (3, 5, 7, 9) are on one side and even spots (2, 4, 6, 8) on the other;
- each side has, front to back, the front side panel, the front door, the back door and the back side panel.
On a sedan, at 1.09 m car height, the spots stand at 0.49 m. A coupe skips spots 6 and 7, its back doors. The van's own part frames were not read, so its rows are not checked.
Start (0x002ddc18) drops the target, drops a held object of set 1 (a knife), and takes the spot the human
already holds, if any.
Process, each update:
- Done when the car is gone. Every 30 updates, look at the car for 1.5 s.
- Wait while actions are queued. A failed move (brain
+0x284not 0) clears that flag and ends the goal. - With a leash (goal
+0x14> 0), done when farther than the leash from the gang's leader. - No spot yet. Done if the goal has had a spot before (
+0x1a). Otherwise fetch a weapon (DestroyCar_GetWeapon, above), or else reserve a spot (done when none is free) and make the car the object target (+0x128). - When the spot has become blocked, release it, clear the object target and wait.
- Mark that the goal has had a spot. When the human is more than 0.5 m from the spot, walk there (gait 2 within 2 m, else gait 4), out of the fight stance.
- At the spot. Find the spot's part (
Car_GetSpotPartMask,Car_FindPartRecordByBits). When the facing is more than 15° off the part, turn to it. Otherwise: - the kind: 11 (
0x36, the push 21ATTACK_PUSH) when the part is at least 1.33 m above the human's feet, 12 (0x37, the grounded strike 193) when lower, and 0 (cross) whenever an object is held, so an armed AI swings its weapon at the car; - drop the human target, make the car the object target, and copy the part's position into the record's
+0xe0-+0xec, where a player's target search puts a car target (Combat: Target selection); - queue the attack at himself (
Brain_QueueAttack); - every 8 s, when he may gesture: say line
0x8e(30 %) or0x8f(70 %).
How the strike reaches the car. Confirmed (code) at 0x0027de78, 0x00287fe0, 0x00261c80 and 0x00261a08;
the strike path is the player's.
- The clip plays in place. The queued kind becomes a command in the per-player record:
- kind 11 is
0x36, handled byPlayer_OnCommand36, which callsAttack_StartAtTarget(h, target, 21); - kind 12 is
0x37, handled byAttack_StartGroundStrike, which callsAttack_StartGrounded(h, target, 193).
- kind 11 is
Both read the target with Human_GetTarget, the human target, which step 7 dropped. With none, both skip the
steer and the turn and just start the clip (chained in over 0.1 s and 0.2 s, held flag 0x10). The facing comes
from step 7's turn to within 15° of the part. Nothing reads the record's +0xe0 car copy or the object target
+0x128 here.
2. The strike is a body overlap. The clip's strike window turns its strike shapes on:
- 21 ATTACK_PUSH: both hands, frames 2-8;
- 193 GROUNDED_STRIKE_01: foot B, frames 10-12.
While they are on, Human_TestStrikes tests them each update against the bodies near him, the car's physics
body included. The first overlap calls Strike_Contact (Combat: How a moving attack
strikes). The spot stands 0.8 m out from the part's origin, so a hand or foot that
reaches the car's box strikes it; a swing that misses the box does nothing.
3. The part comes from where he stands. Strike_Contact sees a car (type word 0x100000) and calls Car_OnHit
(0x0038bea0) directly. For a plain human hit, that picks the parts from the attacker's position in the car's zone
tables, with no facing test (0x0038b8d0). It does not use the clip's contact point. Standing at the spot of
part p, he hits the parts of that zone, which for these spots includes p (inferred from the spot positions
and the zone tables). An intact window shields its door, so at a door spot the first hit breaks the window
(Cars: Windows, hits and the stereo).
The car takes 0.34 per hit from a weapon or thrown object, 0.51 from a human with held flag 0x400000, and 0.115
otherwise. A gang-locked car ignores hits from other gangs.
Breakables, climbs and charges on a route¶
The route follower handles these link kinds (AI: Following a route). On the Human side, confirmed (code):
- The charge (
Route_SmashLeg,0x0029bca0), at a breakable door or pane: - aims at the link's point, at the route's radius, with gait 4;
- turns the body to face the point at once (
Human_SetRotation), and sets its velocity to 8 m/s toward it; - writes the command of attack kind 19 (
0x20, the running charge) into the per-player record.
The player's charge then breaks the object (Combat: Breakables).
- The climb (Route_ClimbLeg 0x0029b848, and Route_TryClimbNear 0x0029b9b0 for a fast climber, human flag
0x2, at a gait above 3 within 4.5 m) calls the player's Climb_TryStart
(Characters: Climbing). The executable has no separate vault (no such function or
caller), so a low fence is the same climb; inferred.
Doors¶
An AI never opens a closed door on its own. Confirmed (code) at the addresses cited.
- On a route, a closed door's link (kind
0x10with the avoid bit) refuses the move with brain+0x284= 4, an open door's link is walked, and a breakable door is charged (AI: Following a route). - Scripted:
OpenDoorAnimated(door, human)sends the door message 0.Door_OpenAnimated(0x00396fa8) makes the door the human's object target and sets its action code (record+0x14) to 26 (Human_SetAction,0x002266a8; World objects: Doors).Human_ChooseAnimState(0x00259578) turns action 26 into anim state 34 (0x22).- Anim state 34's builder (table
0x005106e0) isHuman_StartObjectSteerIdle(0x0025ff18). It runsHuman_StartObjectSteer(0x0025e948), then puts the anim state and the action back to 0. Human_StartObjectSteerplays clip 666ANIM_SPECIAL_OPEN_DOOR, then the idle. While the clip plays it holds flag0x4000, gives the human a push weight of 1e9, and steers him onto the object target over 0.1 s.- On the clip's animation event, with an object target,
Human_HandleMessage(0x00245920) callsDoor_OpenBy(door, human)(0x00396f08) and then clears the object target. Door_OpenBysends the door DoorOpen (message0x0b) with the human, which swings the door ±170° away from him. It also runs the objects' script callback.
Confirmed (code) at each address. This action 26 is not the jump's anim state 26 (Characters),
which is the anim-state field +0x18.
- Gang spawners (GangSpawner_Update, 0x001681a0). When a member is spawned, the spawner opens its door
(spawner +0x70, gang +0x6b0 for the first). It keeps the new human at spawner +0x10 and notes the time at
+0x78 and +0x80. Each update after that:
- while that human has no character instance yet (human +0xd8 is 0,
Characters), the open time is renewed. So the door stays open until the human
has his model (inferred: the model is still loading);
- once the time is more than +0x6b4 ms past, the door closes;
- otherwise the door is told to open again every 500 ms.
AI: Spawners gives the slot's other fields.
Where a reinforcement spawner puts its humans¶
A spawner in state 7 ("reinforcements", Spawner states) does not spawn at its own
position: Spawner_PlaceState7 (0x001679e8) puts each human on a pedestrian flag (the flag list of
AI: World flags), out of the camera's sight and away from the player. It is the placement of every
spawner level34 runs (Scripts: level34), and of states 7 in level2, level3,
level5, level9, level11 and level14. One try per spawner update; a failed try spawns nothing that update.
Confirmed (code) at the addresses cited unless marked:
- Camera and player. The camera of the spawner's player (
+0xe1; player 1's when that one has none) and that player's human (game state+0x228 + 4 × player); no camera, no spawn. - The aim. The origin is the camera's position (vtable
+0x21c) with its z replaced by the player's feet z (position table0x00714b00). The forward is the camera's y axis (vtable+0xac, then0x003363b0) with z set to 0 and not normalised again. h = (field of view (vtable+0x2ac) × 0.5 + 10)° in radians. One angle θ =Random_FloatRange2(0, 2π)(0x00335420). - The distance d: when θ lies in [h, 2π − h] (beside or behind the view) 35 m; otherwise (ahead,
inside the cone) the camera's view distance (vtable
+0x20c) capped at 70 m (0x0050cc60). Code at0x00167b74-0x00167ba8. - The aim point = origin + d × the forward turned by θ about the vertical (the quaternion axis at
0x00511740). - The flag.
FlagList_FindNearest(d, aim point, player's feet, type, 0)(0x002adac0): of the listed flags (0x006e9440, 128 entries of 20 bytes) that have an activity (+0xd4≠ 0), lie at least d from the player's feet (3D) and suit the character class of the spawner's first type (slot 0 of+0x24, throughFlagNet_GetMask0x002a7538: a flag whose mask+0xd8is 0 suits anyone, and so does a class whose mask is0x20), the one nearest the aim point. No flag, no spawn. The human stands on that flag's position. - Turf. The flag must lie in one of the gang's turf boxes (
Gang_IsPointInTurf0x001652e8; a gang with no turf takes any, AI: Out of sight). - Unseen.
Camera_CanSeePoint(0.3, d, camera, flag + 1.6 m up)(0x00122548, Off screen) must not answer 1. With two players, the other player's camera must not see it either, at its view distance capped at 70 m and raised to at least 35 m. - Not crowded. With z back on the flag, the gang's first member that still resolves (16 handles at gang
+0x48) is the reference. A gang with none passes. OtherwiseHumans_ListNear(0x0029c6d0, radius 5 m passed inf12) lists the humans near the flag that are friendly to him (Filter_IsFriendly0x0029c3f8). Any one there refuses the spot. Code at0x00167db0-0x00167e44.
Nothing in this function sends the human anywhere: the first live member is only the friendliness reference. What a
reinforcement does next is its spawn callback's business (level34's give a riot goal or a flag-net walk). The
Spawners summary used to say the human is sent to that member; this reading replaces it.
In Coney (repo:src/ai/spawners.cpp, Spawners::spawnOne): state 7 is placed as state 8 with a value of 0, by
the outward route search from the player's node. With a value of 0, any node outside the view cone qualifies,
however close, so the human appears beside the player on whatever route graph the player stands on. In level34
that is the subway the mission starts in (user checklist item 17).
Coney fixes (state 7).
- Give state 7 its own placement, the steps above: one random angle a try, 35 m beside or behind, up to 70 m ahead, the nearest suitable pedestrian flag to the aim point at least that far from the player, in the gang's turf, unseen from 1.6 m above, and no human friendly to the gang's first live member within 5 m.
- Spawn nothing in an update whose try fails, so the spawner tries again on its next update.
- Leave the human where the flag is: no walk to the first live member.
- Tests: synthetic flags and camera. A flag inside 35 m behind the player is never chosen. The chosen flag is the nearest qualifying one to the aim point. A flag in view, outside the turf, or with a friend within 5 m refuses the spot. No flag means no spawn.
Reacting to the world¶
What an AI does about world things it does not use:
- Dealers: AI: GoalDealer.
- Breakables smashed by gangs: VandalizeItem, DestroyItem and Riot (AI goals).
- A crime at a car: the Pursue tactic (AI).
- Trains: RunFromTrain (AI).
No goal reacts to a door opening or to an object breaking as such: those reach the AI only as noises and crime events (AI). Inferred: no other caller of the door or breakable functions in the AI range.
Open questions¶
- The van's part frames, so its spots 0, 1, 6 and 7 can be placed without guessing (only sedans and a coupe were read).
- Whether the push's hands (21) and the ground kick's foot (193) reach the car's box from every spot in practice: a runtime check of a DestroyCar gang at a parked car.