Key functions
A directory of the game's traced functions, grouped by subsystem - the who's-who of the code the reverse-engineering has mapped. Each entry names a function and says in one line what it does. This page is the quick orientation; the full per-function reference lives in docs/reference/functions.md, which is a lookup table you grep for an address.
How to read an entry
A name like FUN_8003E4E8 is Ghidra's (the disassembler's) automatic label for the function whose code starts at RAM address 0x8003E4E8 - the game shipped no symbol names, so the address is the name, and it is stable across every doc and probe in this project. DAT_/PTR_ prefixes mark data and pointer-table addresses the same way; "JT" is a jump table (the array of handler addresses behind a switch).
The one thing that catches people out: functions at 0x801C0000+ are RAM-loaded overlays (code the game pages into RAM per game mode), and several overlays share that address window. One address can therefore name a different function depending on which overlay was resident when the dump was taken. If an entry does not match the code you are reading, check which overlay you have before concluding the entry is wrong - see overlay capture.
By subsystem
Boot + asset loader
FUN_8003E4E8- boot-time TOC loader; reads first 3 sectors of PROT.DAT into0x801C70F0FUN_8003E8A8- LBA resolver against the in-RAM TOCFUN_8003E6BC- path-based file opener (data\battle\efect.datetc.)FUN_8003EBE4/FUN_8003EC70- overlay loaders A / B;param + 0x381→ raw TOC index = extraction entryparam + 0x37F(the resolver indexes the raw in-RAMPROT.DAThead, 2 above extraction indexing); two overlays resident at once. Loader B pages in the per-summon Seru-magic overlays: a player Seru-magic cast (spell id in0x81..0x8b) callsFUN_8003EC70(id - 0x79)→ extraction PROT 903..913 (Gimard Burning Attack0x81→ PROT 903). The summon's 3D models live in those overlays + the extraction-0871etmd.datmodel library, not inbefect_data.FUN_8001F05C- asset-type dispatcherFUN_80020224- descriptor-pair walkerFUN_8002541C- streaming-asset driverFUN_80021934- scene-transition streaming actor (5-state SM overactor+0x1A, jump table0x80010760; real entry 3 insns before the0x80021940prologue - the body sat in never-analyzed space, invisible to instruction walks). Spawned on demand byFUN_8001FD44viaFUN_80020DE0from the spawn descriptor at0x80070734(one of the phase-misaligned descriptor family0x800705FC..0x80070763, NOT a mode-table row). Streams the destination scene'sDATA_FIELD\<scene>.LZSbundle (rawscene_base+3) into_DAT_8007B85C- by PROT index in dev (state 2), by built filename in retail (state 4) - then hands off with_DAT_8007B83C = 2(MAIN INIT). This is the_DAT_8007B85Cstaging path described in asset loader. Seeghidra/scripts/funcs/80021940.txt.
Game VMs
FUN_801D6628- actor / sprite VM (13 opcodes, JT at0x801CED70)FUN_80023070- move-table VM (71 opcodes, JT at0x80010778)FUN_801D362C- move-VM extension (61 sub-opcodes via op0x2F); same dispatcher in town / world-map / dialog / cutscene overlays at the same RAM addressFUN_8002519C- per-frame actor-list iterator; called 5x per frame fromFUN_80016444against the actor-list heads at_DAT_8007C34C..0x36CFUN_801DE840- field / event script VM (43 ops, switch at0x801E00F4)FUN_801E0C3C- field-VM0x4C2nd-stage dispatcher (16-entry JT at0x801CEE60)FUN_801E3040- field-VM0x4Couter-nibble-0xEsub-dispatcher (15-entry JT at0x801CF008)FUN_801E30E4- field-VM0x4C 0xE2FMV trigger; writes FMV index to_DAT_8007BA78+ game mode0x1A(StrInit) to_DAT_8007B83CFUN_8003CE9C- field-VM context resolver (sign-extended u16 read)FUN_80038158- per-actor motion / bytecode VM (the second motion VM; dispatched byFUN_8003BC08when actor+0x10 & 0x80); op-7sets / op-8clears the system story-flag bankDAT_80085758inline, flag index from its own script bytecode. Carrier = MAN tail-section 1 (installerFUN_8003A9D4, parserlegaia_asset::man_motion), swept disc-wide byman-scripts --motion-flag-census: the spine gates0x142/0x482/0x1BEand the town01 one-shot549appear in no motion stream - the first three are field-VM script bytes in the streaming variant MAN carriers, and549is a direct code path (the earlier "549 via op-7 bytecode" carrier reading is falsified).FUN_800204F8- move-buffer setup (Tactical Arts)FUN_80021DF4- per-frame actor tickFUN_8003A1E4- field-NPC placement installer (reads[model, anim, tile_x, tile_z]- no facing byte in the record). Its tail (body0x8003A474..0x8003A4F8) runs a spawn-time field-VM prologue pre-run: if the placement record's script opens with op0x24/0x25, it executes the leading ops one at a time throughFUN_801DE840until a0x21NOP or a sub-0x20byte - this is where a never-walked NPC's INITIAL FACING comes from (ops0x4C 0x51sub-1 and0x38writeactor+0x26from the 8-direction heading LUT at0x80073F04, entryi*0x200). Portman_field_scripts::placement_initial_facing+World::seed_field_npc_facings; see field locomotion. Seeghidra/scripts/funcs/8003a1e4.txt.
Cutscene / FMV
FUN_801CEA3C- STR/MDEC master dispatch (cutscene_str overlay 0970, modes 26/27): decoder select (Iki default; dev slots 9/10 = STRv2/v3), letterbox clears, play-loop call on0x801D0A6C + fmv_id * 0x20, and the post-play return-scene hand-off (label table0x801CE8AC→ scene-name global0x80084548+ spawn word0x80084540)FUN_801CF098- STR/MDEC FMV main play loop (1236 B / 309 instr; takes(wide_flag, &dispatch_slot); pad-abort honoured only forfmv_id 0)FUN_8005F024- STR frame-demux state machine (SCUS St library; ready-callback frontFUN_8005ECD4): magic-0x160/stream-number gate, seek-to-start-frame, chunk sequencing into per-frame ring slots, end-frame latch; ring APIStSetRing FUN_8005BBF8/StGetNext FUN_8005EF40/StFreeRing FUN_8005EE4C, read startFUN_8005EB68(Setmode0xE0, no SF)FUN_8003D764- XA-clip drive sequencer / channel selector (SCUS):CdlSeekL→ Setmode0xC8→CdlSetloc→CdlSetfilter {file 1, chan}→CdlReadS→CdlGetlocPpoll; armed byFUN_8003D53C/FUN_8003EAE4off the 34-slotXA1..XA34clip table at0x801C6ED80x801CAE08(data) - libcdCdlFILEdirectory cache ([loc][size][name[16]]per file of the last-searched dir)0x801D0A6C(data) - FMV dispatch table (32 B × 23 slots; static overlay data,legaia_asset::fmv_dispatch)FUN_8003BDE0- partition-record → VM-context dispatcher,(x, z, record, gate); named-record header (name + 3 story-flag gates: C1 blocks if ANY set vs bitmapDAT_80085758, C2 requires ALL), script entry1 + name_len*2 + (1+C0) + (1+C1*2) + (1+C2*2)(opdeene record 18 →0x10). Two caller families: field-VM op0x44SPAWN_RECORD (ra0x801DF098) and the walk-on tile triggerFUN_801D1EC4→FUN_801D5630(ra0x801D218C)FUN_80037174- narration crawl roller actor handler (the[CC F8 80 N]op): spawned as a child context so the parent timeline keeps running and the between-block camera cuts play under the scroll (parent blocks only before a new block and before the terminal SceneChange); owns all N pages, bottom-up crawl, all glyphs at once, capture-pinned per-scene window/speed; engine scrolls it on a 60 fps sub-clock since the sim ticks at 100 HzFUN_8003C764- on-screen text-balloon spawner (the4C E1op; handlerFUN_801DA7F0kills the predecessor); centers the line, fixesY=180, seeds the per-page timer to0x78(120 frames) - not the opening crawlFUN_8003C83C- field-VM cross-context resolver;0xF8→ player / camera-anchor actor (_DAT_8007C364),0xFB→ system channelFUN_801DB8EC- camera focus + projection setter (field overlay; disassembled from live overlay RAM in thenew_game_cutscene_intro_asave, since the headless Ghidra dump truncates it). CallsFUN_801DAB90(transform_ptr, 0x801F3580)(builds the camera-param struct), sets the GTE H register from_DAT_8007B6F4viafunc_0x8003D254(=setCopControlWord(2,…)), and writes the focus globals_DAT_80089118/_DAT_80089120: when camera-mode byteDAT_8007B607>>4 == 5the focus is tile-derived-(tile<<7)-0x40, otherwise anchor-follow-(anchor+0x14)/-(anchor+0x18). So this is the focus + FOV setter, not an eye-position build - the eye-back depth lives in the op-0x45translation trio's slot 5 (_DAT_800840C0), not here (see cutscene op-0x45). Invoked by field-VM op0x4C 0x39and op0x4C 0x3E.FUN_801DBC20- camera-zone config loader (resident camera cluster). Splits the 18-byte camera-region record'sbytes[5..17]into the camera globals0x8007B607..0x8007B627, keyed on the mode nibblebyte[5] >> 4(3= look-at-anchor split,5= fixed-shot split,6= no-op, else the position-sweep split); consumed by the camera-param builderFUN_801DAB90+ follow-easeFUN_801DB510, query miss loads fixed defaults inFUN_801DBE9C. Full byte split: encounter § camera-region table.
Renderer + GTE
FUN_8002735C- Legaia 60-GTE TMD renderer; the landmark emit leaf reached fromFUN_8001ADA4case-5 for each landmark TMD in a kingdom packFUN_8001B964- per-actor animated-mesh renderer: walks the actor's object table against its ANM record (actor[+0x4C]), posing TMD objectiwith bonei'sR·v + T; skips the draw unless the object count equals the record's bone countFUN_8001BE80- per-(bone, frame) ANM entry decoder (3 nibble-packed signed-12-bit translations + 3 u8 rotations); ported atlegaia_asset::player_anm::BoneTransformFUN_80024D78- actor object-table fill:actor[+0x44]=[count = *(tmd+8)][ptr to tmd+0xC+i*0x1C per object], straight off the pool TMDFUN_80024E80- screen-fade primitive spawn(fade_template, mode): allocates an actor from pool&DAT_80070674viaFUN_80020DE0, storesmodeatactor[+0x18]and loads the fade ramp viaFUN_80020B00(start RGB + frame count<< 6, per-frame deltas). The battle-action SM stages the summon backdrop fade (state0x33) and the successful-escape white-out (state0x66) through it. Portengine-core::fade::spawn_fade. Seeghidra/scripts/funcs/80024e80.txt.FUN_80043390- Per-prim renderer dispatcher insideFUN_8001ADA4case-5 (default textured-TMD path). Selects an emit leaf from one of two function-pointer tables (SCUS0x8007657Cvs world-map overlay0x801F8968) based on_DAT_1F800394 & 1- the overlay variant routes every prim through fog-enabled leaves at0x801F7644..0x801F8690. This is the bulk world-map continent emit path.FUN_8001ADA4- Per-actor RENDER dispatcher (switch onactor[+0x56]); case-5 walks the mesh chain atactor[+0x44]and dispatches each TMD toFUN_80043390(textured),FUN_80029888(env-mapped), orFUN_8002735C(landmark); case-0xBis the ocean CLUT-walk emitter (banksacc += DAT_1F800393, fires a 16×1MoveImageper kingdom-slot-5 table entry onacc >= hold, resets to zero)FUN_8001D140- Stack-swap wrapper aroundFUN_8001ADA4; called 6× per frame fromFUN_80016444against_DAT_8007C34C..0x36C(render pass)FUN_8002519C- Per-frame actor-list TICK iterator; called 5× per frame (distinct from the render pass)FUN_8002C69C- HUD / menu / dialog sprite-batch POLY_FT4 emitter (~120 prims/frame for world-map UI; not the continent)FUN_80026B4C- TMD validate + register. Storestmd_ptratDAT_8007C018[DAT_8007B774++]then callsFUN_800268DCfor the per-group descriptor fixup. Reached fromFUN_8001F05Ccase 2 (TMD-pack) and case 9 (TMD2).FUN_800268DC- TMD pointer fixup; builds the+0xCgroup descriptor array (0x1C-byte stride) consumed byFUN_80043390.FUN_801F69D8- World-map top-view tile-visibility dispatcher inoverlay_world_map_top_ext.bin(643 instr, 2572 B). Walks per-tile visibility scratchpad and emits TMDs fromDAT_8007C018viaFUN_80043390. In world-map warp-transition captures it is the live cluster-A caller (Drake read-breakpointra = 0x801F725C).FUN_801D8280-DAT_8007C018table walker (overlay-resident). Iterates entries0..DAT_8007BB38and for each pointed-to TMD callsFUN_801D5E20per sub-record.0x8007C018- global TMD pointer table; installer-counter at0x8007B774, walk-counter at0x8007BB38. See formats / world-map-overlay -DAT_8007C018.0x80010778- move-VM jump tableDAT_8007326C- per-mode primitive descriptor table0x801CE868- move-VM extension JT0x800EB654- battle context struct (pointed to by_DAT_8007BD24)
Battle
FUN_801E295C- battle action state machine (16 KB)FUN_801D0748- battle / level-up main tick; sub-states 0x1E/0x32/0x6E/0xFEFUN_801D388C- battle animation dispatcher; switch on animation_type (0..0x31+)FUN_801D5854- battle per-pose camera/presentation driver (never writes the anim-id fields; the anim system isFUN_80047430→FUN_8004AD80→FUN_8004998C)FUN_801D8DE8- HUD element renderer; switches onelem_id(80-entry table) to draw each on-screen element (HP bars, Spirit names, hand-card portraits, victory banner). Shared by the battle HUD and Muscle Dome.FUN_801DA6B4- battle actor display-state controller; opacity + pose flags for alive actorsFUN_801DB81C- next-valid-target scan;actor[+0x14C] != 0& no death/stoneFUN_801ED710- records / stats screen renderer: nine label-heading rows - battles + escapes (cap 99999), play time (H:MM:SS), six per-character stat categories iterating the record at0x80084140 + n*0x414(+0x6B4/+0x6B0,+0x660/+0x664,+0x74D/+0x704), and a final averages row over the0x801C6460countersFUN_800520F0- battle scene loader; sequential state machine that pulls thebefect_datacluster (etim texels, etmd effect models registered viaFUN_80026B4C, vdf, efect.dat) and the PROT 871 effect-model library intoDAT_8007C018[3..32]FUN_80020050- flame / effect-texture atlas loader (SCUS). Uploads PROT entry0x366(870 - the flame TIMs) into VRAM twice viaFUN_8001fc00(→FUN_8003e8a8, the PROT-index/TOC resolver); the VRAM region is set up byFUN_80017888/FUN_8001e54c(arg0xf000). Gated on_DAT_8007b868 == 0. This is the VRAM blit site for PROT 870 - it is not loaded by the battle-bundle pathFUN_800520F0(which pulls0x367..0x36d).FUN_80026B4C- TMD validate + register (asserts magic0x80000002); stores into the global TMD tableDAT_8007C018FUN_8004E2F0- battle range / line-of-sightFUN_80054CB0- monster initFUN_80042558- per-frame stat aggregatorFUN_8003FB10- action validatorFUN_800431D0- ability bitmask readFUN_8002CDD0/FUN_8002C2E4/FUN_8002C488- battle status-HUD panel / per-member row / icon sprite drawer (the SCUS on-screen-element cluster;FUN_8002C2E4pins the status-bitfield bit layout at char record+0x12E)- PROT
0967- battle sparring-tutorial overlay, co-resident at0x801F69D8during the Tetsu fight (overlapping overlay 0898's rodata tail); drives the how-to-fight tutorial prompts 0x801C9370- 8-actor pointer table (party 0–2, monsters 3–7); actor HP at+0x14C
Menu overlay
FUN_801DD35C- per-frame title-overlay tick / top-level menu dispatcher (12 KB, 3 026 instr). Decrements the attract countdown at0x801DDCCC(sw v0, -0xe94(a0)) by the per-frame scalar_DAT_1F800393;bgezbranches to0x801DFC3Cwhile still counting, underflow writes_DAT_8007B83C = 0x1A(= STR FMV mode 26) and zeroes_DAT_8007BA78→MV1.STR. Same fall-through as the field-VM0x4C 0xE2trigger atFUN_801E30E4. Pinned via PCSX-Redux watchpoint on the countdown; dump atghidra/scripts/funcs/overlay_title_801ddccc.txt.FUN_801D33D8- per-character status / party panel renderer (Status / Magic / Moves / Skills tabs). Draws one member's page into a caller-supplied window rect (WX=*(i16*)(a0+0xa),WY=*(i16*)(a0+0xc)); content only, frame is caller-drawn. Dispatched as window descriptor 28 of the window table at0x801E4738(rect(90,16,218,188)). Submenu idDAT_801e46c0 & 0xffffolded to 0..5; shared string / icon / number primitives; CLUT-staging globalDAT_8007b454read only by the string primitive. Pixel-pinned layout: field menu.- window descriptor table
0x801E4738(data, PROT 0899 file0x15F20) - 52 x 0x10-byte records[content_id][park_edge][class][x,y,w,h][renderer VA]: the rect + content-renderer dispatch behind every pause-menu window. Renderers by id: 50 =FUN_801CFD68(top-level command list), 49 =FUN_801D0148(money/play-time box), 51 =FUN_801D030C(top-level party panel), 26/21 =FUN_801D2094(party list), 27 =FUN_801D30A4("Condition" pager), 30 =FUN_801D31EC(summary), 22 =FUN_801D21C0(equip main), 48 =FUN_801DCEF0(options), 0..4 = title tabs. Live windows: 0x5C-stride linked structs, animated rect at+0xa(slide-out parking). Parserlegaia_asset::menu_windows; details: field menu. FUN_801E1C1C- shared menu-element rendererFUN_801CF650- equipment stat aggregator; reads 5 slots at char+0x196, sums intoDAT_801EF08C–09CFUN_801DD0C0- item category / slot validity check
Audio (PsyQ)
FUN_8001FA88- sound init / .dpk loaderFUN_8001FC00- streaming-asset loader (sound\)FUN_8001EBEC- equipment-conditional per-character TMD group patch (OBJECT 10/11 swap)FUN_800243F0- BGM lookup (PROT-relative)FUN_8003E104- monster.snd loader0x80061-0x80067- libsnd SsAPI sequencer clusterFUN_80068D94-SsVabOpenHeadcore: validates thepBAVVAB magic, builds the program-number → packed-tone-page rank map into the ProgAtr+8reserved words, allocates SPU memory, stashes per-VAG SPU addresses (the earlier "SsSepOpen/ 'VAP' loader" reading is corrected from the disassembly - see do not re-walk). Engine port:engine-audio::VabBank::upload0x80068-0x6D- libspu SPU control clusterFUN_80069B18- SPU DMA transfer state machine
World map
FUN_801E76D4- world-map controller (9320 B); top-view debug toggle + camera scroll/azimuth/zoomFUN_801EAD98- world-map developer menu renderer (7280 B); 24-entry scrollable list incl. MAP CHANGE / EVENT FLAG / PLAY POS / GET ITEM (display-only; the tools live in field overlay 0897). Row model + digit formatter ported atlegaia_engine_vm::world_map_overlay; draws stay render-sideFUN_801EE094/FUN_801EE328(0897) - dev-menu warp appliers ("ON RIREMITO," / "ON RULA,"): map-table walk on_DAT_80084628, scene load viafunc_0x8001fd44, player teleport - the MAP CHANGE half of the debug "jump to beat" behaviourFUN_801DBD04(0897) - dev-menu EVENT FLAG editor: cursorDAT_801f2aa0over flag ids0..0xFFF, SET/CLEAR appliers at0x801EA4F8/52C- the debug path that can set any story flag incl. the spine gates; also the register-pointer editor that produced the FMV trigger corpusFUN_801EF014(0897) - flag-window picker widget (descriptor via_DAT_8007B450, op-0x49-installed:+2= first visible row,+3= visible row count; confirm on a different row setsbase + selection, re-picking the remembered current row or cancelling sets nothing). Disc usage (man-scripts --op49-window-census, 209 sites): the ONLY genuine flag-window family is kor/kor3/kor4 sub-4base=0x138 count=8(24 sites) - the Uru Mais warp-pad destination memory; no window contains a spine flag.FUN_801F159C(0897) - system-actor dispatcher over the 52-entry handler tablePTR_FUN_801f33b4, indexed byactor+0x50FUN_801D2EBC(0897) - timed-flag scheduler consumer (installer = field-VM op0x4C 0xD3); retail use:chitei2escape timer, flag0x4C7FUN_801DA51C- per-entity tick (260 B); 5-state SM onentity[+0x8A]FUN_801CFC40- top-view sprite batcher (524 B, top-view only)FUN_80016444(SCUS, 1352 B) - per-frame render tick reached fromFUN_80025EEC(default per-mode handler) orFUN_80025F2C(Mode 13 MAPDSIP);jal 0x801D7EA0gated by_DAT_8007BC3C == 2FUN_801D7EA0- 832-byte POLY_FT4 batch emitter; one-shot gated by_DAT_801F351C; 224-iter cos-rotation loopFUN_801D8258- 40-byte gate setter;_DAT_801F351C = 1+ scale/step/OT-layer paramsFUN_801D1344(world_map overlay) +FUN_801C2B2C(0897 field overlay) - 1332-byte gate-arm wrapper (overlay relocation pair). Distinct from the dialog overlay'sFUN_801D1344(different code at the same RAM address).
BIOS + libapi
0x80056678-EnterCriticalSection0x80056688-ExitCriticalSection0x80056658-TestEvent0x8006B844-WaitEvent0x80057024-memmove0x8005ACAC-memset0x8005E540-memcpy0x80056698+stride 0x10 - BIOS B-vector thunk cluster
Full reference
Every function above (and ~50 more) is described in detail with provenance citations in the markdown doc:
Per-function dumps (Ghidra disassembly + decompile) live under ghidra/scripts/funcs/<addr>.txt in the repo (gitignored - Sony-derived). Overlay-specific dumps are prefixed overlay_<label>_<addr>.txt.