New-game starting-party table Confirmed
Where a brand-new game comes from: the starting party's stats and names live in a small static
table in SCUS_942.54 (the game's main executable on the disc) - four 26-byte rows, one each for
Vahn, Noa, Gala, and Terra - the later rows are the templates used as each character is introduced, since
only Vahn has joined at a true New Game. When the title
screen's NEW GAME row is confirmed, the boot chain (FUN_80025B64 →
FUN_801D6704; FUN_80xxxxxx names are Ghidra-traced functions) expands these rows
into the live per-character records at 0x80084708 + n×0x414. Two details worth knowing up
front: the starting inventory is not a table at all - Healing Leaf ×5 is hard-coded as
instructions (below) - and the level number the game displays is a stored byte, not
something recomputed from experience (below). The opening scene is
town01 (Rim Elm) - the executable's default map-name buffer at 0x8007050C holds the
literal "town01".
Table base + record layout
| Field | Value |
|---|---|
| Base address | 0x80078C4C (Vahn's record) |
| Stride | 26 bytes (8×u16 stats + 10-byte name) |
| Records | 4 - Vahn, Noa, Gala, Terra, in roster order |
+0 u16 hp_max (also the starting HP)
+2 u16 mp_max (also the starting MP)
+4 u16 agl (also seeds the spirit-gauge value + stat cap)
+6 u16 atk
+8 u16 udf (upper / physical defence)
+10 u16 ldf (lower / magical defence)
+12 u16 spd (turn-order initiative seed)
+14 u16 intel
+16 u8[10] display name, NUL-padded
| Slot | Name | HP | MP | AGL | ATK | uDEF | lDEF | SPD | INT |
|---|---|---|---|---|---|---|---|---|---|
| 0 | Vahn | 180 | 20 | 100 | 24 | 16 | 12 | 19 | 9 |
| 1 | Noa | 150 | 10 | 120 | 21 | 13 | 11 | 30 | 3 |
| 2 | Gala | 210 | 40 | 80 | 30 | 43 | 30 | 15 | 20 |
| 3 | Terra | 400 | 200 | 200 | 45 | 20 | 17 | 45 | 25 |
At a true New Game only Vahn has joined; the other rows are the templates the game uses as each character is introduced. The +4 stat fans out to several live fields at once - cross-validated against an early town01 save state, Vahn's 100 lands in the live record as agl, the stat-cap constant, and the initial spirit-gauge value.
Starting inventory (code-built, not a table)
The opening inventory is built in code by the new-game data-init FUN_80034A6C, writing a single slot into the live owned-item array at 0x80085958 (= SC save-context base 0x80084140 + 0x1818; 2 bytes/slot [id: u8][count: u8], id-0 terminator):
0x80034b0c addiu $v0, $zero, 0x77 ; item id = Healing Leaf
0x80034b10 sb $v0, 0x1818($s0) ; inventory[0].id ($s0 = SC base)
0x80034b14 addiu $v0, $zero, 5 ; count = 5
0x80034b18 sb $v0, 0x1819($s0) ; inventory[0].count
A vanilla New Game starts with Healing Leaf ×5 and nothing else. The array at +0x1818 is a single ordered (id, count) owned-item list shared by every item category - the inventory menu only filters it into Items / Goods / Key tabs by item id, so a seeded slot can hold any id regardless of category (the randomizer's starting-bag toggles use this same array). legaia_asset::new_game::StartingInventory decodes the region by replaying its $v0-source stores (addiu 0x2402 / sb 0xA202 / sh 0xA602 top-16 signatures) into an SC-offset → byte map, so it reads back either the vanilla byte pair or a randomizer-packed halfword store.
Starting level / XP seed
The seed routine FUN_800560B4 also initialises each live record's progression fields:
| Record offset | Field | Vanilla seed |
|---|---|---|
+0x0 (u32) | cumulative experience | 0 |
+0x4 (u32) | next-level XP threshold | reach(L2): Vahn/Terra 121, Noa 102, Gala 140 |
+0x130 (u8) | displayed character level (what "LV" shows; maintained +1 per level-up event) | 1 |
+0x131 (u8) | second per-character byte the seed inits (magic-rank candidate, unconfirmed) | 1 |
The shown level is read from +0x130 directly, not re-derived from experience - confirmed live: a record with level-10 experience + stats but +0x130 == 1 still shows LV 1. The per-character +0x4 thresholds differ because of the small FUN_801E9504 per-slot correction, not because the XP curve is per-character. The starting-level randomizer retargets this seed routine with same-size in-place edits (level byte party-wide, in-band experience + threshold for the growth-capable slots).
Parser + provenance
The table base + stride are pinned by byte-search of SCUS_942.54 for Vahn's stat run followed by the "Vahn" name, with every field cross-validated against the live per-character record at 0x80084708 lifted from an early town01 save state. legaia_asset::new_game::StartingParty parses the table from a SCUS_942.54 image at runtime (PSX-EXE t_addr → file-offset map), so the engine seeds a faithful New Game from the user's own disc without committing any Sony bytes. The disc-gated new_game_real test pins the four rows against the real executable. CLI: asset new-game <SCUS> [--json] (dumps the party template + the code-built starting inventory).