From 95909749bbc4d025db58d5e4cb563cf27b4930aa Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Tue, 11 Aug 2026 20:56:31 -0600 Subject: [PATCH] =?UTF-8?q?feat(phase-30=20S48-T6):=20recover=20all=2021?= =?UTF-8?q?=20"lost"=20wave-2=20drafts=20from=20the=20transcripts=20?= =?UTF-8?q?=E2=80=94=2017=20more=20banked?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drew's question ("can you just analyze the workflow results to get those drafts back?") was right, and my write-off was wrong. The drafts were never lost: every agent's tool calls are recorded in the run transcripts, content included. Recovery is deterministic and cost ~0 agent tokens. Method (all three passes were needed): 1. Write records -> 20 of 21 had one. Naive extraction gated only 8/21, because agents REFINE with Edit and I was treating each edit's new_string as a whole file. 2. Replay Write-then-Edit in order per (agent, file_path), snapshotting after every mutation, then gate every snapshot newest-first -> 20/21 MATCH. 3. The last one (func_8017DF40) never used Write/Edit — it wrote via a shell heredoc. Extracted the heredoc bodies from the bash tool calls -> MATCH. Whole-binary gate on the 21: 17 BANKED, 4 NEAR. md_SC03_073 func_801EFC94 x8 <- a MODULE exemplar, through the path fixed earlier today (commit:1626) ov_SC03_014 func_8017C154 x7 func_8017C6A0 x7 func_8017D1E0 x7 ov_SC03_118 func_80187180 x8 func_80187B80 x8 ov_SC06_018 func_80185C2C func_8018DE60 func_801850F4 func_801857CC func_801880C4 func_80185DD8 (all x6) ov_MAIN_012 func_8017DD28 x5 · ov_SC02_026 func_801814D8 x6 ov_SC03_093 func_8018171C x5 · ov_SC03_107 func_8017EB70 x5 ov_SC06_008 func_80180000 x8 NEAR at the binary gate: func_8017DF40, func_8017EEEC, func_80187960, func_8018A974 — the §52b population (per-function MATCH, binary gate refuses). Wave 2 now stands at 22 of 28 banked (79%) vs wave 1's 8 of 12 (67%), with 20 of 28 drafted by Sonnet. --- src/md_SC03_073/md_SC03_073.c | 49 ++- src/ov_MAIN_012/ov_MAIN_012_jr_8017CF3C.c | 130 +++++++- src/ov_SC02_026/ov_SC02_026_jr_8017C180.c | 61 +++- src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c | 254 +++++++++++++++- src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c | 2 +- src/ov_SC03_014/ov_SC03_014_jr_80184440.c | 2 +- src/ov_SC03_014/ov_SC03_014_jr_801848E4.c | 2 +- src/ov_SC03_014/ov_SC03_014_o0c.c | 2 +- src/ov_SC03_014/ov_SC03_014_o0d.c | 2 +- src/ov_SC03_093/ov_SC03_093_jr_8017D898.c | 47 ++- src/ov_SC03_107/ov_SC03_107_jr_801789AC.c | 128 +++++++- src/ov_SC03_118/ov_SC03_118_jr_801863CC.c | 121 +++++++- src/ov_SC06_008/ov_SC06_008_jr_8017C294.c | 59 +++- src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c | 351 +++++++++++++++++++++- src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c | 157 +++++++++- 15 files changed, 1344 insertions(+), 23 deletions(-) diff --git a/src/md_SC03_073/md_SC03_073.c b/src/md_SC03_073/md_SC03_073.c index 35e766c88..c1ffa3a89 100644 --- a/src/md_SC03_073/md_SC03_073.c +++ b/src/md_SC03_073/md_SC03_073.c @@ -273,7 +273,54 @@ void func_801EFBF4(s32 a0) { } -INCLUDE_ASM("asm/md_SC03_073/nonmatchings/md_SC03_073", func_801EFC94); +#include "common.h" + +extern s32 func_801789AC(s32 arg0); +extern void func_80188F20(s32 a0); +extern void func_80178CBC(s32 a0, s32 a1); +extern void func_80174438(s32 a0); +extern u8 *D_80126B10; + +void func_801EFC94(void *a0) { + + extern s32 D_801EFFF8; + extern s32 D_801F0010; + extern s32 D_801EFF94; + + switch (*(u16 *)((s32)a0 + 0x34)) { + case 0: { + s32 v0 = func_801789AC((s32)a0); + switch (v0) { + case 1: + *(u16 *)((s32)a0 + 0x34) = 2; + func_80188F20(3); + break; + case 2: + func_80178CBC((s32)a0, (s32)&D_801EFFF8); + *(u16 *)((s32)a0 + 0x34) = 0; + break; + case 3: + func_80178CBC((s32)a0, (s32)&D_801F0010); + *(u16 *)((s32)a0 + 0x34) = 3; + break; + } + break; + } + case 1: + break; + case 2: + func_80178CBC((s32)a0, (s32)&D_801EFF94); + *(u16 *)((s32)a0 + 0x34) = 0; + break; + case 3: + if (func_801789AC((s32)a0) != 0) { + func_80174438((s32)D_80126B10); + *(u16 *)((s32)a0 + 0x34) = 1; + } + break; + } +} + extern void func_8012C1B8(void); extern void func_8012CAE4(void *a0); diff --git a/src/ov_MAIN_012/ov_MAIN_012_jr_8017CF3C.c b/src/ov_MAIN_012/ov_MAIN_012_jr_8017CF3C.c index 3a825f6c5..8a9eb5276 100644 --- a/src/ov_MAIN_012/ov_MAIN_012_jr_8017CF3C.c +++ b/src/ov_MAIN_012/ov_MAIN_012_jr_8017CF3C.c @@ -4225,7 +4225,135 @@ u32 func_8017DC48(s32 a0, s32 a1) { INCLUDE_ASM("asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_8017CF3C", func_8017DCB0); -INCLUDE_ASM("asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_8017CF3C", func_8017DD28); +#include "common.h" + +/* func_8017DD28 @ 0x8017DD28 — ov_MAIN_012 / jr_8017CF3C, 124 ins, frame 0x30. + * Family exemplar (reach x5, zero prior cracks). + * + * WHAT IT DOES. Fills one 0x14-byte SPRT (tag 0x04000000, rgb/code 0x64808080, + * u0/v0 = 0x70/0x10, clut 0x4056, w/h = 0x10/0x10) whose x/y come from the + * current HUD panel's Prim4 (D_80115134[D_8011511A].f18), offset by a table + * value when D_8011512C == 1. Links it into the OT with the psyq addPrim + * idiom, advances past it, has func_8005A600 (SetDrawTPage-shaped, 2 words) + * write the next primitive, links THAT one too, and returns the write cursor. + * + * STEP-0 SIBLING (cookbook §160g) — the whole prim fill + the PTag bitfield + * addPrim were copy-edited from the already-banked, SAME-OVERLAY + * src/ov_MAIN_012/ov_MAIN_012_jr_8013F350.c:1746 func_80140D68 + * which has the identical 0x04000000 / 0x70 / 0x10 / 0x64808080 / 0x4056 / + * 0x10 / 0x10 store sequence and the identical + * ((PTag *)out)->addr = ((PTag *)(D_800AE7BC[*pb].ot + 2))->addr; + * ((PTag *)(D_800AE7BC[*pb].ot + 2))->addr = (u32)out; + * pair. Only the 24-bit-bitfield spelling emits exactly two `and`s per half. + * + * THE THREE LEVERS (each byte-measured with tools/match_one.py): + * + * [L1] `out += 5;` IN PLACE, never `p = out + 5;`. A second pointer local is + * a 5th callee-saved allocno: frame stays 0x30 but the target's four + * ($s0..$s3) become five ($s0..$s4) and every save/restore shifts. + * 125 ins / 115 mismatched -> 123 / 33. + * + * [L2] `d = n - 0x60;` INTO ITS OWN LOCAL, then `q->f0 + d`. Writing the + * obvious `q->f0 + (n - 0x60)` lets fold reassociate the constant onto + * the OTHER addend — `addiu $v0,$v0,-0x60` on the lhu result — and + * writing `n -= 0x60;` makes it a single pseudo, so the subtract is + * in-place (`addiu $a0,$a0,-0x60`) and floats up ~10 slots because its + * destination is free early. Only a distinct, single-set pseudo gives + * the target's `addiu $v1,$a0,-0x60`, which cannot be scheduled before + * `sw $v1,0x4($s3)` frees $v1 — and that one anchor pins the whole + * lui/ori/li/move ordering of the fill block. 26 mismatched -> 16. + * + * [L3] The LAST addPrim write-half must keep its loaded word in $v0 through + * the `or`, so the return value `addiu $v0,$s3,0x8` cannot be scheduled + * into the load-delay slot. With the plain bitfield spelling gcc puts + * that word in $v1/$a0, $v0 falls free, sched2 hoists the return insn + * into the slot, and the target's `nop` after `lw $v1,%lo(D_800AE7BC)` + * disappears — a LENGTH-DRIFT of exactly -1 that no amount of statement + * reordering fixes. `register u32 v __asm__("$2")`, REUSED for the + * or-result, is the only lever that holds it. 16 mismatched -> MATCH. + * (Ablated: pinning `op` to $3 and `pb` to $18 are NOT needed once [L3] + * is in; both were removed and the gate still reads MATCH.) + * + * §94 TYPE-CARRY: every typedef here is BLOCK-scope on purpose — extract_unit + * carries file-scope externs but drops file-scope typedefs, so the four + * mechanical siblings would sweep 0/4 if these lived at file scope. + */ + +s32 *func_8017DD28(s32 *out) { + typedef struct { u32 addr : 24; u32 len : 8; } PTag_8017DD28; + typedef struct { u32 *ot; u32 pad[4]; } Env_8017DD28; /* 0x14 stride */ + typedef struct { u16 f0; u16 f2; } Prim4_8017DD28; + typedef struct { + s16 f0; /* 0x00 */ + s16 f2; /* 0x02 */ + void *f4; /* 0x04 */ + void *f8; /* 0x08 */ + s16 fC; /* 0x0C */ + s16 fE; /* 0x0E */ + s16 f10; /* 0x10 */ + s16 f12; /* 0x12 */ + void *f14; /* 0x14 */ + Prim4_8017DD28 *f18; /* 0x18 */ + void *f1C; /* 0x1C */ + } Panel_8017DD28; /* 0x20 stride */ + + extern Env_8017DD28 D_800AE7BC[]; + extern short D_800B9A02; + extern Panel_8017DD28 *D_80115134; + extern u16 D_8011511A; + extern s16 D_8011512C; + extern u16 D_80115116; + extern u16 D_80182798[]; + extern s32 func_8005A600(s32, s32, s32, s32, s32); + + Prim4_8017DD28 *q; + volatile u16 *pb; + s32 n; + s32 d; + + /* `lh` on a u16-declared symbol: the address cast, not a second decl — + the TU already fixes D_8011511A as u16 at file scope. */ + q = D_80115134[*(s16 *)&D_8011511A].f18; + if (D_8011512C == 1) { + n = D_80182798[D_80115116 & 7]; + } else { + n = 0; + } + + out[0] = 0x04000000; + *((u8 *)out + 0xC) = 0x70; + *((u8 *)out + 0xD) = 0x10; + out[1] = 0x64808080; + pb = (volatile u16 *)&D_800B9A02; + *(u16 *)((u8 *)out + 0xE) = 0x4056; + + d = n - 0x60; /* [L2] */ + *(s16 *)((u8 *)out + 0x8) = q->f0 + d; + *(s16 *)((u8 *)out + 0xA) = q->f2 - 2; + *(s16 *)((u8 *)out + 0x12) = 0x10; + *(s16 *)((u8 *)out + 0x10) = 0x10; + + ((PTag_8017DD28 *)out)->addr = + ((PTag_8017DD28 *)(D_800AE7BC[*pb].ot + 2))->addr; + ((PTag_8017DD28 *)(D_800AE7BC[*pb].ot + 2))->addr = (u32)out; + + out += 5; /* [L1] */ + func_8005A600((s32)out, 0, 0, 0x15, 0); + + ((PTag_8017DD28 *)out)->addr = + ((PTag_8017DD28 *)(D_800AE7BC[*pb].ot + 2))->addr; + { + u32 *op; + register u32 v __asm__("$2"); /* [L3] */ + op = D_800AE7BC[*pb].ot; + v = op[2]; + v = (v & 0xFF000000) | (((u32)out) & 0xFFFFFF); + op[2] = v; + } + + return out + 2; +} + INCLUDE_ASM("asm/ov_MAIN_012/nonmatchings/ov_MAIN_012_jr_8017CF3C", func_8017DF18); diff --git a/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c b/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c index 63d850179..93d500785 100644 --- a/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c +++ b/src/ov_SC02_026/ov_SC02_026_jr_8017C180.c @@ -4558,7 +4558,66 @@ void func_80181374(s32 a0) { INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_8018144C); -INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_801814D8); + + + + + + + +extern s32 func_80182550(void); +extern void func_8012CAE4(void *a0); +extern s32 func_8012C354(s32 a0, s32 a1); +extern void func_8012E8A8(u8 *a0); +extern void func_8012B2CC(s32 a0); +extern s32 rand(void); + +extern u8 D_801AC1D0[]; +extern u8 D_801AC270[]; + +void func_801814D8(s32 a0) { + s16 state; + s16 flag; + s32 p; + s32 dst; + + if ((*(u16 *)(a0 + 0x70) & 0xF) == 0 && func_80182550() == 0) { + func_8012CAE4((void *)a0); + return; + } + + state = *(u16 *)(a0 + 0x70) & 0xF; + if (func_8012C354(a0, (s32)(D_801AC1D0 + state * 0x34)) == 0) { + return; + } + + *(u8 *)(a0 + 0xC0) = 1; + *(s32 *)(a0 + 0xBC) = (s32)D_801AC270; + *(s32 *)(a0 + 0xB4) = -2; + *(s32 *)(a0 + 0xC4) |= 1; + *(s16 *)(a0 + 0xFE) = (rand() % 16) + 8; + + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x2C) |= 0x10; + + flag = *(s16 *)(a0 + 0x70); + if ((flag & 0x8000) == 0) { + if ((flag & 0x800) != 0) { + *(s16 *)(a0 + 0x2) = 5; + func_8012E8A8((u8 *)a0); + } else { + *(s16 *)(a0 + 0x2) = 1; + } + } else { + p = *(s32 *)(a0 + 0x64); + *(s16 *)(a0 + 0x2) = 3; + *(s16 *)(a0 + 0x5C) = 0; + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) = *(u16 *)(*(s32 *)(p + 0x20) + 0x12); + dst = *(s32 *)(a0 + 0x20); + *(s16 *)(dst + 0x18) = *(s16 *)(dst + 0x1A) = *(s16 *)(dst + 0x1C) = 1; + func_8012B2CC(a0); + } +} + INCLUDE_ASM("asm/ov_SC02_026/nonmatchings/ov_SC02_026_jr_8017C180", func_80181644); diff --git a/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c b/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c index 0b5f94396..f15328948 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c @@ -3384,7 +3384,7 @@ void func_8017C0C8(void *a0) { INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C104); -extern void func_8017C154(void); +extern void func_8017C154(); void func_8017C12C(void) { func_8017C154(); } @@ -3392,7 +3392,39 @@ extern void func_8017C154(void); DEFINE_func_8017C14C() /* dedup: shared engine-core @0x8017C14C (src/shared) */ -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C154); + + +extern void func_80015978(s32 a0, s32 *a1); +extern void func_8017C290(int a, s16 *b, SVECTOR_8017C290 *c, SVECTOR_8017C290 *d, + SVECTOR_8017C290 *e, SVECTOR_8017C290 *f, s16 *g); +extern SVECTOR_8017C290 D_8018F038[4]; + +void func_8017C154(void *a0) +{ + s16 buf20[4]; + SVECTOR_8017C290 c; + SVECTOR_8017C290 d; + SVECTOR_8017C290 e; + SVECTOR_8017C290 f; + s32 i, j; + + *(s16 *)((u8 *)a0 + 0x10) = *(s32 *)((u8 *)a0 + 0x30); + func_80015978((s32)a0 + 4, (s32 *)buf20); + + for (j = 0; j < 4; j++) { + c.vx = 0; + c.vy = 0; + c.vz = 0; + d = c; + e = c; + for (i = 0; i < 4; i++) { + f = D_8018F038[i]; + *(s16 *)((u8 *)a0 + 0x12) = i + j; + func_8017C290((int)a0, buf20, &c, &d, &e, &f, (s16 *)((u8 *)a0 + 0x10)); + } + } +} + // @class: regalloc-order // @stuck: none — §136c SIBLING-FIRST. Near-twin = banked func_8017E830 in @@ -3540,7 +3572,115 @@ void func_8017C664(void *a0) { } -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C6A0); +#include "common.h" + +/* MATCH (match_one, 93/93). ov_SC03_014_jr_8017AE2C, family reach x7 (zero-crack exemplar; see + * asm/ov_SC03_0{14,15,24,118,119}/... and ov_SC06_000, all still INCLUDE_ASM as of this crack). + * + * sibling-search (cookbook §160g) hits, all from src/ov_SC03_014/ov_SC03_014_jr_8017AE2C.c + * (the destination TU itself) plus one cross-overlay MATCHed twin: + * - func_8017CE10(void *a0, s32 a1, s32 a2) -- defined verbatim in THIS TU (line 3679) + * - func_80147324(D_8018EFC0[idx][0]) -- exact idiom of func_8017C8FC's + * func_80147324(D_8018EFD4[idx][0]) (same TU) + * - func_8001CB00(s32,void*,s32,s32) -- signature + literal 0x280/0x100 pair pinned + * by src/ov_SC03_007/ov_SC03_007_jr_8017AE2C.c:5317 func_80186BE8 (labeled MATCH), whose tail + * `*(short*)(param_1+2) += 1;` is the exact idiom of this function's own final statement. + * - func_8012A68C()/func_8012A758()/func_8004978C()/ApplyMatrixSV() call trio -- exact shape of + * shared-engine func_80146F58 (src/ov_SC07_007/ov_SC07_007_jr_801457A4.c:1459): two s16 calls + * stored, func_8004978C(anglesPtr, matOut), ApplyMatrixSV(mat, in, out). + * - func_801465C0 loose void(void) file-scope decl (TU:130) fought via a cast-at-callsite, + * per §161c -- mirrors src/ov_SC06_008/ov_SC06_008_jr_8016AB6C.c's + * `((s32 (*)(void))func_801465C0)()` pattern. No explicit a0 setup precedes the target's jal + * (a0 still holds the entry parameter unclobbered) so a ZERO-ARG cast is the byte-safe choice + * -- it can never force a spurious argument-setup instruction. + * + * PROCESS NOTE (worth banking in the cookbook): a 2-instruction "REGALLOC-LOCAL" residual on + * func_80015954's args looked exactly like local-alloc's optimize_reg_copy_1 collapsing two + * identical-valued arg copies (byte-verified via `cc1 -da`: `.sched` had insn112/114 both reading + * pseudo 80 cleanly, `.lreg` had insn114 rewritten to read insn112's DEST instead of pseudo80's + * hard reg -- textbook §162j1). The `register s32 zr __asm__("$0"); x + zr` opaque-copy lever + * (§136d-1/RC-12) did NOT defeat it when applied to the SECOND of the pair (validate_replace_rtx + * substitutes inside a PLUS operand just as readily as inside a plain SET) -- applying it to the + * FIRST copy instead (so insn117 is no longer a `single_set(REG)` and never qualifies as "a copy" + * for the pass to scan forward from) did defeat it, dropping to a genuine 1-instruction + * REGALLOC-PERM ($s3-vs-$s0). That flushed out the REAL bug: `func_80015954`'s first argument is + * `vecOut` (the ApplyMatrixSV output), not `s3` -- I had the wrong VALUE, not a regalloc quirk. + * Fixing the argument made the "residual" vanish with NO register-pin needed at all. Lesson: a + * clean REGALLOC-LOCAL/-PERM diff on an ARGUMENT SETUP is worth re-deriving the argument's + * identity from the target's OWN register (here $s0, not the more "obvious" $s3) before reaching + * for §162j1/RC-12 levers -- they can mask a semantic error long enough to look load-bearing. + */ + +extern void func_801465C0(void); +extern void func_80149374(s32 a0, s32 a1); +extern s16 func_8012A68C(void); +extern s16 func_8012A758(void); +extern void func_8004978C(s16 *a0, void *a1); +extern void ApplyMatrixSV(void *a0, void *a1, void *a2); +extern void func_80015978(s32 a0, s32 *a1); +extern void func_8012EF70(s32 a0, s32 a1); +extern void func_80015954(s32 a0, s32 a1); +extern void func_8001CB00(s32 a0, void *a1, s32 a2, s32 a3); +extern void func_8017CE10(void *a0, s32 a1, s32 a2); +extern void func_80147324(s32 a0); +extern void func_80146C3C(void); + +/* new-to-this-TU data symbols (own address only in this function; payload owned by + * asm/ov_SC03_014/data/tail.data.s, a data-only splat unit -- extern is correct, not a definition, + * per §160c's "same .s as the function" test). D_8018F07C bytes: 0000 0000 ECFF 0000 = {0,0,-20,0}. + * D_8018F058: 12 opaque bytes (a GPU-primitive template), address-only use -> §160f array style. */ +extern s16 D_8018F07C[4]; +extern u8 D_8018F058[12]; +extern u16 D_8018EFC0[][2]; + +void func_8017C6A0(void *a0) { + void *s3; + s32 s0; + s32 s1; + u8 mat[0x20]; + u16 vecOut[4]; + + s0 = *(s32 *)(a0 + 0x34); + s3 = ((void *(*)(void))func_801465C0)(); + *(void **)(a0 + 0x20) = s3; + + if (s3 != NULL) { + s1 = (s32)a0 + 4; + func_80149374(s0, s1); + + *(s16 *)(s3 + 0x10) = func_8012A68C(); + *(s16 *)(s3 + 0x12) = func_8012A758(); + func_8004978C((s16 *)(s3 + 0x10), mat); + + ApplyMatrixSV(mat, D_8018F07C, vecOut); + + *(u16 *)(a0 + 0x6) = *(u16 *)(a0 + 0x6) + vecOut[0]; + *(u16 *)(a0 + 0xA) = *(u16 *)(a0 + 0xA) + vecOut[1]; + *(u16 *)(a0 + 0xE) = *(u16 *)(a0 + 0xE) + vecOut[2]; + + func_80015978(s1, (s32 *)vecOut); + func_8012EF70((s32)vecOut, (s32)vecOut); + func_80015954((s32)vecOut, s1); + + func_8001CB00((s32)s3, D_8018F058, 0x280, 0x100); + + *(u8 *)(s3 + 0x27) = 0x80; + + *(s16 *)(s3 + 0x2C) = *(u16 *)(a0 + 0xE); + *(s16 *)(s3 + 0x1A) = 0; + *(s16 *)(s3 + 0x18) = 0; + + *(s32 *)(a0 + 0x10) = 0; + func_8017CE10(a0, *(s32 *)(a0 + 0x2C), 0x8F); + + func_80147324(D_8018EFC0[*(s32 *)(a0 + 0x2C)][0]); + + *(u16 *)(a0 + 2) = *(u16 *)(a0 + 2) + 1; + } else { + ((void (*)(s32))func_80146C3C)((s32)a0); + } +} + INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017C814); @@ -3718,7 +3858,113 @@ INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017D11 INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017D194); -INCLUDE_ASM("asm/ov_SC03_014/nonmatchings/ov_SC03_014_jr_8017AE2C", func_8017D1E0); +/* func_8017D1E0 -- ov_SC03_014, TU ov_SC03_014_jr_8017AE2C.c + * + * §160g sibling-first: this TU's own func_8017D318 (defined a few lines below this + * function's INCLUDE_ASM site, same file) is func_8017D1E0's ONLY non-engine callee -- + * it fixes the SVECTOR_8017C290 {u16 vx,vy,vz,pad;} type and func_8017D318's exact + * signature `(int a0, SVECTOR_8017C290 *a1, SVECTOR_8017C290 *a2, s32 a3)` for free. + * The two locals `vec1`/`vec2` are that call's a1/a2: each stack SVECTOR gets vx=0, + * vy=the just-clamped position field, vz=1 (a constant -- see below). + * + * D_8018EFFC: same TU's func_8017C8FC has the identical idiom one page up -- + * `idx = *(s32*)(a0+0x2C); func_80147324(D_8018EFD4[idx][0]);` against + * `extern u16 D_8018EFD4[][2];` at the SAME struct field offset (0x2C). D_8018EFFC + * sits 0x28 bytes after D_8018EFD4 in this overlay's rodata and is read with the + * identical `sll 2 / lhu [idx][0]` shape, so it is typed `u16[][2]` the same way. + * NOT independently verified against a byte dump of the table itself -- flag this + * decl for a second look if D_8018EFFC ever gets its own definition banked. + * (D_8018EFFC also exists as a DIFFERENT symbol -- a fn-ptr table -- in the + * unrelated overlay ov_SC03_001; overlays never share a TU, so no collision.) + * + * @class: regalloc-split (two REGISTER PINS, both load-bearing, neither a §17 tie) + * `t = field0x30 + 0x6000` feeds an accumulate BEFORE the func_80146E98 call and a + * second accumulate AFTER it. A plain `s32 t` (or even a `tmp`/`t` two-variable + * split) gets folded by cse/local-alloc into ONE pseudo living in $s1 for its WHOLE + * life -- the definition itself targets $s1 directly, with NO copy. The target, + * however, computes into $a0 first (its natural scratch there) and only copies into + * $s1 in the FIRST clamp branch's delay slot -- i.e. genuinely TWO pseudos joined by + * a real `addu $s1,$a0,$zero` that must survive both cse's copy-propagation AND local + * scheduling picking it (not the clamp's own field store) to fill that delay slot. + * FIX: `register s32 tmp __asm__("$4"); register s32 t __asm__("$17");` -- pinning + * BOTH ends to their target hard registers stops cse from unifying them (neither + * register can be "renamed away") and gives the scheduler exactly the copy the + * target has, in the position the target has it. An UNPINNED two-variable split + * (`t = tmp;`) is not enough by itself: cse/copy-prop still eliminates it. Reusing + * `tmp` a second time for the clamp subtraction ALSO defeats the copy-elimination + * (a real redefinition blocks the fold) but then clobbers $a0's `t` value TOO EARLY + * (before the branch), forcing the copy to schedule immediately instead of into the + * delay slot (76/78 ins, LENGTH-DRIFT). The double-pin is the only variant tried + * that reproduces both the register split AND its exact scheduling position. + * @stuck: none -- MATCH (match_one), first iteration after the double-pin. + * + * INTEGRATION NOTE (§161c-style): the SVECTOR_8017C290 typedef below is here ONLY so + * this file compiles STANDALONE for match_one. The real host TU already provides it + * at file scope ahead of func_8017C290 (~L3420, per that function's own "provided by + * the TU (§100)" comments) -- when banking, DROP this typedef and rely on the TU's + * existing one; do not leave a duplicate at the integration point. + */ +#include "common.h" + + + +extern s32 func_80146E98(s32 a0); +extern void func_80147324(s32 arg0); +extern void func_80146C3C(void); +extern void func_8017D318(int a0, SVECTOR_8017C290 *a1, SVECTOR_8017C290 *a2, s32 a3); +extern u16 D_8018EFFC[][2]; + +void func_8017D1E0(void *a0) +{ + s16 n; + register s32 tmp __asm__("$4"); + register s32 t __asm__("$17"); + s16 v; + SVECTOR_8017C290 vec1; + SVECTOR_8017C290 vec2; + + n = *(s16 *)((s32)a0 + 0x28); + if (n != 0) { + n = n - 1; + *(s16 *)((s32)a0 + 0x28) = n; + if (n == 0) { + func_80147324(D_8018EFFC[*(s32 *)((s32)a0 + 0x2C)][0]); + } + } + + tmp = *(s32 *)((s32)a0 + 0x30) + 0x6000; + *(s32 *)((s32)a0 + 0x14) += tmp; + t = tmp; + + v = *(u16 *)((s32)a0 + 0x10) - *(u16 *)((s32)a0 + 0x16); + *(s16 *)((s32)a0 + 0x10) = v; + if (v < 0) { + *(s16 *)((s32)a0 + 0x10) = 0; + } + + if (func_80146E98((s32)a0)) { + *(s32 *)((s32)a0 + 0x18) += t; + + v = *(u16 *)((s32)a0 + 0x12) - *(u16 *)((s32)a0 + 0x1A); + *(s16 *)((s32)a0 + 0x12) = v; + if (v < 0) { + *(s16 *)((s32)a0 + 0x12) = 0; + } + } + + vec1.vx = 0; + vec1.vy = *(u16 *)((s32)a0 + 0x10); + vec1.vz = 1; + vec2.vx = 0; + vec2.vy = *(u16 *)((s32)a0 + 0x12); + vec2.vz = 1; + func_8017D318((int)a0, &vec1, &vec2, *(s16 *)((s32)a0 + 0x24)); + + if (*(s32 *)((s32)a0 + 0x10) == 0) { + ((void (*)(s32))func_80146C3C)((s32)a0); + } +} + /* func_8017D318 -- ov_SC03_014, TU ov_SC03_014_jr_8017AE2C.c * diff --git a/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c b/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c index ed73d55f0..a905866b0 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_8017EB7C.c @@ -2661,7 +2661,7 @@ extern void func_8017BFC8(void *a0); extern void func_8017C07C(void); extern void (*D_8018F024[])(void); extern void func_8017C0C8(void *a0); -extern void func_8017C154(void); +extern void func_8017C154(); extern void func_8017C12C(void); extern void func_8017C14C(void); extern void (*D_8018F064[])(void); diff --git a/src/ov_SC03_014/ov_SC03_014_jr_80184440.c b/src/ov_SC03_014/ov_SC03_014_jr_80184440.c index 8fc208bad..976a90041 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_80184440.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_80184440.c @@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0); extern void func_8017C07C(void); extern void (*D_8018F024[])(void); extern void func_8017C0C8(void *a0); -extern void func_8017C154(void); +extern void func_8017C154(); extern void func_8017C12C(void); extern void func_8017C14C(void); extern void (*D_8018F064[])(void); diff --git a/src/ov_SC03_014/ov_SC03_014_jr_801848E4.c b/src/ov_SC03_014/ov_SC03_014_jr_801848E4.c index dac928897..48a82d0c5 100644 --- a/src/ov_SC03_014/ov_SC03_014_jr_801848E4.c +++ b/src/ov_SC03_014/ov_SC03_014_jr_801848E4.c @@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0); extern void func_8017C07C(void); extern void (*D_8018F024[])(void); extern void func_8017C0C8(void *a0); -extern void func_8017C154(void); +extern void func_8017C154(); extern void func_8017C12C(void); extern void func_8017C14C(void); extern void (*D_8018F064[])(void); diff --git a/src/ov_SC03_014/ov_SC03_014_o0c.c b/src/ov_SC03_014/ov_SC03_014_o0c.c index da5917a1e..4a99d26f5 100644 --- a/src/ov_SC03_014/ov_SC03_014_o0c.c +++ b/src/ov_SC03_014/ov_SC03_014_o0c.c @@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0); extern void func_8017C07C(void); extern void (*D_8018F024[])(void); extern void func_8017C0C8(void *a0); -extern void func_8017C154(void); +extern void func_8017C154(); extern void func_8017C12C(void); extern void func_8017C14C(void); extern void (*D_8018F064[])(void); diff --git a/src/ov_SC03_014/ov_SC03_014_o0d.c b/src/ov_SC03_014/ov_SC03_014_o0d.c index 3edaa1194..c5a231e52 100644 --- a/src/ov_SC03_014/ov_SC03_014_o0d.c +++ b/src/ov_SC03_014/ov_SC03_014_o0d.c @@ -2664,7 +2664,7 @@ extern void func_8017BFC8(void *a0); extern void func_8017C07C(void); extern void (*D_8018F024[])(void); extern void func_8017C0C8(void *a0); -extern void func_8017C154(void); +extern void func_8017C154(); extern void func_8017C12C(void); extern void func_8017C14C(void); extern void (*D_8018F064[])(void); diff --git a/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c b/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c index fcd30155a..8ef713fd9 100644 --- a/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c +++ b/src/ov_SC03_093/ov_SC03_093_jr_8017D898.c @@ -4607,7 +4607,52 @@ INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8018164 INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_801816C8); -INCLUDE_ASM("asm/ov_SC03_093/nonmatchings/ov_SC03_093_jr_8017D898", func_8018171C); +#include "common.h" + +extern s32 func_8004787C(s32 a0); +extern s32 func_8014CB0C(void); +extern s32 rand(void); +extern void func_80181F88(s32 a0, s32 a1); +extern void func_8012CBF4(s32 a0); +extern void func_80182288(s16 *a0, s32 a1); +extern void func_80181ED4(s32 a0); + +void func_8018171C(s32 a0) { + s16 sp10[3]; + s32 pad[2]; + + if ((*(u16 *)(a0 + 0x70) & 1) == 0) { + *(s16 *)(a0 + 0x52) = (u32)func_8004787C(*(s32 *)(a0 + 0x1C) << 5) >> 8; + if (*(s32 *)(a0 + 0x1C) == (*(s32 *)(a0 + 0x1C) / 24) * 24) { + sp10[0] = *(u16 *)(*(s32 *)(a0 + 0x20) + 0x8); + sp10[1] = *(u16 *)(*(s32 *)(a0 + 0x20) + 0xA) + 0x40; + sp10[2] = *(u16 *)(*(s32 *)(a0 + 0x20) + 0xC); + func_80182288(sp10, 0x60); + } + } else { + if (*(u8 *)(a0 + 0x1C) == 0) { + s32 r = rand(); + *(s32 *)(a0 + 0xE8) = (r % 64) + 0x40; + } + if (func_8014CB0C() == 0) { + func_80181F88(a0, 0xFFFD8000); + func_8012CBF4(a0); + *(u16 *)(a0 + 0xA) = *(u16 *)(a0 + 0x8A); + } + if (*(s32 *)(a0 + 0x1C) == (*(s32 *)(a0 + 0x1C) / 24) * 24) { + sp10[0] = *(u16 *)(a0 + 0x6); + sp10[1] = *(u16 *)(a0 + 0xA); + sp10[2] = *(u16 *)(a0 + 0xE); + sp10[1] = sp10[1] + 0x38; + func_80182288(sp10, 0x80); + } + } + func_80181ED4(a0); + *(s16 *)(*(s32 *)(a0 + 0x20) + 0x1A) = + 0x2000 - (func_8004787C((*(s32 *)(a0 + 0x1C) << 5) & 0x7E0) >> 1); + *(s32 *)(a0 + 0x1C) = *(s32 *)(a0 + 0x1C) + 1; +} + #include "common.h" diff --git a/src/ov_SC03_107/ov_SC03_107_jr_801789AC.c b/src/ov_SC03_107/ov_SC03_107_jr_801789AC.c index 9fe5dec90..3f6f3d5c2 100644 --- a/src/ov_SC03_107/ov_SC03_107_jr_801789AC.c +++ b/src/ov_SC03_107/ov_SC03_107_jr_801789AC.c @@ -6449,7 +6449,133 @@ extern s32 rand(void); INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_801789AC", func_8017EB04); -INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_801789AC", func_8017EB70); +/* func_8017EB70 (ov_SC03_107 / jr_801789AC) — 127 ins, match_one MATCH. + * + * "Chase/push-away" AI tick: read the actor's state word, bail on states 2 / 0x1A, + * clamp two fields, then walk the 0x60-entry entity table at D_801202A0 (stride + * 0x10C) looking for a nearby live neighbour and try to step this actor to a point + * 0x61 units away from it (func_8012CEB0 is the collision/move probe). + * + * Provenance (cookbook §160g sibling search): the INNER half is the already-banked + * func_8017E404 in src/ov_SC02_000/ov_SC02_000_jr_8017AE2C.c:4538 — same + * ratan2->func_8012B0B4->`d = *(s32*)&buf`->out.vx/out.vz packed-offset idiom, same + * SVEC in/out/buf stack order. The OUTER counted walk is the in-TU banked + * func_801822E4 (same file, :7772): `p = D_801202A0; for (i=0;i<0x60;i++)`. + * + * Three non-obvious levers, in the order the gate found them: + * + * 1. `lose:` INSIDE the 0x1A arm (cookbook §162g). The target's `beqz $v0, + * .L8017EBDC` at 0x8017ECFC is a BACKWARD branch into a block emitted between the + * 0x1A arm and the 0x2000 test. Per §162g cross-jumping only ever emits FORWARD + * merges, so this edge can only be a source-level `goto`. Putting the label + * after the arm's `return 0;` (C permits a goto into a block) reproduces the + * block order with zero extra jumps — no `if (0) {}` wrapper, no jump threading + * needed. + * + * 2. `bp` exists only to create a MOVABLE (cookbook §162e2). `&buf` passed straight + * to func_8012B0B4 is expanded into the arg register in place, so scan_loop has + * nothing to hoist: the draft was 124 ins with only $s0-$s5 and no + * `addiu $s6,$sp,0x20` preheader hoist. Naming it forces a pseudo, which becomes + * the second movable (after `arg0 + 4`), lands in $s6, and the preheader order + * falls out as body order: $s0, $s4, $s5, $s6, then the +0xE giv $s2. (&in/&out + * stay unnamed — the target keeps THOSE inline as `addiu $a0,$sp,0x10` / + * `addiu $a1,$sp,0x18`.) -3 ins -> 0. + * + * 3. `i++, p += 0x10C` in the FOR-INCREMENT, not `p += 0x10C;` as the last body + * statement. The +0xE giv's increment is emitted adjacent to its biv ($s0), so + * body-tail `p += ...` gives [$s2++, $s4++] and the comma form gives the target's + * [$s4++, $s2++]. Last 2 mismatched instructions. + * + * INTEGRATION (§161c): every extern below except func_8017EEA8 is ALREADY declared + * at file scope in src/ov_SC03_107/ov_SC03_107_jr_801789AC.c, identically — + * D_801202A0 :338, func_8012ADE4 :349, func_8012B0B4 :361, func_8012B6D4 :382, + * func_8012BC60 :397, func_8012CBA4 :452, func_8012CEB0 :458, func_80131E00 :562. + * The whole extern block may be dropped on banking. func_8012CBA4 is declared + * `void` there and func_8012BC60/func_80131E00 take struct pointers, so all three + * are reached through call-site function-pointer casts (codegen-neutral, §17a-1) — + * verified MATCH both with those casts against loose `()` decls and against the TU's + * exact struct-typed prototypes. func_8017EEA8 has no decl in the TU (it is + * INCLUDE_ASM at :6456), so its extern must be kept. SVEC_EB70 is a fresh tag — + * no collision in the TU. + */ +#include "common.h" + +typedef struct { s16 vx, vy, vz, pad; } SVEC_EB70; + +struct Vec; +struct S80131E00; + +extern u8 D_801202A0[]; +extern void func_8012CBA4(s32 a0); /* TU decl is void -> cast at call site */ +extern void func_80131E00(struct S80131E00 *a0, s32 a1); +extern void func_8017EEA8(void *a0); +extern void func_8012ADE4(u8 *a0); +extern s32 func_8012BC60(struct Vec *a0, struct Vec *a1); +extern s32 func_8012B6D4(s16 *a0, s16 *a1); +extern void func_8012B0B4(unsigned int *param_1, int param_2, int param_3); +extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2); + +s32 func_8017EB70(s32 arg0) { + SVEC_EB70 in; + SVEC_EB70 out; + SVEC_EB70 buf; + s32 v; + s32 d; + s32 i; + u8 *p; + u16 px, pz; + unsigned int *bp; + + v = ((s32 (*)(s32))func_8012CBA4)(arg0); + if ((v & 0xFF) == 2) { + ((void (*)(s32, s32))func_80131E00)(arg0, 0x12); + return 0; + } + if ((v & 0xFF) == 0x1A) { + func_8017EEA8((void *)arg0); + return 0; + lose: + func_8012ADE4((u8 *)arg0); + return 1; + } + if ((v & 0x2000) == 0) { + func_8012ADE4((u8 *)arg0); + } + *(s32 *)(arg0 + 0xDC) &= ~0x40; + if (*(s32 *)(arg0 + 0x14) > 0xFFFFF) { + *(s32 *)(arg0 + 0x14) = 0x100000; + } + p = D_801202A0; + for (i = 0; i < 0x60; i++, p += 0x10C) { + if (*(u16 *)p != 0 && *(s32 *)(p + 0x58) != 0 && arg0 != (s32)p) { + if (((s32 (*)(s32, s32))func_8012BC60)(arg0 + 4, (s32)(p + 4)) < 0x2400) { + bp = (unsigned int *)&buf; + func_8012B0B4(bp, + func_8012B6D4((s16 *)(arg0 + 4), (s16 *)(p + 4)), 0x61); + d = *(s32 *)&buf; + px = *(u16 *)(p + 6); + out.vx = px; + out.vy = *(u16 *)(p + 0xA); + pz = *(u16 *)(p + 0xE); + out.vz = pz; + out.vx = px + d; + out.vz = pz + (d >> 16); + in.vx = *(u16 *)(arg0 + 0x3A); + in.vy = *(u16 *)(arg0 + 0x3E); + in.vz = *(u16 *)(arg0 + 0x42); + if ((func_8012CEB0((s32)&in, (s32)&out, 0) & 0x2000) == 0) { + goto lose; + } + *(s16 *)(arg0 + 6) = out.vx; + *(s16 *)(arg0 + 0xA) = out.vy; + *(s16 *)(arg0 + 0xE) = out.vz; + break; + } + } + } + return 1; +} + INCLUDE_ASM("asm/ov_SC03_107/nonmatchings/ov_SC03_107_jr_801789AC", func_8017ED6C); diff --git a/src/ov_SC03_118/ov_SC03_118_jr_801863CC.c b/src/ov_SC03_118/ov_SC03_118_jr_801863CC.c index 4863708d5..5cdbbb663 100644 --- a/src/ov_SC03_118/ov_SC03_118_jr_801863CC.c +++ b/src/ov_SC03_118/ov_SC03_118_jr_801863CC.c @@ -3391,7 +3391,67 @@ void func_80186B78(s32 a0) } -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187180); +#include "common.h" + +extern s32 func_8012B8E4(s32 a0, s32 a1); +extern void func_8012B1B4(s32 a0, s32 a1); +extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2); +extern s32 func_8012BCCC(s32 a0); +extern s32 func_8012BDBC(s32 a0, s32 a1); +extern void func_8012CC40(s32 arg0, s32 arg1); /* fleet-canonical: void; $v0 used -> cast at call site */ + +void func_80187180(s32 a0) +{ + extern u8 D_801C6FA8[]; + extern s32 D_801C6FC4; + + s16 pos1[4]; + s16 pos2[4]; + s32 s1; + + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) += func_8012B8E4(a0, 0x10); + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) &= 0xFFF; + func_8012B1B4(a0, (s32)D_801C6FA8); + + { + s16 *p1 = pos1; + s16 *p2 = pos2; + s32 x, y, z; + + x = *(u16 *)(a0 + 0x6); + p2[0] = x; + p1[0] = x; + y = *(u16 *)(a0 + 0xA); + p2[1] = y; + p1[1] = y; + z = *(u16 *)(a0 + 0xE); + p2[1] = y + 0x40; + p2[2] = z; + p1[2] = z; + s1 = func_8012CEB0((s32)p1, (s32)p2, 1); + } + + if (s1 & 0x6000) { + if (!(s1 & 0x1000)) { + s1 = func_8012BCCC(a0); + if (s1 < 0x4001) { + if (func_8012BDBC(a0, 0x200) == 1) { + *(s16 *)(a0 + 0x2) = 4; + *(s16 *)(a0 + 0xFC) = 0; + *(s16 *)(a0 + 0x100) = *(u16 *)(a0 + 0xA); + } + } + } + } + if (s1 > 0x40000) { + *(s16 *)(a0 + 0x2) = 1; + } + + if ((((s32 (*)(s32, s32))func_8012CC40)(a0, (s32)&D_801C6FC4) & 0x1000) != 0) { + *(s16 *)(a0 + 0x2) = 0x12; + } +} + #include "common.h" @@ -3699,7 +3759,64 @@ INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187A8 INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187AEC); -INCLUDE_ASM("asm/ov_SC03_118/nonmatchings/ov_SC03_118_jr_801863CC", func_80187B80); +extern s32 func_8012CEB0(s32 a0, s32 a1, s32 a2); +extern void func_8012B23C(s32 a0); +extern void func_8012B1B4(s32 a0, s32 a1); + +void func_80187B80(s32 a0) +{ + extern u8 D_801C6FA8[]; + u16 out[4]; + u16 pos[4]; + u16 t0, t1, t2; + + *(u16 *)(a0 + 0x5C) = 0xA810; + *(u16 *)(a0 + 0x2) = *(u16 *)(a0 + 0x34); + + t0 = *(u16 *)(a0 + 0x6); + pos[0] = t0; + out[0] = t0; + t1 = *(u16 *)(a0 + 0xA); + pos[1] = t1; + out[1] = t1 - 0x18; + t2 = *(u16 *)(a0 + 0xE); + pos[2] = t2; + out[2] = t2; + func_8012CEB0((s32)out, (s32)pos, 1); + + *(u16 *)(a0 + 0xA) = pos[1] - 0x10; + + if (*(s16 *)(a0 + 0x70) == 0xF) { + s32 c; + + c = *(s32 *)(a0 + 0x20); + *(u16 *)(c + 0x14) = 0; + + *(u16 *)(a0 + 0x2) = 1; + *(u16 *)(a0 + 0x34) = 1; + *(u16 *)(a0 + 0x70) = 0; + *(u16 *)(a0 + 0x88) = *(u16 *)(a0 + 0x6); + *(u16 *)(a0 + 0x8A) = *(u16 *)(a0 + 0xA); + *(u16 *)(a0 + 0x8C) = *(u16 *)(a0 + 0xE); + func_8012B23C(a0); + func_8012B1B4(a0, (s32)D_801C6FA8); + + { + s32 n = *(s32 *)(a0 + 0x6C); + while (n != 0) { + *(u16 *)(n + 0x2) = 2; + *(u16 *)(n + 0x70) = *(u16 *)(n + 0x70) - 0x10; + *(u16 *)(*(s32 *)(n + 0x20) + 0x14) = 0; + n = *(s32 *)(n + 0x6C); + } + } + *(u16 *)(a0 + 0xFC) = 0; + } else { + func_8012B23C(a0); + func_8012B1B4(a0, (s32)D_801C6FA8); + } +} + extern void func_8012E688(s32 *a0, s32 a1, s32 a2); void func_80187CA8(void *a0) { diff --git a/src/ov_SC06_008/ov_SC06_008_jr_8017C294.c b/src/ov_SC06_008/ov_SC06_008_jr_8017C294.c index cbaa101b6..cd092c1f5 100644 --- a/src/ov_SC06_008/ov_SC06_008_jr_8017C294.c +++ b/src/ov_SC06_008/ov_SC06_008_jr_8017C294.c @@ -4356,7 +4356,64 @@ extern void func_8017ED80(void); INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8017C294", func_8017FF74); -INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8017C294", func_80180000); +extern s32 func_8012C354(s32 a0, s32 a1); +extern void func_80143970(); +extern void func_8012A828(s32 a0, void *a1); +extern void func_8012B200(u8 *a0); +extern void func_8012C1B8(void); +extern void func_8001C214(s32 a0, s32 a1); +extern void func_80016714(void *a0, s32 a1); +extern void func_8012CAE4(void *a0); + +void func_80180000(s32 a0) { + + extern u8 D_8019C808[]; + extern u8 D_8019E548[]; + extern u8 D_8019C83C[]; + extern u8 D_8019E258[]; + extern u8 D_8019E530[]; + extern u8 D_80185B40[]; + + s32 s0; + u16 t; + + if (func_8012C354(a0, D_8019C808) == 0) { + return; + } + *(u8 *)(a0 + 0xC0) = 1; + *(s32 *)(a0 + 0xB4) = -0x1001; + ((s32 (*)(s32))func_80143970)(a0); + func_8012A828(a0, D_8019E548); + *(u16 *)(a0 + 0x2) += 1; + func_8012B200((u8 *)a0); + *(s32 *)(a0 + 0xBC) = (s32)D_8019C83C; + + s0 = ((s32 (*)(void))func_8012C1B8)(); + if (s0 == 0) { + goto fail; + } + *(s32 *)(a0 + 0xCC) = s0; + func_8001C214(s0, (s32)D_8019E258); + t = *(u16 *)(s0 + 0x2C) | 0x10; + *(s32 *)(s0 + 0x20) = *(s32 *)D_80185B40; + *(u16 *)(s0 + 0x2C) = t; + + s0 = ((s32 (*)(void))func_8012C1B8)(); + if (s0 == 0) { + func_80016714((void *)*(s32 *)(a0 + 0xCC), 0x84); +fail: + func_8012CAE4((void *)a0); + return; + } + *(s32 *)(a0 + 0xD0) = s0; + func_8001C214(s0, (s32)D_8019E530); + t = *(u16 *)(s0 + 0x2C) | 0x10; + *(s32 *)(s0 + 0x20) = *(s32 *)D_80185B40; + *(u16 *)(s0 + 0x2C) = t; + *(u16 *)(a0 + 0x100) = 0x3C; + *(s32 *)(a0 + 0xDC) = 0xFFFC0000; +} + INCLUDE_ASM("asm/ov_SC06_008/nonmatchings/ov_SC06_008_jr_8017C294", func_80180128); diff --git a/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c b/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c index 86b488390..099eb52c4 100644 --- a/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c +++ b/src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c @@ -7061,7 +7061,86 @@ void func_80184C74(s32 p) } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_801850F4); +#include "common.h" + +/* Host TU: src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c + * Insertion point replaces the INCLUDE_ASM at line 6996, in scope after the + * decl block that begins at line 6786 (#include "common.h"). That block + * ALREADY declares (in scope, do not redeclare): + * extern s32 func_8012BEE8(); (line 6789) + * extern void func_8012A828(s32 a0, void *a1); (line 6790) + * extern u8 D_801CC868[]; (line 6803) + * and elsewhere earlier in the SAME TU (still in scope, file-scope extern): + * extern void func_80013350(s32 a0, void *a1); (line 6647) + * -- loose prototype (real callee takes/returns s32,s32->s32); per + * cookbook §161c do NOT add a conflicting extern here, cast at the + * call site instead (matches the TU's own sibling func_8018457C). + * New decls needed for this function (not yet declared in this TU's scope + * at the insertion point): + * func_8012B6D4, func_8012B608, func_8012B178, func_8018765C, + * func_8012C218, func_8001C924, D_801CD0E8[], D_801BC090[] + * (func_8012B6D4/B608/B178/8765C signatures copied verbatim from this TU's + * other declarations of the same symbols, e.g. lines 6643-6646/7043-7045; + * func_8012C218/func_8001C924 copied from lines 6639-6640.) + */ + +extern s32 func_8012BEE8(); +extern void func_8012A828(s32 a0, void *a1); +extern void func_80013350(s32 a0, void *a1); /* loose proto, real TU decl (line 6647); cast at call site per §161c */ +extern s32 func_8012B6D4(s16 *a0, s16 *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_8018765C(s32 a0); +extern void func_8012C218(void *a0); +extern void func_8001C924(s32 a0, void *a1); + +extern u8 D_801CD0E8[]; +extern u8 D_801CC868[]; +extern u8 D_801BC090[]; + +void func_801850F4(s32 p) +{ + s32 s1; + s32 r; + + if (*(u16 *)(p + 0x34) == 0) { + s1 = *(s32 *)(p + 0xCC); + if (s1 == 0 || *(s16 *)(s1 + 0x36) != *(s16 *)(p + 0xEC) || + func_8012BEE8(p) != 0) { + *(u16 *)(p + 2) = 0x23; + *(u32 *)(p + 0xE0) |= 0x800; + return; + } + + r = func_8012B6D4((s16 *)(p + 4), (s16 *)(s1 + 4)); + *(s32 *)(p + 0xE8) = r; + + r = func_8012B608(*(s16 *)(*(s32 *)(p + 0x20) + 0x12), *(s32 *)(p + 0xE8), 8); + *(u16 *)(*(s32 *)(p + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(p + 0x20) + 0x12) + r; + + func_8012B178(p, 0xFFF8D000); + func_8018765C(p); + + r = ((s32 (*)(s32, s32))func_80013350)(p + 4, s1 + 4); + if (r < 0x900) { + *(u16 *)(p + 0x34) = *(u16 *)(p + 0x34) + 1; + func_8012A828(p, D_801CD0E8); + } + } else { + if (*(s16 *)(p + 0x98) != 0) { + return; + } + func_8012C218((void *)*(s32 *)(p + 0xCC)); + *(s32 *)(p + 0xCC) = 0; + func_8001C924(*(s32 *)(p + 0x20), D_801BC090); + func_8012A828(p, D_801CC868); + *(s32 *)(p + 0x48) = 0x4650; + *(s16 *)(p + 2) = 0x12; + *(u32 *)(p + 0xE0) &= ~4; + } +} + #include "common.h" @@ -7250,7 +7329,87 @@ void func_801854F8(s32 p) { } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_801857CC); +#include "common.h" + +/* §160g sibling search: callee set {func_8012BEE8, func_8012B6D4, func_8012B608, + * func_8012B178, func_8018765C, func_80013350, func_8012A828, func_8012C218, + * func_8001C924} matches the ALREADY-MATCHED func_8018457C in this exact TU + * (src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c, lines 6654-6733) almost verbatim -- + * that function's case 0 (the s1=*(p+0xCC) null/field-0x36-vs-0xEC/func_8012BEE8 + * mismatch guard, then func_8012B6D4 + the func_8012B608/func_8012B178/ + * func_8018765C/func_80013350 tail with the same D_801CD0E8 transition) is a + * structural template for our "state==0" branch. The "state!=0" branch's tail + * (set +2=0x1D, +0x34=0, +0x1C=0xF, call func_8012A828) is verbatim the body of + * the tiny already-MATCHED func_801854C0 a few lines above ours in the same TU + * (it uses a function-pointer cast only because ITS param is `short *`; ours is + * already `s32 param_1` so a plain call suffices, mirroring func_801854F8's own + * plain `func_8012A828(p, D_801CC358);` two lines before our INCLUDE_ASM slot). + * The `*(u32*)(p+0xE0) &= 0xFFFFFFFB;` mask is byte-identical to func_8018457C's + * case 1 mask. All extern decls below are copied verbatim from these matched + * siblings' own decl blocks (same TU, same file-scope conventions). + */ + +extern s32 func_8012BEE8(); +extern s32 func_8012B6D4(s16 *a0, s16 *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_8018765C(s32 a0); +extern void func_80013350(s32 a0, void *a1); +extern void func_8012A828(s32 a0, void *a1); +extern void func_8012C218(void *a0); +extern void func_8001C924(s32 a0, void *a1); + +extern u8 D_801CD0E8[]; +extern u8 D_801BBC78; +extern u8 D_801CC358[]; + +void func_801857CC(s32 param_1) +{ + s32 s1; + s32 uVar4; + s32 sVar1; + s32 r; + + if (*(u16 *)(param_1 + 0x34) == 0) { + s1 = *(s32 *)(param_1 + 0xCC); + if (s1 == 0 || *(s16 *)(s1 + 0x36) != *(s16 *)(param_1 + 0xEC) || + func_8012BEE8(param_1) != 0) { + *(s16 *)(param_1 + 2) = 0x23; + *(u32 *)(param_1 + 0xE0) |= 0x800; + return; + } + + uVar4 = func_8012B6D4((s16 *)(param_1 + 4), (s16 *)(s1 + 4)); + *(s32 *)(param_1 + 0xE8) = uVar4; + + sVar1 = func_8012B608((s32)*(s16 *)(*(s32 *)(param_1 + 0x20) + 0x12), uVar4, 8); + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(param_1 + 0x20) + 0x12) + sVar1; + + func_8012B178(param_1, 0xFFF8D000); + func_8018765C(param_1); + + r = ((s32 (*)(s32, s32))func_80013350)(param_1 + 4, s1 + 4); + if (r < 0x900) { + *(u16 *)(param_1 + 0x34) = *(u16 *)(param_1 + 0x34) + 1; + func_8012A828(param_1, D_801CD0E8); + } + return; + } + + if (*(s16 *)(param_1 + 0x98) != 0) { + return; + } + func_8012C218((void *)*(s32 *)(param_1 + 0xCC)); + *(s32 *)(param_1 + 0xCC) = 0; + func_8001C924(*(s32 *)(param_1 + 0x20), &D_801BBC78); + *(s16 *)(param_1 + 2) = 0x1D; + *(u16 *)(param_1 + 0x34) = 0; + *(s32 *)(param_1 + 0x1C) = 0xF; + func_8012A828(param_1, D_801CC358); + *(u32 *)(param_1 + 0xE0) &= 0xFFFFFFFB; +} + INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_80185944); @@ -7356,7 +7515,75 @@ void func_8018598C(s32 param_1) { } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_80185C2C); +#include "common.h" + +/* Sibling-search hit (cookbook §160g): src/ov_SC06_018/ov_SC06_018_jr_8017C24C.c:6654 + * func_8018457C (already banked) is the SAME structural family — its case 0 (the + * s0==0||mismatch||func_8012BEE8() guard + call_b6d4/LAB_80184738 tail) and case 3 + * (func_8012C218/func_8001C924/func_8012A828 teardown chain) are literally this + * function's two branches with different field offsets/globals. Types/signatures below + * mirror that TU's existing extern decls exactly (host TU already declares all of + * these at file scope before this insertion point, e.g. lines 6639-6652, 7203-7213). + */ + +extern s32 func_8012BEE8(s32 a0); +extern s32 func_8012B6D4(s16 *a0, s16 *a1); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_8018765C(s32 a0); +extern void func_80013350(s32 a0, void *a1); +extern void func_8012A828(s32 a0, void *a1); +extern void func_8012C218(void *a0); +extern void func_8001C924(s32 a0, void *a1); + +extern u8 D_801CD0E8[]; +extern u8 D_801BC494; +extern u8 D_801CC6E8[]; + +void func_80185C2C(s32 p) +{ + s32 s0; + s32 r; + + if (*(u16 *)(p + 0x34) == 0) { + s0 = *(s32 *)(p + 0xCC); + if (s0 == 0 || *(s16 *)(s0 + 0x36) != *(s16 *)(p + 0xEC) || + func_8012BEE8(p) != 0) { + *(u16 *)(p + 2) = 0x23; + *(u32 *)(p + 0xE0) |= 0x800; + } else { + r = func_8012B6D4((s16 *)(p + 4), (s16 *)(s0 + 4)); + *(s32 *)(p + 0xE8) = r; + + r = func_8012B608(*(s16 *)(*(s32 *)(p + 0x20) + 0x12), *(s32 *)(p + 0xE8), 8); + *(u16 *)(*(s32 *)(p + 0x20) + 0x12) = + *(u16 *)(*(s32 *)(p + 0x20) + 0x12) + r; + + func_8012B178(p, 0xFFF8D000); + + func_8018765C(p); + + r = ((s32 (*)(s32, s32))func_80013350)(p + 4, s0 + 4); + if (r < 0x900) { + *(u16 *)(p + 0x34) = *(u16 *)(p + 0x34) + 1; + func_8012A828(p, D_801CD0E8); + } + } + } else { + if (*(s16 *)(p + 0x98) == 0) { + func_8012C218((void *)*(s32 *)(p + 0xCC)); + *(s32 *)(p + 0xCC) = 0; + func_8001C924(*(s32 *)(p + 0x20), &D_801BC494); + *(u16 *)(p + 2) = 0x20; + func_8012A828(p, D_801CC6E8); + *(s32 *)(p + 0x48) = 0x4650; + *(s32 *)(p + 0x1C) = 0; + *(s32 *)(p + 0xE4) = 0; + *(u32 *)(p + 0xE0) &= 0xFFFFFFFB; + } + } +} + extern void func_80187038(void); void func_80185DA8(s32 arg0) { @@ -7366,7 +7593,123 @@ extern void func_80187038(void); } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_8017C24C", func_80185DD8); +#include "common.h" + +/* Sibling-search (§160g) findings, kept for the integration note: + * - func_8018598C (same TU, ov_SC06_018_jr_8017C24C.c:7215, MATCHED/banked already) shares + * func_8012BEE8/func_8012B608/func_8012B178/func_8018765C/func_801877E4 with identical + * argument shapes -- confirms every extern signature below except func_8012B8A4/func_8012EFB8. + * - func_8018457C (same TU, :6654) uses the SAME func_8012B608(*(s16*)(*(s32*)(p+0x20)+0x12), + * *(s32*)(p+0xE8), 8) / field += pattern and the SAME func_8012B178(p, 0xFFF8D000) magic + * literal -- confirms the b608/b178 idiom byte-for-byte. + * - func_8012B8A4 canonical decl (many matched TUs): extern s32 func_8012B8A4(s16 *a0); + * - func_8012EFB8's byte-true body (src/ov_SC03_099/ov_SC03_099_jr_8012ACE0.c:1106) is + * `s32 func_8012EFB8(void *param_1, void *param_2)` -- TWO pointers, s32 return -- but the + * fleet-canon extern in THIS TU (line 335: `extern void func_8012EFB8(s32 a0);`, file scope, + * already in effect before this function) conflicts on both arity and return axis. Per §161c, + * do NOT add a second extern; cast the existing symbol at the call site instead. + * - Ghidra seed at .run/ghidra_c/func_80185DD8.c confirms the callee set and control flow + * (verified address-matched: FUN_80185dd8, calls FUN_8012be54/bee8/b8a4/b608/b178/8765c/877e4/ + * efb8/c098) -- used only to cross-check, not copied verbatim (Ghidra's decompile is + * -O0-shaped and not reg-alloc-accurate). + * + * INTEGRATION SURFACE (for the banking step): every extern below is checked against this TU's + * (ov_SC06_018_jr_8017C24C.c) own file-scope decls already in effect before line 7301: + * func_8012BE54 -> void(s32) EXACT match (host decl at :4212/:5193; cast to (s32(*)(s32)) at + * the one call site, mirroring the host's own existing call-site casts at :4363/:5291). + * func_8012BEE8 -> s32(s32) EXACT match (:7203). + * func_8012B608 -> s32(s32,s32,s32) EXACT match (:6644). + * func_8012B178 -> void(s32,s32) EXACT match (:6645/:7044/:7207). + * func_8018765C -> s32(s32) EXACT match (:6646/:7045/:7208). + * func_801877E4 -> void(s32) EXACT match (:7046/:7209). + * func_8012EFB8 -> declared void(s32) to match the host's loose file-scope decl (:335); the + * real (void*,void*)->s32 body is invoked through a cast at the call site (§161c), so no + * second/conflicting extern is introduced. + * func_8012C098 -> void(void*) EXACT match (:5603). + * func_8012B8A4 -> NOT declared anywhere in this TU before this point; the draft's + * `extern s32 func_8012B8A4(s16 *a0);` is the canonical signature used fleet-wide and + * introduces no conflict. + * Net: zero declaration conflicts predicted against the host TU. + */ + +extern void func_8012BE54(s32 a0); /* host TU decl is void (§161c-style loose proto); cast at call site */ +extern s32 func_8012BEE8(s32 a0); +extern s32 func_8012B8A4(s16 *a0); +extern s32 func_8012B608(s32 a0, s32 a1, s32 a2); +extern void func_8012B178(s32 a0, s32 a1); +extern s32 func_8018765C(s32 a0); +extern void func_801877E4(s32 a0); +extern void func_8012EFB8(s32 a0); /* loose decl, real body is (void*,void*)->s32; call via cast */ +extern void func_8012C098(void *param_1); + +void func_80185DD8(s32 a0) { + s32 r; + s16 vecA[4]; + s16 vecB[4]; + s32 x, z; + + if ((*(u32 *)(a0 + 0xE0) & 0x40) == 0) { + s32 ret = ((s32 (*)(s32))func_8012BE54)(a0); + if (ret <= 0x63FFF) { + if (func_8012BEE8(a0) != 0) { + s32 t; + s32 rr; + + t = func_8012B8A4((s16 *)a0); + *(u32 *)(a0 + 0xE8) = (t + 0x800) & 0xFFF; + rr = rand(); + *(s32 *)(a0 + 0x1C) = rr % 0x40 + 0x40; + } + } + } + + r = func_8012B608((s32) * (s16 *)(*(s32 *)(a0 + 0x20) + 0x12), *(s32 *)(a0 + 0xE8), 8); + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) = *(u16 *)(*(s32 *)(a0 + 0x20) + 0x12) + r; + + *(u32 *)(a0 + 0xE0) &= 0xFFFFFFBF; + func_8012B178(a0, 0xFFF8D000); + + if (func_8018765C(a0) == 0) { + func_801877E4(a0); + } + + vecA[0] = *(s16 *)(a0 + 0x6); + vecA[1] = *(s16 *)(a0 + 0xA); + vecA[2] = *(s16 *)(a0 + 0xE); + ((s32 (*)(void *, void *))func_8012EFB8)(vecA, vecB); + + x = vecB[0]; + if (x < 0) { + x = -x; + } + if (x < 0x105) { + z = vecB[1]; + if (z >= 0) { + if (z < 0xC9) { + /* NEW LEVER (not yet in cookbook): a bare if/else-with-return here compiles + * to a value-converge merge (ONE shared `slti`+`bne` fed by both signs of z, + * ~91 ins) instead of the target's genuine PER-BRANCH duplicate compare + * (96 ins: `bltz`+`slti`+`beqz`+`j` in this arm, `negu`+`slti`+`bnez` in the + * else arm). A zero-emission `__asm__ __volatile__("":::"memory")` right + * before this `return` is a scheduling/combine barrier that blocks whatever + * RTL-level pass performs that merge, without adding a single byte itself -- + * the compiled result is byte-exact target. Byte-proven via 9 probe variants + * (assignment-abs, ternary-condition, if/else, 2-independent-ifs, goto-labeled + * return) that ALL either fully merged or left a redundant extra sign-retest; + * only this barrier reproduces the target exactly. See match_one MATCH 96/96. + */ + __asm__ __volatile__("" ::: "memory"); + return; + } + } else { + if (-z < 0xC9) { + return; + } + } + } + func_8012C098((void *)a0); +} + #include "common.h" diff --git a/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c b/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c index 4d135b39c..59af0255d 100644 --- a/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c +++ b/src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c @@ -3201,7 +3201,85 @@ void func_80188088(void *a0) { } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_801880C4); +#include "common.h" + +/* Sibling-search (cookbook §160g): every declaration below is TU-canonical, lifted verbatim + * from src/ov_SC06_018/ov_SC06_018_jr_80187AEC.c (the destination TU): + * func_8012C354 -- decl at TU:2846 "extern s32 func_8012C354(s32 a0, void *a1);" + * func_8012CAE4 -- decl at TU:2849 "extern void func_8012CAE4(s32 a0);" + * func_80143994 -- decl at TU:2847 "extern s32 func_80143994(s32 a0, s32 a1);" + * func_80188B00 -- ALREADY DEFINED in this TU at :3492 "void func_80188B00(s32 p)" (banked) + * func_8012C1B8 -- TU-canonical `void (void)` at :4123/:3929, called via the established + * cast-through-function-pointer idiom (§161c) seen in this TU's own + * func_80189A34 (:4138) and func_801894F0 (:3948) -- byte-identical spawn + * idiom, same handle-alloc-then-null-check shape as our case 2. + * func_8001CA1C -- not yet declared in THIS TU; canonical form taken from the sibling TU + * ov_SC06_018_jr_80140608.c:1704 "extern void func_8001CA1C(s32 a0, s32 a1);" + * func_80188234 -- INCLUDE_ASM in this TU at :3206 (still unmatched); called here with the + * object pointer and its own return discarded, so declared void(s32). + * D_801B545C / D_801B5490 / D_801B5430 are new (undeclared anywhere in src/); declared as + * plain byte arrays per this TU's own convention for opaque data blobs (e.g. D_801AD470[] + * at TU:2791) -- only their address is used (func_8012C354's a1 is void*, func_8001CA1C's a1 + * is a raw s32 cast of the address), so element type is codegen-irrelevant. + */ +extern s32 func_8012C354(s32 a0, void *a1); +extern void func_8012CAE4(s32 a0); +extern s32 func_80143994(s32 a0, s32 a1); +extern void func_80188234(s32 a0); +extern void func_8012C1B8(void); +extern void func_8001CA1C(s32 a0, s32 a1); +extern void func_80188B00(s32 p); + +extern u8 D_801B545C[]; +extern u8 D_801B5490[]; +extern u8 D_801B5430[]; + +void func_801880C4(s32 a0) { + s32 v1; + s32 obj; + + v1 = *(u16 *)(a0 + 0x70) & 0xF; + switch (v1) { + case 0: + if (func_8012C354(a0, D_801B545C) == 0) { + return; + } + *(s32 *)(*(s32 *)(a0 + 0x20) + 0x20) = a0 + 0xE8; + *(u16 *)(a0 + 0x104) = 0x78; + func_80188234(a0); + func_80143994(a0, 0x1800); + return; + case 1: + if (func_8012C354(a0, D_801B5490) == 0) { + return; + } + *(u16 *)(a0 + 0x104) = 0xA0; + if ((*(s16 *)(a0 + 0x70) & 0x8000) == 0) { + *(s16 *)(a0 + 0x2) = 3; + return; + } + *(s16 *)(a0 + 0x2) = 5; + func_80143994(a0, 0x1800); + return; + case 2: + obj = ((s32 (*)(void))func_8012C1B8)(); + *(s32 *)(a0 + 0x20) = obj; + if (obj == 0) { + func_8012CAE4(a0); + return; + } + func_8001CA1C(obj, (s32)D_801B5430); + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x18) = 0x14CC; + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x1A) = 0x1199; + *(s32 *)(*(s32 *)(a0 + 0x20) + 4) |= 0x58000000; + *(u16 *)(*(s32 *)(a0 + 0x20) + 0x2C) |= 0x10; + func_80188B00(a0); + return; + default: + return; + } +} + INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_80188234); @@ -4997,7 +5075,82 @@ void func_8018D870(void *arg) { } -INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_8018DE60); +// func_8018DE60 -- ov_SC06_018 / ov_SC06_018_jr_80187AEC +// +// Structural sibling of func_8018E188 (SAME TU, banked MATCH, this file: func_8018E188). +// Shares VERBATIM: the 0x60 gate + 0x1D snapshot block, the 0x78/0x60 decrement block +// (AND form -- see E188's @stuck note), the 0x82&1 finisher, and the C8/C9 pokes. +// Diverges after that: instead of E188's 0x76<0 spawn-loop / CC-D0-D4 reseed, this +// function's 0x76<0 arm sets a distinct "state 2" field group (offsets 2/0x5C/0x34/ +// 0xC1/0xF4 + clears bit 0x80 of *(p+0x20)->0x2C), and its else arm plays a different +// sound (func_8002D4C8(0xAD8,0) vs E188's 0xAE0) then tail-calls func_8018D654 (still +// INCLUDE_ASM in this TU -- no other TU references it, so this call site sets its own +// convention: void func_8018D654(void *)). +// +// @class: regalloc-order +// @stuck: none -- see match_one output. + +extern void func_8016AA50(s32, s32); +extern s32 func_8016B428(s32); +extern void func_80019064(void *); +extern void func_8002A520(int); +extern void func_8002A790(int); +extern void func_8002D4C8(s32, s32); +extern void func_8018D654(void *); +extern u8 D_801D1210; + +void func_8018DE60(void *arg) { + u8 *p = (u8 *)arg; + s32 e = *(u8 *)(p + 0x5E); + + if (*(s16 *)(p + 0x60) != 0) { + if (e == 0x1D) { + *(u16 *)(p + 0x82) = 0; + *(u16 *)(p + 0x7C) = *(u16 *)(p + 0x06); + *(u16 *)(p + 0x7E) = *(u16 *)(p + 0x0A); + *(u16 *)(p + 0x80) = *(u16 *)(p + 0x0E); + } + { + s32 dec; + s32 q = *(s32 *)(p + 0x78); + if (q != 0 && *(s16 *)(p + 0x60) != 0) { + dec = ((s32)*(s16 *)(p + 0x60) * (s32)*(s16 *)(q + 0x30)) >> 12; + if (dec < 1) dec = 1; + } else { + dec = *(s16 *)(p + 0x60); + } + *(u16 *)(p + 0x76) = *(u16 *)(p + 0x76) - dec; + ((void (*)(void *, s32))func_8016AA50)(p, dec); + } + if (*(u16 *)(p + 0x82) & 1) { + ((void (*)(void *))func_8016B428)(p); + func_80019064(&D_801D1210); + } + } + + if (e != 0x1D) { + if (*(u8 *)(p + 0xC8)) func_8002A520(p); + if (*(u8 *)(p + 0xC9)) func_8002A790(p); + } + + if (*(s16 *)(p + 0x76) < 0) { + s32 q = *(s32 *)(p + 0x20); + *(s16 *)(p + 0x02) = 0xA; + *(u16 *)(p + 0x5C) = 0x800; + *(u16 *)(p + 0x34) = 0; + *(u8 *)(p + 0xC1) = 0; + *(s32 *)(p + 0xF4) = 1; + *(u16 *)(q + 0x2C) &= 0xFF7F; + } else { + func_8002D4C8(0xAD8, 0); + *(u16 *)(p + 0x5C) = 0x8800; + *(u16 *)(p + 0x60) = 0; + *(u8 *)(p + 0xC1) = 0; + *(u8 *)(p + 0xC2) = 0x10; + func_8018D654(p); + } +} + INCLUDE_ASM("asm/ov_SC06_018/nonmatchings/ov_SC06_018_jr_80187AEC", func_8018DFF4);