Sprites & objects
Field objects and how they reach the screen: the per-object animation tick and frame-build queue, the frame builders that copy graphics into a WRAM buffer and queue them for VRAM, and the OAM shadow that every visible object is appended to each frame. The full walk-through, with the data structures, is the Sprite Init Explainer.
The function table below lists the "Sprites & objects" group, the routines named Obj_*. The
OAM and placement routines (Oam_*, Spr_*, SprBuf_*, VramQ_Flush) and
Field_ProcessAnimQueue belong to the same system but are in the "Engine" group, on the
Engine core page.
See also: Frame cycle and NMI, Field event scripts.
Objects
Each location defines Evt_ObjCount objects (from its event data), kept in per-object tables indexed by object number × 2 (Obj_Cur, $016D). Positions (Obj_PosX/Y) are in
1/16 pixel, the high byte being the 16-pixel map tile; Obj_SprSize gives the size class (4, 8,
12 or 24 sprite tiles), Obj_State the progress of the frame build, Obj_OamFlags the OAM range.
Every frame, Vblank_UnkA810 ($C0:A810) walks the objects: moves each one (Obj_MoveStep,
Obj_MoveStepFree), tests it against a window a little larger than the view (Obj_UpdateInView),
and for one in the window ticks its animation (Obj_AnimTickAndQueue), works out its screen
position (Obj_CalcScreenPos) and re-links it into the draw bucket for that position
(Obj_DrawUnlink, Obj_DrawLink). Field_UnkB0E6 is the same pass at a location load, without
movement.
Frames
When an object's animation timer runs out it joins the frame-build queue, and
Field_ProcessAnimQueue builds queued frames while the frame still has time
(Obj_BuildSpriteFrameStep → Obj_BuildFrame4 / 8 / 12, in one, two or three passes). A
build copies the frame's 8×8 graphics tiles into one to three $200-byte chunks of the WRAM tile
buffer at $7F:3800, queues them for VRAM, and writes the object's tile records.
Spr_LoadLargeObj loads a 24-tile object in one go.
Slots
Objects take VRAM tile space and palette rows by kind (Obj_Unk1100): Obj_Unk6F9A /
Obj_Unk7056 allocate and free tile slots (Obj_TileSlot), and Obj_Unk7170 / Obj_Unk72B4 /
Obj_Unk734C palette slots (Obj_PalSlot; kinds 0–2 have fixed slots 5–7). These keep Unk
names for their verified callers; NEXT.md suggests Obj_TileSlotAlloc/Free and
Obj_PalSlotAlloc/AllocBtl/Free.
Drawing
Oam_BuildShadow ($C0:B271) rebuilds the OAM shadow before each frame wait: for every object in
every draw bucket, Spr_AppendToOam brings its tile records up to date (Spr_PrepareTiles) and
copies them into one of three ranges of the shadow; leftover entries are parked off screen. The
NMI uploads the shadow and the queued graphics.
Functions
| Address | Function | Size | Status | Notes |
|---|---|---|---|---|
$C0:305D | Obj_ | 86 | verified | Steps Obj_Cur toward the point $80 / $F0 within its tile (Obj_TileCentreX, Obj_TileFootY: the middle column, the bottom row of the tile), one frame at a time. |
$C0:30B3 | Obj_ | 161 | verified | Steps Obj_Cur onto the position of the object in ObjFront_Other, one frame at a time: compares Obj_PosX and then Obj_PosY of the two with the low four bits masked (Obj_PosCoarseMask). |
$C0:5614 | Obj_ | 119 | verified | Picks Obj_Cur's animation row from its speed. |
$C0:568B | Obj_ | 27 | verified | |
$C0:6F9A | Obj_ | 13 | verified | Runs Obj_TileSlotHandlers entry Obj_Unk1100 of Obj_Cur, unless bit 7 of it is set. |
$C0:6FA7 | Obj_ | 18 | verified | Obj_Unk6F9A's handlers by Obj_Unk1100 (9 words, kinds 0-8). |
$C0:6FB9 | Obj_ | 1 | verified | Obj_TileSlotHandlers' entry for the kinds that take no tile slot: RTS. |
$C0:6FBA | Obj_ | 156 | verified | Gives Obj_Cur tile slots in Obj_TileSlot by its size class (Obj_SprSize & ObjSpr_SizeMask): - class 0: the first free slot from ObjTile_SingleTop ($19) down to 1 (slot 0 is never tried); - classes... |
$C0:7056 | Obj_ | 46 | verified | Gives back Obj_Cur's tile slot(s): n = Obj_TileRecOfs / $20 (the slot Obj_TileSlotAllocKind took). |
$C0:7170 | Obj_ | 17 | verified | Unless Field_Unk54 bit 7 is set or Obj_Cur's Obj_Unk1100 has bit 7 set, runs Obj_PalSlotHandlers entry Obj_Unk1100 (kinds 0-11) to give the object a palette slot. |
$C0:7181 | Obj_ | 24 | verified | Obj_Unk7170's handlers by Obj_Unk1100 (12 words, kinds 0-11). |
$C0:7199 | Obj_ | 2 | verified | Kind 0: X = ObjPal_SlotKind0 (slot 5), then falls into Obj_PalSlotFixed. |
$C0:719B | Obj_ | 119 | verified | Gives Obj_Cur the palette slot X (5, 6 or 7 for kinds 0, 1 and 2). |
$C0:7212 | Obj_ | 5 | verified | Kind 1: Obj_PalSlotFixed with X = ObjPal_SlotKind1 (slot 6). |
$C0:7217 | Obj_ | 5 | verified | Kind 2: Obj_PalSlotFixed with X = ObjPal_SlotKind2 (slot 7). |
$C0:721C | Obj_ | 152 | verified | Kinds 3, 4 and 7-11: first looks through slots 0 to ObjPal_AnyEnd - 1 (0-4) for a taken one whose owner has Obj_Cur's Obj_PalSrc and, at the first, chains Obj_Cur after the owner (Obj_PalPrev =... |
$C0:72B4 | Obj_ | 152 | verified | As Obj_PalSlotAny over slots ObjPal_BtlFirst to ObjPal_BtlEnd - 1 (1-3): kinds 5 and 6 through Obj_PalSlotHandlers, and FieldBtl_SaveObj for an object with Obj_Unk1A81 bit 7 set. |
$C0:734C | Obj_ | 77 | verified | Takes Obj_Cur out of its palette slot's chain, unless Field_Unk54 bit 7 is set (then nothing, C=1). |
$C0:A7E9 | Obj_ | 39 | verified | For each location object (Evt_ObjCount of them) writes 0 to its Obj_Unk0F00 (no frame to build) and Obj_LastFrameNone to its Obj_LastFrame (so the next frame is always rebuilt), through the WRAM... |
$C0:A88D | Obj_ | 186 | verified | Tests object Obj_Cur against the view window and sets it up or drops it as it enters or leaves. |
$C0:A947 | Obj_ | 67 | verified | The view test for objects whose Obj_Unk1100 is Obj_Unk1100Seven: only sets Obj_Unk0F00 = Obj_Unk0F00Active in the window and 0 out of it, with no set-up, linking or release. |
$C0:A98A | Obj_ | 67 | verified | Takes object Obj_Cur out of its draw bucket, if it is in one (Obj_DrawOut bit 7 clear). |
$C0:A9CD | Obj_ | 58 | verified | Puts object Obj_Cur at the head of the draw bucket for its Obj_ScreenY, unless it is already in one (Obj_DrawOut bit 7 clear). |
$C0:AA07 | Obj_ | 192 | verified | One frame of movement for object Obj_Cur (Obj_Unk1100 3 and up), while Obj_MoveFrames is nonzero (it is decremented first). |
$C0:AAC7 | Obj_ | 54 | verified | |
$C0:AAFD | Obj_ | 72 | verified | Movement for objects with Obj_Unk1100 below Obj_Unk1100FreeMove: with Obj_ArcMode set, the arc step (BRA Obj_MoveStep_Arc); otherwise, while Obj_MoveFrames is nonzero (decremented first), the low... |
$C0:AB45 | Obj_ | 93 | verified | Screen position of object Obj_Cur from its map position and the layer-1 view: ObjScr_ViewX = Map_TileOriginX (low byte) x 8 + (Map_Unk1D87 & 7), ObjScr_ViewY likewise from Map_TileOriginY and... |
$C0:ABA2 | Obj_ | 199 | verified | Direction from point (ObjDir_FromX, ObjDir_FromY) to (ObjDir_ToX, ObjDir_ToY), map tiles, as an angle in Obj_Direction: 256 per turn, $00 = +X (right), $40 = +Y (down), $80 = -X, $C0 = -Y. |
$C0:AC69 | Obj_ | 148 | verified | Sets object X's steps from Obj_Direction and Obj_Speed with the hardware multiplier: Obj_VelY = speed x sin / 256 and Obj_VelX = speed x cos / 256 (Rom_SineTable256 at the direction and at the... |
$C0:ACFD | Obj_ | 410 | verified | As Obj_SetVelocity (steps from Obj_Direction and Obj_Speed, the sine into ObjVel_Y and the cosine into ObjVel_X, sign-extended into ObjVel_YHi / ObjVel_XHi), but it looks at the map tile the... |
$C0:AE97 | Obj_ | 153 | verified | |
$C0:AF30 | Obj_ | 30 | verified | Zeroes one of the two steps in ObjVel_X / ObjVel_Y, then probes and stores them through Obj_SetVelocityChecked_Probe: when |Y step| >= |X step| the Y step goes, else the X step. |
$C0:B127 | Obj_ | 107 | verified | Obj_UpdateInView's set-up half for a location load: when Obj_Unk1A81 is 1..$7F and the object lies in the view window, sets it up exactly as Obj_UpdateInView does (Obj_DrawPrev / Obj_DrawNext /... |
$C0:B192 | Obj_ | 32 | verified | (was Sub_B192.) Clears Obj_State for every object the location defines (count in Evt_ObjCount), pointing DP at the Obj_State table so each clear is a 2-byte dp store, then tail-jumps to... |
$C0:B204 | Obj_ | 94 | verified | Empties the draw buckets: with DP=$2100 it writes ObjQ_Empty ($80) to the first 32 bytes at Obj_DrawBucket through the WRAM port, then MVNs spread them over the rest of the page ($0E20-$0EFF: 32... |
$C0:C98A | Obj_ | 236 | verified | Per-object animation tick, called for object Obj_Cur from the object loop ($C0:A832, $C0:A878). |
$C0:CAD9 | Obj_ | 49 | verified | One step of building object Obj_Cur's current frame, graphics included: skips (C=0) unless Obj_Unk1100 bit 7 is clear, Obj_Unk1A81 is 1..$7F and Obj_Unk0F00 is nonzero; then by size class... |
$C0:CB0A | Obj_ | 48 | verified | (was Sub_CB0A.) Like Obj_BuildSpriteFrameStep, but for objects whose tiles are already in VRAM: tail-calls Obj_FrameLayout4 / 8 / 12, which only rewrite the SprTile records for Obj_LastFrame. |
$C0:CB3A | Obj_ | 162 | verified | (was Sub_CB3A.) Returns in A the frame number object X should show: Anim_FramePtr = Obj_AnimFrameTbl + (Obj_Facing × Obj_AnimFacingStride) + row*4 + Obj_AnimColumn, row = Obj_AnimRow (or... |
$C0:CBDC | Obj_ | 492 | verified | (was Sub_CBDC.) Builds frame A (Obj_FixedFrame in mode 3, else Obj_AnimFrameLookup) of a 4-tile object, in one pass. |
$C0:CDC8 | Obj_ | 301 | verified | (was Sub_CDC8.) Rewrites the 4 SprTile records of a 4-tile object for Obj_LastFrame directly (tiles already in VRAM): offsets from the frame record, Tile = Obj_VramTile + 2n, attributes as in... |
$C0:CEF5 | Obj_ | 559 | verified | (was Sub_CEF5.) Builds the current frame of an 8-tile object. |
$C0:D124 | Obj_ | 358 | verified | (was Sub_D124.) As Obj_FrameLayout4 for an 8-tile object (frame record 80 bytes, positions after 32 tile words); the first four tiles take Obj_PrioLow, the last four Obj_PrioHigh (by index, not by... |
$C0:D28A | Obj_ | 131 | verified | (was Sub_D28A.) First pass of an 8-tile frame: look the frame up, SprBuf_Alloc2 (2 adjacent SprBuf chunks), copy tiles 0-15 into the first chunk, INC Obj_State, return C=1 (more to do). |
$C0:D30D | Obj_ | 490 | verified | (was Sub_D30D.) Second pass: tiles 16-31 into the second chunk (Obj_TileBuf + $200), queue the VRAM upload ($200 bytes to Obj_VramTile*16, $200 more to the next tile row), write the 8 SprTileSrc... |
$C0:D4F7 | Obj_ | 79 | verified | (was Sub_D4F7.) Builds the current frame of a 12-tile object over three passes chosen by the Obj_State count (0 / 1 / 2+), each with an "Alt" variant when Obj_VramTile is ObjTile_AltLayout ($68... |
$C0:D546 | Obj_ | 194 | verified | (was Sub_D546.) Pass 0: frame lookup, SprBuf_Alloc3 (3 adjacent SprBuf chunks), tiles 0-7 to the buffer start and tiles 8-15 to +$200, INC Obj_State; C=1. |
$C0:D608 | Obj_ | 131 | verified | (was Sub_D608.) Pass 0 for the ObjTile_AltLayout ($68) layout: frame lookup, SprBuf_Alloc3, tiles 0-15 in one run to the buffer start, INC Obj_State; C=1 (C=0 when nothing changed or no chunks are... |
$C0:D68B | Obj_ | 173 | verified | (was Sub_D68B.) Pass 1: tiles 16-23 to +$100, tiles 24-31 to +$300; INC Obj_State; C=1. |
$C0:D738 | Obj_ | 173 | verified | (was Sub_D738.) Pass 1 for the ObjTile_AltLayout ($68) layout: tiles 16-23 to +$200, tiles 24-31 to +$400; INC Obj_State; C=1. |
$C0:D7E5 | Obj_ | 644 | verified | (was Sub_D7E5.) Pass 2: tiles 32-47 to +$400, queue the VRAM upload ($500 bytes from Obj_TileBuf to Obj_VramTile*16, then $100 bytes from +$500 to 3 tile rows further on, +$300 words), write the... |
$C0:DA69 | Obj_ | 703 | verified | (was Sub_DA69.) Pass 2 for the ObjTile_AltLayout ($68) layout: tiles 32-39 to +$300 and 40-47 to +$500, queue the upload ($100 bytes to Obj_VramTile*16, then $500 bytes from +$100 to the next tile... |
$C0:DD28 | Obj_ | 1,026 | verified | (was Sub_DD28.) Rewrites the 12 SprTile records of a 12-tile object for Obj_LastFrame (tiles already in VRAM): offsets from the frame record (120 bytes, positions after 48 tile words), tile... |