From 7fbc500e5cfbc2a314fdfc4509119e24c9fa7a0e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 5 Jun 2026 22:35:53 +0200 Subject: [PATCH 001/134] add claude.md --- CLAUDE.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..49fdd185 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,76 @@ +# CLAUDE.md + +Guidance for working in this repo (a WIP decompilation of the PS2 game *Sly +Cooper and the Thievius Raccoonus*, NTSC-U `SCUS_971.98`). The goal is matching +C/C++ source: code that compiles (with the EE GCC 2.95 toolchain under Wine) to +bytes identical to the original executable. + +## Conventions & style + +Follow [docs/STYLEGUIDE.md](docs/STYLEGUIDE.md) for naming (Hungarian-style +prefixes: `p`ointer, `c`ount, `f`lag, `g_`lobal, `m_`ember…), capitalization +(`ALLCAPS` structs/enums, `UpperCamelCase` functions, `lowerCamelCase` +locals), brace-on-new-line + 4-space indent, and Doxygen comments. See +[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for the end-to-end matching +workflow. Prefer official symbol names from the May 19 2002 prototype; when +unknown, use a clear descriptive name (offset-suffixed placeholders like +`unk_0x360` are acceptable for not-yet-understood struct fields). + +## Build & verify + +- Full build + checksum: `./scripts/build.sh` → expect `out/SCUS_971.98: OK`. + This (`sha1sum -c config/checksum.sha1`) is the ground-truth "did I break + anything" check — run it after touching shared headers. +- Per-function diff (interactive TUI): `./scripts/diff.sh [P2/unit]`. +- The build defines `-DSKIP_ASM`, so the real ELF is built from C; `INCLUDE_ASM` + expands to nothing under `SKIP_ASM` and pulls in the `.s` otherwise. Objdiff + dual-builds `obj/target/*.o` (asm) vs `obj/current/*.o` (your C, `-DSKIP_ASM`) + via `python3 configure.py --objects && ninja`. +- Headless one-shot verify (the TUI needs a tty): build the dual objects, then + `objdump -dr obj/{target,current}/.o`, slice out the symbol, strip the + leading address/opcode-byte columns, and diff. Equal instructions **and** + relocations = a match (objdump prints all unresolved calls as `jal 0 `, + so always compare the `R_MIPS_26` reloc rows too). +- To inspect a struct's real compiled layout, compile an address-of/`sizeof` + probe with the EE compiler and read the immediates: + `wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee -isystem include/gcc -x c++ -B$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/ -O2 -G0 -ffast-math probe.cpp`. + +## Critical: do NOT grow engine base struct sizes + +The base classes `LO` → `ALO` → `SO` are intentionally **truncated**: +`sizeof(SO)` compiles to `0x2d0`, even though the real game's `SO` is `0x550`. +The `/* 0xNN */` offset comments in the base headers are aspirational targets, +**not** the compiled offsets (e.g. `ALO::grfzon` compiles to `0x7c`, documented +`0x88`). + +Each subclass instead places its own fields at correct **absolute** offsets +using explicit `STRUCT_PADDING(...)` **calibrated to the current truncated base +size** (e.g. `struct JT` pads ~1090 words to land `paloMine` at `0x1518`). + +Growing `SO`/`ALO`/`LO` to their "true" size shifts every subclass's fields and +**fails the checksum** — the breakage surfaces in compiled-C accessors of other +subclasses (e.g. `SetFsp` reading `JT`), not in your file. So when reversing a +new subclass: + +- Keep the base structs as-is. Lay out the whole object inside the subclass via + leading `STRUCT_PADDING` from `sizeof(base)` — including fields that + semantically belong to the SO base but live past `0x2d0`. +- For a base field accessed through a generic `SO*` (e.g. the `grfso` flag word + at `0x538`), cast to the subclass type to reach the offset; note it in a + comment. + +## GCC 2.95 matching tips + +Matching is mostly about steering this old compiler's scheduler/allocator: + +- `x & ~A & ~B` with two constant masks gets folded into one `&` by the front + end / combiner. To force two separate ANDs (one load, two ANDs, one store), + load into a local and split into `tmp &= ~A; tmp &= ~B;`. +- Register choice is driven by variable live-ranges: reusing one variable pins + it to a register across its whole range; use a *fresh* local for a late block + to let the allocator pick the register the target uses. +- Mirror the original's pointer/index reuse — introduce locals like + `MRG *pmrg = &x->mrg;` or `int c = p->count;` when the asm keeps a value in a + register rather than reloading it. +- Store ordering: GCC may reverse independent store pairs; reorder the source + statements to compensate. From 8798f9ff46215c8def3da0c499fddba0808d941f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 5 Jun 2026 22:47:32 +0200 Subject: [PATCH 002/134] update workflow --- CLAUDE.md | 44 +++++++++++++++++++++--------- scripts/match.sh | 49 +++++++++++++++++++++++++++++++++ scripts/structoff.sh | 64 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 12 deletions(-) create mode 100755 scripts/match.sh create mode 100755 scripts/structoff.sh diff --git a/CLAUDE.md b/CLAUDE.md index 49fdd185..8684d550 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,18 +22,38 @@ unknown, use a clear descriptive name (offset-suffixed placeholders like This (`sha1sum -c config/checksum.sha1`) is the ground-truth "did I break anything" check — run it after touching shared headers. - Per-function diff (interactive TUI): `./scripts/diff.sh [P2/unit]`. -- The build defines `-DSKIP_ASM`, so the real ELF is built from C; `INCLUDE_ASM` - expands to nothing under `SKIP_ASM` and pulls in the `.s` otherwise. Objdiff - dual-builds `obj/target/*.o` (asm) vs `obj/current/*.o` (your C, `-DSKIP_ASM`) - via `python3 configure.py --objects && ninja`. -- Headless one-shot verify (the TUI needs a tty): build the dual objects, then - `objdump -dr obj/{target,current}/.o`, slice out the symbol, strip the - leading address/opcode-byte columns, and diff. Equal instructions **and** - relocations = a match (objdump prints all unresolved calls as `jal 0 `, - so always compare the `R_MIPS_26` reloc rows too). -- To inspect a struct's real compiled layout, compile an address-of/`sizeof` - probe with the EE compiler and read the immediates: - `wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee -isystem include/gcc -x c++ -B$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/ -O2 -G0 -ffast-math probe.cpp`. +- **Headless per-symbol match check** (the TUI needs a tty; use this for + automated/iterative work): `./scripts/match.sh `, e.g. + `./scripts/match.sh P2/water InitWater__FP5WATER`. It dual-builds and diffs the + symbol's instructions **and** relocations, printing `MATCH` or the diff. +- **Inspect a struct's real compiled layout**: + `./scripts/structoff.sh
'EXPR' ['EXPR' ...]`, e.g. + `./scripts/structoff.sh water.h 'sizeof(WATER)' '(int)(long)&((WATER*)0)->grfso'`. + Always probe with the EE compiler — host gcc gives wrong offsets (different + EABI alignment), and the `/* 0xNN */` header comments are not the compiled + offsets. +- Mechanics behind those scripts: the build defines `-DSKIP_ASM`, so the real + ELF is built from C; `INCLUDE_ASM` expands to nothing under `SKIP_ASM` and + pulls in the `.s` otherwise. Objdiff dual-builds `obj/target/*.o` (asm) vs + `obj/current/*.o` (your C) via `python3 configure.py --objects && ninja`. + objdump prints every unresolved call as `jal 0 `, so a real check must + compare the `R_MIPS_26` reloc rows too (`match.sh` does). + +## Suggested matching workflow + +1. Read the target `.s` in `asm/nonmatchings//.s` and the function + prototype in the header. Note every struct offset it touches. +2. Lay out the struct: probe sizes/offsets with `scripts/structoff.sh`, then add + fields to the (sub)struct via `STRUCT_PADDING` to land at absolute offsets — + **never grow the base structs** (see below). +3. Write the C under the `INCLUDE_ASM` line, wrapped in `#ifdef SKIP_ASM` / + `#endif`, so the asm is still available as the diff target. +4. Loop: edit → `scripts/match.sh ` → adjust for GCC 2.95 quirks + (see tips below) until it prints `MATCH`. +5. When matched, delete the `INCLUDE_ASM` line and the `#ifdef SKIP_ASM`/`#endif` + wrapper, leaving plain C. +6. After the file is done (or after any shared-header edit), run + `./scripts/build.sh` and confirm `out/SCUS_971.98: OK`. ## Critical: do NOT grow engine base struct sizes diff --git a/scripts/match.sh b/scripts/match.sh new file mode 100755 index 00000000..345535dd --- /dev/null +++ b/scripts/match.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Headless per-symbol match check (no TUI). Builds the target (asm) and current +# (your C, -DSKIP_ASM) objects, then diffs a single symbol's instructions AND +# relocations. Prints "MATCH" or the instruction diff. +# +# Usage: scripts/match.sh +# splat unit path, e.g. P2/water (object: obj/{target,current}/water.o) +# +# Example: scripts/match.sh P2/water InitWater__FP5WATER +# +set -e + +if [ -z "$2" ]; then + echo "Usage: $0 (e.g. $0 P2/water InitWater__FP5WATER)" >&2 + exit 1 +fi + +cd "$(dirname "$0")/.." +if [ -z "$VIRTUAL_ENV" ]; then + source "env/bin/activate" +fi + +UNIT="$1" +SYM="$2" +OBJ="$(basename "$UNIT").o" + +python3 configure.py --objects >/dev/null +ninja "obj/target/$OBJ" "obj/current/$OBJ" >/dev/null + +for v in target current; do + mips-linux-gnu-objdump -dr "obj/$v/$OBJ" 2>/dev/null | awk -v s="<$SYM>:" ' + $0 ~ s {p=1} p && /^$/ {p=0} p {print}' \ + | sed -E 's/^\s*[0-9a-f]+:\s+[0-9a-f]{8}\s+//; s/^\s*[0-9a-f]+: (R_MIPS)/\1/; s/^[0-9a-f]+ "/tmp/match_$v.txt" +done + +if ! [ -s /tmp/match_target.txt ]; then + echo "error: symbol '$SYM' not found in obj/target/$OBJ" >&2 + exit 2 +fi + +if diff -q /tmp/match_target.txt /tmp/match_current.txt >/dev/null; then + echo "MATCH: $SYM" +else + echo "DIFFERS: $SYM" + diff /tmp/match_target.txt /tmp/match_current.txt + exit 1 +fi diff --git a/scripts/structoff.sh b/scripts/structoff.sh new file mode 100755 index 00000000..58081bc3 --- /dev/null +++ b/scripts/structoff.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Print REAL compiled struct offsets/sizes using the EE (GCC 2.95) toolchain. +# Host gcc gives wrong layout (different EABI alignment), so always probe with +# the actual compiler. Each EXPR must be an integer constant expression; use a +# null base for offsetof-style queries, e.g. (int)(long)&((WATER*)0)->grfso +# +# Usage: scripts/structoff.sh
'EXPR' ['EXPR' ...] +# +# Example: +# scripts/structoff.sh water.h 'sizeof(WATER)' \ +# '(int)(long)&((WATER*)0)->grfso' '(int)(long)&((WATER*)0)->zpd.cploThrow' +# +set -e + +if [ -z "$2" ]; then + echo "Usage: $0
'EXPR' ['EXPR' ...]" >&2 + exit 1 +fi + +cd "$(dirname "$0")/.." + +HDR="$1" +shift + +SRC="$(mktemp /tmp/structoff.XXXXXX.cpp)" +OBJ="${SRC%.cpp}.o" +trap 'rm -f "$SRC" "$OBJ"' EXIT + +{ + echo "#include <$HDR>" + i=0 + for e in "$@"; do + echo "int probe_$i(){ return (int)($e); }" + i=$((i + 1)) + done +} > "$SRC" + +WINEDEBUG=-all wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee \ + -isystem include/gcc -x c++ -B"$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/" \ + -O2 -G0 -ffast-math "$SRC" -o "$OBJ" 2>&1 | grep -viE 'warning|radv' || true + +if ! [ -s "$OBJ" ]; then + echo "error: compile failed (run without the grep filter to see why)" >&2 + exit 2 +fi + +DIS="$(mips-linux-gnu-objdump -d "$OBJ" 2>/dev/null)" +echo "# <$HDR>" +i=0 +for e in "$@"; do + # Each probe is a constant function: jr ra ; li v0,N (or move v0,zero for 0). + block="$(echo "$DIS" | awk -v f=" Date: Sat, 6 Jun 2026 20:18:13 +0200 Subject: [PATCH 003/134] Add decomp batch-matching workflow and harness scripts/decomp_lhf_draft.workflow.js fans out parallel read-only agents that draft matching C for batches of tiny leaf functions. scripts/decomp_apply_drafts.py verifies each draft in isolation (instructions + relocations vs the asm), rejects ones that grow non-.text sections (rodata-layout ripple) or whose raw FUN_ symbol has asm callers, then applies the byte-exact matches and renames FUN_ symbols. Co-Authored-By: Claude Opus 4.8 --- scripts/decomp_apply_drafts.py | 152 +++++++++++++++++++++++++++ scripts/decomp_lhf_draft.workflow.js | 73 +++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 scripts/decomp_apply_drafts.py create mode 100644 scripts/decomp_lhf_draft.workflow.js diff --git a/scripts/decomp_apply_drafts.py b/scripts/decomp_apply_drafts.py new file mode 100644 index 00000000..156686c1 --- /dev/null +++ b/scripts/decomp_apply_drafts.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# Apply workflow drafts one-at-a-time (isolated), build the unit object, diff +# against the target asm, and keep only byte-exact matches. Then apply all +# keepers together. Run: python3 /tmp/apply_drafts.py [verify|finalize] +import json, subprocess, os, re, sys + +REPO = "/home/johan/git/sly1" +os.chdir(REPO) +DRAFTS = json.load(open("/tmp/drafts.json")) + +def sh(cmd): + return subprocess.run(["bash", "-lc", cmd], capture_output=True, text=True) + +def cfile(unit): return f"src/{unit}.c" +def objbase(unit): return os.path.basename(unit) # P2/crv -> crv + +# ---- backup every file we might touch ---- +TOUCHED = set(cfile(d["unit"]) for d in DRAFTS) | {"config/symbol_addrs.txt"} +BAK = {f: open(f).read() for f in TOUCHED if os.path.exists(f)} + +def restore_all(): + for f, c in BAK.items(): + open(f, "w").write(c) + +def apply_one(unit, sym, code, includes, wrap=True): + f = cfile(unit) + s = open(f).read() + line = f'INCLUDE_ASM("asm/nonmatchings/{unit}", {sym});' + if line not in s: + return False, "INCLUDE_ASM line not found" + if wrap: + # keep INCLUDE_ASM (asm target) + add C under SKIP_ASM (current) + repl = line + "\n#ifdef SKIP_ASM\n" + code.rstrip() + "\n#endif" + else: + repl = code # finalize: plain C replaces the stub + s = s.replace(line, repl, 1) + for inc in includes or []: + tok = inc.strip() + if not tok: + continue + directive = f"#include {tok}" + if directive not in s: + ms = list(re.finditer(r'^#include .*$', s, re.M)) + if ms: + pos = ms[-1].end() + s = s[:pos] + "\n" + directive + s[pos:] + else: + s = directive + "\n" + s + open(f, "w").write(s) + return True, "" + +def norm_disasm(obj, sym): + r = sh(f"mips-linux-gnu-objdump -dr {obj} 2>/dev/null") + out, p = [], False + for ln in r.stdout.splitlines(): + if re.search(rf"<{re.escape(sym)}>:", ln): + p = True; continue + if p and ln.strip() == "": + break + if p: + ln = re.sub(r'^\s*[0-9a-f]+:\s+[0-9a-f]{8}\s+', '', ln) + ln = re.sub(r'^\s*[0-9a-f]+: (R_MIPS)', r'\1', ln) + ln = re.sub(r'[0-9a-f]+ <', '<', ln) + ln = ln.strip() + if ln: + out.append(ln) + return out + +def current_symname(unit, sym): + if "__" in sym: + return sym + obj = f"obj/current/{objbase(unit)}.o" + r = sh(f"mips-linux-gnu-objdump -t {obj} 2>/dev/null") + for ln in r.stdout.splitlines(): + m = re.search(rf"\b({re.escape(sym)}__\S+)", ln) + if m and (" F " in ln or " g " in ln): + return m.group(1) + return sym # maybe extern "C" / unchanged + +def has_asm_callers(sym): + # any other .s referencing this raw symbol? + r = sh(f"grep -rl '\\b{re.escape(sym)}\\b' asm/nonmatchings/ 2>/dev/null") + files = [x for x in r.stdout.split() if not x.endswith(f"/{sym}.s")] + return len(files) > 0 + +def data_sec_size(obj): + # total size of allocatable non-.text sections (rodata/data/bss/sdata...) + r = sh(f"mips-linux-gnu-objdump -h {obj} 2>/dev/null") + tot = 0 + for ln in r.stdout.splitlines(): + m = re.match(r'\s*\d+\s+(\.\S+)\s+([0-9a-f]{8})', ln) + if m: + name, sz = m.group(1), int(m.group(2), 16) + if name == ".text" or name.startswith((".pdr", ".reginfo", ".comment", ".gnu", ".mdebug", ".debug")): + continue + tot += sz + return tot + +def verify(): + sh("source env/bin/activate; python3 configure.py --objects >/dev/null 2>&1") + # cache clean data-section sizes per unit + restore_all() + units = sorted(set(d["unit"] for d in DRAFTS)) + sh("source env/bin/activate; ninja " + " ".join(f"obj/current/{objbase(u)}.o" for u in units) + " 2>&1") + clean_size = {u: data_sec_size(f"obj/current/{objbase(u)}.o") for u in units} + results = [] + for d in DRAFTS: + unit, sym = d["unit"], d["sym"] + restore_all() + ok, msg = apply_one(unit, sym, d["code"], d.get("includes")) + if not ok: + results.append([unit, sym, "SKIP", msg]); continue + oc, ot = f"obj/current/{objbase(unit)}.o", f"obj/target/{objbase(unit)}.o" + b = sh(f"source env/bin/activate; ninja {oc} {ot} 2>&1") + if b.returncode != 0: + err = b.stdout.strip().splitlines()[-1] if b.stdout.strip() else "compile failed" + results.append([unit, sym, "COMPILE_FAIL", err[:160]]); continue + if data_sec_size(oc) != clean_size[unit]: + results.append([unit, sym, "DATA_GROWTH", "adds rodata/data -> layout ripple"]); continue + cs = current_symname(unit, sym) + dt, dc = norm_disasm(ot, sym), norm_disasm(oc, cs) + if dt and dt == dc: + tag = "MATCH" if "__" in sym else ("MATCH_FUN_CALLERS" if has_asm_callers(sym) else "MATCH_FUN") + results.append([unit, sym, tag, cs]) + else: + results.append([unit, sym, "DIFFER", f"t={len(dt)} c={len(dc)}"]) + restore_all() + json.dump(results, open("/tmp/verify_results.json", "w"), indent=0) + from collections import Counter + print(Counter(r[2] for r in results)) + for r in results: + print(r) + +def finalize(): + results = json.load(open("/tmp/verify_results.json")) + keep = {(r[0], r[1]): r for r in results if r[2] in ("MATCH", "MATCH_FUN")} + restore_all() + sa = open("config/symbol_addrs.txt").read() + for d in DRAFTS: + key = (d["unit"], d["sym"]) + if key not in keep: + continue + apply_one(d["unit"], d["sym"], d["code"], d.get("includes"), wrap=False) + r = keep[key] + if r[2] == "MATCH_FUN": # rename raw FUN_ -> mangled in symbol_addrs + raw, mangled = d["sym"], r[3] + sa = re.sub(rf'^{re.escape(raw)}(\s)', mangled + r'\1', sa, flags=re.M) + open("config/symbol_addrs.txt", "w").write(sa) + print("applied", len(keep), "keepers") + +if __name__ == "__main__": + (verify if len(sys.argv) < 2 or sys.argv[1] == "verify" else finalize)() diff --git a/scripts/decomp_lhf_draft.workflow.js b/scripts/decomp_lhf_draft.workflow.js new file mode 100644 index 00000000..b2c9bbb4 --- /dev/null +++ b/scripts/decomp_lhf_draft.workflow.js @@ -0,0 +1,73 @@ +export const meta = { + name: 'decomp-lhf-draft', + description: 'Draft matching C for tiny sly1 leaf functions (parallel, read-only)', + phases: [{ title: 'Draft' }], +} + +const cands = (typeof args === 'string' ? JSON.parse(args) : args) || [] +const BATCH = 4 +const batches = [] +for (let i = 0; i < cands.length; i += BATCH) batches.push(cands.slice(i, i + BATCH)) + +const SCHEMA = { + type: 'object', + additionalProperties: false, + properties: { + drafts: { + type: 'array', + items: { + type: 'object', + additionalProperties: false, + properties: { + unit: { type: 'string' }, + sym: { type: 'string' }, + code: { type: 'string' }, + includes: { type: 'array', items: { type: 'string' } }, + confidence: { type: 'number' }, + notes: { type: 'string' }, + }, + required: ['unit', 'sym', 'code', 'includes', 'confidence', 'notes'], + }, + }, + }, + required: ['drafts'], +} + +function draftPrompt(batch) { + const list = batch + .map((c) => `- unit "${c.unit}", symbol "${c.sym}" (asm: asm/nonmatchings/${c.unit}/${c.sym}.s, ~${c.n} instrs; source file: src/${c.unit}.c)`) + .join('\n') + return [ + 'You are decompiling TINY functions in the Sly 1 PS2 decomp at /home/johan/git/sly1 to C++ that compiles with EE GCC 2.95 to bytes IDENTICAL to the original MIPS assembly. Produce a matching C function for EACH candidate below.', + '', + 'Per candidate, do this:', + '1. Read asm/nonmatchings//.s. Work out EXACTLY what it does. Reg conventions: args $4=a0,$5=a1,$6=a2,$7=a3; float args $f12,$f14; int return in $2($v0); float return in $f0. daddu $2,$0,$0 => return 0; addiu $2,$0,1 => return 1.', + '2. Determine the signature. Demangle the symbol (e.g. Set...__FP9STEPGUARDf => void Set...(STEPGUARD*, float); __FP4ROST => (ROST*)). Cross-check the prototype in the unit header (grep the symbol base name under include/). For FUN_ names with no mangling, infer arg types from how regs are used and give the function the EXACT name FUN_xxxx; note that it will mangle (handled later).', + '3. Struct field access at offset 0xNN on a pointer: read the struct def. If a NAMED field already lands at that exact COMPILED offset, use it (verify with: scripts/structoff.sh \'(int)(long)&((TYPE*)0)->field\'). Otherwise use STRUCT_OFFSET(ptr, 0xNN, type) — macro in common.h: (*(type*)((uint8_t*)(ptr)+(offset))). MATCH THE WIDTH: lb=>char, lbu=>uchar, lh=>short, lhu=>ushort, lw/sw=>int (or a pointer/float type per use), ld/sd=>64-bit (use long long/uint64_t), lq/sq=>16-byte qword copy (use a 16-byte type; lower your confidence and explain in notes).', + '4. Float ops: a float field read/returned => float type. Compares/moves => mirror them.', + '5. Output the FULL C function definition that REPLACES this exact line in src/.c: INCLUDE_ASM("asm/nonmatchings/", );', + '6. In "includes": list ONLY header tokens (e.g. "") needed that are NOT already #included at the top of src/.c (read that file to check). Prefer adding nothing.', + '', + 'HARD RULES:', + '- DO NOT modify any struct/header, DO NOT add or grow struct fields. Use STRUCT_OFFSET for unnamed fields.', + '- DO NOT run ninja, configure.py, scripts/match.sh, or build/link ANYTHING (builds are serialized by the caller). You MAY run scripts/structoff.sh (it only writes /tmp) and read any file.', + '- Keep the C as direct as the asm (GCC 2.95 is literal). Mirror operation order.', + '- confidence: 0..1 (1 = you are sure it is a byte-exact match). Put any risk in notes (esp. lq/sq, float, or guessed FUN_ signatures).', + '', + 'Candidates:', + list, + '', + 'Return every candidate as a draft via the schema (one entry per candidate, even low-confidence ones).', + ].join('\n') +} + +phase('Draft') +const results = await parallel( + batches.map((b, i) => () => + agent(draftPrompt(b), { label: `draft#${i + 1} [${b.length}]`, phase: 'Draft', schema: SCHEMA }) + ) +) + +const drafts = results.filter(Boolean).flatMap((r) => (r && r.drafts) || []) +log(`drafted ${drafts.length} / ${cands.length} functions`) +return { drafts } From 2fcad9e89723b94fe010f6a0d407aef77281e7ae Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 20:18:27 +0200 Subject: [PATCH 004/134] Match AddWaterExternalAccelerations and zpd-reset helper in water.c AddWaterExternalAccelerations dispatches through the SO vtable (offset 0x128) via STRUCT_OFFSET; FUN_001ef830 clears zpd.cploThrow. Annotate the remaining INCLUDE_ASM stubs with why they're deferred (VU0 SIMD, or permuter-class codegen for PostWaterLoad/HandleWaterMessage). Co-Authored-By: Claude Opus 4.8 --- config/symbol_addrs.txt | 2 +- src/P2/water.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 887e2713..d6daaa5a 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -4971,7 +4971,7 @@ UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2 = 0x1EF5B8; // type:func UpdateWaterBounds__FP5WATER = 0x1EF768; // type:func FInflictWaterZap__FP5WATERP2XPP3ZPR = 0x1EF808; // type:func PzpdEnsureWater__FP5WATER4ENSK = 0x1EF828; // type:func -FUN_001ef830 = 0x1EF830; // type:func +FUN_001ef830__FP5WATER = 0x1EF830; // type:func //////////////////////////////////////////////////////////////// diff --git a/src/P2/water.c b/src/P2/water.c index ea9a29a4..a72fbebe 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -1,5 +1,6 @@ #include #include +#include void InitWater(WATER *pwater) { @@ -17,8 +18,11 @@ void InitWater(WATER *pwater) pwater->zpd.zpk = ZPK_Water; } +// TODO: logic matches except the DLI-prologue (s_pdliFirst push) store/load +// scheduling; needs decomp-permuter to settle the instruction order. INCLUDE_ASM("asm/nonmatchings/P2/water", PostWaterLoad__FP5WATER); +// TODO: blocked on VU0 SIMD (lqc2/sqc2/vadd) — no VU0 intrinsic infra yet. INCLUDE_ASM("asm/nonmatchings/P2/water", CalculateWaterCurrent__FP5WATERP6VECTORN21); void UpdateSwXaList(SW *psw, XA **ppxa) @@ -64,10 +68,18 @@ void UpdateSwXaList(SW *psw, XA **ppxa) FreeSwXaList(psw, pxaFree); } +// TODO: blocked on VU0 SIMD (lqc2/sqc2/vsub/vadd) + ~16KB — no VU0 infra yet. INCLUDE_ASM("asm/nonmatchings/P2/water", UpdateWater__FP5WATERf); -INCLUDE_ASM("asm/nonmatchings/P2/water", AddWaterExternalAccelerations__FP5WATERP2XAf); +void AddWaterExternalAccelerations(WATER *pwater, XA *pxa, float dt) +{ + SO *pso = pxa->pso; + ((void (*)(SO *, WATER *))STRUCT_OFFSET(pso->pvtlo, 0x128, void *))(pso, pwater); +} +// TODO: logic matches except the find-one XA loop's gcc form (peeling + +// *ppxa reload); needs decomp-permuter. Handler: MSGID_removed drops the +// object(s) from the XA list and sends MSGID_water_left via pfnSendLoMessage. INCLUDE_ASM("asm/nonmatchings/P2/water", HandleWaterMessage__FP5WATER5MSGIDPv); void UpdateWaterMergeGroup(WATER *pwater) @@ -93,8 +105,10 @@ void UpdateWaterMergeGroup(WATER *pwater) AddSwMergeGroup(pwater->psw, pmrg); } +// TODO: blocked on VU0 SIMD (lqc2/qmtc2/vmulax/vmaddx) — no VU0 infra yet. INCLUDE_ASM("asm/nonmatchings/P2/water", UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2); +// TODO: blocked on VU0 SIMD (vmul/vsqrt/lqc2/sqc2 bounds math) — no VU0 infra yet. INCLUDE_ASM("asm/nonmatchings/P2/water", UpdateWaterBounds__FP5WATER); int FInflictWaterZap(WATER *pwater, XP *pxp, ZPR *pzpr) @@ -108,4 +122,7 @@ ZPD *PzpdEnsureWater(WATER *pwater, ENSK ensk) return &pwater->zpd; } -INCLUDE_ASM("asm/nonmatchings/P2/water", FUN_001ef830); +void FUN_001ef830(WATER *pwater) +{ + pwater->zpd.cploThrow = 0; +} From 19bb0952d40f4a1c5b258342688a978b0644aa14 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 20:18:27 +0200 Subject: [PATCH 005/134] Match alo/so/sw object accessors (25 functions) Small getters/setters and helpers on ALO/SO/SW: interact/look-at/throb/ack accessors, FInflictSoZap, UpdateSoPosWorldPrev, and SW list/world helpers. Base-struct fields past the truncated structs are reached via STRUCT_OFFSET. Co-Authored-By: Claude Opus 4.8 --- config/symbol_addrs.txt | 16 +++---- src/P2/alo.c | 94 ++++++++++++++++++++++++++++++++++------- src/P2/so.c | 17 ++++++-- src/P2/sw.c | 41 +++++++++++++++--- 4 files changed, 135 insertions(+), 33 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index d6daaa5a..e33102fd 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -804,7 +804,7 @@ FUN_0012a810 = 0x12A810; // type:f FUN_0012a848 = 0x12A848; // type:func FUN_0012a860 = 0x12A860; // type:func FUN_0012a888 = 0x12A888; // type:func -FUN_0012a8b8 = 0x12A8B8; // type:func +FUN_0012a8b8__FP3ALO = 0x12A8B8; // type:func FUN_0012a8c8 = 0x12A8C8; // type:func SetAloRotationMatchesVelocity__FP3ALOff3ACK = 0x12A8D8; // type:func PtargetEnsureAlo__FP3ALO = 0x12A970; // type:func @@ -4548,8 +4548,8 @@ SetupBulkDataFromBrx__FiP18CBinaryInputStream = 0x1DB928; // LoadBulkDataFromBrx__FP18CBinaryInputStream = 0x1DBA38; // type:func SetSwGravity__FP2SWf = 0x1DBA90; // type:func FUN_001dbac0 = 0x1DBAC0; // type:func -FUN_001dbae0 = 0x1DBAE0; // type:func -FUN_001dbb00 = 0x1DBB00; // type:func +FUN_001dbae0__FP2SWi = 0x1DBAE0; // type:func +FUN_001dbb00__FP2SWii = 0x1DBB00; // type:func FOverflowSwLo__FP2SWP2LOi = 0x1DBB20; // type:func PxaAllocSw__FP2SW = 0x1DBB50; // type:func FreeSwXaList__FP2SWP2XA = 0x1DBB90; // type:func @@ -4590,12 +4590,12 @@ FUN_001dd758 = 0x1DD758; // FUN_001dd7a0 = 0x1DD7A0; // type:func FUN_001dd7e8 = 0x1DD7E8; // type:func FUN_001dd888 = 0x1DD888; // type:func -FUN_001dd8e8 = 0x1DD8E8; // type:func -FUN_001dd908 = 0x1DD908; // type:func +FUN_001dd8e8__FP2SW9GAMEWORLD = 0x1DD8E8; // type:func +FUN_001dd908__FP2SW9GAMEWORLD = 0x1DD908; // type:func FUN_001dd928 = 0x1DD928; // type:func FUN_001dd950 = 0x1DD950; // type:func -FUN_001dd9a0 = 0x1DD9A0; // type:func -FUN_001dd9c0 = 0x1DD9C0; // type:func +FUN_001dd9a0__Ff = 0x1DD9A0; // type:func +FUN_001dd9c0__FPvPf = 0x1DD9C0; // type:func SetSwPlayerSuck__FP2SWf = 0x1DD9D8; // type:func GetSwPlayerSuck__FP2SWPf = 0x1DDA08; // type:func IncrementSwHandsOff__FP2SW = 0x1DDA20; // type:func @@ -4612,7 +4612,7 @@ FUN_001ddbf8 = 0x1DDBF8; // FUN_001ddc18 = 0x1DDC18; // type:func FUN_001ddc38 = 0x1DDC38; // type:func FUN_001ddc40 = 0x1DDC40; // type:func -FUN_001ddc78 = 0x1DDC78; // type:func +FUN_001ddc78__FPvi = 0x1DDC78; // type:func FUN_001ddc90 = 0x1DDC90; // type:func FUN_001ddcb0 = 0x1DDCB0; // type:func FUN_001ddcc8 = 0x1DDCC8; // type:func diff --git a/src/P2/alo.c b/src/P2/alo.c index 9c81f639..05346221 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -378,9 +378,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSmoothMaxAccel__FP3ALOf); INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSmoothDetail__FP3ALOP4SMPA); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloDefaultAckPos__FP3ALO3ACK); +void SetAloDefaultAckPos(ALO *palo, ACK ack) +{ + STRUCT_OFFSET(palo, 0x2c9, char) = ack; +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloDefaultAckRot__FP3ALO3ACK); +void SetAloDefaultAckRot(ALO *palo, ACK ack) +{ + STRUCT_OFFSET(palo, 0x2ca, char) = ack; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestorePosition__FP3ALOi); @@ -402,7 +408,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAt__FP3ALO3ACK); INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtIgnore__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtIgnore__FP3ALOPf); +void GetAloLookAtIgnore(ALO *palo, float *psIgnore) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + float sIgnore = 0.0f; + + if (pactla) + sIgnore = STRUCT_OFFSET(pactla, 0x40, float); + + *psIgnore = sIgnore; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtPanFunction__FP3ALOP3CLQ); @@ -422,11 +437,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtTiltLimits__FP3ALOP2LM); INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtEnabledPriority__FP3ALOi); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtEnabledPriority__FP3ALOPi); +void GetAloLookAtEnabledPriority(ALO *palo, int *pnPriority) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + int nPriority = 0; + + if (pactla) + nPriority = STRUCT_OFFSET(pactla, 0x44, int); + + *pnPriority = nPriority; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtDisabledPriority__FP3ALOi); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtDisabledPriority__FP3ALOPi); +void GetAloLookAtDisabledPriority(ALO *palo, int *pnPriority) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + int nPriority = 0; + + if (pactla) + nPriority = STRUCT_OFFSET(pactla, 0x48, int); + + *pnPriority = nPriority; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a810); @@ -436,7 +469,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a860); INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a888); -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a8b8); +void FUN_0012a8b8(ALO *palo) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void*); + STRUCT_OFFSET(pactla, 0x4C, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a8c8); @@ -650,19 +687,40 @@ void GetAloThrobDtInOut(ALO *palo, float *pdtInOut) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloInteractCane__FP3ALOi); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloInteractCane__FP3ALOPi); +void GetAloInteractCane(ALO *palo, GRFIC *pgrfic) +{ + *pgrfic = STRUCT_OFFSET(palo, 0x2B0, uchar); +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloInteractCaneSweep__FP3ALOi); +void SetAloInteractCaneSweep(ALO *palo, GRFIC grfic) +{ + STRUCT_OFFSET(palo, 0x2b0, char) = grfic; +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloInteractCaneSweep__FP3ALOPi); +void GetAloInteractCaneSweep(ALO *palo, GRFIC *pgrfic) +{ + *pgrfic = STRUCT_OFFSET(palo, 0x2B0, uchar); +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloInteractCaneRush__FP3ALOi); +void SetAloInteractCaneRush(ALO *palo, GRFIC grfic) +{ + STRUCT_OFFSET(palo, 0x2b1, char) = grfic; +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloInteractCaneRush__FP3ALOPi); +void GetAloInteractCaneRush(ALO *palo, GRFIC *pgrfic) +{ + *pgrfic = STRUCT_OFFSET(palo, 0x2B1, uchar); +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloInteractCaneSmash__FP3ALOi); +void SetAloInteractCaneSmash(ALO *palo, GRFIC grfic) +{ + STRUCT_OFFSET(palo, 0x2b2, char) = grfic; +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloInteractCaneSmash__FP3ALOPi); +void GetAloInteractCaneSmash(ALO *palo, GRFIC *pgrfic) +{ + *pgrfic = STRUCT_OFFSET(palo, 0x2B2, uchar); +} void SetAloInteractBomb(ALO *palo, GRFIC grfic) { @@ -674,9 +732,15 @@ void GetAloInteractBomb(ALO *palo, GRFIC *pgrfic) *pgrfic = STRUCT_OFFSET(palo, 0x2B3, uchar); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloInteractShock__FP3ALOi); +void SetAloInteractShock(ALO *palo, GRFIC grfic) +{ + STRUCT_OFFSET(palo, 0x2b4, char) = grfic; +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloInteractShock__FP3ALOPi); +void GetAloInteractShock(ALO *palo, GRFIC *pgrfic) +{ + *pgrfic = STRUCT_OFFSET(palo, 0x2B4, uchar); +} int FAbsorbAloWkr(ALO *palo, WKR *pwkr) { diff --git a/src/P2/so.c b/src/P2/so.c index 9e2f3a98..b274c936 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -129,7 +129,12 @@ void AddSoExternalAccelerations(SO *pso, XA *pxa, float dt) INCLUDE_ASM("asm/nonmatchings/P2/so", LoadSoFromBrx__FP2SOP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoSphere__FP2SOf); +void SetSoSphere(SO *pso, float sRadius) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + STRUCT_OFFSET(pso, 0x3CC, float) = sRadius; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso | 0x10000000000; +} void SetSoNoInteract(SO *pso, int fNoInteract) { @@ -148,7 +153,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoIgnoreLocked__FP2SOi); INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoIceable__FP2SOi); -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoMtlk__FP2SO4MTLK); +void SetSoMtlk(SO *pso, MTLK mtlk) +{ + STRUCT_OFFSET(pso, 0x2c8, char) = mtlk; +} INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoEdgeGrab__FP2SO3EGK); @@ -178,7 +186,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", FSoInStsoList__FP4STSOP2SO); INCLUDE_ASM("asm/nonmatchings/P2/so", GenerateSoSpliceTouchingEvents__FP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/so", FInflictSoZap__FP2SOP2XPP3ZPR); +int FInflictSoZap(SO *pso, XP *pxp, ZPR *pzpr) +{ + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/so", EnsureSoLvo__FP2SO); diff --git a/src/P2/sw.c b/src/P2/sw.c index 76db9e23..e4f601de 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -6,6 +6,8 @@ #include #include <989snd.h> #include +#include +#include extern SW *g_psw; extern int g_fLoadDebugInfo; @@ -46,9 +48,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", SetSwGravity__FP2SWf); INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dbac0); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dbae0); +extern "C" int FUN_001c0c50(int reg); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dbb00); +int FUN_001dbae0(SW *psw, int reg) +{ + return FUN_001c0c50(reg); +} + +extern "C" void FUN_001c0c68(int reg, int value); + +void FUN_001dbb00(SW *psw, int reg, int value) +{ + FUN_001c0c68(reg, value); +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FOverflowSwLo__FP2SWP2LOi); @@ -243,17 +255,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7e8); INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd888); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd8e8); +int FUN_001dd8e8(SW *psw, GAMEWORLD gameworld) +{ + return g_pgsCur->aws[gameworld].fws & 0x1; +} -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd908); +int FUN_001dd908(SW *psw, GAMEWORLD gameworld) +{ + return g_pgsCur->aws[gameworld].fws & 0x20; +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd928); INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd950); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd9a0); +void FUN_001dd9a0(float nParam) +{ + ChangeSuck(nParam, &g_difficulty); +} -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd9c0); +void FUN_001dd9c0(void *pv, float *pu) +{ + *pu = g_plsCur->uSuck; +} void SetSwPlayerSuck(SW *psw, float uSuck) { @@ -327,7 +351,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc38); INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc40); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc78); +void FUN_001ddc78(void *pv, int n) +{ + STRUCT_OFFSET(pv, 0x235C, int) |= (1 << n); +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc90); From 49923bd5c629868b7020ae2197855d6f6226eb0f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 20:18:38 +0200 Subject: [PATCH 006/134] Match assorted P2 leaf functions (22 functions) Small wrappers/getters/setters across act, chkpnt, cplcy, difficulty, dmas, path, po, puffer, pzo, rog, sb, sensor, stepguard, and xform, drafted by the batch workflow and verified byte-exact (instructions + relocations). Co-Authored-By: Claude Opus 4.8 --- config/symbol_addrs.txt | 16 ++++++++-------- src/P2/act.c | 16 +++++++++++++--- src/P2/chkpnt.c | 5 ++++- src/P2/cplcy.c | 14 +++++++++++--- src/P2/difficulty.c | 5 ++++- src/P2/dmas.c | 7 ++++++- src/P2/path.c | 15 +++++++++++++-- src/P2/po.c | 5 ++++- src/P2/puffer.c | 5 ++++- src/P2/pzo.c | 6 +++++- src/P2/rog.c | 5 ++++- src/P2/sb.c | 7 ++++++- src/P2/sensor.c | 5 ++++- src/P2/stepguard.c | 23 +++++++++++++++++++---- src/P2/xform.c | 7 ++++++- 15 files changed, 111 insertions(+), 30 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index e33102fd..312eae4f 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -1309,7 +1309,7 @@ FUN_001417f0 = 0x1417F0; // type:func TriggerChkpnt__FP6CHKPNT = 0x141870; // type:func FUN_001419A0 = 0x1419A0; // type:func FUN_001419C0 = 0x1419C0; // type:func -FUN_001419E0 = 0x1419E0; // type:func +FUN_001419E0__FPii = 0x1419E0; // type:func g_chkmgr = 0x261420; // size:0x430 @@ -1531,7 +1531,7 @@ s_asnipDprize = 0x2619A0; // size:0x3c InitCplcy = 0x149398; // type:func FActiveCplcy = 0x1493A0; // type:func SetCpmanCpmt = 0x1493B8; // type:func -FUN_001493c0 = 0x1493C0; // type:func +FUN_001493c0__Fv = 0x1493C0; // type:func PosCplookAnchor = 0x1493C8; // type:func FUN_00149458 = 0x149458; // type:func plays_binoc_sfx = 0x149508; // type:func @@ -1545,8 +1545,8 @@ FUN_0014a7b8 = 0x14A7B8; // type:func InitCpalign = 0x14A888; // type:func FUN_0014a8d0 = 0x14A8D0; // type:func UpdateCpalign = 0x14A8F8; // type:func -FUN_0014aa90 = 0x14AA90; // type:func -FUN_0014aa98 = 0x14AA98; // type:func +FUN_0014aa90__FPii = 0x14AA90; // type:func +FUN_0014aa98__FPv = 0x14AA98; // type:func UpdateCpaseg = 0x14AAA0; // type:func @@ -1726,7 +1726,7 @@ g_pdialogPlaying = 0x27051C; // P2/difficulty.c //////////////////////////////////////////////////////////////// PdifficultyEnsureSw = 0x1519E0; // type:func -FUN_00151A58 = 0x151A58; // type:func +FUN_00151A58__Fv = 0x151A58; // type:func OnDifficultyGameLoad__FP10DIFFICULTY = 0x151A68; // type:func OnDifficultyWorldPreLoad = 0x151A88; // type:func OnDifficultyWorldPostLoad = 0x151D28; // type:func @@ -3069,7 +3069,7 @@ FUN_00192a70 = 0x192A70; // type:func UpdatePo__FP2POf = 0x192B58; // type:func UsePoCharm__FP2PO = 0x192C58; // type:func FUN_00192dd0 = 0x192DD0; // type:func -FUN_001930B0 = 0x1930B0; // type:func +FUN_001930B0__FP2PO = 0x1930B0; // type:func po__static_initialization_and_destruction_04 = 0x1930B8; // type:func _GLOBAL_$I$InitPo__FP2PO = 0x1931F0; // type:func @@ -3548,7 +3548,7 @@ OnSbgEnteringSgs__FP3SBG3SGSP4ASEG = 0x1A99F8; // type:func UpdateSbg__FP3SBGf = 0x1A9A40; // type:func FUN_001a9a98 = 0x1A9A98; // type:func FAbsorbSbgWkr__FP3SBGP3WKR = 0x1A9AE8; // type:func -FUN_001a9c58 = 0x1A9C58; // type:func +FUN_001a9c58__FP3SBGiii = 0x1A9C58; // type:func //////////////////////////////////////////////////////////////// @@ -5084,7 +5084,7 @@ CloneWarp__FP4WARPT0 = 0x1F3EE0; // type:func PostWarpLoad__FP4WARP = 0x1F3F80; // type:func TriggerWarp__FP4WARP = 0x1F4008; // type:func SetWarpRsmg__FP4WARPi3OIDN22 = 0x1F42D0; // type:func -FUN_001F4308 = 0x1F4308; // type:func +FUN_001F4308__FP4WARPf = 0x1F4308; // type:func TeleportSwPlayer__FP2SW3OIDT1 = 0x1F4318; // type:func PexitDefault__Fv = 0x1F4378; // type:func TriggerDefaultExit__Fi5WIPEK = 0x1F4408; // type:func diff --git a/src/P2/act.c b/src/P2/act.c index 1cb564d3..c5a0b97f 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -14,11 +14,18 @@ INCLUDE_ASM("asm/nonmatchings/P2/act", GetActPositionGoal__FP3ACTfP6VECTORT2); INCLUDE_ASM("asm/nonmatchings/P2/act", GetActRotationGoal__FP3ACTfP7MATRIX3P6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/act", GetActTwistGoal__FP3ACTPfT1); +void GetActTwistGoal(ACT *pact, float *pradTwist, float *pdradTwist) +{ + *pradTwist = STRUCT_OFFSET(STRUCT_OFFSET(pact->palo, 0x224, uint8_t *), 0x8c, float); + *(int *)pdradTwist = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/act", GetActScale__FP3ACTP7MATRIX3); -INCLUDE_ASM("asm/nonmatchings/P2/act", GGetActPoseGoal__FP3ACTi); +float GGetActPoseGoal(ACT *pact, int ipose) +{ + return STRUCT_OFFSET(pact->palo, 0x274, float*)[ipose]; +} INCLUDE_ASM("asm/nonmatchings/P2/act", CalculateActDefaultAck__FP3ACT); @@ -73,7 +80,10 @@ void GetActrefTwistGoal(ACTREF *pactref, float *pradTwist, float *pdradTwist) INCLUDE_ASM("asm/nonmatchings/P2/act", GetActrefScale__FP6ACTREFP7MATRIX3); -INCLUDE_ASM("asm/nonmatchings/P2/act", GGetActrefPoseGoal__FP6ACTREFi); +float GGetActrefPoseGoal(ACTREF *pactref, int ipose) +{ + return STRUCT_OFFSET(pactref, 0x3c, float*)[ipose]; +} INCLUDE_ASM("asm/nonmatchings/P2/act", InitActadj__FP6ACTADJP3ALO); diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index 8a88840e..b94b0b02 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -73,4 +73,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001419A0); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001419C0); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001419E0); +void FUN_001419E0(int *param_1, int param_2) +{ + param_1[0x168] = param_2; +} diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index 0ad9e4cf..93b29f9c 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -9,7 +9,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FActiveCplcy); INCLUDE_ASM("asm/nonmatchings/P2/cplcy", SetCpmanCpmt); -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_001493c0); +void FUN_001493c0(void) +{ +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", PosCplookAnchor); @@ -37,8 +39,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_0014a8d0); INCLUDE_ASM("asm/nonmatchings/P2/cplcy", UpdateCpalign); -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_0014aa90); +void FUN_0014aa90(int *param_1, int param_2) +{ + param_1[2] = param_2; +} -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_0014aa98); +void FUN_0014aa98(void *p) +{ + STRUCT_OFFSET(p, 0x8, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", UpdateCpaseg); diff --git a/src/P2/difficulty.c b/src/P2/difficulty.c index 25f82a98..4fe892f3 100644 --- a/src/P2/difficulty.c +++ b/src/P2/difficulty.c @@ -6,7 +6,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/difficulty", PdifficultyEnsureSw); -INCLUDE_ASM("asm/nonmatchings/P2/difficulty", FUN_00151A58); +DIFFICULTY *FUN_00151A58() +{ + return &g_difficulty; +} void OnDifficultyGameLoad(DIFFICULTY *pdifficulty) { diff --git a/src/P2/dmas.c b/src/P2/dmas.c index 8c3408b7..a6f00721 100644 --- a/src/P2/dmas.c +++ b/src/P2/dmas.c @@ -46,7 +46,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/dmas", AllocSw__4DMASii); INCLUDE_ASM("asm/nonmatchings/P2/dmas", AllocStack__4DMASi); -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AllocStatic__4DMASiP2QW); +void DMAS::AllocStatic(int c, QW *aqw) +{ + m_ab = (uchar *)aqw; + m_pb = (uchar *)aqw; + m_pbMax = (uchar *)(aqw + c); +} void DMAS::Detach(int *pcqw, QW **paqw) { diff --git a/src/P2/path.c b/src/P2/path.c index 7e90cd89..b06e0c4b 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -1,6 +1,11 @@ #include -INCLUDE_ASM("asm/nonmatchings/P2/path", PcbspExtract__FP4CBSP); +struct CBSP; + +CBSP* PcbspExtract(CBSP* pcbsp) +{ + return ((int)pcbsp & 1) ? (CBSP*)0 : pcbsp; +} INCLUDE_ASM("asm/nonmatchings/P2/path", PcgtExtract__FP3CGT); @@ -14,7 +19,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/path", ClsgClipEdgeToCbsp__FP4CBSPP6VECTORT1iP3 INCLUDE_ASM("asm/nonmatchings/P2/path", FClipEdgeToCbsp__FP4CBSPP6VECTORT1); -INCLUDE_ASM("asm/nonmatchings/P2/path", IcgvFromPcgv__FP2CGP3CGV); +struct CG; +struct CGV; + +int IcgvFromPcgv(CG* pcg, CGV* pcgv) +{ + return ((int)pcgv - STRUCT_OFFSET(pcg, 0x4, int)) >> 5; +} INCLUDE_ASM("asm/nonmatchings/P2/path", FindPathAStar__FP2CGP3CGVT1iPiPP3CGV); diff --git a/src/P2/po.c b/src/P2/po.c index 4212d835..41a6aa95 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -135,7 +135,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/po", UsePoCharm__FP2PO); INCLUDE_ASM("asm/nonmatchings/P2/po", FUN_00192dd0); -INCLUDE_ASM("asm/nonmatchings/P2/po", FUN_001930B0); +PO *FUN_001930B0(PO *ppo) +{ + return ppo; +} INCLUDE_ASM("asm/nonmatchings/P2/po", po__static_initialization_and_destruction_04); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 28e6fa97..88074559 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -52,7 +52,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", HandlePuffcMessage__FP5PUFFC5MSGIDPv); INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffc__FP5PUFFCf); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", FCanPuffcAttack__FP5PUFFC); +int FCanPuffcAttack(PUFFC *ppuffc) +{ + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00198860); diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 4e91c2af..8f869656 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/pzo", InitSprize__FP6SPRIZE); @@ -175,7 +176,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", RenderClueAll__FP4CLUEP2CMP2RO); INCLUDE_ASM("asm/nonmatchings/P2/pzo", CollectAllClues__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", SetGrfvault__Fi); +void SetGrfvault(int grfvault) +{ + g_pgsCur->grfvault = grfvault; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", FUN_0019a000); diff --git a/src/P2/rog.c b/src/P2/rog.c index 2f73f30b..467e9993 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -204,7 +204,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRostLoad__FP4ROST); INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRost__FP4ROSTf); -INCLUDE_ASM("asm/nonmatchings/P2/rog", RostsNextRost__FP4ROST); +ROSTS RostsNextRost(ROST *prost) +{ + return STRUCT_OFFSET(prost, 0x550, ROSTS); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRostRosts__FP4ROST5ROSTS); diff --git a/src/P2/sb.c b/src/P2/sb.c index 2f35cca8..05e26cc1 100644 --- a/src/P2/sb.c +++ b/src/P2/sb.c @@ -25,4 +25,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/sb", FUN_001a9a98); INCLUDE_ASM("asm/nonmatchings/P2/sb", FAbsorbSbgWkr__FP3SBGP3WKR); -INCLUDE_ASM("asm/nonmatchings/P2/sb", FUN_001a9c58); +void FUN_001a9c58(SBG *psbg, int a, int b, int c) +{ + STRUCT_OFFSET(psbg, 0xC14, int) = a; + STRUCT_OFFSET(psbg, 0xC18, int) = b; + STRUCT_OFFSET(psbg, 0xC1C, int) = c; +} diff --git a/src/P2/sensor.c b/src/P2/sensor.c index a4d280ab..f385fb4e 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -205,7 +205,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateCamsen__FP6CAMSENf); INCLUDE_ASM("asm/nonmatchings/P2/sensor", RenderCamsenSelf__FP6CAMSENP2CMP2RO); -INCLUDE_ASM("asm/nonmatchings/P2/sensor", FIgnoreCamsenIntersection__FP6CAMSENP2SO); +int FIgnoreCamsenIntersection(CAMSEN *pcamsen, SO *psoOther) +{ + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", FFilterCamsen__FPvP2SO); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 655aa512..766db3be 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -173,9 +173,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PasegFindStepguard__FP9STEPGUARD3OI INCLUDE_ASM("asm/nonmatchings/P2/stepguard", LoadStepguardAnimations__FP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardExpl__FP9STEPGUARD3OID); +void UseStepguardExpl(STEPGUARD *pstepguard, OID oidExpl) +{ + STRUCT_OFFSET(pstepguard, 0xafc, OID) = oidExpl; + STRUCT_OFFSET(pstepguard, 0xaf8, int) = 1; +} -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardRwm__FP9STEPGUARD3OID); +void UseStepguardRwm(STEPGUARD *pstepguard, OID oidRwm) +{ + STRUCT_OFFSET(pstepguard, 0xb08, OID) = oidRwm; + STRUCT_OFFSET(pstepguard, 0xb04, int) = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardPhys__FP9STEPGUARD3SGS3OID); @@ -189,7 +197,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PsoEnemyStepguard__FP9STEPGUARD); INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001caad0); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SetStepguardEnemyObject__FP9STEPGUARDP2SO); +void SetStepguardEnemyObject(STEPGUARD *pstepguard, SO *psoEnemy) +{ + STRUCT_OFFSET(pstepguard, 0xB48, SO *) = psoEnemy; + STRUCT_OFFSET(pstepguard, 0xB40, int) = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", RebindStepguardEnemy__FP9STEPGUARD); @@ -199,7 +211,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001cac30); INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AdjustStepguardDz__FP9STEPGUARDiP2DZif); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SetStepguardAttackAngleMax__FP9STEPGUARDf); +void SetStepguardAttackAngleMax(STEPGUARD *pstepguard, float degAttackMax) +{ + STRUCT_OFFSET(pstepguard, 0x74c, float) = degAttackMax * 0.017453294f; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddStepguardAlarm__FP9STEPGUARDP5ALARM); diff --git a/src/P2/xform.c b/src/P2/xform.c index c33a3878..353243a2 100644 --- a/src/P2/xform.c +++ b/src/P2/xform.c @@ -54,7 +54,12 @@ void SetWarpRsmg(WARP *pwarp, int fOnTrigger, OID oidRoot, OID oidSM, OID oidGoa FAddRsmg(&STRUCT_OFFSET(pwarp, 0xb8, RSMG), 4, &STRUCT_OFFSET(pwarp, 0xb4, int), fOnTrigger, oidRoot, oidSM, oidGoal); } -INCLUDE_ASM("asm/nonmatchings/P2/xform", FUN_001F4308); +int FUN_001F4308(WARP *pwarp, float g) +{ + STRUCT_OFFSET(pwarp, 0x9c, float) = g; + STRUCT_OFFSET(pwarp, 0x98, int) = 1; + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/xform", TeleportSwPlayer__FP2SW3OIDT1); From e7f95550b115f2550bef3402dc0735e8a1702a3b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 23:25:53 +0200 Subject: [PATCH 007/134] Fix VU_VECTOR to a 128-bit quadword; match ClipVismapSphereOneHop VU_VECTOR was a 2-byte stub { ushort data; }, so passing it by value compiled to lhu instead of lq. It is a 128-bit VU quadword passed in a single 128-bit GP register, so define it as { qword data; } (TImode, 16 bytes, 16-aligned). Kept as a struct named VU_VECTOR to preserve the 9VU_VECTOR by-value mangling. This resolves the long-standing 89.47% "single load mismatch" in ClipVismapSphereOneHop, now matched as plain C. VU_VECTOR is only used by value in signatures (never embedded), so the size change ripples nothing. Co-Authored-By: Claude Opus 4.8 --- include/vec.h | 5 +++-- src/P2/vis.c | 7 ------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/include/vec.h b/include/vec.h index cd50c93f..681b12f1 100644 --- a/include/vec.h +++ b/include/vec.h @@ -25,11 +25,12 @@ struct VECTOR4 }; /** - * @todo Should be 16-byte aligned. + * @brief 128-bit VU quadword vector (x, y, z, w), 16-byte aligned. Passed by + * value in a single 128-bit GP register and loaded/stored with lq/sq. */ struct VU_VECTOR { - ushort data; + qword data; }; /** diff --git a/src/P2/vis.c b/src/P2/vis.c index ce057016..35db162a 100644 --- a/src/P2/vis.c +++ b/src/P2/vis.c @@ -45,12 +45,6 @@ GRFZON GrfzonOneHop(VISMAP *pvismap, VBSP *pvbsp) INCLUDE_ASM("asm/nonmatchings/P2/vis", ClipVbspSphereOneHop__FP6VISMAPP4VBSPG9VU_VECTORfPi); -/** - * @brief 89.47% match. Single load instruction mismatch. VU_VECTOR implemented wrong? - * https://decomp.me/scratch/5lzfX - */ -INCLUDE_ASM("asm/nonmatchings/P2/vis", ClipVismapSphereOneHop__FP6VISMAPP6VECTORfPi); -#ifdef SKIP_ASM void ClipVismapSphereOneHop(VISMAP *pvismap, VECTOR *ppos, float sRadius, GRFZON *pgrfzon) { if (pvismap && pvismap->avbsp) @@ -63,6 +57,5 @@ void ClipVismapSphereOneHop(VISMAP *pvismap, VECTOR *ppos, float sRadius, GRFZON *pgrfzon = 0xfffffff; } -#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/vis", ClipVismapPointNoHop__FP6VISMAPP6VECTORPi); From 6e3b2334e0844532d55bfc720cd268e0c2c4c20a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 23:32:04 +0200 Subject: [PATCH 008/134] Fix VU_FLOAT to a 128-bit quadword VU_FLOAT was a 2-byte stub { uint16_t data; }; like VU_VECTOR it is a 128-bit VU scalar (the VU_FLOAT(float) ctor stores it with sq, and it is passed by value in a single 128-bit GP register). Define it as { qword data; }. Used only by value in signatures, so the size change ripples nothing; full checksum OK. Co-Authored-By: Claude Opus 4.8 --- include/blip.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/blip.h b/include/blip.h index 875991e4..f244879d 100644 --- a/include/blip.h +++ b/include/blip.h @@ -20,11 +20,13 @@ struct RPL; typedef int GRFZON; /** + * @brief 128-bit VU scalar (the value lives in the x lane), 16-byte aligned. + * Passed by value in a single 128-bit GP register and stored with sq. * @todo Move elsewhere? */ struct VU_FLOAT { - uint16_t data; + qword data; }; /** From 310ddbf9bdad4113d1052f9b63a5cbd9eb4fcd0f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 23:25:53 +0200 Subject: [PATCH 009/134] Fix VU_VECTOR to a 128-bit quadword; match ClipVismapSphereOneHop VU_VECTOR was a 2-byte stub { ushort data; }, so passing it by value compiled to lhu instead of lq. It is a 128-bit VU quadword passed in a single 128-bit GP register, so define it as { qword data; } (TImode, 16 bytes, 16-aligned). Kept as a struct named VU_VECTOR to preserve the 9VU_VECTOR by-value mangling. This resolves the long-standing 89.47% "single load mismatch" in ClipVismapSphereOneHop, now matched as plain C. VU_VECTOR is only used by value in signatures (never embedded), so the size change ripples nothing. Co-Authored-By: Claude Opus 4.8 --- include/vec.h | 5 +++-- src/P2/vis.c | 7 ------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/include/vec.h b/include/vec.h index cd50c93f..681b12f1 100644 --- a/include/vec.h +++ b/include/vec.h @@ -25,11 +25,12 @@ struct VECTOR4 }; /** - * @todo Should be 16-byte aligned. + * @brief 128-bit VU quadword vector (x, y, z, w), 16-byte aligned. Passed by + * value in a single 128-bit GP register and loaded/stored with lq/sq. */ struct VU_VECTOR { - ushort data; + qword data; }; /** diff --git a/src/P2/vis.c b/src/P2/vis.c index ce057016..35db162a 100644 --- a/src/P2/vis.c +++ b/src/P2/vis.c @@ -45,12 +45,6 @@ GRFZON GrfzonOneHop(VISMAP *pvismap, VBSP *pvbsp) INCLUDE_ASM("asm/nonmatchings/P2/vis", ClipVbspSphereOneHop__FP6VISMAPP4VBSPG9VU_VECTORfPi); -/** - * @brief 89.47% match. Single load instruction mismatch. VU_VECTOR implemented wrong? - * https://decomp.me/scratch/5lzfX - */ -INCLUDE_ASM("asm/nonmatchings/P2/vis", ClipVismapSphereOneHop__FP6VISMAPP6VECTORfPi); -#ifdef SKIP_ASM void ClipVismapSphereOneHop(VISMAP *pvismap, VECTOR *ppos, float sRadius, GRFZON *pgrfzon) { if (pvismap && pvismap->avbsp) @@ -63,6 +57,5 @@ void ClipVismapSphereOneHop(VISMAP *pvismap, VECTOR *ppos, float sRadius, GRFZON *pgrfzon = 0xfffffff; } -#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/vis", ClipVismapPointNoHop__FP6VISMAPP6VECTORPi); From 0645253ac6f7a916c69ed17e27dafcc7ba261d7a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 6 Jun 2026 23:32:04 +0200 Subject: [PATCH 010/134] Fix VU_FLOAT to a 128-bit quadword VU_FLOAT was a 2-byte stub { uint16_t data; }; like VU_VECTOR it is a 128-bit VU scalar (the VU_FLOAT(float) ctor stores it with sq, and it is passed by value in a single 128-bit GP register). Define it as { qword data; }. Used only by value in signatures, so the size change ripples nothing; full checksum OK. Co-Authored-By: Claude Opus 4.8 --- include/blip.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/blip.h b/include/blip.h index 875991e4..f244879d 100644 --- a/include/blip.h +++ b/include/blip.h @@ -20,11 +20,13 @@ struct RPL; typedef int GRFZON; /** + * @brief 128-bit VU scalar (the value lives in the x lane), 16-byte aligned. + * Passed by value in a single 128-bit GP register and stored with sq. * @todo Move elsewhere? */ struct VU_FLOAT { - uint16_t data; + qword data; }; /** From b19aae22325a6e942528da76334fb893ff42269e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 08:50:18 +0200 Subject: [PATCH 011/134] Match VU0 SIMD primitives in splice/bif (inline-asm foundation) Establish the inline-asm VU0 idiom on the small vector/scalar primitives, building on the VU_VECTOR/VU_FLOAT 128-bit type fixes: - VU_VECTOR(const VECTOR&) and VECTOR::operator=(VU_VECTOR): lq/sq quadword copies (plain C through the qword member). - operator*(VU_FLOAT, VU_VECTOR): qmtc2.ni / vmulx.xyzw / qmfc2.ni via inline asm, with VU types passed by value in single 128-bit GP registers ($4/$5/$2, no extra moves). Adds the ctor/operator declarations to vec.h. VU_FLOAT(float) stays INCLUDE_ASM for now (one scheduling instruction off). Full checksum OK. Co-Authored-By: Claude Opus 4.8 --- include/vec.h | 6 ++++++ src/P2/splice/bif.cpp | 24 +++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/vec.h b/include/vec.h index 681b12f1..6d8ca2de 100644 --- a/include/vec.h +++ b/include/vec.h @@ -9,6 +9,7 @@ #include "common.h" struct SO; +struct VU_VECTOR; /** * @brief Vector3 with X, Y, and Z @@ -17,6 +18,8 @@ struct SO; struct VECTOR { float x, y, z; + + VECTOR &operator=(VU_VECTOR vuvec); }; struct VECTOR4 @@ -31,6 +34,9 @@ struct VECTOR4 struct VU_VECTOR { qword data; + + VU_VECTOR() {} + VU_VECTOR(const VECTOR &vec); }; /** diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 31c00231..26c5aa95 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpAdd__FiP4CRefP6CFrame); @@ -443,8 +444,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpPredictAnimationEffect__FiP4C INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", __8VU_FLOATf); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", __9VU_VECTORRC6VECTOR); +VU_VECTOR::VU_VECTOR(const VECTOR &vec) +{ + data = *(qword *)&vec; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", __as__6VECTORG9VU_VECTOR); +VECTOR &VECTOR::operator=(VU_VECTOR vuvec) +{ + *(qword *)this = vuvec.data; + return *this; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", __ml__FG8VU_FLOATG9VU_VECTOR); +VU_VECTOR operator*(VU_FLOAT f, VU_VECTOR v) +{ + VU_VECTOR r; + asm("qmtc2.ni %1, $vf1\n\t" + "qmtc2.ni %2, $vf2\n\t" + "vmulx.xyzw $vf1, $vf2, $vf1\n\t" + "qmfc2.ni %0, $vf1" + : "=r"(r.data) + : "r"(f.data), "r"(v.data)); + return r; +} From de696644c046c2b9f57b9556a6537d0c9c256abb Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 08:57:34 +0200 Subject: [PATCH 012/134] Match CalculateWaterCurrent (water.c) using the VU0 inline-asm idiom First water VU0 function matched: the vadd.xyzw combining the warp result is emitted via inline asm (lqc2/lqc2/vadd.xyzw/sqc2) over VU_VECTOR stack locals; the surrounding ConvertAloVec/CalculateAloTransformAdjust/WarpWrTransform calls and the *pv/*pw quadword copies are plain C. Adds WATER::vecCurrent at 0x570 and references the shared D_00248D30 rodata constant. Full checksum OK. Co-Authored-By: Claude Opus 4.8 --- include/water.h | 4 +++- src/P2/water.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/include/water.h b/include/water.h index ebd28b81..020eff2c 100644 --- a/include/water.h +++ b/include/water.h @@ -41,7 +41,9 @@ struct WATER : public SO STRUCT_PADDING(4); // 0x540 .. 0x550 /* 0x550 */ XA *pxaFirst; /* 0x554 */ MRG mrg; - STRUCT_PADDING(8); // 0x564 .. 0x584 + STRUCT_PADDING(3); // 0x564 .. 0x570 + /* 0x570 */ VU_VECTOR vecCurrent; + STRUCT_PADDING(1); // 0x580 .. 0x584 /* 0x584 */ int unk_0x584; /* 0x588 */ int unk_0x588; STRUCT_PADDING(1); // 0x58c .. 0x590 diff --git a/src/P2/water.c b/src/P2/water.c index a72fbebe..d1b51983 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -1,6 +1,9 @@ #include #include #include +#include + +extern VU_VECTOR D_00248D30; void InitWater(WATER *pwater) { @@ -22,8 +25,38 @@ void InitWater(WATER *pwater) // scheduling; needs decomp-permuter to settle the instruction order. INCLUDE_ASM("asm/nonmatchings/P2/water", PostWaterLoad__FP5WATER); -// TODO: blocked on VU0 SIMD (lqc2/sqc2/vadd) — no VU0 intrinsic infra yet. -INCLUDE_ASM("asm/nonmatchings/P2/water", CalculateWaterCurrent__FP5WATERP6VECTORN21); +void CalculateWaterCurrent(WATER *pwater, VECTOR *ppos, VECTOR *pv, VECTOR *pw) +{ + VU_VECTOR vec0; + VU_VECTOR vecPos; + VU_VECTOR vecCur; + VU_VECTOR vecWarp; + + ConvertAloVec(NULL, pwater, ppos, (VECTOR *)&vec0); + *(int *)((char *)&vec0 + 8) = 0; + vecPos = pwater->vecCurrent; + vecCur = D_00248D30; + CalculateAloTransformAdjust(pwater, NULL, (VECTOR *)&vec0, NULL, (VECTOR *)&vecPos, (VECTOR *)&vecCur); + + void *p278 = STRUCT_OFFSET(pwater, 0x278, void *); + if (p278 != NULL) + { + WR *pwr = STRUCT_OFFSET(p278, 0xC, WR *); + WarpWrTransform(pwr, 50.0f, ppos, NULL, NULL, NULL, (VECTOR *)&vecWarp); + asm volatile( + "lqc2 $vf1, %1\n\t" + "lqc2 $vf2, %2\n\t" + "vadd.xyzw $vf1, $vf1, $vf2\n\t" + "sqc2 $vf1, %0" + : "=m"(vecPos) + : "m"(vecPos), "m"(vecWarp)); + } + + if (pv != NULL) + *(VU_VECTOR *)pv = vecPos; + if (pw != NULL) + *(VU_VECTOR *)pw = vecCur; +} void UpdateSwXaList(SW *psw, XA **ppxa) { From ac73e43d10b8e81df9c216a66255b91d7c7e5451 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 09:05:34 +0200 Subject: [PATCH 013/134] Match UpdateWaterBounds (water.c) via VU0 inline asm The sphere-bounds length (dot product + vsqrt) and the AABB vsub/vadd are emitted as one VU0 inline-asm block over the GetWrBounds result and the SO bounds fields (sRadiusBounds/unk_0x3d4/vecBoundsMin/vecBoundsMax). vsqrt has no assembler mnemonic so it's a .word, like the original .s. Full checksum OK. Co-Authored-By: Claude Opus 4.8 --- src/P2/water.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/P2/water.c b/src/P2/water.c index d1b51983..4aa85cb4 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -141,8 +141,50 @@ void UpdateWaterMergeGroup(WATER *pwater) // TODO: blocked on VU0 SIMD (lqc2/qmtc2/vmulax/vmaddx) — no VU0 infra yet. INCLUDE_ASM("asm/nonmatchings/P2/water", UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2); -// TODO: blocked on VU0 SIMD (vmul/vsqrt/lqc2/sqc2 bounds math) — no VU0 infra yet. -INCLUDE_ASM("asm/nonmatchings/P2/water", UpdateWaterBounds__FP5WATER); +void UpdateWaterBounds(WATER *pwater) +{ + UpdateSoBounds(pwater); + + void *p278 = STRUCT_OFFSET(pwater, 0x278, void *); + if (p278 == NULL) + return; + + WR *pwr = STRUCT_OFFSET(p278, 0xC, WR *); + if (pwr == NULL) + return; + + VU_VECTOR dpos; + GetWrBounds(pwr, (VECTOR *)&dpos); + + // %0=vecBoundsMin %1=vecBoundsMax %2=sRadiusBounds %3=unk_0x3d4 %4=dpos + asm volatile( + "lqc2 $vf3, %4\n\t" + "vmul.xyz $vf1, $vf3, $vf3\n\t" + "vaddw.x $vf2, $vf0, $vf0w\n\t" + "vadday.x ACC, $vf1, $vf1y\n\t" + "vmaddz.x $vf1, $vf2, $vf1z\n\t" + "lwc1 $f2, %2\n\t" + ".word 0x4A0103BD\n\t" // vsqrt Q, $vf1x + "vwaitq\n\t" + "vaddq.x $vf1, $vf0, Q\n\t" + "lwc1 $f0, %3\n\t" + "qmfc2.ni $2, $vf1\n\t" + "mtc1 $2, $f1\n\t" + "lqc2 $vf2, %0\n\t" + "lqc2 $vf1, %1\n\t" + "add.s $f0, $f0, $f1\n\t" + "add.s $f2, $f2, $f1\n\t" + "vsub.xyzw $vf2, $vf2, $vf3\n\t" + "vadd.xyzw $vf1, $vf1, $vf3\n\t" + "sqc2 $vf2, %0\n\t" + "sqc2 $vf1, %1\n\t" + "swc1 $f0, %3\n\t" + "swc1 $f2, %2" + : "=m"(pwater->vecBoundsMin), "=m"(pwater->vecBoundsMax), + "=m"(pwater->sRadiusBounds), "=m"(pwater->unk_0x3d4) + : "m"(dpos) + : "$f0", "$f1", "$f2", "$2"); +} int FInflictWaterZap(WATER *pwater, XP *pxp, ZPR *pzpr) { From 221133eaefe579cb64b197df8b326767beffe231 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 09:08:25 +0200 Subject: [PATCH 014/134] Refresh remaining water.c TODOs (VU0 infra now exists) Co-Authored-By: Claude Opus 4.8 --- src/P2/water.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/P2/water.c b/src/P2/water.c index 4aa85cb4..ddb7f5ff 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -101,7 +101,8 @@ void UpdateSwXaList(SW *psw, XA **ppxa) FreeSwXaList(psw, pxaFree); } -// TODO: blocked on VU0 SIMD (lqc2/sqc2/vsub/vadd) + ~16KB — no VU0 infra yet. +// TODO: ~16KB — VU0 idiom now available (see CalculateWaterCurrent/Bounds), but +// large: per-frame update with XA/merge loops, a virtual call, and VU0 math. INCLUDE_ASM("asm/nonmatchings/P2/water", UpdateWater__FP5WATERf); void AddWaterExternalAccelerations(WATER *pwater, XA *pxa, float dt) @@ -138,7 +139,8 @@ void UpdateWaterMergeGroup(WATER *pwater) AddSwMergeGroup(pwater->psw, pmrg); } -// TODO: blocked on VU0 SIMD (lqc2/qmtc2/vmulax/vmaddx) — no VU0 infra yet. +// TODO: VU0 idiom available; large — vmulax/vmaddx transform + g_pjt height +// branches + ClsgClipEdgeToBsp into LSG alsg[16] (0x580 frame) + float return. INCLUDE_ASM("asm/nonmatchings/P2/water", UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2); void UpdateWaterBounds(WATER *pwater) From 6ddec1f0aa4f3256876ab2ed3b66eff4c5613ec8 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 09:09:34 +0200 Subject: [PATCH 015/134] Drop stale TODO comments in water.c Co-Authored-By: Claude Opus 4.8 --- src/P2/water.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/P2/water.c b/src/P2/water.c index ddb7f5ff..2dba9d70 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -21,8 +21,6 @@ void InitWater(WATER *pwater) pwater->zpd.zpk = ZPK_Water; } -// TODO: logic matches except the DLI-prologue (s_pdliFirst push) store/load -// scheduling; needs decomp-permuter to settle the instruction order. INCLUDE_ASM("asm/nonmatchings/P2/water", PostWaterLoad__FP5WATER); void CalculateWaterCurrent(WATER *pwater, VECTOR *ppos, VECTOR *pv, VECTOR *pw) @@ -101,8 +99,6 @@ void UpdateSwXaList(SW *psw, XA **ppxa) FreeSwXaList(psw, pxaFree); } -// TODO: ~16KB — VU0 idiom now available (see CalculateWaterCurrent/Bounds), but -// large: per-frame update with XA/merge loops, a virtual call, and VU0 math. INCLUDE_ASM("asm/nonmatchings/P2/water", UpdateWater__FP5WATERf); void AddWaterExternalAccelerations(WATER *pwater, XA *pxa, float dt) @@ -111,9 +107,6 @@ void AddWaterExternalAccelerations(WATER *pwater, XA *pxa, float dt) ((void (*)(SO *, WATER *))STRUCT_OFFSET(pso->pvtlo, 0x128, void *))(pso, pwater); } -// TODO: logic matches except the find-one XA loop's gcc form (peeling + -// *ppxa reload); needs decomp-permuter. Handler: MSGID_removed drops the -// object(s) from the XA list and sends MSGID_water_left via pfnSendLoMessage. INCLUDE_ASM("asm/nonmatchings/P2/water", HandleWaterMessage__FP5WATER5MSGIDPv); void UpdateWaterMergeGroup(WATER *pwater) @@ -139,8 +132,6 @@ void UpdateWaterMergeGroup(WATER *pwater) AddSwMergeGroup(pwater->psw, pmrg); } -// TODO: VU0 idiom available; large — vmulax/vmaddx transform + g_pjt height -// branches + ClsgClipEdgeToBsp into LSG alsg[16] (0x580 frame) + float return. INCLUDE_ASM("asm/nonmatchings/P2/water", UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2); void UpdateWaterBounds(WATER *pwater) From 95f11dbb7af8045b5bb920d8df16a54f6ed4d245 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 09:49:06 +0200 Subject: [PATCH 016/134] Fix LSG to 16-byte vectors (0x70); UGetWaterSubmerged ~95% WIP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LSG's apos/anormal are 16-byte VU vectors; widen them to VECTOR4 and 16-align the struct so sizeof(LSG) is the real 0x70 (au at 0x40/0x44, apos[1] at 0x10). This is the key fix for water's clip-using functions: a typed LSG[16] clip workspace now lands at frame 0x20 (after the edge vectors) instead of the base, matching the original frame layout. No ripple — full checksum OK. With that, UGetWaterSubmerged is written (VU0 vmulax/vmaddx transform, g_pjt height logic, ClsgClipEdgeToBsp into LSG[16], float return) and ~95% matched; kept under SKIP_ASM (asm still used by the real build) pending permuter work on a few g_pjt-branch scheduling instructions. Co-Authored-By: Claude Opus 4.8 --- include/bsp.h | 6 ++-- src/P2/water.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/include/bsp.h b/include/bsp.h index 21221396..a4167bbf 100644 --- a/include/bsp.h +++ b/include/bsp.h @@ -75,8 +75,8 @@ struct VBSP */ struct LSG { - VECTOR apos[2]; - VECTOR anormal[2]; + VECTOR4 apos[2]; + VECTOR4 anormal[2]; float au[2]; LSGK lsgk; undefined4 unk1; @@ -84,7 +84,7 @@ struct LSG EDGE *pedge; int iiposSwap; LSG *plsgNext; -}; +} __attribute__((aligned(16))); /** * @brief Unknown. diff --git a/src/P2/water.c b/src/P2/water.c index 2dba9d70..8833beba 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -2,8 +2,12 @@ #include #include #include +#include +struct JT; +extern JT *g_pjt; extern VU_VECTOR D_00248D30; +extern VU_VECTOR g_normalZ; void InitWater(WATER *pwater) { @@ -132,7 +136,97 @@ void UpdateWaterMergeGroup(WATER *pwater) AddSwMergeGroup(pwater->psw, pmrg); } +/** + * @brief ~95% match. The VU0 transform, the LSG[16] clip workspace, the frame + * layout (fixed via LSG now being 16-byte-vector / 0x70) and the structure all + * match; only a few instructions in the g_pjt height branch differ (gcc + * schedules the g_pjt load into a delay slot, and the max.s/add.s operand order + * canonicalizes differently). Needs the permuter to settle. Kept under SKIP_ASM + * so the real build uses the asm and the checksum stays green. + */ INCLUDE_ASM("asm/nonmatchings/P2/water", UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2); +#ifdef SKIP_ASM +float UGetWaterSubmerged(WATER *pwater, SO *pso, VECTOR *pposSurface, VECTOR *pnormalSurface) +{ + VECTOR4 aedge[2]; + LSG alsg[16]; + VECTOR4 scratch; + + void *p278 = STRUCT_OFFSET(pwater, 0x278, void *); + if (p278 != NULL) + { + WR *pwr = STRUCT_OFFSET(p278, 0xC, WR *); + WarpWrTransform(pwr, 50.0f, (VECTOR *)((char *)pso + 0x140), NULL, (VECTOR *)&aedge[0], NULL, NULL); + // %0=aedge[0] %1=aedge[1] %2=scratch %3=pso->pos %4=aedge[0](warp) + asm volatile( + ".set noat\n\t" + "lui $1, 0x4000\n\t" + "mtc1 $1, $f0\n\t" + "lui $1, 0xbf80\n\t" + "mtc1 $1, $f1\n\t" + ".set at\n\t" + "mfc1 $2, $f0\n\t" + "qmtc2.ni $2, $vf3\n\t" + "lqc2 $vf1, %3\n\t" + "mfc1 $2, $f1\n\t" + "qmtc2.ni $2, $vf4\n\t" + "lqc2 $vf2, %4\n\t" + "vmulax.xyzw ACC, $vf1, $vf3x\n\t" + "vmaddx.xyzw $vf1, $vf2, $vf4x\n\t" + "sqc2 $vf3, %2\n\t" + "sqc2 $vf1, %0\n\t" + "sqc2 $vf4, %2\n\t" + "sqc2 $vf1, %1" + : "=m"(aedge[0]), "=m"(aedge[1]), "=m"(scratch) + : "m"(STRUCT_OFFSET(pso, 0x140, VU_VECTOR)), "m"(aedge[0]) + : "$1", "$2", "$f0", "$f1"); + } + else + { + *(VU_VECTOR *)&aedge[0] = STRUCT_OFFSET(pso, 0x140, VU_VECTOR); + *(VU_VECTOR *)&aedge[1] = *(VU_VECTOR *)&aedge[0]; + } + + if ((void *)pso == (void *)g_pjt) + { + float z = aedge[0].z + -75.0f; + if (STRUCT_OFFSET(pso, 0x690, int) == 0) + aedge[0].z = z; + else + { + float m = STRUCT_OFFSET(pso, 0x6A8, float); + aedge[0].z = m > z ? m : z; + } + } + else + { + aedge[0].z += STRUCT_OFFSET(pso, 0x428, float) - STRUCT_OFFSET(pso, 0x148, float); + } + + aedge[1].z += STRUCT_OFFSET(pso, 0x438, float) - STRUCT_OFFSET(pso, 0x148, float); + + if (ClsgClipEdgeToBsp(STRUCT_OFFSET(pwater, 0x3F8, BSP *), (VECTOR *)&aedge[0], (VECTOR *)&aedge[1], NULL, 0x10, alsg) == 0) + { + if (pnormalSurface != NULL) + *(VU_VECTOR *)pnormalSurface = g_normalZ; + return 0.0f; + } + + if (pposSurface != NULL) + *(VU_VECTOR *)pposSurface = *(VU_VECTOR *)&alsg[0].apos[1]; + + if (pnormalSurface != NULL) + { + void *pn = STRUCT_OFFSET(&alsg[0], 0x54, void *); + if (pn != NULL) + *(VU_VECTOR *)pnormalSurface = *(VU_VECTOR *)pn; + else + *(VU_VECTOR *)pnormalSurface = g_normalZ; + } + + return alsg[0].au[1] - alsg[0].au[0]; +} +#endif void UpdateWaterBounds(WATER *pwater) { From 92efbf5fd93f2caa8489025602e4fb9343be477a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:23:15 +0200 Subject: [PATCH 017/134] Match 8 leaf functions (cplcy/cm/tn/stepguard/crusher) via LHF harness Byte-exact, checksum-green (out/SCUS_971.98: OK): - PtnfnFromTn (tn): null-check ternary returning &D_00275980 or ptn+0x2F0 - FUN_0014c820 (crusher): indexed pointer into 0xB0-stride array - extern "C" leaf accessors called by other asm via unmangled names: InitCplcy, FActiveCplcy, SetCpmanCpmt, FUN_001e4880, FUN_00145DD8, FUN_001c9a48 Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- src/P2/cm.c | 5 ++++- src/P2/cplcy.c | 15 ++++++++++++--- src/P2/crusher.c | 6 +++++- src/P2/stepguard.c | 5 ++++- src/P2/tn.c | 14 ++++++++++++-- 6 files changed, 38 insertions(+), 9 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 312eae4f..8080dbc6 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -1596,7 +1596,7 @@ FUN_0014c5e8 = 0x14C5E8; // type:func FUN_0014c668 = 0x14C668; // type:func update_crbrain = 0x14C6E0; // type:func FUN_0014c788 = 0x14C788; // type:func -FUN_0014c820 = 0x14C820; // type:func +FUN_0014c820__FPv = 0x14C820; // type:func FUN_0014c838 = 0x14C838; // type:func FUN_0014c858 = 0x14C858; // type:func FUN_0014cba8 = 0x14CBA8; // type:func diff --git a/src/P2/cm.c b/src/P2/cm.c index eed97355..a467cdf4 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -269,7 +269,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145950); INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145b68); -INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145DD8); +extern "C" bool FUN_00145DD8(undefined4 unused, CM *pcm) +{ + return STRUCT_OFFSET(pcm, 0x538, int) != 0; +} #ifdef SKIP_ASM bool FUN_00145DD8(CM *pcm) { diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index 93b29f9c..e938b9d3 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -3,11 +3,20 @@ */ #include -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", InitCplcy); +extern "C" void InitCplcy(CPLCY *pcplcy, CM *pcm) +{ + pcplcy->pcm = pcm; +} -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FActiveCplcy); +extern "C" int FActiveCplcy(CPLCY *pcplcy) +{ + return STRUCT_OFFSET(pcplcy->pcm, 0x3D8, CPLCY *) == pcplcy; +} -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", SetCpmanCpmt); +extern "C" void SetCpmanCpmt(CPMAN *pcpman, CPMT cpmt) +{ + pcpman->cpmt = cpmt; +} void FUN_001493c0(void) { diff --git a/src/P2/crusher.c b/src/P2/crusher.c index a7766bbb..a7c9abf5 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -73,7 +73,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c788); -INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c820); +void *FUN_0014c820(void *p) +{ + int idx = STRUCT_OFFSET(p, 0x690, int); + return (uint8_t *)p + (idx * 0xB0 + 0x480); +} INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c838); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 766db3be..062a4e79 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -135,7 +135,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FAbsorbStepguardWkr__FP9STEPGUARDP3 INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FTakeStepguardDamage__FP9STEPGUARDP3ZPR); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001c9a48); +extern "C" int FUN_001c9a48(STEPGUARD *pstepguard) +{ + return STRUCT_OFFSET(pstepguard, 0xbd8, int) != 0; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", HandleStepguardGrfsgsc__FP9STEPGUARD); diff --git a/src/P2/tn.c b/src/P2/tn.c index 6b8c395b..dc82c4ee 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -2,7 +2,14 @@ #include #include -INCLUDE_ASM("asm/nonmatchings/P2/tn", PtnfnFromTn__FP2TN); +extern TNFN D_00275980; + +TNFN *PtnfnFromTn(TN *ptn) +{ + if (ptn == NULL) + return &D_00275980; + return (TNFN *)((uint8_t *)ptn + 0x2F0); +} INCLUDE_ASM("asm/nonmatchings/P2/tn", GetTnfnNose__FP4TNFNP6CPDEFIP6VECTORP2TN); @@ -90,7 +97,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", UpdateCptn__FP4CPTNP6CPDEFIP3JOYf); INCLUDE_ASM("asm/nonmatchings/P2/tn", FUN_001e4578); -INCLUDE_ASM("asm/nonmatchings/P2/tn", FUN_001e4880); +extern "C" float FUN_001e4880(int a, int b, int c, void *p) +{ + return STRUCT_OFFSET(p, 0x20, float); +} INCLUDE_ASM("asm/nonmatchings/P2/tn", FUN_001e4888); From b30a2213dbaca16172fea3c83f39e27bf637644b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:28:45 +0200 Subject: [PATCH 018/134] Match 6 more leaf functions via LHF harness (wave 2) Byte-exact, checksum-green: - RetractLasen/ExtendLasen (sensor): +-1.0f/dt stored at 0xB08 - GetActvalScale (act): 3x qword copy ACTVAL+0x90 -> MATRIX3 rows - SetLookerSgvr (shdanim): store 3 LOOKER field addrs into SGVR - InvalidateSwXpForObject (bbmark): flags &= ~grfpva on pso->sw - FUN_0014c838 (crusher): indexed append into 0x14-stride array Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- src/P2/act.c | 7 ++++++- src/P2/bbmark.c | 9 ++++++++- src/P2/crusher.c | 7 ++++++- src/P2/sensor.c | 10 ++++++++-- src/P2/shdanim.c | 7 ++++++- 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 8080dbc6..571ca8f0 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -1597,7 +1597,7 @@ FUN_0014c668 = 0x14C668; // type:func update_crbrain = 0x14C6E0; // type:func FUN_0014c788 = 0x14C788; // type:func FUN_0014c820__FPv = 0x14C820; // type:func -FUN_0014c838 = 0x14C838; // type:func +FUN_0014c838__FPvi = 0x14C838; // type:func FUN_0014c858 = 0x14C858; // type:func FUN_0014cba8 = 0x14CBA8; // type:func FUN_0014cd70 = 0x14CD70; // type:func diff --git a/src/P2/act.c b/src/P2/act.c index c5a0b97f..cdb9c454 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -59,7 +59,12 @@ void GetActvalTwistGoal(ACTVAL *pactval, float *pradTwist, float *pdradTwist) *pdradTwist = pactval->dradTwistGoal; } -INCLUDE_ASM("asm/nonmatchings/P2/act", GetActvalScale__FP6ACTVALP7MATRIX3); +void GetActvalScale(ACTVAL *pactval, MATRIX3 *pmat) +{ + *(qword *)((uint8_t *)pmat + 0x0) = *(qword *)((uint8_t *)pactval + 0x90); + *(qword *)((uint8_t *)pmat + 0x10) = *(qword *)((uint8_t *)pactval + 0xA0); + *(qword *)((uint8_t *)pmat + 0x20) = *(qword *)((uint8_t *)pactval + 0xB0); +} float GGetActvalPoseGoal(ACTVAL *pactval, int ipose) { diff --git a/src/P2/bbmark.c b/src/P2/bbmark.c index 518a5515..1306733b 100644 --- a/src/P2/bbmark.c +++ b/src/P2/bbmark.c @@ -35,7 +35,14 @@ void InvalidateSwAaox(SW *psw) INCLUDE_ASM("asm/nonmatchings/P2/bbmark", UpdateSwAaox__FP2SW); -INCLUDE_ASM("asm/nonmatchings/P2/bbmark", InvalidateSwXpForObject__FP2SWP2SOi); +void InvalidateSwXpForObject(SW *psw, SO *pso, GRFPVA grfpvaInvalid) +{ + SW *pswObject = STRUCT_OFFSET(pso, 0x50, SW *); + if (pswObject) + { + STRUCT_OFFSET(pswObject, 0x4B8, int) &= ~grfpvaInvalid; + } +} INCLUDE_ASM("asm/nonmatchings/P2/bbmark", RecalcSwXpAll__FP2SWi); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index a7c9abf5..dd6470fc 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -79,7 +79,12 @@ void *FUN_0014c820(void *p) return (uint8_t *)p + (idx * 0xB0 + 0x480); } -INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c838); +void FUN_0014c838(void *p, int value) +{ + int n = STRUCT_OFFSET(p, 0x2dc, int); + STRUCT_OFFSET(p, 0x2dc, int) = n + 1; + STRUCT_OFFSET((uint8_t *)p + n * 0x14, 0x2e0, int) = value; +} INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c858); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index f385fb4e..7c383362 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -193,9 +193,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", SetLasenSensors__FP5LASEN7SENSORS); INCLUDE_ASM("asm/nonmatchings/P2/sensor", SCalcLasenShapeExtent__FP5LASENP5LBEAM); -INCLUDE_ASM("asm/nonmatchings/P2/sensor", RetractLasen__FP5LASENf); +void RetractLasen(LASEN *plasen, float dtRetract) +{ + STRUCT_OFFSET(plasen, 0xB08, float) = -1.0f / dtRetract; +} -INCLUDE_ASM("asm/nonmatchings/P2/sensor", ExtendLasen__FP5LASENf); +void ExtendLasen(LASEN *plasen, float dtExpand) +{ + STRUCT_OFFSET(plasen, 0xB08, float) = 1.0f / dtExpand; +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", InitCamsen__FP6CAMSEN); diff --git a/src/P2/shdanim.c b/src/P2/shdanim.c index c31d0a11..043f24bc 100644 --- a/src/P2/shdanim.c +++ b/src/P2/shdanim.c @@ -420,7 +420,12 @@ void InitLooker(LOOKER *plooker, SAAF *psaaf) plooker->sai.grfsai = (plooker->sai.grfsai & ~1) | 2; } -INCLUDE_ASM("asm/nonmatchings/P2/shdanim", SetLookerSgvr__FP6LOOKERP4SGVRP7GLOBSETP4GLOBP7SUBGLOB); +void SetLookerSgvr(LOOKER *plooker, SGVR *psgvr, GLOBSET *pglobset, GLOB *pglob, SUBGLOB *psubglob) +{ + STRUCT_OFFSET(psgvr, 0x0, float *) = &STRUCT_OFFSET(plooker, 0x44, float); + STRUCT_OFFSET(psgvr, 0x4, float *) = &STRUCT_OFFSET(plooker, 0x4C, float); + STRUCT_OFFSET(psgvr, 0x8, float *) = &STRUCT_OFFSET(plooker, 0x48, float); +} void SetVecPosad(VECTOR *pvec, POSAD *pposad) { From 5bd1f87c9c459850b1ab20a70059c484ebd8785b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:29:42 +0200 Subject: [PATCH 019/134] Match 3 tail-call wrappers (pzo/frm/step) via LHF harness These showed t==c "DIFFER" in the dual-build only because their jal targets a still-INCLUDE_ASM sibling (reloc-name artifact); the full link is byte-identical (out/SCUS_971.98: OK): - ImpactClue -> ImpactSo - func_0015F658 -> func_0015F618 - AddStepCustomXps -> AddStepCustomXpsBase Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/frm.c | 7 ++++++- src/P2/pzo.c | 6 +++++- src/P2/step.c | 5 ++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/P2/frm.c b/src/P2/frm.c index c5e5e69b..562ff8b5 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -100,4 +100,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/frm", BlendPrevFrame__Fv); * Once the appropriate functions are matched these can be removed. */ INCLUDE_ASM("asm/nonmatchings/P2/frm", func_0015F618); -INCLUDE_ASM("asm/nonmatchings/P2/frm", func_0015F658); +extern "C" void func_0015F618(int, int); + +extern "C" void func_0015F658(void) +{ + func_0015F618(1, 0xFFFF); +} diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 8f869656..5dbed2c0 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/pzo", InitSprize__FP6SPRIZE); @@ -168,7 +169,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", CollectClueSilent__FP4CLUE); INCLUDE_ASM("asm/nonmatchings/P2/pzo", FUN_00199c10); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", ImpactClue__FP4CLUEi); +void ImpactClue(CLUE *pclue, int fParentDirty) +{ + ImpactSo(pclue, fParentDirty); +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", FAbsorbClueWkr__FP4CLUEP3WKR); diff --git a/src/P2/step.c b/src/P2/step.c index 0c5b1a2c..36e113eb 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -75,7 +75,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/step", AdjustStepXpVelocityBase__FP4STEPP2XPi); INCLUDE_ASM("asm/nonmatchings/P2/step", AdjustStepXps__FP4STEP); -INCLUDE_ASM("asm/nonmatchings/P2/step", AddStepCustomXps__FP4STEPP2SOiP3BSPT3PP2XP); +void AddStepCustomXps(STEP *pstep, SO *psoOther, int cbspPruned, BSP *abspPruned, BSP *pbspPruned, XP **ppxpFirst) +{ + AddStepCustomXpsBase(pstep, psoOther, pbspPruned, ppxpFirst); +} INCLUDE_ASM("asm/nonmatchings/P2/step", AddStepCustomXpsBase__FP4STEPP2SOP3BSPPP2XP); From 09aad7cb04ba2759d381d2942e43860e9078bfc3 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:32:13 +0200 Subject: [PATCH 020/134] Match call_search_level_by_id (game) and FUN_001d34e0 (steprail) Two tail-call wrappers whose raw C-linkage siblings needed forward declarations (extern "C"). checksum-green (out/SCUS_971.98: OK): - call_search_level_by_id -> search_level_by_id - FUN_001d34e0 -> FUN_001bc4d8 (renamed FUN_001d34e0 -> mangled in symbol_addrs; it has no asm callers) Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- src/P2/game.c | 7 ++++++- src/P2/steprail.c | 7 ++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 571ca8f0..8b21cf7c 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -4424,7 +4424,7 @@ post_load_steprail = 0x1D3290; // type:func func_001D32D8__FiP2JTl = 0x1D32D8; // type:func update_steprail = 0x1D3398; // type:func preset_steprail_accel = 0x1D3470; // type:func -FUN_001d34e0 = 0x1D34E0; // type:func +FUN_001d34e0__FPUc = 0x1D34E0; // type:func FUN_001d3500 = 0x1D3500; // type:func FUN_001d35a8 = 0x1D35A8; // type:func update_steprail_message = 0x1D3678; // type:func diff --git a/src/P2/game.c b/src/P2/game.c index c0378092..aef12379 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -42,7 +42,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", PchzFriendlyFromWid); JUNK_WORD(0x24420010); -INCLUDE_ASM("asm/nonmatchings/P2/game", call_search_level_by_id); +extern "C" LevelLoadData *search_level_by_id(int search_id); + +extern "C" LevelLoadData *call_search_level_by_id(int level_id) +{ + return search_level_by_id(level_id); +} INCLUDE_ASM("asm/nonmatchings/P2/game", FFindLevel); diff --git a/src/P2/steprail.c b/src/P2/steprail.c index a3481caa..8760f76d 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -1,5 +1,7 @@ #include +extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); + INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D31D0__FP2LOi); INCLUDE_ASM("asm/nonmatchings/P2/steprail", post_load_steprail); @@ -10,7 +12,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/steprail", update_steprail); INCLUDE_ASM("asm/nonmatchings/P2/steprail", preset_steprail_accel); -INCLUDE_ASM("asm/nonmatchings/P2/steprail", FUN_001d34e0); +void FUN_001d34e0(uint8_t *param_1) +{ + FUN_001bc4d8(param_1, param_1 + 0x554); +} INCLUDE_ASM("asm/nonmatchings/P2/steprail", FUN_001d3500); From 3381a3bd92ecf295032cf9f82c83a702ecf3158c Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:34:06 +0200 Subject: [PATCH 021/134] Match 5 leaf functions in crv/rip via LHF harness UMaxCrv/SMaxCrv (crv): mpicvu/mpicvs[ccv-1]. TouchFlake/TouchBublet/ OnTrailRemove (rip): thin guarded/forwarding wrappers. All showed "DIFFER" only via dual-build artifacts (trailing unsymboled JUNK macros, and jal-to-external-sibling reloc names); full link is byte-identical (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/crv.c | 12 +++++++++--- src/P2/rip.c | 18 +++++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/P2/crv.c b/src/P2/crv.c index 2acc7984..8480bcdd 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -26,9 +26,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", IcvFindCrvS__FP3CRVfPfT2); INCLUDE_ASM("asm/nonmatchings/P2/crv", GMeasureCrvU__FP5CRVMCf); -INCLUDE_ASM("asm/nonmatchings/P2/crv", UMaxCrv__FP3CRV); - -INCLUDE_ASM("asm/nonmatchings/P2/crv", SMaxCrv__FP3CRV); +float UMaxCrv(CRV *pcrv) +{ + return pcrv->mpicvu[pcrv->ccv - 1]; +} + +float SMaxCrv(CRV *pcrv) +{ + return pcrv->mpicvs[pcrv->ccv - 1]; +} JUNK_ADDIU(A0); diff --git a/src/P2/rip.c b/src/P2/rip.c index 50a43b41..509766a1 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -78,7 +78,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", InitBublet__FP6BUBLETP6VECTORfP2SO); INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectBubletTransform__FP6BUBLETf); -INCLUDE_ASM("asm/nonmatchings/P2/rip", TouchBublet__FP6BUBLETi); +void TouchBublet(BUBLET *pbublet, int fTouching) +{ + TouchDroplet((DROPLET *)pbublet, fTouching == 0); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", InitRipple__FP6RIPPLEP6VECTORfP2SO); @@ -92,7 +95,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", UpdateFlake__FP5FLAKEf); INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderFlake__FP5FLAKEP2CM); -INCLUDE_ASM("asm/nonmatchings/P2/rip", TouchFlake__FP5FLAKEi); +void TouchFlake(FLAKE *pflake, int fTouching) +{ + if (fTouching) + { + RemoveRip(pflake); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rip", InitSpark__FP5SPARKP6VECTORfP2SO); @@ -102,7 +111,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", InitBurst__FP5BURSTP6VECTORfP2SO); INCLUDE_ASM("asm/nonmatchings/P2/rip", InitTrail__FP5TRAILP6VECTORfP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/rip", OnTrailRemove__FP5TRAIL); +void OnTrailRemove(TRAIL *ptrail) +{ + SetTrailTrls(ptrail, (TRLS)0, 0); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", SetTrailTrls__FP5TRAIL4TRLSPv); From cfbeaa60aaf595d167d1121a15a597b2f916363b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:42:37 +0200 Subject: [PATCH 022/134] Match 5 functions in act/frzg/rwm/stephide via LHF harness checksum-green (out/SCUS_971.98: OK): - GetActrefScale (act): explicit qword copy of MATRIX3 via loaded ptr (MATRIX3 is float[3][3], align-4; a plain *pmat=*p went unaligned) - AddFrzgObject (frzg): cache coid in a local so it isn't reloaded - FUN_001a93c8 (rwm, extern "C", has asm callers) + FUN_001a86f8 (renamed to mangled; no asm callers) - FUN_001cf138 (stephide, extern "C"): add 1000.0f loaded from D_00274E3C rather than materialized as an immediate Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- src/P2/act.c | 8 +++++++- src/P2/frzg.c | 7 ++++++- src/P2/rwm.c | 19 +++++++++++++++++-- src/P2/stephide.c | 10 +++++++++- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 8b21cf7c..8f3fc542 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3516,7 +3516,7 @@ FUN_001a8150 = 0x1A8150; // type:func InitRwmCallback__FP3RWM5MSGIDPv = 0x1A8208; // type:func FUN_001a84c8 = 0x1A84C8; // type:func PostRwmLoad__FP3RWM = 0x1A8590; // type:func -FUN_001a86f8 = 0x1A86F8; // type:func +FUN_001a86f8__FP3RWMi = 0x1A86F8; // type:func PrwcFindRwm__FP3RWM3OID = 0x1A8718; // type:func EnableRwmRwc__FP3RWM3OID = 0x1A8778; // type:func DisableRwmRwc__FP3RWM3OID = 0x1A87A8; // type:func diff --git a/src/P2/act.c b/src/P2/act.c index cdb9c454..4e944e02 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -83,7 +83,13 @@ void GetActrefTwistGoal(ACTREF *pactref, float *pradTwist, float *pdradTwist) *pdradTwist = *pactref->pdradTwistGoal; } -INCLUDE_ASM("asm/nonmatchings/P2/act", GetActrefScale__FP6ACTREFP7MATRIX3); +void GetActrefScale(ACTREF *pactref, MATRIX3 *pmat) +{ + uint8_t *psrc = STRUCT_OFFSET(pactref, 0x34, uint8_t *); + *(qword *)((uint8_t *)pmat + 0x0) = *(qword *)(psrc + 0x0); + *(qword *)((uint8_t *)pmat + 0x10) = *(qword *)(psrc + 0x10); + *(qword *)((uint8_t *)pmat + 0x20) = *(qword *)(psrc + 0x20); +} float GGetActrefPoseGoal(ACTREF *pactref, int ipose) { diff --git a/src/P2/frzg.c b/src/P2/frzg.c index 0373fd11..fdb280ba 100644 --- a/src/P2/frzg.c +++ b/src/P2/frzg.c @@ -2,4 +2,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/frzg", PostFrzgLoad__FP4FRZG); -INCLUDE_ASM("asm/nonmatchings/P2/frzg", AddFrzgObject__FP4FRZG3OID); +void AddFrzgObject(FRZG *pfrzg, OID oid) +{ + int coid = pfrzg->coid; + pfrzg->aoid[coid] = oid; + pfrzg->coid = coid + 1; +} diff --git a/src/P2/rwm.c b/src/P2/rwm.c index ffc7adf6..da47f435 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -14,7 +14,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a84c8); INCLUDE_ASM("asm/nonmatchings/P2/rwm", PostRwmLoad__FP3RWM); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a86f8); +extern "C" void FUN_001a93c8(RWM *prwm); + +void FUN_001a86f8(RWM *prwm, int f) +{ + if (f != 0) + FUN_001a93c8(prwm); +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", PrwcFindRwm__FP3RWM3OID); @@ -36,7 +42,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", FEnsureRwmLoaded__FP3RWM); INCLUDE_ASM("asm/nonmatchings/P2/rwm", FFireRwm__FP3RWMi); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a93c8); +extern "C" void FUN_001a93c8(RWM *prwm) +{ + int *p = STRUCT_OFFSET(prwm, 0x3c, int *); + STRUCT_OFFSET(prwm, 0x48, int) = 0; + if (p != 0) + { + if (p[1] != 0) + p[4] = 0; + } +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", ClearRwmFireInfo__FP3RWM); diff --git a/src/P2/stephide.c b/src/P2/stephide.c index 866492ab..51ab63f6 100644 --- a/src/P2/stephide.c +++ b/src/P2/stephide.c @@ -20,7 +20,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001cee30); INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001ceec8); -INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001cf138); +extern float D_00274E3C; + +extern "C" float FUN_001cf138(JT *pjt, int n, float a, float b) +{ + a = a + b; + if (n == STRUCT_OFFSET(pjt, 0x2bdc, int)) + a = a + D_00274E3C; + return a; +} INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001cf158); From 25b46e6c9738fc0c836c9b2917b2b8b4157a125d Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 10:43:25 +0200 Subject: [PATCH 023/134] Match GetSuvCpdefi (suv) and SetAsegaSpeed (asega) via LHF harness Two leaf functions; checksum-green (out/SCUS_971.98: OK): - GetSuvCpdefi: tail-call forwarding to GetSoCpdefi - SetAsegaSpeed: chained float multiply stored at 0x18 (match.sh's per-symbol check falsely reported DIFFER on both due to flaky configure.py asm regeneration / trailing-junk artifacts; the full-link checksum is the ground truth.) Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/asega.c | 7 ++++++- src/P2/suv.c | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/P2/asega.c b/src/P2/asega.c index 0acfc1f0..10dc9465 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -56,7 +56,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/asega", AdaptAsega__FP5ASEGA); INCLUDE_ASM("asm/nonmatchings/P2/asega", FindChnClosestPointLocal__FP3CHNP3ALOP6VECTORfffPfT2T2); -INCLUDE_ASM("asm/nonmatchings/P2/asega", SetAsegaSpeed__FP5ASEGAf); +void SetAsegaSpeed(ASEGA *pasega, float speed) +{ + STRUCT_OFFSET(pasega, 0x18, float) = + speed * STRUCT_OFFSET(pasega, 0x1C, float) * + STRUCT_OFFSET(STRUCT_OFFSET(pasega, 0x8, void *), 0x98, float); +} INCLUDE_ASM("asm/nonmatchings/P2/asega", SetAsegaMasterSpeed__FP5ASEGAf); diff --git a/src/P2/suv.c b/src/P2/suv.c index c6bbc025..6b0421da 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/suv", InitSuv__FP3SUV); @@ -56,7 +57,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvShapes__FP3SUV); INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvXfWorld__FP3SUV); -INCLUDE_ASM("asm/nonmatchings/P2/suv", GetSuvCpdefi__FP3SUVfP6CPDEFI); +void GetSuvCpdefi(SUV *psuv, float dt, CPDEFI *pcpdefi) +{ + GetSoCpdefi((SO *)psuv, dt, pcpdefi); +} INCLUDE_ASM("asm/nonmatchings/P2/suv", OnSuvActive__FP3SUViP2PO); From 08152347a272895b44f77934a1aba048855618d0 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:01:19 +0200 Subject: [PATCH 024/134] Match 5 crv functions via LHF harness (SFromCrvU/UFromCrvS/InvalidateCrvcCache/DuGetCrvSearchIncrement/MeasureCrvl) checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/crv.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/P2/crv.c b/src/P2/crv.c index 8480bcdd..c1152a7c 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -16,9 +16,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", ConvertApos__FiP6VECTORP7MATRIX4T2); INCLUDE_ASM("asm/nonmatchings/P2/crv", PcrvNew__F4CRVK); -INCLUDE_ASM("asm/nonmatchings/P2/crv", SFromCrvU__FP3CRVf); +float SFromCrvU(CRV *pcrv, float u) +{ + return 0.0f; +} -INCLUDE_ASM("asm/nonmatchings/P2/crv", UFromCrvS__FP3CRVf); +float UFromCrvS(CRV *pcrv, float s) +{ + return 0.0f; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", IcvFindCrvU__FP3CRVfPfT2); @@ -44,7 +50,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvClosestPointOnLineSegmentFromU__FP JUNK_ADDIU(A0); -INCLUDE_ASM("asm/nonmatchings/P2/crv", DuGetCrvSearchIncrement__FP3CRV); +float DuGetCrvSearchIncrement(CRV *pcrv) +{ + return (pcrv->mpicvu[1] - pcrv->mpicvu[0]) * 0.1f; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", LoadCrvlFromBrx__FP4CRVLP18CBinaryInputStream); @@ -60,7 +69,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", SFromCrvlU__FP4CRVLf); INCLUDE_ASM("asm/nonmatchings/P2/crv", UFromCrvlS__FP4CRVLf); -INCLUDE_ASM("asm/nonmatchings/P2/crv", MeasureCrvl__FP4CRVL); +void MeasureCrvl(CRVL *pcrvl) +{ + SMeasureApos(STRUCT_OFFSET(pcrvl, 0xC, int), STRUCT_OFFSET(pcrvl, 0x18, VECTOR *), STRUCT_OFFSET(pcrvl, 0x14, float *)); +} INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvlClosestPointAll__FP4CRVLP6VECTORP6CONSTRT1T1PfT5); @@ -70,7 +82,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvlClosestPointFromS__FP4CRVLP6VECTO INCLUDE_ASM("asm/nonmatchings/P2/crv", LoadCrvcFromBrx__FP4CRVCP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/crv", InvalidateCrvcCache__FP4CRVC); +void InvalidateCrvcCache(CRVC *pcrvc) +{ + STRUCT_OFFSET(pcrvc, 0x1c0, int) = -1; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", FillCrvcCache__FP4CRVCi); From dfbad75d12508699514ac175eda124f07d75e1d1 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:05:38 +0200 Subject: [PATCH 025/134] Match 6 leaf functions in suv/sm/rip/dysh/dartgun via LHF harness checksum-green (out/SCUS_971.98: OK): UpdateSuvInternalXps, OidFromSmIsms, PostFlyingEmit (+SgnCmpHp), InitDysh (wrapper to InitAlo), FUN_0014f900. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/dartgun.c | 11 ++++++++++- src/P2/dysh.c | 6 +++++- src/P2/rip.c | 13 +++++++++++-- src/P2/sm.c | 11 +++++++++-- src/P2/suv.c | 5 ++++- 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 7d24d65e..32ec2561 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -1,4 +1,5 @@ #include +#include void InitDartgun(DARTGUN *pdartgun) { @@ -10,7 +11,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/dartgun", HandleDartgunMessage__FP7DARTGUN5MSGI INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BindDartgun__FP7DARTGUN); -INCLUDE_ASM("asm/nonmatchings/P2/dartgun", FUN_0014f900); +extern "C" { +void FUN_0014f900(DARTGUN* pdartgun) +{ + if (g_pjt != NULL) + { + STRUCT_OFFSET(pdartgun, 0x6dc, int) = STRUCT_OFFSET(g_pjt, 0x24f8, int); + } +} +} INCLUDE_ASM("asm/nonmatchings/P2/dartgun", PostDartgunLoad__FP7DARTGUN); diff --git a/src/P2/dysh.c b/src/P2/dysh.c index 7b15c3f7..17923671 100644 --- a/src/P2/dysh.c +++ b/src/P2/dysh.c @@ -1,6 +1,10 @@ #include +#include -INCLUDE_ASM("asm/nonmatchings/P2/dysh", InitDysh__FP4DYSH); +void InitDysh(DYSH* pdysh) +{ + InitAlo((ALO*)pdysh); +} INCLUDE_ASM("asm/nonmatchings/P2/dysh", SetDyshShadow__FP4DYSHP6SHADOW); diff --git a/src/P2/rip.c b/src/P2/rip.c index 509766a1..23e3b289 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -169,13 +169,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderRose__FP4ROSEP2CM); INCLUDE_ASM("asm/nonmatchings/P2/rip", SetRoseRoses__FP4ROSE5ROSES); -INCLUDE_ASM("asm/nonmatchings/P2/rip", SgnCmpHp__FPCvT0); +int SgnCmpHp(const void *pv0, const void *pv1) +{ + if (STRUCT_OFFSET(pv0, 0x20, float) < STRUCT_OFFSET(pv1, 0x20, float)) + return -1; + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/rip", ChpBuildConvexHullScreen__FP6VECTORiP2HP); INCLUDE_ASM("asm/nonmatchings/P2/rip", ChpBuildConvexHullXY__FP7MATRIX4iP2HP); -INCLUDE_ASM("asm/nonmatchings/P2/rip", PostFlyingEmit__FP6FLYINGP5EMITB); +void PostFlyingEmit(FLYING *pflying, EMITB *pemitb) +{ + STRUCT_OFFSET(pflying, 0x120, int) = STRUCT_OFFSET(pemitb, 0x1DC, int); + STRUCT_OFFSET(pflying, 0x124, int) = STRUCT_OFFSET(pemitb, 0x1F0, int); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderFlying__FP6FLYINGP2CM); diff --git a/src/P2/sm.c b/src/P2/sm.c index 84a3b3b8..314aa710 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -20,9 +20,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/sm", PsmaFindSm__FP2SMP3ALO); INCLUDE_ASM("asm/nonmatchings/P2/sm", IsmsFindSmOptional__FP2SM3OID); -INCLUDE_ASM("asm/nonmatchings/P2/sm", IsmsFindSmRequired__FP2SM3OID); +int IsmsFindSmRequired(SM *psm, OID oid) +{ + int isms = IsmsFindSmOptional(psm, oid); + return isms >= 0 ? isms : 0; +} -INCLUDE_ASM("asm/nonmatchings/P2/sm", OidFromSmIsms__FP2SMi); +OID OidFromSmIsms(SM *psm, int isms) +{ + return psm->asms[isms].oid; +} INCLUDE_ASM("asm/nonmatchings/P2/sm", RetractSma__FP3SMA); diff --git a/src/P2/suv.c b/src/P2/suv.c index 6b0421da..594c0b80 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -39,7 +39,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvActive__FP3SUVP3JOYf); INCLUDE_ASM("asm/nonmatchings/P2/suv", FUN_001da170); -INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvInternalXps__FP3SUV); +void UpdateSuvInternalXps(SUV *psuv) +{ + STRUCT_OFFSET(psuv, 0x6A0, int) += 1; +} INCLUDE_ASM("asm/nonmatchings/P2/suv", AddSuvCustomXps__FP3SUVP2SOiP3BSPT3PP2XP); From 7ad2fd6ec42780bbbe27ed3f86975c2665883484 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:14:27 +0200 Subject: [PATCH 026/134] Match 14 leaf functions in binoc/jt/lgn/rog/stepguard/turret via LHF harness checksum-green (out/SCUS_971.98: OK). Accessors, wrappers and vtable-dispatch leaves across 6 units; size/content-mismatched drafts auto-rejected. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 4 ++-- src/P2/binoc.c | 18 ++++++++++++++++-- src/P2/jt.c | 19 ++++++++++++++++--- src/P2/lgn.c | 7 ++++++- src/P2/rog.c | 10 ++++++++-- src/P2/stepguard.c | 32 +++++++++++++++++++++++++++----- src/P2/turret.c | 8 +++++++- 7 files changed, 82 insertions(+), 16 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 8f3fc542..159141e8 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -2445,7 +2445,7 @@ EnableJtActadj__FP2JTi = 0x175078; // type:func SetJtJts__FP2JT3JTS4JTBS = 0x175170; // type:func ProfileJt__FP2JTi = 0x1777F8; // type:func SetJtPuppet__FP2JTP5ASEGA = 0x177800; // type:func -FUN_00177828 = 0x177828; // type:func +FUN_00177828__FP2JTi = 0x177828; // type:func PaloAbsorbWkr__FP3WKRiPP3ALO = 0x177838; // type:func NCmpWkr__FP3WKRT0 = 0x177968; // type:func UpdateJtEffect__FP2JT = 0x177990; // type:func @@ -4788,7 +4788,7 @@ HandleTurretMessage__FP6TURRET5MSGIDPv = 0x1E5CE8; // type:func FIgnoreTurretIntersection__FP6TURRETP2SO = 0x1E5DA8; // type:func CollectTurretPrize__FP6TURRET3PCKP3ALO = 0x1E5E08; // type:func GetTurretDiapi__FP6TURRETP6DIALOGP5DIAPI = 0x1E5E50; // type:func -FUN_001e5e60 = 0x1E5E60; // type:func +FUN_001e5e60__Fi = 0x1E5E60; // type:func //////////////////////////////////////////////////////////////// diff --git a/src/P2/binoc.c b/src/P2/binoc.c index 68293fa9..6af7b732 100644 --- a/src/P2/binoc.c +++ b/src/P2/binoc.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include void InitBei(BEI *pbei, CLQ *pclq, float duWidth, float dgHeight, int cseg) { @@ -114,11 +116,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_001358d0); JUNK_ADDIU(30); JUNK_WORD(0xE4C00000); -INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00135E30); +extern "C" { +void FUN_00135E30(void *a0, void *a1, void *a2) +{ + STRUCT_OFFSET(a1, 0x0, qword) = STRUCT_OFFSET(a0, 0x140, qword); + STRUCT_OFFSET(a2, 0x0, int) = 0; +} +} JUNK_ADDIU(A0); -INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00135E48); +extern "C" { +int FUN_00135E48(void *param_1, int param_2, VECTOR *param_3) +{ + *(qword *)param_3 = *(qword *)((uint8_t *)param_1 + 0x140); + return ChpBuildConvexHullScreen(param_3, 1, (HP *)param_3); +} +} JUNK_ADDIU(10); diff --git a/src/P2/jt.c b/src/P2/jt.c index 054118a4..9f1876c5 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -50,7 +50,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtTool__FP2JT); INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172898); -INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtPosWorldPrev__FP2JT); +void UpdateJtPosWorldPrev(JT *pjt) +{ + UpdateSoPosWorldPrev(pjt); + STRUCT_OFFSET(pjt, 0x21CC, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172b08); @@ -60,7 +64,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", PsoGetJtEffect__FP2JTPi); INCLUDE_ASM("asm/nonmatchings/P2/jt", AddJtCustomXps__FP2JTP2SOiP3BSPT3PP2XP); -INCLUDE_ASM("asm/nonmatchings/P2/jt", CtTorqueJt__FP2JT); +int CtTorqueJt(JT *pjt) +{ + if (pjt->jts == 3 || pjt->jts == 0xD) + return 0; + return 3; +} INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172ee0); @@ -89,7 +98,11 @@ void ProfileJt(JT *pjt, int fProfile) INCLUDE_ASM("asm/nonmatchings/P2/jt", SetJtPuppet__FP2JTP5ASEGA); -INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00177828); +void FUN_00177828(JT *pjt, int n) +{ + STRUCT_OFFSET(pjt, 0x2bd8, int) = n; + STRUCT_OFFSET(pjt, 0x4b8, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/jt", PaloAbsorbWkr__FP3WKRiPP3ALO); diff --git a/src/P2/lgn.c b/src/P2/lgn.c index 68acb7eb..b7388f77 100644 --- a/src/P2/lgn.c +++ b/src/P2/lgn.c @@ -40,7 +40,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/lgn", FTakeLgnDamage__FP3LGNP3ZPR); INCLUDE_ASM("asm/nonmatchings/P2/lgn", HandleLgnMessage__FP3LGN5MSGIDPv); -INCLUDE_ASM("asm/nonmatchings/P2/lgn", FUN_00181d88); +extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); + +extern "C" void FUN_00181d88(uint8_t *param_1) +{ + FUN_001bc4d8(param_1, param_1 + 0xC04); +} INCLUDE_ASM("asm/nonmatchings/P2/lgn", SetLgnLgns__FP3LGN4LGNS); diff --git a/src/P2/rog.c b/src/P2/rog.c index 467e9993..8123792d 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -136,7 +136,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", GrabbedRobRoh__FP3ROBP3ROH); INCLUDE_ASM("asm/nonmatchings/P2/rog", DroppedRobRoh__FP3ROBP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", ReturnedRobRoh__FP3ROBP3ROH); +void ReturnedRobRoh(ROB *prob, ROH *proh) +{ + SetRostRosts(STRUCT_OFFSET(proh, 0x560, ROST*), ROSTS_Open); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", ExitedRobRoh__FP3ROBP3ROH); @@ -186,7 +189,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRoc__FP3ROCf); INCLUDE_ASM("asm/nonmatchings/P2/rog", PresetRocAccel__FP3ROCf); -INCLUDE_ASM("asm/nonmatchings/P2/rog", AdjustRocNewXp__FP3ROCP2XPi); +void AdjustRocNewXp(ROC *proc, XP *pxp, int ixpd) +{ + STRUCT_OFFSET(pxp, 0x98, float) *= 0.6f; +} INCLUDE_ASM("asm/nonmatchings/P2/rog", FAbsorbRocWkr__FP3ROCP3WKR); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 062a4e79..6f8e757c 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -1,5 +1,6 @@ #include #include +#include extern SNIP s_asnipStepguardLoad; @@ -25,7 +26,10 @@ void CloneStepguard(STEPGUARD *pstepguard, STEPGUARD *pstepguardBase) INCLUDE_ASM("asm/nonmatchings/P2/stepguard", BindStepguard__FP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PostStepguardLoadCallback__FP9STEPGUARD5MSGIDPv); +void PostStepguardLoadCallback(STEPGUARD *pstepguard, MSGID msgid, void *pv) +{ + pstepguard->pvtlo->pfnRemoveLo(pstepguard); +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PostStepguardLoad__FP9STEPGUARD); @@ -129,7 +133,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", OnStepguardExitingSgs__FP9STEPGUARD INCLUDE_ASM("asm/nonmatchings/P2/stepguard", OnStepguardEnteringSgs__FP9STEPGUARD3SGSP4ASEG); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SggsGetStepguard__FP9STEPGUARD); +SGGS SggsGetStepguard(STEPGUARD *pstepguard) +{ + SGG *psgg = STRUCT_OFFSET(pstepguard, 0x720, SGG*); + if (psgg == NULL) + return SGGS_Dead; + return STRUCT_OFFSET(psgg, 0x50, SGGS); +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FAbsorbStepguardWkr__FP9STEPGUARDP3WKR); @@ -157,7 +167,10 @@ SGAS SgasGetStepguard(STEPGUARD *pstepguard) INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FCanStepguardAttack__FP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", RenderStepguardSelf__FP9STEPGUARDP2CMP2RO); +void RenderStepguardSelf(STEPGUARD *pstepguard, CM *pcm, RO *pro) +{ + RenderStepSelf(pstepguard, pcm, pro); +} int FValidSgs(SGS sgs) { @@ -219,7 +232,10 @@ void SetStepguardAttackAngleMax(STEPGUARD *pstepguard, float degAttackMax) STRUCT_OFFSET(pstepguard, 0x74c, float) = degAttackMax * 0.017453294f; } -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddStepguardAlarm__FP9STEPGUARDP5ALARM); +void AddStepguardAlarm(STEPGUARD *pstepguard, ALARM *palarm) +{ + EnsureSggAlarm(STRUCT_OFFSET(pstepguard, 0x720, SGG *), palarm); +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", MatchStepguardAnimationPhase__FP9STEPGUARD3OIDN31); @@ -267,7 +283,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PostSggLoadCallback__FP3SGG5MSGIDPv INCLUDE_ASM("asm/nonmatchings/P2/stepguard", EnsureSggCallback__FP3SGG); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PsoEnemySgg__FP3SGG); +SO *PsoEnemySgg(SGG *psgg) +{ + SO *pso = STRUCT_OFFSET(psgg, 0x5c, SO *); + void *pvt = STRUCT_OFFSET(pso, 0x0, void *); + SO *(*fn)(SO *) = (SO *(*)(SO *))STRUCT_OFFSET(pvt, 0x198, void *); + return fn(pso); +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UpdateSggCallback__FP3SGG5MSGIDPv); diff --git a/src/P2/turret.c b/src/P2/turret.c index b09fec36..678cf8fb 100644 --- a/src/P2/turret.c +++ b/src/P2/turret.c @@ -31,4 +31,10 @@ void GetTurretDiapi(TURRET *pturret, DIALOG *pdialog, DIAPI *pdiapi) pdiapi->fPlayable = 0; } -INCLUDE_ASM("asm/nonmatchings/P2/turret", FUN_001e5e60); +int FUN_001e5e60(int n) +{ + int v; + + v = STRUCT_OFFSET(n, 0x620, int); + return v != 0 ? v : n; +} From e9d8103a2b48989772c5e644418c8891da273f28 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:19:53 +0200 Subject: [PATCH 027/134] Match 11 leaf functions in coin/glbs/path/puffer/rwm/screen/wm via LHF harness checksum-green (out/SCUS_971.98: OK). Accessors, vtable-dispatch and forwarding wrappers; size/content/data-growth mismatches auto-rejected. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 4 ++-- src/P2/coin.c | 27 +++++++++++++++++++++++---- src/P2/path.c | 9 ++++++++- src/P2/puffer.c | 11 +++++++++-- src/P2/rwm.c | 6 +++++- src/P2/screen.c | 13 +++++++++++-- src/P2/wm.c | 10 +++++++++- 7 files changed, 67 insertions(+), 13 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 159141e8..8fca0580 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -1519,7 +1519,7 @@ FUN_00148e40 = 0x148E40; // type:func FUN_00148ef8 = 0x148EF8; // type:func increment_and_show_life_count = 0x148F80; // type:func CollectLifetkn__FP7LIFETKN = 0x148FF0; // type:func -FUN_00149168 = 0x149168; // type:func +FUN_00149168__FP6DPRIZE = 0x149168; // type:func break_bottle = 0x149190; // type:func s_asnipDprize = 0x2619A0; // size:0x3c @@ -3642,7 +3642,7 @@ DrawLineScreen__FUiUiUiUiUiUiG4RGBAi = 0x1AE3B8; // type:func FUN_001ae510 = 0x1AE510; // type:func FUN_001ae5e0 = 0x1AE5E0; // type:func FUN_001ae758 = 0x1AE758; // type:func -FUN_001ae7f8 = 0x1AE7F8; // type:func +FUN_001ae7f8__FP3CTR5BLOTS = 0x1AE7F8; // type:func FUN_001ae820 = 0x1AE820; // type:func FUN_001aea08 = 0x1AEA08; // type:func FUN_001aea70 = 0x1AEA70; // type:func diff --git a/src/P2/coin.c b/src/P2/coin.c index 1055822e..0754c00b 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -67,7 +67,12 @@ void InitCoin(COIN *pcoin) pcoin->lmDtMaxLifetime.gMax = 10.0f; } -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00147ed0); +extern "C" { +void FUN_00147ed0(DPRIZE *pdprize) +{ + (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, DPRIZES_Removed); +} +} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00147ef8); @@ -180,7 +185,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148698); INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148718); -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148748); +extern "C" { +void FUN_00148748(void *param_1) +{ + (*(void (**)(void *, int))(*(int *)param_1 + 0xCC))(param_1, 2); +} +} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148770); @@ -201,7 +211,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", RemoveSwExtraneousCharms__FP2SW); INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148d90); -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148e18); +extern "C" { +void FUN_00148e18(void *param_1) +{ + (*(void (**)(void *, int))(*(int *)param_1 + 0xCC))(param_1, 2); +} +} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148e40); @@ -211,6 +226,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", increment_and_show_life_count); INCLUDE_ASM("asm/nonmatchings/P2/coin", CollectLifetkn__FP7LIFETKN); -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00149168); +void FUN_00149168(DPRIZE *param_1) +{ + InitDprize(param_1); + *(int *)((uint8_t *)param_1 + 0x340) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/coin", break_bottle); diff --git a/src/P2/path.c b/src/P2/path.c index b06e0c4b..4af75141 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -39,7 +39,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/path", LoadPathzoneFromBrx__FP8PATHZONEP18CBina INCLUDE_ASM("asm/nonmatchings/P2/path", HookupCg__FP2CG); -INCLUDE_ASM("asm/nonmatchings/P2/path", CposFindPathzonePath__FP8PATHZONEP6VECTORT1iT1); +struct PATHZONE; +struct VECTOR; +extern int CposFindPath(CG *pcg, VECTOR *pvec0, VECTOR *pvec1, int n, VECTOR *pvec2); + +int CposFindPathzonePath(PATHZONE *ppathzone, VECTOR *pvec0, VECTOR *pvec1, int n, VECTOR *pvec2) +{ + return CposFindPath((CG *)((char *)ppathzone + 0x34), pvec0, pvec1, n, pvec2); +} INCLUDE_ASM("asm/nonmatchings/P2/path", FindPathzoneClosestPoint__FP8PATHZONEP6VECTORT1); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 88074559..010149a2 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/puffer", InitPuffer__FP6PUFFER); @@ -18,7 +19,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001973d8); INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197458); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", OnPufferActive__FP6PUFFERiP2PO); +void OnPufferActive(PUFFER *ppuffer, int fActive, PO *ppoOther) +{ + OnPoActive(ppuffer, fActive, ppoOther); +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePufferActive__FP6PUFFERP3JOYf); @@ -34,7 +38,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", AddPufferWaterAcceleration__FP6PUFFERP INCLUDE_ASM("asm/nonmatchings/P2/puffer", HandlePufferMessage__FP6PUFFER5MSGIDPv); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", PostPuffcLoad__FP5PUFFC); +void PostPuffcLoad(PUFFC *ppuffc) +{ + PostStepguardLoad((STEPGUARD *)ppuffc); +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", PresetPuffcAccel__FP5PUFFCf); diff --git a/src/P2/rwm.c b/src/P2/rwm.c index da47f435..ece65381 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); @@ -57,7 +58,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", ClearRwmFireInfo__FP3RWM); INCLUDE_ASM("asm/nonmatchings/P2/rwm", ClearRwmTargetInfo__FP3RWM); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", ClearRwmAimConstraints__FP3RWM); +void ClearRwmAimConstraints(RWM *prwm) +{ + memset((uint8_t *)prwm + 0x150, 0, 0x18); +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", GetRwfiPosMat__FP4RWFIP6VECTORP7MATRIX3); diff --git a/src/P2/screen.c b/src/P2/screen.c index a66201c6..7e05db63 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -71,7 +71,10 @@ void SetBlotDtDisappear(BLOT *pblot, float dtDisappear) pblot->dtDisappear = dtDisappear; } -INCLUDE_ASM("asm/nonmatchings/P2/screen", OnBlotReset__FP4BLOT); +void OnBlotReset(BLOT *pblot) +{ + ((void (*)(BLOT *, BLOTS))pblot->pvtblot->pfnSetBlotBlots)(pblot, BLOTS_Hidden); +} INCLUDE_ASM("asm/nonmatchings/P2/screen", ShowBlot__FP4BLOT); @@ -258,7 +261,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae5e0); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae758); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae7f8); +void FUN_001ae7f8(CTR *pctr, BLOTS blots) +{ + if (blots == BLOTS_Hidden) + pctr->nDisplay = 0; + + SetBlotBlots(pctr, blots); +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae820); diff --git a/src/P2/wm.c b/src/P2/wm.c index 2edf1c0d..0fe3164b 100644 --- a/src/P2/wm.c +++ b/src/P2/wm.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/wm", FUN_001f0468); @@ -12,7 +13,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/wm", BindWm__FP2WM); INCLUDE_ASM("asm/nonmatchings/P2/wm", RefreshWmMoveStats__FP2WM10WORLDLEVEL); -INCLUDE_ASM("asm/nonmatchings/P2/wm", ThrowWmDisplayState__FP2WM10WORLDLEVELi); +extern WORLDLEVEL D_00276250; +extern int D_00276654; + +void ThrowWmDisplayState(WM *pwm, WORLDLEVEL worldlevel, int fReverse) +{ + D_00276250 = worldlevel; + D_00276654 = fReverse; +} INCLUDE_ASM("asm/nonmatchings/P2/wm", CatchWmDisplayState__FP2WM); From ed8f0f06dddd9c9045c86ca5230e6b261ff37e2a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:24:21 +0200 Subject: [PATCH 028/134] Match 6 leaf functions in cplcy/credit/light/pzo/shadow via LHF harness checksum-green (out/SCUS_971.98: OK): PushCplookLookk, FUN_0014a8d0, VacateCredit, SetLightHighlightColor, BreakClue, SetShadowFrustrumUp. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- src/P2/cplcy.c | 18 ++++++++++++++++-- src/P2/credit.c | 7 ++++++- src/P2/light.c | 6 +++++- src/P2/pzo.c | 5 ++++- src/P2/shadow.c | 6 +++++- 6 files changed, 37 insertions(+), 7 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 8fca0580..005ef95a 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -1543,7 +1543,7 @@ FUN_001496c0 = 0x1496C0; // type:func UpdateCplook = 0x149760; // type:func FUN_0014a7b8 = 0x14A7B8; // type:func InitCpalign = 0x14A888; // type:func -FUN_0014a8d0 = 0x14A8D0; // type:func +FUN_0014a8d0__FP7CPALIGN = 0x14A8D0; // type:func UpdateCpalign = 0x14A8F8; // type:func FUN_0014aa90__FPii = 0x14AA90; // type:func FUN_0014aa98__FPv = 0x14AA98; // type:func diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index e938b9d3..abad9fd8 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -28,7 +28,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_00149458); INCLUDE_ASM("asm/nonmatchings/P2/cplcy", plays_binoc_sfx); -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", PushCplookLookk__FP6CPLOOK5LOOKK); +void PushCplookLookk(CPLOOK *pcplook, LOOKK lookk) +{ + int clookk = STRUCT_OFFSET(pcplook, 0x40, int); + if ((unsigned int)clookk < 4) + { + STRUCT_OFFSET_INDEX(pcplook, 0x30, LOOKK, clookk) = lookk; + STRUCT_OFFSET(pcplook, 0x40, int) = clookk + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", LookkPopCplook__FP6CPLOOK); @@ -44,7 +52,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_0014a7b8); INCLUDE_ASM("asm/nonmatchings/P2/cplcy", InitCpalign); -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_0014a8d0); +extern "C" void ResetCmLookAtSmooth(CM *pcm, void *pv); + +void FUN_0014a8d0(CPALIGN *pcpalign) +{ + CM *pcm = pcpalign->pcm; + ResetCmLookAtSmooth(pcm, (void *)((uint8_t *)STRUCT_OFFSET(pcm, 0x3DC, void *) + 0x370)); +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", UpdateCpalign); diff --git a/src/P2/credit.c b/src/P2/credit.c index fdb8deab..80a06f51 100644 --- a/src/P2/credit.c +++ b/src/P2/credit.c @@ -12,6 +12,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/credit", DrawCredit__FP6CREDIT); INCLUDE_ASM("asm/nonmatchings/P2/credit", PlaceCredit__FP6CREDITffi); -INCLUDE_ASM("asm/nonmatchings/P2/credit", VacateCredit__FP6CREDIT); +struct CREDIT; + +void VacateCredit(CREDIT *pcredit) +{ + (*(void (**)(CREDIT *, int))((char *)*(void **)pcredit + 0x40))(pcredit, 0); +} INCLUDE_ASM("asm/nonmatchings/P2/credit", SetCreditLine__FP6CREDITiPcf); diff --git a/src/P2/light.c b/src/P2/light.c index ef552ad1..0a6ada64 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -131,7 +131,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/light", RebuildLightVifs__FP5LIGHT); INCLUDE_ASM("asm/nonmatchings/P2/light", SetLightKind__FP5LIGHT6LIGHTK); -INCLUDE_ASM("asm/nonmatchings/P2/light", SetLightHighlightColor__FP5LIGHTP6VECTOR); +void SetLightHighlightColor(LIGHT *plight, VECTOR *pvecHighlight) +{ + STRUCT_OFFSET(plight, 0x2E0, VU_VECTOR) = *(VU_VECTOR *)pvecHighlight; + RebuildLightVifs(plight); +} void SetLightMidtoneStrength(LIGHT *plight, float gMidtone) { diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 5dbed2c0..a4f8c503 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -163,7 +163,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", OnClueSmack__FP4CLUE); INCLUDE_ASM("asm/nonmatchings/P2/pzo", CollectClue__FP4CLUE); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", BreakClue__FP4CLUE); +void BreakClue(CLUE *pclue) +{ + ((void (*)(CLUE *))STRUCT_OFFSET(pclue->pvtlo, 0x134, void *))(pclue); +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", CollectClueSilent__FP4CLUE); diff --git a/src/P2/shadow.c b/src/P2/shadow.c index 34cff6a8..e96b2835 100644 --- a/src/P2/shadow.c +++ b/src/P2/shadow.c @@ -76,7 +76,11 @@ void SetShadowConeAngle(SHADOW *pshadow, float degConeAngle) InvalidateShadowVifs(pshadow); } -INCLUDE_ASM("asm/nonmatchings/P2/shadow", SetShadowFrustrumUp__FP6SHADOWP6VECTOR); +void SetShadowFrustrumUp(SHADOW *pshadow, VECTOR *pvecUp) +{ + STRUCT_OFFSET(pshadow, 0x30, VU_VECTOR) = *(VU_VECTOR *)pvecUp; + InvalidateShadowVifs(pshadow); +} INCLUDE_ASM("asm/nonmatchings/P2/shadow", FShadowValid__FP6SHADOWi); From 3b845dd3b0405456108480b600d9d0ea6de06e65 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:27:40 +0200 Subject: [PATCH 029/134] Match FUN_001aec90 (screen) via LHF harness Tail wrapper FUN_001aea70(1, 0xFFFF); extern "C" fwd-decl of the raw sibling; renamed FUN_001aec90 -> mangled (no asm callers). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- src/P2/screen.c | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 005ef95a..ce7e9c7a 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3647,7 +3647,7 @@ FUN_001ae820 = 0x1AE820; // type:func FUN_001aea08 = 0x1AEA08; // type:func FUN_001aea70 = 0x1AEA70; // type:func junk_001aec80 = 0x1AEC80; // type:func -FUN_001aec90 = 0x1AEC90; // type:func +FUN_001aec90__Fv = 0x1AEC90; // type:func // Global blots g_lifectr = 0x26c6c8; // size:0x280 diff --git a/src/P2/screen.c b/src/P2/screen.c index 7e05db63..1638b1e8 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -278,4 +278,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001aea70); JUNK_WORD(0xE48C0000); JUNK_WORD(0xE48C0008); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001aec90); +extern "C" void FUN_001aea70(int, int); + +void FUN_001aec90(void) +{ + FUN_001aea70(1, 0xFFFF); +} From d04bfc46ef44783a8b1c8a2ec9f7ae247c688418 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:30:14 +0200 Subject: [PATCH 030/134] Match RobkCur (rog) via LHF harness grfrob bit tests on g_plsCur; '(x & 2) > 0' steers GCC to andi+sltu (matching the ROM) instead of the shift-fold. Removed stale 80%% scratch. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/rog.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/P2/rog.c b/src/P2/rog.c index 8123792d..96ccbffc 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -1,5 +1,6 @@ #include #include +#include extern SNIP s_asnipLoadRov[2]; @@ -93,22 +94,13 @@ void AddRobSpawnTunnel(ROB *prob, OID oidSpawnTunnel) STRUCT_OFFSET(prob, 0x2e0, int) = coidRost + 1; // prob->coidRost } -/** - * @brief 80% match. - * https://decomp.me/scratch/s3oRy - */ -INCLUDE_ASM("asm/nonmatchings/P2/rog", RobkCur__Fv); -#ifdef SKIP_ASM ROBK RobkCur() { - if ((uint)g_plsCur->fls & FLS_Secondary) - { - return ROBK_Tertiary; - } - - return (ROBK)((uint)g_plsCur->fls & FLS_KeyCollected); + int grfrob = *(int *)g_plsCur; + if ((grfrob & 0x4) == 0) + return (ROBK)((grfrob & 0x2) > 0); + return ROBK_Tertiary; } -#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/rog", BindRob__FP3ROB); From af95e87cb6c58af29d1d97869831beaac8e63899 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:34:32 +0200 Subject: [PATCH 031/134] Match GLBS::SetNormal (glbs) via LHF harness Copies VECTOR x/y/z to this+0xFC/0x100/0x104; added JUNK_NOP() so the trailing JUNK_WORD stays aligned. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/glbs.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/P2/glbs.c b/src/P2/glbs.c index e0ed3cad..85d0c977 100644 --- a/src/P2/glbs.c +++ b/src/P2/glbs.c @@ -45,8 +45,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/glbs", DrawThreeWay__4GLBS); INCLUDE_ASM("asm/nonmatchings/P2/glbs", EndStrip__4GLBS); -INCLUDE_ASM("asm/nonmatchings/P2/glbs", SetNormal__4GLBSP6VECTOR); +void GLBS::SetNormal(VECTOR *ppos) +{ + STRUCT_OFFSET(this, 0xFC, float) = ppos->x; + STRUCT_OFFSET(this, 0x100, float) = ppos->y; + STRUCT_OFFSET(this, 0x104, float) = ppos->z; +} +JUNK_NOP(); JUNK_WORD(0xE4800110); INCLUDE_ASM("asm/nonmatchings/P2/glbs", SetRgba__4GLBSG4RGBA); From 687c52e86c437bf4ecd444aef698c804bbab561c Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:36:58 +0200 Subject: [PATCH 032/134] Match NCmpWkr (jt) via LHF harness WKR comparator on the 0x14 float; 'a > b ? 1 : -1' yields the ROM's c.lt.s/bc1f form. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/jt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/P2/jt.c b/src/P2/jt.c index 9f1876c5..163fb714 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -106,7 +106,10 @@ void FUN_00177828(JT *pjt, int n) INCLUDE_ASM("asm/nonmatchings/P2/jt", PaloAbsorbWkr__FP3WKRiPP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/jt", NCmpWkr__FP3WKRT0); +int NCmpWkr(WKR *pwkr1, WKR *pwkr2) +{ + return STRUCT_OFFSET(pwkr1, 0x14, float) > STRUCT_OFFSET(pwkr2, 0x14, float) ? 1 : -1; +} INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtEffect__FP2JT); From babfe1a904a60629655205fbbc3f19f9aba3a350 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:40:17 +0200 Subject: [PATCH 033/134] Match GetAloFrozen (freeze) and DtVisibleCtr (screen) via LHF harness GetAloFrozen: (int)(flag>>38)&1 gives the 5-instr ld/dsrl32/andi form (no dsll32). DtVisibleCtr: g_clock.fEnabled ? 2.5f : 0.0f. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/freeze.c | 5 ++++- src/P2/screen.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/P2/freeze.c b/src/P2/freeze.c index e4829f65..6b2f36fa 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -18,7 +18,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/freeze", RemergeSwObjects__FP2SW); INCLUDE_ASM("asm/nonmatchings/P2/freeze", FreezeAloHierarchy__FP3ALOi); -INCLUDE_ASM("asm/nonmatchings/P2/freeze", GetAloFrozen__FP3ALOPi); +void GetAloFrozen(ALO *palo, int *pf) +{ + *pf = (int)(STRUCT_OFFSET(palo, 0x2c8, unsigned long long) >> 38) & 1; +} INCLUDE_ASM("asm/nonmatchings/P2/freeze", FreezeAlo__FP3ALOi); diff --git a/src/P2/screen.c b/src/P2/screen.c index 1638b1e8..1d230c39 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -100,7 +100,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawCtr__FP3CTR); INCLUDE_ASM("asm/nonmatchings/P2/screen", RebuildCtrAchzDraw__FP3CTR); -INCLUDE_ASM("asm/nonmatchings/P2/screen", DtVisibleCtr__FP3CTR); +float DtVisibleCtr(CTR *pctr) +{ + return g_clock.fEnabled ? 2.5f : 0.0f; +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ab600); From 0daedd72d82e31ec808bc476b55945a148ee7760 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:43:40 +0200 Subject: [PATCH 034/134] Match FUN_001c29e8 (sqtr) and FUN_001e29e8 (tn) via LHF harness extern "C" (raw asm callers); store order tuned to match GCC's scheduling (sqtr 0xc-then-0x8 source -> 0x8/0xc emit; tn 0x364/0x368/ 0x360 source -> 0x360/0x368/0x364 emit). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/sqtr.c | 6 +++++- src/P2/tn.c | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/P2/sqtr.c b/src/P2/sqtr.c index 6e57e4f1..37cdfc42 100644 --- a/src/P2/sqtr.c +++ b/src/P2/sqtr.c @@ -1,6 +1,10 @@ #include -INCLUDE_ASM("asm/nonmatchings/P2/sqtr", FUN_001c29e8); +extern "C" void FUN_001c29e8(SQTRM *psqtrm) +{ + STRUCT_OFFSET(psqtrm, 0xc, int) = 0; + STRUCT_OFFSET(psqtrm, 0x8, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/sqtr", UpdateSqtrm__FP5SQTRMP6VECTORP7MATRIX3ff); diff --git a/src/P2/tn.c b/src/P2/tn.c index dc82c4ee..8953e40f 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -71,7 +71,12 @@ void FreezeTn(TN *ptn, int fFreeze) } } -INCLUDE_ASM("asm/nonmatchings/P2/tn", FUN_001e29e8); +extern "C" void FUN_001e29e8(TN *ptn, float g) +{ + STRUCT_OFFSET(ptn, 0x364, float) = g; + STRUCT_OFFSET(ptn, 0x368, float) = 1.0f; + STRUCT_OFFSET(ptn, 0x360, float) = g; +} INCLUDE_ASM("asm/nonmatchings/P2/tn", CalculateTnCrv__FP2TNP6VECTORN21); From 127633aa8666174dc3567c96ea2fb600ff162b1a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:46:33 +0200 Subject: [PATCH 035/134] Match ProddCurRob (rog) and PcgtExtract (path) via LHF harness ProddCurRob: parenthesize (irodd*0xC0 + 0x3E0) so the base addu stays a0-first. PcgtExtract: tag-bit extract (added struct CGT; fwd-decl). checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/path.c | 8 +++++++- src/P2/rog.c | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/P2/path.c b/src/P2/path.c index 4af75141..83265cb2 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -1,13 +1,19 @@ #include struct CBSP; +struct CGT; CBSP* PcbspExtract(CBSP* pcbsp) { return ((int)pcbsp & 1) ? (CBSP*)0 : pcbsp; } -INCLUDE_ASM("asm/nonmatchings/P2/path", PcgtExtract__FP3CGT); +CGT* PcgtExtract(CGT* pcgt) +{ + if ((int)pcgt & 1) + return (CGT*)((int)pcgt & ~1); + return (CGT*)0; +} INCLUDE_ASM("asm/nonmatchings/P2/path", PcgtPointInCbspQuick__FP4CBSPP6VECTOR); diff --git a/src/P2/rog.c b/src/P2/rog.c index 96ccbffc..b8180b1e 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -147,7 +147,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", FChooseRobReturnPoint__FP3ROBP3ROH); INCLUDE_ASM("asm/nonmatchings/P2/rog", ChooseRobWanderLocation__FP3ROBP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", ProddCurRob__FP3ROB4ENSK); +RODD *ProddCurRob(ROB *prob, ENSK ensk) +{ + int irodd = STRUCT_OFFSET(prob, 0x620, int); + return (RODD *)((uint8_t *)prob + (irodd * 0xC0 + 0x3E0)); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRoh__FP3ROH); From 80d641c49a506d96136ba367a7ac627e15fa3bb1 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:50:47 +0200 Subject: [PATCH 036/134] Match FUN_001f0468 (wm) via LHF harness extern "C" (raw asm callers); 'if (D != 2) return g_pgsCur->[0x19DC]; return 10;' yields the ROM's bne block order. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/wm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/P2/wm.c b/src/P2/wm.c index 0fe3164b..13976ba6 100644 --- a/src/P2/wm.c +++ b/src/P2/wm.c @@ -1,7 +1,14 @@ #include #include -INCLUDE_ASM("asm/nonmatchings/P2/wm", FUN_001f0468); +extern int D_00275BF0; + +extern "C" int FUN_001f0468(void) +{ + if (D_00275BF0 != 2) + return STRUCT_OFFSET(g_pgsCur, 0x19DC, int); + return 10; +} INCLUDE_ASM("asm/nonmatchings/P2/wm", FUN_001f0490); From 922a1f1ddeb9112e9e9758a52a0657646824604e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:52:01 +0200 Subject: [PATCH 037/134] Match SetJtPuppet (jt) via LHF harness Wrapper: SetJtJts(pjt, paseg ? JTS_Peek : JTS_Stand, JTBS_Nil); the ternary yields the movz idiom. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/jt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/P2/jt.c b/src/P2/jt.c index 163fb714..e326f92c 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -96,7 +96,10 @@ void ProfileJt(JT *pjt, int fProfile) return; } -INCLUDE_ASM("asm/nonmatchings/P2/jt", SetJtPuppet__FP2JTP5ASEGA); +void SetJtPuppet(JT *pjt, ASEGA *paseg) +{ + SetJtJts(pjt, paseg ? JTS_Peek : JTS_Stand, JTBS_Nil); +} void FUN_00177828(JT *pjt, int n) { From b97e0fc3cc299a9633f2ce9b5463bf5eed4c3f40 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:53:51 +0200 Subject: [PATCH 038/134] Match FindPathzoneClosestPoint and FUN_00191aa8 (path) via LHF harness Two CG/CBSP sub-object forwarding wrappers (a0 += 0x34 / a0 = a0->0x54); FUN_00191aa8 extern "C" for its raw caller. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/path.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/P2/path.c b/src/P2/path.c index 83265cb2..5e812d49 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -2,6 +2,7 @@ struct CBSP; struct CGT; +struct LSG; CBSP* PcbspExtract(CBSP* pcbsp) { @@ -54,9 +55,19 @@ int CposFindPathzonePath(PATHZONE *ppathzone, VECTOR *pvec0, VECTOR *pvec1, int return CposFindPath((CG *)((char *)ppathzone + 0x34), pvec0, pvec1, n, pvec2); } -INCLUDE_ASM("asm/nonmatchings/P2/path", FindPathzoneClosestPoint__FP8PATHZONEP6VECTORT1); +void FindClosestPointInCg(CG *pcg, VECTOR *pvec0, VECTOR *pvec1); -INCLUDE_ASM("asm/nonmatchings/P2/path", FUN_00191aa8); +void FindPathzoneClosestPoint(PATHZONE *ppathzone, VECTOR *pvec0, VECTOR *pvec1) +{ + FindClosestPointInCg((CG *)((char *)ppathzone + 0x34), pvec0, pvec1); +} + +int ClsgClipEdgeToCbsp(CBSP *pcbsp, VECTOR *pvec0, VECTOR *pvec1, int i, LSG *plsg); + +extern "C" int FUN_00191aa8(void *p, VECTOR *pvec0, VECTOR *pvec1, int i, LSG *plsg) +{ + return ClsgClipEdgeToCbsp(STRUCT_OFFSET(p, 0x54, CBSP *), pvec0, pvec1, i, plsg); +} INCLUDE_ASM("asm/nonmatchings/P2/path", FUN_00191ac8); From 44cb5fcf85f9e72a18a42e8f99b6c92176763e60 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:57:00 +0200 Subject: [PATCH 039/134] Match GetActScale (act) and FUN_00197a68 (puffer) via LHF harness GetActScale: 3x qword copy of global MATRIX3 D_002483D0. FUN_00197a68: extern "C" (rodata table ref); temps force both global-float loads before the stores. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 9 ++++++++- src/P2/puffer.c | 11 ++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index 4e944e02..5a1df3a4 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -20,7 +20,14 @@ void GetActTwistGoal(ACT *pact, float *pradTwist, float *pdradTwist) *(int *)pdradTwist = 0; } -INCLUDE_ASM("asm/nonmatchings/P2/act", GetActScale__FP3ACTP7MATRIX3); +extern char D_002483D0[]; + +void GetActScale(ACT *pact, MATRIX3 *pmat) +{ + *(qword *)((char *)pmat + 0x0) = *(qword *)(D_002483D0 + 0x0); + *(qword *)((char *)pmat + 0x10) = *(qword *)(D_002483D0 + 0x10); + *(qword *)((char *)pmat + 0x20) = *(qword *)(D_002483D0 + 0x20); +} float GGetActPoseGoal(ACT *pact, int ipose) { diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 010149a2..fb5340ac 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -32,7 +32,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197848); INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197a08); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197a68); +extern float D_0026A83C; +extern float D_0026A840; + +extern "C" void FUN_00197a68(void *pv, void *p) +{ + float dx = D_0026A83C; + float dy = D_0026A840; + STRUCT_OFFSET(p, 0x98, float) = dx; + STRUCT_OFFSET(p, 0x94, float) = dy; +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", AddPufferWaterAcceleration__FP6PUFFERP5WATERf); From 19c1080f7cd64572b73056be487d275399d7aa37 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:58:23 +0200 Subject: [PATCH 040/134] Match MATRIX4::PostCopyMatrix3 (mat) via LHF harness Declared as a MATRIX4 member (layout-neutral) to match the method mangling its asm callers use; zeros col-3 w-components and sets row 3 from D_0024B260. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- include/mat.h | 3 ++- src/P2/mat.c | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/mat.h b/include/mat.h index 34ddb25a..d9e58a98 100644 --- a/include/mat.h +++ b/include/mat.h @@ -14,6 +14,8 @@ struct MATRIX4 { float mat[4][4]; + + void PostCopyMatrix3(); }; /** @@ -24,7 +26,6 @@ struct MATRIX3 float mat[3][3]; }; -void PostCopyMatrix3(MATRIX4 *pmat); MATRIX3 *MatMulMatTransMat(MATRIX3 *matLeft, MATRIX3 *matRight); diff --git a/src/P2/mat.c b/src/P2/mat.c index 2b5c228a..5baadfc9 100644 --- a/src/P2/mat.c +++ b/src/P2/mat.c @@ -3,7 +3,15 @@ extern VECTOR g_normalZ; -INCLUDE_ASM("asm/nonmatchings/P2/mat", PostCopyMatrix3__7MATRIX4); +extern qword D_0024B260; + +void MATRIX4::PostCopyMatrix3() +{ + STRUCT_OFFSET(this, 0xc, int) = 0; + STRUCT_OFFSET(this, 0x1c, int) = 0; + STRUCT_OFFSET(this, 0x2c, int) = 0; + *(qword *)((char *)this + 0x30) = D_0024B260; +} INCLUDE_ASM("asm/nonmatchings/P2/mat", __as__7MATRIX4RC7MATRIX3); From 324ac1857a381fe4f0c7e316b4ca05386b06799e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 11:59:37 +0200 Subject: [PATCH 041/134] Match CFontBrx::FValid (font) via LHF harness Declared FValid/PglyffFromCh as CFontBrx members (layout-neutral); returns PglyffFromCh(ch) != 0. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- include/font.h | 4 ++++ src/P2/font.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/font.h b/include/font.h index d861e278..79c346dc 100644 --- a/include/font.h +++ b/include/font.h @@ -37,6 +37,10 @@ class CFont class CFontBrx : public CFont { + public: + void *PglyffFromCh(char ch); + bool FValid(char ch); + private: undefined1 m_padding[0x33]; }; diff --git a/src/P2/font.c b/src/P2/font.c index d75adc6c..14b14363 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -48,7 +48,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", PfontClone__8CFontBrxff); INCLUDE_ASM("asm/nonmatchings/P2/font", CopyTo__8CFontBrxP8CFontBrx); -INCLUDE_ASM("asm/nonmatchings/P2/font", FValid__8CFontBrxc); +bool CFontBrx::FValid(char ch) +{ + return PglyffFromCh(ch) != 0; +} INCLUDE_ASM("asm/nonmatchings/P2/font", DxFromCh__8CFontBrxc); From 75b21ab28b2123a8326e56b932079e97b108bf81 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:01:30 +0200 Subject: [PATCH 042/134] Match FUN_001419A0/FUN_001419C0 (chkpnt) via LHF harness Array-append: 'int *a = &STRUCT_OFFSET(p, off, int); a[c] = n' yields the ROM's a0-first addu (the bare-pointer form gave index-first). extern "C" for raw callers. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/chkpnt.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index b94b0b02..649fd3ee 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -69,9 +69,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001417f0); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", TriggerChkpnt__FP6CHKPNT); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001419A0); +extern "C" void FUN_001419A0(CHKPNT *pchkpnt, int n) +{ + int c = STRUCT_OFFSET(pchkpnt, 0x578, int); + int *a = &STRUCT_OFFSET(pchkpnt, 0x57c, int); + a[c] = n; + STRUCT_OFFSET(pchkpnt, 0x578, int) = c + 1; +} -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001419C0); +extern "C" void FUN_001419C0(CHKPNT *pchkpnt, int n) +{ + int c = STRUCT_OFFSET(pchkpnt, 0x550, int); + int *a = &STRUCT_OFFSET(pchkpnt, 0x554, int); + a[c] = n; + STRUCT_OFFSET(pchkpnt, 0x550, int) = c + 1; +} void FUN_001419E0(int *param_1, int param_2) { From 171975dd6ccb241ec9298b298cc2d1fe5bdb5981 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:07:23 +0200 Subject: [PATCH 043/134] Match 12 array-append functions via LHF harness (pzo/button/sensor/missile/stepguard/smartguard) The cracked append idiom (named array pointer + a[c]) yields the ROM's a0-first addu; bounded variants use (unsigned)c < N for sltiu; button's return variants reuse c to land the address temp in v0. extern "C" for raw-referenced FUN_ names. checksum-green (out/SCUS_971.98: OK). Matched: AddSprizeAseg, FAddAshOid, FAddAshAseg, AddSensorTriggerObject, AddSensorNoTriggerObject, AddSensorTriggerClass, AddSensorNoTriggerClass, FUN_0018dd50, FUN_0018dd78, AddSggGuardName, AddSggSearchXfmName, FUN_001B7100. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/button.c | 20 ++++++++++++++++++-- src/P2/missile.c | 22 ++++++++++++++++++++-- src/P2/pzo.c | 8 +++++++- src/P2/sensor.c | 44 ++++++++++++++++++++++++++++++++++++++++---- src/P2/smartguard.c | 11 ++++++++++- src/P2/stepguard.c | 22 ++++++++++++++++++++-- 6 files changed, 115 insertions(+), 12 deletions(-) diff --git a/src/P2/button.c b/src/P2/button.c index 6a569ee8..ea06800d 100644 --- a/src/P2/button.c +++ b/src/P2/button.c @@ -5,9 +5,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/button", PostAshLoad__FP2SWP3ASHP3ALO); INCLUDE_ASM("asm/nonmatchings/P2/button", FFoundAshAseg__FP3ASHP4ASEG); -INCLUDE_ASM("asm/nonmatchings/P2/button", FAddAshAseg__FP3ASHP4ASEG); +int FAddAshAseg(ASH *pash, ASEG * paseg) +{ + int c = STRUCT_OFFSET(pash, 0x44, int); + ASEG * *a = &STRUCT_OFFSET(pash, 0x48, ASEG *); + a[c] = paseg; + c = c + 1; + STRUCT_OFFSET(pash, 0x44, int) = c; + return c < 16; +} -INCLUDE_ASM("asm/nonmatchings/P2/button", FAddAshOid__FP3ASH3OID); +int FAddAshOid(ASH *pash, OID oid) +{ + int c = STRUCT_OFFSET(pash, 0x0, int); + OID *a = &STRUCT_OFFSET(pash, 0x4, OID); + a[c] = oid; + c = c + 1; + STRUCT_OFFSET(pash, 0x0, int) = c; + return c < 16; +} void InitBtn(BTN *pbtn) { diff --git a/src/P2/missile.c b/src/P2/missile.c index 5d65e43c..10ddd85d 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -27,9 +27,27 @@ INCLUDE_ASM("asm/nonmatchings/P2/missile", RenderMissileAll__FP7MISSILEP2CMP2RO) INCLUDE_ASM("asm/nonmatchings/P2/missile", FUN_0018dc88); -INCLUDE_ASM("asm/nonmatchings/P2/missile", FUN_0018dd50); +extern "C" void FUN_0018dd50(void * p, int val) +{ + int c = STRUCT_OFFSET(p, 0x6bc, int); + if ((unsigned int)c < 4) + { + int *a = &STRUCT_OFFSET(p, 0x6c0, int); + a[c] = val; + STRUCT_OFFSET(p, 0x6bc, int) = c + 1; + } +} -INCLUDE_ASM("asm/nonmatchings/P2/missile", FUN_0018dd78); +extern "C" void FUN_0018dd78(void * p, int val) +{ + int c = STRUCT_OFFSET(p, 0x6d0, int); + if ((unsigned int)c < 4) + { + int *a = &STRUCT_OFFSET(p, 0x6d4, int); + a[c] = val; + STRUCT_OFFSET(p, 0x6d0, int) = c + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/missile", InitAccmiss__FP7ACCMISS); diff --git a/src/P2/pzo.c b/src/P2/pzo.c index a4f8c503..1b93c554 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -19,7 +19,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", EmitSprizeExplosion__FP6SPRIZE); INCLUDE_ASM("asm/nonmatchings/P2/pzo", PcsFromSprize__FP6SPRIZE); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", AddSprizeAseg__FP6SPRIZE3OID); +void AddSprizeAseg(SPRIZE * p, OID oidAseg) +{ + int c = STRUCT_OFFSET(p, 0x55c, int); + OID *a = &STRUCT_OFFSET(p, 0x560, OID); + a[c] = oidAseg; + STRUCT_OFFSET(p, 0x55c, int) = c + 1; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", HandleSprizeMessage__FP6SPRIZE5MSGIDPv); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 7c383362..098e3d71 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -63,7 +63,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", PauseSensor__FP6SENSOR); INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateSensor__FP6SENSORf); -INCLUDE_ASM("asm/nonmatchings/P2/sensor", AddSensorTriggerObject__FP6SENSOR3OID); +void AddSensorTriggerObject(SENSOR * p, OID oid) +{ + int c = STRUCT_OFFSET(p, 0x564, int); + if ((unsigned int)c < 4) + { + OID *a = &STRUCT_OFFSET(p, 0x568, OID); + a[c] = oid; + STRUCT_OFFSET(p, 0x564, int) = c + 1; + } +} #ifdef SKIP_ASM /** * @todo 100% matched but sensor struct offsets are wrong. @@ -79,7 +88,16 @@ void AddSensorTriggerObject(SENSOR *psensor, OID oid) } #endif -INCLUDE_ASM("asm/nonmatchings/P2/sensor", AddSensorNoTriggerObject__FP6SENSOR3OID); +void AddSensorNoTriggerObject(SENSOR * p, OID oid) +{ + int c = STRUCT_OFFSET(p, 0x578, int); + if ((unsigned int)c < 4) + { + OID *a = &STRUCT_OFFSET(p, 0x57c, OID); + a[c] = oid; + STRUCT_OFFSET(p, 0x578, int) = c + 1; + } +} #ifdef SKIP_ASM /** * @todo 100% matched but sensor struct offsets are wrong. @@ -95,7 +113,16 @@ void AddSensorNoTriggerObject(SENSOR *psensor, OID oid) } #endif -INCLUDE_ASM("asm/nonmatchings/P2/sensor", AddSensorTriggerClass__FP6SENSOR3CID); +void AddSensorTriggerClass(SENSOR * p, CID cid) +{ + int c = STRUCT_OFFSET(p, 0x58c, int); + if ((unsigned int)c < 4) + { + CID *a = &STRUCT_OFFSET(p, 0x590, CID); + a[c] = cid; + STRUCT_OFFSET(p, 0x58c, int) = c + 1; + } +} #ifdef SKIP_ASM /** * @todo 100% matched but sensor struct offsets are wrong. @@ -111,7 +138,16 @@ void AddSensorTriggerClass(SENSOR *psensor, CID cid) } #endif -INCLUDE_ASM("asm/nonmatchings/P2/sensor", AddSensorNoTriggerClass__FP6SENSOR3CID); +void AddSensorNoTriggerClass(SENSOR * p, CID cid) +{ + int c = STRUCT_OFFSET(p, 0x5a0, int); + if ((unsigned int)c < 4) + { + CID *a = &STRUCT_OFFSET(p, 0x5a4, CID); + a[c] = cid; + STRUCT_OFFSET(p, 0x5a0, int) = c + 1; + } +} #ifdef SKIP_ASM /** * @todo 100% matched but sensor struct offsets are wrong. diff --git a/src/P2/smartguard.c b/src/P2/smartguard.c index fcaa9aba..5986ceb0 100644 --- a/src/P2/smartguard.c +++ b/src/P2/smartguard.c @@ -13,7 +13,16 @@ void UseSmartguardFlashlightTarget(SMARTGUARD *psmartguard, SGS sgs, OID oidTarg mpsgssgft[sgs].oidTarget = oidTarget; } -INCLUDE_ASM("asm/nonmatchings/P2/smartguard", FUN_001B7100__FP10SMARTGUARDi); +void FUN_001B7100(SMARTGUARD *p, int val) +{ + int c = STRUCT_OFFSET(p, 0xcd4, int); + if ((unsigned int)c < 4) + { + long long *a = &STRUCT_OFFSET(p, 0xcd8, long long); + *(int *)&a[c] = val; + STRUCT_OFFSET(p, 0xcd4, int) = c + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/smartguard", PostSmartguardLoad__FP10SMARTGUARD); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 6f8e757c..d6a2e4f3 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -271,9 +271,27 @@ void InitSgg(SGG *psgg) INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddSggGuard__FP3SGGP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddSggGuardName__FP3SGG3OID); +void AddSggGuardName(SGG * p, OID oid) +{ + int c = STRUCT_OFFSET(p, 0x9c, int); + if ((unsigned int)c < 16) + { + OID *a = &STRUCT_OFFSET(p, 0xa0, OID); + a[c] = oid; + STRUCT_OFFSET(p, 0x9c, int) = c + 1; + } +} -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddSggSearchXfmName__FP3SGG3OID); +void AddSggSearchXfmName(SGG * p, OID oid) +{ + int c = STRUCT_OFFSET(p, 0x124, int); + if ((unsigned int)c < 16) + { + OID *a = &STRUCT_OFFSET(p, 0x128, OID); + a[c] = oid; + STRUCT_OFFSET(p, 0x124, int) = c + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", RemoveSggGuard__FP3SGGP9STEPGUARD); From 8eaae8ee0e29d1b2f2f4710a5826ae95fb8aa89b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:10:44 +0200 Subject: [PATCH 044/134] Match LookkPopCplook (cplcy) via LHF harness Stack pop: 'if (n<=0) return -1' + cracked array-pointer read yields the ROM's blez/a0-first addu. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/cplcy.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index abad9fd8..1b5c38bb 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -38,7 +38,16 @@ void PushCplookLookk(CPLOOK *pcplook, LOOKK lookk) } } -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", LookkPopCplook__FP6CPLOOK); +LOOKK LookkPopCplook(CPLOOK *pcplook) +{ + int n = STRUCT_OFFSET(pcplook, 0x40, int); + if (n <= 0) + return (LOOKK)-1; + n = n - 1; + STRUCT_OFFSET(pcplook, 0x40, int) = n; + LOOKK *a = &STRUCT_OFFSET(pcplook, 0x30, LOOKK); + return a[n]; +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", LookkCurCplook__FP6CPLOOK); From b6e743aa70d930deeeecc8c1e928b66ea8e46a81 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:12:15 +0200 Subject: [PATCH 045/134] Match FReachedStepguardGoal (stepguard) and FFilterFastShadows (shadow) Explicit 'int f = 0; if (...) f = ...; return f;' yields the ROM's merged-result register form; FReached needed the equality operands swapped to match lw order. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/shadow.c | 8 +++++++- src/P2/stepguard.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/P2/shadow.c b/src/P2/shadow.c index e96b2835..7cef73fb 100644 --- a/src/P2/shadow.c +++ b/src/P2/shadow.c @@ -84,7 +84,13 @@ void SetShadowFrustrumUp(SHADOW *pshadow, VECTOR *pvecUp) INCLUDE_ASM("asm/nonmatchings/P2/shadow", FShadowValid__FP6SHADOWi); -INCLUDE_ASM("asm/nonmatchings/P2/shadow", FFilterFastShadows__FPvP2SO); +int FFilterFastShadows(void *pv, SO *pso) +{ + int fFast = 0; + if (!(STRUCT_OFFSET(pso, 0x538, unsigned long long) & ((unsigned long long)0x8000 << 28))) + fFast = STRUCT_OFFSET(pso, 0x410, int) != 0; + return fFast; +} INCLUDE_ASM("asm/nonmatchings/P2/shadow", UpdateShadow__FP6SHADOWf); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index d6a2e4f3..2145dff3 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -107,7 +107,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SgsNextStepguardAI__FP9STEPGUARD); INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SetStepguardGoal__FP9STEPGUARDP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FReachedStepguardGoal__FP9STEPGUARD); +int FReachedStepguardGoal(STEPGUARD *pstepguard) +{ + int fReached = 0; + if (STRUCT_OFFSET(pstepguard, 0xa60, int)) + fReached = STRUCT_OFFSET(pstepguard, 0x930, int) == STRUCT_OFFSET(pstepguard, 0x92c, int); + return fReached; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FFilterStepguardJump__FP9STEPGUARDP2SO); From 8b6ca963bda2cfe0242ec14c2c3c63b59555fc62 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:19:23 +0200 Subject: [PATCH 046/134] Match GLBS::SetUv (glbs) via LHF harness 8-byte unaligned copy (ldl/ldr/sdl/sdr) via a packed long long; updated glbs.h to UVF* to match the symbol mangling. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- include/glbs.h | 3 ++- src/P2/glbs.c | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/include/glbs.h b/include/glbs.h index 2b000f78..dc7fd5c8 100644 --- a/include/glbs.h +++ b/include/glbs.h @@ -13,6 +13,7 @@ // Forward. struct UV; +struct UVF; /** * @brief (?) kind. @@ -94,7 +95,7 @@ struct GLBS void SetRgba(RGBA &rgba); // Might not be correct. - void SetUv(UV *puv); + void SetUv(UVF *puv); void SetVtx(int fAdc); }; diff --git a/src/P2/glbs.c b/src/P2/glbs.c index 85d0c977..3a8ddfa7 100644 --- a/src/P2/glbs.c +++ b/src/P2/glbs.c @@ -57,6 +57,10 @@ JUNK_WORD(0xE4800110); INCLUDE_ASM("asm/nonmatchings/P2/glbs", SetRgba__4GLBSG4RGBA); -INCLUDE_ASM("asm/nonmatchings/P2/glbs", SetUv__4GLBSP3UVF); +void GLBS::SetUv(UVF *puv) +{ + struct PACK { long long v; } __attribute__((packed)); + *(PACK *)((char *)this + 0x118) = *(PACK *)puv; +} INCLUDE_ASM("asm/nonmatchings/P2/glbs", AddVtx__4GLBSi); From e3b5a38abdb0b121e41b50c387e743ca4279f8e1 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:20:29 +0200 Subject: [PATCH 047/134] Match FUN_001cac28 (stepguard) via LHF harness Symbol mangling __FP9STEPGUARD is truncated (1 param) but the body stores a1; defined as extern "C" with the literal symbol name so a 2-param function provides it. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/stepguard.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 2145dff3..98324be8 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -227,7 +227,10 @@ void SetStepguardEnemyObject(STEPGUARD *pstepguard, SO *psoEnemy) INCLUDE_ASM("asm/nonmatchings/P2/stepguard", RebindStepguardEnemy__FP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001cac28__FP9STEPGUARD); +extern "C" void FUN_001cac28__FP9STEPGUARD(STEPGUARD *pstepguard, int n) +{ + STRUCT_OFFSET(pstepguard, 0xB50, int) = n; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001cac30); From 2c96a8f1a735dbb4da7813527c4757c0dc8ec687 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:21:20 +0200 Subject: [PATCH 048/134] Match GLBS::SetRgba (glbs) via LHF harness The G4RGBA by-value mangling reads a1 as a pointer (ABI invisible-ref) which plain C++ can't reproduce; defined as extern "C" with the literal symbol name and a RGBA* param + packed int copy. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/glbs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/P2/glbs.c b/src/P2/glbs.c index 3a8ddfa7..4ee33e9d 100644 --- a/src/P2/glbs.c +++ b/src/P2/glbs.c @@ -55,7 +55,11 @@ void GLBS::SetNormal(VECTOR *ppos) JUNK_NOP(); JUNK_WORD(0xE4800110); -INCLUDE_ASM("asm/nonmatchings/P2/glbs", SetRgba__4GLBSG4RGBA); +extern "C" void SetRgba__4GLBSG4RGBA(GLBS *pglbs, RGBA *prgba) +{ + struct PACK { int v; } __attribute__((packed)); + *(PACK *)((char *)pglbs + 0x114) = *(PACK *)prgba; +} void GLBS::SetUv(UVF *puv) { From 7375164cdefde9352c662995a5757d62054ff297 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:22:31 +0200 Subject: [PATCH 049/134] Match LookkCurCplook (cplcy) via LHF harness Explicit 'int i = n - 1' index defeats GCC's fold of (n-1)*4+0x30 into a displacement, restoring the ROM's addiu/sll/addu form. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/cplcy.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index 1b5c38bb..b78dd821 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -49,7 +49,15 @@ LOOKK LookkPopCplook(CPLOOK *pcplook) return a[n]; } -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", LookkCurCplook__FP6CPLOOK); +LOOKK LookkCurCplook(CPLOOK *pcplook) +{ + int n = STRUCT_OFFSET(pcplook, 0x40, int); + if (n <= 0) + return (LOOKK)-1; + int i = n - 1; + LOOKK *a = &STRUCT_OFFSET(pcplook, 0x30, LOOKK); + return a[i]; +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", InitCplook); From 431048296bef14dcd01fce2d7309232e9ed571a0 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:25:05 +0200 Subject: [PATCH 050/134] Match InitAct (act) via LHF harness Four -1 sentinel bytes at 0x10-0x13 + palo at 0x4; the int 'du' local (reused for three bytes) and a separate literal for 0x13 reproduce the ROM's two -1 registers, and the source store order compensates for GCC's scheduling. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/P2/act.c b/src/P2/act.c index 5a1df3a4..cc9e6712 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -6,7 +6,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/act", PactNewClone__FP3ACTP2SWP3ALO); INCLUDE_ASM("asm/nonmatchings/P2/act", CloneAct__FP3ACTT0); -INCLUDE_ASM("asm/nonmatchings/P2/act", InitAct__FP3ACTP3ALO); +void InitAct(ACT *pact, ALO *palo) +{ + int du = -1; + STRUCT_OFFSET(pact, 0x12, char) = du; + pact->palo = palo; + STRUCT_OFFSET(pact, 0x13, char) = -1; + STRUCT_OFFSET(pact, 0x11, char) = du; + STRUCT_OFFSET(pact, 0x10, char) = du; +} INCLUDE_ASM("asm/nonmatchings/P2/act", RetractAct__FP3ACTi); From f0f1515f19cdaa2d5fecf2214a9e80a8083191c2 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 12:26:13 +0200 Subject: [PATCH 051/134] Match LoadHndFromBrx (hnd) via LHF harness Resolves the long-standing 'objdiff 100%% but checksum fails' TODO: the wrapper needed a JUNK_NOP() before the JUNK_ADDIUs so the function's trailing nop is emitted. checksum-green (out/SCUS_971.98: OK). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/hnd.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/P2/hnd.c b/src/P2/hnd.c index 83e802a3..16f2a71a 100644 --- a/src/P2/hnd.c +++ b/src/P2/hnd.c @@ -13,16 +13,11 @@ void InitHnd(HND *phnd) STRUCT_OFFSET(phnd, 0xb4, float) = val; } -/** - * @todo Objdiff reports a 100% match, but checksum check still fails. - */ -INCLUDE_ASM("asm/nonmatchings/P2/hnd", LoadHndFromBrx__FP3HNDP18CBinaryInputStream); -#ifdef SKIP_ASM void LoadHndFromBrx(HND *phnd, CBinaryInputStream *pbis) { LoadXfmFromBrx(phnd, pbis); } -#endif // SKIP_ASM +JUNK_NOP(); JUNK_ADDIU(A0); JUNK_ADDIU(E0); From 0af2f42d3c5d4d7713eccf9dba3948655853e5c9 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 17:55:28 +0200 Subject: [PATCH 052/134] Remove dead #ifdef SKIP_ASM attempt-blocks (cm/sensor) These pre-existing non-matching attempts were left orphaned next to the now-matched plain C definitions; the --clean build excluded them but the objdiff --objects dual-build hit redefinition errors. Both build configs green again; report.json generates cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/cm.c | 7 ------ src/P2/sensor.c | 60 ------------------------------------------------- 2 files changed, 67 deletions(-) diff --git a/src/P2/cm.c b/src/P2/cm.c index a467cdf4..5f27c171 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -273,13 +273,6 @@ extern "C" bool FUN_00145DD8(undefined4 unused, CM *pcm) { return STRUCT_OFFSET(pcm, 0x538, int) != 0; } -#ifdef SKIP_ASM -bool FUN_00145DD8(CM *pcm) -{ - return pcm->cptn.tMoveLast != 0; //If tMoveLast is a int/undefined4 it matches only it uses a0 instead of a1 :/ -} -#endif - INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145de8); INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145e68); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 098e3d71..9c5e1f88 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -73,21 +73,6 @@ void AddSensorTriggerObject(SENSOR * p, OID oid) STRUCT_OFFSET(p, 0x564, int) = c + 1; } } - #ifdef SKIP_ASM -/** - * @todo 100% matched but sensor struct offsets are wrong. - */ -void AddSensorTriggerObject(SENSOR *psensor, OID oid) -{ - uint ccur = psensor->ctriggerObjects; - if (ccur >= 4) - return; - - psensor->atriggerObjects[ccur] = oid; - psensor->ctriggerObjects = ccur + 1; -} -#endif - void AddSensorNoTriggerObject(SENSOR * p, OID oid) { int c = STRUCT_OFFSET(p, 0x578, int); @@ -98,21 +83,6 @@ void AddSensorNoTriggerObject(SENSOR * p, OID oid) STRUCT_OFFSET(p, 0x578, int) = c + 1; } } - #ifdef SKIP_ASM -/** - * @todo 100% matched but sensor struct offsets are wrong. - */ -void AddSensorNoTriggerObject(SENSOR *psensor, OID oid) -{ - uint ccur = psensor->cnoTriggerObjects; - if (ccur >= 4) - return; - - psensor->anoTriggerObjects[ccur] = oid; - psensor->cnoTriggerObjects = ccur + 1; -} -#endif - void AddSensorTriggerClass(SENSOR * p, CID cid) { int c = STRUCT_OFFSET(p, 0x58c, int); @@ -123,21 +93,6 @@ void AddSensorTriggerClass(SENSOR * p, CID cid) STRUCT_OFFSET(p, 0x58c, int) = c + 1; } } - #ifdef SKIP_ASM -/** - * @todo 100% matched but sensor struct offsets are wrong. - */ -void AddSensorTriggerClass(SENSOR *psensor, CID cid) -{ - uint ccur = psensor->ctriggerClasses; - if (ccur >= 4) - return; - - psensor->atriggerClasses[ccur] = cid; - psensor->ctriggerClasses = ccur + 1; -} -#endif - void AddSensorNoTriggerClass(SENSOR * p, CID cid) { int c = STRUCT_OFFSET(p, 0x5a0, int); @@ -148,21 +103,6 @@ void AddSensorNoTriggerClass(SENSOR * p, CID cid) STRUCT_OFFSET(p, 0x5a0, int) = c + 1; } } - #ifdef SKIP_ASM -/** - * @todo 100% matched but sensor struct offsets are wrong. - */ -void AddSensorNoTriggerClass(SENSOR *psensor, CID cid) -{ - uint ccur = psensor->cnoTriggerClasses; - if (ccur >= 4) - return; - - psensor->anoTriggerClasses[ccur] = cid; - psensor->cnoTriggerClasses = ccur + 1; -} -#endif - INCLUDE_ASM("asm/nonmatchings/P2/sensor", InitLasen__FP5LASEN); INCLUDE_ASM("asm/nonmatchings/P2/sensor", LoadLasenFromBrx__FP5LASENP18CBinaryInputStream); From 312de9d062512f6d44f7aace1dacdf3ab5813dea Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 20:27:49 +0200 Subject: [PATCH 053/134] Match 28 medium (11-20 instr) functions via LHF harness First wave of the widened size window. Wrappers, list-walks, vtable dispatch, ensure/clone/init patterns across blip/coin/crv/emitter/hide/ po/pzo/rwm/screen/sensor/stepguard/tn/wipe. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 4 +-- src/P2/blip.c | 7 +++++- src/P2/coin.c | 9 ++++++- src/P2/crv.c | 24 ++++++++++++++++-- src/P2/emitter.c | 26 +++++++++++++++++--- src/P2/font.c | 54 +++++++++++++++++++++++++++++++++++++++++ src/P2/hide.c | 20 ++++++++++++--- src/P2/po.c | 7 +++++- src/P2/pzo.c | 54 +++++++++++++++++++++++++++++++++++------ src/P2/rwm.c | 15 ++++++++++-- src/P2/screen.c | 6 ++++- src/P2/sensor.c | 31 ++++++++++++++++++++--- src/P2/stepguard.c | 7 +++++- src/P2/tn.c | 13 +++++++++- src/P2/wipe.c | 6 ++++- 15 files changed, 253 insertions(+), 30 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index ce7e9c7a..953d4b9f 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3048,7 +3048,7 @@ MakePoActive__FP2PO = 0x192418; // type:func FInvulnerablePo__FP2PO3ZPK = 0x192450; // type:func FTakePoDamage__FP2POP3ZPR = 0x192488; // type:func JthsCurrentPo__FP2PO = 0x192490; // type:func -FUN_00192498 = 0x192498; // type:func +FUN_00192498__FP2POPi = 0x192498; // type:func CollectPoPrize__FP2PO3PCKP3ALO = 0x1924C8; // type:func FUN_001925C0 = 0x1925C0; // type:func PpoCur__Fv = 0x1925F0; // type:func @@ -3628,7 +3628,7 @@ DrawTotals__FP6TOTALS = 0x1AD3F0; // type:func FUN_001ad6a8 = 0x1AD6A8; // type:func FUN_001ad718 = 0x1AD718; // type:func FUN_001ad7b0 = 0x1AD7B0; // type:func -FUN_001ad940 = 0x1AD940; // type:func +FUN_001ad940__FP4BLOT = 0x1AD940; // type:func FUN_001ad970 = 0x1AD970; // type:func DrawLetterbox__FP9LETTERBOX = 0x1ADB00; // type:func FUN_001adc60 = 0x1ADC60; // type:func diff --git a/src/P2/blip.c b/src/P2/blip.c index 2f236ae9..fec690c5 100644 --- a/src/P2/blip.c +++ b/src/P2/blip.c @@ -19,7 +19,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/blip", PblipgNew__FP2SW); INCLUDE_ASM("asm/nonmatchings/P2/blip", InitBlipg__FP5BLIPG); -INCLUDE_ASM("asm/nonmatchings/P2/blip", OnBlipgAdd__FP5BLIPG); +void OnBlipgAdd(BLIPG *pblipg) +{ + RemoveDlEntry((DL *)((uint8_t *)STRUCT_OFFSET(pblipg, 0x14, void *) + 0x1CC0), pblipg); + AppendDlEntry((DL *)((uint8_t *)STRUCT_OFFSET(pblipg, 0x14, void *) + 0x1CB4), pblipg); + OnAloAdd((ALO *)pblipg); +} INCLUDE_ASM("asm/nonmatchings/P2/blip", OnBlipgRemove__FP5BLIPG); diff --git a/src/P2/coin.c b/src/P2/coin.c index 0754c00b..ff227d53 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -2,6 +2,7 @@ #include #include #include +#include void InitDprize(DPRIZE *pdprize) { @@ -183,7 +184,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", SetKeyDprizes__FP3KEY7DPRIZES); INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148698); -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148718); +void PostDprizeLoad(DPRIZE *pdprize); + +extern "C" void FUN_00148718(DPRIZE *pdprize) +{ + PostDprizeLoad(pdprize); + STRUCT_OFFSET(&g_note, 0x270, DPRIZE *) = pdprize; +} extern "C" { void FUN_00148748(void *param_1) diff --git a/src/P2/crv.c b/src/P2/crv.c index c1152a7c..a46197b6 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -57,9 +57,29 @@ float DuGetCrvSearchIncrement(CRV *pcrv) INCLUDE_ASM("asm/nonmatchings/P2/crv", LoadCrvlFromBrx__FP4CRVLP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/crv", EvaluateCrvlFromU__FP4CRVLfP6VECTORT2); +void EvaluateCrvlFromU(CRVL *pcrvl, float u, VECTOR *ppos, VECTOR *pnormTangent) +{ + EvaluateAposG( + u, + STRUCT_OFFSET(pcrvl, 0xC, int), + STRUCT_OFFSET(pcrvl, 0x18, VECTOR *), + STRUCT_OFFSET(pcrvl, 0x10, float *), + STRUCT_OFFSET(pcrvl, 0x8, int), + ppos, + pnormTangent); +} -INCLUDE_ASM("asm/nonmatchings/P2/crv", EvaluateCrvlFromS__FP4CRVLfP6VECTORT2); +void EvaluateCrvlFromS(CRVL *pcrvl, float s, VECTOR *ppos, VECTOR *pnormTangent) +{ + EvaluateAposG( + s, + STRUCT_OFFSET(pcrvl, 0xC, int), + STRUCT_OFFSET(pcrvl, 0x18, VECTOR *), + STRUCT_OFFSET(pcrvl, 0x14, float *), + STRUCT_OFFSET(pcrvl, 0x8, int), + ppos, + pnormTangent); +} INCLUDE_ASM("asm/nonmatchings/P2/crv", RenderCrvlSegment__FP4CRVLiP7MATRIX4P2CMG4RGBAi); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 54381cca..746455ca 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -188,7 +188,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", InitExplo__FP5EXPLO); INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadExploFromBrx__FP5EXPLOP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", CloneExplo__FP5EXPLOT0); +void CloneExplo(EXPLO *pexplo, EXPLO *pexploBase) +{ + CloneLo(pexplo, pexploBase); + STRUCT_OFFSET(pexplo, 0x90, EMITB *)->cref++; +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindExplo__FP5EXPLO); @@ -199,7 +203,15 @@ void ExplodeExploExplso(EXPLO *pexplo, EXPLSO *pexplso) INCLUDE_ASM("asm/nonmatchings/P2/emitter", AddExploSkeleton__FP5EXPLO3OIDT1ffff); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", PemitbEnsureExplo__FP5EXPLO4ENSK); +EMITB *PemitbEnsureExplo(EXPLO *pexplo, ENSK ensk) +{ + if (ensk == ENSK_Set) + { + STRUCT_OFFSET(pexplo, 0x90, EMITB *) = PemitbCopyOnWrite(STRUCT_OFFSET(pexplo, 0x90, EMITB *)); + } + + return STRUCT_OFFSET(pexplo, 0x90, EMITB *); +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", InitExpls__FP5EXPLS); @@ -209,7 +221,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", HandleExplsMessage__FP5EXPLS5MSGIDPv) INCLUDE_ASM("asm/nonmatchings/P2/emitter", ExplodeExplsExplso__FP5EXPLSP6EXPLSO); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", PsfxEnsureExpls__FP5EXPLS4ENSK); +SFX *PsfxEnsureExpls(EXPLS *pexpls, ENSK ensk) +{ + if (STRUCT_OFFSET(pexpls, 0xa0, SFX *) == 0) + { + NewSfx(&STRUCT_OFFSET(pexpls, 0xa0, SFX *)); + } + + return STRUCT_OFFSET(pexpls, 0xa0, SFX *); +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", FireExplsExplso__FP5EXPLSP6EXPLSO); diff --git a/src/P2/font.c b/src/P2/font.c index 14b14363..46d458ef 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -8,7 +8,29 @@ void StartupFont() INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c188); +#ifdef SKIP_ASM +extern CFont *D_00262268[5]; + +CFont *FUN_0015c1c0(int i) +{ + CFont *pfont; + + if (i == -1) + { + return NULL; + } + + pfont = D_00262268[i]; + if (pfont != NULL) + { + return pfont; + } + + return g_pfont; +} +#else INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c1c0); +#endif INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c200); @@ -40,9 +62,31 @@ JUNK_ADDIU(50); INCLUDE_ASM("asm/nonmatchings/P2/font", DrawPchz__5CFontPcP8CTextBoxT2P4GIFS); +#ifdef SKIP_ASM +void CFont::PushScaling(float rx, float ry) +{ + int csfr = m_csfr; + + m_csfr = csfr + 1; + m_asfr[csfr].rx = m_rxScale; + m_asfr[csfr].ry = m_rxScale; + m_rxScale = m_asfr[0].rx * rx; + m_ryScale = m_asfr[0].ry * ry; +} + +void CFont::PopScaling() +{ + int csfr = m_csfr - 1; + + m_csfr = csfr; + m_rxScale = m_asfr[csfr].rx; + m_ryScale = m_asfr[csfr].ry; +} +#else INCLUDE_ASM("asm/nonmatchings/P2/font", PushScaling__5CFontff); INCLUDE_ASM("asm/nonmatchings/P2/font", PopScaling__5CFont); +#endif INCLUDE_ASM("asm/nonmatchings/P2/font", PfontClone__8CFontBrxff); @@ -102,7 +146,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", Dx__9CRichText); INCLUDE_ASM("asm/nonmatchings/P2/font", ClineWrap__9CRichTextf); +#ifdef SKIP_ASM +float FUN_0015e1b0(CRichText *prt) +{ + CFont *pfont = prt->m_pfontBase; + float dy = (float)pfont->m_dyUnscaled * pfont->m_ryScale; + + return dy * (float)prt->ClineWrap(dy); +} +#else INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015e1b0); +#endif INCLUDE_ASM("asm/nonmatchings/P2/font", DxMaxLine__9CRichText); diff --git a/src/P2/hide.c b/src/P2/hide.c index d7596a24..23391651 100644 --- a/src/P2/hide.c +++ b/src/P2/hide.c @@ -1,5 +1,6 @@ #include #include +#include extern DL g_dlHshape; extern DL g_dlHpnt; @@ -12,7 +13,12 @@ void StartupHide() InitDl(&g_dlHbsk, 0x558); } -INCLUDE_ASM("asm/nonmatchings/P2/hide", ResetHideList__Fv); +void ResetHideList() +{ + ClearDl(&g_dlHshape); + ClearDl(&g_dlHpnt); + ClearDl(&g_dlHbsk); +} INCLUDE_ASM("asm/nonmatchings/P2/hide", InitHshape__FP6HSHAPE); @@ -46,9 +52,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/hide", InitHbsk__FP4HBSK); INCLUDE_ASM("asm/nonmatchings/P2/hide", LoadHbskFromBrx__FP4HBSKP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/hide", OnHbskAdd__FP4HBSK); +void OnHbskAdd(HBSK *phbsk) +{ + OnSoAdd((SO *)phbsk); + AppendDlEntry(&g_dlHbsk, phbsk); +} -INCLUDE_ASM("asm/nonmatchings/P2/hide", OnHbskRemove__FP4HBSK); +void OnHbskRemove(HBSK *phbsk) +{ + OnSoRemove((SO *)phbsk); + RemoveDlEntry(&g_dlHbsk, phbsk); +} INCLUDE_ASM("asm/nonmatchings/P2/hide", CloneHbsk__FP4HBSKT0); diff --git a/src/P2/po.c b/src/P2/po.c index 41a6aa95..f7161a0b 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -56,7 +56,12 @@ JTHS JthsCurrentPo(PO *ppo) return JTHS_Normal; } -INCLUDE_ASM("asm/nonmatchings/P2/po", FUN_00192498); +void FUN_00192498(PO *ppo, int *pi) +{ + void *pvt = STRUCT_OFFSET(ppo, 0x0, void *); + int (*pfn)(PO *) = (int (*)(PO *))STRUCT_OFFSET(pvt, 0x144, void *); + *pi = pfn(ppo); +} INCLUDE_ASM("asm/nonmatchings/P2/po", CollectPoPrize__FP2PO3PCKP3ALO); diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 1b93c554..6703f600 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -2,8 +2,14 @@ #include #include #include +#include +#include -INCLUDE_ASM("asm/nonmatchings/P2/pzo", InitSprize__FP6SPRIZE); +void InitSprize(SPRIZE *psprize) +{ + InitSo(psprize); + STRUCT_OFFSET(psprize, 0x554, int) = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", LoadSprizeFromBrx__FP6SPRIZEP18CBinaryInputStream); @@ -33,13 +39,26 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", FIgnoreSprizeIntersection__FP6SPRIZEP2SO) INCLUDE_ASM("asm/nonmatchings/P2/pzo", FUN_00199000); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", InitScprize__FP7SCPRIZE); +void InitScprize(SCPRIZE *pscprize) +{ + InitSprize(pscprize); + STRUCT_OFFSET(pscprize, 0x5a0, int) = IchkAllocChkmgr(&g_chkmgr); +} -INCLUDE_ASM("asm/nonmatchings/P2/pzo", CloneScprize__FP7SCPRIZET0); +void CloneScprize(SCPRIZE *pscprize, SCPRIZE *pscprizeBase) +{ + int ichk = STRUCT_OFFSET(pscprize, 0x5a0, int); + CloneSo(pscprize, pscprizeBase); + STRUCT_OFFSET(pscprize, 0x5a0, int) = ichk; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", PcsFromScprize__FP7SCPRIZE); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", CollectScprize__FP7SCPRIZE); +void CollectScprize(SCPRIZE *pscprize) +{ + SetChkmgrIchk(&g_chkmgr, STRUCT_OFFSET(pscprize, 0x5a0, int)); + CollectSprize(pscprize); +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", LoadLockFromBrx__FP4LOCKP18CBinaryInputStream); #ifdef SKIP_ASM @@ -153,13 +172,34 @@ void AddLockgLock(LOCKG *plockg, OID oidLock) plockg->coidLock = ++ccur; } -INCLUDE_ASM("asm/nonmatchings/P2/pzo", TriggerLockg__FP5LOCKG); +extern "C" void func_001781E0(JT *pjt, LOCKG *plockg); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", InitClue__FP4CLUE); +void TriggerLockg(LOCKG *plockg) +{ + if (g_pjt) + func_001781E0(g_pjt, plockg); +} + +void InitClue(CLUE *pclue) +{ + SW *psw; + int n; + + InitSprize(pclue); + psw = pclue->psw; + n = STRUCT_OFFSET(psw, 0x2300, int); + STRUCT_OFFSET(pclue, 0x5a0, int) = n; + STRUCT_OFFSET(psw, 0x2300, int) = n + 1; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", LoadClueFromBrx__FP4CLUEP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", CloneClue__FP4CLUET0); +void CloneClue(CLUE *pclue, CLUE *pclueBase) +{ + int n = STRUCT_OFFSET(pclue, 0x5a0, int); + CloneSo(pclue, pclueBase); + STRUCT_OFFSET(pclue, 0x5a0, int) = n; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", PostClueLoad__FP4CLUE); diff --git a/src/P2/rwm.c b/src/P2/rwm.c index ece65381..ac5c0d77 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -3,7 +3,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", OnRwmRemove); +extern "C" void FUN_001a93c8(RWM *prwm); + +extern "C" void OnRwmRemove(RWM *prwm) +{ + OnLoRemove(prwm); + FUN_001a93c8(prwm); +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a8110); @@ -25,7 +31,12 @@ void FUN_001a86f8(RWM *prwm, int f) INCLUDE_ASM("asm/nonmatchings/P2/rwm", PrwcFindRwm__FP3RWM3OID); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", EnableRwmRwc__FP3RWM3OID); +void EnableRwmRwc(RWM *prwm, OID oidCache) +{ + RWC *prwc = PrwcFindRwm(prwm, oidCache); + if (prwc != NULL) + STRUCT_OFFSET(prwc, 0x10, int) |= 0x2; +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", DisableRwmRwc__FP3RWM3OID); diff --git a/src/P2/screen.c b/src/P2/screen.c index 1d230c39..62b3fcf2 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -236,7 +236,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad718); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad7b0); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad940); +void FUN_001ad940(BLOT *pblot) +{ + PostBlotLoad(pblot); + pblot->dtDisappear = 0.5f; +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad970); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 9c5e1f88..86080bdd 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -59,7 +59,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", FIgnoreSensorObject__FP6SENSORP2SO); INCLUDE_ASM("asm/nonmatchings/P2/sensor", FOnlySensorTriggerObject__FP6SENSORP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/sensor", PauseSensor__FP6SENSOR); +void PauseSensor(SENSOR *psensor) +{ + ASEGA *pasega = PasegaFindAloNearest((ALO *)psensor); + if (pasega) + { + STRUCT_OFFSET(psensor, 0x5CC, float) = STRUCT_OFFSET(pasega, 0x18, float); + STRUCT_OFFSET(pasega, 0x18, int) = 0; + STRUCT_OFFSET(psensor, 0x5C8, ASEGA *) = pasega; + } +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateSensor__FP6SENSORf); @@ -103,9 +112,19 @@ void AddSensorNoTriggerClass(SENSOR * p, CID cid) STRUCT_OFFSET(p, 0x5a0, int) = c + 1; } } -INCLUDE_ASM("asm/nonmatchings/P2/sensor", InitLasen__FP5LASEN); +void InitLasen(LASEN *plasen) +{ + InitSensor(plasen); + STRUCT_OFFSET(plasen, 0xB04, float) = 1.0f; +} -INCLUDE_ASM("asm/nonmatchings/P2/sensor", LoadLasenFromBrx__FP5LASENP18CBinaryInputStream); +void LoadLasenFromBrx(LASEN *plasen, CBinaryInputStream *pbis) +{ + extern SNIP D_002744B8[2]; + + LoadSoFromBrx(plasen, pbis); + SnipAloObjects(plasen, 2, D_002744B8); +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", BindLasen__FP5LASEN); @@ -179,7 +198,11 @@ void ExtendLasen(LASEN *plasen, float dtExpand) STRUCT_OFFSET(plasen, 0xB08, float) = 1.0f / dtExpand; } -INCLUDE_ASM("asm/nonmatchings/P2/sensor", InitCamsen__FP6CAMSEN); +void InitCamsen(CAMSEN *pcamsen) +{ + InitSensor(pcamsen); + STRUCT_OFFSET(pcamsen, 0x5D8, int) = -1; +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", PostCamsenLoad__FP6CAMSEN); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 98324be8..5c0b7b20 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -217,7 +217,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SetStepguardPathzone__FP9STEPGUARD3 INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PsoEnemyStepguard__FP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001caad0); +extern "C" void FUN_001caad0(SO *pso, SO **ppso) +{ + void *pvt = STRUCT_OFFSET(pso, 0x0, void *); + SO *(*fn)(SO *) = (SO *(*)(SO *))STRUCT_OFFSET(pvt, 0x198, void *); + *ppso = fn(pso); +} void SetStepguardEnemyObject(STEPGUARD *pstepguard, SO *psoEnemy) { diff --git a/src/P2/tn.c b/src/P2/tn.c index 8953e40f..69eb59b3 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -84,7 +84,18 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", CalculateTnPos__FP2TNP6VECTORffP3CLQP2LM4F INCLUDE_ASM("asm/nonmatchings/P2/tn", ActivateCptn__FP4CPTNPv); -INCLUDE_ASM("asm/nonmatchings/P2/tn", DeactivateCptn__FP4CPTNPv); +void DeactivateCptn(CPTN *pcptn, void *pv) +{ + TN *ptn = pcptn->ptn; + if (ptn != NULL) + { + if (STRUCT_OFFSET(ptn, 0x438, float) != 0.0f) + { + STRUCT_OFFSET(g_pcm, 0x1c8, float) = STRUCT_OFFSET(ptn, 0x43c, float); + } + } + pcptn->ptn = NULL; +} void SetCptn(CPTN *pcptn, void *pv) { diff --git a/src/P2/wipe.c b/src/P2/wipe.c index e9353e40..cf7a8d64 100644 --- a/src/P2/wipe.c +++ b/src/P2/wipe.c @@ -47,7 +47,11 @@ void DrawWipe(WIPE *pwipe) INCLUDE_ASM("asm/nonmatchings/P2/wipe", ActivateWipe__FP4WIPEP5TRANS5WIPEK); -INCLUDE_ASM("asm/nonmatchings/P2/wipe", SetWipeButtonTrans__FP4WIPEP5TRANS5WIPEK); +void SetWipeButtonTrans(WIPE *pwipe, TRANS *ptrans, WIPEK wipek) +{ + STRUCT_OFFSET(pwipe, 0x28, TRANS) = *ptrans; + STRUCT_OFFSET(pwipe, 0x3c, WIPEK) = wipek; +} INCLUDE_ASM("asm/nonmatchings/P2/wipe", FCatchWipeButtonTrans__FP4WIPEP3JOY5WIPES); From d4e46f0b247e1d1bd3112bf8aae46a867cf09d9e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 20:41:29 +0200 Subject: [PATCH 054/134] Match 18 more medium functions via LHF harness (round 2) act/asega/bbmark/binoc/bomb/break/button/chkpnt/cm/crv: clone-save-restore, list-walks, clamp/min, ensure, virtual dispatch, matrix copies. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 18 ++++++++++++++++-- src/P2/asega.c | 37 +++++++++++++++++++++++++++++++++---- src/P2/bbmark.c | 33 +++++++++++++++++++++++++++++++-- src/P2/binoc.c | 24 ++++++++++++++++++++++-- src/P2/bomb.c | 11 ++++++++++- src/P2/break.c | 11 ++++++++++- src/P2/button.c | 18 ++++++++++++++++-- src/P2/chkpnt.c | 11 ++++++++++- src/P2/cm.c | 7 ++++++- src/P2/crv.c | 10 ++++++++-- 10 files changed, 162 insertions(+), 18 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index cc9e6712..fa64bd08 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -60,7 +60,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/act", PredictAloPosition__FP3ALOfP6VECTORT2); INCLUDE_ASM("asm/nonmatchings/P2/act", PredictAloRotation__FP3ALOfP7MATRIX3P6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/act", AdaptAct__FP3ACT); +void AdaptAct(ACT *pact) +{ + if (STRUCT_OFFSET(pact, 0x10, char) == 7) + STRUCT_OFFSET(pact, 0x10, char) = 3; + if (STRUCT_OFFSET(pact, 0x11, char) == 7) + STRUCT_OFFSET(pact, 0x11, char) = 3; +} INCLUDE_ASM("asm/nonmatchings/P2/act", InitActval__FP6ACTVALP3ALO); @@ -88,7 +94,15 @@ float GGetActvalPoseGoal(ACTVAL *pactval, int ipose) INCLUDE_ASM("asm/nonmatchings/P2/act", InitActref__FP6ACTREFP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/act", GetActrefPositionGoal__FP6ACTREFfP6VECTORT2); +void GetActrefPositionGoal(ACTREF *pactref, float dtOffset, VECTOR *ppos, VECTOR *pv) +{ + *(qword *)ppos = *(qword *)STRUCT_OFFSET(pactref, 0x1c, uint8_t *); + *(qword *)pv = *(qword *)STRUCT_OFFSET(pactref, 0x20, uint8_t *); + ALO *palo = pactref->palo; + void (*pfn)(ALO *) = (void (*)(ALO *))STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x0, void *), 0xB0, void *); + if (pfn) + pfn(palo); +} INCLUDE_ASM("asm/nonmatchings/P2/act", GetActrefRotationGoal__FP6ACTREFfP7MATRIX3P6VECTOR); diff --git a/src/P2/asega.c b/src/P2/asega.c index 10dc9465..277b7309 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -1,7 +1,16 @@ #include #include -INCLUDE_ASM("asm/nonmatchings/P2/asega", PasegaNew__FP2SW); +extern char D_002197B8[]; + +ASEGA *PasegaNew(SW *psw) +{ + ASEGA *pasega = (ASEGA *)PvAllocSlotheapClearImpl(&psw->slotheapAsega); + STRUCT_OFFSET(pasega, 0x0, void *) = D_002197B8; + InitDl(&pasega->dlActseg, 0x20); + STRUCT_OFFSET(pasega, 0x60, void *) = (char *)pasega + 0x64; + return pasega; +} void SetAsegaHandsOff(ASEGA *pasega, int fHandsOff) { @@ -63,12 +72,32 @@ void SetAsegaSpeed(ASEGA *pasega, float speed) STRUCT_OFFSET(STRUCT_OFFSET(pasega, 0x8, void *), 0x98, float); } -INCLUDE_ASM("asm/nonmatchings/P2/asega", SetAsegaMasterSpeed__FP5ASEGAf); +void SetAsegaMasterSpeed(ASEGA *pasega, float gSpeed) +{ + float denom = STRUCT_OFFSET(pasega, 0x1C, float) * + STRUCT_OFFSET(STRUCT_OFFSET(pasega, 0x8, void *), 0x98, float); + float speed = STRUCT_OFFSET(pasega, 0x18, float); + if (denom != 0.0f) + speed = speed / denom; + STRUCT_OFFSET(pasega, 0x1C, float) = gSpeed; + SetAsegaSpeed(pasega, speed); +} INCLUDE_ASM("asm/nonmatchings/P2/asega", SetAsegaPriority__FP5ASEGAi); INCLUDE_ASM("asm/nonmatchings/P2/asega", SendAsegaMessage__FP5ASEGA5MSGIDPv); -INCLUDE_ASM("asm/nonmatchings/P2/asega", SubscribeAsegaStruct__FP5ASEGAPFPv5MSGIDPv_vPv); +void SubscribeAsegaStruct(ASEGA *pasega, PFNMQ pfnmq, void *pvContext) +{ + SubscribeSwPpmqStruct(STRUCT_OFFSET(STRUCT_OFFSET(pasega, 0x8, void *), 0x14, SW *), + &STRUCT_OFFSET(pasega, 0xE4, MQ *), + pfnmq, pvContext); +} -INCLUDE_ASM("asm/nonmatchings/P2/asega", SubscribeAsegaObject__FP5ASEGAP2LO); +void SubscribeAsegaObject(ASEGA *pasega, LO *plo) +{ + SubscribeSwPpmqStruct(STRUCT_OFFSET(STRUCT_OFFSET(pasega, 0x8, void *), 0x14, SW *), + &STRUCT_OFFSET(pasega, 0xE4, MQ *), + STRUCT_OFFSET(plo->pvtlo, 0x44, PFNMQ), + plo); +} diff --git a/src/P2/bbmark.c b/src/P2/bbmark.c index 1306733b..89d6dc37 100644 --- a/src/P2/bbmark.c +++ b/src/P2/bbmark.c @@ -14,9 +14,38 @@ OX *PoxAddSw(SW *psw, OXA *poxa, OXA *poxaOther) return pox; } -INCLUDE_ASM("asm/nonmatchings/P2/bbmark", PoxRemoveSw__FP2SWP3OXAT1); +OX *PoxRemoveSw(SW *psw, OXA *poxa, OXA *poxaOther) +{ + OX **ppox = &poxa->pox; + OX *pox = poxa->pox; + SO *psoOther = poxaOther->pso; + + while (pox) + { + if (pox->psoOther == psoOther) + { + *ppox = pox->poxNext; + break; + } + ppox = &pox->poxNext; + pox = pox->poxNext; + } -INCLUDE_ASM("asm/nonmatchings/P2/bbmark", PoxFromSoSo__FP2SOT0); + return pox; +} + +OX *PoxFromSoSo(SO *pso, SO *psoOther) +{ + OX *pox = STRUCT_OFFSET(STRUCT_OFFSET(pso, 0x50, SW *), 0x480, OXA *)->pox; + SO *psoKey = STRUCT_OFFSET(psoOther, 0x50, SO *); + while (pox != NULL) + { + if (pox->psoOther == psoKey) + return pox; + pox = pox->poxNext; + } + return NULL; +} XP *PxpFirstFromSoSo(SO *pso, SO *psoOther) { diff --git a/src/P2/binoc.c b/src/P2/binoc.c index 6af7b732..4060c213 100644 --- a/src/P2/binoc.c +++ b/src/P2/binoc.c @@ -4,6 +4,7 @@ #include #include #include +#include void InitBei(BEI *pbei, CLQ *pclq, float duWidth, float dgHeight, int cseg) { @@ -144,7 +145,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136040); INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136238); -INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_001363d0); +extern "C" { +void FUN_001363d0(BINOC *pbinoc) +{ + OnBlotReset(pbinoc); + DIALOG *pdialog = STRUCT_OFFSET(pbinoc, 0x324, DIALOG *); + if (pdialog) + SetDialogDialogs(pdialog, DIALOGS_Disabled); +} +} INCLUDE_ASM("asm/nonmatchings/P2/binoc", SetBinocAchzDraw); @@ -199,7 +208,18 @@ void GetBinocReticleFocus(BINOC *binoc, float *dxReticle, float *dyReticle) INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136ef8); -INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136fa8); +extern "C" { +void open_close_binoc(BINOC *pbinoc, int state); + +void FUN_00136fa8(BINOC *pbinoc) +{ + DIALOG *pdialog = STRUCT_OFFSET(pbinoc, 0x324, DIALOG *); + if (pdialog) + SetDialogDialogs(pdialog, DIALOGS_Calling); + else + open_close_binoc(pbinoc, 0); +} +} INCLUDE_ASM("asm/nonmatchings/P2/binoc", binoc__static_initialization_and_destruction_0); diff --git a/src/P2/bomb.c b/src/P2/bomb.c index e9799cf7..d113b1de 100644 --- a/src/P2/bomb.c +++ b/src/P2/bomb.c @@ -49,4 +49,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/bomb", ApplyBombThrow__FP4BOMBP2PO); INCLUDE_ASM("asm/nonmatchings/P2/bomb", DetonateBomb__FP4BOMB); -INCLUDE_ASM("asm/nonmatchings/P2/bomb", PsfxEnsureBomb__FP4BOMB4ENSK); +SFX *PsfxEnsureBomb(BOMB *pbomb, ENSK ensk) +{ + // pbomb->psfxDet + if (!STRUCT_OFFSET(pbomb, 0x680, SFX *)) + { + NewSfx(&STRUCT_OFFSET(pbomb, 0x680, SFX *)); + } + + return STRUCT_OFFSET(pbomb, 0x680, SFX *); +} diff --git a/src/P2/break.c b/src/P2/break.c index df8acc09..6b2fd91a 100644 --- a/src/P2/break.c +++ b/src/P2/break.c @@ -16,7 +16,16 @@ void PostBrkLoad(BRK *pbrk) INCLUDE_ASM("asm/nonmatchings/P2/break", PostBrkLoadCallbackHookup__FP3BRK5MSGIDPv); -INCLUDE_ASM("asm/nonmatchings/P2/break", UpdateBrk__FP3BRKf); +void UpdateBrk(BRK *pbrk, float dt) +{ + UpdateSo(pbrk, dt); + + if (STRUCT_OFFSET(pbrk, 0x678, int)) + { + STRUCT_OFFSET(pbrk, 0x678, int) = 0; + (*(void (**)(BRK *))((char *)pbrk->pvtlo + 0x130))(pbrk); + } +} INCLUDE_ASM("asm/nonmatchings/P2/break", FAbsorbBrkWkr__FP3BRKP3WKR); diff --git a/src/P2/button.c b/src/P2/button.c index ea06800d..552907e4 100644 --- a/src/P2/button.c +++ b/src/P2/button.c @@ -35,9 +35,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/button", LoadBtn__FP3BTNP3ALO); INCLUDE_ASM("asm/nonmatchings/P2/button", PostBtnLoad__FP3BTN); -INCLUDE_ASM("asm/nonmatchings/P2/button", RestoreBtnFromCheckpointCallback__FP3BTN5MSGIDPv); +void RestoreBtnFromCheckpointCallback(BTN *pbtn, MSGID msgid, void *pv) +{ + if (msgid == MSGID_callback) + { + PostSwCallback(pbtn->paloOwner->psw, (PFNMQ)RestoreBtnFromCheckpointCallback, pbtn, + MSGID_button_trigger, NULL); + } + else + { + TriggerBtn(pbtn, 1, 1); + } +} -INCLUDE_ASM("asm/nonmatchings/P2/button", SetBtnRsmg__FP3BTNi3OIDN22); +void SetBtnRsmg(BTN *pbtn, int fOnTrigger, OID oidRoot, OID oidSM, OID oidGoal) +{ + FAddRsmg(pbtn->arsmg, 8, &pbtn->crsmg, fOnTrigger, oidRoot, oidSM, oidGoal); +} INCLUDE_ASM("asm/nonmatchings/P2/button", SetBtnButtons__FP3BTN7BUTTONS); diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index 649fd3ee..bacd6199 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ResetChkmgrCheckpoints__FP6CHKMGR); #ifdef SKIP_ASM @@ -51,7 +52,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ClearChkmgrIchk__FP6CHKMGRi); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", LoadVolFromBrx__FP3VOLP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FCheckVolPoint__FP3VOLP6VECTOR); +extern int ConvertXfmLocalToWorld(XFM *pxfm, VECTOR *pposWorld, VECTOR *pposLocal); + +int FCheckVolPoint(VOL *pvol, VECTOR *ppos) +{ + VECTOR posLocal; + + ConvertXfmLocalToWorld(pvol, ppos, &posLocal); + return FCheckTbspPoint(STRUCT_OFFSET(pvol, 0x8c, TBSP *), &posLocal); +} INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", InitChkpnt__FP6CHKPNT); diff --git a/src/P2/cm.c b/src/P2/cm.c index 5f27c171..d1dbeb02 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -215,7 +215,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", DrawCm__FP2CM); INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmPosMat__FP2CMP6VECTORP7MATRIX3); -INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmLookAt); +extern "C" void SetCmLookAtSmooth(CM *pcm, int a1, VECTOR *pposEye, VECTOR *pposCenter, int a4, float u0, float u1, float u2, float u3, float u4, float u5); + +extern "C" void SetCmLookAt(CM *pcm, VECTOR *pposEye, VECTOR *pposCenter) +{ + SetCmLookAtSmooth(pcm, 0, pposEye, pposCenter, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); +} INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertWorldToCylindVelocity); diff --git a/src/P2/crv.c b/src/P2/crv.c index a46197b6..0f7bdcf0 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -28,7 +28,10 @@ float UFromCrvS(CRV *pcrv, float s) INCLUDE_ASM("asm/nonmatchings/P2/crv", IcvFindCrvU__FP3CRVfPfT2); -INCLUDE_ASM("asm/nonmatchings/P2/crv", IcvFindCrvS__FP3CRVfPfT2); +int IcvFindCrvS(CRV *pcrv, float s, float *ds, float *dsSeg) +{ + return IposFindAposG(s, pcrv->ccv, pcrv->mpicvs, pcrv->fClosed, ds, dsSeg); +} INCLUDE_ASM("asm/nonmatchings/P2/crv", GMeasureCrvU__FP5CRVMCf); @@ -83,7 +86,10 @@ void EvaluateCrvlFromS(CRVL *pcrvl, float s, VECTOR *ppos, VECTOR *pnormTangent) INCLUDE_ASM("asm/nonmatchings/P2/crv", RenderCrvlSegment__FP4CRVLiP7MATRIX4P2CMG4RGBAi); -INCLUDE_ASM("asm/nonmatchings/P2/crv", ConvertCrvl__FP4CRVLP7MATRIX4T1); +void ConvertCrvl(CRVL *pcrvl, MATRIX4 *pmatSrc, MATRIX4 *pmatDst) +{ + ConvertApos(STRUCT_OFFSET(pcrvl, 0xC, int), STRUCT_OFFSET(pcrvl, 0x18, VECTOR *), pmatSrc, pmatDst); +} INCLUDE_ASM("asm/nonmatchings/P2/crv", SFromCrvlU__FP4CRVLf); From 64239756f8aefb90e5d18cc8d02511b841b779e3 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 20:55:37 +0200 Subject: [PATCH 055/134] Match 23 more medium functions via LHF harness (round 3) crv/dmas/emitter/freeze/glob/gs/hide/jlo/jt/light/mat/missile/path/puffer/rip: DMA tag builders, clone save/restore, vtable dispatch, subscribe wrappers, matrix ops, list reduction. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/crv.c | 5 ++++- src/P2/dmas.c | 35 +++++++++++++++++++++++++++++++---- src/P2/emitter.c | 35 +++++++++++++++++++++++++++++++++-- src/P2/freeze.c | 14 +++++++++++++- src/P2/glob.c | 17 ++++++++++++++++- src/P2/gs.c | 19 +++++++++++++++++-- src/P2/hide.c | 9 ++++++++- src/P2/jlo.c | 6 +++++- src/P2/jt.c | 11 ++++++++++- src/P2/light.c | 7 ++++++- src/P2/mat.c | 12 +++++++++++- src/P2/missile.c | 8 +++++++- src/P2/path.c | 9 ++++++++- src/P2/puffer.c | 11 ++++++++++- src/P2/rip.c | 24 ++++++++++++++++++++---- 15 files changed, 199 insertions(+), 23 deletions(-) diff --git a/src/P2/crv.c b/src/P2/crv.c index 0f7bdcf0..9a09f709 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -26,7 +26,10 @@ float UFromCrvS(CRV *pcrv, float s) return 0.0f; } -INCLUDE_ASM("asm/nonmatchings/P2/crv", IcvFindCrvU__FP3CRVfPfT2); +int IcvFindCrvU(CRV *pcrv, float u, float *du, float *duSeg) +{ + return IposFindAposG(u, pcrv->ccv, pcrv->mpicvu, pcrv->fClosed, du, duSeg); +} int IcvFindCrvS(CRV *pcrv, float s, float *ds, float *dsSeg) { diff --git a/src/P2/dmas.c b/src/P2/dmas.c index a6f00721..48f0a90e 100644 --- a/src/P2/dmas.c +++ b/src/P2/dmas.c @@ -1,6 +1,7 @@ #include #include #include +#include extern sceDmaChan *g_pdcVif0; extern sceDmaChan *g_pdcVif1; @@ -80,17 +81,43 @@ void DMAS::Send(sceDmaChan *chan) JUNK_NOP(); JUNK_ADDIU(10); -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaCnt__4DMAS); +void DMAS::AddDmaCnt() +{ + EndDmaCnt(); + QW *pqw = (QW *)m_pb; + m_pqwCnt = pqw; + m_pb += sizeof(QW); + pqw->aul[0] = 0x10000000; + m_pqwCnt->aul[1] = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaRefs__4DMASiP2QW); INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaCall__4DMASP2QW); -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaRet__4DMAS); +void DMAS::AddDmaRet() +{ + EndDmaCnt(); + uchar *pb = m_pb; + m_pb = pb + 0x10; + *(ulong *)pb = 0x60000000; + *(ulong *)(pb + 8) = 0; +} -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaBulk__4DMASiP2QW); +void DMAS::AddDmaBulk(int c, QW *aqw) +{ + CopyAqw(m_pb, aqw, c); + m_pb += c * sizeof(QW); +} -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaEnd__4DMAS); +void DMAS::AddDmaEnd() +{ + EndDmaCnt(); + QW *pqw = (QW *)m_pb; + m_pb += sizeof(QW); + pqw->aul[0] = 0x70000000; + pqw->aul[1] = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/dmas", EndDmaCnt__4DMAS); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 746455ca..90444291 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -59,7 +59,34 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", ModifyEmitterParticles__FP7EMITTER); INCLUDE_ASM("asm/nonmatchings/P2/emitter", UpdateEmitter__FP7EMITTERf); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", FUN_00155f28); +extern "C" { +void FUN_00155f28(SO *pso) +{ + SO *psoParent; + + if ((STRUCT_OFFSET(pso, 0x2c8, unsigned long long) & 0xC000000) == 0x8000000) + { + return; + } + + psoParent = STRUCT_OFFSET(pso, 0x18, SO *); + while (psoParent != 0) + { + if ((STRUCT_OFFSET(psoParent, 0x2c8, unsigned long long) & 0xC000000) == 0x8000000) + { + break; + } + psoParent = STRUCT_OFFSET(psoParent, 0x18, SO *); + } + + if (psoParent == 0) + { + return; + } + + STRUCT_OFFSET(pso, 0x88, int) = STRUCT_OFFSET(psoParent, 0x88, int); +} +} void PauseEmitter(EMITTER *pemitter, float dtPause) { @@ -163,7 +190,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", SetEmitdvEmitb__FP6EMITDVP5EMITB); INCLUDE_ASM("asm/nonmatchings/P2/emitter", CalculateEmitdvMatrix__FP6EMITDVfP7MATRIX4); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", PostExplLoad__FP4EXPL); +void PostExplLoad(EXPL *pexpl) +{ + PostLoLoad(pexpl); + pexpl->pvtlo->pfnRemoveLo(pexpl); +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", CalculateExplTransform__FP4EXPLP6VECTORP7MATRIX3); diff --git a/src/P2/freeze.c b/src/P2/freeze.c index 6b2f36fa..f8e3d1b2 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -1,6 +1,18 @@ #include -INCLUDE_ASM("asm/nonmatchings/P2/freeze", RemergeSwObject__FP2SWP3ALO); +void RemergeSwObject(SW *psw, ALO *palo) +{ + unsigned long long grfalo = STRUCT_OFFSET(palo, 0x2c8, unsigned long long); + + if ((grfalo & (0x8000ULL << 24)) == 0) + { + STRUCT_OFFSET(palo, 0x2c8, unsigned long long) = grfalo | (0x8000ULL << 24); + int cpalo = STRUCT_OFFSET(psw, 0x1ed0, int); + ALO **apalo = STRUCT_OFFSET(psw, 0x1ed4, ALO **); + apalo[cpalo] = palo; + STRUCT_OFFSET(psw, 0x1ed0, int) = cpalo + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/freeze", MergeSwFreezeGroups__FP2SWP3ALOT1); diff --git a/src/P2/glob.c b/src/P2/glob.c index 1762474a..e95fc9dc 100644 --- a/src/P2/glob.c +++ b/src/P2/glob.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/glob", BuildGlobsetSaaArray__FP7GLOBSET); @@ -26,7 +27,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/glob", CloneGlob__FP7GLOBSETP4GLOBP5GLOBI); INCLUDE_ASM("asm/nonmatchings/P2/glob", UpdateGlobset__FP7GLOBSETP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/glob", UpdateAloConstraints__FP3ALO); +void UpdateAloConstraints(ALO *palo) +{ + void *p = STRUCT_OFFSET(palo, 0x224, void *); + + if (p != NULL) + { + if (STRUCT_OFFSET(p, 0xb0, int) & 0x10) + { + if (STRUCT_OFFSET(p, 0x64, int) != 0) + { + SolveAloIK(STRUCT_OFFSET(p, 0x60, ALO *)); + } + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/glob", UpdateAloInfluences__FP3ALOP2RO); diff --git a/src/P2/gs.c b/src/P2/gs.c index fd57ed20..a1b49ec3 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -1,10 +1,18 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/gs", BlendDisplayOnBufferMismatch__Fv); INCLUDE_ASM("asm/nonmatchings/P2/gs", VBlankS_Interrupt__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/gs", SyncVBlank__Fv); +extern int D_002BE460; +extern int D_002BE46C; + +void SyncVBlank() +{ + D_002BE46C = 1; + WaitSema(D_002BE460); +} INCLUDE_ASM("asm/nonmatchings/P2/gs", SwapGsBuffers__Fv); @@ -26,7 +34,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", ClearFrameBuffers__Fv); INCLUDE_ASM("asm/nonmatchings/P2/gs", FadeFramesToBlack__Ff); -INCLUDE_ASM("asm/nonmatchings/P2/gs", ResetGsMemory__Fv); +extern GSB D_002626D8; +extern int D_002626D0; + +void ResetGsMemory() +{ + InitGsb(&D_002626D8, 0x1E00, 0x4000); + D_002626D0 = 0; +} uint NLog2(uint value) { diff --git a/src/P2/hide.c b/src/P2/hide.c index 23391651..eab21d4f 100644 --- a/src/P2/hide.c +++ b/src/P2/hide.c @@ -28,7 +28,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/hide", OnHshapeRemove__FP6HSHAPE); INCLUDE_ASM("asm/nonmatchings/P2/hide", BindHshape__FP6HSHAPE); -INCLUDE_ASM("asm/nonmatchings/P2/hide", CloneHshape__FP6HSHAPET0); +struct HSHAPE; + +void CloneHshape(HSHAPE *phshape, HSHAPE *phshapeBase) +{ + DLE dle = STRUCT_OFFSET(phshape, 0x38, DLE); + CloneLo((LO *)phshape, (LO *)phshapeBase); + STRUCT_OFFSET(phshape, 0x38, DLE) = dle; +} INCLUDE_ASM("asm/nonmatchings/P2/hide", GetHshapeHidePos__FP6HSHAPEfP6VECTORPf); diff --git a/src/P2/jlo.c b/src/P2/jlo.c index dd51f2ad..8569f3b6 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -73,7 +73,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", InitJloc__FP4JLOC); INCLUDE_ASM("asm/nonmatchings/P2/jlo", LoadJlocFromBrx__FP4JLOCP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/jlo", PostJlocLoad__FP4JLOC); +void PostJlocLoad(JLOC *pjloc) +{ + PostAloLoad(pjloc); + pjloc->pvtlo->pfnRemoveLo(pjloc); +} INCLUDE_ASM("asm/nonmatchings/P2/jlo", PxfmChooseJloc__FP4JLOC); diff --git a/src/P2/jt.c b/src/P2/jt.c index e326f92c..7a2bd9ac 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/jt", InitJt__FP2JT); @@ -116,7 +117,15 @@ int NCmpWkr(WKR *pwkr1, WKR *pwkr2) INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtEffect__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/jt", FIsJtSoundBase__FP2JT); +extern "C" int FActiveCplcy(CPLCY *pcplcy); + +int FIsJtSoundBase(JT *pjt) +{ + if (pjt->jts == JTS_Ball && pjt->jtbs == JTBS_Zap_Electric) + return 0; + + return !FActiveCplcy(&STRUCT_OFFSET(g_pcm, 0x454, CPLCY)); +} INCLUDE_ASM("asm/nonmatchings/P2/jt", CollectJtPrize__FP2JT3PCKP3ALO); diff --git a/src/P2/light.c b/src/P2/light.c index 0a6ada64..3ed34495 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -195,7 +195,12 @@ void SetLightHotSpotAngle(LIGHT *plight, float degHotSpot) RebuildLightVifs(plight); } -INCLUDE_ASM("asm/nonmatchings/P2/light", SetLightFrustrumUp__FP5LIGHTP6VECTOR); +void SetLightFrustrumUp(LIGHT *plight, VECTOR *pvecUpLocal) +{ + STRUCT_OFFSET(plight, 0x340, VU_VECTOR) = *(VU_VECTOR *)pvecUpLocal; + RebuildLightVifs(plight); + UpdateLightBeamGrfzon(plight); +} INCLUDE_ASM("asm/nonmatchings/P2/light", RebuildLightFrustrum__FP5LIGHT); diff --git a/src/P2/mat.c b/src/P2/mat.c index 5baadfc9..79843f0d 100644 --- a/src/P2/mat.c +++ b/src/P2/mat.c @@ -1,5 +1,6 @@ #include #include +#include extern VECTOR g_normalZ; @@ -59,7 +60,16 @@ JUNK_NOP(); JUNK_NOP(); JUNK_ADDIU(60); -INCLUDE_ASM("asm/nonmatchings/P2/mat", CosRotateMatrixMagnitude__FP7MATRIX3); +float CosRotateMatrixMagnitude(MATRIX3 *pmat) +{ + float gTrace; + + gTrace = STRUCT_OFFSET(pmat, 0x0, float) + STRUCT_OFFSET(pmat, 0x14, float); + gTrace = gTrace + STRUCT_OFFSET(pmat, 0x28, float); + gTrace = gTrace - 1.0f; + + return GLimitAbs(gTrace * 0.5f, 1.0f); +} INCLUDE_ASM("asm/nonmatchings/P2/mat", DecomposeRotateMatrixRad__FP7MATRIX3PfP6VECTOR); diff --git a/src/P2/missile.c b/src/P2/missile.c index 10ddd85d..36c8d1b1 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -49,7 +49,13 @@ extern "C" void FUN_0018dd78(void * p, int val) } } -INCLUDE_ASM("asm/nonmatchings/P2/missile", InitAccmiss__FP7ACCMISS); +extern qword D_00248D30; + +void InitAccmiss(ACCMISS *paccmiss) +{ + InitMissile(paccmiss); + *(qword *)((char *)paccmiss + 0x350) = D_00248D30; +} INCLUDE_ASM("asm/nonmatchings/P2/missile", FireAccmiss__FP7ACCMISSP3ALOP6VECTOR); diff --git a/src/P2/path.c b/src/P2/path.c index 5e812d49..18eb5035 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -20,7 +20,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/path", PcgtPointInCbspQuick__FP4CBSPP6VECTOR); INCLUDE_ASM("asm/nonmatchings/P2/path", PcgtPointInCbspSafe__FP4CBSPP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/path", CbskFromG__Ff); +int CbskFromG(float g) +{ + if (g > 1.0f) + return 0; + if (g < -1.0f) + return 1; + return 2; +} INCLUDE_ASM("asm/nonmatchings/P2/path", ClsgClipEdgeToCbsp__FP4CBSPP6VECTORT1iP3LSG); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index fb5340ac..b461cdc2 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -60,7 +60,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffcGoal__FP5PUFFCi); INCLUDE_ASM("asm/nonmatchings/P2/puffer", OnPuffcExitingSgs__FP5PUFFC3SGS); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", OnPuffcEnteringSgs__FP5PUFFC3SGSP4ASEG); +extern "C" void FUN_001c8920(PUFFC *ppuffc); + +void OnPuffcEnteringSgs(PUFFC *ppuffc, SGS sgsPrev, ASEG *pasegOverride) +{ + OnStepguardEnteringSgs((STEPGUARD *)ppuffc, sgsPrev, pasegOverride); + if (STRUCT_OFFSET(ppuffc, 0x724, int) == SGS_Stun) + { + FUN_001c8920(ppuffc); + } +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffcSgs__FP5PUFFC); diff --git a/src/P2/rip.c b/src/P2/rip.c index 23e3b289..f87ba51e 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -64,11 +64,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", FRenderRipPosMat__FP3RIPP2CMP6VECTORP7MAT INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderRip__FP3RIPP2CM); -INCLUDE_ASM("asm/nonmatchings/P2/rip", SubscribeRipObject__FP3RIPP2LO); +void SubscribeRipObject(RIP *prip, LO *ploTarget) +{ + SubscribeSwPpmqStruct(g_psw, &STRUCT_OFFSET(prip, 0x118, MQ *), ploTarget->pvtlo->pfnHandleLoMessage, ploTarget); +} -INCLUDE_ASM("asm/nonmatchings/P2/rip", SubscribeRipStruct__FP3RIPPFPv5MSGIDPv_vPv); +void SubscribeRipStruct(RIP *prip, PFNMQ pfnmq, void *pvContext) +{ + SubscribeSwPpmqStruct(g_psw, &STRUCT_OFFSET(prip, 0x118, MQ *), pfnmq, pvContext); +} -INCLUDE_ASM("asm/nonmatchings/P2/rip", UnsubscribeRipStruct__FP3RIPPFPv5MSGIDPv_vPv); +void UnsubscribeRipStruct(RIP *prip, PFNMQ pfnmq, void *pvContext) +{ + UnsubscribeSwPpmqStruct(g_psw, &STRUCT_OFFSET(prip, 0x118, MQ *), pfnmq, pvContext); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", InitDroplet__FP7DROPLETP6VECTORfP2SO); @@ -202,7 +211,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectLeafTransform__FP4LEAFf); INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceLeaf__FP4LEAFP2SOP6VECTORT2); -INCLUDE_ASM("asm/nonmatchings/P2/rip", FFilterFlameObjects__FPvP2SO); +int FFilterFlameObjects(void *pv, SO *pso) +{ + if (STRUCT_OFFSET(pso, 0x538, unsigned long long) & ((unsigned long long)0x8000 << 28)) + { + return 0; + } + return pso != STRUCT_OFFSET(pv, 0x7C, SO *); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", PostFlameEmit__FP5FLAMEP5EMITB); From 4b7be8a5c2882a70c44d944f9b13f467901b4707 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:03:13 +0200 Subject: [PATCH 056/134] Match 10 more medium functions via LHF harness (round 4) screen/sm/smartguard/step/stephang/steprail/suv: blot resize/reset, SMA transitions, JT hang heading, track normalize, vtable post-load. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/screen.c | 20 ++++++++++++++++++-- src/P2/sm.c | 20 ++++++++++++++++++-- src/P2/smartguard.c | 12 +++++++++++- src/P2/step.c | 7 ++++++- src/P2/stephang.c | 20 ++++++++++++++++++-- src/P2/steprail.c | 11 ++++++++++- src/P2/suv.c | 11 ++++++++++- 7 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/P2/screen.c b/src/P2/screen.c index 62b3fcf2..ec7368c6 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -10,7 +10,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", UpdateBlots__Fv); INCLUDE_ASM("asm/nonmatchings/P2/screen", ForceHideBlots__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/screen", ResetBlots__Fv); +void ResetBlots(void) +{ + extern BLOT *D_002486B0[]; + + for (int i = 0; i < 0x25; i++) + { + BLOT *pblot = D_002486B0[i]; + ((VTBLOT *)pblot->pvtblot)->pfnOnBlotReset(pblot); + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", RenderBlots__Fv); @@ -84,7 +93,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", SetBlotBlots__FP4BLOT5BLOTS); INCLUDE_ASM("asm/nonmatchings/P2/screen", FIncludeBlotForPeg__FP4BLOTT0); -INCLUDE_ASM("asm/nonmatchings/P2/screen", ResizeBlot__FP4BLOTff); +void ResizeBlot(BLOT *pblot, float dx, float dy) +{ + if (dx >= 0.0f) + pblot->width = dx; + if (dy >= 0.0f) + pblot->height = dy; + RepositionBlot(pblot); +} INCLUDE_ASM("asm/nonmatchings/P2/screen", RepositionBlot__FP4BLOT); diff --git a/src/P2/sm.c b/src/P2/sm.c index 314aa710..33a99d8b 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -47,9 +47,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/sm", SeekSma__FP3SMA3OID); INCLUDE_ASM("asm/nonmatchings/P2/sm", ChooseSmaTransition__FP3SMA); -INCLUDE_ASM("asm/nonmatchings/P2/sm", EndSmaTransition__FP3SMA); +void EndSmaTransition(SMA *psma) +{ + int cur = STRUCT_OFFSET(psma, 0x28, int); + int next = STRUCT_OFFSET(psma, 0x2C, int); + NotifySmaSpliceOnEnterState(psma, cur, next); + int nextCopy = STRUCT_OFFSET(psma, 0x2C, int); + STRUCT_OFFSET(psma, 0x2C, int) = -1; + STRUCT_OFFSET(psma, 0x28, int) = nextCopy; +} -INCLUDE_ASM("asm/nonmatchings/P2/sm", HandleSmaMessage__FP3SMA5MSGIDPv); +void HandleSmaMessage(SMA *psma, MSGID msgid, void *pv) +{ + if (msgid == MSGID_asega_limit) { + if ((ASEGA*)pv == psma->pasegaCur) { + EndSmaTransition(psma); + ChooseSmaTransition(psma); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/sm", SkipSma__FP3SMAf); diff --git a/src/P2/smartguard.c b/src/P2/smartguard.c index 5986ceb0..30e23be2 100644 --- a/src/P2/smartguard.c +++ b/src/P2/smartguard.c @@ -40,7 +40,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/smartguard", UpdateSmartguardFlashlight__FP10SM INCLUDE_ASM("asm/nonmatchings/P2/smartguard", OnSmartguardEnteringSgs__FP10SMARTGUARD3SGSP4ASEG); -INCLUDE_ASM("asm/nonmatchings/P2/smartguard", FCanSmartguardAttack__FP10SMARTGUARD); +int FCanSmartguardAttack(SMARTGUARD *psmartguard) +{ + if (!FCanStepguardAttack((STEPGUARD *)psmartguard)) + { + return 0; + } + + void *pvt = STRUCT_OFFSET(psmartguard, 0x0, void *); + int (*fn)(SMARTGUARD *) = (int (*)(SMARTGUARD *))STRUCT_OFFSET(pvt, 0x16C, void *); + return fn(psmartguard); +} INCLUDE_ASM("asm/nonmatchings/P2/smartguard", SgasGetSmartguard__FP10SMARTGUARD); diff --git a/src/P2/step.c b/src/P2/step.c index 36e113eb..b0d275c3 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/step", InitStep__FP4STEP); @@ -65,7 +66,11 @@ void AdjustStepDzBase(STEP *pstep, GRFADJ grfadj, DZ *pdz, int ixpd) return; } -INCLUDE_ASM("asm/nonmatchings/P2/step", UpdateStepMatTarget__FP4STEP); +void UpdateStepMatTarget(STEP *pstep) +{ + extern VECTOR g_normalZ; + LoadRotateMatrixRad(*(float *)((uint8_t *)(pstep) + 0x638), &g_normalZ, (MATRIX3 *)((uint8_t *)(pstep) + 0x660)); +} INCLUDE_ASM("asm/nonmatchings/P2/step", AdjustStepXpVelocity__FP4STEPP2XPi); diff --git a/src/P2/stephang.c b/src/P2/stephang.c index 1ca1f853..622ae3df 100644 --- a/src/P2/stephang.c +++ b/src/P2/stephang.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/stephang", PostJtLoadSwing__FP2JTP2BLPP6ASEGBL); @@ -8,7 +9,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/stephang", CalculateJtHangAccel__FP2JT); INCLUDE_ASM("asm/nonmatchings/P2/stephang", PresetJtAccelHang__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/stephang", AddJtExternalAccelerations__FP2JTP2XAf); +void AddJtExternalAccelerations(JT *pjt, XA *pxa, float dt) +{ + SO *pso = STRUCT_OFFSET(pjt, 0x22AC, SO *); + SO *psoBody = STRUCT_OFFSET(pso, 0x4, SO *); + AddSoAcceleration(psoBody, (VECTOR *)((uint8_t *)pjt + 0x22D0)); + pso = STRUCT_OFFSET(pjt, 0x22AC, SO *); + psoBody = STRUCT_OFFSET(pso, 0x4, SO *); + AddSoAngularAcceleration(psoBody, (VECTOR *)((uint8_t *)pjt + 0x22E0)); +} INCLUDE_ASM("asm/nonmatchings/P2/stephang", UpdateJtActiveHang__FP2JTP3JOY); @@ -18,7 +27,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/stephang", UpdateJtHookOx__FP2JTP2LOi); INCLUDE_ASM("asm/nonmatchings/P2/stephang", AddJtHookXps__FP2JTiP2LOP6VECTORN23); -INCLUDE_ASM("asm/nonmatchings/P2/stephang", GetJtHangHeading__FP2JTPf); +void GetJtHangHeading(JT *pjt, float *pradForward) +{ + ALO *paloHook = STRUCT_OFFSET(pjt, 0x2204, ALO *); + ALO *paloParent = STRUCT_OFFSET(paloHook, 0x18, ALO *); + VECTOR vec; + ConvertAloVec(paloParent, NULL, (VECTOR *)((uint8_t *)paloHook + 0x50), &vec); + *pradForward = atan2f(vec.y, vec.x); +} INCLUDE_ASM("asm/nonmatchings/P2/stephang", UpdateJtIkHang__FP2JT); diff --git a/src/P2/steprail.c b/src/P2/steprail.c index 8760f76d..f4fdf476 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -1,10 +1,19 @@ #include +#include extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D31D0__FP2LOi); -INCLUDE_ASM("asm/nonmatchings/P2/steprail", post_load_steprail); +extern "C" void post_load_steprail(ALO *palo) +{ + extern SNIP D_00274F90; + PostAloLoad(palo); + SnipAloObjects(palo, 1, &D_00274F90); + void **ppvtable = (void **)STRUCT_OFFSET(palo, 0x0, void*); + void (*pfn)(ALO *) = (void (*)(ALO *))STRUCT_OFFSET(ppvtable, 0x1c, void*); + pfn(palo); +} INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D32D8__FiP2JTl); diff --git a/src/P2/suv.c b/src/P2/suv.c index 594c0b80..ce45dde6 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -11,7 +11,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", GExcludeAlm__FiP2LMf); INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvBalance__FP3SUV); -INCLUDE_ASM("asm/nonmatchings/P2/suv", DsGetTrackRelative__Ffff); +float DsGetTrackRelative(float track, float relative, float range) +{ + relative -= range; + if (track * 0.5f < relative) { + relative -= track; + } else if (relative < track * (-0.5f)) { + relative += track; + } + return relative; +} INCLUDE_ASM("asm/nonmatchings/P2/suv", FIsSuvAheadOf__FP3SUVT0); From 37f1595f9ef49e53a29b840e169d71dccd84b1ca Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:04:55 +0200 Subject: [PATCH 057/134] Match UseStepguardPhys/UseStepguardAnimation (stepguard) via LHF harness Indexed store into 8-byte-stride array; named-pointer idiom (long long *a = &...; *(OID*)&a[sgs]) yields the ROM's a0-first addu. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/stepguard.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 5c0b7b20..9e442802 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -183,7 +183,14 @@ int FValidSgs(SGS sgs) return ((uint)sgs < 0x11); } -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardAnimation__FP9STEPGUARD3SGS3OID); +void UseStepguardAnimation(STEPGUARD *pstepguard, SGS sgs, OID oidAnim) +{ + if (FValidSgs(sgs)) + { + long long *a = &STRUCT_OFFSET(pstepguard, 0x758, long long); + *(OID *)&a[sgs] = oidAnim; + } +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardAnimationImmediate__FP9STEPGUARD3SGS3OID); @@ -207,7 +214,14 @@ void UseStepguardRwm(STEPGUARD *pstepguard, OID oidRwm) STRUCT_OFFSET(pstepguard, 0xb04, int) = 1; } -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardPhys__FP9STEPGUARD3SGS3OID); +void UseStepguardPhys(STEPGUARD *pstepguard, SGS sgs, OID oidPhys) +{ + if (FValidSgs(sgs)) + { + long long *a = &STRUCT_OFFSET(pstepguard, 0x870, long long); + *(OID *)&a[sgs] = oidPhys; + } +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", LoadStepguardPhys__FP9STEPGUARD); From d5b696f16e9b7547e349a5bd28e439620cc865ee Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:08:45 +0200 Subject: [PATCH 058/134] Strip non-matching agent-cruft SKIP_ASM blocks in font.c Three #ifdef SKIP_ASM/#else INCLUDE_ASM WIP drafts (FUN_0015c1c0, PushScaling/PopScaling, FUN_0015e1b0) left by draft agents; harmless to the --clean checksum but broke the objdiff --objects build (protected member access). Restored to plain INCLUDE_ASM. checksum still OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/font.c | 54 --------------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/src/P2/font.c b/src/P2/font.c index 46d458ef..14b14363 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -8,29 +8,7 @@ void StartupFont() INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c188); -#ifdef SKIP_ASM -extern CFont *D_00262268[5]; - -CFont *FUN_0015c1c0(int i) -{ - CFont *pfont; - - if (i == -1) - { - return NULL; - } - - pfont = D_00262268[i]; - if (pfont != NULL) - { - return pfont; - } - - return g_pfont; -} -#else INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c1c0); -#endif INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c200); @@ -62,31 +40,9 @@ JUNK_ADDIU(50); INCLUDE_ASM("asm/nonmatchings/P2/font", DrawPchz__5CFontPcP8CTextBoxT2P4GIFS); -#ifdef SKIP_ASM -void CFont::PushScaling(float rx, float ry) -{ - int csfr = m_csfr; - - m_csfr = csfr + 1; - m_asfr[csfr].rx = m_rxScale; - m_asfr[csfr].ry = m_rxScale; - m_rxScale = m_asfr[0].rx * rx; - m_ryScale = m_asfr[0].ry * ry; -} - -void CFont::PopScaling() -{ - int csfr = m_csfr - 1; - - m_csfr = csfr; - m_rxScale = m_asfr[csfr].rx; - m_ryScale = m_asfr[csfr].ry; -} -#else INCLUDE_ASM("asm/nonmatchings/P2/font", PushScaling__5CFontff); INCLUDE_ASM("asm/nonmatchings/P2/font", PopScaling__5CFont); -#endif INCLUDE_ASM("asm/nonmatchings/P2/font", PfontClone__8CFontBrxff); @@ -146,17 +102,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", Dx__9CRichText); INCLUDE_ASM("asm/nonmatchings/P2/font", ClineWrap__9CRichTextf); -#ifdef SKIP_ASM -float FUN_0015e1b0(CRichText *prt) -{ - CFont *pfont = prt->m_pfontBase; - float dy = (float)pfont->m_dyUnscaled * pfont->m_ryScale; - - return dy * (float)prt->ClineWrap(dy); -} -#else INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015e1b0); -#endif INCLUDE_ASM("asm/nonmatchings/P2/font", DxMaxLine__9CRichText); From b5a6f1740ae994bed593fce79757078421106c4c Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:12:32 +0200 Subject: [PATCH 059/134] Match 4 rwm functions via LHF harness (recovered from stray-file false-exclude) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ClearRwmFireInfo, DisableRwmRwc, FUN_001a8110, ResizeRwmRwc — matched per-symbol in round 3 but excluded when concurrent draft-agent edits corrupted the build. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/rwm.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/src/P2/rwm.c b/src/P2/rwm.c index ac5c0d77..84f23231 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); @@ -11,7 +12,18 @@ extern "C" void OnRwmRemove(RWM *prwm) FUN_001a93c8(prwm); } -INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a8110); +extern "C" { +void *FUN_001a8110(RWM *prwm) +{ + if (STRUCT_OFFSET(prwm, 0x3c, void *) == 0) + { + void *pv = PvAllocSwClearImpl(0x20); + STRUCT_OFFSET(prwm, 0x3c, void *) = pv; + STRUCT_OFFSET(pv, 0x0, RWM *) = prwm; + } + return STRUCT_OFFSET(prwm, 0x3c, void *); +} +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a8150); @@ -38,9 +50,22 @@ void EnableRwmRwc(RWM *prwm, OID oidCache) STRUCT_OFFSET(prwc, 0x10, int) |= 0x2; } -INCLUDE_ASM("asm/nonmatchings/P2/rwm", DisableRwmRwc__FP3RWM3OID); +void DisableRwmRwc(RWM *prwm, OID oidCache) +{ + RWC *prwc = PrwcFindRwm(prwm, oidCache); + if (prwc != NULL) + STRUCT_OFFSET(prwc, 0x10, int) &= ~0x2; +} -INCLUDE_ASM("asm/nonmatchings/P2/rwm", ResizeRwmRwc__FP3RWM3OIDi); +void ResizeRwmRwc(RWM *prwm, OID oidCache, int cpso) +{ + RWC *prwc = PrwcFindRwm(prwm, oidCache); + if (prwc != NULL) + { + int cMax = STRUCT_OFFSET(prwc, 0xc, int); + STRUCT_OFFSET(prwc, 0x4, int) = (cpso < cMax) ? cpso : cMax; + } +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", FIsRwmAmmo__FP3RWMP2SO); @@ -65,7 +90,16 @@ extern "C" void FUN_001a93c8(RWM *prwm) } } -INCLUDE_ASM("asm/nonmatchings/P2/rwm", ClearRwmFireInfo__FP3RWM); +extern qword D_002483D0[3]; + +void ClearRwmFireInfo(RWM *prwm) +{ + uint8_t *p = (uint8_t *)prwm + 0x60; + memset(p, 0, 0x80); + STRUCT_OFFSET(p, 0x20, qword) = D_002483D0[0]; + STRUCT_OFFSET(p, 0x30, qword) = D_002483D0[1]; + STRUCT_OFFSET(p, 0x40, qword) = D_002483D0[2]; +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", ClearRwmTargetInfo__FP3RWM); From 8e07332f224d2614ab5c924c791f09c888c30493 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:22:24 +0200 Subject: [PATCH 060/134] Match 7 more functions via LHF harness (round-3 clean re-process) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit font/rog/rumble/sb: FUN_0015c1c0, InitRop, InitRost, PostRohLoad, UpdateRost, TriggerRumbleRumk, FUN_001a9928 — recovered from the corrupted round-3 run by re-verifying with no draft agents active. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/font.c | 22 +++++++++++++++++++++- src/P2/rog.c | 31 +++++++++++++++++++++++++++---- src/P2/rumble.c | 9 ++++++++- src/P2/sb.c | 8 +++++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/P2/font.c b/src/P2/font.c index 14b14363..d3e5263c 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -8,7 +8,27 @@ void StartupFont() INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c188); -INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c1c0); +extern "C" { +extern CFont *D_00262268[5]; + +CFont *FUN_0015c1c0(int i) +{ + CFont *pfont; + + if (i == -1) + { + return NULL; + } + + pfont = D_00262268[i]; + if (pfont != NULL) + { + return pfont; + } + + return g_pfont; +} +} INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c200); diff --git a/src/P2/rog.c b/src/P2/rog.c index b8180b1e..5ee76913 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -159,7 +159,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRohFromBrx__FP3ROHP18CBinaryInputStre INCLUDE_ASM("asm/nonmatchings/P2/rog", CloneRoh__FP3ROHT0); -INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRohLoad__FP3ROH); +void PostRohLoad(ROH *proh) +{ + PostAloLoad(proh); + SetRohRohs(proh, ROHS_Inactive); + proh->pvtlo->pfnRemoveLo(proh); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRoh__FP3ROHf); @@ -196,7 +201,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", RocsNextRoc__FP3ROC); INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRocRocs__FP3ROC4ROCS); -INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRost__FP4ROST); +void InitRost(ROST *prost) +{ + InitSo(prost); + STRUCT_OFFSET(prost, 0x550, ROSTS) = ROSTS_Nil; // prost->rosts +} INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRostFromBrx__FP4ROSTP18CBinaryInputStream); @@ -204,7 +213,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", CloneRost__FP4ROSTT0); INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRostLoad__FP4ROST); -INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRost__FP4ROSTf); +void UpdateRost(ROST *prost, float dt) +{ + ROSTS rosts; + + UpdateSo(prost, dt); + while ((rosts = RostsNextRost(prost)) != STRUCT_OFFSET(prost, 0x550, ROSTS)) + { + SetRostRosts(prost, rosts); + } +} ROSTS RostsNextRost(ROST *prost) { @@ -213,7 +231,12 @@ ROSTS RostsNextRost(ROST *prost) INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRostRosts__FP4ROST5ROSTS); -INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRop__FP3ROP); +void InitRop(ROP *prop) +{ + InitSo(prop); + STRUCT_OFFSET(prop, 0x550, int) = -1; // prop->rops + SetSoConstraints(prop, CT_Locked, NULL, CT_Locked, NULL); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRopFromBrx__FP3ROPP18CBinaryInputStream); diff --git a/src/P2/rumble.c b/src/P2/rumble.c index 49c697e1..ef96472d 100644 --- a/src/P2/rumble.c +++ b/src/P2/rumble.c @@ -24,7 +24,14 @@ void InitRumble(RUMBLE *prumble, int nPort, int nSlot) INCLUDE_ASM("asm/nonmatchings/P2/rumble", UpdateRumble__FP6RUMBLE); -INCLUDE_ASM("asm/nonmatchings/P2/rumble", TriggerRumbleRumk__FP6RUMBLE4RUMKf); +extern RUMPAT D_0026B8B0[]; + +void TriggerRumbleRumpat(RUMBLE *prumble, RUMPAT *prumpat, float dt); + +void TriggerRumbleRumk(RUMBLE *prumble, RUMK rumk, float dt) +{ + TriggerRumbleRumpat(prumble, &D_0026B8B0[rumk], dt); +} INCLUDE_ASM("asm/nonmatchings/P2/rumble", TriggerRumbleRumpat__FP6RUMBLEP6RUMPATf); diff --git a/src/P2/sb.c b/src/P2/sb.c index 05e26cc1..445c2d19 100644 --- a/src/P2/sb.c +++ b/src/P2/sb.c @@ -1,8 +1,14 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/sb", PostSbgLoad__FP3SBG); -INCLUDE_ASM("asm/nonmatchings/P2/sb", FUN_001a9928__FP3SBG); +undefined4 FUN_001a9928(SBG *psbg) +{ + if (IsSwHandsOff(STRUCT_OFFSET(psbg, 0x14, SW *))) + return 0; + return STRUCT_OFFSET(psbg, 0xc24, int); +} INCLUDE_ASM("asm/nonmatchings/P2/sb", UpdateSbgGoal__FP3SBGi); From e595210dbf4d2ce3883424df2beeba0b48713f1b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:30:04 +0200 Subject: [PATCH 061/134] Match 4 rog Brx-loaders via LHF harness LoadRoc/Roh/Rop/RostFromBrx: LoadSoFromBrx + SnipAloObjects(p, N, &D_00xxxxxx) + InferExpl; the agents guessed s_asnip names, the real rodata SNIP symbols are D_0026B830/B7E8/B8A0/B888. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/rog.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/P2/rog.c b/src/P2/rog.c index 5ee76913..2dfe9db1 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -1,6 +1,7 @@ #include #include #include +#include extern SNIP s_asnipLoadRov[2]; @@ -155,7 +156,14 @@ RODD *ProddCurRob(ROB *prob, ENSK ensk) INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRoh__FP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRohFromBrx__FP3ROHP18CBinaryInputStream); +extern SNIP D_0026B7E8; + +void LoadRohFromBrx(ROH *proh, CBinaryInputStream *pbis) +{ + LoadSoFromBrx(proh, pbis); + SnipAloObjects(proh, 6, &D_0026B7E8); + InferExpl(&STRUCT_OFFSET(proh, 0x5ac, EXPL *), proh); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", CloneRoh__FP3ROHT0); @@ -180,7 +188,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", ProcContactRoh__FP3ROH); INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRoc__FP3ROC); -INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRocFromBrx__FP3ROCP18CBinaryInputStream); +extern SNIP D_0026B830; + +void LoadRocFromBrx(ROC *proc, CBinaryInputStream *pbis) +{ + LoadSoFromBrx(proc, pbis); + SnipAloObjects(proc, 1, &D_0026B830); + InferExpl(&STRUCT_OFFSET(proc, 0x574, EXPL *), proc); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", CloneRoc__FP3ROCT0); @@ -207,7 +222,13 @@ void InitRost(ROST *prost) STRUCT_OFFSET(prost, 0x550, ROSTS) = ROSTS_Nil; // prost->rosts } -INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRostFromBrx__FP4ROSTP18CBinaryInputStream); +extern SNIP D_0026B888; + +void LoadRostFromBrx(ROST *prost, CBinaryInputStream *pbis) +{ + LoadSoFromBrx(prost, pbis); + SnipAloObjects(prost, 1, &D_0026B888); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", CloneRost__FP4ROSTT0); @@ -238,7 +259,14 @@ void InitRop(ROP *prop) SetSoConstraints(prop, CT_Locked, NULL, CT_Locked, NULL); } -INCLUDE_ASM("asm/nonmatchings/P2/rog", LoadRopFromBrx__FP3ROPP18CBinaryInputStream); +extern SNIP D_0026B8A0; + +void LoadRopFromBrx(ROP *prop, CBinaryInputStream *pbis) +{ + LoadSoFromBrx(prop, pbis); + SnipAloObjects(prop, 1, &D_0026B8A0); + InferExpl(&STRUCT_OFFSET(prop, 0x568, EXPL *), prop); +} INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRopLoad__FP3ROP); From 03b1cf8f7b3399b66bf55e0631588e187d39b087 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:31:04 +0200 Subject: [PATCH 062/134] Match 4 more SNIP-loaders (puffer/pzo) via LHF harness LoadPufferFromBrx, LoadLockFromBrx, PostLockLoad, LoadLockgFromBrx: same real-D_-symbol fix (D_0026A728/A918/A928/A938). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/puffer.c | 8 +++++++- src/P2/pzo.c | 24 +++++++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/P2/puffer.c b/src/P2/puffer.c index b461cdc2..9d390ba2 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -3,7 +3,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", InitPuffer__FP6PUFFER); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", LoadPufferFromBrx__FP6PUFFERP18CBinaryInputStream); +extern SNIP D_0026A728; + +void LoadPufferFromBrx(PUFFER *ppuffer, CBinaryInputStream *pbis) +{ + LoadSoFromBrx(ppuffer, pbis); + SnipAloObjects(ppuffer, 1, &D_0026A728); +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", PostPufferLoad__FP6PUFFER); diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 6703f600..182de8e3 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -60,7 +60,13 @@ void CollectScprize(SCPRIZE *pscprize) CollectSprize(pscprize); } -INCLUDE_ASM("asm/nonmatchings/P2/pzo", LoadLockFromBrx__FP4LOCKP18CBinaryInputStream); +extern SNIP D_0026A918; + +void LoadLockFromBrx(LOCK *plock, CBinaryInputStream *pbis) +{ + LoadAloFromBrx(plock, pbis); + SnipAloObjects(plock, 1, &D_0026A918); +} #ifdef SKIP_ASM /** * @todo 95.80% matched. s_asnip may not be defined correctly. @@ -73,7 +79,13 @@ void LoadLockFromBrx(LOCK *plock, CBinaryInputStream *pbis) } #endif -INCLUDE_ASM("asm/nonmatchings/P2/pzo", PostLockLoad__FP4LOCK); +extern SNIP D_0026A928; + +void PostLockLoad(LOCK *plock) +{ + PostAloLoad(plock); + SnipAloObjects(plock, 1, &D_0026A928); +} #ifdef SKIP_ASM /** * @todo 95.00% matched. s_asnip may not be defined correctly. @@ -86,7 +98,13 @@ void PostLockLoad(LOCK *plock) } #endif -INCLUDE_ASM("asm/nonmatchings/P2/pzo", LoadLockgFromBrx__FP5LOCKGP18CBinaryInputStream); +extern SNIP D_0026A938; + +void LoadLockgFromBrx(LOCKG *plockg, CBinaryInputStream *pbis) +{ + LoadAloFromBrx(plockg, pbis); + SnipAloObjects(plockg, 1, &D_0026A938); +} #ifdef SKIP_ASM /** * @todo 95.00% matched. s_asnip may not be defined correctly. From c3ce690bde2fa6be892a2e83af4f269d86a378e4 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:36:10 +0200 Subject: [PATCH 063/134] Match FUN_001aca30/FUN_001aca68 (screen) via LHF harness Blot show/hide guards (field[0x250]==3 && field[0x260]!=0); renamed FUN_ symbols to mangled (no asm callers). False-excluded by process.py's flaky per-symbol check; verified via full checksum. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 4 ++-- src/P2/screen.c | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 953d4b9f..e8ac47fe 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3612,8 +3612,8 @@ FUN_001ac888 = 0x1AC888; // type:func FUN_001ac910 = 0x1AC910; // type:func FUN_001ac990 = 0x1AC990; // type:func FUN_001ac9e0 = 0x1AC9E0; // type:func -FUN_001aca30 = 0x1ACA30; // type:func -FUN_001aca68 = 0x1ACA68; // type:func +FUN_001aca30__FP4BLOT = 0x1ACA30; // type:func +FUN_001aca68__FP4BLOT = 0x1ACA68; // type:func DrawTitle__FP5TITLE = 0x1ACAA8; // type:func PostTotalsLoad__FP6TOTALS = 0x1ACDA0; // type:func FUN_001ace38 = 0x1ACE38; // type:func diff --git a/src/P2/screen.c b/src/P2/screen.c index ec7368c6..e0437c06 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -220,9 +220,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac990); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac9e0); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001aca30); +void FUN_001aca30(BLOT *pblot) +{ + if (STRUCT_OFFSET(pblot, 0x250, int) == 3 && STRUCT_OFFSET(pblot, 0x260, int) != 0) + return; + ShowBlot(pblot); +} -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001aca68); +void FUN_001aca68(BLOT *pblot) +{ + if (STRUCT_OFFSET(pblot, 0x250, int) == 3 && STRUCT_OFFSET(pblot, 0x260, int) != 0) + { + STRUCT_OFFSET(pblot, 0x260, int) = 0; + return; + } + HideBlot(pblot); +} INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawTitle__FP5TITLE); From 2e1050e440f55607e105e536d28df607c8d0bb0f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 21:37:36 +0200 Subject: [PATCH 064/134] Strip duplicate SKIP_ASM stubs in pzo.c (manual-apply cleanup) The hand-applied LoadLock/PostLock loaders left the old #ifdef SKIP_ASM attempts in place; harmless to checksum but broke --objects. Removed. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/pzo.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 182de8e3..3a3c012b 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -67,18 +67,6 @@ void LoadLockFromBrx(LOCK *plock, CBinaryInputStream *pbis) LoadAloFromBrx(plock, pbis); SnipAloObjects(plock, 1, &D_0026A918); } -#ifdef SKIP_ASM -/** - * @todo 95.80% matched. s_asnip may not be defined correctly. - */ -void LoadLockFromBrx(LOCK *plock, CBinaryInputStream *pbis) -{ - static SNIP *s_asnip; - LoadAloFromBrx(plock, pbis); - SnipAloObjects(plock, 1, s_asnip); -} -#endif - extern SNIP D_0026A928; void PostLockLoad(LOCK *plock) @@ -86,18 +74,6 @@ void PostLockLoad(LOCK *plock) PostAloLoad(plock); SnipAloObjects(plock, 1, &D_0026A928); } -#ifdef SKIP_ASM -/** - * @todo 95.00% matched. s_asnip may not be defined correctly. - */ -void PostLockLoad(LOCK *plock) -{ - static SNIP *s_asnip; - PostAloLoad(plock); - SnipAloObjects(plock, 1, s_asnip); -} -#endif - extern SNIP D_0026A938; void LoadLockgFromBrx(LOCKG *plockg, CBinaryInputStream *pbis) @@ -105,17 +81,6 @@ void LoadLockgFromBrx(LOCKG *plockg, CBinaryInputStream *pbis) LoadAloFromBrx(plockg, pbis); SnipAloObjects(plockg, 1, &D_0026A938); } -#ifdef SKIP_ASM -/** - * @todo 95.00% matched. s_asnip may not be defined correctly. - */ -void LoadLockgFromBrx(LOCKG *plockg, CBinaryInputStream *pbis) -{ - LoadAloFromBrx(plockg, pbis); - // SnipAloObjects(plockg, 1, PostLockgLoad); -} -#endif - INCLUDE_ASM("asm/nonmatchings/P2/pzo", PostLockgLoad__FP5LOCKG); #ifdef SKIP_ASM /** From 08c19222f89a9e93c527616be05ca15cc640b10f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 22:46:29 +0200 Subject: [PATCH 065/134] Match 4 functions in gs/mb/pzo/rog (21-30 instr window, round 1) PropagateSur, OnMgExitingSgs, PcsFromScprize, SpawnedRobRoh. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/gs.c | 20 +++++++++++++++++++- src/P2/mb.c | 18 +++++++++++++++++- src/P2/pzo.c | 17 ++++++++++++++++- src/P2/rog.c | 9 ++++++++- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/P2/gs.c b/src/P2/gs.c index a1b49ec3..f58f424a 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/gs", BlendDisplayOnBufferMismatch__Fv); @@ -92,7 +93,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", UploadBitmaps__FiP3GSB); INCLUDE_ASM("asm/nonmatchings/P2/gs", PqwGifsBitmapUpload__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/gs", PropagateSur__FP3SUR); +void PropagateSur(SUR *psur) +{ + CopyAb(psur->pvDst, psur->pvSrc, psur->cb); + + if (psur->cvtx) + { + int *p = (int *)psur->pvDst; + int v0 = p[0]; + int v1 = p[0x10 / 4]; + + v0 |= 0x8000; + v0 |= (int)psur->cvtx; + v1 |= 0x8000; + + p[0] = v0; + p[0x10 / 4] = v1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/gs", ReferenceShaderAqwRegs__FP3SHDP4SHDPP2QWiiP3SAI); diff --git a/src/P2/mb.c b/src/P2/mb.c index 7f447754..d79b3944 100644 --- a/src/P2/mb.c +++ b/src/P2/mb.c @@ -1,4 +1,5 @@ #include +#include extern SNIP s_asnipLoadMbg[2]; @@ -47,7 +48,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/mb", UpdateMbgGoal__FP3MBGi); INCLUDE_ASM("asm/nonmatchings/P2/mb", UpdateMbgSgs__FP3MBG); -INCLUDE_ASM("asm/nonmatchings/P2/mb", OnMgExitingSgs__FP3MBG3SGS); +void OnMgExitingSgs(MBG *pmbg, SGS sgs) +{ + OnStepguardExitingSgs(pmbg, sgs); + + int field_0x724 = STRUCT_OFFSET(pmbg, 0x724, int); + if (field_0x724 == 0x10) + { + int field_0xE3C = STRUCT_OFFSET(pmbg, 0xE3C, int); + if (field_0xE3C != -1) + { + int field_0xE10 = STRUCT_OFFSET(pmbg, 0xE10, int); + SetSmaGoal((SMA *)field_0xE10, (OID)field_0xE3C); + STRUCT_OFFSET(pmbg, 0xE3C, int) = -1; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/mb", HandleMbgMessage__FP3MBG5MSGIDPv); diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 3a3c012b..9f997036 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -52,7 +52,22 @@ void CloneScprize(SCPRIZE *pscprize, SCPRIZE *pscprizeBase) STRUCT_OFFSET(pscprize, 0x5a0, int) = ichk; } -INCLUDE_ASM("asm/nonmatchings/P2/pzo", PcsFromScprize__FP7SCPRIZE); +PCS PcsFromScprize(SCPRIZE *pscprize) +{ + extern int FGetChkmgrIchk(CHKMGR *pchkmgr, int ichk); + extern CHKMGR g_chkmgr; + + PCS pcs = PcsFromSprize((SPRIZE *)pscprize); + + if (pcs == PCS_Collectible) { + int ichk = STRUCT_OFFSET(pscprize, 0x5a0, int); + if (FGetChkmgrIchk(&g_chkmgr, ichk) != 0) { + pcs = PCS_Collected; + } + } + + return pcs; +} void CollectScprize(SCPRIZE *pscprize) { diff --git a/src/P2/rog.c b/src/P2/rog.c index 2dfe9db1..6056f9b2 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -2,6 +2,7 @@ #include #include #include +#include extern SNIP s_asnipLoadRov[2]; @@ -123,7 +124,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", AdjustRobDifficulty__FP3ROBf); INCLUDE_ASM("asm/nonmatchings/P2/rog", DestroyedRobRoc__FP3ROBP3ROC); -INCLUDE_ASM("asm/nonmatchings/P2/rog", SpawnedRobRoh__FP3ROBP3ROH); +void SpawnedRobRoh(ROB *prob, ROH *proh) +{ + RemoveDlEntry((DL *)&STRUCT_OFFSET(prob, 0x3AC, int), STRUCT_OFFSET(proh, 0x560, ROST *)); + AppendDlEntry((DL *)&STRUCT_OFFSET(prob, 0x3A0, int), STRUCT_OFFSET(proh, 0x560, ROST *)); + SetRostRosts(STRUCT_OFFSET(proh, 0x560, ROST *), ROSTS_Close); + STRUCT_OFFSET(proh, 0x560, ROST *) = NULL; +} INCLUDE_ASM("asm/nonmatchings/P2/rog", GrabbedRobRoh__FP3ROBP3ROH); From dd41e0a0f80b3a130fba693b0482489cdeb0524f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 22:52:33 +0200 Subject: [PATCH 066/134] Match InitRoh (rog) via LHF harness (21-30 window, round 2) InitSo + SetSoConstraints(CT_Tangent/CT_Project, g_normalZ). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/rog.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/P2/rog.c b/src/P2/rog.c index 6056f9b2..94da374e 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -161,7 +161,16 @@ RODD *ProddCurRob(ROB *prob, ENSK ensk) return (RODD *)((uint8_t *)prob + (irodd * 0xC0 + 0x3E0)); } -INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRoh__FP3ROH); +extern VECTOR g_normalZ; + +void InitRoh(ROH *proh) +{ + InitSo(proh); + STRUCT_OFFSET(proh, 0x550, int) = -1; + STRUCT_OFFSET(proh, 0x584, float) = 1.0f; + STRUCT_OFFSET(proh, 0x588, float) = 2.5f; + SetSoConstraints(proh, CT_Tangent, &g_normalZ, CT_Project, &g_normalZ); +} extern SNIP D_0026B7E8; From a9e4cb0099622d7fbd3e9d448c2f856e9560f232 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 23:02:16 +0200 Subject: [PATCH 067/134] Match 3 functions in bomb/crv (21-30 window, round 3) HandleBombMessage, GWrapApos, UFromCrvlS. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/bomb.c | 13 ++++++++++++- src/P2/crv.c | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/P2/bomb.c b/src/P2/bomb.c index d113b1de..675d8bbb 100644 --- a/src/P2/bomb.c +++ b/src/P2/bomb.c @@ -25,7 +25,18 @@ void CloneBomb(BOMB *pbomb, BOMB *pbombBase) INCLUDE_ASM("asm/nonmatchings/P2/bomb", PostBombLoad__FP4BOMB); -INCLUDE_ASM("asm/nonmatchings/P2/bomb", HandleBombMessage__FP4BOMB5MSGIDPv); +void HandleBombMessage(BOMB *pbomb, MSGID msgid, void *pv) +{ + HandleAloMessage((ALO *)pbomb, msgid, pv); + + if (msgid == 0xA) { + if (*(int *)((uint8_t *)pv + 0x4) == (int)pbomb) { + if (!STRUCT_OFFSET(pbomb, 0x550, int)) { + PrimeBomb(pbomb, 0.0f); + } + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/bomb", UpdateBomb__FP4BOMBf); diff --git a/src/P2/crv.c b/src/P2/crv.c index 9a09f709..3d45d891 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -2,7 +2,27 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureApos__FiP6VECTORPf); -INCLUDE_ASM("asm/nonmatchings/P2/crv", GWrapApos__FfiPfi); +float GWrapApos(float g, int cpos, float *mpiposg, int fClosed) +{ + float f0 = g; + if (fClosed == 0) { + return f0; + } + + float f1 = mpiposg[0]; + float f3 = mpiposg[cpos - 1]; + float f2 = f3 - f1; + + while (f0 < f1) { + f0 = f0 + f2; + } + + while (f3 < f0) { + f0 = f0 - f2; + } + + return f0; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", IposFindAposG__FfiPfiT2T2); @@ -96,7 +116,21 @@ void ConvertCrvl(CRVL *pcrvl, MATRIX4 *pmatSrc, MATRIX4 *pmatDst) INCLUDE_ASM("asm/nonmatchings/P2/crv", SFromCrvlU__FP4CRVLf); -INCLUDE_ASM("asm/nonmatchings/P2/crv", UFromCrvlS__FP4CRVLf); +float UFromCrvlS(CRVL *pcrvl, float s) +{ + float ds, dsSeg; + int icv; + float *mpicvu; + float u0, u1; + float result; + + icv = IcvFindCrvS((CRV *)pcrvl, s, &ds, &dsSeg); + mpicvu = STRUCT_OFFSET(pcrvl, 0x10, float *); + u0 = mpicvu[icv]; + u1 = mpicvu[icv + 1]; + result = (1.0f - (ds / dsSeg)) * u0 + (ds / dsSeg) * u1; + return result; +} void MeasureCrvl(CRVL *pcrvl) { From 78ca57d0c1628a169e7d43dba42b4794790a59de Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 23:14:36 +0200 Subject: [PATCH 068/134] Match 13 medium functions via LHF harness (21-30 window, editable re-draft 1) act/crusher/jlo/rat/rip/rog/sb/screen/step/stepguard: PactNew(Clone), loaders, vtable dispatch, list ops, indexed stores. Editable agents draft far more rigorously than read-only (34%% vs 4%% hit rate). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 19 +++++++++++++++++-- src/P2/crusher.c | 16 +++++++++++++++- src/P2/jlo.c | 11 ++++++++++- src/P2/rat.c | 11 ++++++++++- src/P2/rip.c | 9 ++++++++- src/P2/rog.c | 9 ++++++++- src/P2/sb.c | 34 ++++++++++++++++++++++++++++++++-- src/P2/screen.c | 30 ++++++++++++++++++++++++++++-- src/P2/step.c | 6 +++++- src/P2/stepguard.c | 13 ++++++++++++- 10 files changed, 145 insertions(+), 13 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index fa64bd08..0fe06427 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -1,8 +1,23 @@ #include +#include +#include -INCLUDE_ASM("asm/nonmatchings/P2/act", PactNew__FP2SWP3ALOP5VTACT); +ACT *PactNew(SW *psw, ALO *palo, VTACT *pvtact) +{ + ACT *pact = (ACT *)PvAllocSlotheapClearImpl((SLOTHEAP *)((uint8_t *)psw + 0x1B20)); + pact->pvtact = pvtact; + (*(void (**)(ACT *, ALO *))pvtact)(pact, palo); + return pact; +} + +extern VTACT D_00219560; -INCLUDE_ASM("asm/nonmatchings/P2/act", PactNewClone__FP3ACTP2SWP3ALO); +ACT *PactNewClone(ACT *pactBase, SW *psw, ALO *palo) +{ + ACT *pact = PactNew(psw, palo, &D_00219560); + (*(void (**)(ACT *, ACT *))((uint8_t *)pact->pvtact + 4))(pact, pactBase); + return pact; +} INCLUDE_ASM("asm/nonmatchings/P2/act", CloneAct__FP3ACTT0); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index dd6470fc..a946db83 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -90,7 +90,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c858); INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014cba8); -INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014cd70); +extern "C" { +void FUN_0014cd70(void *p) +{ + int n; + + if (STRUCT_OFFSET(p, 0x458, int) == STRUCT_OFFSET(p, 0x450, int)) + { + float g = GRandInRange(STRUCT_OFFSET(p, 0x43c, float), STRUCT_OFFSET(p, 0x440, float)); + STRUCT_OFFSET(p, 0x45c, float) = g_clock.t + g; + } + + n = STRUCT_OFFSET(p, 0x458, int); + STRUCT_OFFSET(p, 0x458, int) = n - 1; +} +} INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014cdc8); diff --git a/src/P2/jlo.c b/src/P2/jlo.c index 8569f3b6..4ab7009d 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -1,5 +1,6 @@ #include #include +#include extern JLO *g_pjloCur; extern VECTOR g_normalZ; // TODO: This should be elsewhere. @@ -71,7 +72,15 @@ void DeactivateJlo(JLO *pjlo) INCLUDE_ASM("asm/nonmatchings/P2/jlo", InitJloc__FP4JLOC); -INCLUDE_ASM("asm/nonmatchings/P2/jlo", LoadJlocFromBrx__FP4JLOCP18CBinaryInputStream); +void LoadJlocFromBrx(JLOC *pjloc, CBinaryInputStream *pbis) +{ + LoadAloFromBrx(pjloc, pbis); + + uint cplo = CploFindSwObjectsByClass(pjloc->psw, FSO_FindChild | FSO_ReturnActualCount, (CID)0x73, pjloc, 0x10, &STRUCT_OFFSET(pjloc, 0x2D0, LO *)); + STRUCT_OFFSET(pjloc, 0x310, uint) = cplo; + if (cplo > 0x10) + STRUCT_OFFSET(pjloc, 0x310, uint) = 0x10; +} void PostJlocLoad(JLOC *pjloc) { diff --git a/src/P2/rat.c b/src/P2/rat.c index 50f0430d..3018ac41 100644 --- a/src/P2/rat.c +++ b/src/P2/rat.c @@ -13,7 +13,16 @@ void InitRat(RAT *prat) INCLUDE_ASM("asm/nonmatchings/P2/rat", LoadRatFromBrx__FP3RATP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/rat", PostRatLoad__FP3RAT); +extern SNIP D_0026ABA0; + +void PostRatLoad(RAT *prat) +{ + SnipAloObjects(prat, 1, &D_0026ABA0); + PostAloLoad(prat); + STRUCT_OFFSET(prat, 0x550, int) = -1; + SetRatRats(prat, RATS_Scurry); + STRUCT_OFFSET(prat, 0x650, qword) = STRUCT_OFFSET(prat, 0x140, qword); +} void OnRatAdd(RAT *prat) { diff --git a/src/P2/rip.c b/src/P2/rip.c index f87ba51e..655a230a 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -222,7 +222,14 @@ int FFilterFlameObjects(void *pv, SO *pso) INCLUDE_ASM("asm/nonmatchings/P2/rip", PostFlameEmit__FP5FLAMEP5EMITB); -INCLUDE_ASM("asm/nonmatchings/P2/rip", PostBulletEmit__FP6BULLETP5EMITB); +void PostBulletEmit(BULLET *pbullet, EMITB *pemitb) +{ + ConvertAloPos(STRUCT_OFFSET(pemitb, 0x7c, ALO *), NULL, &STRUCT_OFFSET(pemitb, 0x20, VECTOR), &STRUCT_OFFSET(pbullet, 0x80, VECTOR)); + STRUCT_OFFSET(pbullet, 0xb0, int) = 0; + STRUCT_OFFSET(pbullet, 0x110, int) = 0; + STRUCT_OFFSET(pbullet, 0x120, int) = STRUCT_OFFSET(pemitb, 0x1f4, int); + STRUCT_OFFSET(pbullet, 0x124, int) = STRUCT_OFFSET(pemitb, 0x1f0, int); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderBullet__FP6BULLETP2CM); diff --git a/src/P2/rog.c b/src/P2/rog.c index 94da374e..e3ff0358 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -57,7 +57,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", PresetRovAccel__FP3ROVf); INCLUDE_ASM("asm/nonmatchings/P2/rog", AdjustRovXpVelocity__FP3ROVP2XPi); -INCLUDE_ASM("asm/nonmatchings/P2/rog", AdjustRovNewXp__FP3ROVP2XPi); +void AdjustRovNewXp(ROV *prov, XP *pxp, int ixpd) +{ + if (FDrivenAlo(prov)) + return; + + if (0.7f < STRUCT_OFFSET(pxp, 0x88, float)) + STRUCT_OFFSET(pxp, 0x94, float) = 20.0f; +} INCLUDE_ASM("asm/nonmatchings/P2/rog", PropagateRovForce__FP3ROViP2XPiP2DZP2FX); diff --git a/src/P2/sb.c b/src/P2/sb.c index 445c2d19..edf7fc0e 100644 --- a/src/P2/sb.c +++ b/src/P2/sb.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/sb", PostSbgLoad__FP3SBG); @@ -10,7 +11,21 @@ undefined4 FUN_001a9928(SBG *psbg) return STRUCT_OFFSET(psbg, 0xc24, int); } -INCLUDE_ASM("asm/nonmatchings/P2/sb", UpdateSbgGoal__FP3SBGi); +void UpdateSbgGoal(SBG *psbg, int fEnter) +{ + UpdateStepguardGoal(psbg, fEnter); + + if (STRUCT_OFFSET(psbg, 0x724, int) == 0x10) + { + void *pvt = STRUCT_OFFSET(psbg, 0x0, void *); + SO *(*fn)(SO *) = (SO *(*)(SO *))STRUCT_OFFSET(pvt, 0x198, void *); + SO *pso = fn((SO *)psbg); + if (pso != NULL) + { + SetStepguardGoal(psbg, (VECTOR *)((char *)pso + 0x140)); + } + } +} void UpdateSbgSgs(SBG *psbg) { @@ -25,7 +40,22 @@ void UpdateSbgSgs(SBG *psbg) INCLUDE_ASM("asm/nonmatchings/P2/sb", OnSbgEnteringSgs__FP3SBG3SGSP4ASEG); -INCLUDE_ASM("asm/nonmatchings/P2/sb", UpdateSbg__FP3SBGf); +void UpdateSbg(SBG *psbg, float dt) +{ + ASEGA *pasega; + + UpdateStepguard(psbg, dt); + + pasega = STRUCT_OFFSET(psbg, 0xC20, ASEGA *); + if (pasega != NULL) + { + if (STRUCT_OFFSET(pasega, 0x18, float) == 0.0f) + { + RetractAsega(pasega); + STRUCT_OFFSET(psbg, 0xC20, ASEGA *) = NULL; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/sb", FUN_001a9a98); diff --git a/src/P2/screen.c b/src/P2/screen.c index e0437c06..a35ec604 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -1,10 +1,20 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/screen", StartupScreen__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/screen", PostBlotsLoad__Fv); +void PostBlotsLoad() +{ + extern BLOT *D_002486B0[]; + + for (int i = 0x24; i >= 0; i--) + { + BLOT *pblot = D_002486B0[i]; + ((VTBLOT *)pblot->pvtblot)->pfnPostBlotLoad(pblot); + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", UpdateBlots__Fv); @@ -251,7 +261,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", render_level_info); INCLUDE_ASM("asm/nonmatchings/P2/screen", render_hideout_world_info); -INCLUDE_ASM("asm/nonmatchings/P2/screen", SetTotalsBlots__FP6TOTALS5BLOTS); +void SetTotalsBlots(TOTALS *ptotals, BLOTS blots) +{ + if (ptotals->fReshow) + { + if (blots == BLOTS_Hidden) + { + ptotals->fReshow = 0; + SetBlotAchzDraw(ptotals, (char *)&ptotals->grflsReshow); + blots = BLOTS_Appearing; + } + } + + if (blots == BLOTS_Hidden) + STRUCT_OFFSET(ptotals, 0x464, int) = 0; + + SetBlotBlots(ptotals, blots); +} INCLUDE_ASM("asm/nonmatchings/P2/screen", ShowTotalsQMARK); diff --git a/src/P2/step.c b/src/P2/step.c index b0d275c3..9c883fbb 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -72,7 +72,11 @@ void UpdateStepMatTarget(STEP *pstep) LoadRotateMatrixRad(*(float *)((uint8_t *)(pstep) + 0x638), &g_normalZ, (MATRIX3 *)((uint8_t *)(pstep) + 0x660)); } -INCLUDE_ASM("asm/nonmatchings/P2/step", AdjustStepXpVelocity__FP4STEPP2XPi); +void AdjustStepXpVelocity(STEP *pstep, XP *pxp, int ixpd) +{ + if ((*(int (**)(STEP *))((char *)pstep->pvtlo + 0x168))(pstep)) + AdjustStepXpVelocityBase(pstep, pxp, ixpd); +} INCLUDE_ASM("asm/nonmatchings/P2/step", UpdateStepXfWorld__FP4STEP); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 9e442802..104780d9 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -1,6 +1,7 @@ #include #include #include +#include extern SNIP s_asnipStepguardLoad; @@ -160,7 +161,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", HandleStepguardGrfsgsc__FP9STEPGUAR INCLUDE_ASM("asm/nonmatchings/P2/stepguard", DoStepguardFreefallJump__FP9STEPGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", DoStepguardFreefallLanding__FP9STEPGUARD); +void SeekAsega(ASEGA *pasega, SEEK seek, float t, float svt); + +void DoStepguardFreefallLanding(STEPGUARD *pstepguard) +{ + ASEGA *pasegaSgs = STRUCT_OFFSET(pstepguard, 0x7e0, ASEGA *); + STRUCT_OFFSET(pstepguard, 0xb8c, int) = 0; + STRUCT_OFFSET(pstepguard, 0xa60, int) = 0; + float t = TFindAsegLabel(STRUCT_OFFSET(pasegaSgs, 0x8, ASEG *), (OID)0x1B1); + SeekAsega(STRUCT_OFFSET(pstepguard, 0x7e0, ASEGA *), SEEK_Start, t, 1.0f); + STRUCT_OFFSET(pstepguard, 0xba4, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001c9d50); From c030d7dbee006f8fdefabdd9483ac0bf6b6e6c5d Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 23:27:37 +0200 Subject: [PATCH 069/134] Match 14 medium functions via LHF harness (21-30 window, editable re-draft 2) break/clip/cplcy/crv/dartgun/dialog/eyes/rip/rog/screen/splicemap/step/ stepguard: clone, comparators, init, list-walk, vtable dispatch, atan2. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/break.c | 13 ++++++++++++- src/P2/clip.c | 10 +++++++++- src/P2/cplcy.c | 11 ++++++++++- src/P2/crv.c | 21 ++++++++++++++++++++- src/P2/dartgun.c | 11 ++++++++++- src/P2/dialog.c | 18 +++++++++++++++++- src/P2/eyes.c | 12 +++++++++++- src/P2/rip.c | 10 +++++++++- src/P2/rog.c | 31 +++++++++++++++++++++++++++++-- src/P2/screen.c | 11 ++++++++++- src/P2/splicemap.c | 15 ++++++++++++++- src/P2/step.c | 13 ++++++++++++- src/P2/stepguard.c | 13 ++++++++++++- 13 files changed, 175 insertions(+), 14 deletions(-) diff --git a/src/P2/break.c b/src/P2/break.c index 6b2fd91a..c6fa001a 100644 --- a/src/P2/break.c +++ b/src/P2/break.c @@ -1,12 +1,23 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/break", InitBrk__FP3BRK); INCLUDE_ASM("asm/nonmatchings/P2/break", LoadBrkFromBrx__FP3BRKP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/break", CloneBrk__FP3BRKT0); +void CloneBrk(BRK *pbrk, BRK *pbrkBase) +{ + int ichkBroken = STRUCT_OFFSET(pbrk, 0x688, int); + CloneSo(pbrk, pbrkBase); + STRUCT_OFFSET(pbrk, 0x688, int) = ichkBroken; + + if (STRUCT_OFFSET(pbrkBase, 0x6b4, SFX *) != NULL) + { + STRUCT_OFFSET(pbrk, 0x6b4, SFX *) = (SFX *)PvAllocSwCopyImpl(0x24, STRUCT_OFFSET(pbrkBase, 0x6b4, SFX *)); + } +} void PostBrkLoad(BRK *pbrk) { diff --git a/src/P2/clip.c b/src/P2/clip.c index b63fc4e1..17bbad89 100644 --- a/src/P2/clip.c +++ b/src/P2/clip.c @@ -20,7 +20,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/clip", ClsgClipEdgeToCylinder__FP6VECTORT0fT0T0 JUNK_WORD(0x27BD01C0); -INCLUDE_ASM("asm/nonmatchings/P2/clip", SgnCompareMaa__FP3MAAT0); +int SgnCompareMaa(MAA *pmaa1, MAA *pmaa2) +{ + float d = pmaa1->u - pmaa2->u; + if (d < -1e-4f) + return -1; + if (1e-4f < d) + return 1; + return pmaa1->iu - pmaa2->iu; +} INCLUDE_ASM("asm/nonmatchings/P2/clip", ClsgMergeAlsg__FiP3LSG); diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index b78dd821..3af4c839 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -59,7 +59,16 @@ LOOKK LookkCurCplook(CPLOOK *pcplook) return a[i]; } -INCLUDE_ASM("asm/nonmatchings/P2/cplcy", InitCplook); +extern "C" void InitCplook(CPLOOK *pcplook, CM *pcm) +{ + InitCplcy(pcplook, pcm); + pcplook->fSoundPaused = 0; + pcplook->rZoomMax = 10.0f; + PushCplookLookk(pcplook, LOOKK_User); + pcplook->sRadiusSniper = 0.5f; + pcplook->rScreenSniper = -1.0f; + pcplook->ppntAnchor = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_001496c0); diff --git a/src/P2/crv.c b/src/P2/crv.c index 3d45d891..6a4a760d 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureApos__FiP6VECTORPf); @@ -70,7 +71,25 @@ float SMaxCrv(CRV *pcrv) JUNK_ADDIU(A0); -INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureCrvSegmentU__FP5CRVMSf); +float SMeasureCrvSegmentU(CRVMS *pcrvms, float u) +{ + VECTOR pos; + float du, ps; + void *pcrv; + void **pvtbl; + void (*pfn)(void *, VECTOR *, int); + + pcrv = STRUCT_OFFSET(pcrvms, 0x0, void *); + pvtbl = STRUCT_OFFSET(pcrv, 0x0, void **); + pfn = (void (*)(void *, VECTOR *, int))pvtbl[1]; + if (pfn != NULL) + { + pfn(pcrv, &pos, 0); + } + + FindClosestPointOnLineSegment(&pos, STRUCT_OFFSET(pcrvms, 0x4, VECTOR *), STRUCT_OFFSET(pcrvms, 0x8, VECTOR *), &du, &ps); + return ps; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvClosestPointOnLineSegmentFromU__FP3CRVP6VECTORT1fT1T1PfT6); diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 32ec2561..72a6f95a 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -25,7 +25,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/dartgun", PostDartgunLoad__FP7DARTGUN); INCLUDE_ASM("asm/nonmatchings/P2/dartgun", UpdateDartgun__FP7DARTGUNf); -INCLUDE_ASM("asm/nonmatchings/P2/dartgun", FIgnoreDartgunIntersection__FP7DARTGUNP2SO); +int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) +{ + if (FIsBasicDerivedFrom(psoOther, CID_RAT)) + { + if (STRUCT_OFFSET(psoOther, 0x588, SO *) == (SO *)pdartgun) + return 1; + } + + return FIgnoreSoIntersection((SO *)pdartgun, psoOther); +} INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BreakDartgun__FP7DARTGUN); diff --git a/src/P2/dialog.c b/src/P2/dialog.c index 03b31ec8..568d242e 100644 --- a/src/P2/dialog.c +++ b/src/P2/dialog.c @@ -24,7 +24,23 @@ void LoadDialogFromBrx(DIALOG *pdialog, CBinaryInputStream *pbis) INCLUDE_ASM("asm/nonmatchings/P2/dialog", LoadDialogEventsFromBrx__FP6DIALOGP18CBinaryInputStreamPiPP2DE); -INCLUDE_ASM("asm/nonmatchings/P2/dialog", PostDialogLoad__FP6DIALOG); +void PostDialogLoad(DIALOG *pdialog) +{ + extern int *PfLookupDialog(LS *pls, OID oid); + + PostAloLoad(pdialog); + + if (STRUCT_OFFSET(pdialog, 0x30c, OID) == OID_Nil) + { + STRUCT_OFFSET(pdialog, 0x30c, OID) = STRUCT_OFFSET(pdialog, 0x8, OID); + } + + STRUCT_OFFSET(pdialog, 0x304, int *) = PfLookupDialog(g_plsCur, STRUCT_OFFSET(pdialog, 0x30c, OID)); + if (STRUCT_OFFSET(pdialog, 0x304, int *) == NULL) + { + STRUCT_OFFSET(pdialog, 0x304, int *) = &STRUCT_OFFSET(pdialog, 0x308, int); + } +} void SetDialogInstruct(DIALOG *pdialog) { diff --git a/src/P2/eyes.c b/src/P2/eyes.c index daded505..0e46d997 100644 --- a/src/P2/eyes.c +++ b/src/P2/eyes.c @@ -1,6 +1,16 @@ #include +#include -INCLUDE_ASM("asm/nonmatchings/P2/eyes", InitEyes__FP4EYESP4SAAF); +void InitEyes(EYES *peyes, SAAF *psaaf) +{ + InitSaa(peyes, psaaf); + peyes->unk2 = STRUCT_OFFSET(peyes, 0x10, int); + peyes->oid = (OID)*(short *)&psaaf->dframe; + *(float *)&peyes->unk[0] = psaaf->dtLoopMin; + *(float *)&peyes->unk[1] = psaaf->dtLoopMax; + *(float *)&peyes->unk[2] = psaaf->dtPauseMin; + *(float *)&peyes->unk[3] = psaaf->dtPauseMax; +} INCLUDE_ASM("asm/nonmatchings/P2/eyes", PostEyesLoad__FP4EYES); diff --git a/src/P2/rip.c b/src/P2/rip.c index 655a230a..72feb625 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/rip", PripgNew__FP2SW5RIPGT); @@ -151,7 +152,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectSmackTransform__FP5SMACKf); INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderSmack__FP5SMACKP2CM); -INCLUDE_ASM("asm/nonmatchings/P2/rip", UpdateSmack__FP5SMACKf); +void UpdateSmack(SMACK *psmack, float dt) +{ + if (STRUCT_OFFSET(psmack, 0x1c, float) < g_clock.t - STRUCT_OFFSET(psmack, 0x18, float)) + { + RemoveRip(psmack); + (*(void (**)(int))((uint8_t *)STRUCT_OFFSET(psmack, 0x130, void *) + 0x60))(STRUCT_OFFSET(psmack, 0x134, int)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rip", InitOrbit__FP5ORBITP6VECTORfP2SO); diff --git a/src/P2/rog.c b/src/P2/rog.c index e3ff0358..2377b3a0 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -207,7 +207,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRohRohs__FP3ROH4ROHS); INCLUDE_ASM("asm/nonmatchings/P2/rog", FAbsorbRohWkr__FP3ROHP3WKR); -INCLUDE_ASM("asm/nonmatchings/P2/rog", ProcContactRoh__FP3ROH); +ROC *ProcContactRoh(ROH *proh) +{ + void *pv = STRUCT_OFFSET(STRUCT_OFFSET(proh, 0x480, DL *), 0x0, void *); + + while (pv != NULL) + { + if (STRUCT_OFFSET(pv, 0x0, int) != 0) + { + if (FIsBasicDerivedFrom(STRUCT_OFFSET(pv, 0xc, BASIC *), (CID)0x43)) + return STRUCT_OFFSET(pv, 0xc, ROC *); + } + pv = STRUCT_OFFSET(pv, 0x4, void *); + } + + return NULL; +} INCLUDE_ASM("asm/nonmatchings/P2/rog", InitRoc__FP3ROC); @@ -226,7 +241,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRocLoad__FP3ROC); INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRoc__FP3ROCf); -INCLUDE_ASM("asm/nonmatchings/P2/rog", PresetRocAccel__FP3ROCf); +void PresetRocAccel(ROC *proc, float dt) +{ + MATRIX3 mat; + extern SMP D_0026B850; + + PresetSoAccel(proc, dt); + + if (STRUCT_OFFSET(proc, 0x18, int) == 0) + { + TiltMatUpright((MATRIX3 *)((uint8_t *)proc + 0x110), NULL, &mat); + AccelSoTowardMatSmooth(proc, g_clock.dt, &mat, &D_0026B850); + } +} void AdjustRocNewXp(ROC *proc, XP *pxp, int ixpd) { diff --git a/src/P2/screen.c b/src/P2/screen.c index a35ec604..b9bc0ad3 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -18,7 +18,16 @@ void PostBlotsLoad() INCLUDE_ASM("asm/nonmatchings/P2/screen", UpdateBlots__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/screen", ForceHideBlots__Fv); +void ForceHideBlots() +{ + extern BLOT *D_002486B0[]; + + for (int i = 0x24; i >= 0; i--) + { + BLOT *pblot = D_002486B0[i]; + ((void (*)(BLOT *, BLOTS))pblot->pvtblot->pfnSetBlotBlots)(pblot, BLOTS_Hidden); + } +} void ResetBlots(void) { diff --git a/src/P2/splicemap.c b/src/P2/splicemap.c index 9bcad552..3d56da0c 100644 --- a/src/P2/splicemap.c +++ b/src/P2/splicemap.c @@ -1,7 +1,20 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/splicemap", LoadSwSpliceFromBrx__FP2SWP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/splicemap", PframeFromIsplice__FiP2SW); +CFrame *PframeFromIsplice(int isplice, SW *psw) +{ + CFrame *pframe; + + if (isplice == -1) + return NULL; + + pframe = *(CFrame **)((uint8_t *)STRUCT_OFFSET(psw, 0x1EF4, void *) + isplice * 8 + 4); + if (pframe != NULL) + g_gc.AddRootFrame(pframe); + + return pframe; +} INCLUDE_ASM("asm/nonmatchings/P2/splicemap", RefEvalModule__FiP2SW); diff --git a/src/P2/step.c b/src/P2/step.c index 9c883fbb..ed557efa 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/step", InitStep__FP4STEP); @@ -91,7 +92,17 @@ void AddStepCustomXps(STEP *pstep, SO *psoOther, int cbspPruned, BSP *abspPruned INCLUDE_ASM("asm/nonmatchings/P2/step", AddStepCustomXpsBase__FP4STEPP2SOP3BSPPP2XP); -INCLUDE_ASM("asm/nonmatchings/P2/step", FixStepAngularVelocity__FP4STEP); +void FixStepAngularVelocity(STEP *pstep) +{ + qword local; + float radTarget; + + local = STRUCT_OFFSET(pstep, 0x160, qword); + radTarget = atan2f(STRUCT_OFFSET(pstep, 0xd4, float), STRUCT_OFFSET(pstep, 0xd0, float)); + RadSmooth(radTarget, STRUCT_OFFSET(pstep, 0x638, float), 0.0f, + (SMP *)((uint8_t *)pstep + 0x6e0), (float *)((uint8_t *)&local + 8)); + (*(void (**)(STEP *, qword *))((uint8_t *)pstep->pvtlo + 0x94))(pstep, &local); +} INCLUDE_ASM("asm/nonmatchings/P2/step", PredictStepRotation__FP4STEPfP7MATRIX3P6VECTOR); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 104780d9..7dbade39 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -2,6 +2,7 @@ #include #include #include +#include extern SNIP s_asnipStepguardLoad; @@ -280,7 +281,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", MatchStepguardAnimationPhase__FP9ST INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddStepguardCustomXps__FP9STEPGUARDP2SOiP3BSPT3PP2XP); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001caee0); +extern "C" { +void FUN_001caee0(STEPGUARD *pstepguard, SO *pso) +{ + (*(void (**)(SO *, void *))((char *)pso->pvtlo + 0x90))(pso, (char *)pstepguard + 0xAB0); + + if (FIsBasicDerivedFrom(pso, CID_JT)) + { + SetJtJts((JT *)pso, JTS_Sidestep, (JTBS)0x2b); + } +} +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UpdateStepguardEffect__FP9STEPGUARD); From 0da2988cd2b74283ec7fbfd55c00ddb14ae547fd Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 23:41:28 +0200 Subject: [PATCH 070/134] Match 13 medium functions via LHF harness (21-30 window, editable re-draft 3) ac/actseg/chkpnt/gifs/puffer/pzo/rog/screen/smartguard/stepguard: EvaluateAcpb, GGetActsegPoseGoal, LoadVolFromBrx, GIFS packers, loaders, RenderBlots/ShowBlot, SgasGetSmartguard, AddSggGuard. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/ac.c | 16 +++++++++++++++- src/P2/actseg.c | 18 +++++++++++++++++- src/P2/chkpnt.c | 13 ++++++++++++- src/P2/gifs.c | 15 +++++++++++++-- src/P2/puffer.c | 26 ++++++++++++++++++++++++-- src/P2/pzo.c | 9 ++++++++- src/P2/rog.c | 17 ++++++++++++++++- src/P2/screen.c | 33 +++++++++++++++++++++++++++++++-- src/P2/smartguard.c | 25 ++++++++++++++++++++++++- src/P2/stepguard.c | 13 ++++++++++++- 10 files changed, 172 insertions(+), 13 deletions(-) diff --git a/src/P2/ac.c b/src/P2/ac.c index b32b5d76..565c7340 100644 --- a/src/P2/ac.c +++ b/src/P2/ac.c @@ -102,7 +102,21 @@ void GetAcpcTimes(ACPC *pacpc, int *pct, float **pat) GetApacgTimes(&STRUCT_OFFSET(pacpc, 0x20, ACG *), pct, pat); // pacpc->apacg } -INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateAcpb__FP4ACPBP3ALOffiP6VECTORT5); +void EvaluateAcpb(ACPB *pacpb, ALO *palo, float t, float svt, GRFEVAL grfeval, VECTOR *ppos, VECTOR *pv) +{ + // pacpb->ckvb, pacpb->akvb + EvaluateAkvb(STRUCT_OFFSET(pacpb, 0xc, int), STRUCT_OFFSET(pacpb, 0x10, KVB *), t, svt, grfeval, ppos, pv); + + if (palo) + { + void (*pfn)(ALO *, VECTOR *, VECTOR *) = + *(void (**)(ALO *, VECTOR *, VECTOR *))((char *)palo->pvtlo + 0xB0); + if (pfn) + { + pfn(palo, ppos, pv); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAcpbFromBrx__FP4ACPBP18CBinaryInputStream); diff --git a/src/P2/actseg.c b/src/P2/actseg.c index b15e0e0b..7b3427d9 100644 --- a/src/P2/actseg.c +++ b/src/P2/actseg.c @@ -33,4 +33,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/actseg", GetActsegTwistGoal__FP6ACTSEGPfT1); INCLUDE_ASM("asm/nonmatchings/P2/actseg", GetActsegScale__FP6ACTSEGP7MATRIX3); -INCLUDE_ASM("asm/nonmatchings/P2/actseg", GGetActsegPoseGoal__FP6ACTSEGi); +float GGetActsegPoseGoal(ACTSEG *pactseg, int ipose) +{ + float gGoal; + ASEGA *pasega = pactseg->pasega; + int iapose = STRUCT_OFFSET(pactseg, 0x28, int); + void *p8 = STRUCT_OFFSET(pasega, 0x8, void *); + uint8_t *pbase = STRUCT_OFFSET(p8, 0x3C, uint8_t *) + iapose * 0x1C; + void **parr = STRUCT_OFFSET(pbase, 0x18, void **); + void *papx = parr[ipose]; + + (*(void (**)(void *, ALO *, int, float *, int, float, float))(*(void ***)papx))( + papx, pactseg->palo, 0, &gGoal, 0, + STRUCT_OFFSET(pasega, 0x14, float), + STRUCT_OFFSET(pasega, 0x18, float)); + + return gGoal; +} diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index bacd6199..eb37f806 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ResetChkmgrCheckpoints__FP6CHKMGR); #ifdef SKIP_ASM @@ -50,7 +51,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", SetChkmgrIchk__FP6CHKMGRi); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ClearChkmgrIchk__FP6CHKMGRi); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", LoadVolFromBrx__FP3VOLP18CBinaryInputStream); +void LoadVolFromBrx(VOL *pvol, CBinaryInputStream *pbis) +{ + pbis->ReadMatrix((MATRIX3 *)((uint8_t *)pvol + 0x50)); + pbis->ReadVector((VECTOR *)((uint8_t *)pvol + 0x40)); + LoadTbspFromBrx(pbis, + &STRUCT_OFFSET(pvol, 0x80, int), + &STRUCT_OFFSET(pvol, 0x84, TSURF *), + &STRUCT_OFFSET(pvol, 0x88, int), + &STRUCT_OFFSET(pvol, 0x8c, TBSP *)); + LoadOptionsFromBrx(pvol, pbis); +} extern int ConvertXfmLocalToWorld(XFM *pxfm, VECTOR *pposWorld, VECTOR *pposLocal); diff --git a/src/P2/gifs.c b/src/P2/gifs.c index ce6b8003..8115be35 100644 --- a/src/P2/gifs.c +++ b/src/P2/gifs.c @@ -45,7 +45,14 @@ void GIFS::PackUV(int u, int v) pqw->an[1] = v; } -INCLUDE_ASM("asm/nonmatchings/P2/gifs", PackSTQ__4GIFSfff); +void GIFS::PackSTQ(float s, float t, float q) +{ + CheckReg(1, 2); + QW *pqw = ((QW *)m_pb)++; + pqw->ag[0] = s; + pqw->ag[1] = t; + pqw->ag[2] = q; +} void GIFS::PackXYZ(int x, int y, int z) { @@ -84,7 +91,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/gifs", ListRGBAQ__4GIFSUif); JUNK_ADDIU(30); -INCLUDE_ASM("asm/nonmatchings/P2/gifs", ListUV__4GIFSii); +void GIFS::ListUV(int u, int v) +{ + CheckReg(0, 3); + *((long *)m_pb)++ = u | (v << 16); +} INCLUDE_ASM("asm/nonmatchings/P2/gifs", ListXYZF__4GIFSiiii); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 9d390ba2..fcf82bd0 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -1,5 +1,7 @@ #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/puffer", InitPuffer__FP6PUFFER); @@ -36,7 +38,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197788); INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197848); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197a08); +extern "C" void FUN_00197a08(void *pv1, void *pv2) +{ + ROST *prost = STRUCT_OFFSET(pv2, 0xC14, ROST *); + SetRostRosts(prost, ROSTS_Close); + RemoveDlEntry((DL *)((char *)pv1 + 0x6A8), prost); + AppendDlEntry((DL *)((char *)pv1 + 0x69C), prost); + STRUCT_OFFSET(pv2, 0xC14, ROST *) = 0; +} extern float D_0026A83C; extern float D_0026A840; @@ -90,4 +99,17 @@ int FCanPuffcAttack(PUFFC *ppuffc) INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00198860); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", PostPuffbLoad__FP5PUFFB); +extern SNIP D_0026A8E0; + +void PostPuffbLoad(PUFFB *ppuffb) +{ + LO *plo; + + SnipAloObjects(ppuffb, 3, &D_0026A8E0); + PostAloLoad(ppuffb); + plo = PloFindSwObjectByClass(ppuffb->psw, FSO_FindAll, CID_TURRET, NULL); + if (plo != NULL) + { + STRUCT_OFFSET(plo, 0x684, int)++; + } +} diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 9f997036..128d02c8 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -240,7 +240,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", FUN_0019a0f0); INCLUDE_ASM("asm/nonmatchings/P2/pzo", InitVault__FP5VAULT); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", PostTmblLoad__FP4TMBL3OID); +void PostTmblLoad(TMBL *ptmbl, OID oidInitialState) +{ + LO *plo = PloFindSwObject(g_psw, 0x101, (OID)0x37A, ptmbl->palo); + ptmbl->psmDial = (SM *)plo; + SnipLo(plo); + + ptmbl->psmaDial = PsmaApplySm((SM *)ptmbl->psmDial, ptmbl->palo, oidInitialState, 0); +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", PostVaultLoad__FP5VAULT); diff --git a/src/P2/rog.c b/src/P2/rog.c index 2377b3a0..db64cfe0 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -3,6 +3,7 @@ #include #include #include +#include extern SNIP s_asnipLoadRov[2]; @@ -318,7 +319,21 @@ void LoadRopFromBrx(ROP *prop, CBinaryInputStream *pbis) InferExpl(&STRUCT_OFFSET(prop, 0x568, EXPL *), prop); } -INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRopLoad__FP3ROP); +void PostRopLoad(ROP *prop) +{ + PostAloLoad(prop); + + if (STRUCT_OFFSET(prop, 0x558, int) == 0) + { + prop->pvtlo->pfnRemoveLo(prop); + } + else + { + STRUCT_OFFSET(prop, 0x55C, LO *) = + PloFindSwObjectByClass(prop->psw, 0x101, (CID)0x59, STRUCT_OFFSET(prop, 0x34, LO *)); + SetRopRops(prop, ROPS_StayPut); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRop__FP3ROPf); diff --git a/src/P2/screen.c b/src/P2/screen.c index b9bc0ad3..3036f5dc 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -40,7 +40,24 @@ void ResetBlots(void) } } -INCLUDE_ASM("asm/nonmatchings/P2/screen", RenderBlots__Fv); +void RenderBlots() +{ + extern BLOT *D_002486B0[]; + + BLOT **ppblot = D_002486B0; + + for (int i = 0x24; i >= 0; i--) + { + BLOT *pblot = *ppblot; + ppblot++; + + if (pblot->blots != BLOTS_Hidden) + { + if (((VTBLOT *)pblot->pvtblot)->pfnRenderBlot != NULL) + ((VTBLOT *)pblot->pvtblot)->pfnRenderBlot(pblot); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawBlots__Fv); @@ -104,7 +121,19 @@ void OnBlotReset(BLOT *pblot) ((void (*)(BLOT *, BLOTS))pblot->pvtblot->pfnSetBlotBlots)(pblot, BLOTS_Hidden); } -INCLUDE_ASM("asm/nonmatchings/P2/screen", ShowBlot__FP4BLOT); +void ShowBlot(BLOT *pblot) +{ + switch (pblot->blots) + { + case BLOTS_Hidden: + case BLOTS_Disappearing: + ((void (*)(BLOT *, BLOTS))pblot->pvtblot->pfnSetBlotBlots)(pblot, BLOTS_Appearing); + break; + case BLOTS_Visible: + pblot->tBlots = *pblot->ptNow; + break; + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", HideBlot__FP4BLOT); diff --git a/src/P2/smartguard.c b/src/P2/smartguard.c index 30e23be2..161b8f17 100644 --- a/src/P2/smartguard.c +++ b/src/P2/smartguard.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/smartguard", InitSmartguard__FP10SMARTGUARD); @@ -52,7 +53,29 @@ int FCanSmartguardAttack(SMARTGUARD *psmartguard) return fn(psmartguard); } -INCLUDE_ASM("asm/nonmatchings/P2/smartguard", SgasGetSmartguard__FP10SMARTGUARD); +SGAS SgasGetSmartguard(SMARTGUARD *psmartguard) +{ + SGS sgs = STRUCT_OFFSET(psmartguard, 0x724, SGS); + + if (sgs == SGS_Dying) + { + return SGAS_Yes; + } + + if (sgs == SGS_SearchIdle) + { + if (STRUCT_OFFSET(psmartguard, 0xCC4, int) > 0) + { + if (5.0f < g_clock.t - STRUCT_OFFSET(psmartguard, 0x728, float)) + { + return SGAS_Force; + } + return SGAS_Yes; + } + } + + return SGAS_No; +} void HandleSmartguardMessage(SMARTGUARD *psmartguard, MSGID msgid, void *pv) { diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 7dbade39..afc4c794 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -319,7 +319,18 @@ void InitSgg(SGG *psgg) STRUCT_OFFSET(psgg, 0x180, OID) = OID_Nil; // psgg->oidSync } -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddSggGuard__FP3SGGP9STEPGUARD); +void AddSggGuard(SGG *psgg, STEPGUARD *pstepguard) +{ + if (STRUCT_OFFSET(psgg, 0x58, int) == 0) + SetSggSggs(psgg, (SGGS)0); + + int c = STRUCT_OFFSET(psgg, 0x58, int); + if ((unsigned int)c < 0x10) + { + STRUCT_OFFSET_INDEX(psgg, 0x5c, STEPGUARD *, c) = pstepguard; + STRUCT_OFFSET(psgg, 0x58, int) = c + 1; + } +} void AddSggGuardName(SGG * p, OID oid) { From e2506dbf4fa069a20716165adfb5df8f0eb8a0c6 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 23:55:58 +0200 Subject: [PATCH 071/134] Match 19 medium functions via LHF harness (21-30 window, editable re-draft 4) alarm/binoc/break/crv/emitter/gs/hide/mb/missile/puffer/shd/stepguard/ stephide/steprail: vtable-loop dispatch, message handlers, loaders, list-walks, accel/spring, binary helpers. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/alarm.c | 30 ++++++++++++++++++++++++++++-- src/P2/binoc.c | 16 +++++++++++++++- src/P2/break.c | 22 +++++++++++++++++++++- src/P2/crv.c | 25 +++++++++++++++++++++++-- src/P2/emitter.c | 34 ++++++++++++++++++++++++++++++++-- src/P2/gs.c | 12 +++++++++++- src/P2/hide.c | 33 +++++++++++++++++++++++++++++++-- src/P2/mb.c | 20 +++++++++++++++++++- src/P2/missile.c | 12 +++++++++++- src/P2/puffer.c | 11 ++++++++++- src/P2/shd.c | 31 ++++++++++++++++++++++++++++++- src/P2/stepguard.c | 32 ++++++++++++++++++++++++++++++-- src/P2/stephide.c | 18 +++++++++++++++++- src/P2/steprail.c | 20 +++++++++++++++++++- 14 files changed, 297 insertions(+), 19 deletions(-) diff --git a/src/P2/alarm.c b/src/P2/alarm.c index b5c25dda..2e0a1422 100644 --- a/src/P2/alarm.c +++ b/src/P2/alarm.c @@ -68,9 +68,35 @@ void DisableAlarmAlbrk(ALARM *palarm) INCLUDE_ASM("asm/nonmatchings/P2/alarm", EnableAlarmSensors__FP5ALARM); -INCLUDE_ASM("asm/nonmatchings/P2/alarm", DisableAlarmSensors__FP5ALARM); +void DisableAlarmSensors(ALARM *palarm) +{ + int ipsensor; + + for (ipsensor = 0; ipsensor < STRUCT_OFFSET(palarm, 0x5bc, int); ipsensor++) // palarm->cpsensors + { + SENSOR *psensor = STRUCT_OFFSET_INDEX(palarm, 0x5c0, SENSOR *, ipsensor); // palarm->apsensors[ipsensor] + void **ppvtable = (void **)STRUCT_OFFSET(psensor, 0x0, void *); + void (*pfn)(SENSOR *) = (void (*)(SENSOR *))STRUCT_OFFSET(ppvtable, 0x138, void *); + + if (pfn != NULL) + pfn(psensor); + } +} -INCLUDE_ASM("asm/nonmatchings/P2/alarm", NotifyAlarmSensorsOnTrigger__FP5ALARM); +void NotifyAlarmSensorsOnTrigger(ALARM *palarm) +{ + int ipsensor; + + for (ipsensor = 0; ipsensor < STRUCT_OFFSET(palarm, 0x5bc, int); ipsensor++) // palarm->cpsensors + { + SENSOR *psensor = STRUCT_OFFSET_INDEX(palarm, 0x5c0, SENSOR *, ipsensor); // palarm->apsensors[ipsensor] + void **ppvtable = (void **)STRUCT_OFFSET(psensor, 0x0, void *); + void (*pfn)(SENSOR *) = (void (*)(SENSOR *))STRUCT_OFFSET(ppvtable, 0x13c, void *); + + if (pfn != NULL) + pfn(psensor); + } +} void AddAlarmAlbrk(ALARM *palarm, OID oid) { diff --git a/src/P2/binoc.c b/src/P2/binoc.c index 4060c213..bd0e3093 100644 --- a/src/P2/binoc.c +++ b/src/P2/binoc.c @@ -108,7 +108,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00135550); INCLUDE_ASM("asm/nonmatchings/P2/binoc", open_close_binoc); -INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_001357f0); +extern "C" { +int FUN_001357f0(void *a, void *b) +{ + if (!FIsLoInWorld(STRUCT_OFFSET(a, 0x0, LO *))) + return 1; + + if (!FIsLoInWorld(STRUCT_OFFSET(b, 0x0, LO *))) + return -1; + + if (STRUCT_OFFSET(a, 0x4, float) < STRUCT_OFFSET(b, 0x4, float)) + return -1; + + return 1; +} +} INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00135858); diff --git a/src/P2/break.c b/src/P2/break.c index c6fa001a..45dfa177 100644 --- a/src/P2/break.c +++ b/src/P2/break.c @@ -2,10 +2,30 @@ #include #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/break", InitBrk__FP3BRK); -INCLUDE_ASM("asm/nonmatchings/P2/break", LoadBrkFromBrx__FP3BRKP18CBinaryInputStream); +void LoadBrkFromBrx(BRK *pbrk, CBinaryInputStream *pbis) +{ + LoadSoFromBrx(pbrk, pbis); + + if (STRUCT_OFFSET(pbrk, 0x614, OID) == (OID)-1) + { + InferExpl((EXPL **)((uint8_t *)pbrk + 0x618), (ALO *)pbrk); + } + else + { + LO *plo = PloFindSwObject(pbrk->psw, 0x101, STRUCT_OFFSET(pbrk, 0x614, OID), (LO *)pbrk); + STRUCT_OFFSET(pbrk, 0x618, LO *) = plo; + + if (plo != NULL) + { + SnipLo(plo); + } + } +} void CloneBrk(BRK *pbrk, BRK *pbrkBase) { diff --git a/src/P2/crv.c b/src/P2/crv.c index 6a4a760d..8320359f 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -133,7 +133,19 @@ void ConvertCrvl(CRVL *pcrvl, MATRIX4 *pmatSrc, MATRIX4 *pmatDst) ConvertApos(STRUCT_OFFSET(pcrvl, 0xC, int), STRUCT_OFFSET(pcrvl, 0x18, VECTOR *), pmatSrc, pmatDst); } -INCLUDE_ASM("asm/nonmatchings/P2/crv", SFromCrvlU__FP4CRVLf); +float SFromCrvlU(CRVL *pcrvl, float u) +{ + float du; + float duSeg; + int icv; + float frac; + float *mpicvs; + + icv = IcvFindCrvU((CRV *)pcrvl, u, &du, &duSeg); + frac = du / duSeg; + mpicvs = ((CRV *)pcrvl)->mpicvs; + return (1.0f - frac) * mpicvs[icv] + frac * mpicvs[icv + 1]; +} float UFromCrvlS(CRVL *pcrvl, float s) { @@ -173,7 +185,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FillCrvcCache__FP4CRVCi); INCLUDE_ASM("asm/nonmatchings/P2/crv", EvaluateCrvcFromU__FP4CRVCfP6VECTORT2); -INCLUDE_ASM("asm/nonmatchings/P2/crv", EvaluateCrvcFromS__FP4CRVCfP6VECTORT2); +void EvaluateCrvcFromS(CRVC *pcrvc, float s, VECTOR *ppos, VECTOR *pnormTangent) +{ + float u; + + u = ((float (*)(CRVC *, float))STRUCT_OFFSET(*(void **)pcrvc, 0x18, void *))(pcrvc, s); + if (STRUCT_OFFSET(*(void **)pcrvc, 0x4, void *)) + { + ((void (*)(CRVC *, float, VECTOR *, VECTOR *))STRUCT_OFFSET(*(void **)pcrvc, 0x4, void *))(pcrvc, u, ppos, pnormTangent); + } +} INCLUDE_ASM("asm/nonmatchings/P2/crv", RenderCrvcSegment__FP4CRVCiP7MATRIX4P2CMG4RGBAi); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 90444291..bcbb66e7 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -24,7 +24,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindEmitter__FP7EMITTER); INCLUDE_ASM("asm/nonmatchings/P2/emitter", PostEmitterLoad__FP7EMITTER); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", HandleEmitterMessage__FP7EMITTER5MSGIDPv); +void HandleEmitterMessage(EMITTER *pemitter, MSGID msgid, void *pv) +{ + if (msgid == MSGID_removed) + { + if (pv == STRUCT_OFFSET(pemitter, 0x344, void *)) + { + (*(void (**)(void *, EMITTER *))((char *)*(void **)pv + 0x70))(pv, pemitter); + STRUCT_OFFSET(pemitter, 0x344, void *) = 0; + } + else if (pv == STRUCT_OFFSET(pemitter, 0x348, void *)) + { + (*(void (**)(void *, EMITTER *))((char *)*(void **)pv + 0x70))(pv, pemitter); + STRUCT_OFFSET(pemitter, 0x348, void *) = 0; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", PemitbCopyOnWrite__FP5EMITB); @@ -248,7 +263,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", InitExpls__FP5EXPLS); INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindExpls__FP5EXPLS); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", HandleExplsMessage__FP5EXPLS5MSGIDPv); +void HandleExplsMessage(EXPLS *pexpls, MSGID msgid, void *pv) +{ + if (msgid == MSGID_removed) + { + if (pv == STRUCT_OFFSET(pexpls, 0xc0, void *)) + { + (*(void (**)(void *, EXPLS *))((char *)*(void **)pv + 0x70))(pv, pexpls); + STRUCT_OFFSET(pexpls, 0xc0, void *) = 0; + } + else if (pv == STRUCT_OFFSET(pexpls, 0xc4, void *)) + { + (*(void (**)(void *, EXPLS *))((char *)*(void **)pv + 0x70))(pv, pexpls); + STRUCT_OFFSET(pexpls, 0xc4, void *) = 0; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", ExplodeExplsExplso__FP5EXPLSP6EXPLSO); diff --git a/src/P2/gs.c b/src/P2/gs.c index f58f424a..8586ae6b 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -118,7 +118,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", ReferenceUVAnimation__FP2QWiP3SAI); INCLUDE_ASM("asm/nonmatchings/P2/gs", RebaseSurs__FiiPvT2); -INCLUDE_ASM("asm/nonmatchings/P2/gs", PropagateSurs__Fv); +extern SUR D_0027DC20[]; + +void PropagateSurs() +{ + int isur; + + for (isur = 0; isur < D_002626D0; isur++) + { + PropagateSur(&D_0027DC20[isur]); + } +} INCLUDE_ASM("asm/nonmatchings/P2/gs", PqwVifsBitmapUpload__Fi); diff --git a/src/P2/hide.c b/src/P2/hide.c index eab21d4f..c53f9889 100644 --- a/src/P2/hide.c +++ b/src/P2/hide.c @@ -1,6 +1,7 @@ #include #include #include +#include extern DL g_dlHshape; extern DL g_dlHpnt; @@ -57,7 +58,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/hide", FUN_0016a320); INCLUDE_ASM("asm/nonmatchings/P2/hide", InitHbsk__FP4HBSK); -INCLUDE_ASM("asm/nonmatchings/P2/hide", LoadHbskFromBrx__FP4HBSKP18CBinaryInputStream); +extern qword D_002483D0[3]; + +void LoadHbskFromBrx(HBSK *phbsk, CBinaryInputStream *pbis) +{ + LoadSoFromBrx((SO *)phbsk, pbis); + if (STRUCT_OFFSET(phbsk, 0x224, void *) == 0) + STRUCT_OFFSET(phbsk, 0x224, void *) = PvAllocSwClearImpl(0xC0); + STRUCT_OFFSET(STRUCT_OFFSET(phbsk, 0x224, void *), 0xB0, int) |= 1; + { + void *pv = STRUCT_OFFSET(phbsk, 0x224, void *); + STRUCT_OFFSET(pv, 0x0, qword) = D_002483D0[0]; + STRUCT_OFFSET(pv, 0x10, qword) = D_002483D0[1]; + STRUCT_OFFSET(pv, 0x20, qword) = D_002483D0[2]; + } +} void OnHbskAdd(HBSK *phbsk) { @@ -75,7 +90,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/hide", CloneHbsk__FP4HBSKT0); INCLUDE_ASM("asm/nonmatchings/P2/hide", FIgnoreHbskIntersection__FP4HBSKP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/hide", PresetHbskAccel__FP4HBSKf); +extern VECTOR D_00248D30; + +void PresetHbskAccel(HBSK *phbsk, float dt) +{ + MATRIX3 matUpright; + + PresetSoAccel((SO *)phbsk, dt); + if (STRUCT_OFFSET(phbsk, 0x550, int) == 0) + { + TiltMatUpright((MATRIX3 *)((uint8_t *)phbsk + 0xD0), 0, &matUpright); + AccelSoTowardMatSpring((SO *)phbsk, &matUpright, + STRUCT_OFFSET(phbsk, 0x214, CLQ *), &D_00248D30, + STRUCT_OFFSET(phbsk, 0x218, CLQ *), dt); + } +} INCLUDE_ASM("asm/nonmatchings/P2/hide", SetHbskHbsks__FP4HBSK5HBSKS); diff --git a/src/P2/mb.c b/src/P2/mb.c index d79b3944..a1e66f54 100644 --- a/src/P2/mb.c +++ b/src/P2/mb.c @@ -33,7 +33,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/mb", FDetectMbg__FP3MBG); INCLUDE_ASM("asm/nonmatchings/P2/mb", FUN_0018ab88__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/mb", FUN_0018abf0__Fi); +SGS FUN_0018abf0(int param) +{ + STEPGUARD *pstepguard = (STEPGUARD *)param; + OID oid; + + if (STRUCT_OFFSET(pstepguard, 0x724, int) == 4) + { + GetSmaCur((SMA *)STRUCT_OFFSET(pstepguard, 0xE10, int), &oid); + if (oid == (OID)0x438) + { + if (SggsGetStepguard(pstepguard) == 0) + { + return (SGS)2; + } + } + } + + return SgsNextStepguardAI(pstepguard); +} INCLUDE_ASM("asm/nonmatchings/P2/mb", FUN_0018ac58__Fi); diff --git a/src/P2/missile.c b/src/P2/missile.c index 36c8d1b1..38b04b4a 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -7,7 +7,17 @@ void InitMissile(MISSILE *pmissile) STRUCT_OFFSET(pmissile, 0x6b8, int) = 1; // pmissile->fFollowTrajectory } -INCLUDE_ASM("asm/nonmatchings/P2/missile", LoadMissileFromBrx__FP7MISSILEP18CBinaryInputStream); +extern SNIP s_asnipMissile; + +void LoadMissileFromBrx(MISSILE *pmissile, CBinaryInputStream *pbis) +{ + uint64_t grfalo; + + LoadBombFromBrx(pmissile, pbis); + SnipAloObjects(pmissile, 1, &s_asnipMissile); + grfalo = STRUCT_OFFSET(pmissile, 0x2c8, uint64_t); + STRUCT_OFFSET(pmissile, 0x2c8, uint64_t) = (grfalo & ~0x30000000000ULL) | (0x8000ULL << 0x19); +} void OnMissileRemove(MISSILE *pmissile) { diff --git a/src/P2/puffer.c b/src/P2/puffer.c index fcf82bd0..0c5db656 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -17,7 +17,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", PostPufferLoad__FP6PUFFER); INCLUDE_ASM("asm/nonmatchings/P2/puffer", PresetPufferAccel__FP6PUFFERf); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", FFilterPuffer__FP6PUFFERP2SO); +int FFilterPuffer(PUFFER *ppuffer, SO *pso) +{ + if ((STRUCT_OFFSET(pso, 0x538, unsigned long long) & ((unsigned long long)0x8000 << 28)) != 0) + { + if (!FIsBasicDerivedFrom(pso, (CID)0x1F)) + return 0; + } + + return STRUCT_OFFSET(pso, 0x50, SO *) != ppuffer; +} INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffer__FP6PUFFERf); diff --git a/src/P2/shd.c b/src/P2/shd.c index 0220c56e..3bd7b29b 100644 --- a/src/P2/shd.c +++ b/src/P2/shd.c @@ -65,7 +65,36 @@ INCLUDE_ASM("asm/nonmatchings/P2/shd", PshdFindShader__F3OID); INCLUDE_ASM("asm/nonmatchings/P2/shd", SetSaiIframe__FP3SAIi); -INCLUDE_ASM("asm/nonmatchings/P2/shd", SetSaiDuDv__FP3SAIff); +extern SAI *g_psaiUpdate; +extern SAI *g_psaiUpdateTail; + +void SetSaiDuDv(SAI *psai, float du, float dv) +{ + SAI *psaiNext; + + if (!STRUCT_OFFSET(psai, 0x4, int)) + return; + + if (STRUCT_OFFSET(psai, 0xc, float) == du && + STRUCT_OFFSET(psai, 0x10, float) == dv) + return; + + psaiNext = STRUCT_OFFSET(psai, 0x18, SAI *); + STRUCT_OFFSET(psai, 0xc, float) = du; + STRUCT_OFFSET(psai, 0x10, float) = dv; + + if (psaiNext != 0) + return; + + if (psai == g_psaiUpdateTail) + return; + + if (g_psaiUpdateTail == 0) + g_psaiUpdateTail = psai; + + STRUCT_OFFSET(psai, 0x18, SAI *) = g_psaiUpdate; + g_psaiUpdate = psai; +} INCLUDE_ASM("asm/nonmatchings/P2/shd", PropagateSais__Fv); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index afc4c794..86243193 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -3,6 +3,7 @@ #include #include #include +#include extern SNIP s_asnipStepguardLoad; @@ -210,7 +211,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", FUN_001ca6d0); INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UseStepguardDeathAnimation__FP9STEPGUARDi3OID); -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PasegFindStepguard__FP9STEPGUARD3OID); +ASEG *PasegFindStepguard(STEPGUARD *pstepguard, OID oidAseg) +{ + ASEG *paseg = (ASEG *)PloFindSwObject(pstepguard->psw, 0x101, oidAseg, STRUCT_OFFSET(pstepguard, 0xb74, LO *)); + + if (paseg != NULL) + { + STRUCT_OFFSET(paseg, 0x48, int) = 0; + StripAsegAlo(paseg, (ALO *)pstepguard); + SnipLo(paseg); + } + + return paseg; +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", LoadStepguardAnimations__FP9STEPGUARD); @@ -370,7 +383,22 @@ SO *PsoEnemySgg(SGG *psgg) return fn(pso); } -INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UpdateSggCallback__FP3SGG5MSGIDPv); +void UpdateSggCallback(SGG *psgg, MSGID msgid, void *pv) +{ + SGGS sggs; + + STRUCT_OFFSET(psgg, 0x17c, int) = 0; + + if (STRUCT_OFFSET(psgg, 0x50, SGGS) != SGGS_Dead) + { + STRUCT_OFFSET(psgg, 0x188, int) = FDetectSgg(psgg); + + while ((sggs = SggsNextSgg(psgg)) != STRUCT_OFFSET(psgg, 0x50, SGGS)) + { + SetSggSggs(psgg, sggs); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SggsNextSgg__FP3SGG); diff --git a/src/P2/stephide.c b/src/P2/stephide.c index 51ab63f6..ca2df40f 100644 --- a/src/P2/stephide.c +++ b/src/P2/stephide.c @@ -6,7 +6,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/stephide", MeasureJtJumpToTarget__FP2JTP6VECTOR INCLUDE_ASM("asm/nonmatchings/P2/stephide", GetJtRailLanding__FP2JTP4RAILfP6VECTORT3); -INCLUDE_ASM("asm/nonmatchings/P2/stephide", GMeasureJumpRail__FP3MJRf); +float GMeasureJumpRail(MJR *pmjr, float u) +{ + VECTOR posLanding; + VECTOR vLanding; + float gInteg; + + GetJtRailLanding(STRUCT_OFFSET(pmjr, 0x0, JT *), + STRUCT_OFFSET(pmjr, 0x4, RAIL *), + u, &posLanding, &vLanding); + + MeasureJtJumpToTarget(STRUCT_OFFSET(pmjr, 0x0, JT *), + (VECTOR *)((uint8_t *)pmjr + 0x10), + STRUCT_OFFSET(STRUCT_OFFSET(pmjr, 0x4, RAIL *), 0x18, ALO *), + &posLanding, &vLanding, 0, &gInteg, 0, 0); + + return gInteg; +} INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001cea58); diff --git a/src/P2/steprail.c b/src/P2/steprail.c index f4fdf476..0769ef19 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -19,7 +19,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D32D8__FiP2JTl); INCLUDE_ASM("asm/nonmatchings/P2/steprail", update_steprail); -INCLUDE_ASM("asm/nonmatchings/P2/steprail", preset_steprail_accel); +extern "C" void preset_steprail_accel(SO *pso, float dt) +{ + MATRIX3 mat; + extern VECTOR D_00248D30; + + PresetSoAccel(pso, dt); + + if (STRUCT_OFFSET(pso, 0x18, int) == 0) // pso->paloParent + { + TiltMatUpright((MATRIX3 *)((uint8_t *)pso + 0xD0), NULL, &mat); + AccelSoTowardMatSpring( + pso, + &mat, + STRUCT_OFFSET(pso, 0x214, CLQ *), + &D_00248D30, + STRUCT_OFFSET(pso, 0x218, CLQ *), + dt); + } +} void FUN_001d34e0(uint8_t *param_1) { From 6cc2cd7639ae3e02aaaf84d37d27d0e65dde1e26 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 00:10:14 +0200 Subject: [PATCH 072/134] Match 11 medium functions via LHF harness (21-30 window, editable re-draft 5) ac/gs/jt/lgn/mat/rog/speaker/suv/tank/turret: evaluator, factory, frame-buffer clear, prize collectors, loader, matrix decompose, list-next, SM-idle setter, init, fire. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/ac.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- src/P2/gs.c | 14 +++++++++++++- src/P2/jt.c | 16 +++++++++++++++- src/P2/lgn.c | 18 +++++++++++++++++- src/P2/mat.c | 9 ++++++++- src/P2/rog.c | 27 ++++++++++++++++++++++++++- src/P2/speaker.c | 23 ++++++++++++++++++++++- src/P2/suv.c | 19 ++++++++++++++++++- src/P2/tank.c | 19 ++++++++++++++++++- src/P2/turret.c | 20 +++++++++++++++++++- 10 files changed, 200 insertions(+), 11 deletions(-) diff --git a/src/P2/ac.c b/src/P2/ac.c index 565c7340..6630efae 100644 --- a/src/P2/ac.c +++ b/src/P2/ac.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/ac", FindKey__FfiiiPcPfT5PPv); @@ -93,7 +94,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAkvbFromBrx__FPiPP3KVBP18CBinaryInputS INCLUDE_ASM("asm/nonmatchings/P2/ac", GetAkvbTimes__FiP3KVBPiPPf); -INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateAcpc__FP4ACPCP3ALOffiP6VECTORT5); +void EvaluateAcpc(ACPC *pacpc, ALO *palo, float t, float svt, GRFEVAL grfeval, VECTOR *ppos, VECTOR *pv) +{ + EvaluateApacg(&STRUCT_OFFSET(pacpc, 0x20, ACG *), palo, t, svt, grfeval, &STRUCT_OFFSET(pacpc, 0x10, VECTOR), ppos, pv); + + if (palo) + { + void (*pfn)(ALO *, VECTOR *, VECTOR *) = + *(void (**)(ALO *, VECTOR *, VECTOR *))((char *)palo->pvtlo + 0xB0); + if (pfn) + { + pfn(palo, ppos, pv); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAcpcFromBrx__FP4ACPCP18CBinaryInputStream); @@ -198,6 +212,34 @@ INCLUDE_ASM("asm/nonmatchings/P2/ac", PacpNew__F4ACVK); INCLUDE_ASM("asm/nonmatchings/P2/ac", PacrNew__F4ACVK); -INCLUDE_ASM("asm/nonmatchings/P2/ac", PacsNew__F4ACVK); +extern void *D_00219718; +extern void *D_00219728; + +ACS *PacsNew(ACVK acvk) +{ + void *pacs; + + switch (acvk) + { + case ACVK_Component: + pacs = PvAllocSwClearImpl(0x30); + STRUCT_OFFSET(pacs, 0x0, void *) = &D_00219718; + break; + case ACVK_Bezier: + pacs = PvAllocSwClearImpl(0x10); + STRUCT_OFFSET(pacs, 0x0, void *) = &D_00219728; + break; + default: + pacs = NULL; + break; + } + + if (pacs) + { + STRUCT_OFFSET(pacs, 0x4, ACVK) = acvk; + } + + return (ACS *)pacs; +} INCLUDE_ASM("asm/nonmatchings/P2/ac", PacgNew__F4ACGK); diff --git a/src/P2/gs.c b/src/P2/gs.c index 8586ae6b..3168aa6d 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -31,7 +31,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", StartupGs__Fv); INCLUDE_ASM("asm/nonmatchings/P2/gs", BlastAqwGifsBothFrames__FP2QW); -INCLUDE_ASM("asm/nonmatchings/P2/gs", ClearFrameBuffers__Fv); +extern QW D_002BE1A0[]; + +void ClearFrameBuffers() +{ + DMAS dmas; + QW aqw[2]; + + dmas.AllocStatic(2, aqw); + dmas.AddDmaRefs(0x2C, D_002BE1A0); + dmas.AddDmaEnd(); + dmas.Detach(NULL, NULL); + BlastAqwGifsBothFrames(aqw); +} INCLUDE_ASM("asm/nonmatchings/P2/gs", FadeFramesToBlack__Ff); diff --git a/src/P2/jt.c b/src/P2/jt.c index 7a2bd9ac..0aa48e36 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -127,7 +127,21 @@ int FIsJtSoundBase(JT *pjt) return !FActiveCplcy(&STRUCT_OFFSET(g_pcm, 0x454, CPLCY)); } -INCLUDE_ASM("asm/nonmatchings/P2/jt", CollectJtPrize__FP2JT3PCKP3ALO); +void CollectJtPrize(JT *pjt, PCK pck, ALO *paloOther) +{ + CollectPoPrize(pjt, pck, paloOther); + + switch (pck) + { + case PCK_Key: + SetJtJts(pjt, JTS_Rush, JTBS_Rush_Attack); + break; + + case PCK_Gold: + SetJtJts(pjt, JTS_Rush, JTBS_Rush_Bounce); + break; + } +} INCLUDE_ASM("asm/nonmatchings/P2/jt", GetJtDiapi__FP2JTP6DIALOGP5DIAPI); diff --git a/src/P2/lgn.c b/src/P2/lgn.c index b7388f77..f04d5466 100644 --- a/src/P2/lgn.c +++ b/src/P2/lgn.c @@ -1,5 +1,7 @@ #include #include +#include +#include void InitLgn(LGN *plgn) { @@ -55,7 +57,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/lgn", DrawLgnr__FP4LGNR); INCLUDE_ASM("asm/nonmatchings/P2/lgn", InitSwp__FP3SWP); -INCLUDE_ASM("asm/nonmatchings/P2/lgn", PostSwpLoad__FP3SWP); +extern SNIP D_00264230; + +void PostSwpLoad(SWP *pswp) +{ + ACG *pacg; + + PostBrkLoad((BRK *)pswp); + SnipAloObjects((ALO *)pswp, 2, &D_00264230); + STRUCT_OFFSET(pswp, 0x6c8, SMA *) = + PsmaApplySm(STRUCT_OFFSET(pswp, 0x6c4, SM *), (ALO *)pswp, (OID)0x36e, 0); + pacg = PacgNew((ACGK)0); + STRUCT_OFFSET(pswp, 0x6e8, ACG *) = pacg; + STRUCT_OFFSET(pacg, 0x8, int) = 0; + STRUCT_OFFSET(STRUCT_OFFSET(pswp, 0x6e8, ACG *), 0xc, void *) = PvAllocSwImpl(0xc00); +} INCLUDE_ASM("asm/nonmatchings/P2/lgn", UpdateSwp__FP3SWPf); diff --git a/src/P2/mat.c b/src/P2/mat.c index 79843f0d..6269cde7 100644 --- a/src/P2/mat.c +++ b/src/P2/mat.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include extern VECTOR g_normalZ; @@ -83,7 +85,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/mat", CalculateDmat__FP7MATRIX3N20); INCLUDE_ASM("asm/nonmatchings/P2/mat", CalculateDmat4__FP7MATRIX4N20); -INCLUDE_ASM("asm/nonmatchings/P2/mat", DecomposeRotateMatrixPanTilt__FP7MATRIX3PfT1); +void DecomposeRotateMatrixPanTilt(MATRIX3 *pmat, float *pradPan, float *pradTilt) +{ + *pradPan = atan2f(pmat->mat[0][1], pmat->mat[0][0]); + *pradTilt = atan2f(pmat->mat[0][2], + SQRTF(pmat->mat[0][0] * pmat->mat[0][0] + pmat->mat[0][1] * pmat->mat[0][1])); +} INCLUDE_ASM("asm/nonmatchings/P2/mat", LoadRotateMatrixPanTilt__FffP7MATRIX3); diff --git a/src/P2/rog.c b/src/P2/rog.c index db64cfe0..3f69225d 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -48,7 +48,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", RovsNextRov__FP3ROV); INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRovRovs__FP3ROV4ROVS); -INCLUDE_ASM("asm/nonmatchings/P2/rog", RovtsNextRov__FP3ROV); +ROVTS RovtsNextRov(ROV *prov) +{ + ROVTS rovts; + + rovts = STRUCT_OFFSET(prov, 0x614, ROVTS); + + switch (rovts) + { + case ROVTS_Calm: + if (STRUCT_OFFSET(prov, 0x624, float) >= 0.8f) + { + rovts = ROVTS_Firing; + } + break; + case ROVTS_Firing: + if (STRUCT_OFFSET(prov, 0x624, float) < 0.8f) + { + rovts = ROVTS_Calm; + } + break; + default: + break; + } + + return rovts; +} INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRovRovts__FP3ROV5ROVTS); diff --git a/src/P2/speaker.c b/src/P2/speaker.c index 0e329e49..0e93ba47 100644 --- a/src/P2/speaker.c +++ b/src/P2/speaker.c @@ -1,7 +1,28 @@ #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/speaker", InitSpeaker__FP7SPEAKER); INCLUDE_ASM("asm/nonmatchings/P2/speaker", PostSpeakerLoad__FP7SPEAKER); -INCLUDE_ASM("asm/nonmatchings/P2/speaker", SetSpeakerSmIdle__FP7SPEAKER3OID); +void SetSpeakerSmIdle(SPEAKER *pspeaker, OID oid) +{ + SM *psm; + + if (STRUCT_OFFSET(pspeaker, 0x334, SMA *) != NULL) + { + RetractSma(STRUCT_OFFSET(pspeaker, 0x334, SMA *)); + STRUCT_OFFSET(pspeaker, 0x334, SMA *) = NULL; + } + + psm = (SM *)PloFindSwObject(pspeaker->psw, 0x101, oid, pspeaker); + STRUCT_OFFSET(pspeaker, 0x330, SM *) = psm; + + if (psm != NULL) + { + STRUCT_OFFSET(pspeaker, 0x334, SMA *) = PsmaApplySm(psm, pspeaker, (OID)-1, 1); + } + + STRUCT_OFFSET(pspeaker, 0x32c, OID) = oid; +} diff --git a/src/P2/suv.c b/src/P2/suv.c index ce45dde6..a9b58359 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -1,5 +1,7 @@ #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/suv", InitSuv__FP3SUV); @@ -63,7 +65,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", RenderSuvSelf__FP3SUVP2CMP2RO); INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvBounds__FP3SUV); -INCLUDE_ASM("asm/nonmatchings/P2/suv", CollectSuvPrize__FP3SUV3PCKP3ALO); +void CollectSuvPrize(SUV *psuv, PCK pck, ALO *paloOther) +{ + STEPGUARD *pstepguard; + + pstepguard = STRUCT_OFFSET(psuv, 0xb78, STEPGUARD *); + if (pstepguard != NULL) + { + SetStepguardPatrolAnimation(pstepguard, NULL); + pstepguard = STRUCT_OFFSET(psuv, 0xb78, STEPGUARD *); + (*(void (**)(STEPGUARD *, PCK, ALO *))((char *)pstepguard->pvtlo + 0x148))(pstepguard, pck, paloOther); + } + else + { + CollectPoPrize((PO *)psuv, pck, paloOther); + } +} INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvShapes__FP3SUV); diff --git a/src/P2/tank.c b/src/P2/tank.c index 622fd9a7..2b9361c4 100644 --- a/src/P2/tank.c +++ b/src/P2/tank.c @@ -1,7 +1,24 @@ #include #include +#include +#include -INCLUDE_ASM("asm/nonmatchings/P2/tank", InitTank__FP4TANK); +void InitTank(TANK *ptank) +{ + extern VECTOR g_normalZ; + extern qword D_00275740; + float rad; + + InitStep((STEP *)ptank); + + rad = atan2f(STRUCT_OFFSET(ptank, 0xD4, float), STRUCT_OFFSET(ptank, 0xD0, float)); + STRUCT_OFFSET(ptank, 0x638, float) = rad; + LoadRotateMatrixRad(rad, &g_normalZ, (MATRIX3 *)((uint8_t *)ptank + 0x660)); + + STRUCT_OFFSET(ptank, 0x720, int) = -1; + STRUCT_OFFSET(ptank, 0x72C, float) = -10.0f; + STRUCT_OFFSET(ptank, 0x6F0, qword) = D_00275740; +} INCLUDE_ASM("asm/nonmatchings/P2/tank", PostTankLoad__FP4TANK); diff --git a/src/P2/turret.c b/src/P2/turret.c index 678cf8fb..ab1ab783 100644 --- a/src/P2/turret.c +++ b/src/P2/turret.c @@ -1,5 +1,8 @@ #include #include +#include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/turret", InitTurret__FP6TURRET); @@ -17,7 +20,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/turret", FFilterTurret__FP6TURRETP2SO); INCLUDE_ASM("asm/nonmatchings/P2/turret", UpdateTurretAim__FP6TURRET); -INCLUDE_ASM("asm/nonmatchings/P2/turret", FireTurret__FP6TURRET); +void FireTurret(TURRET *pturret) +{ + OID oidCur; + OID oidGoal; + + GetSmaCur(STRUCT_OFFSET(pturret, 0x614, SMA *), &oidCur); + GetSmaGoal(STRUCT_OFFSET(pturret, 0x614, SMA *), &oidGoal); + + if (oidCur == (OID)0x359 && oidGoal == oidCur) + { + if (FEnsureRwmLoaded(STRUCT_OFFSET(pturret, 0x618, RWM *))) + { + SetSmaGoal(STRUCT_OFFSET(pturret, 0x614, SMA *), (OID)0x35A); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/turret", HandleTurretMessage__FP6TURRET5MSGIDPv); From d2b0ea9c197652280ba4033041b088bace41901b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 00:23:10 +0200 Subject: [PATCH 073/134] Match 6 medium functions via LHF harness (21-30 window, editable re-draft 6) eyes/hide/rip/stepcane: SetEyesClosed, InitHbsk, FBounceShrapnel, PripgNew, RenderStuck, ChooseJtSmashTarget. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/eyes.c | 18 +++++++++++++++++- src/P2/hide.c | 10 +++++++++- src/P2/rip.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- src/P2/stepcane.c | 18 +++++++++++++++++- 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/P2/eyes.c b/src/P2/eyes.c index 0e46d997..913c39ca 100644 --- a/src/P2/eyes.c +++ b/src/P2/eyes.c @@ -18,6 +18,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/eyes", SetEyesEyess__FP4EYES5EYESS); INCLUDE_ASM("asm/nonmatchings/P2/eyes", UpdateEyes__FP4EYESf); -INCLUDE_ASM("asm/nonmatchings/P2/eyes", SetEyesClosed__FP4EYESf); +void SetEyesClosed(EYES *peyes, float uClosed) +{ + STRUCT_OFFSET(peyes, 0x74, float) = uClosed; + + if (1.0f <= uClosed) + { + SetEyesEyess(peyes, EYESS_Closed); + } + else + { + peyes->eyess = EYESS_Nil; + SetEyesEyess(peyes, EYESS_Open); + } + + SetSaiIframe((SAI *)((uint8_t *)peyes + 0x10), (int)STRUCT_OFFSET(peyes, 0x70, float)); + SetSaiIframe((SAI *)((uint8_t *)peyes + 0x40), (int)STRUCT_OFFSET(peyes, 0x70, float)); +} INCLUDE_ASM("asm/nonmatchings/P2/eyes", PsaiFromEyesShd__FP4EYESP3SHD); diff --git a/src/P2/hide.c b/src/P2/hide.c index c53f9889..935ffe4d 100644 --- a/src/P2/hide.c +++ b/src/P2/hide.c @@ -56,7 +56,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/hide", GetHpntClosestHidePos__FP4HPNTP6VECTORPf INCLUDE_ASM("asm/nonmatchings/P2/hide", FUN_0016a320); -INCLUDE_ASM("asm/nonmatchings/P2/hide", InitHbsk__FP4HBSK); +void InitHbsk(HBSK *phbsk) +{ + InitSo((SO *)phbsk); + SetAloRotationSpring((ALO *)phbsk, 3.0f); + SetAloRotationDamping((ALO *)phbsk, 3.0f); + SetAloPositionSmooth((ALO *)phbsk, 3.0f); + SetAloRotationSmooth((ALO *)phbsk, 2.0f); + STRUCT_OFFSET(phbsk, 0x568, float) = 300.0f; +} extern qword D_002483D0[3]; diff --git a/src/P2/rip.c b/src/P2/rip.c index 72feb625..424b0042 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -1,7 +1,33 @@ #include #include +#include +#include -INCLUDE_ASM("asm/nonmatchings/P2/rip", PripgNew__FP2SW5RIPGT); +RIPG *PripgNew(SW *psw, RIPGT ripgt) +{ + RIPG *pripg; + + if (ripgt == RIPGT_Default) + { + if (STRUCT_OFFSET(psw, 0x1B3C, RIPG *) != NULL) + { + return STRUCT_OFFSET(psw, 0x1B3C, RIPG *); + } + } + + pripg = STRUCT_OFFSET(psw, 0x1B38, RIPG *); + if (pripg != NULL) + { + STRUCT_OFFSET(psw, 0x1B38, RIPG *) = STRUCT_OFFSET(pripg, 0x564, RIPG *); + STRUCT_OFFSET(pripg, 0x550, RIPGT) = ripgt; + (*(void (**)(RIPG *))((uint8_t *)STRUCT_OFFSET(pripg, 0x0, void *) + 0x18))(pripg); + if (ripgt == RIPGT_Default) + { + STRUCT_OFFSET(psw, 0x1B3C, RIPG *) = pripg; + } + } + return pripg; +} INCLUDE_ASM("asm/nonmatchings/P2/rip", InitRipg__FP4RIPG); @@ -211,7 +237,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceFlying__FP6FLYINGP2SOP6VECTORT2); INCLUDE_ASM("asm/nonmatchings/P2/rip", UpdateStuck__FP5STUCKf); -INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderStuck__FP5STUCKP2CM); +void RenderStuck(STUCK *pstuck, CM *pcm) +{ + VECTOR pos; + MATRIX3 mat; + + ConvertAloPos(STRUCT_OFFSET(pstuck, 0x120, ALO *), NULL, &STRUCT_OFFSET(pstuck, 0x80, VECTOR), &pos); + ConvertAloMat(STRUCT_OFFSET(pstuck, 0x120, ALO *), NULL, &STRUCT_OFFSET(pstuck, 0x50, MATRIX3), &mat); + FRenderRipPosMat((RIP *)pstuck, pcm, &pos, &mat); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", PostLeafEmit__FP4LEAFP5EMITB); @@ -245,7 +279,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceBullet__FP6BULLETP2SOP6VECTORT2); INCLUDE_ASM("asm/nonmatchings/P2/rip", PostShrapnelEmit__FP8SHRAPNELP5EMITB); -INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceShrapnel__FP8SHRAPNELP2SOP6VECTORT2); +int FBounceShrapnel(SHRAPNEL *pshrapnel, SO *psoOther, VECTOR *ppos, VECTOR *pnormal) +{ + if (FIsBasicDerivedFrom(STRUCT_OFFSET(psoOther, 0x50, BASIC *), CID_STEP)) + return 0; + return FBounceRip((RIP *)pshrapnel, psoOther, ppos, pnormal); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderShrapnel__FP8SHRAPNELP2CM); diff --git a/src/P2/stepcane.c b/src/P2/stepcane.c index ff77abe9..ba6c83cf 100644 --- a/src/P2/stepcane.c +++ b/src/P2/stepcane.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/stepcane", SetJtJtcs__FP2JT4JTCS); @@ -12,4 +13,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtSweepTarget__FP2JTP2BLP6ASEG INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtRushTarget__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtSmashTarget__FP2JT); +void ChooseJtSmashTarget(JT *pjt) +{ + extern VECTOR D_00274C00; + VECTOR dposProj; + TARGET *ptarget; + + ChooseJtAttackTarget(pjt, 4, &D_00274C00, 0.25f, 3.15f, &ptarget, &dposProj); + STRUCT_OFFSET(pjt, 0x2204, int) = 0; + STRUCT_OFFSET(pjt, 0x2200, TARGET *) = ptarget; + STRUCT_OFFSET(pjt, 0x2208, int) = 0; + if (ptarget != NULL) + { + STRUCT_OFFSET(pjt, 0x638, float) = atan2f(dposProj.y, dposProj.x); + FixStepAngularVelocity((STEP *)pjt); + } +} From 8ce4de095b471fa04615d66754403b85607269b3 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 00:36:42 +0200 Subject: [PATCH 074/134] Match 3 medium functions via LHF harness (21-30 window, editable re-draft 7) act/glob/stephide: CloneAct, EnsureBuffer, GMeasureJumpHshape. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 10 +++++++++- src/P2/glob.c | 17 ++++++++++++++++- src/P2/stephide.c | 18 +++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index 0fe06427..79711548 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -1,6 +1,7 @@ #include #include #include +#include ACT *PactNew(SW *psw, ALO *palo, VTACT *pvtact) { @@ -19,7 +20,14 @@ ACT *PactNewClone(ACT *pactBase, SW *psw, ALO *palo) return pact; } -INCLUDE_ASM("asm/nonmatchings/P2/act", CloneAct__FP3ACTT0); +void CloneAct(ACT *pact, ACT *pactBase) +{ + DLE dleSav = pact->dleAlo; + ALO *paloSav = pact->palo; + CopyAb(pact, pactBase, STRUCT_OFFSET(g_psw, 0x1B20, int)); + pact->dleAlo = dleSav; + pact->palo = paloSav; +} void InitAct(ACT *pact, ALO *palo) { diff --git a/src/P2/glob.c b/src/P2/glob.c index e95fc9dc..028b6274 100644 --- a/src/P2/glob.c +++ b/src/P2/glob.c @@ -1,11 +1,26 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/glob", BuildGlobsetSaaArray__FP7GLOBSET); INCLUDE_ASM("asm/nonmatchings/P2/glob", LoadGlobsetFromBrx__FP7GLOBSETP18CBinaryInputStreamP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/glob", EnsureBuffer__FiP4VIFS); +extern char D_18C0; +extern char D_18F8; + +void EnsureBuffer(int iBuffer, VIFS *pvifs) +{ + switch (iBuffer) + { + case 0: + pvifs->AddVifMscal(&D_18C0); + break; + case 1: + pvifs->AddVifMscal(&D_18F8); + break; + } +} INCLUDE_ASM("asm/nonmatchings/P2/glob", EnsureBufferCel__FiP4VIFS); diff --git a/src/P2/stephide.c b/src/P2/stephide.c index ca2df40f..a6721bad 100644 --- a/src/P2/stephide.c +++ b/src/P2/stephide.c @@ -26,7 +26,23 @@ float GMeasureJumpRail(MJR *pmjr, float u) INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001cea58); -INCLUDE_ASM("asm/nonmatchings/P2/stephide", GMeasureJumpHshape__FP3MJHf); +struct HSHAPE; +extern void GetHshapeHidePos(HSHAPE *phshape, float s, VECTOR *ppos, float *pf); + +float GMeasureJumpHshape(MJH *pmjh, float s) +{ + VECTOR posTarget; + float gInteg; + + GetHshapeHidePos(STRUCT_OFFSET(pmjh, 0x4, HSHAPE *), s, &posTarget, 0); + + MeasureJtJumpToTarget(STRUCT_OFFSET(pmjh, 0x0, JT *), + (VECTOR *)((uint8_t *)pmjh + 0x10), + STRUCT_OFFSET(STRUCT_OFFSET(pmjh, 0x4, HSHAPE *), 0x18, ALO *), + &posTarget, 0, 0, &gInteg, 0, 0); + + return gInteg; +} INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001ceb18); From 8d152d32e29ff27d7f59d5fe5ab2340b8e6e5ba8 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 00:51:35 +0200 Subject: [PATCH 075/134] Match 8 functions via LHF harness (31-40 window, editable wave 1) asega/cm/emitter/glob/jlo/sm/wm: message-forwarders (SendAsegaMessage, SendSmaMessage), DrawCm vif sequence, OnEmitterValuesChanged, globset array builder, jlo target/init, ShowWm state machine. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/asega.c | 21 ++++++++++++++++++++- src/P2/cm.c | 11 ++++++++++- src/P2/emitter.c | 27 ++++++++++++++++++++++++++- src/P2/glob.c | 21 ++++++++++++++++++++- src/P2/jlo.c | 31 +++++++++++++++++++++++++++++-- src/P2/sm.c | 21 ++++++++++++++++++++- src/P2/wm.c | 19 ++++++++++++++++++- 7 files changed, 143 insertions(+), 8 deletions(-) diff --git a/src/P2/asega.c b/src/P2/asega.c index 277b7309..26813d05 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -85,7 +85,26 @@ void SetAsegaMasterSpeed(ASEGA *pasega, float gSpeed) INCLUDE_ASM("asm/nonmatchings/P2/asega", SetAsegaPriority__FP5ASEGAi); -INCLUDE_ASM("asm/nonmatchings/P2/asega", SendAsegaMessage__FP5ASEGA5MSGIDPv); +void SendAsegaMessage(ASEGA *pasega, MSGID msgid, void *pv) +{ + LO *plo = STRUCT_OFFSET(pasega, 0xC, LO *); + if (plo) + { + plo->pvtlo->pfnSendLoMessage(plo, msgid, pv); + } + + MQ *pmq = STRUCT_OFFSET(pasega, 0xE4, MQ *); + + while (pmq) + { + PFNMQ pfnmq = pmq->pfnmq; + void *pmqContext = pmq->pvContext; + + pmq = pmq->pmqNext; + + pfnmq(pmqContext, msgid, pv); + } +} void SubscribeAsegaStruct(ASEGA *pasega, PFNMQ pfnmq, void *pvContext) { diff --git a/src/P2/cm.c b/src/P2/cm.c index d1dbeb02..995c0fb8 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include // todo fix data and rodata // VECTOR4 g_posEyeDefault = { 0.0f, -2000.0f, 500.0f, 0.0f }; @@ -211,7 +213,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", BuildFrustrum); INCLUDE_ASM("asm/nonmatchings/P2/cm", UpdateCmMat4); -INCLUDE_ASM("asm/nonmatchings/P2/cm", DrawCm__FP2CM); +void DrawCm(CM *pcm) +{ + g_vifs.AddDmaCnt(); + g_vifs.AddVifBaseOffset(0, 0); + g_vifs.AddVifUnpack(UPK_V4_32, 4, (uint8_t *)pcm + 0x100, 4); + g_vifs.AddVifUnpack(UPK_V4_32, 4, (uint8_t *)pcm + 0x140, 8); + g_vifs.EndDmaCnt(); +} INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmPosMat__FP2CMP6VECTORP7MATRIX3); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index bcbb66e7..73cee0f4 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -1,4 +1,7 @@ #include +#include +#include +#include extern float DAT_0024a124; @@ -141,7 +144,29 @@ void GetEmitterPaused(EMITTER *pemitter, int *pfPaused) *pfPaused = FPausedEmitter(pemitter); } -INCLUDE_ASM("asm/nonmatchings/P2/emitter", OnEmitterValuesChanged__FP7EMITTER); +void OnEmitterValuesChanged(EMITTER *pemitter) +{ + STRUCT_OFFSET(pemitter, 0x34c, int) = 0; // pemitter->fValuesChanged + + if (STRUCT_OFFSET(pemitter, 0x348, BLIPG *) != 0) + { + SetBlipgEmitb(STRUCT_OFFSET(pemitter, 0x348, BLIPG *), STRUCT_OFFSET(pemitter, 0x2d0, EMITB *)); + } + + if (STRUCT_OFFSET(pemitter, 0x344, RIPG *) != 0) + { + SetRipgEmitb(STRUCT_OFFSET(pemitter, 0x344, RIPG *), STRUCT_OFFSET(pemitter, 0x2d0, EMITB *)); + } + + if (STRUCT_OFFSET(pemitter, 0x2d4, int) == 3) + { + STRUCT_OFFSET(pemitter, 0x328, float) = GRandInRange(STRUCT_OFFSET(pemitter, 0x2dc, float), STRUCT_OFFSET(pemitter, 0x2e0, float)) * 60.0f; + } + else + { + STRUCT_OFFSET(pemitter, 0x328, float) = GRandInRange(STRUCT_OFFSET(pemitter, 0x2dc, float), STRUCT_OFFSET(pemitter, 0x2e0, float)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", SetEmitterParticleCount__FP7EMITTERi); diff --git a/src/P2/glob.c b/src/P2/glob.c index 028b6274..644a5ae4 100644 --- a/src/P2/glob.c +++ b/src/P2/glob.c @@ -1,8 +1,27 @@ #include #include #include +#include -INCLUDE_ASM("asm/nonmatchings/P2/glob", BuildGlobsetSaaArray__FP7GLOBSET); +void BuildGlobsetSaaArray(GLOBSET *pglobset) +{ + void **psaa; + int i; + int iDst; + + psaa = (void **)PvAllocSwImpl(STRUCT_OFFSET(pglobset, 0x50, int) * 4); + STRUCT_OFFSET(pglobset, 0x54, void **) = psaa; + + iDst = 0; + for (i = 0; i < STRUCT_OFFSET(pglobset, 0xc, int); i++) + { + void *p; + + p = STRUCT_OFFSET((uint8_t *)STRUCT_OFFSET(pglobset, 0x10, uint8_t *) + i * 0x70, 0x38, void *); + if (p != 0) + STRUCT_OFFSET(pglobset, 0x54, void **)[iDst++] = p; + } +} INCLUDE_ASM("asm/nonmatchings/P2/glob", LoadGlobsetFromBrx__FP7GLOBSETP18CBinaryInputStreamP3ALO); diff --git a/src/P2/jlo.c b/src/P2/jlo.c index 4ab7009d..6ada8771 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -27,7 +27,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", LoadJloFromBrx__FP3JLOP18CBinaryInputStre INCLUDE_ASM("asm/nonmatchings/P2/jlo", PostJloLoad__FP3JLO); -INCLUDE_ASM("asm/nonmatchings/P2/jlo", FUN_0016d040); +extern "C" { +void FUN_0016d040(JLO *pjlo, OID oid) +{ + JLOVOL *pjlovol; + + STRUCT_OFFSET(pjlo, 0x578, OID) = oid; + pjlovol = (JLOVOL *)PloFindSwNearest(pjlo->psw, oid, pjlo); + if (pjlovol != NULL) + { + SetJloJlovol(pjlo, pjlovol); + LandJlo(pjlo); + if (STRUCT_OFFSET(pjlovol, 0x7AC, int) != 0) + SetJloJlos(pjlo, JLOS_Idle); + else + SetJloJlos(pjlo, JLOS_Taunt); + } +} +} void PresetJloAccel(JLO *pjlo, float dt) { @@ -70,7 +87,17 @@ void DeactivateJlo(JLO *pjlo) g_pjloCur = NULL; } -INCLUDE_ASM("asm/nonmatchings/P2/jlo", InitJloc__FP4JLOC); +void InitJloc(JLOC *pjloc) +{ + InitAlo(pjloc); + STRUCT_OFFSET(pjloc, 0x31C, float) = 2.25f; + STRUCT_OFFSET(pjloc, 0x320, float) = 2.0f; + STRUCT_OFFSET(pjloc, 0x324, float) = 0.8f; + STRUCT_OFFSET(pjloc, 0x328, float) = 4.0f; + STRUCT_OFFSET(pjloc, 0x32C, float) = 0.5f; + STRUCT_OFFSET(pjloc, 0x330, float) = 1000.0f; + STRUCT_OFFSET(pjloc, 0x334, float) = 2000.0f; +} void LoadJlocFromBrx(JLOC *pjloc, CBinaryInputStream *pbis) { diff --git a/src/P2/sm.c b/src/P2/sm.c index 33a99d8b..58bfe305 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -69,7 +69,26 @@ void HandleSmaMessage(SMA *psma, MSGID msgid, void *pv) INCLUDE_ASM("asm/nonmatchings/P2/sm", SkipSma__FP3SMAf); -INCLUDE_ASM("asm/nonmatchings/P2/sm", SendSmaMessage__FP3SMA5MSGIDPv); +void SendSmaMessage(SMA *psma, MSGID msgid, void *pv) +{ + ALO *paloRoot = psma->paloRoot; + if (paloRoot) + { + paloRoot->pvtlo->pfnSendLoMessage(paloRoot, msgid, pv); + } + + MQ *pmq = psma->pmqFirst; + + while (pmq) + { + PFNMQ pfnmq = pmq->pfnmq; + void *pmqContext = pmq->pvContext; + + pmq = pmq->pmqNext; + + pfnmq(pmqContext, msgid, pv); + } +} INCLUDE_ASM("asm/nonmatchings/P2/sm", FUN_001b6df8); diff --git a/src/P2/wm.c b/src/P2/wm.c index 13976ba6..619a4532 100644 --- a/src/P2/wm.c +++ b/src/P2/wm.c @@ -39,7 +39,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/wm", HandleWmMessage__FP2WM5MSGIDPv); INCLUDE_ASM("asm/nonmatchings/P2/wm", SetWmWms__FP2WM3WMS); -INCLUDE_ASM("asm/nonmatchings/P2/wm", ShowWm__FP2WM10WORLDLEVEL3WMS); +void ShowWm(WM *pwm, WORLDLEVEL worldlevel, WMS wmsActive) +{ + switch (STRUCT_OFFSET(pwm, 0x2D0, WMS)) + { + case WMS_Hidden: + case WMS_Disappearing: + STRUCT_OFFSET(pwm, 0x2DC, WORLDLEVEL) = worldlevel; + STRUCT_OFFSET(pwm, 0x2E0, WMS) = wmsActive; + SetWmWms(pwm, WMS_Appearing); + break; + + case WMS_Manual: + STRUCT_OFFSET(pwm, 0x2DC, WORLDLEVEL) = worldlevel; + if (wmsActive == WMS_Warping) + SetWmWms(pwm, WMS_Warping); + break; + } +} INCLUDE_ASM("asm/nonmatchings/P2/wm", HideWm__FP2WM); From 8de0bb87a8ddf6f02a91aa02fa8d278ba4a94dbe Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 01:06:22 +0200 Subject: [PATCH 076/134] Match 17 functions via LHF harness (31-40 window, editable wave 2) alarm/button/crv/dmas/dysh/font/murray/puffer/rog/screen/shd/sm/ stephang/xform: PostLoad hooks (camera/warp/murray/fonts), AddDmaCall, RenderDyshSelf, GetExtents, SkipSma, PropagateShaders, wander-location, absorb-wkr, timer tick. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/alarm.c | 19 ++++++++++++++++++- src/P2/button.c | 15 ++++++++++++++- src/P2/crv.c | 19 ++++++++++++++++++- src/P2/dmas.c | 25 ++++++++++++++++++++++++- src/P2/dysh.c | 20 +++++++++++++++++++- src/P2/font.c | 33 +++++++++++++++++++++++++++++++-- src/P2/murray.c | 13 ++++++++++++- src/P2/puffer.c | 25 ++++++++++++++++++++++++- src/P2/rog.c | 23 +++++++++++++++++++++-- src/P2/screen.c | 29 ++++++++++++++++++++++++++++- src/P2/shd.c | 22 +++++++++++++++++++++- src/P2/sm.c | 21 ++++++++++++++++++++- src/P2/stephang.c | 16 +++++++++++++++- src/P2/xform.c | 36 ++++++++++++++++++++++++++++++++++-- 14 files changed, 299 insertions(+), 17 deletions(-) diff --git a/src/P2/alarm.c b/src/P2/alarm.c index 2e0a1422..852c2656 100644 --- a/src/P2/alarm.c +++ b/src/P2/alarm.c @@ -1,6 +1,7 @@ #include #include #include +#include void BreakAlbrk(ALBRK *palbrk) { @@ -66,7 +67,23 @@ void DisableAlarmAlbrk(ALARM *palarm) STRUCT_OFFSET(palarm, 0x61c, int)++; // palarm->calbrksDisabled } -INCLUDE_ASM("asm/nonmatchings/P2/alarm", EnableAlarmSensors__FP5ALARM); +void EnableAlarmSensors(ALARM *palarm) +{ + int i; + + for (i = 0; i < STRUCT_OFFSET(palarm, 0x5bc, int); i++) + { + SENSOR *psensor = ((SENSOR **)((uint8_t *)palarm + 0x5c0))[i]; + if (STRUCT_OFFSET(psensor, 0x560, int) == -1) + { + void (*pfn)(SENSOR *, int) = (void (*)(SENSOR *, int))STRUCT_OFFSET(psensor->pvtlo, 0x134, void *); + if (pfn != 0) + { + pfn(psensor, 0); + } + } + } +} void DisableAlarmSensors(ALARM *palarm) { diff --git a/src/P2/button.c b/src/P2/button.c index 552907e4..7ca20a5e 100644 --- a/src/P2/button.c +++ b/src/P2/button.c @@ -138,7 +138,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/button", UpdateButtonInternalXps__FP6BUTTON); INCLUDE_ASM("asm/nonmatchings/P2/button", UpdateButton__FP6BUTTONf); -INCLUDE_ASM("asm/nonmatchings/P2/button", FAbsorbButtonWkr__FP6BUTTONP3WKR); +int FAbsorbButtonWkr(BUTTON* pbutton, WKR* pwkr) +{ + int fAbsorbed = FAbsorbSoWkr(pbutton, pwkr); + + if (fAbsorbed && + !(pwkr->grfic & 0x4) && + STRUCT_OFFSET(pbutton, 0x550, int) == BUTTONS_Disabled && + !STRUCT_OFFSET(pbutton, 0x680, int)) + { + SetButtonButtons(pbutton, BUTTONS_Contact); + } + + return fAbsorbed; +} void InitVolbtn(VOLBTN *pvolbtn) { diff --git a/src/P2/crv.c b/src/P2/crv.c index 8320359f..1e4ca036 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureApos__FiP6VECTORPf); @@ -200,7 +201,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", RenderCrvcSegment__FP4CRVCiP7MATRIX4P2CMG INCLUDE_ASM("asm/nonmatchings/P2/crv", ConvertCrvc__FP4CRVCP7MATRIX4T1); -INCLUDE_ASM("asm/nonmatchings/P2/crv", SFromCrvcU__FP4CRVCf); +float SFromCrvcU(CRVC *pcrvc, float u) +{ + float du; + float duSeg; + int icv; + + icv = IcvFindCrvU((CRV *)pcrvc, u, &du, &duSeg); + + return SBezierPosLength( + duSeg, + du, + (VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x18, void *) + icv * 16), + (VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x20, void *) + icv * 16), + (VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x18, void *) + (icv * 16 + 16)), + (VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x1C, void *) + (icv * 16 + 16))) + + STRUCT_OFFSET(pcrvc, 0x14, float *)[icv]; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", UFromCrvcS__FP4CRVCf); diff --git a/src/P2/dmas.c b/src/P2/dmas.c index 48f0a90e..cb8a14d7 100644 --- a/src/P2/dmas.c +++ b/src/P2/dmas.c @@ -93,7 +93,30 @@ void DMAS::AddDmaCnt() INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaRefs__4DMASiP2QW); -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaCall__4DMASP2QW); +void DMAS::AddDmaCall(QW *pqw) +{ + int fCnt = 0; + + if (m_pqwCnt) + { + EndDmaCnt(); + fCnt = 1; + } + + uchar *pb = m_pb; + m_pb = pb + 0x10; + *(ulong *)pb = ((ulong)(uint)pqw << 32) | 0x50000000; + *(ulong *)(pb + 8) = 0; + + if (fCnt) + { + QW *pqwCnt = (QW *)m_pb; + m_pqwCnt = pqwCnt; + m_pb += sizeof(QW); + pqwCnt->aul[0] = 0x10000000; + m_pqwCnt->aul[1] = 0; + } +} void DMAS::AddDmaRet() { diff --git a/src/P2/dysh.c b/src/P2/dysh.c index 17923671..1772968e 100644 --- a/src/P2/dysh.c +++ b/src/P2/dysh.c @@ -1,5 +1,7 @@ #include #include +#include +#include void InitDysh(DYSH* pdysh) { @@ -8,6 +10,22 @@ void InitDysh(DYSH* pdysh) INCLUDE_ASM("asm/nonmatchings/P2/dysh", SetDyshShadow__FP4DYSHP6SHADOW); -INCLUDE_ASM("asm/nonmatchings/P2/dysh", RenderDyshSelf__FP4DYSHP2CMP2RO); +void RenderDyshSelf(DYSH* pdysh, CM* pcm, RO* pro) +{ + RPL rpl; + + if (STRUCT_OFFSET(pdysh, 0x2D0, int)) + { + void** pvtbl = STRUCT_OFFSET(pdysh, 0x0, void**); + ((void (*)(DYSH*, RO*))pvtbl[0xAC / 4])(pdysh, pro); + + memset(&rpl, 0, 0x80); + rpl.pfnDraw = DrawDysh; + rpl.rp = RP_DynamicTexture; + DupAloRo((ALO*)pdysh, pro, (RO*)((char*)&rpl + 0x10)); + STRUCT_OFFSET(&rpl, 0x60, DYSH*) = pdysh; + SubmitRpl(&rpl); + } +} INCLUDE_ASM("asm/nonmatchings/P2/dysh", DrawDysh__FP3RPL); diff --git a/src/P2/font.c b/src/P2/font.c index d3e5263c..f69b7c8f 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -1,5 +1,6 @@ #include #include +#include void StartupFont() { @@ -126,11 +127,39 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015e1b0); INCLUDE_ASM("asm/nonmatchings/P2/font", DxMaxLine__9CRichText); -INCLUDE_ASM("asm/nonmatchings/P2/font", GetExtents__9CRichTextPfT1f); +extern "C" int ClineWrap__9CRichTextf(CRichText *self, float dyMax); +extern "C" float DxMaxLine__9CRichText(CRichText *self); + +extern "C" void GetExtents__9CRichTextPfT1f(CRichText *self, float *pdx, float *pdy, float dyMax) +{ + int cline = ClineWrap__9CRichTextf(self, dyMax); + float dxMax = DxMaxLine__9CRichText(self); + CFont *pfont = STRUCT_OFFSET(self, 0xC, CFont *); + float dyLine = (float)STRUCT_OFFSET(pfont, 0x8, int) * STRUCT_OFFSET(pfont, 0x48, float); + float dyTotal = (float)cline * dyLine; + if (pdx) + *pdx = dxMax; + if (pdy) + *pdy = dyTotal; +} INCLUDE_ASM("asm/nonmatchings/P2/font", Draw__9CRichTextP8CTextBoxT1P4GIFS); -INCLUDE_ASM("asm/nonmatchings/P2/font", PostFontsLoad__Fv); +extern int D_00262260; +extern CFontBrx *D_00262264; +extern "C" void PostLoad__8CFontBrxP3GSB(CFontBrx *self, GSB *pgsb); + +void PostFontsLoad() +{ + GSB gsb; + int i; + + InitGsb(&gsb, 0x1400, 0x1E00); + for (i = 0; i < D_00262260; i++) + { + PostLoad__8CFontBrxP3GSB(D_00262264 + i, &gsb); + } +} JUNK_WORD(0x46000802); JUNK_WORD(0x46000802); diff --git a/src/P2/murray.c b/src/P2/murray.c index 5c210c36..29b2eb95 100644 --- a/src/P2/murray.c +++ b/src/P2/murray.c @@ -7,7 +7,18 @@ void InitMurray(MURRAY *pmurray) STRUCT_OFFSET(pmurray, 0xbd0, float) = 0.0f; // pmurray->uFling } -INCLUDE_ASM("asm/nonmatchings/P2/murray", PostMurrayLoad__FP6MURRAY); +extern SNIP D_00269B60[2]; + +void PostMurrayLoad(MURRAY *pmurray) +{ + PostStepguardLoad(pmurray); + SnipAloObjects(pmurray, 2, D_00269B60); + STRUCT_OFFSET(pmurray, 0x5f0, ASEG *) = PasegFindStepguard(pmurray, (OID)0xEF); + STRUCT_OFFSET(pmurray, 0xc38, ASEG *) = PasegFindStepguard(pmurray, (OID)0x16C); + STRUCT_OFFSET(pmurray, 0xc3c, ASEG *) = PasegFindStepguard(pmurray, (OID)0x16D); + STRUCT_OFFSET(pmurray, 0xc40, ASEG *) = PasegFindStepguard(pmurray, (OID)0x16A); + STRUCT_OFFSET(pmurray, 0xc44, ASEG *) = PasegFindStepguard(pmurray, (OID)0x16B); +} INCLUDE_ASM("asm/nonmatchings/P2/murray", FUN_0018ffb0); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 0c5db656..31dc319c 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/puffer", InitPuffer__FP6PUFFER); @@ -34,7 +35,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", PpufftChoosePuffer__FP6PUFFER); INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001973d8); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197458); +extern "C" void FUN_001973d8(void *p); +extern void *D_0026A904; + +extern "C" void FUN_00197458(void *p, int n) +{ + OID oidGoal; + OID oidCur; + + if (n == 1) + { + if (STRUCT_OFFSET(D_0026A904, 0x6B8, SMA *) != NULL) + { + GetSmaGoal(STRUCT_OFFSET(D_0026A904, 0x6B8, SMA *), &oidGoal); + GetSmaCur(STRUCT_OFFSET(D_0026A904, 0x6B8, SMA *), &oidCur); + + if (oidGoal != (OID)0x3F4 && oidCur != (OID)0x3F4) + { + SetSmaGoal(STRUCT_OFFSET(D_0026A904, 0x6B8, SMA *), (OID)0x3F5); + FUN_001973d8(D_0026A904); + } + } + } +} void OnPufferActive(PUFFER *ppuffer, int fActive, PO *ppoOther) { diff --git a/src/P2/rog.c b/src/P2/rog.c index 3f69225d..c1609ae6 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include extern SNIP s_asnipLoadRov[2]; @@ -167,7 +169,18 @@ void SpawnedRobRoh(ROB *prob, ROH *proh) INCLUDE_ASM("asm/nonmatchings/P2/rog", GrabbedRobRoh__FP3ROBP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", DroppedRobRoh__FP3ROBP3ROH); +void DroppedRobRoh(ROB *prob, ROH *proh) +{ + extern VECTOR D_00248D30; + extern VECTOR g_normalZ; + + SO *pso = STRUCT_OFFSET(proh, 0x55c, SO *); + + (*(void (**)(SO *, int))(*(uint8_t **)pso + 0x64))(pso, 0); + (*(void (**)(SO *, VECTOR *))(*(uint8_t **)pso + 0x90))(pso, &D_00248D30); + (*(void (**)(SO *, VECTOR *))(*(uint8_t **)pso + 0x94))(pso, &D_00248D30); + SetSoConstraints(pso, CT_Project, &g_normalZ, CT_Locked, NULL); +} void ReturnedRobRoh(ROB *prob, ROH *proh) { @@ -186,7 +199,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", FChooseRobRoh__FP3ROBP3ROC); INCLUDE_ASM("asm/nonmatchings/P2/rog", FChooseRobReturnPoint__FP3ROBP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", ChooseRobWanderLocation__FP3ROBP3ROH); +void ChooseRobWanderLocation(ROB *prob, ROH *proh) +{ + float rad = GRandInRange(0.0f, 6.2831855f); + float sXY = GRandInRange(0.0f, STRUCT_OFFSET(prob, 0x348, float)); + SetVectorCylind((VECTOR *)((uint8_t *)proh + 0x570), rad, sXY, 0.0f); + STRUCT_OFFSET(proh, 0x574, float) = STRUCT_OFFSET(proh, 0x574, float) * STRUCT_OFFSET(prob, 0x34c, float); +} RODD *ProddCurRob(ROB *prob, ENSK ensk) { diff --git a/src/P2/screen.c b/src/P2/screen.c index 3036f5dc..574fd0ad 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -250,7 +250,34 @@ float FUN_001ABE60() INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001abe70); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac060); +extern "C" { +void FUN_001ac060(TIMER *ptimer) +{ + int n = STRUCT_OFFSET(ptimer, 0x270, int) - 1; + STRUCT_OFFSET(ptimer, 0x270, int) = n; + if (n <= 0) + { + int s = STRUCT_OFFSET(ptimer, 0x26c, int) - 1; + STRUCT_OFFSET(ptimer, 0x26c, int) = s; + if (s <= 0) + { + STRUCT_OFFSET(ptimer, 0x270, int) = 0; + STRUCT_OFFSET(ptimer, 0x26c, int) = 0; + } + else + { + STRUCT_OFFSET(ptimer, 0x270, int) = STRUCT_OFFSET(ptimer, 0x264, int); + } + } + + { + int tmp = STRUCT_OFFSET(ptimer, 0x26c, int) - 1; + int num = (tmp > -1 ? tmp : 0) * STRUCT_OFFSET(ptimer, 0x264, int) + STRUCT_OFFSET(ptimer, 0x270, int); + STRUCT_OFFSET(ptimer, 0x278, float) = (float)num / (float)STRUCT_OFFSET(ptimer, 0x268, int); + STRUCT_OFFSET(ptimer, 0x27c, float) = g_clock.t; + } +} +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac0e8); diff --git a/src/P2/shd.c b/src/P2/shd.c index 3bd7b29b..d20f0c09 100644 --- a/src/P2/shd.c +++ b/src/P2/shd.c @@ -1,5 +1,6 @@ #include #include +#include extern GRFZON g_grfzonShaders; extern byte *g_pbBulkData; @@ -40,7 +41,26 @@ void UploadPermShaders() g_grfzonShaders = 0; } -INCLUDE_ASM("asm/nonmatchings/P2/shd", PropagateShaders__Fi); +extern "C" { + extern GSB D_002626D8; + extern int D_002626CC; +} +void PropagateSurs(); + +void PropagateShaders(GRFZON grfzonCamera) +{ + PropagateSais(); + if (grfzonCamera != g_grfzonShaders) + { + ResetGsb(&D_002626D8); + UploadBitmaps(grfzonCamera, &D_002626D8); + FillShaders(grfzonCamera); + PropagateSurs(); + PropagateBlipgShaders(grfzonCamera); + D_002626CC = 2; + g_grfzonShaders = grfzonCamera; + } +} INCLUDE_ASM("asm/nonmatchings/P2/shd", FillShaders__Fi); diff --git a/src/P2/sm.c b/src/P2/sm.c index 58bfe305..61b4ff3d 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/sm", LoadSmFromBrx__FP2SMP18CBinaryInputStream); @@ -67,7 +68,25 @@ void HandleSmaMessage(SMA *psma, MSGID msgid, void *pv) } } -INCLUDE_ASM("asm/nonmatchings/P2/sm", SkipSma__FP3SMAf); +void SkipSma(SMA *psma, float dtSkip) +{ + ASEGA *pasega; + + extern void SeekAsega(ASEGA *pasega, SEEK seek, float t, float svt); + + while ((pasega = psma->pasegaCur) != NULL) + { + float diff = STRUCT_OFFSET(STRUCT_OFFSET(pasega, 0x8, uint8_t *), 0x34, float) - STRUCT_OFFSET(pasega, 0x14, float); + if (dtSkip < diff) + { + SeekAsega(pasega, SEEK_Current, dtSkip, 1.0f); + break; + } + dtSkip -= diff; + EndSmaTransition(psma); + ChooseSmaTransition(psma); + } +} void SendSmaMessage(SMA *psma, MSGID msgid, void *pv) { diff --git a/src/P2/stephang.c b/src/P2/stephang.c index 622ae3df..691f9b9c 100644 --- a/src/P2/stephang.c +++ b/src/P2/stephang.c @@ -1,7 +1,21 @@ #include #include +#include -INCLUDE_ASM("asm/nonmatchings/P2/stephang", PostJtLoadSwing__FP2JTP2BLPP6ASEGBL); +void PostJtLoadSwing(JT *pjt, BL *ablSwing, ASEGBL **ppasegbl) +{ + ASEGBL *pasegbl; + + STRUCT_OFFSET(ablSwing, 0x0, int) = 0; + STRUCT_OFFSET(ablSwing, 0xC, int) = 0; + STRUCT_OFFSET(ablSwing, 0x18, float) = 1.0f; + + EnsureAsegBlendDynamic((ALO *)pjt, 0xC, 3, ablSwing, 0, NULL, NULL, &pasegbl); + ReblendAsegbl(pasegbl, 0xC, 3, ablSwing); + + if (ppasegbl != NULL) + *ppasegbl = pasegbl; +} INCLUDE_ASM("asm/nonmatchings/P2/stephang", AnticipateJtForce__FP2JTP2SOP6VECTORT2P2FX); diff --git a/src/P2/xform.c b/src/P2/xform.c index 353243a2..cae3c070 100644 --- a/src/P2/xform.c +++ b/src/P2/xform.c @@ -3,6 +3,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/xform", InitXfm__FP3XFM); @@ -44,7 +45,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/xform", LoadWarpFromBrx__FP4WARPP18CBinaryInput INCLUDE_ASM("asm/nonmatchings/P2/xform", CloneWarp__FP4WARPT0); -INCLUDE_ASM("asm/nonmatchings/P2/xform", PostWarpLoad__FP4WARP); +void PostWarpLoad(WARP *pwarp) +{ + int i; + + PostLoLoad(pwarp); + + for (i = 0; i < STRUCT_OFFSET(pwarp, 0xa0, int); i++) + { + LO *plo = STRUCT_OFFSET(pwarp, 0xa4, LO **)[i]; + (*(void (**)(LO *, ALO *))((char *)plo->pvtlo + 0x64))(plo, pwarp->paloParent); + SnipLo(plo); + } +} INCLUDE_ASM("asm/nonmatchings/P2/xform", TriggerWarp__FP4WARP); @@ -112,7 +125,26 @@ void InitCamera(CAMERA *pcamera) STRUCT_OFFSET(pcamera, 0x2d0, OID) = OID_Nil; // pcamera->oidTarget } -INCLUDE_ASM("asm/nonmatchings/P2/xform", PostCameraLoad__FP6CAMERA); +void PostCameraLoad(CAMERA *pcamera) +{ + PostAloLoad(pcamera); + + if (pcamera->oidTarget != OID_Nil) + { + LO *plo = PloFindSwObject(pcamera->psw, 0x104, pcamera->oidTarget, pcamera); + if (plo) + { + if (plo->pvtlo->grfcid & 1) + { + pcamera->paloTarget = (ALO *)plo; + } + else if (FIsBasicDerivedFrom(plo, (CID)0x7e)) + { + pcamera->ppntTarget = (PNT *)plo; + } + } + } +} void EnableCamera(CAMERA *pcamera) { From eb36c4e7d43b0cb44f2f7beab576a78f960b6c5a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 01:21:02 +0200 Subject: [PATCH 077/134] Match 10 functions via LHF harness (31-40 window, editable wave 3) act/cm/coin/emitter/eyes/mark/po/pzo/rip: InitActref, AdjustCmJoy, UpdateCoin, PemitbCopyOnWrite, StockSplashSmall, PostEyesLoad, MuFromAmtlk, GetPoCpdefi, FAbsorbClueWkr, RenderRip. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 22 +++++++++++++++++++++- src/P2/cm.c | 21 ++++++++++++++++++++- src/P2/coin.c | 17 ++++++++++++++++- src/P2/emitter.c | 43 +++++++++++++++++++++++++++++++++++++++++-- src/P2/eyes.c | 38 +++++++++++++++++++++++++++++++++++++- src/P2/mark.c | 22 ++++++++++++++++++++-- src/P2/po.c | 22 +++++++++++++++++++++- src/P2/pzo.c | 15 ++++++++++++++- src/P2/rip.c | 31 ++++++++++++++++++++++++++++++- 9 files changed, 220 insertions(+), 11 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index 79711548..74f91907 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -115,7 +115,27 @@ float GGetActvalPoseGoal(ACTVAL *pactval, int ipose) return pactval->agPoses[ipose]; } -INCLUDE_ASM("asm/nonmatchings/P2/act", InitActref__FP6ACTREFP3ALO); +extern VECTOR D_00248D30; + +void InitActref(ACTREF *pactref, ALO *palo) +{ + uint8_t *psen; + + InitAct(pactref, palo); + STRUCT_OFFSET(pactref, 0x1c, uint8_t *) = (uint8_t *)palo + 0x190; + STRUCT_OFFSET(pactref, 0x24, uint8_t *) = (uint8_t *)palo + 0x1a0; + STRUCT_OFFSET(pactref, 0x38, uint8_t *) = (uint8_t *)palo + 0x26c; + STRUCT_OFFSET(pactref, 0x20, VECTOR *) = &D_00248D30; + STRUCT_OFFSET(pactref, 0x28, VECTOR *) = &D_00248D30; + STRUCT_OFFSET(pactref, 0x3c, float *) = STRUCT_OFFSET(palo, 0x274, float *); + psen = STRUCT_OFFSET(palo, 0x224, uint8_t *); + if (psen != 0 && (STRUCT_OFFSET(psen, 0xb0, int) & 0x20)) + { + STRUCT_OFFSET(pactref, 0x30, VECTOR *) = &D_00248D30; + STRUCT_OFFSET(pactref, 0x2c, uint8_t *) = psen + 0x8c; + } + STRUCT_OFFSET(pactref, 0x34, char *) = D_002483D0; +} void GetActrefPositionGoal(ACTREF *pactref, float dtOffset, VECTOR *ppos, VECTOR *pv) { diff --git a/src/P2/cm.c b/src/P2/cm.c index 995c0fb8..a61b770a 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -7,6 +7,7 @@ #include #include #include +#include // todo fix data and rodata // VECTOR4 g_posEyeDefault = { 0.0f, -2000.0f, 500.0f, 0.0f }; @@ -239,7 +240,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", ResetCmLookAtSmooth); INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmLookAtSmooth); -INCLUDE_ASM("asm/nonmatchings/P2/cm", AdjustCmJoy__FP2CMP3JOY5JOYIDPf); +void AdjustCmJoy(CM *pcm, JOY *pjoy, JOYID joyid, float *prad) +{ + float rad; + + switch (joyid) + { + case JOYID_Left: + rad = atan2f(-pjoy->x, pjoy->y); + break; + case JOYID_Right: + rad = atan2f(-pjoy->x2, pjoy->y2); + break; + default: + rad = 0.0f; + break; + } + + *prad = RadNormalize(rad + atan2f(STRUCT_OFFSET(pcm, 0x84, float), STRUCT_OFFSET(pcm, 0x80, float))); +} JUNK_WORD(0x0000102D); diff --git a/src/P2/coin.c b/src/P2/coin.c index ff227d53..52cf4063 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -77,7 +77,22 @@ void FUN_00147ed0(DPRIZE *pdprize) INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00147ef8); -INCLUDE_ASM("asm/nonmatchings/P2/coin", UpdateCoin__FP4COINf); +extern int D_00270458; + +void UpdateDprize(DPRIZE *pdprize, float dt); + +void UpdateCoin(COIN *pcoin, float dt) +{ + UpdateDprize(pcoin, dt); + if (pcoin->oidInitialState != OID_Unknown) + return; + if (pcoin->fNeverReuse == 0) + return; + if (D_00270458 != 2) + pcoin->tLose -= g_clock.dt; + if (pcoin->tLose <= 0.0f) + (*(void (**)(COIN *, DPRIZES))((char *)pcoin->pvtlo + 0xCC))(pcoin, DPRIZES_Lose); +} INCLUDE_ASM("asm/nonmatchings/P2/coin", CreateSwCharm__FP2SW); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 73cee0f4..caa1ab49 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -2,6 +2,7 @@ #include #include #include +#include extern float DAT_0024a124; @@ -44,7 +45,31 @@ void HandleEmitterMessage(EMITTER *pemitter, MSGID msgid, void *pv) } } -INCLUDE_ASM("asm/nonmatchings/P2/emitter", PemitbCopyOnWrite__FP5EMITB); +EMITB *PemitbCopyOnWrite(EMITB *pemitb) +{ + EMITB *pemitbNew; + + if (pemitb->cref < 2) + { + return pemitb; + } + + pemitbNew = (EMITB *)PvAllocSwCopyImpl(0x200, pemitb); + + if (STRUCT_OFFSET(pemitb, 0x10, int) == 3) + { + if (STRUCT_OFFSET(pemitb, 0x24, void *) != 0) + { + STRUCT_OFFSET(pemitbNew, 0x24, void *) = + PvAllocSwCopyImpl(0x28 * STRUCT_OFFSET(pemitb, 0x20, int), STRUCT_OFFSET(pemitb, 0x24, void *)); + } + } + + pemitbNew->cref = 1; + pemitb->cref--; + + return pemitbNew; +} EMITB *PemitbEnsureEmitter(EMITTER *pemitter, ENSK ensk) { @@ -220,7 +245,21 @@ JUNK_WORD(0x27bd0290); // junk_00157FF0 INCLUDE_ASM("asm/nonmatchings/P2/emitter", StockSplashBig__FP6VECTORfP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", StockSplashSmall__FP6VECTORfP2SO); +void StockSplashSmall(VECTOR *ppos, float gScale, SO *psoTouch) +{ + RIP *prip = PripNewRipg(RIPT_Ripple, 0); + + if (prip) + { + (*(void (**)(RIP *, VECTOR *, float, SO *))(*(void **)prip))(prip, ppos, gScale, 0); + STRUCT_OFFSET(prip, 0x1c, float) = 0.75f; + + if (STRUCT_OFFSET(psoTouch, 0x278, SO *) != 0) + { + STRUCT_OFFSET(prip, 0x114, int) = STRUCT_OFFSET(STRUCT_OFFSET(psoTouch, 0x278, SO *), 0xc, int); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", AddEmitoSkeleton__FP5EMITO3OIDT1ffffP2LO); diff --git a/src/P2/eyes.c b/src/P2/eyes.c index 913c39ca..0fc7e9e4 100644 --- a/src/P2/eyes.c +++ b/src/P2/eyes.c @@ -1,5 +1,6 @@ #include #include +#include void InitEyes(EYES *peyes, SAAF *psaaf) { @@ -12,7 +13,42 @@ void InitEyes(EYES *peyes, SAAF *psaaf) *(float *)&peyes->unk[3] = psaaf->dtPauseMax; } -INCLUDE_ASM("asm/nonmatchings/P2/eyes", PostEyesLoad__FP4EYES); +void PostEyesLoad(EYES *peyes) +{ + SHD *pshd; + int sCur; + int sShd; + + PostSaaLoad((SAA *)peyes); + + pshd = PshdFindShader(peyes->oid); + peyes->pshd = pshd; + if (pshd != NULL) + { + if (STRUCT_OFFSET(pshd, 0x24, SAA *) == NULL) + { + if (STRUCT_OFFSET(peyes->sai.pshd, 0x24, SAA *) == (SAA *)peyes) + { + STRUCT_OFFSET(pshd, 0x24, SAA *) = (SAA *)peyes; + } + } + } + + sCur = 0; + if (peyes->sai.pshd != NULL) + { + sCur = STRUCT_OFFSET(peyes->sai.pshd, 0x20, int); + } + sShd = 0; + if (peyes->pshd != NULL) + { + sShd = STRUCT_OFFSET(peyes->pshd, 0x20, int); + } + + peyes->eyess = EYESS_Nil; + STRUCT_OFFSET(peyes, 0x5C, int) = (sShd < sCur) ? sCur : sShd; + SetEyesEyess(peyes, EYESS_Open); +} INCLUDE_ASM("asm/nonmatchings/P2/eyes", SetEyesEyess__FP4EYES5EYESS); diff --git a/src/P2/mark.c b/src/P2/mark.c index e300caf4..e38e95db 100644 --- a/src/P2/mark.c +++ b/src/P2/mark.c @@ -1,6 +1,24 @@ #include - -INCLUDE_ASM("asm/nonmatchings/P2/mark", MuFromAmtlk__FP4MTLK); +#include + +extern float D_00264840[][2]; + +float MuFromAmtlk(MTLK *amtlk) +{ + float mu; + + mu = (D_00264840[amtlk[0]][1] + D_00264840[amtlk[1]][1]) / + (D_00264840[amtlk[0]][0] + D_00264840[amtlk[1]][0]); + if (mu < 0.0f) + { + mu = 0.0f; + } + if (g_grfcht & FCHT_LowFriction) + { + mu *= 0.2f; + } + return mu; +} INCLUDE_ASM("asm/nonmatchings/P2/mark", ElasFromAmtlk__FP4MTLK); diff --git a/src/P2/po.c b/src/P2/po.c index f7161a0b..aa4c442d 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -29,7 +29,27 @@ INCLUDE_ASM("asm/nonmatchings/P2/po", HandlePoMessage__FP2PO5MSGIDPv); INCLUDE_ASM("asm/nonmatchings/P2/po", OnPoActive__FP2POiT0); -INCLUDE_ASM("asm/nonmatchings/P2/po", GetPoCpdefi__FP2POfP6CPDEFI); +extern SMP D_00269BC0; + +void GetPoCpdefi(PO *ppo, float dt, CPDEFI *pcpdefi) +{ + GetSoCpdefi((SO *)ppo, dt, pcpdefi); + + if (STRUCT_OFFSET(ppo, 0x554, int) != 0) + { + STRUCT_OFFSET(pcpdefi, 0x10, VU_VECTOR) = STRUCT_OFFSET(ppo, 0x560, VU_VECTOR); + } + else + { + if (g_pcm->field41_0x224 == 0) + { + pcpdefi->posBase.z = GSmooth(STRUCT_OFFSET(ppo, 0x568, float), + STRUCT_OFFSET(ppo, 0x148, float), + dt, &D_00269BC0, NULL); + } + STRUCT_OFFSET(ppo, 0x560, VU_VECTOR) = STRUCT_OFFSET(pcpdefi, 0x10, VU_VECTOR); + } +} int FIsPoSoundBase(PO *ppo) { diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 128d02c8..f2166c67 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -221,7 +221,20 @@ void ImpactClue(CLUE *pclue, int fParentDirty) ImpactSo(pclue, fParentDirty); } -INCLUDE_ASM("asm/nonmatchings/P2/pzo", FAbsorbClueWkr__FP4CLUEP3WKR); +int FAbsorbClueWkr(CLUE *pclue, WKR *pwkr) +{ + if (pwkr->grfic & 0x8) + { + ((void (*)(CLUE *, int))STRUCT_OFFSET(pclue->pvtlo, 0x64, void *))(pclue, 0); + SetSoConstraints(pclue, CT_Free, 0, CT_Locked, 0); + } + FAbsorbSoWkr(pclue, pwkr); + if (pwkr->grfic & 0x10) + { + ((void (*)(CLUE *))STRUCT_OFFSET(pclue->pvtlo, 0x134, void *))(pclue); + } + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/pzo", RenderClueAll__FP4CLUEP2CMP2RO); diff --git a/src/P2/rip.c b/src/P2/rip.c index 424b0042..38562fcc 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -2,6 +2,7 @@ #include #include #include +#include RIPG *PripgNew(SW *psw, RIPGT ripgt) { @@ -89,7 +90,35 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", UpdateRip__FP3RIPf); INCLUDE_ASM("asm/nonmatchings/P2/rip", FRenderRipPosMat__FP3RIPP2CMP6VECTORP7MATRIX3); -INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderRip__FP3RIPP2CM); +void RenderRip(RIP *prip, CM *pcm) +{ + VECTOR pos; + MATRIX3 mat; + VECTOR *ppos; + MATRIX3 *pmat; + WR *pwr; + + pwr = STRUCT_OFFSET(prip, 0x114, WR *); + if (pwr != NULL) + { + WarpWrTransform(pwr, 50.0f, + &STRUCT_OFFSET(prip, 0x80, VECTOR), + &STRUCT_OFFSET(prip, 0x50, MATRIX3), + &pos, &mat, NULL); + ppos = &pos; + pmat = &mat; + } + else + { + ppos = &STRUCT_OFFSET(prip, 0x80, VECTOR); + pmat = &STRUCT_OFFSET(prip, 0x50, MATRIX3); + } + + if (!FRenderRipPosMat(prip, pcm, ppos, pmat)) + { + RemoveRip(prip); + } +} void SubscribeRipObject(RIP *prip, LO *ploTarget) { From 3e31d647d1b9c5e1572e37917ea34b1ae6ac5c31 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 01:34:34 +0200 Subject: [PATCH 078/134] Match 10 functions via LHF harness (31-40 window, editable wave 4) ac/blip/dart/emitter/jt/po/rchm: EvaluateAkvb, GetAcgb/Acgbw/Acgl-Times, InitBlipg, OnDartAdd, AddExploSkeleton, FCheckJtXpBase, OnPoActive, TrackJtTarget. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/ac.c | 61 ++++++++++++++++++++++++++++++++++++++++++++---- src/P2/blip.c | 17 +++++++++++++- src/P2/dart.c | 19 ++++++++++++++- src/P2/emitter.c | 6 ++++- src/P2/jt.c | 25 +++++++++++++++++++- src/P2/po.c | 19 ++++++++++++++- src/P2/rchm.c | 21 ++++++++++++++++- 7 files changed, 158 insertions(+), 10 deletions(-) diff --git a/src/P2/ac.c b/src/P2/ac.c index 6630efae..84f59d55 100644 --- a/src/P2/ac.c +++ b/src/P2/ac.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/ac", FindKey__FfiiiPcPfT5PPv); @@ -68,19 +69,58 @@ INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAcgbFromBrx__FP4ACGBP18CBinaryInputStr INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateAcgb__FP4ACGBP3ALOffiPfT5); -INCLUDE_ASM("asm/nonmatchings/P2/ac", GetAcgbTimes__FP4ACGBPiPPf); +void GetAcgbTimes(ACGB *pacgb, int *pct, float **pat) +{ + int cct = STRUCT_OFFSET(pacgb, 0x8, int); + *pct = cct; + if (pat) + { + int i; + *pat = (float *)PvAllocStackImpl(cct << 2); + for (i = 0; i < *pct; i++) + { + (*pat)[i] = *(float *)((char *)STRUCT_OFFSET(pacgb, 0xC, void *) + i * 0x18); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAcgbwFromBrx__FP5ACGBWP18CBinaryInputStream); INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateAcgbw__FP5ACGBWP3ALOffiPfT5); -INCLUDE_ASM("asm/nonmatchings/P2/ac", GetAcgbwTimes__FP5ACGBWPiPPf); +void GetAcgbwTimes(ACGBW *pacgbw, int *pct, float **pat) +{ + int cct = STRUCT_OFFSET(pacgbw, 0x8, int); + *pct = cct; + if (pat) + { + int i; + *pat = (float *)PvAllocStackImpl(cct << 2); + for (i = 0; i < *pct; i++) + { + (*pat)[i] = *(float *)((char *)STRUCT_OFFSET(pacgbw, 0xC, void *) + i * 0x20); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateAcgl__FP4ACGLP3ALOffiPfT5); INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAcglFromBrx__FP4ACGLP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/ac", GetAcglTimes__FP4ACGLPiPPf); +void GetAcglTimes(ACGL *pacgl, int *pct, float **pat) +{ + int i; + + *pct = STRUCT_OFFSET(pacgl, 0x8, int); + if (pat) + { + *pat = (float *)PvAllocStackImpl(*pct * 4); + for (i = 0; i < *pct; i++) + { + (*pat)[i] = *(float *)((char *)STRUCT_OFFSET(pacgl, 0xc, char *) + i * 8); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateApacg__FPP3ACGP3ALOffiP6VECTORN25); @@ -88,7 +128,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadApacgFromBrx__FPP3ACGP6VECTORP18CBinar INCLUDE_ASM("asm/nonmatchings/P2/ac", GetApacgTimes__FPP3ACGPiPPf); -INCLUDE_ASM("asm/nonmatchings/P2/ac", EvaluateAkvb__FiP3KVBffiP6VECTORT5); +void EvaluateAkvb(int ckvb, KVB *akvb, float t, float svt, GRFEVAL grfeval, VECTOR *pvec, VECTOR *pdvec) +{ + float dt; + float dtSeg; + void *pkey; + + FindKey(t, grfeval, 0x40, ckvb, (char *)akvb, &dt, &dtSeg, &pkey); + EvaluateBezierPos(dtSeg, dt, svt, + (VECTOR *)((char *)pkey + 0x10), + (VECTOR *)((char *)pkey + 0x30), + (VECTOR *)((char *)pkey + 0x50), + (VECTOR *)((char *)pkey + 0x60), + pvec, pdvec, NULL); +} INCLUDE_ASM("asm/nonmatchings/P2/ac", LoadAkvbFromBrx__FPiPP3KVBP18CBinaryInputStream); diff --git a/src/P2/blip.c b/src/P2/blip.c index fec690c5..20daee6b 100644 --- a/src/P2/blip.c +++ b/src/P2/blip.c @@ -17,7 +17,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/blip", RemoveBlip__FP4BLIP); INCLUDE_ASM("asm/nonmatchings/P2/blip", PblipgNew__FP2SW); -INCLUDE_ASM("asm/nonmatchings/P2/blip", InitBlipg__FP5BLIPG); +void InitBlipg(BLIPG *pblipg) +{ + uint64_t flags; + + AppendDlEntry((DL *)((uint8_t *)STRUCT_OFFSET(pblipg, 0x14, void *) + 0x1CC0), pblipg); + InitAlo((ALO *)pblipg); + InitDl((DL *)((uint8_t *)pblipg + 0x624), 0x1090); + + flags = STRUCT_OFFSET(pblipg, 0x2C8, uint64_t); + flags &= 0xFFFFFFFFCFFFFFFFULL; + flags |= 0x20000000; + STRUCT_OFFSET(pblipg, 0x80, float) = 10000000000.0f; + flags &= 0xFFFFFCFFFFFFFFFFULL; + flags |= 0x10000000000ULL; + STRUCT_OFFSET(pblipg, 0x2C8, uint64_t) = flags; +} void OnBlipgAdd(BLIPG *pblipg) { diff --git a/src/P2/dart.c b/src/P2/dart.c index 085e0d21..630b25be 100644 --- a/src/P2/dart.c +++ b/src/P2/dart.c @@ -10,7 +10,24 @@ void InitDart(DART *pdart) SetDartDarts(pdart, DARTS_Nil); } -INCLUDE_ASM("asm/nonmatchings/P2/dart", OnDartAdd__FP4DART); +void OnDartAdd(DART *pdart) +{ + OnSoAdd(pdart); + + if (FFindDlEntry(&pdart->psw->dlDartFree, pdart)) + { + RemoveDlEntry(&pdart->psw->dlDartFree, pdart); + } + + if (STRUCT_OFFSET(pdart, 0x18, ALO *) && FIsBasicDerivedFrom((BASIC *)STRUCT_OFFSET(pdart, 0x18, ALO *), CID_IKH)) + { + STRUCT_OFFSET(pdart, 0x538, unsigned long long) |= ((unsigned long long)0x8000 << 28); + } + else + { + STRUCT_OFFSET(pdart, 0x538, unsigned long long) &= ~((unsigned long long)0x8000 << 28); + } +} void RemoveDart(DART *pdart) { diff --git a/src/P2/emitter.c b/src/P2/emitter.c index caa1ab49..cc1ba7e0 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -311,7 +311,11 @@ void ExplodeExploExplso(EXPLO *pexplo, EXPLSO *pexplso) return; } -INCLUDE_ASM("asm/nonmatchings/P2/emitter", AddExploSkeleton__FP5EXPLO3OIDT1ffff); +void AddExploSkeleton(EXPLO *pexplo, OID oid, OID oidOther, float sRadius, float gDensity, float sRadiusOther, float gDensityOther) +{ + EMITB *pemitb = PemitbEnsureExplo(pexplo, ENSK_Set); + AddEmitoSkeleton(&pemitb->emito, oid, oidOther, sRadius, gDensity, sRadiusOther, gDensityOther, pexplo); +} EMITB *PemitbEnsureExplo(EXPLO *pexplo, ENSK ensk) { diff --git a/src/P2/jt.c b/src/P2/jt.c index 0aa48e36..3146f840 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/jt", InitJt__FP2JT); @@ -19,7 +20,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", HandleJtGrfjtsc); INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtInternalXps__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/jt", FCheckJtXpBase__FP2JTP2XPi); +int FCheckJtXpBase(JT *pjt, XP *pxp, int ixpd) +{ + extern float D_00274AD0[]; + + if (pjt->jts != JTS_Max) + { + return FCheckStepXpBase(pjt, pxp, ixpd); + } + + if (STRUCT_OFFSET(pxp, 0x88, float) * D_00274AD0[ixpd] < 0.7f) + { + return 0; + } + + { + int n = STRUCT_OFFSET(pxp, 0x9C, int); + if (n >= 7) + return 0; + if (n < 4) + return 0; + return ixpd == 0; + } +} INCLUDE_ASM("asm/nonmatchings/P2/jt", AdjustJtXpVelocity__FP2JTP2XPi); diff --git a/src/P2/po.c b/src/P2/po.c index aa4c442d..40724964 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -1,6 +1,7 @@ #include #include #include +#include extern int g_ippoCur; extern PO *g_appo[]; @@ -27,7 +28,23 @@ void ClonePo(PO *ppo, PO *ppoBase) INCLUDE_ASM("asm/nonmatchings/P2/po", HandlePoMessage__FP2PO5MSGIDPv); -INCLUDE_ASM("asm/nonmatchings/P2/po", OnPoActive__FP2POiT0); +void OnPoActive(PO *ppo, int fActive, PO *ppoOther) +{ + if (fActive) + { + STRUCT_OFFSET(ppo, 0x560, VU_VECTOR) = STRUCT_OFFSET(ppo, 0x140, VU_VECTOR); + SetCmPolicy(g_pcm, CPP_Default, &STRUCT_OFFSET(g_pcm, 0x520, CPLCY), (SO *)ppo, 0); + } + else + { + int i; + + for (i = 1; i < 7; i++) + { + RevokeCmPolicy(g_pcm, 5, (CPP)i, 0, (SO *)ppo, 0); + } + } +} extern SMP D_00269BC0; diff --git a/src/P2/rchm.c b/src/P2/rchm.c index 96505c62..75646b30 100644 --- a/src/P2/rchm.c +++ b/src/P2/rchm.c @@ -1,4 +1,5 @@ #include +#include void InitRchm(RCHM *prchm) { @@ -40,6 +41,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/rchm", PtwrMapRchmSafe__FP4RCHMP3BSPP6VECTOR); INCLUDE_ASM("asm/nonmatchings/P2/rchm", FindRchmClosestPoint__FP4RCHMP6VECTORT1PP3TWRPf); -INCLUDE_ASM("asm/nonmatchings/P2/rchm", TrackJtTarget__FP2JTP4RCHMP6TARGET); +void TrackJtTarget(JT *pjt, RCHM *prchm, TARGET *ptarget) +{ + VECTOR posLocal; + VECTOR posClosest; + TWR *ptwr; + float s; + float dt; + + if (ptarget == NULL) + return; + + dt = STRUCT_OFFSET(pjt, 0x2424, float) - g_clock.t; + if (dt < g_clock.dt) + dt = g_clock.dt; + + PredictRchmTargetLocalPos(prchm, ptarget, dt, &posLocal); + FindRchmClosestPoint(prchm, &posLocal, &posClosest, &ptwr, &s); + ReblendRchm(prchm, ptwr, &posClosest); +} INCLUDE_ASM("asm/nonmatchings/P2/rchm", TrackJtPipe__FP2JTP4RCHMP4PIPEPf); From 061aa144f11b3626ea0a15e9e5534fa653fecebf Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 01:48:25 +0200 Subject: [PATCH 079/134] Match 3 functions via LHF harness (31-40 window, editable wave 5) screen/spliceobj/vifs: PostTotalsLoad, RefGetOption, UnpackHelper. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/screen.c | 24 +++++++++++++++++++++++- src/P2/spliceobj.c | 15 ++++++++++++++- src/P2/vifs.c | 19 ++++++++++++++++++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/P2/screen.c b/src/P2/screen.c index 574fd0ad..5a159f57 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -314,7 +314,29 @@ void FUN_001aca68(BLOT *pblot) INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawTitle__FP5TITLE); -INCLUDE_ASM("asm/nonmatchings/P2/screen", PostTotalsLoad__FP6TOTALS); +extern "C" CFont *FUN_0015c1c0(int i); +extern "C" int FUN_0015c188(int i); +extern CFont *D_00274410; + +void PostTotalsLoad(TOTALS *ptotals) +{ + CFont *pfont; + void *pv; + + PostBlotLoad((BLOT *)ptotals); + pfont = FUN_0015c1c0(0); + pv = STRUCT_OFFSET(pfont, 0x4c, void *); + STRUCT_OFFSET(ptotals, 0x4, int) = + (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( + (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), 1.0f, 1.0f); + STRUCT_OFFSET(ptotals, 0x20c, float) = 0.8f; + STRUCT_OFFSET(ptotals, 0x248, float) = 0.5f; + if (FUN_0015c188(2)) + { + STRUCT_OFFSET(ptotals, 0x210, CFont **) = &D_00274410; + *STRUCT_OFFSET(ptotals, 0x210, CFont **) = FUN_0015c1c0(2); + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ace38); diff --git a/src/P2/spliceobj.c b/src/P2/spliceobj.c index 6e1c5c9c..351eefea 100644 --- a/src/P2/spliceobj.c +++ b/src/P2/spliceobj.c @@ -16,7 +16,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefSetArgListFromPvs__FiP4OTYPPPv); INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefSetPeopid__FP5BASICP5EOPIDP4CRef); -INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefGetOption__FP5BASICi); +CRef RefGetOption(BASIC *pbasic, int optid) +{ + if (optid < 0x495) + { + EOPID *peopid = PeopidFind(pbasic, optid); + return RefGetPeopid(pbasic, peopid); + } + else + { + CRef ref; + pbasic->psidebag->FFindBinding(optid, &ref); + return ref; + } +} INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefSetOption__FP5BASICiP4CRef); diff --git a/src/P2/vifs.c b/src/P2/vifs.c index ce2682da..81ea8588 100644 --- a/src/P2/vifs.c +++ b/src/P2/vifs.c @@ -66,7 +66,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/vifs", AddVifStmask__4VIFSUi); INCLUDE_ASM("asm/nonmatchings/P2/vifs", CbUnpackSetup__4VIFS3UPKii); -INCLUDE_ASM("asm/nonmatchings/P2/vifs", UnpackHelper__4VIFS3UPKiiPiPPUi); +void VIFS::UnpackHelper(UPK upk, int c, int iqw, int *pcb, uint **ppun) +{ + if (c == 0) + { + if (ppun != NULL) + *ppun = 0; + if (pcb != NULL) + *pcb = 0; + return; + } + + int cb = CbUnpackSetup(upk, c, iqw); + if (ppun != NULL) + *ppun = (uint *)m_pb; + m_pb = m_pb + ((cb + 3) / 4) * 4; + if (pcb != NULL) + *pcb = cb; +} INCLUDE_ASM("asm/nonmatchings/P2/vifs", AddVifUnpack__4VIFS3UPKiPvi); From 42d8cb7a8f73bc114a06f711eaa34ee3dc1d0f2b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 02:02:52 +0200 Subject: [PATCH 080/134] Match 7 functions via LHF harness (41-60 window, editable wave 1) act/button/coin/lgn/sensor/steprail/wr: InitActval, PostBtnLoad, PostDprizeLoad, ApplyLgnThrow, PostCamsenLoad, FUN_001d3500, GFromOnz. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 21 ++++++++++++++++++++- src/P2/button.c | 19 ++++++++++++++++++- src/P2/coin.c | 21 ++++++++++++++++++++- src/P2/lgn.c | 17 ++++++++++++++++- src/P2/sensor.c | 27 ++++++++++++++++++++++++++- src/P2/steprail.c | 22 +++++++++++++++++++++- src/P2/wr.c | 24 +++++++++++++++++++++++- 7 files changed, 144 insertions(+), 7 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index 74f91907..996744f6 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -91,7 +91,26 @@ void AdaptAct(ACT *pact) STRUCT_OFFSET(pact, 0x11, char) = 3; } -INCLUDE_ASM("asm/nonmatchings/P2/act", InitActval__FP6ACTVALP3ALO); +void InitActval(ACTVAL *pactval, ALO *palo) +{ + uint8_t *psen; + + InitAct(pactval, palo); + *(qword *)((uint8_t *)pactval + 0x20) = *(qword *)((uint8_t *)palo + 0x190); + *(qword *)((uint8_t *)pactval + 0x40) = *(qword *)((uint8_t *)palo + 0x1a0); + *(qword *)((uint8_t *)pactval + 0x50) = *(qword *)((uint8_t *)palo + 0x1b0); + *(qword *)((uint8_t *)pactval + 0x60) = *(qword *)((uint8_t *)palo + 0x1c0); + psen = STRUCT_OFFSET(palo, 0x224, uint8_t *); + if (psen != 0 && (STRUCT_OFFSET(psen, 0xb0, int) & 0x20)) + { + pactval->radTwistGoal = STRUCT_OFFSET(psen, 0x8c, float); + } + *(qword *)((uint8_t *)pactval + 0x90) = *(qword *)(D_002483D0 + 0x0); + *(qword *)((uint8_t *)pactval + 0xa0) = *(qword *)(D_002483D0 + 0x10); + *(qword *)((uint8_t *)pactval + 0xb0) = *(qword *)(D_002483D0 + 0x20); + STRUCT_OFFSET(pactval, 0xc0, int) = STRUCT_OFFSET(palo, 0x26c, int); + STRUCT_OFFSET(pactval, 0xc4, int) = STRUCT_OFFSET(palo, 0x274, int); +} INCLUDE_ASM("asm/nonmatchings/P2/act", GetActvalPositionGoal__FP6ACTVALfP6VECTORT2); diff --git a/src/P2/button.c b/src/P2/button.c index 7ca20a5e..be7e6615 100644 --- a/src/P2/button.c +++ b/src/P2/button.c @@ -33,7 +33,24 @@ void InitBtn(BTN *pbtn) INCLUDE_ASM("asm/nonmatchings/P2/button", LoadBtn__FP3BTNP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/button", PostBtnLoad__FP3BTN); +void PostBtnLoad(BTN *pbtn) +{ + int iash; + SW *psw; + + pbtn->buttons = (BUTTONS)-1; + psw = pbtn->paloOwner->psw; + + for (iash = 0; iash < IASH_Max; iash++) + { + PostAshLoad(psw, &pbtn->aash[iash], pbtn->paloOwner); + } + + if (pbtn->fCheckpointed && FGetChkmgrIchk(&g_chkmgr, pbtn->ichkPushed)) + { + PostSwCallback(psw, (PFNMQ)RestoreBtnFromCheckpointCallback, pbtn, MSGID_callback, NULL); + } +} void RestoreBtnFromCheckpointCallback(BTN *pbtn, MSGID msgid, void *pv) { diff --git a/src/P2/coin.c b/src/P2/coin.c index 52cf4063..eb726bda 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include void InitDprize(DPRIZE *pdprize) { @@ -36,7 +38,24 @@ void CloneDprize(DPRIZE *pdprize, DPRIZE *pdprizeBase) pdprize->ichkCollected = ichkCollected; } -INCLUDE_ASM("asm/nonmatchings/P2/coin", PostDprizeLoad__FP6DPRIZE); +void PostDprizeLoad(DPRIZE *pdprize) +{ + LO *plo; + + PostAloLoad(pdprize); + plo = PloFindSwObjectByClass(pdprize->psw, 1, (CID)0x75, (LO *)pdprize); + pdprize->ptarget = (TARGET *)plo; + if (plo != NULL) + { + (*(void (**)(LO *))((char *)plo->pvtlo + 0x1C))(plo); + } + if (((STRUCT_OFFSET(g_pgsCur, 0x19D8, int) << 8) | STRUCT_OFFSET(g_pgsCur, 0x19DC, int)) != 0x308) + { + if (FGetChkmgrIchk(&g_chkmgr, pdprize->ichkCollected)) + pdprize->dprizesInit = DPRIZES_Removed; + } + (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, pdprize->dprizesInit); +} INCLUDE_ASM("asm/nonmatchings/P2/coin", ProjectDprizeTransform__FP6DPRIZEfi); diff --git a/src/P2/lgn.c b/src/P2/lgn.c index f04d5466..c5c2d112 100644 --- a/src/P2/lgn.c +++ b/src/P2/lgn.c @@ -2,6 +2,7 @@ #include #include #include +#include void InitLgn(LGN *plgn) { @@ -36,7 +37,21 @@ void UseLgnCharm(LGN *plgn) SetLgnLgns(plgn, LGNS_Active); } -INCLUDE_ASM("asm/nonmatchings/P2/lgn", ApplyLgnThrow__FP3LGNP2PO); +extern VECTOR D_00264180; +extern float D_00264190; + +void ApplyLgnThrow(LGN *plgn, PO *ppo) +{ + VECTOR posTarget; + VECTOR v; + + ConvertAloPos((ALO *)plgn, NULL, &D_00264180, &posTarget); + CalculateSoTrajectoryApex((SO *)ppo, &posTarget, D_00264190, &v); + (*(void (**)(SO *, VECTOR *))(*(uint8_t **)ppo + 0x90))((SO *)ppo, &v); + STRUCT_OFFSET(ppo, 0x638, float) = RadNormalize(atan2f(v.y, v.x) + 3.1415927f); + FixStepAngularVelocity((STEP *)ppo); + SetJtJts((JT *)ppo, JTS_Sidestep, (JTBS)0x2B); +} INCLUDE_ASM("asm/nonmatchings/P2/lgn", FTakeLgnDamage__FP3LGNP3ZPR); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 86080bdd..269886b3 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -204,7 +204,32 @@ void InitCamsen(CAMSEN *pcamsen) STRUCT_OFFSET(pcamsen, 0x5D8, int) = -1; } -INCLUDE_ASM("asm/nonmatchings/P2/sensor", PostCamsenLoad__FP6CAMSEN); +void PostCamsenLoad(CAMSEN *pcamsen) +{ + void *pvt; + void (*pfn)(CAMSEN *, int); + extern SNIP D_002744D8[2]; + + PostAloLoad(pcamsen); + SnipAloObjects(pcamsen, 2, D_002744D8); + + if (STRUCT_OFFSET(pcamsen, 0x5d0, int) == 0) + STRUCT_OFFSET(pcamsen, 0x5d0, int) = (int)pcamsen; + + if (STRUCT_OFFSET(pcamsen, 0x5d4, int) == 0) + STRUCT_OFFSET(pcamsen, 0x5d4, int) = STRUCT_OFFSET(pcamsen->psw, 0x1d14, int); + + if (STRUCT_OFFSET(pcamsen, 0x200, void *) != NULL) + STRUCT_OFFSET(STRUCT_OFFSET(pcamsen, 0x200, void *), 0x44, int) = 0; + + STRUCT_OFFSET(pcamsen, 0x538, ulong) |= ((ulong)0x8000) << 28; + + SetSoConstraints(pcamsen, CT_Locked, NULL, CT_Locked, NULL); + + pvt = STRUCT_OFFSET(pcamsen, 0x0, void *); + pfn = (void (*)(CAMSEN *, int))STRUCT_OFFSET(pvt, 0x144, void *); + pfn(pcamsen, STRUCT_OFFSET(pcamsen, 0x560, int)); +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateCamsen__FP6CAMSENf); diff --git a/src/P2/steprail.c b/src/P2/steprail.c index 0769ef19..9f327e5a 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -44,7 +44,27 @@ void FUN_001d34e0(uint8_t *param_1) FUN_001bc4d8(param_1, param_1 + 0x554); } -INCLUDE_ASM("asm/nonmatchings/P2/steprail", FUN_001d3500); +extern "C" int FUN_001d3500(SO *pso, WKR *pwkr) +{ + int fAbsorbed = FAbsorbSoWkr(pso, pwkr); + if (fAbsorbed != 0 && (pwkr->grfic & 0x20)) + { + LO *plo = pwkr->ploSource; + int g; + if (STRUCT_OFFSET(STRUCT_OFFSET(plo, 0x0, uint8_t *), 0x8, int) & 1) + { + g = STRUCT_OFFSET(plo, 0x50, int); + } + else + { + g = STRUCT_OFFSET(STRUCT_OFFSET(plo, 0x18, uint8_t *), 0x50, int); + } + func_001D32D8((int)pso, (JT *)pwkr->ploSource, g == (int)(long)g_pjt); + FreeSwXpList(STRUCT_OFFSET(pso, 0x14, SW *), STRUCT_OFFSET(pso, 0x554, XP *)); + STRUCT_OFFSET(pso, 0x554, XP *) = 0; + } + return fAbsorbed; +} INCLUDE_ASM("asm/nonmatchings/P2/steprail", FUN_001d35a8); diff --git a/src/P2/wr.c b/src/P2/wr.c index 2cdd9e11..60a23fa6 100644 --- a/src/P2/wr.c +++ b/src/P2/wr.c @@ -32,7 +32,29 @@ float UBias(float u, float v) return u / ((1.0f / v - 2.0f) * (1.0f - u) + 1.0f); } -INCLUDE_ASM("asm/nonmatchings/P2/wr", GFromOnz__FP3ONZ); +float GFromOnz(ONZ *ponz) +{ + float g = 0.0f; + float uAmplSum = 0.0f; + int i = 0; + + if (ponz->conze > 0) + { + ONZE *ponze = ponz->aonze; + do + { + float n = UNoise(ponze->gFreq, ponze->gPhase, ponze->uRandom); + float uAmpl = ponze->uAmpl; + ponze++; + i++; + g += uAmpl * n; + uAmplSum += uAmpl; + } while (i < ponz->conze); + } + + return ponz->lm.gMin + + UBias(g / uAmplSum, ponz->uBias) * (ponz->lm.gMax - ponz->lm.gMin); +} INCLUDE_ASM("asm/nonmatchings/P2/wr", UpdateWrMatrixes__FP2WR); From 450d61311db9357491a29dae9dc2413f18df47b4 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 02:17:21 +0200 Subject: [PATCH 081/134] Match 5 functions via LHF harness (41-60 window, editable wave 2) chkpnt/jsg/rip/turret/vifs: RestoreChkmgrFromCheckpoint, SetJsgTn, FBounceLeaf, UpdateTurretActive, AddVifUnpackRefs. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/chkpnt.c | 7 ++++++- src/P2/jsg.c | 28 +++++++++++++++++++++++++++- src/P2/rip.c | 18 +++++++++++++++++- src/P2/turret.c | 28 +++++++++++++++++++++++++++- src/P2/vifs.c | 14 +++++++++++++- 5 files changed, 90 insertions(+), 5 deletions(-) diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index eb37f806..b9d09c48 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -38,7 +38,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", SaveChkmgrCheckpoint__FP6CHKMGR3OIDT1) INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ReturnChkmgrToCheckpoint__FP6CHKMGR); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", RestoreChkmgrFromCheckpoint__FP6CHKMGR); +void RestoreChkmgrFromCheckpoint(CHKMGR *pchkmgr) +{ + pchkmgr->cbitChk = 0; + memcpy(&pchkmgr->abitChk, (char *)pchkmgr + 0x220, 0x204); + pchkmgr->fChkDirty = 0; +} int IchkAllocChkmgr(CHKMGR *pchkmgr) { diff --git a/src/P2/jsg.c b/src/P2/jsg.c index 4c2259fc..f472771e 100644 --- a/src/P2/jsg.c +++ b/src/P2/jsg.c @@ -17,7 +17,33 @@ INCLUDE_ASM("asm/nonmatchings/P2/jsg", GetJsgLocation__FP3JSGP2LOP6VECTORPf); INCLUDE_ASM("asm/nonmatchings/P2/jsg", SetJsgFocus__FP3JSGP2LO); -INCLUDE_ASM("asm/nonmatchings/P2/jsg", SetJsgTn__FP3JSGP2TN); +extern void FUN_001e2840(TN *ptn, TNS tns); + +void SetJsgTn(JSG *pjsg, TN *ptn) +{ + if (pjsg->ptnCur != NULL) + { + FUN_001e2840(pjsg->ptnCur, TNS_Nil); + STRUCT_OFFSET(pjsg->ptnCur, 0x2d0, int) = 0; + if (pjsg->fHideTn != 0) + { + (*(void (**)(LO *))((char *)pjsg->ptnCur->pvtlo + 0x1c))((LO *)pjsg->ptnCur); + } + pjsg->ptnCur = NULL; + } + + if (ptn != NULL) + { + pjsg->ptnCur = ptn; + pjsg->fHideTn = (FIsLoInWorld(ptn) == 0); + if (pjsg->fHideTn != 0) + { + (*(void (**)(LO *))((char *)ptn->pvtlo + 0x18))((LO *)ptn); + } + STRUCT_OFFSET(ptn, 0x2d0, JT *) = pjsg->pjt; + FUN_001e2840(ptn, TNS_In); + } +} INCLUDE_ASM("asm/nonmatchings/P2/jsg", NextJsgJsge__FP3JSG); diff --git a/src/P2/rip.c b/src/P2/rip.c index 38562fcc..09667d64 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -280,7 +280,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", PostLeafEmit__FP4LEAFP5EMITB); INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectLeafTransform__FP4LEAFf); -INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceLeaf__FP4LEAFP2SOP6VECTORT2); +int FBounceLeaf(LEAF *pleaf, SO *psoOther, VECTOR *ppos, VECTOR *pnormal) +{ + STUCK *pstuck; + + if (FIsBasicDerivedFrom(STRUCT_OFFSET(psoOther, 0x50, BASIC *), CID_MISSILE)) + return 0; + if (FIsBasicDerivedFrom(STRUCT_OFFSET(psoOther, 0x50, BASIC *), CID_STEP)) + return 0; + + CreateStuck((RIP *)pleaf, STRUCT_OFFSET(pleaf, 0x20, ALO *), psoOther, ppos, pnormal, &pstuck); + if (pstuck != NULL) + { + ConvertAloMat(NULL, psoOther, &STRUCT_OFFSET(pstuck, 0x50, MATRIX3), &STRUCT_OFFSET(pstuck, 0x50, MATRIX3)); + } + RemoveRip((RIP *)pleaf); + return 1; +} int FFilterFlameObjects(void *pv, SO *pso) { diff --git a/src/P2/turret.c b/src/P2/turret.c index ab1ab783..de347a24 100644 --- a/src/P2/turret.c +++ b/src/P2/turret.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/turret", InitTurret__FP6TURRET); @@ -12,7 +14,31 @@ INCLUDE_ASM("asm/nonmatchings/P2/turret", PostTurretLoad__FP6TURRET); INCLUDE_ASM("asm/nonmatchings/P2/turret", UpdateTurret__FP6TURRETf); -INCLUDE_ASM("asm/nonmatchings/P2/turret", UpdateTurretActive__FP6TURRETP3JOYf); +void UpdateTurretActive(TURRET *pturret, JOY *pjoy, float dt) +{ + char b[0xC4]; + + UpdateTurretAim(pturret); + + if ((pjoy->grfbtnPressed & 0xC0) != 0) + { + SetJoyBtnHandled(pjoy, 0xC0); + FireTurret(pturret); + } + + if (g_pjt != NULL && STRUCT_OFFSET(g_pjt, 0x2740, int) != 0) + { + if (FIsLoInWorld(g_pjt)) + { + void (*pfn)(JT *, void *, float); + + memset(b, 0, 0xC4); + pfn = (void (*)(JT *, void *, float))STRUCT_OFFSET(g_pjt->pvtlo, 0x134, void *); + if (pfn != 0) + pfn(g_pjt, b, dt); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/turret", OnTurretActive__FP6TURRETiP2PO); diff --git a/src/P2/vifs.c b/src/P2/vifs.c index 81ea8588..a69a66e4 100644 --- a/src/P2/vifs.c +++ b/src/P2/vifs.c @@ -87,7 +87,19 @@ void VIFS::UnpackHelper(UPK upk, int c, int iqw, int *pcb, uint **ppun) INCLUDE_ASM("asm/nonmatchings/P2/vifs", AddVifUnpack__4VIFS3UPKiPvi); -INCLUDE_ASM("asm/nonmatchings/P2/vifs", AddVifUnpackRefs__4VIFS3UPKiPviPPPv); +void VIFS::AddVifUnpackRefs(UPK upk, int c, void *pvSrc, int iqw, void ***pppv) +{ + if (c == 0) + return; + + Align(3); + + int cb = CbUnpackSetup(upk, c, iqw); + AddDmaRefs((cb + 15) / 16, (QW *)pvSrc); + + if (pppv != NULL) + *pppv = (void **)((char *)m_pqwCnt - 0xC); +} /** * @todo Figure out why using the inlined function doesn't work here. From a2da9771f0973d9758c471f6bf5be434aee55288 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 02:31:56 +0200 Subject: [PATCH 082/134] Match 6 functions via LHF harness (41-60 window, editable wave 3) blip/crv/rip/smartguard/step/wm: PblipNew, UFromCrvcS, UpdateRip, FFilterSmartguardDetect, FUN_001c4790, RenderWmAll. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/blip.c | 37 ++++++++++++++++++++++++++++++++++++- src/P2/crv.c | 18 +++++++++++++++++- src/P2/rip.c | 31 ++++++++++++++++++++++++++++++- src/P2/smartguard.c | 37 ++++++++++++++++++++++++++++++++++++- src/P2/step.c | 31 ++++++++++++++++++++++++++++++- src/P2/wm.c | 14 +++++++++++++- 6 files changed, 162 insertions(+), 6 deletions(-) diff --git a/src/P2/blip.c b/src/P2/blip.c index 20daee6b..e1a72a18 100644 --- a/src/P2/blip.c +++ b/src/P2/blip.c @@ -1,4 +1,5 @@ #include +#include extern QW *g_aqwBlipeGifsNormal; extern QW *g_aqwBlipeGifsClampedAdd; @@ -11,7 +12,41 @@ void StartupBlips() BuildBlipAqwGifs(2, &g_aqwBlipeGifsClampedAdd); } -INCLUDE_ASM("asm/nonmatchings/P2/blip", PblipNew__FP5BLIPG); +BLIP *PblipNew(BLIPG *pblipg) +{ + BLIP *pblip; + void *pv; + + pblip = (BLIP *)PvAllocSlotheapUnsafe( + (SLOTHEAP *)((uint8_t *)STRUCT_OFFSET(pblipg, 0x14, void *) + 0x1B40)); + if (pblip == NULL) + return NULL; + + memset(pblip, 0, 0x10C0); + + if (STRUCT_OFFSET(pblipg, 0x320, int) == 2) + { + pv = PvAllocSlotheapUnsafe( + (SLOTHEAP *)((uint8_t *)STRUCT_OFFSET(pblipg, 0x14, void *) + 0x1B4C)); + STRUCT_OFFSET(pblip, 0x1088, void *) = pv; + if (pv == NULL) + { + FreeSlotheapPv( + (SLOTHEAP *)((uint8_t *)STRUCT_OFFSET(pblipg, 0x14, void *) + 0x1B40), + pblip); + return NULL; + } + memset(pv, 0, 0x580); + STRUCT_OFFSET(pblip, 0x108C, BLIPG *) = pblipg; + } + else + { + STRUCT_OFFSET(pblip, 0x108C, BLIPG *) = pblipg; + } + + AppendDlEntry((DL *)((uint8_t *)pblipg + 0x624), pblip); + return pblip; +} INCLUDE_ASM("asm/nonmatchings/P2/blip", RemoveBlip__FP4BLIP); diff --git a/src/P2/crv.c b/src/P2/crv.c index 1e4ca036..0f609b4a 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -219,7 +219,23 @@ float SFromCrvcU(CRVC *pcrvc, float u) STRUCT_OFFSET(pcrvc, 0x14, float *)[icv]; } -INCLUDE_ASM("asm/nonmatchings/P2/crv", UFromCrvcS__FP4CRVCf); +float UFromCrvcS(CRVC *pcrvc, float s) +{ + int icv; + int ipos; + float g; + float dg; + float dgSeg; + float u; + float *pmp; + + icv = IcvFindCrvS((CRV *)pcrvc, s, &g, NULL); + FillCrvcCache(pcrvc, icv); + ipos = IposFindAposG(g, 0x14, &STRUCT_OFFSET(pcrvc, 0x170, float), 0, &dg, &dgSeg); + pmp = STRUCT_OFFSET(pcrvc, 0x10, float *); + u = ((float)ipos + dg / dgSeg) * (1.0f / 19.0f); + return (1.0f - u) * pmp[icv] + u * pmp[icv + 1]; +} INCLUDE_ASM("asm/nonmatchings/P2/crv", MeasureCrvc__FP4CRVC); diff --git a/src/P2/rip.c b/src/P2/rip.c index 09667d64..2e0ce35f 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -3,6 +3,7 @@ #include #include #include +#include RIPG *PripgNew(SW *psw, RIPGT ripgt) { @@ -86,7 +87,35 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceRip__FP3RIPP2SOP6VECTORT2); INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectRipTransform__FP3RIPf); -INCLUDE_ASM("asm/nonmatchings/P2/rip", UpdateRip__FP3RIPf); +void UpdateRip(RIP *prip, float dt) +{ + int fInBsp; + RIPG *pripg; + + if (STRUCT_OFFSET(prip, 0x1c, float) < g_clock.t - STRUCT_OFFSET(prip, 0x18, float)) + { + RemoveRip(prip); + return; + } + + pripg = prip->pripg; + if (STRUCT_OFFSET(pripg, 0x550, int) == 1) + return; + + if (STRUCT_OFFSET(prip, 0x24, ALO *) == NULL) + return; + if (STRUCT_OFFSET(STRUCT_OFFSET(prip, 0x24, ALO *), 0x3f8, BSP *) == NULL) + return; + + fInBsp = 0; + if (FIsLoInWorld((LO *)STRUCT_OFFSET(prip, 0x24, ALO *))) + { + if (PbspPointInBspQuick(&STRUCT_OFFSET(prip, 0x80, VECTOR), STRUCT_OFFSET(STRUCT_OFFSET(prip, 0x24, ALO *), 0x3f8, BSP *))) + fInBsp = 1; + } + + (*(void (**)(RIP *, int))((uint8_t *)STRUCT_OFFSET(prip, 0x0, void *) + 0x18))(prip, fInBsp); +} INCLUDE_ASM("asm/nonmatchings/P2/rip", FRenderRipPosMat__FP3RIPP2CMP6VECTORP7MATRIX3); diff --git a/src/P2/smartguard.c b/src/P2/smartguard.c index 161b8f17..817b10f9 100644 --- a/src/P2/smartguard.c +++ b/src/P2/smartguard.c @@ -27,7 +27,42 @@ void FUN_001B7100(SMARTGUARD *p, int val) INCLUDE_ASM("asm/nonmatchings/P2/smartguard", PostSmartguardLoad__FP10SMARTGUARD); -INCLUDE_ASM("asm/nonmatchings/P2/smartguard", FFilterSmartguardDetect__FP10SMARTGUARDP2SO); +int FFilterSmartguardDetect(SMARTGUARD *psmartguard, SO *pso) +{ + int i; + int c; + + if (STRUCT_OFFSET(pso, 0x538, long long) & 0x80000000000LL) + { + return 0; + } + + if (FIsBasicDerivedFrom(pso->paloRoot, CID_PO)) + { + return 0; + } + + if (FIsBasicDerivedFrom(pso->paloRoot, CID_UBV)) + { + return 0; + } + + c = STRUCT_OFFSET(psmartguard, 0xcd4, int); + if (c > 0) + { + i = 0; + do + { + if (FFindLoParent(pso, STRUCT_OFFSET(psmartguard, 0xcdc + i * 8, ALO *))) + { + return 0; + } + i++; + } while (i < STRUCT_OFFSET(psmartguard, 0xcd4, int)); + } + + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/smartguard", FDetectSmartguard__FP10SMARTGUARD); diff --git a/src/P2/step.c b/src/P2/step.c index ed557efa..96a72002 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/step", InitStep__FP4STEP); @@ -11,7 +12,35 @@ INCLUDE_ASM("asm/nonmatchings/P2/step", LimitStepHands__FP4STEPi); // TODO: This might be "RetractStepExtremity". Further research needed. INCLUDE_ASM("asm/nonmatchings/P2/step", FUN_001c4618); -INCLUDE_ASM("asm/nonmatchings/P2/step", FUN_001c4790); +extern "C" { +void FUN_001c4790(void *p1, SO *pso, BSP *pbsp, void *p4) +{ + LSG alsg[2]; + int clsg; + int i; + + if (STRUCT_OFFSET(p4, 0x50, int) == 0) + return; + + clsg = ClsgClipEdgeToObjectPruned(pso, pbsp, (VECTOR *)((uint8_t *)p4 + 0x70), + (VECTOR *)((uint8_t *)p4 + 0x60), 2, alsg); + + i = 0; + if (clsg > 0) + { + if (alsg[0].au[0] == 0.0f) + i = 1; + } + + if (i < clsg) + { + if (alsg[i].au[0] < STRUCT_OFFSET(p4, 0xD0, float)) + { + *(LSG *)((uint8_t *)p4 + 0x90) = alsg[i]; + } + } +} +} INCLUDE_ASM("asm/nonmatchings/P2/step", FUN_001c4848); diff --git a/src/P2/wm.c b/src/P2/wm.c index 619a4532..49e2760c 100644 --- a/src/P2/wm.c +++ b/src/P2/wm.c @@ -33,7 +33,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/wm", CatchWmDisplayState__FP2WM); INCLUDE_ASM("asm/nonmatchings/P2/wm", UpdateWm__FP2WMf); -INCLUDE_ASM("asm/nonmatchings/P2/wm", RenderWmAll__FP2WMP2CMP2RO); +void RenderWmAll(WM *pwm, CM *pcm, RO *pro) +{ + RO ro; + float sNearFog = g_pcm->fgfn.sNearFog; + float duFogPlusClipBias = g_pcm->fgfn.duFogPlusClipBias; + + SetCmFov(g_pcm, 1.0f); + DupAloRo((ALO *)pwm, pro, &ro); + LoadMatrixFromPosRot((VECTOR *)((char *)pcm + 0x40), (MATRIX3 *)((char *)pcm + 0x80), &ro.mat); + RenderAloAll((ALO *)pwm, pcm, &ro); + SetCmFov(g_pcm, sNearFog); + g_pcm->fgfn.duFogPlusClipBias = duFogPlusClipBias; +} INCLUDE_ASM("asm/nonmatchings/P2/wm", HandleWmMessage__FP2WM5MSGIDPv); From bb530d7e183f65e5757cb9acea6b28ca44a7d3c9 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 02:44:58 +0200 Subject: [PATCH 083/134] Match 5 functions via LHF harness (41-60 window, editable wave 4) dartgun/emitter/rip/rog/rwm: SetDartgunGoalState, BindExpls, TouchDroplet, GrabbedRobRoh, FUN_001a84c8. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/dartgun.c | 29 ++++++++++++++++++++++++++++- src/P2/emitter.c | 34 +++++++++++++++++++++++++++++++++- src/P2/rip.c | 37 ++++++++++++++++++++++++++++++++++++- src/P2/rog.c | 11 ++++++++++- src/P2/rwm.c | 27 ++++++++++++++++++++++++++- 5 files changed, 133 insertions(+), 5 deletions(-) diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 72a6f95a..1a912a63 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -38,7 +38,34 @@ int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BreakDartgun__FP7DARTGUN); -INCLUDE_ASM("asm/nonmatchings/P2/dartgun", SetDartgunGoalState__FP7DARTGUN3OID); +void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) +{ + OID oidCur; + + GetSmaGoal(STRUCT_OFFSET(pdartgun, 0x740, SMA *), &oidCur); + if (oidCur == OID_Nil) + GetSmaCur(STRUCT_OFFSET(pdartgun, 0x740, SMA *), &oidCur); + + if (oidStateGoal == oidCur) + return; + + if (oidCur == (OID)0x2B7) + { + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x4C, int) = 0; + } + + if (oidStateGoal < (OID)0x2BA) + { + if (oidStateGoal >= (OID)0x2B8) + { + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = (oidStateGoal == (OID)0x2B9); + if ((unsigned int)(oidCur - 0x2BA) >= 2) + STRUCT_OFFSET(pdartgun, 0x6D8, int) = 0; + } + } + + SetSmaGoal(STRUCT_OFFSET(pdartgun, 0x740, SMA *), oidStateGoal); +} INCLUDE_ASM("asm/nonmatchings/P2/dartgun", TrackDartgun__FP7DARTGUNP3OID); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index cc1ba7e0..a43c5cf8 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include extern float DAT_0024a124; @@ -329,7 +331,37 @@ EMITB *PemitbEnsureExplo(EXPLO *pexplo, ENSK ensk) INCLUDE_ASM("asm/nonmatchings/P2/emitter", InitExpls__FP5EXPLS); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindExpls__FP5EXPLS); +void BindExpls(EXPLS *pexpls) +{ + EMITB *pemitb; + LO *plo; + + BindExplo(pexpls); + + if (STRUCT_OFFSET(pexpls, 0xAC, int) == -1 && + STRUCT_OFFSET(pexpls, 0xB0, long long) == -1) + return; + + pemitb = PemitbEnsureExplo(pexpls, ENSK_Set); + + if (STRUCT_OFFSET(pexpls, 0xAC, int) != -1) + STRUCT_OFFSET(pemitb, 0x1D8, LO *) = + PloFindSwObject(STRUCT_OFFSET(pexpls, 0x14, SW *), 0x104, + STRUCT_OFFSET(pexpls, 0xAC, OID), (LO *)pexpls); + + if (STRUCT_OFFSET(pexpls, 0xB0, int) != -1) + STRUCT_OFFSET(pemitb, 0x1DC, LO *) = + PloFindSwObject(STRUCT_OFFSET(pexpls, 0x14, SW *), 0x104, + STRUCT_OFFSET(pexpls, 0xB0, OID), (LO *)pexpls); + + if (STRUCT_OFFSET(pexpls, 0xB4, int) != -1) + { + plo = PloFindSwObject(STRUCT_OFFSET(pexpls, 0x14, SW *), 0x104, + STRUCT_OFFSET(pexpls, 0xB4, OID), (LO *)pexpls); + if (FIsBasicDerivedFrom((BASIC *)plo, CID_SO)) + STRUCT_OFFSET(pemitb, 0x1E0, LO *) = plo; + } +} void HandleExplsMessage(EXPLS *pexpls, MSGID msgid, void *pv) { diff --git a/src/P2/rip.c b/src/P2/rip.c index 2e0ce35f..7a9f0f38 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -166,7 +166,42 @@ void UnsubscribeRipStruct(RIP *prip, PFNMQ pfnmq, void *pvContext) INCLUDE_ASM("asm/nonmatchings/P2/rip", InitDroplet__FP7DROPLETP6VECTORfP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/rip", TouchDroplet__FP7DROPLETi); +void TouchDroplet(DROPLET *pdroplet, int fTouching) +{ + LSG alsg[16]; + + if (fTouching) + { + *(VU_VECTOR *)alsg = STRUCT_OFFSET(pdroplet, 0x80, VU_VECTOR); + + BSP *pbsp = STRUCT_OFFSET(STRUCT_OFFSET(pdroplet, 0x24, ALO *), 0x3f8, BSP *); + if (pbsp) + { + ClsgClipEdgeToBsp( + pbsp, + (VECTOR *)((uint8_t *)pdroplet + 0x90), + (VECTOR *)((uint8_t *)pdroplet + 0x80), + NULL, 0x10, alsg); + } + + RIP *prip = PripNewRipg(RIPT_Ripple, NULL); + if (prip != NULL) + { + (*(void (**)(RIP *, VECTOR *, float, SO *))(STRUCT_OFFSET(prip, 0x0, void *)))( + prip, (VECTOR *)alsg, 40.0f, NULL); + STRUCT_OFFSET(prip, 0x1c, float) = 0.75f; + STRUCT_OFFSET(prip, 0x34, float) = 30.0f; + + void *p278 = STRUCT_OFFSET(STRUCT_OFFSET(pdroplet, 0x24, ALO *), 0x278, void *); + if (p278 != NULL) + { + STRUCT_OFFSET(prip, 0x114, int) = STRUCT_OFFSET(p278, 0xc, int); + } + } + + RemoveRip((RIP *)pdroplet); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rip", InitBublet__FP6BUBLETP6VECTORfP2SO); diff --git a/src/P2/rog.c b/src/P2/rog.c index c1609ae6..e8b73b8b 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -167,7 +167,16 @@ void SpawnedRobRoh(ROB *prob, ROH *proh) STRUCT_OFFSET(proh, 0x560, ROST *) = NULL; } -INCLUDE_ASM("asm/nonmatchings/P2/rog", GrabbedRobRoh__FP3ROBP3ROH); +void GrabbedRobRoh(ROB *prob, ROH *proh) +{ + extern VECTOR D_00248D30; + + (*(void (**)(SO *))(*(uint8_t **)STRUCT_OFFSET(proh, 0x55c, SO *) + 0x64))(STRUCT_OFFSET(proh, 0x55c, SO *)); + (*(void (**)(SO *, VECTOR *))(*(uint8_t **)STRUCT_OFFSET(proh, 0x55c, SO *) + 0x90))(STRUCT_OFFSET(proh, 0x55c, SO *), &D_00248D30); + (*(void (**)(SO *, VECTOR *))(*(uint8_t **)STRUCT_OFFSET(proh, 0x55c, SO *) + 0x94))(STRUCT_OFFSET(proh, 0x55c, SO *), &D_00248D30); + SetSoConstraints(STRUCT_OFFSET(proh, 0x55c, SO *), CT_Locked, NULL, CT_Locked, NULL); + StartSound((SFXID)0x151, NULL, NULL, NULL, 3000.0f, 300.0f, 1.0f, 0.0f, 0.0f, NULL, NULL); +} void DroppedRobRoh(ROB *prob, ROH *proh) { diff --git a/src/P2/rwm.c b/src/P2/rwm.c index 84f23231..8da41ded 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -29,7 +29,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a8150); INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwmCallback__FP3RWM5MSGIDPv); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a84c8); +extern "C" void FUN_001a84c8(RWM *prwmDst, RWM *prwmSrc) +{ + CloneLo((LO *)prwmDst, (LO *)prwmSrc); + if (STRUCT_OFFSET(prwmDst, 0x3c, void *) != 0 && + STRUCT_OFFSET(STRUCT_OFFSET(prwmDst, 0x3c, void *), 0x4, int) != 0) + { + if (STRUCT_OFFSET(STRUCT_OFFSET(prwmSrc, 0x3c, void *), 0x8, int) == 0) + { + STRUCT_OFFSET(STRUCT_OFFSET(prwmSrc, 0x3c, void *), 0x8, int) = 1; + InitDl((DL *)((uint8_t *)STRUCT_OFFSET(prwmSrc, 0x3c, void *) + 0x14), 0x18); + } + STRUCT_OFFSET(prwmDst, 0x3c, void *) = 0; + FUN_001a8110(prwmDst); + STRUCT_OFFSET(STRUCT_OFFSET(prwmDst, 0x3c, void *), 0x4, int) = 1; + STRUCT_OFFSET(STRUCT_OFFSET(prwmDst, 0x3c, void *), 0x8, int) = 2; + STRUCT_OFFSET(STRUCT_OFFSET(prwmDst, 0x3c, void *), 0x14, RWM *) = prwmSrc; + AppendDlEntry((DL *)((uint8_t *)STRUCT_OFFSET(prwmSrc, 0x3c, void *) + 0x14), + STRUCT_OFFSET(prwmDst, 0x3c, void *)); + } + else + { + STRUCT_OFFSET(prwmDst, 0x38, void *) = + PvAllocSwCopyImpl(STRUCT_OFFSET(prwmSrc, 0x34, int) * 0x14, + STRUCT_OFFSET(prwmSrc, 0x38, void *)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", PostRwmLoad__FP3RWM); From 19b46c095679c03d2851821dbc50f355c035d2f0 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 02:59:47 +0200 Subject: [PATCH 084/134] Match 4 functions via LHF harness (41-60 window, editable wave 5) emitter/freeze/rchm/rog: BindExplo, MergeSwGroup, TrackJtPipe, TakeRobRoc. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/emitter.c | 40 +++++++++++++++++++++++++++++++++++++++- src/P2/freeze.c | 22 +++++++++++++++++++++- src/P2/rchm.c | 23 ++++++++++++++++++++++- src/P2/rog.c | 36 +++++++++++++++++++++++++++++++++++- 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/src/P2/emitter.c b/src/P2/emitter.c index a43c5cf8..b122a265 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -306,7 +306,45 @@ void CloneExplo(EXPLO *pexplo, EXPLO *pexploBase) STRUCT_OFFSET(pexplo, 0x90, EMITB *)->cref++; } -INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindExplo__FP5EXPLO); +void BindExplo(EXPLO *pexplo) +{ + EMITB *pemitb; + EMITB *pemitbNew; + + if (STRUCT_OFFSET(pexplo, 0x94, int) == -1 && + STRUCT_OFFSET(pexplo, 0x98, int) == -1 && + STRUCT_OFFSET(STRUCT_OFFSET(pexplo, 0x90, EMITB *), 0x10, int) != 3) + { + EMITB *pemitbCur = STRUCT_OFFSET(pexplo, 0x90, EMITB *); + + if (STRUCT_OFFSET(pemitbCur, 0x120, int) != 0) + goto bind; + + if (STRUCT_OFFSET(pemitbCur, 0x188, int) == -1) + goto done; + } + + pemitbNew = PemitbEnsureExplo(pexplo, ENSK_Set); + + if (STRUCT_OFFSET(pexplo, 0x94, int) != -1) + { + STRUCT_OFFSET(pemitbNew, 0x7C, void *) = + PloFindSwObject(STRUCT_OFFSET(pexplo, 0x14, SW *), 0x104, + (OID)STRUCT_OFFSET(pexplo, 0x94, int), (LO *)pexplo); + } + + if (STRUCT_OFFSET(pexplo, 0x98, int) != -1) + { + LO *plo = PloFindSwObject(STRUCT_OFFSET(pexplo, 0x14, SW *), 0x104, + (OID)STRUCT_OFFSET(pexplo, 0x98, int), (LO *)pexplo); + STRUCT_OFFSET(pemitbNew, 0x20, int) = STRUCT_OFFSET(plo, 0x34, int); + STRUCT_OFFSET(pemitbNew, 0x7C, int) = STRUCT_OFFSET(plo, 0x18, int); + } + +done: +bind: + BindEmitb(STRUCT_OFFSET(pexplo, 0x90, EMITB *), (LO *)pexplo); +} void ExplodeExploExplso(EXPLO *pexplo, EXPLSO *pexplso) { diff --git a/src/P2/freeze.c b/src/P2/freeze.c index f8e3d1b2..951842fc 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -18,7 +18,27 @@ INCLUDE_ASM("asm/nonmatchings/P2/freeze", MergeSwFreezeGroups__FP2SWP3ALOT1); INCLUDE_ASM("asm/nonmatchings/P2/freeze", SplinterSwFreezeGroup__FP2SWP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/freeze", MergeSwGroup__FP2SWP3MRG); +void MergeSwGroup(SW *psw, MRG *pmrg) +{ + int i = 0; + int iFirst; + + while (i < pmrg->cpalo) + { + if (FIsLoInWorld((LO *)pmrg->apalo[i])) + break; + i++; + } + + iFirst = i; + for (; i < pmrg->cpalo; i++) + { + if (FIsLoInWorld((LO *)pmrg->apalo[i])) + { + MergeSwFreezeGroups(psw, pmrg->apalo[iFirst]->paloFreezeRoot, pmrg->apalo[i]->paloFreezeRoot); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/freeze", AddSwMergeGroup__FP2SWP3MRG); diff --git a/src/P2/rchm.c b/src/P2/rchm.c index 75646b30..9dbfd0f8 100644 --- a/src/P2/rchm.c +++ b/src/P2/rchm.c @@ -61,4 +61,25 @@ void TrackJtTarget(JT *pjt, RCHM *prchm, TARGET *ptarget) ReblendRchm(prchm, ptwr, &posClosest); } -INCLUDE_ASM("asm/nonmatchings/P2/rchm", TrackJtPipe__FP2JTP4RCHMP4PIPEPf); +void TrackJtPipe(JT *pjt, RCHM *prchm, PIPE *ppipe, float *psPipe) +{ + VECTOR posPipeLocal; + VECTOR posOnPipe; + VECTOR posWorld; + VECTOR posLocal; + TWR *ptwr; + float s; + + ConvertAloPos(NULL, ppipe->paloParent, (VECTOR *)((uint8_t *)pjt + 0x140), &posPipeLocal); + + if (STRUCT_OFFSET(STRUCT_OFFSET(ppipe, 0x34, void *), 0x0, void **)[0xc] != NULL) + { + (*(void (**)(void *, float, VECTOR *, int, VECTOR *, int, int, float *)) + (STRUCT_OFFSET(STRUCT_OFFSET(ppipe, 0x34, void **), 0x0, void **) + 0xc))( + STRUCT_OFFSET(ppipe, 0x34, void *), *psPipe, &posPipeLocal, 0, &posOnPipe, 0, 0, psPipe); + } + + ConvertAloPos(ppipe->paloParent, (ALO *)pjt, &posOnPipe, &posWorld); + FindRchmClosestPoint(prchm, &posWorld, &posLocal, &ptwr, &s); + ReblendRchm(prchm, ptwr, &posLocal); +} diff --git a/src/P2/rog.c b/src/P2/rog.c index e8b73b8b..c3e21167 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -202,7 +202,41 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", KilledRobRoh__FP3ROBP3ROH); INCLUDE_ASM("asm/nonmatchings/P2/rog", FChooseRobRoc__FP3ROBP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", TakeRobRoc__FP3ROBP3ROHP3ROC); +void TakeRobRoc(ROB *prob, ROH *proh, ROC *proc) +{ + ROC *procPrev = STRUCT_OFFSET(proh, 0x55c, ROC *); + if (procPrev != NULL) + { + if (procPrev == proc) + return; + } + + ROH *prohPrev = STRUCT_OFFSET(proc, 0x55c, ROH *); + STRUCT_OFFSET(proh, 0x55c, ROC *) = proc; + STRUCT_OFFSET(proc, 0x55c, ROH *) = proh; + + if (prohPrev == NULL) + { + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x368, DL), proc); + AppendDlEntry(&STRUCT_OFFSET(prob, 0x35c, DL), proc); + } + + if (procPrev != NULL) + { + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x35c, DL), procPrev); + AppendDlEntry(&STRUCT_OFFSET(prob, 0x368, DL), procPrev); + STRUCT_OFFSET(procPrev, 0x55c, ROH *) = NULL; + FChooseRobRoh(prob, procPrev); + } + + if (prohPrev != NULL) + { + STRUCT_OFFSET(prohPrev, 0x55c, ROC *) = NULL; + SetRohRohs(prohPrev, ROHS_Wander); + if (FChooseRobRoc(prob, prohPrev)) + SetRohRohs(prohPrev, ROHS_Collect); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rog", FChooseRobRoh__FP3ROBP3ROC); From 4031d2923ba989db7d1ae799a5533001e318911c Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 03:15:13 +0200 Subject: [PATCH 085/134] Match 4 functions via LHF harness (41-60 window, editable wave 6) dzg/emitter/frm/gs: InitDzg, ExplodeExplsExplso, CloseFrame, BuildImageGifs. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/dzg.c | 23 +++++++++++++++++++++-- src/P2/emitter.c | 32 +++++++++++++++++++++++++++++++- src/P2/frm.c | 28 +++++++++++++++++++++++++++- src/P2/gs.c | 10 +++++++++- 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/src/P2/dzg.c b/src/P2/dzg.c index 3e8654e1..f6bb0bf7 100644 --- a/src/P2/dzg.c +++ b/src/P2/dzg.c @@ -1,6 +1,25 @@ #include - -INCLUDE_ASM("asm/nonmatchings/P2/dzg", InitDzg__FP3DZGi); +#include +#include + +void InitDzg(DZG *pdzg, int cpxp) +{ + int c; + + memset(pdzg, 0, sizeof(DZG)); + c = cpxp * 2; + pdzg->cdzMax = c; + pdzg->adz = (DZ *)PvAllocStackImpl(c * 0x60); + memset(pdzg->adz, 0, c * 0x60); + InitDl(&pdzg->dlPos, 0x4C); + InitDl(&pdzg->dlZero, 0x4C); + InitDl(&pdzg->dlMax, 0x4C); + InitDl(&pdzg->dlUncat, 0x4C); + pdzg->aagPos = (float *)PvAllocStackImpl(c * c * 4); + pdzg->aagPosCrout = (float *)PvAllocStackImpl(c * c * 4); + pdzg->asdv = (float *)PvAllocStackImpl(cpxp * 8); + pdzg->adsfPos = (float *)PvAllocStackImpl(cpxp * 8); +} INCLUDE_ASM("asm/nonmatchings/P2/dzg", ClearDzgSolution__FP3DZG); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index b122a265..d8b79961 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include extern float DAT_0024a124; @@ -418,7 +421,34 @@ void HandleExplsMessage(EXPLS *pexpls, MSGID msgid, void *pv) } } -INCLUDE_ASM("asm/nonmatchings/P2/emitter", ExplodeExplsExplso__FP5EXPLSP6EXPLSO); +struct EXPLSOBLOB +{ + qword aqw[5]; +}; + +void ExplodeExplsExplso(EXPLS *pexpls, EXPLSO *pexplso) +{ + int fFired = 0; + + if (0.0f < STRUCT_OFFSET(pexpls, 0xB8, float)) + { + void *pv = PvAllocSlotheapUnsafe( + (SLOTHEAP *)((char *)STRUCT_OFFSET(pexpls, 0x14, SW *) + 0x1BD0)); + + if (pv != 0) + { + STRUCT_OFFSET(pv, 0x0, EXPLS *) = pexpls; + *(EXPLSOBLOB *)((char *)pv + 0x10) = *(EXPLSOBLOB *)pexplso; + fFired = 1; + STRUCT_OFFSET(pv, 0x60, float) = g_clock.t + STRUCT_OFFSET(pexpls, 0xB8, float); + ClearDle((DLE *)((char *)pv + 0x64)); + AppendDlEntry((DL *)((char *)STRUCT_OFFSET(pexpls, 0x14, SW *) + 0x1BDC), pv); + } + } + + if (!fFired) + FireExplsExplso(pexpls, pexplso); +} SFX *PsfxEnsureExpls(EXPLS *pexpls, ENSK ensk) { diff --git a/src/P2/frm.c b/src/P2/frm.c index 562ff8b5..ea7aff5a 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -6,6 +6,7 @@ #include #include #include +#include extern void *g_pvVu1Code; @@ -60,7 +61,32 @@ void FinalizeFrameGifs(GIFS *pgifs, int *pcqwGifs, QW **ppqwGifs) pgifs->Detach(pcqwGifs, ppqwGifs); } -INCLUDE_ASM("asm/nonmatchings/P2/frm", CloseFrame__Fv); +extern "C" int SignalSema(int sid); + +extern DL D_002622E0; +extern DL D_002622F0; +extern DL D_00262300; +extern int D_002622D0; +extern int D_002623B0; + +void CloseFrame() +{ + FinalizeFrameVifs(&g_vifs, &g_pfrmOpen->cqwVifs, 0); + FinalizeFrameGifs(&g_gifs, &g_pfrmOpen->cqwGifs, 0); + + STRUCT_OFFSET(g_pfrmOpen, 0x20, DL) = D_002622E0; + ClearDl(&D_002622E0); + + STRUCT_OFFSET(g_pfrmOpen, 0x2C, DL) = D_002622F0; + ClearDl(&D_002622F0); + + STRUCT_OFFSET(g_pfrmOpen, 0x38, DL) = D_00262300; + ClearDl(&D_00262300); + + D_002622D0 = 0; + g_pfrmOpen = 0; + SignalSema(D_002623B0); +} void PrepareGsForFrameRender(FRM *pfrm) { diff --git a/src/P2/gs.c b/src/P2/gs.c index 3168aa6d..3a48397b 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -89,7 +89,15 @@ int IgsAllocGsb(GSB *pgsb, int iCount) return igsOld; } -INCLUDE_ASM("asm/nonmatchings/P2/gs", BuildImageGifs__FiiiiiiP4GIFS); +void BuildImageGifs(int dbp, int dbw, int psm, int dsax, int dsay, int cqw, GIFS *pgifs) +{ + pgifs->AddPrimPack(0, 1, 0xE); + pgifs->PackAD(0x50, ((long)dbp << 32) | ((long)dbw << 48) | ((long)psm << 56)); + pgifs->PackAD(0x51, 0); + pgifs->PackAD(0x52, (long)dsax | ((long)dsay << 32)); + pgifs->PackAD(0x53, 0); + pgifs->AddImage(cqw); +} INCLUDE_ASM("asm/nonmatchings/P2/gs", BuildClutTex2__FP4CLUTi); From 399a44b61ce422ae2a384f1cbd432b7baa2c23d0 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 03:29:37 +0200 Subject: [PATCH 086/134] Match 5 functions via LHF harness (61-80 window, editable wave 1) bsp/gs/jt/po: CloneBspc, UploadBitmaps, EnableJtActadj, PsoGetJtEffect, CollectPoPrize. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/bsp.c | 24 +++++++++++++++- src/P2/gs.c | 31 +++++++++++++++++++- src/P2/jt.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++-- src/P2/po.c | 40 +++++++++++++++++++++++++- 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/src/P2/bsp.c b/src/P2/bsp.c index 056056dc..a00cd71f 100644 --- a/src/P2/bsp.c +++ b/src/P2/bsp.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/bsp", ClsgClipEdgeToBsp__FP3BSPP6VECTORT1PiiP3LSG); @@ -6,4 +7,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/bsp", PruneBsp__FP3BSPP6VECTORfPP3BSP); INCLUDE_ASM("asm/nonmatchings/P2/bsp", PbspPointInBspQuick__FP6VECTORP3BSP); -INCLUDE_ASM("asm/nonmatchings/P2/bsp", CloneBspc__FP4GEOMP4BSPCT0T1); +void CloneBspc(GEOM *pgeomSrc, BSPC *pbspcSrc, GEOM *pgeomDst, BSPC *pbspcDst) +{ + int ibsp; + + pbspcDst->cbsp = pbspcSrc->cbsp; + pbspcDst->cbspFull = pbspcSrc->cbspFull; + pbspcDst->absp = (BSP *)PvAllocSwImpl(pbspcSrc->cbsp * sizeof(BSP)); + + for (ibsp = 0; ibsp < pbspcDst->cbsp; ibsp++) + { + BSP *pbspSrc = &pbspcSrc->absp[ibsp]; + BSP *pbspDst = &pbspcDst->absp[ibsp]; + + pbspDst->psurf = (SURF *)((int)pgeomDst->asurf + ((int)pbspSrc->psurf - (int)pgeomSrc->asurf)); + pbspDst->pbspNeg = pbspSrc->pbspNeg + ? (BSP *)((int)pbspcDst->absp + ((int)pbspSrc->pbspNeg - (int)pbspcSrc->absp)) + : NULL; + pbspDst->pbspPos = pbspSrc->pbspPos + ? (BSP *)((int)pbspcDst->absp + ((int)pbspSrc->pbspPos - (int)pbspcSrc->absp)) + : NULL; + } +} diff --git a/src/P2/gs.c b/src/P2/gs.c index 3a48397b..cd4736ea 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/gs", BlendDisplayOnBufferMismatch__Fv); @@ -109,7 +110,35 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", BuildBmpGifs__FP3BMPiP4GIFS); INCLUDE_ASM("asm/nonmatchings/P2/gs", FBuildUploadBitmapGifs__FiP3GSBP4GIFS); -INCLUDE_ASM("asm/nonmatchings/P2/gs", UploadBitmaps__FiP3GSB); +extern int g_cclutUpload; +extern int g_cbmpUpload; +int FBuildUploadBitmapGifs(int grfzon, GSB *pgsb, GIFS *pgifs); + +void UploadBitmaps(GRFZON grfzon, GSB *pgsb) +{ + if (grfzon == 0) + return; + + { + GIFS gifs; + QW *pqw; + + InitStackImpl(); + gifs.AllocStack(((g_cclutUpload * 3 + g_cbmpUpload) << 3) | 4); + gifs.AddDmaCnt(); + if (FBuildUploadBitmapGifs(grfzon, pgsb, &gifs)) + { + gifs.AddPrimPack(0, 1, 0xE); + gifs.PackAD(0x3F, 0); + gifs.PackAD(0x61, 0); + gifs.AddPrimEnd(); + gifs.AddDmaEnd(); + gifs.Detach(NULL, &pqw); + SendDmaSyncGsFinish(g_pdcGif, pqw); + } + FreeStackImpl(); + } +} INCLUDE_ASM("asm/nonmatchings/P2/gs", PqwGifsBitmapUpload__Fi); diff --git a/src/P2/jt.c b/src/P2/jt.c index 3146f840..c862ec25 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/jt", InitJt__FP2JT); @@ -84,7 +85,62 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172b08); INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtBounds__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/jt", PsoGetJtEffect__FP2JTPi); +SO *PsoGetJtEffect(JT *pjt, int *pn) +{ + SO *pso; + + pso = STRUCT_OFFSET(pjt, 0x25D8, SO *); + if (pso != NULL) + { + if (FIsLoInWorld(pso)) + { + *pn = 0; + return STRUCT_OFFSET(pjt, 0x25D8, SO *); + } + } + + pso = STRUCT_OFFSET(pjt, 0x25E0, SO *); + if (pso != NULL) + { + if (FIsLoInWorld(pso)) + { + *pn = 1; + return STRUCT_OFFSET(pjt, 0x25E0, SO *); + } + } + + pso = STRUCT_OFFSET(pjt, 0x25DC, SO *); + if (pso != NULL) + { + if (FIsLoInWorld(pso)) + { + *pn = 2; + return STRUCT_OFFSET(pjt, 0x25DC, SO *); + } + } + + pso = STRUCT_OFFSET(pjt, 0x25E4, SO *); + if (pso != NULL) + { + if (FIsLoInWorld(pso)) + { + *pn = 2; + return STRUCT_OFFSET(pjt, 0x25E4, SO *); + } + } + + pso = STRUCT_OFFSET(pjt, 0x25E8, SO *); + if (pso != NULL) + { + if (FIsLoInWorld(pso)) + { + *pn = 1; + return STRUCT_OFFSET(pjt, 0x25E8, SO *); + } + } + + return NULL; +} INCLUDE_ASM("asm/nonmatchings/P2/jt", AddJtCustomXps__FP2JTP2SOiP3BSPT3PP2XP); @@ -111,7 +167,28 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtDrive__FP2JT); INCLUDE_ASM("asm/nonmatchings/P2/jt", ChooseJtPhys__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/jt", EnableJtActadj__FP2JTi); +void EnableJtActadj(JT *pjt, int grf) +{ + int a0; + int a2; + + if (STRUCT_OFFSET(pjt, 0x2500, void *) != NULL) + { + a0 = grf & 0x1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2500, char *), 0x10, char) = a0 ? 9 : -1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2504, char *), 0x10, char) = a0 ? 9 : -1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2508, char *), 0x10, char) = a0 ? 9 : -1; + a2 = grf & 0x2; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x250C, char *), 0x10, char) = a2 ? 9 : -1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2510, char *), 0x10, char) = a2 ? 9 : -1; + + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x24F8, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x24F8, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x618, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x618, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x61C, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x61C, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x610, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x610, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x614, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x614, void *)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/jt", SetJtJts__FP2JT3JTS4JTBS); diff --git a/src/P2/po.c b/src/P2/po.c index 40724964..c66f9d5b 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include extern int g_ippoCur; extern PO *g_appo[]; @@ -100,7 +102,43 @@ void FUN_00192498(PO *ppo, int *pi) *pi = pfn(ppo); } -INCLUDE_ASM("asm/nonmatchings/P2/po", CollectPoPrize__FP2PO3PCKP3ALO); +void CollectPoPrize(PO *ppo, PCK pck, ALO *palo) +{ + switch (pck) + { + case PCK_Key: + if (STRUCT_OFFSET(ppo, 0x5F0, ASEG *) != 0) + { + RIP *prip = PripNewRipg(RIPT_Match, NULL); + STRUCT_OFFSET(ppo, 0x5AC, RIP *) = prip; + STRUCT_OFFSET(ppo, 0x5D0, int) = 1; + if (prip != NULL) + { + void (*pfnInit)(RIP *, float, VECTOR *, int) = + (void (*)(RIP *, float, VECTOR *, int))STRUCT_OFFSET(STRUCT_OFFSET(prip, 0x0, void *), 0x0, void *); + pfnInit(prip, 1.0f, (VECTOR *)((uint8_t *)palo + 0x140), 0); + SubscribeRipObject(prip, (LO *)ppo); + STRUCT_OFFSET(prip, 0x1C, float) = TFindAsegLabel(STRUCT_OFFSET(ppo, 0x5F0, ASEG *), (OID)0x13F); + STRUCT_OFFSET(prip, 0x20, int) = STRUCT_OFFSET(ppo, 0x59C, int); + STRUCT_OFFSET(prip, 0xC0, qword) = STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x14, uint8_t *), 0x1EE0, qword); + STRUCT_OFFSET(prip, 0x134, ALO *) = palo; + } + { + void (*pfnPrize)(PO *, int) = + (void (*)(PO *, int))STRUCT_OFFSET(STRUCT_OFFSET(ppo, 0x0, void *), 0x14C, void *); + pfnPrize(ppo, 1); + } + } + break; + case PCK_Gold: + { + void (*pfnPrize)(PO *, int) = + (void (*)(PO *, int))STRUCT_OFFSET(STRUCT_OFFSET(ppo, 0x0, void *), 0x14C, void *); + pfnPrize(ppo, 2); + } + break; + } +} INCLUDE_ASM("asm/nonmatchings/P2/po", FUN_001925C0); From 51e84ac1b7c8e7dde08a4cd128884b1854ad097b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 03:46:31 +0200 Subject: [PATCH 087/134] Match 4 functions via LHF harness (61-80 window, editable wave 2) act/dartgun/eyes/rog: SnapAct, TrackDartgun, SetEyesEyess, DestroyedRobRoc. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 24 +++++++++++++++++++++++- src/P2/dartgun.c | 38 +++++++++++++++++++++++++++++++++++++- src/P2/eyes.c | 39 ++++++++++++++++++++++++++++++++++++++- src/P2/rog.c | 39 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index 996744f6..a0e37ff6 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -2,6 +2,7 @@ #include #include #include +#include ACT *PactNew(SW *psw, ALO *palo, VTACT *pvtact) { @@ -67,7 +68,28 @@ float GGetActPoseGoal(ACT *pact, int ipose) INCLUDE_ASM("asm/nonmatchings/P2/act", CalculateActDefaultAck__FP3ACT); -INCLUDE_ASM("asm/nonmatchings/P2/act", SnapAct__FP3ACTi); +void SnapAct(ACT *pact, int fForce) +{ + VECTOR pos; + VECTOR v; + MATRIX3 mat; + ALO *palo = pact->palo; + + if (pact == STRUCT_OFFSET(palo, 0x1ec, ACT *) && + (fForce != 0 || STRUCT_OFFSET(pact, 0x10, char) == 2)) + { + (*(void (**)(ACT *, float, VECTOR *, VECTOR *))((char *)pact->pvtact + 0x10))(pact, 0.0f, &pos, &v); + (*(void (**)(ALO *, VECTOR *))((char *)palo->pvtlo + 0x84))(palo, &pos); + (*(void (**)(ALO *, VECTOR *))((char *)palo->pvtlo + 0x90))(palo, &v); + } + if (pact == STRUCT_OFFSET(palo, 0x1f0, ACT *) && + (fForce != 0 || STRUCT_OFFSET(pact, 0x11, char) == 2)) + { + (*(void (**)(ACT *, float, MATRIX3 *, VECTOR *))((char *)pact->pvtact + 0x14))(pact, 0.0f, &mat, &pos); + (*(void (**)(ALO *, MATRIX3 *))((char *)palo->pvtlo + 0x88))(palo, &mat); + (*(void (**)(ALO *, VECTOR *))((char *)palo->pvtlo + 0x94))(palo, &pos); + } +} INCLUDE_ASM("asm/nonmatchings/P2/act", CalculateAloPositionSpring__FP3ALOfP6VECTORN22); diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 1a912a63..2192a8a6 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -1,5 +1,7 @@ #include #include +#include +#include void InitDartgun(DARTGUN *pdartgun) { @@ -67,7 +69,41 @@ void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) SetSmaGoal(STRUCT_OFFSET(pdartgun, 0x740, SMA *), oidStateGoal); } -INCLUDE_ASM("asm/nonmatchings/P2/dartgun", TrackDartgun__FP7DARTGUNP3OID); +void TrackDartgun(DARTGUN *pdartgun, OID *poidStateGoal) +{ + extern VECTOR D_00248D30; + + if (*poidStateGoal == (OID)0x2B8) + { + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = 0; + if (STRUCT_OFFSET(pdartgun, 0x6D0, float) < g_clock.t - STRUCT_OFFSET(pdartgun, 0x6D8, float)) + { + if (FPrepareDartgunToFire(pdartgun)) + *poidStateGoal = (OID)0x2BA; + } + } + else + { + LO *plo = STRUCT_OFFSET(pdartgun, 0x6E0, LO *); + if (plo == NULL || FIsLoInWorld(plo) == 0 || + STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x6E0, SO *), 0x550, int) == 3 || + STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x6E0, SO *), 0x550, int) == 4) + { + STRUCT_OFFSET(pdartgun, 0x6E0, RAT *) = PratGetDartgunRatTarget(pdartgun); + } + + if (STRUCT_OFFSET(pdartgun, 0x6E0, RAT *) != NULL) + { + SetActlaTarget((ACTLA *)STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), + (ALO *)STRUCT_OFFSET(pdartgun, 0x6E0, ALO *), &D_00248D30); + if (STRUCT_OFFSET(pdartgun, 0x6D0, float) < g_clock.t - STRUCT_OFFSET(pdartgun, 0x6D8, float)) + { + if (FPrepareDartgunToFire(pdartgun)) + *poidStateGoal = (OID)0x2BB; + } + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/dartgun", FPrepareDartgunToFire__FP7DARTGUN); diff --git a/src/P2/eyes.c b/src/P2/eyes.c index 0fc7e9e4..8cb23c9f 100644 --- a/src/P2/eyes.c +++ b/src/P2/eyes.c @@ -1,6 +1,7 @@ #include #include #include +#include void InitEyes(EYES *peyes, SAAF *psaaf) { @@ -50,7 +51,43 @@ void PostEyesLoad(EYES *peyes) SetEyesEyess(peyes, EYESS_Open); } -INCLUDE_ASM("asm/nonmatchings/P2/eyes", SetEyesEyess__FP4EYES5EYESS); +void SetEyesEyess(EYES *peyes, EYESS eyess) +{ + if (peyes->eyess == eyess) + return; + + switch (eyess) + { + case EYESS_Open: + { + int c = STRUCT_OFFSET(peyes, 0x5C, int); + STRUCT_OFFSET(peyes, 0x70, float) = (float)(c - 1) * STRUCT_OFFSET(peyes, 0x74, float); + STRUCT_OFFSET(peyes, 0x6C, float) = + (float)(c * 2) * (1.0f - STRUCT_OFFSET(peyes, 0x74, float)) / + STRUCT_OFFSET(peyes, 0x2C, float); + if (GRandInRange(0.0f, 1.0f) < STRUCT_OFFSET(peyes, 0x38, float)) + STRUCT_OFFSET(peyes, 0x68, float) = 0.0f; + else + STRUCT_OFFSET(peyes, 0x68, float) = + GRandInRange(STRUCT_OFFSET(peyes, 0x30, float), STRUCT_OFFSET(peyes, 0x34, float)); + break; + } + case EYESS_Closing: + break; + case EYESS_Closed: + { + int c = STRUCT_OFFSET(peyes, 0x5C, int); + if ((int)STRUCT_OFFSET(peyes, 0x70, float) != c - 1) + STRUCT_OFFSET(peyes, 0x70, float) = (float)(c - 1); + break; + } + case EYESS_Opening: + break; + } + + peyes->eyess = eyess; + STRUCT_OFFSET(peyes, 0x64, float) = g_clock.t; +} INCLUDE_ASM("asm/nonmatchings/P2/eyes", UpdateEyes__FP4EYESf); diff --git a/src/P2/rog.c b/src/P2/rog.c index c3e21167..17f74ca8 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -157,7 +157,44 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", AddRobRoh__FP3ROB); INCLUDE_ASM("asm/nonmatchings/P2/rog", AdjustRobDifficulty__FP3ROBf); -INCLUDE_ASM("asm/nonmatchings/P2/rog", DestroyedRobRoc__FP3ROBP3ROC); +void DestroyedRobRoc(ROB *prob, ROC *proc) +{ + int cRoc; + + cRoc = STRUCT_OFFSET(prob, 0x3c4, int) + 1; + STRUCT_OFFSET(prob, 0x3c4, int) = cRoc; + AdjustRobDifficulty(prob, (float)cRoc / (float)STRUCT_OFFSET(prob, 0x3b8, int)); + + if (STRUCT_OFFSET(proc, 0x55c, ROH *) != NULL) + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x35c, DL), proc); + else + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x368, DL), proc); + + AppendDlEntry(&STRUCT_OFFSET(prob, 0x374, DL), proc); + + if (STRUCT_OFFSET(proc, 0x55c, ROH *) != NULL) + { + if (FChooseRobRoc(prob, STRUCT_OFFSET(proc, 0x55c, ROH *))) + { + SetRohRohs(STRUCT_OFFSET(proc, 0x55c, ROH *), ROHS_Collect); + } + else + { + STRUCT_OFFSET(STRUCT_OFFSET(proc, 0x55c, ROH *), 0x55c, ROC *) = NULL; + SetRohRohs(STRUCT_OFFSET(proc, 0x55c, ROH *), ROHS_Wander); + } + } + + STRUCT_OFFSET(proc, 0x55c, ROH *) = NULL; + (*(void (**)(ROC *))((char *)((LO *)proc)->pvtlo + 0x1c))(proc); + + if (STRUCT_OFFSET(prob, 0x380, int) == STRUCT_OFFSET(prob, 0x624, int)) + { + STRUCT_OFFSET(prob, 0x634, float) = + g_clock.t + GRandInRange(STRUCT_OFFSET(prob, 0x62c, float), STRUCT_OFFSET(prob, 0x630, float)); + } + STRUCT_OFFSET(prob, 0x380, int) -= 1; +} void SpawnedRobRoh(ROB *prob, ROH *proh) { From a5564b955335a5eeefb9fd5c33a309f14d4c8c17 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 04:06:01 +0200 Subject: [PATCH 088/134] Match 3 functions via LHF harness (61-80 window, editable wave 3) freeze/prompt/pzo: FreezeAlo, FUN_00194278, CollectClue. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/freeze.c | 31 ++++++++++++++++++++++++++++++- src/P2/prompt.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/P2/pzo.c | 29 ++++++++++++++++++++++++++++- 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/src/P2/freeze.c b/src/P2/freeze.c index 951842fc..6bd4b84c 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -55,7 +55,36 @@ void GetAloFrozen(ALO *palo, int *pf) *pf = (int)(STRUCT_OFFSET(palo, 0x2c8, unsigned long long) >> 38) & 1; } -INCLUDE_ASM("asm/nonmatchings/P2/freeze", FreezeAlo__FP3ALOi); +void FreezeAlo(ALO *palo, int fFreeze) +{ + extern VECTOR D_00248D30; + + if (fFreeze) + { + SFX *psfx; + + STRUCT_OFFSET(palo, 0xa0, VU_VECTOR) = STRUCT_OFFSET(palo, 0x150, VU_VECTOR); + STRUCT_OFFSET(palo, 0xb0, VU_VECTOR) = STRUCT_OFFSET(palo, 0x160, VU_VECTOR); + psfx = STRUCT_OFFSET(palo, 0x2ac, SFX *); + STRUCT_OFFSET(palo, 0x29c, int) = 0; + if (psfx) + StopSound(psfx->pamb, 0); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)palo + 0x90))(palo, &D_00248D30); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)palo + 0x94))(palo, &D_00248D30); + STRUCT_OFFSET(palo, 0x2c8, unsigned long long) |= (0x8000ULL << 23); + } + else + { + SFX *psfx; + + STRUCT_OFFSET(palo, 0x2c8, unsigned long long) &= ~(0x8000ULL << 23); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)palo + 0x90))(palo, (VECTOR *)((uint8_t *)palo + 0xa0)); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)palo + 0x94))(palo, (VECTOR *)((uint8_t *)palo + 0xb0)); + psfx = STRUCT_OFFSET(palo, 0x2ac, SFX *); + if (psfx) + StartSound(psfx->sfxid, &psfx->pamb, palo, NULL, psfx->sStart, psfx->sFull, psfx->uVol, psfx->uPitch, psfx->uDoppler, &psfx->lmRepeat, NULL); + } +} INCLUDE_ASM("asm/nonmatchings/P2/freeze", FreezeSo__FP2SOi); diff --git a/src/P2/prompt.c b/src/P2/prompt.c index 45b6148d..449bdcff 100644 --- a/src/P2/prompt.c +++ b/src/P2/prompt.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include // TODO: Change to static when possible. extern char *s_mprespkachz[13]; @@ -49,7 +51,52 @@ INCLUDE_ASM("asm/nonmatchings/P2/prompt", FUN_00193fb8); INCLUDE_ASM("asm/nonmatchings/P2/prompt", OnPromptActive__FP6PROMPTi); -INCLUDE_ASM("asm/nonmatchings/P2/prompt", FUN_00194278); +extern "C" { +void FUN_00194278(PROMPT *pprompt, int fButton, WIPEK wipek) +{ + int idLevel; + + SetPrompt(pprompt, (PRP)0, (PRK)-1); + + idLevel = (STRUCT_OFFSET(g_pgsCur, 0x19d8, int) << 8) | STRUCT_OFFSET(g_pgsCur, 0x19dc, int); + + if (idLevel == 0x106) + { + if (fButton) + { + TRANS trans; + trans.fSet = 1; + trans.pchzWorld = (LevelTableStruct *)((char *)&g_transition + 0x14); + trans.oidWarp = (OID)-1; + trans.oidWarpContet = (OID)-1; + trans.grftrans = 0; + ActivateWipe(&g_wipe, &trans, wipek); + } + else + { + LO *plo = PloFindSwObjectByClass(g_psw, 5, (CID)0x5F, NULL); + SetRobRobs((ROB *)plo, (ROBS)6); + } + } + else + { + if (fButton) + { + TRANS trans; + trans.fSet = 1; + trans.pchzWorld = (LevelTableStruct *)((char *)&g_transition + 0x14); + trans.oidWarp = (OID)-1; + trans.oidWarpContet = (OID)-1; + trans.grftrans = 0x10; + ActivateWipe(&g_wipe, &trans, wipek); + } + else + { + TriggerDefaultExit(0, wipek); + } + } +} +} INCLUDE_ASM("asm/nonmatchings/P2/prompt", FUN_00194398__Fv); diff --git a/src/P2/pzo.c b/src/P2/pzo.c index f2166c67..2db94090 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include void InitSprize(SPRIZE *psprize) { @@ -205,7 +207,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", UpdateClue); INCLUDE_ASM("asm/nonmatchings/P2/pzo", OnClueSmack__FP4CLUE); -INCLUDE_ASM("asm/nonmatchings/P2/pzo", CollectClue__FP4CLUE); +void CollectClue(CLUE *pclue) +{ + extern char D_0026A970; + RIP *pripg; + VECTOR vec; + + (*(void (**)(CLUECTR *))(*(int *)&g_cluectr + 0x38))(&g_cluectr); + pripg = PripNewRipg(RIPT_Smack, NULL); + if (pripg) + { + if (STRUCT_OFFSET(g_plsCur, 0x64, int) + 1 >= STRUCT_OFFSET(g_psw, 0x2300, int)) + { + StartSound((SFXID)0x21, NULL, NULL, NULL, 3000.0f, 300.0f, 1.0f, 0.0f, 0.0f, NULL, NULL); + } + STRUCT_OFFSET(pripg, 0x134, CLUE *) = pclue; + STRUCT_OFFSET(pripg, 0x130, void *) = &D_0026A970; + ConvertAloPos(pclue, NULL, (VECTOR *)(STRUCT_OFFSET(pclue, 0x5bc, uint8_t *) + 0x100), &vec); + ((void (*)(RIP *, float, VECTOR *, int))STRUCT_OFFSET(STRUCT_OFFSET(pripg, 0x0, void *), 0x0, void *))(pripg, 1.0f, &vec, 0); + STRUCT_OFFSET(pripg, 0x20, int) = STRUCT_OFFSET(pclue, 0x5bc, int); + } + else + { + OnClueSmack(pclue); + } + CollectSprize(pclue); +} void BreakClue(CLUE *pclue) { From 6204e06e8ccb74ef3b5a0238062ef335390fd4f1 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 04:22:27 +0200 Subject: [PATCH 089/134] Match LoadCrvcFromBrx via LHF harness (61-80 window, editable wave 4) crv: LoadCrvcFromBrx (binary loader, 5 PvAllocSwImpl + vector reads). checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/crv.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/P2/crv.c b/src/P2/crv.c index 0f609b4a..1a0f1bc8 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureApos__FiP6VECTORPf); @@ -175,7 +176,35 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvlClosestPointFromU__FP4CRVLP6VECTO INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvlClosestPointFromS__FP4CRVLP6VECTORfP6CONSTRT1T1PfT6); -INCLUDE_ASM("asm/nonmatchings/P2/crv", LoadCrvcFromBrx__FP4CRVCP18CBinaryInputStream); +void LoadCrvcFromBrx(CRVC *pcrvc, CBinaryInputStream *pbis) +{ + int icv; + int ccv; + + STRUCT_OFFSET(pcrvc, 0x8, int) = pbis->U8Read(); + ccv = pbis->U8Read(); + STRUCT_OFFSET(pcrvc, 0xC, int) = ccv; + STRUCT_OFFSET(pcrvc, 0x10, void *) = PvAllocSwImpl(ccv * 4); + STRUCT_OFFSET(pcrvc, 0x14, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 4); + STRUCT_OFFSET(pcrvc, 0x18, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 16); + STRUCT_OFFSET(pcrvc, 0x1C, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 16); + STRUCT_OFFSET(pcrvc, 0x20, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 16); + + for (icv = 0; icv < STRUCT_OFFSET(pcrvc, 0xC, int); icv++) + { + STRUCT_OFFSET(pcrvc, 0x10, float *)[icv] = pbis->F32Read(); + pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x18, void *) + icv * 16)); + pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x1C, void *) + icv * 16)); + pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x20, void *) + icv * 16)); + } + + if (STRUCT_OFFSET(*(void **)pcrvc, 0x24, void *) != NULL) + { + ((void (*)(CRVC *))STRUCT_OFFSET(*(void **)pcrvc, 0x24, void *))(pcrvc); + } + + InvalidateCrvcCache(pcrvc); +} void InvalidateCrvcCache(CRVC *pcrvc) { From 3515ac0264b7a0ea27e5a4be2c7144b9a04740ae Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 04:43:01 +0200 Subject: [PATCH 090/134] Match 3 functions via LHF harness (81-110 window, editable wave 1) act/rwm/screen: RetractAct, PostRwmLoad, DrawLetterbox. checksum-green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 46 ++++++++++++++++++++++++++++++++++++- src/P2/rwm.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- src/P2/screen.c | 17 +++++++++++++- 3 files changed, 120 insertions(+), 3 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index a0e37ff6..b48c1bd9 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -3,6 +3,7 @@ #include #include #include +#include ACT *PactNew(SW *psw, ALO *palo, VTACT *pvtact) { @@ -40,7 +41,50 @@ void InitAct(ACT *pact, ALO *palo) STRUCT_OFFSET(pact, 0x10, char) = du; } -INCLUDE_ASM("asm/nonmatchings/P2/act", RetractAct__FP3ACTi); +void RetractAct(ACT *pact, GRFRA grfra) +{ + VECTOR v; + ALO *palo = pact->palo; + ACT *pactPos; + ACT *pactRot; + extern VECTOR D_00248D30; + + RemoveDlEntry((DL *)((uint8_t *)palo + 0x1E0), pact); + + pactPos = STRUCT_OFFSET(palo, 0x1EC, ACT *); + pactRot = STRUCT_OFFSET(palo, 0x1F0, ACT *); + (*(void (**)(ALO *))((char *)palo->pvtlo + 0xBC))(palo); + + if (pact == pactPos && STRUCT_OFFSET(palo, 0x1EC, int) == 0 && (grfra & 1)) + { + if (palo->pvtlo->grfcid & 2) + { + ApplySoConstraintLocal((SO *)palo, (CONSTR *)((uint8_t *)palo + 0x440), + (VECTOR *)((uint8_t *)palo + 0x150), &v, NULL); + (*(void (**)(ALO *, VECTOR *))((char *)palo->pvtlo + 0x90))(palo, &v); + } + else + { + SetAloVelocityVec(palo, &D_00248D30); + } + } + + if (pact == pactRot && STRUCT_OFFSET(palo, 0x1F0, int) == 0 && (grfra & 2)) + { + if (palo->pvtlo->grfcid & 2) + { + ApplySoConstraintLocal((SO *)palo, (CONSTR *)((uint8_t *)palo + 0x460), + (VECTOR *)((uint8_t *)palo + 0x160), &v, NULL); + (*(void (**)(ALO *, VECTOR *))((char *)palo->pvtlo + 0x94))(palo, &v); + } + else + { + SetAloAngularVelocityVec(palo, &D_00248D30); + } + } + + FreeSlotheapPv((SLOTHEAP *)((uint8_t *)palo->psw + 0x1B20), pact); +} INCLUDE_ASM("asm/nonmatchings/P2/act", GetActPositionGoal__FP3ACTfP6VECTORT2); diff --git a/src/P2/rwm.c b/src/P2/rwm.c index 8da41ded..20b24568 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); @@ -56,7 +57,64 @@ extern "C" void FUN_001a84c8(RWM *prwmDst, RWM *prwmSrc) } } -INCLUDE_ASM("asm/nonmatchings/P2/rwm", PostRwmLoad__FP3RWM); +void PostRwmLoad(RWM *prwm) +{ + LO *plo; + OID oid; + + PostLoLoad((LO *)prwm); + if (STRUCT_OFFSET(prwm, 0x168, int) != 0) + return; + STRUCT_OFFSET(prwm, 0x168, int) = 1; + + oid = STRUCT_OFFSET(prwm, 0x4c, OID); + if (oid != OID_Nil) + { + plo = PloFindSwNearest(STRUCT_OFFSET(prwm, 0x14, SW *), oid, (LO *)prwm); + if (plo != 0) + { + if (FIsBasicDerivedFrom((BASIC *)plo, CID_WARP)) + STRUCT_OFFSET(prwm, 0x60, LO *) = plo; + else if (FIsBasicDerivedFrom((BASIC *)plo, (CID)0x73)) + STRUCT_OFFSET(prwm, 0x64, LO *) = plo; + else if (FIsBasicDerivedFrom((BASIC *)plo, CID_ALO)) + STRUCT_OFFSET(prwm, 0x68, LO *) = plo; + } + } + + oid = STRUCT_OFFSET(prwm, 0x50, OID); + if (oid != OID_Nil) + { + plo = PloFindSwNearest(STRUCT_OFFSET(prwm, 0x14, SW *), oid, (LO *)prwm); + if (plo != 0) + { + if (FIsBasicDerivedFrom((BASIC *)plo, CID_ALO)) + STRUCT_OFFSET(prwm, 0xe0, LO *) = plo; + else if (FIsBasicDerivedFrom((BASIC *)plo, (CID)0x75)) + STRUCT_OFFSET(prwm, 0xe4, LO *) = plo; + } + } + + oid = STRUCT_OFFSET(prwm, 0x54, OID); + if (oid != OID_Nil) + { + plo = PloFindSwNearest(STRUCT_OFFSET(prwm, 0x14, SW *), oid, (LO *)prwm); + if (plo != 0) + { + if (FIsBasicDerivedFrom((BASIC *)plo, (CID)0x73)) + STRUCT_OFFSET(prwm, 0x160, LO *) = plo; + else if (FIsBasicDerivedFrom((BASIC *)plo, CID_ALO)) + STRUCT_OFFSET(prwm, 0x164, LO *) = plo; + } + } + + oid = STRUCT_OFFSET(prwm, 0x58, OID); + if (oid != OID_Nil) + { + STRUCT_OFFSET(prwm, 0x5c, LO *) = + PloFindSwNearest(STRUCT_OFFSET(prwm, 0x14, SW *), oid, (LO *)prwm); + } +} extern "C" void FUN_001a93c8(RWM *prwm); diff --git a/src/P2/screen.c b/src/P2/screen.c index 5a159f57..c3e6e53b 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/screen", StartupScreen__Fv); @@ -386,7 +388,20 @@ void FUN_001ad940(BLOT *pblot) INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad970); -INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawLetterbox__FP9LETTERBOX); +void DrawLetterbox(LETTERBOX *pletterbox) +{ + float u = pletterbox->uOn * 66.400009f; + float v = 492.80002f - u; + + g_gifs.AddPrimPack(6, 7, 0x44441EE); + g_gifs.PackAD(0x47, 0x30000); + g_gifs.PackAD(0x42, 0x44); + g_gifs.PackRGBA(0x80000000); + g_gifs.PackXYZF(0x6C00, 0x7900, 0xFFFFFF0, 0); + g_gifs.PackXYZF(0x9400, (int)((u * 0.45454547f + 1936.0f) * 16.0f), 0xFFFFFF0, 0); + g_gifs.PackXYZF(0x6C00, (int)((v * 0.45454547f + 1936.0f) * 16.0f), 0xFFFFFF0, 0); + g_gifs.PackXYZF(0x9400, 0x8700, 0xFFFFFF0, 0); +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001adc60); From c0d13a7e8aceeff1d0c7b25a2a6404de904c3c45 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 8 Jun 2026 18:42:38 +0200 Subject: [PATCH 091/134] Move cross-TU extern "C" forward decls into owning headers Several files locally forward-declared functions that are defined in another translation unit, only to call them. Move those declarations to the defining unit's header so consumers pick them up via the include: FUN_001bc4d8 -> so.h (steprail.c, lgn.c) FUN_0015c1c0/c188 -> font.h (screen.c) FUN_001c8920 -> stepguard.h (puffer.c) ResetCmLookAtSmooth -> cm.h (cplcy.c, via cplcy.h) FActiveCplcy -> cplcy.h (jt.c) C linkage is kept since these asm symbols are unmangled. stepguard.h forward-declares PUFFC to avoid a circular include with puffer.h. Co-Authored-By: Claude Opus 4.8 (1M context) --- include/cm.h | 2 ++ include/cplcy.h | 2 ++ include/font.h | 6 ++++++ include/so.h | 2 ++ include/stepguard.h | 3 +++ src/P2/cplcy.c | 2 -- src/P2/jt.c | 3 +-- src/P2/lgn.c | 3 +-- src/P2/puffer.c | 2 -- src/P2/screen.c | 2 -- src/P2/steprail.c | 3 +-- 11 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/cm.h b/include/cm.h index b1248574..97ac90f3 100644 --- a/include/cm.h +++ b/include/cm.h @@ -553,4 +553,6 @@ extern int g_rgbaFog; //Just to get the code matching -Kestin // extern float D_0026198c; // extern CM* g_pcm; +extern "C" void ResetCmLookAtSmooth(CM *pcm, void *pv); + #endif // CM_H diff --git a/include/cplcy.h b/include/cplcy.h index e2683e1e..09943f1c 100644 --- a/include/cplcy.h +++ b/include/cplcy.h @@ -17,4 +17,6 @@ LOOKK LookkPopCplook(CPLOOK *pcplook); LOOKK LookkCurCplook(CPLOOK *pcplook); +extern "C" int FActiveCplcy(CPLCY *pcplcy); + #endif // CPLCY_H diff --git a/include/font.h b/include/font.h index 79c346dc..69f29bf9 100644 --- a/include/font.h +++ b/include/font.h @@ -70,4 +70,10 @@ class CRichText void StartupFont(); +extern "C" +{ + CFont *FUN_0015c1c0(int i); + int FUN_0015c188(int i); +} + #endif // FONT_H diff --git a/include/so.h b/include/so.h index 6f72a66d..b079aa25 100644 --- a/include/so.h +++ b/include/so.h @@ -273,4 +273,6 @@ int FAbsorbSoWkr(SO *pso, WKR *pwkr); void CloneSoPhys(SO *pso, SO *psoPhys, int cposExtra); +extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); + #endif // SO_H diff --git a/include/stepguard.h b/include/stepguard.h index bb308e5f..c7cae283 100644 --- a/include/stepguard.h +++ b/include/stepguard.h @@ -260,4 +260,7 @@ void SetSggSggs(SGG *psgg, SGGS sggs); void AssignSggSearchPoints(SGG *psgg); +struct PUFFC; +extern "C" void FUN_001c8920(PUFFC *ppuffc); + #endif // STEPGUARD_H diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index 3af4c839..e0225f5d 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -78,8 +78,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/cplcy", FUN_0014a7b8); INCLUDE_ASM("asm/nonmatchings/P2/cplcy", InitCpalign); -extern "C" void ResetCmLookAtSmooth(CM *pcm, void *pv); - void FUN_0014a8d0(CPALIGN *pcpalign) { CM *pcm = pcpalign->pcm; diff --git a/src/P2/jt.c b/src/P2/jt.c index c862ec25..0f517095 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/jt", InitJt__FP2JT); @@ -217,8 +218,6 @@ int NCmpWkr(WKR *pwkr1, WKR *pwkr2) INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtEffect__FP2JT); -extern "C" int FActiveCplcy(CPLCY *pcplcy); - int FIsJtSoundBase(JT *pjt) { if (pjt->jts == JTS_Ball && pjt->jtbs == JTBS_Zap_Electric) diff --git a/src/P2/lgn.c b/src/P2/lgn.c index c5c2d112..f670187b 100644 --- a/src/P2/lgn.c +++ b/src/P2/lgn.c @@ -3,6 +3,7 @@ #include #include #include +#include void InitLgn(LGN *plgn) { @@ -57,8 +58,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/lgn", FTakeLgnDamage__FP3LGNP3ZPR); INCLUDE_ASM("asm/nonmatchings/P2/lgn", HandleLgnMessage__FP3LGN5MSGIDPv); -extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); - extern "C" void FUN_00181d88(uint8_t *param_1) { FUN_001bc4d8(param_1, param_1 + 0xC04); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 31dc319c..ab42519e 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -107,8 +107,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffcGoal__FP5PUFFCi); INCLUDE_ASM("asm/nonmatchings/P2/puffer", OnPuffcExitingSgs__FP5PUFFC3SGS); -extern "C" void FUN_001c8920(PUFFC *ppuffc); - void OnPuffcEnteringSgs(PUFFC *ppuffc, SGS sgsPrev, ASEG *pasegOverride) { OnStepguardEnteringSgs((STEPGUARD *)ppuffc, sgsPrev, pasegOverride); diff --git a/src/P2/screen.c b/src/P2/screen.c index c3e6e53b..ecaa4860 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -316,8 +316,6 @@ void FUN_001aca68(BLOT *pblot) INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawTitle__FP5TITLE); -extern "C" CFont *FUN_0015c1c0(int i); -extern "C" int FUN_0015c188(int i); extern CFont *D_00274410; void PostTotalsLoad(TOTALS *ptotals) diff --git a/src/P2/steprail.c b/src/P2/steprail.c index 9f327e5a..f40453f5 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -1,7 +1,6 @@ #include #include - -extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); +#include INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D31D0__FP2LOi); From 40728099f4dc1da9c9c2458cd4975b8deb313ec4 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Tue, 9 Jun 2026 08:56:55 +0200 Subject: [PATCH 092/134] Access SO-base fields in water via STRUCT_OFFSET The fields below 0x550 belong to the SO base, which is still truncated. Redeclaring them in WATER pinned the struct to the current sizeof(SO) and would break the checksum if SO later grows. Reach them via STRUCT_OFFSET from water.c instead, leaving only WATER's own fields (0x550+) in the struct. Co-Authored-By: Claude Opus 4.8 (1M context) --- include/water.h | 22 ++++++---------------- src/P2/water.c | 20 +++++++++++--------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/include/water.h b/include/water.h index 020eff2c..75120d78 100644 --- a/include/water.h +++ b/include/water.h @@ -23,22 +23,12 @@ struct XP; */ struct WATER : public SO { - // The fields below 0x550 belong to the SO base, but the engine's base - // structs are not yet fully reversed (SO is currently truncated), so they - // are laid out here via padding to land at their true absolute offsets. - STRUCT_PADDING(36); // 0x2d0 .. 0x360 - /* 0x360 */ float unk_0x360; - /* 0x364 */ float unk_0x364; - /* 0x368 */ float mass; - STRUCT_PADDING(25); // 0x36c .. 0x3d0 - /* 0x3d0 */ float sRadiusBounds; - /* 0x3d4 */ float unk_0x3d4; - STRUCT_PADDING(18); // 0x3d8 .. 0x420 - /* 0x420 */ VECTOR4 vecBoundsMin; - /* 0x430 */ VECTOR4 vecBoundsMax; - STRUCT_PADDING(62); // 0x440 .. 0x538 - /* 0x538 */ uint64_t grfso; - STRUCT_PADDING(4); // 0x540 .. 0x550 + // The span 0x2d0..0x550 holds SO base fields that live past the currently + // truncated SO size. Rather than redeclare them here (which would pin this + // struct to the present sizeof(SO) and break the checksum if SO grows), + // they are reached via STRUCT_OFFSET from water.c until the base structs + // are fully reversed. WATER's own fields begin at 0x550. + STRUCT_PADDING(160); // 0x2d0 .. 0x550 /* 0x550 */ XA *pxaFirst; /* 0x554 */ MRG mrg; STRUCT_PADDING(3); // 0x564 .. 0x570 diff --git a/src/P2/water.c b/src/P2/water.c index 8833beba..9697c247 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -13,11 +13,13 @@ void InitWater(WATER *pwater) { InitSo(pwater); - pwater->grfso |= 0x80000000000; + // grfso (0x538), unk_0x360 and unk_0x364 are SO base fields living past the + // truncated SO size; reach them via STRUCT_OFFSET (see WATER definition). + STRUCT_OFFSET(pwater, 0x538, uint64_t) |= 0x80000000000; pwater->unk_0x584 = 1; - pwater->unk_0x364 = 1.0f; + STRUCT_OFFSET(pwater, 0x364, float) = 1.0f; pwater->unk_0x588 = 1; - pwater->unk_0x360 = 1.0f; + STRUCT_OFFSET(pwater, 0x360, float) = 1.0f; SetSoConstraints(pwater, CT_Locked, NULL, CT_Locked, NULL); @@ -68,9 +70,9 @@ void UpdateSwXaList(SW *psw, XA **ppxa) while (pxa != NULL) { SO *pso = pxa->pso; - // grfso is an SO flag word at 0x538; accessed through WATER until the - // base structs are fully reversed (see WATER definition). - uint64_t grfso = ((WATER *)pso)->grfso; + // grfso is an SO flag word at 0x538, reached via STRUCT_OFFSET until + // the base structs are fully reversed (see WATER definition). + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); XA *pxaNext = pxa->pxaNextTarget; if (((grfso >> 59) & 1) != ((grfso >> 60) & 1)) @@ -81,7 +83,7 @@ void UpdateSwXaList(SW *psw, XA **ppxa) AddSoXa(pso, pxa); } - if (((WATER *)pxa->pso)->grfso & (1ULL << 60)) + if (STRUCT_OFFSET(pxa->pso, 0x538, uint64_t) & (1ULL << 60)) { ppxa = &pxa->pxaNextTarget; } @@ -92,10 +94,10 @@ void UpdateSwXaList(SW *psw, XA **ppxa) pxaFree = pxa; } - uint64_t grfsoClear = ((WATER *)pxa->pso)->grfso; + uint64_t grfsoClear = STRUCT_OFFSET(pxa->pso, 0x538, uint64_t); grfsoClear &= ~(1ULL << 60); grfsoClear &= ~(1ULL << 59); - ((WATER *)pxa->pso)->grfso = grfsoClear; + STRUCT_OFFSET(pxa->pso, 0x538, uint64_t) = grfsoClear; pxa = pxaNext; } From 100044de8cfbe0809c9859405c6c37b37e218e07 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 5 Jun 2026 22:35:53 +0200 Subject: [PATCH 093/134] add claude.md --- CLAUDE.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..49fdd185 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,76 @@ +# CLAUDE.md + +Guidance for working in this repo (a WIP decompilation of the PS2 game *Sly +Cooper and the Thievius Raccoonus*, NTSC-U `SCUS_971.98`). The goal is matching +C/C++ source: code that compiles (with the EE GCC 2.95 toolchain under Wine) to +bytes identical to the original executable. + +## Conventions & style + +Follow [docs/STYLEGUIDE.md](docs/STYLEGUIDE.md) for naming (Hungarian-style +prefixes: `p`ointer, `c`ount, `f`lag, `g_`lobal, `m_`ember…), capitalization +(`ALLCAPS` structs/enums, `UpperCamelCase` functions, `lowerCamelCase` +locals), brace-on-new-line + 4-space indent, and Doxygen comments. See +[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for the end-to-end matching +workflow. Prefer official symbol names from the May 19 2002 prototype; when +unknown, use a clear descriptive name (offset-suffixed placeholders like +`unk_0x360` are acceptable for not-yet-understood struct fields). + +## Build & verify + +- Full build + checksum: `./scripts/build.sh` → expect `out/SCUS_971.98: OK`. + This (`sha1sum -c config/checksum.sha1`) is the ground-truth "did I break + anything" check — run it after touching shared headers. +- Per-function diff (interactive TUI): `./scripts/diff.sh [P2/unit]`. +- The build defines `-DSKIP_ASM`, so the real ELF is built from C; `INCLUDE_ASM` + expands to nothing under `SKIP_ASM` and pulls in the `.s` otherwise. Objdiff + dual-builds `obj/target/*.o` (asm) vs `obj/current/*.o` (your C, `-DSKIP_ASM`) + via `python3 configure.py --objects && ninja`. +- Headless one-shot verify (the TUI needs a tty): build the dual objects, then + `objdump -dr obj/{target,current}/.o`, slice out the symbol, strip the + leading address/opcode-byte columns, and diff. Equal instructions **and** + relocations = a match (objdump prints all unresolved calls as `jal 0 `, + so always compare the `R_MIPS_26` reloc rows too). +- To inspect a struct's real compiled layout, compile an address-of/`sizeof` + probe with the EE compiler and read the immediates: + `wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee -isystem include/gcc -x c++ -B$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/ -O2 -G0 -ffast-math probe.cpp`. + +## Critical: do NOT grow engine base struct sizes + +The base classes `LO` → `ALO` → `SO` are intentionally **truncated**: +`sizeof(SO)` compiles to `0x2d0`, even though the real game's `SO` is `0x550`. +The `/* 0xNN */` offset comments in the base headers are aspirational targets, +**not** the compiled offsets (e.g. `ALO::grfzon` compiles to `0x7c`, documented +`0x88`). + +Each subclass instead places its own fields at correct **absolute** offsets +using explicit `STRUCT_PADDING(...)` **calibrated to the current truncated base +size** (e.g. `struct JT` pads ~1090 words to land `paloMine` at `0x1518`). + +Growing `SO`/`ALO`/`LO` to their "true" size shifts every subclass's fields and +**fails the checksum** — the breakage surfaces in compiled-C accessors of other +subclasses (e.g. `SetFsp` reading `JT`), not in your file. So when reversing a +new subclass: + +- Keep the base structs as-is. Lay out the whole object inside the subclass via + leading `STRUCT_PADDING` from `sizeof(base)` — including fields that + semantically belong to the SO base but live past `0x2d0`. +- For a base field accessed through a generic `SO*` (e.g. the `grfso` flag word + at `0x538`), cast to the subclass type to reach the offset; note it in a + comment. + +## GCC 2.95 matching tips + +Matching is mostly about steering this old compiler's scheduler/allocator: + +- `x & ~A & ~B` with two constant masks gets folded into one `&` by the front + end / combiner. To force two separate ANDs (one load, two ANDs, one store), + load into a local and split into `tmp &= ~A; tmp &= ~B;`. +- Register choice is driven by variable live-ranges: reusing one variable pins + it to a register across its whole range; use a *fresh* local for a late block + to let the allocator pick the register the target uses. +- Mirror the original's pointer/index reuse — introduce locals like + `MRG *pmrg = &x->mrg;` or `int c = p->count;` when the asm keeps a value in a + register rather than reloading it. +- Store ordering: GCC may reverse independent store pairs; reorder the source + statements to compensate. From 96b5842496f5606f3f7a4859d1cf43b596e86b84 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 5 Jun 2026 22:47:32 +0200 Subject: [PATCH 094/134] update workflow --- CLAUDE.md | 44 +++++++++++++++++++++--------- scripts/match.sh | 49 +++++++++++++++++++++++++++++++++ scripts/structoff.sh | 64 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 12 deletions(-) create mode 100755 scripts/match.sh create mode 100755 scripts/structoff.sh diff --git a/CLAUDE.md b/CLAUDE.md index 49fdd185..8684d550 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,18 +22,38 @@ unknown, use a clear descriptive name (offset-suffixed placeholders like This (`sha1sum -c config/checksum.sha1`) is the ground-truth "did I break anything" check — run it after touching shared headers. - Per-function diff (interactive TUI): `./scripts/diff.sh [P2/unit]`. -- The build defines `-DSKIP_ASM`, so the real ELF is built from C; `INCLUDE_ASM` - expands to nothing under `SKIP_ASM` and pulls in the `.s` otherwise. Objdiff - dual-builds `obj/target/*.o` (asm) vs `obj/current/*.o` (your C, `-DSKIP_ASM`) - via `python3 configure.py --objects && ninja`. -- Headless one-shot verify (the TUI needs a tty): build the dual objects, then - `objdump -dr obj/{target,current}/.o`, slice out the symbol, strip the - leading address/opcode-byte columns, and diff. Equal instructions **and** - relocations = a match (objdump prints all unresolved calls as `jal 0 `, - so always compare the `R_MIPS_26` reloc rows too). -- To inspect a struct's real compiled layout, compile an address-of/`sizeof` - probe with the EE compiler and read the immediates: - `wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee -isystem include/gcc -x c++ -B$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/ -O2 -G0 -ffast-math probe.cpp`. +- **Headless per-symbol match check** (the TUI needs a tty; use this for + automated/iterative work): `./scripts/match.sh `, e.g. + `./scripts/match.sh P2/water InitWater__FP5WATER`. It dual-builds and diffs the + symbol's instructions **and** relocations, printing `MATCH` or the diff. +- **Inspect a struct's real compiled layout**: + `./scripts/structoff.sh
'EXPR' ['EXPR' ...]`, e.g. + `./scripts/structoff.sh water.h 'sizeof(WATER)' '(int)(long)&((WATER*)0)->grfso'`. + Always probe with the EE compiler — host gcc gives wrong offsets (different + EABI alignment), and the `/* 0xNN */` header comments are not the compiled + offsets. +- Mechanics behind those scripts: the build defines `-DSKIP_ASM`, so the real + ELF is built from C; `INCLUDE_ASM` expands to nothing under `SKIP_ASM` and + pulls in the `.s` otherwise. Objdiff dual-builds `obj/target/*.o` (asm) vs + `obj/current/*.o` (your C) via `python3 configure.py --objects && ninja`. + objdump prints every unresolved call as `jal 0 `, so a real check must + compare the `R_MIPS_26` reloc rows too (`match.sh` does). + +## Suggested matching workflow + +1. Read the target `.s` in `asm/nonmatchings//.s` and the function + prototype in the header. Note every struct offset it touches. +2. Lay out the struct: probe sizes/offsets with `scripts/structoff.sh`, then add + fields to the (sub)struct via `STRUCT_PADDING` to land at absolute offsets — + **never grow the base structs** (see below). +3. Write the C under the `INCLUDE_ASM` line, wrapped in `#ifdef SKIP_ASM` / + `#endif`, so the asm is still available as the diff target. +4. Loop: edit → `scripts/match.sh ` → adjust for GCC 2.95 quirks + (see tips below) until it prints `MATCH`. +5. When matched, delete the `INCLUDE_ASM` line and the `#ifdef SKIP_ASM`/`#endif` + wrapper, leaving plain C. +6. After the file is done (or after any shared-header edit), run + `./scripts/build.sh` and confirm `out/SCUS_971.98: OK`. ## Critical: do NOT grow engine base struct sizes diff --git a/scripts/match.sh b/scripts/match.sh new file mode 100755 index 00000000..345535dd --- /dev/null +++ b/scripts/match.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Headless per-symbol match check (no TUI). Builds the target (asm) and current +# (your C, -DSKIP_ASM) objects, then diffs a single symbol's instructions AND +# relocations. Prints "MATCH" or the instruction diff. +# +# Usage: scripts/match.sh +# splat unit path, e.g. P2/water (object: obj/{target,current}/water.o) +# +# Example: scripts/match.sh P2/water InitWater__FP5WATER +# +set -e + +if [ -z "$2" ]; then + echo "Usage: $0 (e.g. $0 P2/water InitWater__FP5WATER)" >&2 + exit 1 +fi + +cd "$(dirname "$0")/.." +if [ -z "$VIRTUAL_ENV" ]; then + source "env/bin/activate" +fi + +UNIT="$1" +SYM="$2" +OBJ="$(basename "$UNIT").o" + +python3 configure.py --objects >/dev/null +ninja "obj/target/$OBJ" "obj/current/$OBJ" >/dev/null + +for v in target current; do + mips-linux-gnu-objdump -dr "obj/$v/$OBJ" 2>/dev/null | awk -v s="<$SYM>:" ' + $0 ~ s {p=1} p && /^$/ {p=0} p {print}' \ + | sed -E 's/^\s*[0-9a-f]+:\s+[0-9a-f]{8}\s+//; s/^\s*[0-9a-f]+: (R_MIPS)/\1/; s/^[0-9a-f]+ "/tmp/match_$v.txt" +done + +if ! [ -s /tmp/match_target.txt ]; then + echo "error: symbol '$SYM' not found in obj/target/$OBJ" >&2 + exit 2 +fi + +if diff -q /tmp/match_target.txt /tmp/match_current.txt >/dev/null; then + echo "MATCH: $SYM" +else + echo "DIFFERS: $SYM" + diff /tmp/match_target.txt /tmp/match_current.txt + exit 1 +fi diff --git a/scripts/structoff.sh b/scripts/structoff.sh new file mode 100755 index 00000000..58081bc3 --- /dev/null +++ b/scripts/structoff.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Print REAL compiled struct offsets/sizes using the EE (GCC 2.95) toolchain. +# Host gcc gives wrong layout (different EABI alignment), so always probe with +# the actual compiler. Each EXPR must be an integer constant expression; use a +# null base for offsetof-style queries, e.g. (int)(long)&((WATER*)0)->grfso +# +# Usage: scripts/structoff.sh
'EXPR' ['EXPR' ...] +# +# Example: +# scripts/structoff.sh water.h 'sizeof(WATER)' \ +# '(int)(long)&((WATER*)0)->grfso' '(int)(long)&((WATER*)0)->zpd.cploThrow' +# +set -e + +if [ -z "$2" ]; then + echo "Usage: $0
'EXPR' ['EXPR' ...]" >&2 + exit 1 +fi + +cd "$(dirname "$0")/.." + +HDR="$1" +shift + +SRC="$(mktemp /tmp/structoff.XXXXXX.cpp)" +OBJ="${SRC%.cpp}.o" +trap 'rm -f "$SRC" "$OBJ"' EXIT + +{ + echo "#include <$HDR>" + i=0 + for e in "$@"; do + echo "int probe_$i(){ return (int)($e); }" + i=$((i + 1)) + done +} > "$SRC" + +WINEDEBUG=-all wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee \ + -isystem include/gcc -x c++ -B"$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/" \ + -O2 -G0 -ffast-math "$SRC" -o "$OBJ" 2>&1 | grep -viE 'warning|radv' || true + +if ! [ -s "$OBJ" ]; then + echo "error: compile failed (run without the grep filter to see why)" >&2 + exit 2 +fi + +DIS="$(mips-linux-gnu-objdump -d "$OBJ" 2>/dev/null)" +echo "# <$HDR>" +i=0 +for e in "$@"; do + # Each probe is a constant function: jr ra ; li v0,N (or move v0,zero for 0). + block="$(echo "$DIS" | awk -v f=" Date: Sat, 6 Jun 2026 20:18:13 +0200 Subject: [PATCH 095/134] Add decomp batch-matching workflow and harness scripts/decomp_lhf_draft.workflow.js fans out parallel read-only agents that draft matching C for batches of tiny leaf functions. scripts/decomp_apply_drafts.py verifies each draft in isolation (instructions + relocations vs the asm), rejects ones that grow non-.text sections (rodata-layout ripple) or whose raw FUN_ symbol has asm callers, then applies the byte-exact matches and renames FUN_ symbols. Co-Authored-By: Claude Opus 4.8 --- scripts/decomp_apply_drafts.py | 152 +++++++++++++++++++++++++++ scripts/decomp_lhf_draft.workflow.js | 73 +++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 scripts/decomp_apply_drafts.py create mode 100644 scripts/decomp_lhf_draft.workflow.js diff --git a/scripts/decomp_apply_drafts.py b/scripts/decomp_apply_drafts.py new file mode 100644 index 00000000..156686c1 --- /dev/null +++ b/scripts/decomp_apply_drafts.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# Apply workflow drafts one-at-a-time (isolated), build the unit object, diff +# against the target asm, and keep only byte-exact matches. Then apply all +# keepers together. Run: python3 /tmp/apply_drafts.py [verify|finalize] +import json, subprocess, os, re, sys + +REPO = "/home/johan/git/sly1" +os.chdir(REPO) +DRAFTS = json.load(open("/tmp/drafts.json")) + +def sh(cmd): + return subprocess.run(["bash", "-lc", cmd], capture_output=True, text=True) + +def cfile(unit): return f"src/{unit}.c" +def objbase(unit): return os.path.basename(unit) # P2/crv -> crv + +# ---- backup every file we might touch ---- +TOUCHED = set(cfile(d["unit"]) for d in DRAFTS) | {"config/symbol_addrs.txt"} +BAK = {f: open(f).read() for f in TOUCHED if os.path.exists(f)} + +def restore_all(): + for f, c in BAK.items(): + open(f, "w").write(c) + +def apply_one(unit, sym, code, includes, wrap=True): + f = cfile(unit) + s = open(f).read() + line = f'INCLUDE_ASM("asm/nonmatchings/{unit}", {sym});' + if line not in s: + return False, "INCLUDE_ASM line not found" + if wrap: + # keep INCLUDE_ASM (asm target) + add C under SKIP_ASM (current) + repl = line + "\n#ifdef SKIP_ASM\n" + code.rstrip() + "\n#endif" + else: + repl = code # finalize: plain C replaces the stub + s = s.replace(line, repl, 1) + for inc in includes or []: + tok = inc.strip() + if not tok: + continue + directive = f"#include {tok}" + if directive not in s: + ms = list(re.finditer(r'^#include .*$', s, re.M)) + if ms: + pos = ms[-1].end() + s = s[:pos] + "\n" + directive + s[pos:] + else: + s = directive + "\n" + s + open(f, "w").write(s) + return True, "" + +def norm_disasm(obj, sym): + r = sh(f"mips-linux-gnu-objdump -dr {obj} 2>/dev/null") + out, p = [], False + for ln in r.stdout.splitlines(): + if re.search(rf"<{re.escape(sym)}>:", ln): + p = True; continue + if p and ln.strip() == "": + break + if p: + ln = re.sub(r'^\s*[0-9a-f]+:\s+[0-9a-f]{8}\s+', '', ln) + ln = re.sub(r'^\s*[0-9a-f]+: (R_MIPS)', r'\1', ln) + ln = re.sub(r'[0-9a-f]+ <', '<', ln) + ln = ln.strip() + if ln: + out.append(ln) + return out + +def current_symname(unit, sym): + if "__" in sym: + return sym + obj = f"obj/current/{objbase(unit)}.o" + r = sh(f"mips-linux-gnu-objdump -t {obj} 2>/dev/null") + for ln in r.stdout.splitlines(): + m = re.search(rf"\b({re.escape(sym)}__\S+)", ln) + if m and (" F " in ln or " g " in ln): + return m.group(1) + return sym # maybe extern "C" / unchanged + +def has_asm_callers(sym): + # any other .s referencing this raw symbol? + r = sh(f"grep -rl '\\b{re.escape(sym)}\\b' asm/nonmatchings/ 2>/dev/null") + files = [x for x in r.stdout.split() if not x.endswith(f"/{sym}.s")] + return len(files) > 0 + +def data_sec_size(obj): + # total size of allocatable non-.text sections (rodata/data/bss/sdata...) + r = sh(f"mips-linux-gnu-objdump -h {obj} 2>/dev/null") + tot = 0 + for ln in r.stdout.splitlines(): + m = re.match(r'\s*\d+\s+(\.\S+)\s+([0-9a-f]{8})', ln) + if m: + name, sz = m.group(1), int(m.group(2), 16) + if name == ".text" or name.startswith((".pdr", ".reginfo", ".comment", ".gnu", ".mdebug", ".debug")): + continue + tot += sz + return tot + +def verify(): + sh("source env/bin/activate; python3 configure.py --objects >/dev/null 2>&1") + # cache clean data-section sizes per unit + restore_all() + units = sorted(set(d["unit"] for d in DRAFTS)) + sh("source env/bin/activate; ninja " + " ".join(f"obj/current/{objbase(u)}.o" for u in units) + " 2>&1") + clean_size = {u: data_sec_size(f"obj/current/{objbase(u)}.o") for u in units} + results = [] + for d in DRAFTS: + unit, sym = d["unit"], d["sym"] + restore_all() + ok, msg = apply_one(unit, sym, d["code"], d.get("includes")) + if not ok: + results.append([unit, sym, "SKIP", msg]); continue + oc, ot = f"obj/current/{objbase(unit)}.o", f"obj/target/{objbase(unit)}.o" + b = sh(f"source env/bin/activate; ninja {oc} {ot} 2>&1") + if b.returncode != 0: + err = b.stdout.strip().splitlines()[-1] if b.stdout.strip() else "compile failed" + results.append([unit, sym, "COMPILE_FAIL", err[:160]]); continue + if data_sec_size(oc) != clean_size[unit]: + results.append([unit, sym, "DATA_GROWTH", "adds rodata/data -> layout ripple"]); continue + cs = current_symname(unit, sym) + dt, dc = norm_disasm(ot, sym), norm_disasm(oc, cs) + if dt and dt == dc: + tag = "MATCH" if "__" in sym else ("MATCH_FUN_CALLERS" if has_asm_callers(sym) else "MATCH_FUN") + results.append([unit, sym, tag, cs]) + else: + results.append([unit, sym, "DIFFER", f"t={len(dt)} c={len(dc)}"]) + restore_all() + json.dump(results, open("/tmp/verify_results.json", "w"), indent=0) + from collections import Counter + print(Counter(r[2] for r in results)) + for r in results: + print(r) + +def finalize(): + results = json.load(open("/tmp/verify_results.json")) + keep = {(r[0], r[1]): r for r in results if r[2] in ("MATCH", "MATCH_FUN")} + restore_all() + sa = open("config/symbol_addrs.txt").read() + for d in DRAFTS: + key = (d["unit"], d["sym"]) + if key not in keep: + continue + apply_one(d["unit"], d["sym"], d["code"], d.get("includes"), wrap=False) + r = keep[key] + if r[2] == "MATCH_FUN": # rename raw FUN_ -> mangled in symbol_addrs + raw, mangled = d["sym"], r[3] + sa = re.sub(rf'^{re.escape(raw)}(\s)', mangled + r'\1', sa, flags=re.M) + open("config/symbol_addrs.txt", "w").write(sa) + print("applied", len(keep), "keepers") + +if __name__ == "__main__": + (verify if len(sys.argv) < 2 or sys.argv[1] == "verify" else finalize)() diff --git a/scripts/decomp_lhf_draft.workflow.js b/scripts/decomp_lhf_draft.workflow.js new file mode 100644 index 00000000..b2c9bbb4 --- /dev/null +++ b/scripts/decomp_lhf_draft.workflow.js @@ -0,0 +1,73 @@ +export const meta = { + name: 'decomp-lhf-draft', + description: 'Draft matching C for tiny sly1 leaf functions (parallel, read-only)', + phases: [{ title: 'Draft' }], +} + +const cands = (typeof args === 'string' ? JSON.parse(args) : args) || [] +const BATCH = 4 +const batches = [] +for (let i = 0; i < cands.length; i += BATCH) batches.push(cands.slice(i, i + BATCH)) + +const SCHEMA = { + type: 'object', + additionalProperties: false, + properties: { + drafts: { + type: 'array', + items: { + type: 'object', + additionalProperties: false, + properties: { + unit: { type: 'string' }, + sym: { type: 'string' }, + code: { type: 'string' }, + includes: { type: 'array', items: { type: 'string' } }, + confidence: { type: 'number' }, + notes: { type: 'string' }, + }, + required: ['unit', 'sym', 'code', 'includes', 'confidence', 'notes'], + }, + }, + }, + required: ['drafts'], +} + +function draftPrompt(batch) { + const list = batch + .map((c) => `- unit "${c.unit}", symbol "${c.sym}" (asm: asm/nonmatchings/${c.unit}/${c.sym}.s, ~${c.n} instrs; source file: src/${c.unit}.c)`) + .join('\n') + return [ + 'You are decompiling TINY functions in the Sly 1 PS2 decomp at /home/johan/git/sly1 to C++ that compiles with EE GCC 2.95 to bytes IDENTICAL to the original MIPS assembly. Produce a matching C function for EACH candidate below.', + '', + 'Per candidate, do this:', + '1. Read asm/nonmatchings//.s. Work out EXACTLY what it does. Reg conventions: args $4=a0,$5=a1,$6=a2,$7=a3; float args $f12,$f14; int return in $2($v0); float return in $f0. daddu $2,$0,$0 => return 0; addiu $2,$0,1 => return 1.', + '2. Determine the signature. Demangle the symbol (e.g. Set...__FP9STEPGUARDf => void Set...(STEPGUARD*, float); __FP4ROST => (ROST*)). Cross-check the prototype in the unit header (grep the symbol base name under include/). For FUN_ names with no mangling, infer arg types from how regs are used and give the function the EXACT name FUN_xxxx; note that it will mangle (handled later).', + '3. Struct field access at offset 0xNN on a pointer: read the struct def. If a NAMED field already lands at that exact COMPILED offset, use it (verify with: scripts/structoff.sh \'(int)(long)&((TYPE*)0)->field\'). Otherwise use STRUCT_OFFSET(ptr, 0xNN, type) — macro in common.h: (*(type*)((uint8_t*)(ptr)+(offset))). MATCH THE WIDTH: lb=>char, lbu=>uchar, lh=>short, lhu=>ushort, lw/sw=>int (or a pointer/float type per use), ld/sd=>64-bit (use long long/uint64_t), lq/sq=>16-byte qword copy (use a 16-byte type; lower your confidence and explain in notes).', + '4. Float ops: a float field read/returned => float type. Compares/moves => mirror them.', + '5. Output the FULL C function definition that REPLACES this exact line in src/.c: INCLUDE_ASM("asm/nonmatchings/", );', + '6. In "includes": list ONLY header tokens (e.g. "") needed that are NOT already #included at the top of src/.c (read that file to check). Prefer adding nothing.', + '', + 'HARD RULES:', + '- DO NOT modify any struct/header, DO NOT add or grow struct fields. Use STRUCT_OFFSET for unnamed fields.', + '- DO NOT run ninja, configure.py, scripts/match.sh, or build/link ANYTHING (builds are serialized by the caller). You MAY run scripts/structoff.sh (it only writes /tmp) and read any file.', + '- Keep the C as direct as the asm (GCC 2.95 is literal). Mirror operation order.', + '- confidence: 0..1 (1 = you are sure it is a byte-exact match). Put any risk in notes (esp. lq/sq, float, or guessed FUN_ signatures).', + '', + 'Candidates:', + list, + '', + 'Return every candidate as a draft via the schema (one entry per candidate, even low-confidence ones).', + ].join('\n') +} + +phase('Draft') +const results = await parallel( + batches.map((b, i) => () => + agent(draftPrompt(b), { label: `draft#${i + 1} [${b.length}]`, phase: 'Draft', schema: SCHEMA }) + ) +) + +const drafts = results.filter(Boolean).flatMap((r) => (r && r.drafts) || []) +log(`drafted ${drafts.length} / ${cands.length} functions`) +return { drafts } From 9b114c387dc084b8fe17a6de37b1310fedf64d1f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sun, 7 Jun 2026 08:57:34 +0200 Subject: [PATCH 096/134] Match CalculateWaterCurrent (water.c) using the VU0 inline-asm idiom First water VU0 function matched: the vadd.xyzw combining the warp result is emitted via inline asm (lqc2/lqc2/vadd.xyzw/sqc2) over VU_VECTOR stack locals; the surrounding ConvertAloVec/CalculateAloTransformAdjust/WarpWrTransform calls and the *pv/*pw quadword copies are plain C. Adds WATER::vecCurrent at 0x570 and references the shared D_00248D30 rodata constant. Full checksum OK. Co-Authored-By: Claude Opus 4.8 --- src/P2/water.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/P2/water.c b/src/P2/water.c index 9697c247..10ac11c9 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -269,8 +269,10 @@ void UpdateWaterBounds(WATER *pwater) "sqc2 $vf1, %1\n\t" "swc1 $f0, %3\n\t" "swc1 $f2, %2" - : "=m"(pwater->vecBoundsMin), "=m"(pwater->vecBoundsMax), - "=m"(pwater->sRadiusBounds), "=m"(pwater->unk_0x3d4) + : "=m"(STRUCT_OFFSET(pwater, 0x420, VECTOR4)), + "=m"(STRUCT_OFFSET(pwater, 0x430, VECTOR4)), + "=m"(STRUCT_OFFSET(pwater, 0x3d0, float)), + "=m"(STRUCT_OFFSET(pwater, 0x3d4, float)) : "m"(dpos) : "$f0", "$f1", "$f2", "$2"); } From 15aebb9e9a07d6b2a794f578cf3fa44193548056 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Tue, 9 Jun 2026 09:07:40 +0200 Subject: [PATCH 097/134] Document STRUCT_OFFSET rule for base fields past the truncated base Update the "do NOT grow engine base struct sizes" section: lay out only a subclass's own fields via padding; never redeclare base fields living past the base's truncated end as subclass members (double-pins the layout to the current sizeof(base) and fails the checksum when the base is grown). Reach them via STRUCT_OFFSET / STRUCT_OFFSET_INDEX instead. Note that the subclass's leading STRUCT_PADDING remains inherently tied to sizeof(base). Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8684d550..3d737336 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -72,12 +72,27 @@ Growing `SO`/`ALO`/`LO` to their "true" size shifts every subclass's fields and subclasses (e.g. `SetFsp` reading `JT`), not in your file. So when reversing a new subclass: -- Keep the base structs as-is. Lay out the whole object inside the subclass via - leading `STRUCT_PADDING` from `sizeof(base)` — including fields that - semantically belong to the SO base but live past `0x2d0`. +- Keep the base structs as-is. Lay out only the subclass's **own** fields inside + the subclass via leading `STRUCT_PADDING` from `sizeof(base)`. +- Do **not** redeclare base fields that live past the base's truncated end + (e.g. SO fields between `0x2d0` and a subclass's first own field) as members of + the subclass. Doing so pins the subclass layout to the *current* `sizeof(base)` + in two places, so when the base is later grown to its true size the redeclared + fields collide/shift and fail the checksum — and it misrepresents whose fields + they are. Reach such base fields via `STRUCT_OFFSET` instead, and delete the + redeclaration once it has no compiled users. - For a base field accessed through a generic `SO*` (e.g. the `grfso` flag word - at `0x538`), cast to the subclass type to reach the offset; note it in a + at `0x538`), reach it with `STRUCT_OFFSET(pSo, 0x538, int)` (defined in + `include/common.h`) — `STRUCT_OFFSET(ptr, off, type)` dereferences a typed + field at a raw byte offset, and `STRUCT_OFFSET_INDEX(ptr, off, type, i)` does + the same for an array element (it bakes in the `(i << 2) + off` ordering that + matches GCC's codegen). Prefer these over an ad-hoc cast or a redeclared + member so the offset access is self-documenting; note the field's meaning in a comment. +- The subclass's leading `STRUCT_PADDING` is itself still calibrated to the + current `sizeof(base)` — that dependency is inherent to absolute-offset layout + and unavoidable; `STRUCT_OFFSET` only removes the *extra* coupling from + redeclaring base fields. ## GCC 2.95 matching tips From 15da083e9530a4f68f4670ba5db0096b2d4d84c4 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 20:30:37 +0200 Subject: [PATCH 098/134] =?UTF-8?q?Match=20InitPipe=20(pipe.c)=20=E2=80=94?= =?UTF-8?q?=20pipe.c=20now=20fully=20decompiled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lay out PIPE fields 0x40-0x5c (VU_VECTOR normal copied from g_normalX, scalar params, FLT_MAX via extern D_0024B650 rodata ref). Co-Authored-By: Claude Fable 5 --- include/pipe.h | 8 +++++++- src/P2/pipe.c | 14 +++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/pipe.h b/include/pipe.h index 69119282..fcffc3ed 100644 --- a/include/pipe.h +++ b/include/pipe.h @@ -6,6 +6,7 @@ #include "common.h" #include +#include /** * @class PIPE @@ -16,7 +17,12 @@ struct PIPE : public LO { /* 0x34 */ undefined4 unk; /* 0x38 */ DLE dlePipe; - /* 0x40 */ STRUCT_PADDING(9); + /* 0x40 */ VU_VECTOR normal; // TODO: Verify name. + /* 0x50 */ int unk_0x50; + /* 0x54 */ int unk_0x54; + /* 0x58 */ int unk_0x58; + /* 0x5C */ float unk_0x5c; + /* 0x60 */ STRUCT_PADDING(1); /* 0x64 */ OID oid; // TODO: Verify name. /* 0x68 */ LO *plo; // TODO: Verify type and name. }; diff --git a/src/P2/pipe.c b/src/P2/pipe.c index 8472accf..ae123646 100644 --- a/src/P2/pipe.c +++ b/src/P2/pipe.c @@ -14,7 +14,19 @@ void ResetPipeList() ClearDl(&g_dlPipe); } -INCLUDE_ASM("asm/nonmatchings/P2/pipe", InitPipe__FP4PIPE); +extern VU_VECTOR g_normalX; +extern float D_0024B650; // FLT_MAX + +void InitPipe(PIPE *ppipe) +{ + InitLo(ppipe); + ppipe->normal = g_normalX; + ppipe->unk_0x58 = -1; + ppipe->unk_0x54 = 9; + ppipe->unk_0x50 = 8; + ppipe->unk_0x5c = D_0024B650; + ppipe->oid = OID_Nil; +} void OnPipeAdd(PIPE *ppipe) { From ac26d64b2f817fa8a54455a6a9adc4b1bbee12aa Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 21:27:37 +0200 Subject: [PATCH 099/134] =?UTF-8?q?Match=20PostFrzgLoad=20(frzg.c)=20?= =?UTF-8?q?=E2=80=94=20frzg.c=20fully=20decompiled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds the freeze group's MRG: allocates apalo, resolves each aoid via PloFindSwChild, and registers the merge group with the SW. Co-Authored-By: Claude Fable 5 --- src/P2/frzg.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/P2/frzg.c b/src/P2/frzg.c index fdb280ba..1944b4a3 100644 --- a/src/P2/frzg.c +++ b/src/P2/frzg.c @@ -1,6 +1,28 @@ #include +#include +#include -INCLUDE_ASM("asm/nonmatchings/P2/frzg", PostFrzgLoad__FP4FRZG); +void PostFrzgLoad(FRZG *pfrzg) +{ + int i; + MRG *pmrg = &pfrzg->mrg; + SW *psw; + + PostLoLoad(pfrzg); + psw = pfrzg->psw; + pmrg->apalo = (ALO **)PvAllocSwImpl(pfrzg->coid * 4); + for (i = 0; i < pfrzg->coid; i++) + { + LO *plo = PloFindSwChild(psw, pfrzg->aoid[i], pfrzg->paloParent); + if (plo != 0) + { + int cpalo = pmrg->cpalo; + pmrg->apalo[cpalo] = (ALO *)plo; + pmrg->cpalo = cpalo + 1; + } + } + AddSwMergeGroup(psw, &pfrzg->mrg); +} void AddFrzgObject(FRZG *pfrzg, OID oid) { From e8eea34bfcc82ccf7b9946e8352575f7ba589413 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 21:47:28 +0200 Subject: [PATCH 100/134] Match 14 so.c functions (grfso setters, XA list ops, constraints, phys hook) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SetSoCameraStyle/EdgeGrab/NoGravity/Iceable/IgnoreLocked/NoXpsAll/Self/ Center, UpdateSoPosWorldPrev, AddSoXa, RemoveSoXa, PsoFindSoPhysHook, SetSoConstraints, SendSoMessage — first compiled-C inroads into the so unit, using the reversed SO layout (docs/SO_LAYOUT.md). DiscardSoXps is declared via its literal truncated-mangled symbol since callers pass a discard mode in $a1. Co-Authored-By: Claude Fable 5 --- include/so.h | 5 +- src/P2/so.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 183 insertions(+), 15 deletions(-) diff --git a/include/so.h b/include/so.h index b079aa25..80035d92 100644 --- a/include/so.h +++ b/include/so.h @@ -149,7 +149,10 @@ void SetSoMass(SO *pso, float m); void AdjustSoMomint(SO *pso, float r); -void DiscardSoXps(SO *pso); +// The asm symbol has truncated GCC2 mangling (one declared param) but the +// function takes a discard mode in $a1 (0 = clear cache only, 1 = if-child, +// 2 = if-self, 3 = if-self strict); declare with the literal mangled name. +extern "C" void DiscardSoXps__FP2SO(SO *pso, int mode); void UpdateSoPosWorldPrev(SO *pso); diff --git a/src/P2/so.c b/src/P2/so.c index b274c936..37540a77 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -67,7 +67,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", AdjustSoMomint__FP2SOf); INCLUDE_ASM("asm/nonmatchings/P2/so", DiscardSoXps__FP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateSoPosWorldPrev__FP2SO); +void UpdateSoPosWorldPrev(SO *pso) +{ + // posWorldPrev (0x370) = xf.posWorld (0x140) + STRUCT_OFFSET(pso, 0x370, qword) = STRUCT_OFFSET(pso, 0x140, qword); +} INCLUDE_ASM("asm/nonmatchings/P2/so", TranslateSoToPos__FP2SOP6VECTOR); @@ -87,7 +91,36 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", AddSoAcceleration__FP2SOP6VECTOR); INCLUDE_ASM("asm/nonmatchings/P2/so", AddSoAngularAcceleration__FP2SOP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoConstraints__FP2SO2CTP6VECTORT1T2); +void SetSoConstraints(SO *pso, CT ctForce, VECTOR *pnormalForce, CT ctTorque, VECTOR *pnormalTorque) +{ + SO *psoRoot; + uint64_t fWasLocked; + + STRUCT_OFFSET(pso, 0x450, CT) = ctForce; // constrForce.ct + fWasLocked = (STRUCT_OFFSET(pso, 0x538, uint64_t) >> 54) & 1; + if (pnormalForce != NULL) + { + STRUCT_OFFSET(pso, 0x440, VU_VECTOR) = *(VU_VECTOR *)pnormalForce; + } + STRUCT_OFFSET(pso, 0x470, CT) = ctTorque; // constrTorque.ct + if (pnormalTorque != NULL) + { + STRUCT_OFFSET(pso, 0x460, VU_VECTOR) = *(VU_VECTOR *)pnormalTorque; + } + psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); + if (psoRoot != NULL) + { + int fLocked = 0; + if (ctForce == CT_Locked) + { + fLocked = ctTorque == CT_Locked; + } + if (fWasLocked != fLocked) + { + RecalcSoLocked(psoRoot); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoParent__FP2SOP3ALO); @@ -116,9 +149,46 @@ void ApplySoConstraintLocal(SO *pso, CONSTR *pconstr, VECTOR *pvecLocal, VECTOR ApplyConstr(pconstr, pvecLocal, pvecConstr, pvecRemain); } -INCLUDE_ASM("asm/nonmatchings/P2/so", AddSoXa__FP2SOP2XA); +void AddSoXa(SO *pso, XA *pxaAdd) +{ + STRUCT_OFFSET(pxaAdd, 0x8, XA *) = STRUCT_OFFSET(pso, 0x4B0, XA *); // pxaNext + STRUCT_OFFSET(pso, 0x4B0, XA *) = pxaAdd; // pxaFirst + ResolveAlo(pso); +} -INCLUDE_ASM("asm/nonmatchings/P2/so", RemoveSoXa__FP2SOP2XA); +void RemoveSoXa(SO *pso, XA *pxaRemove) +{ + XA **ppxa = &STRUCT_OFFSET(pso, 0x4B0, XA *); // &pxaFirst + XA *pxa = STRUCT_OFFSET(pso, 0x4B0, XA *); + if (pxa != NULL) + { + if (pxa == pxaRemove) + { + STRUCT_OFFSET(pso, 0x4B0, XA *) = STRUCT_OFFSET(pxaRemove, 0x8, XA *); + } + else + { + for (;;) + { + XA *pxaCur = *ppxa; + XA *pxaNext = STRUCT_OFFSET(pxaCur, 0x8, XA *); + ppxa = &STRUCT_OFFSET(pxaCur, 0x8, XA *); + if (pxaNext == NULL) + { + goto LDone; + } + if (pxaNext == pxaRemove) + { + STRUCT_OFFSET(pxaCur, 0x8, XA *) = STRUCT_OFFSET(pxaRemove, 0x8, XA *); + break; + } + } + } + STRUCT_OFFSET(pxaRemove, 0x8, XA *) = NULL; + } +LDone: + ResolveAlo(pso); +} INCLUDE_ASM("asm/nonmatchings/P2/so", AddSoWaterAcceleration__FP2SOP5WATERf); @@ -147,34 +217,129 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoCnstrForce__FP2SO5CNSTR); INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoCnstrTorque__FP2SO5CNSTR); -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoCameraStyle__FP2SO3CMK); +void SetSoCameraStyle(SO *pso, CMK cmk) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)0xF << 32); // cmk field, grfso bits 32..35 + grfso |= (uint64_t)(cmk & 0xF) << 32; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; +} -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoIgnoreLocked__FP2SOi); +void SetSoIgnoreLocked(SO *pso, int fIgnoreLocked) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 47); // fIgnoreLocked, grfso bit 47 + grfso |= (uint64_t)(fIgnoreLocked & 1) << 47; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; +} -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoIceable__FP2SOi); +void SetSoIceable(SO *pso, int fIceable) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 48); // fIceable, grfso bit 48 + grfso |= (uint64_t)(fIceable & 1) << 48; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; +} void SetSoMtlk(SO *pso, MTLK mtlk) { STRUCT_OFFSET(pso, 0x2c8, char) = mtlk; } -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoEdgeGrab__FP2SO3EGK); +void SetSoEdgeGrab(SO *pso, EGK egk) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)0xF0 << 32); // egk field, grfso bits 36..39 + grfso |= (uint64_t)(egk & 0xF) << 36; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; +} -INCLUDE_ASM("asm/nonmatchings/P2/so", SendSoMessage__FP2SO5MSGIDPv); +void SendSoMessage(SO *pso, MSGID msgid, void *pv) +{ + XA *pxa; + + SendLoMessage(pso, msgid, pv); + pxa = STRUCT_OFFSET(pso, 0x4B0, XA *); // pxaFirst + while (pxa != NULL) + { + SO *psoTarget = STRUCT_OFFSET(pxa, 0x0, SO *); + XA *pxaNext = STRUCT_OFFSET(pxa, 0x8, XA *); + if (psoTarget != pso) + { + // virtual HandleMessage at vtable +0x44 + void (*pfn)(SO *, MSGID, void *) = + (void (*)(SO *, MSGID, void *))STRUCT_OFFSET(STRUCT_OFFSET(psoTarget, 0x0, void *), 0x44, void *); + if (pfn != NULL) + { + pfn(psoTarget, msgid, pv); + } + } + pxa = pxaNext; + } +} INCLUDE_ASM("asm/nonmatchings/P2/so", PxpFindSoGround__FP2SOT0Pi); -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoNoGravity__FP2SOi); +void SetSoNoGravity(SO *pso, int fNoGravity) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 51); // fNoGravity, grfso bit 51 + grfso |= (uint64_t)(fNoGravity & 1) << 51; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; +} -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoNoXpsAll__FP2SOi); +void SetSoNoXpsAll(SO *pso, int fNoXps) +{ + uint64_t bit = (uint64_t)(fNoXps & 1) << 42; // fNoXpsAll, grfso bit 42 + uint64_t mask = ~((uint64_t)1 << 42); + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= mask; + grfso |= bit; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; + DiscardSoXps__FP2SO(pso, fNoXps != 0); +} -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoNoXpsSelf__FP2SOi); +void SetSoNoXpsSelf(SO *pso, int fNoXps) +{ + uint64_t bit = (uint64_t)(fNoXps & 1) << 43; // fNoXpsSelf, grfso bit 43 + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 43); + grfso |= bit; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; + DiscardSoXps__FP2SO(pso, fNoXps ? 2 : 0); +} -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoNoXpsCenter__FP2SOi); +void SetSoNoXpsCenter(SO *pso, int fNoXps) +{ + uint64_t bit = (uint64_t)(fNoXps & 1) << 44; // fNoXpsCenter, grfso bit 44 + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 44); + grfso |= bit; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; + DiscardSoXps__FP2SO(pso, fNoXps ? 3 : 0); +} INCLUDE_ASM("asm/nonmatchings/P2/so", RebuildSoPhysHook__FP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/so", PsoFindSoPhysHook__FP2SOi); +SO *PsoFindSoPhysHook(SO *psoLeaf, int ib) +{ + SO *pso = psoLeaf; + while (pso != NULL) + { + pso = STRUCT_OFFSET(pso, 0x4E4, SO *); // psoPhysHook + if (pso == NULL) + { + break; + } + // hook handles phys if its virtual at vtable offset ib is non-null + if (STRUCT_OFFSET(STRUCT_OFFSET(pso, 0x0, void *), ib, void *) != NULL) + { + return pso; + } + pso = STRUCT_OFFSET(pso, 0x18, SO *); // paloParent + } + return NULL; +} INCLUDE_ASM("asm/nonmatchings/P2/so", RecalcSoLocked__FP2SO); From aca5b980b721c67fce5fb89093e7e649e2b0758e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:05:03 +0200 Subject: [PATCH 101/134] Match 5 more so.c functions (OnSoAdd, EnableSoPhys, SetSoParent, RebuildSoPhysHook, ConstrFromCnstr) CNSTR becomes an enum (mangles identically as 5CNSTR) so ConstrFromCnstr can be defined; its table D_002746E0 holds (VECTOR*, CT) pairs. OnSoRemove also matches per-symbol but is kept INCLUDE_ASM: enabling it triggers an asm-emission bug that inflates the still-asm TranslateSoToPosSafe by 0x14 bytes and fails the checksum (see comment). Co-Authored-By: Claude Fable 5 --- include/so.h | 9 ++- src/P2/so.c | 180 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 183 insertions(+), 6 deletions(-) diff --git a/include/so.h b/include/so.h index 80035d92..162aff4b 100644 --- a/include/so.h +++ b/include/so.h @@ -25,7 +25,14 @@ struct RO; struct WKR; struct ZPR; struct WATER; -struct CNSTR; +/** + * @brief Constraint kind, an index into the s_acnstre table (see + * ConstrFromCnstr); each entry resolves to a CT and a normal vector. + */ +enum CNSTR +{ + // ... +}; struct CONSTR; typedef int GRFFSO; diff --git a/src/P2/so.c b/src/P2/so.c index 37540a77..3ee49903 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -1,12 +1,99 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/so", InitSo__FP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/so", OnSoAdd__FP2SO); +void OnSoAdd(SO *pso) +{ + SW *psw = pso->psw; + void (*pfn)(SO *); + + psw->cpsoAll = psw->cpsoAll + 1; + if (pso->paloParent == NULL) + { + AddSwAaobrObject(psw, pso); + STRUCT_OFFSET(pso, 0x480, OXA *) = PoxaAllocSw(psw, pso); + RecalcSwOxfFilterForObject(psw, pso); + psw->cpsoRoot = psw->cpsoRoot + 1; + AppendDlEntry(&psw->dlRoot, pso); + } + OnAloAdd(pso); + EnableSoPhys(pso, 1); + pfn = (void (*)(SO *))STRUCT_OFFSET(STRUCT_OFFSET(pso, 0x0, void *), 0x120, void *); + pfn(pso); + if ((STRUCT_OFFSET(pso, 0x538, uint64_t) & ((uint64_t)0x8000 << 39)) == 0) // locked, bit 54 + { + RecalcSoLocked(STRUCT_OFFSET(pso, 0x50, SO *)); + } + else + { + RecalcSoLocked(pso); + } + RebuildSoPhysHook(pso); +} +// NOTE: This body per-symbol matches (match.sh), but enabling it trips an +// asm-emission bug in the build: the still-INCLUDE_ASM TranslateSoToPosSafe +// gets emitted 0x14 bytes too large (zero-filled words after its vadd.xyzw), +// shifting the unit and failing the checksum. Keep it wrapped until the +// surrounding functions are decompiled or the tooling quirk is fixed. INCLUDE_ASM("asm/nonmatchings/P2/so", OnSoRemove__FP2SO); +#ifdef SKIP_ASM +void OnSoRemove(SO *pso) +{ + SW *psw = pso->psw; + SO *psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); + + EnableSoPhys(pso, 0); + OnAloRemove(pso); + psw->cpsoAll = psw->cpsoAll - 1; + if (pso->paloParent == NULL) + { + RemoveSwAaobrObject(psw, pso); + FreeSwPoxa(psw, STRUCT_OFFSET(pso, 0x480, OXA *)); + psw->cpsoRoot = psw->cpsoRoot - 1; + RemoveDlEntry(&psw->dlRoot, pso); + } + FreeSwStsoList(psw, STRUCT_OFFSET(pso, 0x540, STSO *)); + STRUCT_OFFSET(pso, 0x540, STSO *) = NULL; // pstsoFirst + if ((STRUCT_OFFSET(pso, 0x538, uint64_t) & ((uint64_t)0x8000 << 39)) == 0) // locked, bit 54 + { + if (psoRoot != pso) + { + RecalcSoLocked(psoRoot); + } + } +} +#endif -INCLUDE_ASM("asm/nonmatchings/P2/so", EnableSoPhys__FP2SOi); +void EnableSoPhys(SO *pso, int fPhys) +{ + uint64_t grfso; + SO *psoRoot; + void (*pfn)(SO *); + + if (fPhys == ((STRUCT_OFFSET(pso, 0x538, uint64_t) >> 50) & 1)) + { + return; + } + if (fPhys) + { + // append to the hierarchy root's dlPhys (root SO* at 0x50, DL at 0x2D8) + AppendDlEntry(&STRUCT_OFFSET(STRUCT_OFFSET(pso, 0x50, SO *), 0x2D8, DL), pso); + } + else + { + RemoveDlEntry(&STRUCT_OFFSET(STRUCT_OFFSET(pso, 0x50, SO *), 0x2D8, DL), pso); + } + grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 50); // fPhys, grfso bit 50 + grfso |= (uint64_t)(fPhys & 1) << 50; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; + InvalidateSwXpForObject(pso->psw, pso, 7); + psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); + pfn = (void (*)(SO *))STRUCT_OFFSET(STRUCT_OFFSET(psoRoot, 0x0, void *), 0xD8, void *); + pfn(psoRoot); +} INCLUDE_ASM("asm/nonmatchings/P2/so", DisplaceSo__FP2SOi); @@ -122,7 +209,45 @@ void SetSoConstraints(SO *pso, CT ctForce, VECTOR *pnormalForce, CT ctTorque, VE } } -INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoParent__FP2SOP3ALO); +void SetSoParent(SO *pso, ALO *paloParent) +{ + VECTOR vecForce; + VECTOR vecTorque; + SO *psoRootOld; + SO *psoRoot; + + if (pso->paloParent == paloParent) + { + return; + } + psoRootOld = STRUCT_OFFSET(pso, 0x50, SO *); + // carry the constraint normals (world space) across the reparent + ConvertAloVec(pso->paloParent, NULL, (VECTOR *)&STRUCT_OFFSET(pso, 0x440, VU_VECTOR), &vecForce); + ConvertAloVec(pso->paloParent, NULL, (VECTOR *)&STRUCT_OFFSET(pso, 0x460, VU_VECTOR), &vecTorque); + SetAloParent(pso, paloParent); + ConvertAloVec(NULL, paloParent, &vecForce, (VECTOR *)&STRUCT_OFFSET(pso, 0x440, VU_VECTOR)); + ConvertAloVec(NULL, paloParent, &vecTorque, (VECTOR *)&STRUCT_OFFSET(pso, 0x460, VU_VECTOR)); + if (STRUCT_OFFSET(pso, 0x50, SO *) != NULL) + { + if (STRUCT_OFFSET(pso, 0x538, uint64_t) & ((uint64_t)0x8000 << 39)) // locked, bit 54 + { + if (psoRootOld != NULL) + { + RecalcSoLocked(psoRootOld); + } + } + psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); + if (STRUCT_OFFSET(psoRoot, 0x538, uint64_t) & ((uint64_t)0x8000 << 40)) // hierarchy locked, bit 55 + { + RecalcSoLocked(psoRoot); + } + else + { + RecalcSoLocked(pso); + } + } + RebuildSoPhysHook(pso); +} INCLUDE_ASM("asm/nonmatchings/P2/so", ApplySoProxy__FP2SOP5PROXY); @@ -211,7 +336,18 @@ void SetSoNoInteract(SO *pso, int fNoInteract) SetSoConstraints(pso, CT_Locked, NULL, CT_Locked, NULL); } -INCLUDE_ASM("asm/nonmatchings/P2/so", ConstrFromCnstr__F5CNSTRP2CTP6VECTOR); +struct CNSTRE +{ + VECTOR *pnormal; + CT ct; +}; +extern CNSTRE D_002746E0[]; // s_acnstre: CNSTR -> (ct, normal) table + +void ConstrFromCnstr(CNSTR cnstr, CT *pct, VECTOR *pnormal) +{ + *pct = D_002746E0[cnstr].ct; + *(qword *)pnormal = *(qword *)D_002746E0[cnstr].pnormal; +} INCLUDE_ASM("asm/nonmatchings/P2/so", SetSoCnstrForce__FP2SO5CNSTR); @@ -319,7 +455,41 @@ void SetSoNoXpsCenter(SO *pso, int fNoXps) DiscardSoXps__FP2SO(pso, fNoXps ? 3 : 0); } -INCLUDE_ASM("asm/nonmatchings/P2/so", RebuildSoPhysHook__FP2SO); +void RebuildSoPhysHook(SO *pso) +{ + SO *psoChild; + VECTOR vecUnused; // dead local; needed for the original's 0x30 frame + void *pvt = STRUCT_OFFSET(pso, 0x0, void *); + + // The object is its own phys hook if it overrides any of the phys + // handler virtuals (vtable slots 0x114 / 0x100 / 0x104 / 0x108). + if (STRUCT_OFFSET(pvt, 0x114, void *) != NULL || STRUCT_OFFSET(pvt, 0x100, void *) != NULL || + STRUCT_OFFSET(pvt, 0x104, void *) != NULL || STRUCT_OFFSET(pvt, 0x108, void *) != NULL) + { + STRUCT_OFFSET(pso, 0x4E4, SO *) = pso; // psoPhysHook + } + else + { + ALO *paloParent = STRUCT_OFFSET(pso, 0x18, ALO *); + if (paloParent != NULL) + { + STRUCT_OFFSET(pso, 0x4E4, SO *) = STRUCT_OFFSET(paloParent, 0x4E4, SO *); + } + else + { + STRUCT_OFFSET(pso, 0x4E4, SO *) = NULL; + } + } + for (psoChild = STRUCT_OFFSET(pso, 0x34, SO *); psoChild != NULL; + psoChild = STRUCT_OFFSET(psoChild, 0x1C, SO *)) + { + // class-flags word at vtable +0x8, bit 1 = derives from SO + if (STRUCT_OFFSET(STRUCT_OFFSET(psoChild, 0x0, void *), 0x8, int) & 2) + { + RebuildSoPhysHook(psoChild); + } + } +} SO *PsoFindSoPhysHook(SO *psoLeaf, int ib) { From eecf79bb4dba18f2ad38386b29a00f66d3ed5a7f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:12:43 +0200 Subject: [PATCH 102/134] =?UTF-8?q?Match=20HeapSort=20(sort.c)=20=E2=80=94?= =?UTF-8?q?=20sort.c=20fully=20decompiled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In-place heapsort with a unified build/extract sift loop. Matching hinged on the rotated while + else-break shape (keeps the swap arm inline and duplicates the bottom test) and a post-decrement on the last index. Co-Authored-By: Claude Fable 5 --- src/P2/sort.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/P2/sort.c b/src/P2/sort.c index 359f8cdd..959f7f9a 100644 --- a/src/P2/sort.c +++ b/src/P2/sort.c @@ -17,4 +17,53 @@ void SwapEntries(void *afoo, int cb, int i1, int i2) } } -INCLUDE_ASM("asm/nonmatchings/P2/sort", HeapSort__FPviiPFPvPv_i); +void HeapSort(void *afoo, int iMac, int cb, PFNCMP pfncmp) +{ + int iLast, cHalf, iRoot, iChild; + + if (iMac < 2) + { + return; + } + iLast = iMac - 1; + cHalf = iMac / 2; + for (;;) + { + if (cHalf > 0) + { + // build phase: sift the next non-leaf down + cHalf--; + } + else + { + // extract phase: move the max to the end, shrink the heap + SwapEntries(afoo, cb, iLast, 0); + if (iLast-- < 2) + { + return; + } + } + iRoot = cHalf; + iChild = iRoot * 2 + 1; + while (iChild <= iLast) + { + if (iChild < iLast) + { + if (pfncmp((void *)(iChild * cb + (int)afoo), (void *)((iChild + 1) * cb + (int)afoo)) < 0) + { + iChild = iChild + 1; + } + } + if (pfncmp((void *)(iRoot * cb + (int)afoo), (void *)(iChild * cb + (int)afoo)) < 0) + { + SwapEntries(afoo, cb, iRoot, iChild); + iRoot = iChild; + iChild += iChild + 1; + } + else + { + break; + } + } + } +} From 3761615360a74f69ecded6f890f0888edf0b58fd Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:30:38 +0200 Subject: [PATCH 103/134] =?UTF-8?q?Match=205=20splice=20functions=20?= =?UTF-8?q?=E2=80=94=20Splice=20perfect=20match=20crosses=2020%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RefOpSetCar/RefOpSetCdr (sret passthrough into RefOpSetCadr with BIFK_SetCar/SetCdr = 35/36), CFrame::FFindBinding (symid is unsigned per the Uii mangling), CSidebag::FFindBinding and CSidebag::CloneTo (the sidebag is a single pointer to 0x10-byte {n, CRef, next} nodes allocated by FUN_0011C498 from g_splotheapUnk1; reached via STRUCT_OFFSET to keep the placeholder class layout intact). Splice: 19.44% -> 20.19% perfect (119 -> 124 functions). Co-Authored-By: Claude Fable 5 --- include/splice/bif.h | 3 +++ include/splice/frame.h | 4 ++-- include/splice/splotheap.h | 6 ++++++ src/P2/splice/bif.cpp | 10 ++++++++-- src/P2/splice/frame.cpp | 15 ++++++++++++++- src/P2/splice/sidebag.cpp | 29 +++++++++++++++++++++++++++-- 6 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/splice/bif.h b/include/splice/bif.h index b0b1bf06..22879518 100644 --- a/include/splice/bif.h +++ b/include/splice/bif.h @@ -17,6 +17,9 @@ class CFrame; */ enum BIFK { + // ... + BIFK_SetCar = 35, + BIFK_SetCdr = 36, // ... BIFK_AddO = 99, BIFK_EnsureO = 100, diff --git a/include/splice/frame.h b/include/splice/frame.h index 249b2b5f..c615a81e 100644 --- a/include/splice/frame.h +++ b/include/splice/frame.h @@ -21,8 +21,8 @@ class CFrame void AddParent(CFrame *pframeParent); CFrame *RefAddBinding(int symid, CRef * pref); CFrame *RefSetBinding(int symid, CRef *pref); - int FFindBinding(int symid, int fRecursive, CRef *pref); - CRef *PrefFindBinding(int symid, int fRecursive); + int FFindBinding(uint symid, int fRecursive, CRef *pref); + CRef *PrefFindBinding(uint symid, int fRecursive); void CloneTo(CFrame *pframeClone); }; diff --git a/include/splice/splotheap.h b/include/splice/splotheap.h index 88623261..bc57c8b1 100644 --- a/include/splice/splotheap.h +++ b/include/splice/splotheap.h @@ -43,6 +43,12 @@ extern CSplotheap g_splotheapUnk1; extern CSplotheap g_splotheapProc; extern CSplotheap g_splotheapMethod; +// Sidebag binding-node helpers: allocate a node {int n; CRef ref; pNext} +// from g_splotheapUnk1, and recursively clone a node list. +class CFrame; +extern "C" void *FUN_0011C498(); +extern "C" void FUN_0011C418(void *psbbFrom, void *psbbTo, CFrame *pframe); + static void *PvFromPsplot(SPLOT *psplot); static SPLOT *PsplotFromPv(void *pv); bool FIsPvGarbage(void *pv); diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 26c5aa95..b68d610b 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -200,9 +200,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpCdr__FiP4CRefP6CFrame); INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSetCadr__FiP4CRefP6CFrame4BIFK); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSetCar__FiP4CRefP6CFrame); +CRef RefOpSetCar(int carg, CRef *aref, CFrame *pframe) +{ + return RefOpSetCadr(carg, aref, pframe, BIFK_SetCar); +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSetCdr__FiP4CRefP6CFrame); +CRef RefOpSetCdr(int carg, CRef *aref, CFrame *pframe) +{ + return RefOpSetCadr(carg, aref, pframe, BIFK_SetCdr); +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpLength__FiP4CRefP6CFrame); diff --git a/src/P2/splice/frame.cpp b/src/P2/splice/frame.cpp index 9a88b10c..6512e980 100644 --- a/src/P2/splice/frame.cpp +++ b/src/P2/splice/frame.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -17,7 +18,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", RefAddBinding__6CFrameUiP4CRef); INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", RefSetBinding__6CFrameUiP4CRef); -INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", FFindBinding__6CFrameUiiP4CRef); +int CFrame::FFindBinding(uint symid, int fRecursive, CRef *pref) +{ + CRef *prefFound = PrefFindBinding(symid, fRecursive); + if (prefFound != NULL) + { + if (pref != NULL) + { + *pref = *prefFound; + } + return 1; + } + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", PrefFindBinding__6CFrameUii); diff --git a/src/P2/splice/sidebag.cpp b/src/P2/splice/sidebag.cpp index 889b4be1..6cf9df74 100644 --- a/src/P2/splice/sidebag.cpp +++ b/src/P2/splice/sidebag.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include @@ -6,9 +8,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/sidebag", RefAddBinding__8CSidebagiP4CRe INCLUDE_ASM("asm/nonmatchings/P2/splice/sidebag", RefSetBinding__8CSidebagiP4CRef); -INCLUDE_ASM("asm/nonmatchings/P2/splice/sidebag", FFindBinding__8CSidebagiP4CRef); +bool CSidebag::FFindBinding(int n, CRef *pref) +{ + // The sidebag is really a single pointer to a list of 0x10-byte nodes + // { int n; CRef ref; node *pNext } (see FUN_0011C498); reach the fields + // via STRUCT_OFFSET so the declared (placeholder) layout stays intact. + void *psbb; + for (psbb = STRUCT_OFFSET(this, 0x0, void *); psbb != NULL; psbb = STRUCT_OFFSET(psbb, 0xC, void *)) + { + if (STRUCT_OFFSET(psbb, 0x0, int) == n) + { + if (pref != NULL) + { + *pref = STRUCT_OFFSET(psbb, 0x4, CRef); + } + return true; + } + } + return false; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/sidebag", CloneTo__8CSidebagP8CSidebag); +void CSidebag::CloneTo(CSidebag *psidebagClone) +{ + void *psbb = FUN_0011C498(); + FUN_0011C418(STRUCT_OFFSET(this, 0x0, void *), psbb, NULL); + STRUCT_OFFSET(psidebagClone, 0x0, void *) = psbb; +} CSidebag *PsidebagNew() { From 9e3679f279b5609f688d219a93d10f7884aab072 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:33:01 +0200 Subject: [PATCH 104/134] Match RefOpCar, RefOpCdr, RefOpCurrentTime (splice bif) Standard RefOp shape: stack CRef temp, setter, copy-construct into the hidden sret. Cdr reads the private m_ppairNext via STRUCT_OFFSET. Splice perfect match: 20.19% -> 20.90%. Co-Authored-By: Claude Fable 5 --- src/P2/splice/bif.cpp | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index b68d610b..41feb3ab 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -194,9 +196,27 @@ CRef RefOpNot(int carg, CRef *aref, CFrame *pframe) INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpCons__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpCar__FiP4CRefP6CFrame); +CRef RefOpCar(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref = aref->m_tag.m_ppair->m_ref; + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpCdr__FiP4CRefP6CFrame); +CRef RefOpCdr(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + CPair *ppairNext = STRUCT_OFFSET(aref->m_tag.m_ppair, 0x8, CPair *); // m_ppairNext (private) + if (ppairNext != NULL) + { + ref.SetPair(ppairNext); + } + else + { + ref.SetTag(TAGK_None); + } + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSetCadr__FiP4CRefP6CFrame4BIFK); @@ -359,7 +379,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMinimum__FiP4CRefP6CFrame); INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpModulo__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpCurrentTime__FiP4CRefP6CFrame); +CRef RefOpCurrentTime(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetF32(g_clock.t); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpScheduleCallback__FiP4CRefP6CFrame); From ba7aeb7ddf0e94870327c11da9cdd08deec888ff Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:45:07 +0200 Subject: [PATCH 105/134] Match 8 more splice functions (float ops, modulo, music register, RefCoerce) RefOpFloor/Truncate/Ceiling/Round/Modulo/SetMusicRegister plus CRef::RefCoerceS32/F32 (ref.h signatures corrected to the sret form). SetAMRegister bound by literal mangled name: ROM callers pass the second arg unnarrowed. RefOpStopSound matches but stays wrapped (asm-emission bug inflates the following still-asm function). Co-Authored-By: Claude Fable 5 --- include/sound.h | 5 ++++ include/splice/ref.h | 4 +-- src/P2/splice/bif.cpp | 57 ++++++++++++++++++++++++++++++++++++++----- src/P2/splice/ref.cpp | 24 ++++++++++++++++-- 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/include/sound.h b/include/sound.h index 98197604..5ab544e8 100644 --- a/include/sound.h +++ b/include/sound.h @@ -256,6 +256,11 @@ void StartSound(SFXID sfxid, AMB **ppamb, ALO *palo, VECTOR *ppos, float sStart, */ void StopSound(AMB *pamb, int msRampdown); +// The symbol's GCC2 mangling says (int, unsigned char), but the ROM call +// sites pass the second argument as a plain word with no narrowing, so the +// in-game declaration must have taken ints; bind by literal symbol name. +extern "C" void SetAMRegister__FiUc(int n, int bReg); + /** * @brief TODO */ diff --git a/include/splice/ref.h b/include/splice/ref.h index f13bfa4a..4c0fde8b 100644 --- a/include/splice/ref.h +++ b/include/splice/ref.h @@ -102,8 +102,8 @@ class CRef void SetSmp(SMP *psmp); void SetBasic(BASIC *pbasic); void SetMethod(CMethod *pmethod); - int RefCoerceS32() const; - float RefCoerceF32() const; + CRef RefCoerceS32(); + CRef RefCoerceF32(); }; #endif // SPLICE_REF_H diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 41feb3ab..26fd8293 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -255,7 +256,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpVector__FiP4CRefP6CFrame); INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrix__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSetMusicRegister__FiP4CRefP6CFrame); +CRef RefOpSetMusicRegister(int carg, CRef *aref, CFrame *pframe) +{ + SetAMRegister__FiUc(aref[0].m_tag.m_n, aref[1].m_tag.m_n); + CRef ref; + ref.SetTag(TAGK_Void); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpClq__FiP4CRefP6CFrame); @@ -363,13 +370,33 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpLmLimit__FiP4CRefP6CFrame); INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpLmCheck__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpFloor__FiP4CRefP6CFrame); +CRef RefOpFloor(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetS32((int)aref->m_tag.m_g); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpCeiling__FiP4CRefP6CFrame); +CRef RefOpCeiling(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetS32((int)(aref->m_tag.m_g + 1.0f)); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpRound__FiP4CRefP6CFrame); +CRef RefOpRound(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetS32((int)(aref->m_tag.m_g + 0.5f)); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpTruncate__FiP4CRefP6CFrame); +CRef RefOpTruncate(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetS32((int)aref->m_tag.m_g); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpAbs__FiP4CRefP6CFrame); @@ -377,7 +404,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMaximum__FiP4CRefP6CFrame); INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMinimum__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpModulo__FiP4CRefP6CFrame); +CRef RefOpModulo(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetS32(aref[0].m_tag.m_n % aref[1].m_tag.m_n); + return ref; +} CRef RefOpCurrentTime(int carg, CRef *aref, CFrame *pframe) { @@ -465,7 +497,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpNearClipCenter__FiP4CRefP6CFr INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpStartSound__FiP4CRefP6CFrame); +// NOTE: matches per-symbol, but unwrapping it trips the asm-emission bug on +// the still-asm RefOpPredictAnimationEffect that follows (+0x14 of phantom +// bytes -> checksum fail), same as so.c OnSoRemove. Keep wrapped until the +// neighbor is decompiled. INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpStopSound__FiP4CRefP6CFrame); +#ifdef SKIP_ASM +CRef RefOpStopSound(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + StopSound((AMB *)aref->m_tag.m_pbasic, 0); + ref.m_tagk = TAGK_Void; + return ref; +} +#endif INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpStartRumble__FiP4CRefP6CFrame); diff --git a/src/P2/splice/ref.cpp b/src/P2/splice/ref.cpp index 8e91db9f..2721f95e 100644 --- a/src/P2/splice/ref.cpp +++ b/src/P2/splice/ref.cpp @@ -253,6 +253,26 @@ void CRef::SetMethod(CMethod *pmethod) m_tagk = TAGK_Method; } -INCLUDE_ASM("asm/nonmatchings/P2/splice/ref", RefCoerceS32__4CRef); +CRef CRef::RefCoerceS32() +{ + if (m_tagk == TAGK_S32) + { + return *this; + } + CRef ref; + ref.SetS32((int)m_tag.m_g); + return ref; +} + +CRef CRef::RefCoerceF32() +{ + if (m_tagk == TAGK_F32) + { + return *this; + } + CRef ref; + ref.SetF32((float)m_tag.m_n); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/ref", RefCoerceF32__4CRef); +JUNK_NOP(); From f90a8a553ca0019065e7904201e1b7e3746dfd2e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:51:00 +0200 Subject: [PATCH 106/134] Match 8 more splice functions (matrix RefOps, find-object RefOps, CFrame::CloneTo, RefEvalSymbol) Co-Authored-By: Claude Fable 5 --- include/splice/eval.h | 7 ++++++ include/splice/vecmat.h | 2 ++ src/P2/splice/bif.cpp | 53 ++++++++++++++++++++++++++++++++++++----- src/P2/splice/eval.cpp | 12 ++++++++-- src/P2/splice/frame.cpp | 14 ++++++++++- 5 files changed, 79 insertions(+), 9 deletions(-) diff --git a/include/splice/eval.h b/include/splice/eval.h index 12f12806..88167954 100644 --- a/include/splice/eval.h +++ b/include/splice/eval.h @@ -6,6 +6,13 @@ #include "common.h" +// Forward. +class CRef; +class CPair; +class CFrame; + +CRef RefEvalSymbol(CPair *ppair, CFrame *pframe); + // ... #endif // SPLICE_EVAL_H diff --git a/include/splice/vecmat.h b/include/splice/vecmat.h index 4b473f36..06fc13e8 100644 --- a/include/splice/vecmat.h +++ b/include/splice/vecmat.h @@ -11,6 +11,8 @@ VECTOR *PvectorNew(); +MATRIX4 *PmatrixNew(); + void IncrefVector(VECTOR *pvector); void DecrefVector(VECTOR *pvector); diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 26fd8293..1e6aedf9 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include @@ -340,15 +342,43 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpVectorBallisticVelocity__FiP4 INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpVectorRadianNormal__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrixTranspose__FiP4CRefP6CFrame); +CRef RefOpMatrixTranspose(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + MATRIX4 *pmatrix = PmatrixNew(); + TransposeMatrix4(aref->m_tag.m_pmatrix, pmatrix); + ref.SetMatrix(pmatrix); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrixInvert__FiP4CRefP6CFrame); +CRef RefOpMatrixInvert(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + MATRIX4 *pmatrix = PmatrixNew(); + FInvertMatrix4(aref->m_tag.m_pmatrix, pmatrix); + ref.SetMatrix(pmatrix); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrixCalculateDmat__FiP4CRefP6CFrame); +CRef RefOpMatrixCalculateDmat(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + MATRIX4 *pmatrix = PmatrixNew(); + CalculateDmat4(aref[0].m_tag.m_pmatrix, aref[1].m_tag.m_pmatrix, pmatrix); + ref.SetMatrix(pmatrix); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrixInterpolateRotate__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrixDecomposeToTranslate__FiP4CRefP6CFrame); +CRef RefOpMatrixDecomposeToTranslate(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + VECTOR *pvector = PvectorNew(); + *(qword *)pvector = STRUCT_OFFSET(aref->m_tag.m_pmatrix, 0x30, qword); // matrix.pos row + ref.SetVector(pvector); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrixDecomposeToRotate__FiP4CRefP6CFrame); @@ -446,11 +476,22 @@ CRef RefOpGetO(int carg, CRef *aref, CFrame *pframe) INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefPairFromAplo__FiPP2LO); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpFindObject__FiP4CRefP6CFrame); +CRef RefOpFindObject(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + LO *plo = (LO *)aref[1].m_tag.m_pbasic; + ref.SetBasic((BASIC *)PloFindSwObject(g_psw, plo ? 0x101 : 0x105, (OID)aref[0].m_tag.m_n, plo)); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpFindObjects__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpFindNearestObject__FiP4CRefP6CFrame); +CRef RefOpFindNearestObject(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref.SetBasic((BASIC *)PloFindSwObject(g_psw, 0x104, (OID)aref[0].m_tag.m_n, (LO *)aref[1].m_tag.m_pbasic)); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpFindNearestObjects__FiP4CRefP6CFrame); diff --git a/src/P2/splice/eval.cpp b/src/P2/splice/eval.cpp index 10d74412..80e11eb7 100644 --- a/src/P2/splice/eval.cpp +++ b/src/P2/splice/eval.cpp @@ -1,6 +1,14 @@ #include - -INCLUDE_ASM("asm/nonmatchings/P2/splice/eval", RefEvalSymbol__FP5CPairP6CFrame); +#include +#include +#include + +CRef RefEvalSymbol(CPair *ppair, CFrame *pframe) +{ + CRef ref; + pframe->FFindBinding(ppair->m_ref.m_tag.m_symid, 1, &ref); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/eval", RefEvalSet__FP5CPairP6CFrame); diff --git a/src/P2/splice/frame.cpp b/src/P2/splice/frame.cpp index 6512e980..ba32b859 100644 --- a/src/P2/splice/frame.cpp +++ b/src/P2/splice/frame.cpp @@ -2,6 +2,7 @@ #include #include #include +#include void CFrame::SetSingleParent(CFrame *pframeParent) { @@ -34,7 +35,18 @@ int CFrame::FFindBinding(uint symid, int fRecursive, CRef *pref) INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", PrefFindBinding__6CFrameUii); -INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", CloneTo__6CFrameP6CFrame); +void CFrame::CloneTo(CFrame *pframeClone) +{ + pframeClone->m_cpframeParent = m_cpframeParent; + CopyAb(pframeClone->m_apframeParent, m_apframeParent, m_cpframeParent * 4); + // binding-node list head at +0x14 (same node type as CSidebag) + if (STRUCT_OFFSET(this, 0x14, void *) != NULL) + { + void *psbb = FUN_0011C498(); + FUN_0011C418(STRUCT_OFFSET(this, 0x14, void *), psbb, pframeClone); + STRUCT_OFFSET(pframeClone, 0x14, void *) = psbb; + } +} CFrame *PframeNew() { From b22a845d448dbba927cce77e11686d52399c96ac Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 22:55:43 +0200 Subject: [PATCH 107/134] Match 8 more splice functions (binding ops, Random, RandomSeed, ConvertObject*) CFrame/CSidebag Ref{Add,Set}Binding return CRef via sret (headers fixed). RefOpAbs also matches (__builtin_abs gives the branchy abssi2) but stays wrapped: unwrapping it inflates the still-asm RefOpPredictAnimationEffect emission and fails the checksum (same bug as RefOpStopSound). Co-Authored-By: Claude Fable 5 --- include/splice/frame.h | 4 +- include/splice/sidebag.h | 4 +- src/P2/splice/bif.cpp | 82 +++++++++++++++++++++++++++++++++++++-- src/P2/splice/frame.cpp | 24 +++++++++++- src/P2/splice/sidebag.cpp | 34 +++++++++++++++- 5 files changed, 136 insertions(+), 12 deletions(-) diff --git a/include/splice/frame.h b/include/splice/frame.h index c615a81e..24c7c4d1 100644 --- a/include/splice/frame.h +++ b/include/splice/frame.h @@ -19,8 +19,8 @@ class CFrame public: void SetSingleParent(CFrame *pframeParent); void AddParent(CFrame *pframeParent); - CFrame *RefAddBinding(int symid, CRef * pref); - CFrame *RefSetBinding(int symid, CRef *pref); + CRef RefAddBinding(uint symid, CRef *pref); + CRef RefSetBinding(uint symid, CRef *pref); int FFindBinding(uint symid, int fRecursive, CRef *pref); CRef *PrefFindBinding(uint symid, int fRecursive); void CloneTo(CFrame *pframeClone); diff --git a/include/splice/sidebag.h b/include/splice/sidebag.h index 858d3469..a806c91b 100644 --- a/include/splice/sidebag.h +++ b/include/splice/sidebag.h @@ -30,9 +30,9 @@ class CSidebag SBB m_asbb[16]; public: - CSidebag& RefAddBinding(int n, CRef *pref); + CRef RefAddBinding(int n, CRef *pref); - CSidebag& RefSetBinding(int n, CRef *pref); + CRef RefSetBinding(int n, CRef *pref); bool FFindBinding(int n, CRef *pref); diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 1e6aedf9..001db938 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include #include @@ -274,9 +276,44 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpSmp__FiP4CRefP6CFrame); INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpGetElement__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpRandomSeed__FiP4CRefP6CFrame); +CRef RefOpRandomSeed(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + if (aref->m_tagk == TAGK_S32) + { + srand(aref->m_tag.m_n); + } + else + { + srand((int)aref->m_tag.m_g); + } + ref.m_tagk = TAGK_Void; + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpRandom__FiP4CRefP6CFrame); +CRef RefOpRandom(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + float g0, g1; + if (aref[0].m_tagk == TAGK_S32) + { + g0 = (float)aref[0].m_tag.m_n; + } + else + { + g0 = aref[0].m_tag.m_g; + } + if (aref[1].m_tagk == TAGK_S32) + { + g1 = (float)aref[1].m_tag.m_n; + } + else + { + g1 = aref[1].m_tag.m_g; + } + ref.SetF32(GRandInRange(g0, g1)); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefUfo__FP4CRef4UFOK); @@ -428,7 +465,30 @@ CRef RefOpTruncate(int carg, CRef *aref, CFrame *pframe) return ref; } +// NOTE: matches per-symbol, but unwrapping it inflates the still-asm +// RefOpPredictAnimationEffect emission (same tooling bug as RefOpStopSound) +// and fails the checksum. Keep wrapped for now. INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpAbs__FiP4CRefP6CFrame); +#ifdef SKIP_ASM +CRef RefOpAbs(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + if (aref->m_tagk == TAGK_S32) + { + ref.SetS32(__builtin_abs(aref->m_tag.m_n)); + } + else + { + float g = aref->m_tag.m_g; + if (g < 0.0f) + { + g = -g; + } + ref.SetF32(g); + } + return ref; +} +#endif INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMaximum__FiP4CRefP6CFrame); @@ -528,9 +588,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpHitTestObjects__FiP4CRefP6CFr INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpHitTestObjectsFirst__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpConvertObjectPosition__FiP4CRefP6CFrame); +CRef RefOpConvertObjectPosition(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + VECTOR *pvector = PvectorNew(); + ConvertAloPos((ALO *)aref[0].m_tag.m_pbasic, (ALO *)aref[1].m_tag.m_pbasic, aref[2].m_tag.m_pvector, pvector); + ref.SetVector(pvector); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpConvertObjectVector__FiP4CRefP6CFrame); +CRef RefOpConvertObjectVector(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + VECTOR *pvector = PvectorNew(); + ConvertAloVec((ALO *)aref[0].m_tag.m_pbasic, (ALO *)aref[1].m_tag.m_pbasic, aref[2].m_tag.m_pvector, pvector); + ref.SetVector(pvector); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpConvertObjectMatrix__FiP4CRefP6CFrame); diff --git a/src/P2/splice/frame.cpp b/src/P2/splice/frame.cpp index ba32b859..e0d4d8a1 100644 --- a/src/P2/splice/frame.cpp +++ b/src/P2/splice/frame.cpp @@ -15,9 +15,29 @@ void CFrame::AddParent(CFrame *pframeParent) m_apframeParent[m_cpframeParent++] = pframeParent; } -INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", RefAddBinding__6CFrameUiP4CRef); +CRef CFrame::RefAddBinding(uint symid, CRef *pref) +{ + CRef ref; + void *psbb = FUN_0011C498(); + STRUCT_OFFSET(psbb, 0x0, uint) = symid; + STRUCT_OFFSET(psbb, 0x4, CRef) = *pref; + STRUCT_OFFSET(psbb, 0xC, void *) = STRUCT_OFFSET(this, 0x14, void *); + STRUCT_OFFSET(this, 0x14, void *) = psbb; + ref.SetTag(TAGK_Void); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/frame", RefSetBinding__6CFrameUiP4CRef); +CRef CFrame::RefSetBinding(uint symid, CRef *pref) +{ + CRef ref; + CRef *prefFound = PrefFindBinding(symid, 1); + if (prefFound != NULL) + { + *prefFound = *pref; + } + ref.SetTag(TAGK_Void); + return ref; +} int CFrame::FFindBinding(uint symid, int fRecursive, CRef *pref) { diff --git a/src/P2/splice/sidebag.cpp b/src/P2/splice/sidebag.cpp index 6cf9df74..4ea49658 100644 --- a/src/P2/splice/sidebag.cpp +++ b/src/P2/splice/sidebag.cpp @@ -4,9 +4,39 @@ #include #include -INCLUDE_ASM("asm/nonmatchings/P2/splice/sidebag", RefAddBinding__8CSidebagiP4CRef); +CRef CSidebag::RefAddBinding(int n, CRef *pref) +{ + CRef ref; + void *psbb = FUN_0011C498(); + STRUCT_OFFSET(psbb, 0x0, int) = n; + STRUCT_OFFSET(psbb, 0x4, CRef) = *pref; + STRUCT_OFFSET(psbb, 0xC, void *) = STRUCT_OFFSET(this, 0x0, void *); + STRUCT_OFFSET(this, 0x0, void *) = psbb; + ref.SetTag(TAGK_Void); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/sidebag", RefSetBinding__8CSidebagiP4CRef); +CRef CSidebag::RefSetBinding(int n, CRef *pref) +{ + void *psbb = STRUCT_OFFSET(this, 0x0, void *); + if (psbb != NULL) + { + do + { + if (STRUCT_OFFSET(psbb, 0x0, int) == n) + { + CRef ref; + STRUCT_OFFSET(psbb, 0x4, CRef) = *pref; + ref.SetTag(TAGK_Void); + return ref; + } + psbb = STRUCT_OFFSET(psbb, 0xC, void *); + } while (psbb != NULL); + } + CRef ref; + ref.SetTag(TAGK_Void); + return ref; +} bool CSidebag::FFindBinding(int n, CRef *pref) { From b87198dd3a9df1e71723968771748e806f87b242 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 10 Jun 2026 23:03:50 +0200 Subject: [PATCH 108/134] Match RefOpHitTestObjects/First, RefOpLength, RefOpDeferObjectUpdate HitTest pair: sret-temp wrappers over RefOpHitTestObjectsImpl with BIFK 113/114. DeferObjectUpdate needed a nested-scope named temp so the coerced float survives the temp's destructor in $f20. Co-Authored-By: Claude Fable 5 --- include/splice/bif.h | 3 +++ src/P2/splice/bif.cpp | 47 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/splice/bif.h b/include/splice/bif.h index 22879518..92f370de 100644 --- a/include/splice/bif.h +++ b/include/splice/bif.h @@ -21,6 +21,9 @@ enum BIFK BIFK_SetCar = 35, BIFK_SetCdr = 36, // ... + BIFK_HitTestObjects = 113, + BIFK_HitTestObjectsFirst = 114, + // ... BIFK_AddO = 99, BIFK_EnsureO = 100, BIFK_SetO = 101, diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 001db938..1c9057a2 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -235,7 +235,25 @@ CRef RefOpSetCdr(int carg, CRef *aref, CFrame *pframe) return RefOpSetCadr(carg, aref, pframe, BIFK_SetCdr); } -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpLength__FiP4CRefP6CFrame); +CRef RefOpLength(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + int c = 0; + if (aref->m_tagk == TAGK_Pair) + { + CPair *ppair = aref->m_tag.m_ppair; + if (ppair != NULL) + { + do + { + ppair = STRUCT_OFFSET(ppair, 0x8, CPair *); // m_ppairNext + c = c + 1; + } while (ppair != NULL); + } + } + ref.SetS32(c); + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpNth__FiP4CRefP6CFrame); @@ -510,7 +528,18 @@ CRef RefOpCurrentTime(int carg, CRef *aref, CFrame *pframe) INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpScheduleCallback__FiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpDeferObjectUpdate__FiP4CRefP6CFrame); +CRef RefOpDeferObjectUpdate(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + BASIC *pbasic = aref->m_tag.m_pbasic; + float g; + { + CRef refCoerced = aref[1].RefCoerceF32(); + g = refCoerced.m_tag.m_g; + } + STRUCT_OFFSET(pbasic, 0x29C, float) = g; + return ref; +} INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpObjectOption__FiP4CRefP6CFrame4BIFK); @@ -584,9 +613,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpFindObjectsInBoundingSphere__ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpHitTestObjectsImpl__F4BIFKiP4CRefP6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpHitTestObjects__FiP4CRefP6CFrame); +CRef RefOpHitTestObjects(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref = RefOpHitTestObjectsImpl(BIFK_HitTestObjects, carg, aref, pframe); + return ref; +} -INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpHitTestObjectsFirst__FiP4CRefP6CFrame); +CRef RefOpHitTestObjectsFirst(int carg, CRef *aref, CFrame *pframe) +{ + CRef ref; + ref = RefOpHitTestObjectsImpl(BIFK_HitTestObjectsFirst, carg, aref, pframe); + return ref; +} CRef RefOpConvertObjectPosition(int carg, CRef *aref, CFrame *pframe) { From e2a4d4fc98e0058cb0a2d8327f8f3eb6564a3650 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 12 Jun 2026 22:35:54 +0200 Subject: [PATCH 109/134] Match 18 wave-1 LHF functions (alo lookat/throb getters, sound VAG, sw splice helpers) Co-Authored-By: Claude Fable 5 --- .gitignore | 7 +++ config/symbol_addrs.txt | 6 +-- src/P2/alo.c | 103 ++++++++++++++++++++++++++++++++++++---- src/P2/sound.c | 24 ++++++++-- src/P2/sw.c | 36 ++++++++++++-- 5 files changed, 155 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index dc71004c..b6f4a9c9 100644 --- a/.gitignore +++ b/.gitignore @@ -88,3 +88,10 @@ __pycache__/ temp/ *.diff *.AppImage + +# Local Claude/agent tooling — keep out of git +CLAUDE.md +.claude/ +docs/DECOMP_PROMPT.md +report_old.json +report_premedium.json diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index e8ac47fe..a917bcd7 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -4592,7 +4592,7 @@ FUN_001dd7e8 = 0x1DD7E8; // FUN_001dd888 = 0x1DD888; // type:func FUN_001dd8e8__FP2SW9GAMEWORLD = 0x1DD8E8; // type:func FUN_001dd908__FP2SW9GAMEWORLD = 0x1DD908; // type:func -FUN_001dd928 = 0x1DD928; // type:func +FUN_001dd928__FP2SW = 0x1DD928; // type:func FUN_001dd950 = 0x1DD950; // type:func FUN_001dd9a0__Ff = 0x1DD9A0; // type:func FUN_001dd9c0__FPvPf = 0x1DD9C0; // type:func @@ -4608,8 +4608,8 @@ CancelSwDialogPlaying__FP2SW = 0x1DDAD0; // FUN_001ddb20 = 0x1DDB20; // type:func FUN_001ddb58 = 0x1DDB58; // type:func FUN_001ddbb8 = 0x1DDBB8; // type:func -FUN_001ddbf8 = 0x1DDBF8; // type:func -FUN_001ddc18 = 0x1DDC18; // type:func +FUN_001ddbf8__FP2SWi = 0x1DDBF8; // type:func +FUN_001ddc18__FP2SWP3EXC = 0x1DDC18; // type:func FUN_001ddc38 = 0x1DDC38; // type:func FUN_001ddc40 = 0x1DDC40; // type:func FUN_001ddc78__FPvi = 0x1DDC78; // type:func diff --git a/src/P2/alo.c b/src/P2/alo.c index 05346221..b37a0cc5 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -394,7 +394,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a3c8); INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a3e8); -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a418); +extern "C" void FUN_0012a418(ALO *palo, int *pn) +{ + *pn = (int)(STRUCT_OFFSET(palo, 0x2c8, uint64_t) >> 40) & 3; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestorePositionAck__FP3ALO3ACK); @@ -421,19 +424,65 @@ void GetAloLookAtIgnore(ALO *palo, float *psIgnore) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtPanFunction__FP3ALOP3CLQ); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtPanFunction__FP3ALOP3CLQ); +void GetAloLookAtPanFunction(ALO *palo, CLQ *pclq) +{ + extern CLQ D_00275C40; + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + CLQ *pclqSrc; + + if (pactla) + pclqSrc = &STRUCT_OFFSET(pactla, 0x50, CLQ); + else + pclqSrc = &D_00275C40; + + *(VU_VECTOR *)pclq = *(VU_VECTOR *)pclqSrc; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtPanLimits__FP3ALOP2LM); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtPanLimits__FP3ALOP2LM); +void GetAloLookAtPanLimits(ALO *palo, LM *plm) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + LM *plmSrc; + + if (pactla) + plmSrc = &STRUCT_OFFSET(pactla, 0x60, LM); + else + plmSrc = &g_lmZeroOne; + + *plm = *plmSrc; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtTiltFunction__FP3ALOP3CLQ); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtTiltFunction__FP3ALOP3CLQ); +extern qword D_00275C40; +void GetAloLookAtTiltFunction(ALO *palo, CLQ *pclq) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + qword *pqSrc; + + if (pactla) + pqSrc = &STRUCT_OFFSET(pactla, 0x70, qword); + else + pqSrc = &D_00275C40; + + *(qword *)pclq = *pqSrc; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtTiltLimits__FP3ALOP2LM); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloLookAtTiltLimits__FP3ALOP2LM); +void GetAloLookAtTiltLimits(ALO *palo, LM *plm) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + LM *plmSrc; + + if (pactla) + plmSrc = &STRUCT_OFFSET(pactla, 0x80, LM); + else + plmSrc = &g_lmZeroOne; + + *plm = *plmSrc; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtEnabledPriority__FP3ALOi); @@ -475,7 +524,11 @@ void FUN_0012a8b8(ALO *palo) STRUCT_OFFSET(pactla, 0x4C, int) = 0; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a8c8); +extern "C" void FUN_0012a8c8(ALO *palo) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + STRUCT_OFFSET(pactla, 0x4C, int) = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationMatchesVelocity__FP3ALOff3ACK); @@ -662,11 +715,38 @@ void GetAloThrobKind(ALO *palo, THROBK *pthrobk) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloThrobInColor__FP3ALOP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloThrobInColor__FP3ALOP6VECTOR); +extern VU_VECTOR D_00248D30; +void GetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) +{ + THROB *pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); // palo->pthrob + VU_VECTOR *pqSrc; + + if (pthrob) + pqSrc = &STRUCT_OFFSET(pthrob, 0x10, VU_VECTOR); // pthrob->hsvInColor + else + pqSrc = &D_00248D30; + + *(VU_VECTOR *)phsvInColor = *pqSrc; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloThrobOutColor__FP3ALOP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloThrobOutColor__FP3ALOP6VECTOR); +void GetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) +{ + THROB *pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); // palo->throb + VU_VECTOR *pvuvec; + + if (pthrob != 0) + { + pvuvec = &STRUCT_OFFSET(pthrob, 0x20, VU_VECTOR); + } + else + { + pvuvec = &D_00248D30; + } + + *(VU_VECTOR *)phsvOutColor = *pvuvec; +} void SetAloThrobDtInOut(ALO *palo, float dtInOut) { @@ -685,7 +765,12 @@ void GetAloThrobDtInOut(ALO *palo, float *pdtInOut) *pdtInOut = dtInOut; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloInteractCane__FP3ALOi); +void SetAloInteractCane(ALO *palo, GRFIC grfic) +{ + STRUCT_OFFSET(palo, 0x2b2, char) = grfic; + STRUCT_OFFSET(palo, 0x2b1, char) = grfic; + STRUCT_OFFSET(palo, 0x2b0, char) = grfic; +} void GetAloInteractCane(ALO *palo, GRFIC *pgrfic) { diff --git a/src/P2/sound.c b/src/P2/sound.c index d744a4e5..0b0d8970 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -44,7 +44,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", RefreshPambVolPan__FP3AMB); INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001be8f8); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FVagPlaying__Fv); +extern u_int D_0027472C; +int FVagPlaying() +{ + return D_0027472C != 0; +} JUNK_WORD(0x0080102D); @@ -109,7 +113,11 @@ void StartupSound() JUNK_NOP(); JUNK_ADDIU(10); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FAmbientsPaused__Fv); +extern int D_00274748; +int FAmbientsPaused() +{ + return D_00274748; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", CalculateVolPan__FfP6VECTORPfT2fff); @@ -129,7 +137,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", CalculateDistVolPan__FP6VECTORPfT1fff); INCLUDE_ASM("asm/nonmatchings/P2/sound", PambAlloc__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/sound", DropPamb__FPP3AMB); +void DropPamb(AMB **ppamb) +{ + (*ppamb)->ppamb = NULL; + *ppamb = NULL; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", RemoveAmb__FP3AMB); @@ -225,7 +237,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", StartSwIntermittentSounds__FP2SW); // TODO: Verify signature. INCLUDE_ASM("asm/nonmatchings/P2/sound", SetAMRegister__FiUc); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001c0c50); +extern int D_006053E0[]; +extern "C" int FUN_001c0c50(int reg) +{ + return D_006053E0[reg]; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001c0c68); diff --git a/src/P2/sw.c b/src/P2/sw.c index e31c1256..7ad4998b 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -8,6 +8,7 @@ #include #include #include +#include extern SW *g_psw; extern int g_fLoadDebugInfo; @@ -46,7 +47,10 @@ void LoadBulkDataFromBrx(CBinaryInputStream *pbis) INCLUDE_ASM("asm/nonmatchings/P2/sw", SetSwGravity__FP2SWf); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dbac0); +extern "C" void FUN_001dbac0(SW *psw, int reg, int value) +{ + SetAMRegister__FiUc(reg, value); +} int FUN_001dbae0(SW *psw, int reg) { @@ -167,7 +171,16 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", RemoveOxa__FP3OXAPP3OXA); INCLUDE_ASM("asm/nonmatchings/P2/sw", InitSwAoxa__FP2SW); -INCLUDE_ASM("asm/nonmatchings/P2/sw", AddOxa__FP3OXAPP3OXA); +void AddOxa(OXA *poxa, OXA **ppoxaFirst) +{ + poxa->poxaNext = *ppoxaFirst; + poxa->poxaPrev = NULL; + if (*ppoxaFirst != NULL) + { + (*ppoxaFirst)->poxaPrev = poxa; + } + *ppoxaFirst = poxa; +} INCLUDE_ASM("asm/nonmatchings/P2/sw", PoxaAllocSw__FP2SWP2SO); @@ -261,7 +274,10 @@ int FUN_001dd908(SW *psw, GAMEWORLD gameworld) return g_pgsCur->aws[gameworld].fws & 0x20; } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd928); +int FUN_001dd928(SW *psw) +{ + return CalculatePercentCompletion(g_pgsCur); +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd950); @@ -339,9 +355,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddb58); INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddbb8); JUNK_WORD(0x0002102a); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddbf8); +EXC *PexcSetExcitement(int gexc); + +EXC *FUN_001ddbf8(SW *psw, int gexc) +{ + return PexcSetExcitement(gexc); +} -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc18); +void UnsetExcitementHyst(EXC *pexc); + +void FUN_001ddc18(SW *psw, EXC *pexc) +{ + UnsetExcitementHyst(pexc); +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc38); From 7b7bd772a9c9bb28eda43b36776655a647f9be10 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 12 Jun 2026 22:42:25 +0200 Subject: [PATCH 110/134] Match 25 more wave-1 functions (sound VAG/music, mpeg queue callbacks, sw splice setters, alo restore/lookat) RenderSoSelf reverted: so.c emits +0x18 zero-fill on a still-asm neighbor when added (same pathology as OnSoRemove). Co-Authored-By: Claude Fable 5 --- config/symbol_addrs.txt | 10 ++--- src/P2/alo.c | 35 +++++++++++++--- src/P2/mpeg.c | 93 +++++++++++++++++++++++++++++++++++++---- src/P2/so.c | 5 ++- src/P2/sound.c | 57 +++++++++++++++++++++---- src/P2/sw.c | 20 +++++++-- 6 files changed, 189 insertions(+), 31 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index a917bcd7..dcb1d81a 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -801,7 +801,7 @@ GetAloLookAtEnabledPriority__FP3ALOPi = 0x12A7A8; // type:f SetAloLookAtDisabledPriority__FP3ALOi = 0x12A7C0; // type:func GetAloLookAtDisabledPriority__FP3ALOPi = 0x12A7F8; // type:func FUN_0012a810 = 0x12A810; // type:func -FUN_0012a848 = 0x12A848; // type:func +FUN_0012a848__FP3ALOPi = 0x12A848; // type:func FUN_0012a860 = 0x12A860; // type:func FUN_0012a888 = 0x12A888; // type:func FUN_0012a8b8__FP3ALO = 0x12A8B8; // type:func @@ -4610,12 +4610,12 @@ FUN_001ddb58 = 0x1DDB58; // FUN_001ddbb8 = 0x1DDBB8; // type:func FUN_001ddbf8__FP2SWi = 0x1DDBF8; // type:func FUN_001ddc18__FP2SWP3EXC = 0x1DDC18; // type:func -FUN_001ddc38 = 0x1DDC38; // type:func +FUN_001ddc38__FPvT0 = 0x1DDC38; // type:func FUN_001ddc40 = 0x1DDC40; // type:func FUN_001ddc78__FPvi = 0x1DDC78; // type:func -FUN_001ddc90 = 0x1DDC90; // type:func -FUN_001ddcb0 = 0x1DDCB0; // type:func -FUN_001ddcc8 = 0x1DDCC8; // type:func +FUN_001ddc90__FPvi = 0x1DDC90; // type:func +FUN_001ddcb0__FPvPi = 0x1DDCB0; // type:func +FUN_001ddcc8__FPvPi = 0x1DDCC8; // type:func g_grfdfl = 0x275630; // size:0x10 g_vecHighlight = 0x275640; // size:0x10 diff --git a/src/P2/alo.c b/src/P2/alo.c index b37a0cc5..48190f4d 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -6,6 +6,7 @@ #include #include #include +#include extern VTACT g_vtactseg; extern SHADOW s_shadow; @@ -388,9 +389,17 @@ void SetAloDefaultAckRot(ALO *palo, ACK ack) STRUCT_OFFSET(palo, 0x2ca, char) = ack; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestorePosition__FP3ALOi); +void SetAloRestorePosition(ALO *palo, int fRestore) +{ + SetAloRestorePositionAck(palo, fRestore ? ACK_Spring : ACK_Nil); +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a3c8); +extern "C" void FUN_0012a3e8(ALO *palo, int unk); + +extern "C" void FUN_0012a3c8(ALO *palo, int unk) +{ + FUN_0012a3e8(palo, unk != 0); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a3e8); @@ -401,7 +410,10 @@ extern "C" void FUN_0012a418(ALO *palo, int *pn) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestorePositionAck__FP3ALO3ACK); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestoreRotation__FP3ALOi); +void SetAloRestoreRotation(ALO *palo, int fRestore) +{ + SetAloRestoreRotationAck(palo, fRestore ? ACK_Spring : ACK_Nil); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestoreRotationAck__FP3ALO3ACK); @@ -512,9 +524,22 @@ void GetAloLookAtDisabledPriority(ALO *palo, int *pnPriority) INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a810); -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a848); +void FUN_0012a848(ALO *palo, int *pn) +{ + void *pactla = STRUCT_OFFSET(palo, 0x200, void *); + int n = -1; + + if (pactla) + n = STRUCT_OFFSET(pactla, 0x20, int); -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a860); + *pn = n; +} + +extern "C" void FUN_0012a860(ALO *palo, ALO *paloTarget) +{ + extern VECTOR D_00248D30; + SetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *), paloTarget, &D_00248D30); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a888); diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 16a9e044..ef602faa 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -12,9 +12,59 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e558); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", StartupMpeg__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Init__15CQueueOutputIopii); - -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Reset__15CQueueOutputIop); +#ifndef CQUEUEOUTPUTIOP_DEFINED +#define CQUEUEOUTPUTIOP_DEFINED +class CQueueOutputIop +{ +public: + int unk_0x0; + int unk_0x4; + int unk_0x8; + int unk_0xc; + int unk_0x10; + int unk_0x14; + int unk_0x18; + int unk_0x1c; + + void Init(int nParam1, int nParam2); + void Reset(); +}; +#endif // CQUEUEOUTPUTIOP_DEFINED + +void CQueueOutputIop::Init(int nParam1, int nParam2) +{ + unk_0x4 = nParam2; + unk_0x8 = nParam1; + Reset(); +} + +#ifndef CQUEUEOUTPUTIOP_DEFINED +#define CQUEUEOUTPUTIOP_DEFINED +class CQueueOutputIop +{ +public: + int unk_0x0; + int unk_0x4; + int unk_0x8; + int unk_0xc; + int unk_0x10; + int unk_0x14; + int unk_0x18; + int unk_0x1c; + + void Init(int nParam1, int nParam2); + void Reset(); +}; +#endif // CQUEUEOUTPUTIOP_DEFINED + +void CQueueOutputIop::Reset() +{ + unk_0x14 = unk_0x8; + unk_0x18 = 0; + unk_0x10 = 0; + unk_0xc = 0; + unk_0x1c = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbWrite__15CQueueOutputIopiPv); @@ -22,11 +72,17 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbSend__15CQueueOutputIopiPv); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__15CQueueOutputIop); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FAsyncDrain__15CQueueOutputIop); +extern "C" int FAsyncDrain__15CQueueOutputIop() +{ + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbWrite__15CQueueOutputIpuiPv); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FAsyncDrain__15CQueueOutputIpu); +extern "C" int FAsyncDrain__15CQueueOutputIpu() +{ + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Init__10CMpegAudio); @@ -40,13 +96,34 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__10CMpegAudio); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegAcceptVideo__FP7sceMpegP16sceMpegCbDataStrP5CMpeg); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegAcceptAudio__FP7sceMpegP16sceMpegCbDataStrP5CMpeg); +struct sceMpeg; +struct sceMpegCbDataStr; +extern "C" int FAccept__10CMpegAudioiPUc(void *pmpega, int cb, uchar *pb); + +int FMpegAcceptAudio(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) +{ + return FAccept__10CMpegAudioiPUc((uint8_t *)pmpeg + 0x80, STRUCT_OFFSET(pcbdata, 0xC, int), STRUCT_OFFSET(pcbdata, 0x8, uchar *)); +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegDecodeVideo__FP7sceMpegP13sceMpegCbDataP5CMpeg); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegDecoderIdle__FP7sceMpegP13sceMpegCbDataP5CMpeg); +struct sceMpeg; +struct sceMpegCbData; +extern "C" void CbDemuxed__5CMpegi(CMpeg *pmpeg, int nParam); + +int FMpegDecoderIdle(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) +{ + CbDemuxed__5CMpegi(pmpeg, 0); + return 1; +} + +struct sceMpeg; +struct sceMpegCbData; -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegDecoderError__FP7sceMpegP13sceMpegCbDataP5CMpeg); +int FMpegDecoderError(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) +{ + return 1; +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", BuildMpegGifs__FP2QWP11sceIpuRGB32iiiii); diff --git a/src/P2/so.c b/src/P2/so.c index 3ee49903..96495f24 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -546,4 +546,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc670); INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc710); -INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc748); +extern "C" void FUN_001bc748(SO *pso, int *pn) +{ + *pn = (int)(STRUCT_OFFSET(pso, 0x538, uint64_t) >> 52) & 1; // grfso bit 52 (qword view) +} diff --git a/src/P2/sound.c b/src/P2/sound.c index 0b0d8970..64ee57e9 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -28,13 +28,27 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", NewSfx__FPP3SFX); INCLUDE_ASM("asm/nonmatchings/P2/sound", FContinuousSound__F5SFXID); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001BE5D8); +extern int D_00274730; +extern "C" void FUN_001BE5D8(void) +{ + D_00274730 = 0; +} -INCLUDE_ASM("asm/nonmatchings/P2/sound", SetVagUnpaused__Fv); +extern u_int D_00274744; +int SetVagUnpaused() +{ + return D_00274744; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadVag__FPc2FK); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001be708); +extern u_int D_00274744; +void StopVag(); +extern "C" void FUN_001be708(void) +{ + D_00274744 = 0; + StopVag(); +} INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadVag1); @@ -54,9 +68,25 @@ JUNK_WORD(0x0080102D); INCLUDE_ASM("asm/nonmatchings/P2/sound", StopVag__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/sound", PauseVag__Fv); +extern u_int D_0027472C; +void PauseVag() +{ + u_int handle = D_0027472C; + if (handle != 0) + { + snd_PauseSound(handle); + } +} -INCLUDE_ASM("asm/nonmatchings/P2/sound", ContinueVag__Fv); +extern u_int D_0027472C; +void ContinueVag() +{ + u_int handle = D_0027472C; + if (handle != 0) + { + snd_ContinueSound(handle); + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", KillMusic__Fv); @@ -76,9 +106,17 @@ void ContinueMusic() SetMvgkRvol(2, MVGK_Music, 1.0f); } -INCLUDE_ASM("asm/nonmatchings/P2/sound", SfxhMusicUnknown1); +extern u_int D_00274728; +extern "C" void SfxhMusicUnknown1() +{ + snd_PauseSound(D_00274728); +} -INCLUDE_ASM("asm/nonmatchings/P2/sound", SfxhMusicUnknown2); +extern u_int D_00274728; +extern "C" void SfxhMusicUnknown2() +{ + snd_ContinueSound(D_00274728); +} INCLUDE_ASM("asm/nonmatchings/P2/sound", PexcAlloc__Fv); @@ -202,7 +240,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", MvgkUnknown2__Fv); INCLUDE_ASM("asm/nonmatchings/P2/sound", MvgkUnknown3); -INCLUDE_ASM("asm/nonmatchings/P2/sound", MvgkUnknown4); +extern "C" void MvgkUnknown4(int mode) +{ + snd_SetPlaybackMode(mode != 0); +} /** * @todo Figure out func_001c0cb0, and use enum values for params where applicable. diff --git a/src/P2/sw.c b/src/P2/sw.c index 7ad4998b..271e9473 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -369,7 +369,10 @@ void FUN_001ddc18(SW *psw, EXC *pexc) UnsetExcitementHyst(pexc); } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc38); +void FUN_001ddc38(void *pv, void *pvBlot) +{ + STRUCT_OFFSET(pv, 0x2324, void *) = pvBlot; +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc40); @@ -378,8 +381,17 @@ void FUN_001ddc78(void *pv, int n) STRUCT_OFFSET(pv, 0x235C, int) |= (1 << n); } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc90); +void FUN_001ddc90(void *pv, int n) +{ + STRUCT_OFFSET(pv, 0x235C, int) &= ~(1 << n); +} -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddcb0); +void FUN_001ddcb0(void *pv, int *pccharm) +{ + *pccharm = g_pgsCur->ccharm; +} -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddcc8); +void FUN_001ddcc8(void *pv, int *pclife) +{ + *pclife = g_pgsCur->clife; +} From e6dca32002de5dd4a677680f6b0bc36717bca684 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 12 Jun 2026 23:28:40 +0200 Subject: [PATCH 111/134] Match 25 wave-2 functions (alo act/lookat/snd, sound AM/intermittent, sw splice ops) Co-Authored-By: Claude Fable 5 --- src/P2/alo.c | 103 +++++++++++++++++++++++++++++++++---- src/P2/mpeg.c | 15 +++++- src/P2/so.c | 21 +++++++- src/P2/sound.c | 48 +++++++++++++++-- src/P2/sw.c | 137 +++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 299 insertions(+), 25 deletions(-) diff --git a/src/P2/alo.c b/src/P2/alo.c index 48190f4d..8b123807 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -47,9 +47,37 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", UpdateAloHierarchy__FP3ALOf); INCLUDE_ASM("asm/nonmatchings/P2/alo", UpdateAlo__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", InvalidateAloLighting__FP3ALO); +void InvalidateAloLighting(ALO *palo) +{ + int iglobi; + + // palo->globset: count at +0xc, GLOBI array (stride 0x28) at +0x14; invalidate lighting frame at +0x8 + for (iglobi = 0; iglobi < STRUCT_OFFSET(palo, 0x238, int); iglobi++) + { + char *pb = STRUCT_OFFSET(palo, 0x240, char *) + iglobi * 0x28; + *(int *)(pb + 8) = -1; + } +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", UpdateAloXfWorld__FP3ALO); +// alo.h declares `void UpdateAloXfWorld__FP3ALO(ALO *palo);` as a C++ function; with that +// declaration in scope, GCC 2.95 mangles a plain `void UpdateAloXfWorld(ALO *)` definition +// to UpdateAloXfWorld__FP3ALO__FP3ALO. Defining the literal symbol with C linkage (void* +// parameter so it does not conflict with the C++ declaration) emits the exact target symbol. +// If alo.h:279 is ever fixed to `void UpdateAloXfWorld(ALO *palo);`, this can become a plain +// C++ `void UpdateAloXfWorld(ALO *palo)` definition (verified to also match). +extern "C" void UpdateAloXfWorld__FP3ALO(void *pvalo) +{ + ALO *palo = (ALO *)pvalo; + // vtable slot at 0x5c: compiled offset of pfnUpdateLoXfWorldHierarchy in VTLO + // (the real game slot is probably "update xf world"; the header's VTLO has an extra + // pfnUpdateLo entry shifting the names, but the compiled offset is what matters). + void (*pfn)(ALO *) = (void (*)(ALO *))palo->pvtlo->pfnUpdateLoXfWorldHierarchy; + + if (pfn != 0) + { + pfn(palo); + } +} INCLUDE_ASM("asm/nonmatchings/P2/alo", UpdateAloXfWorldHierarchy__FP3ALO); @@ -107,11 +135,27 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", RotateAloToMat__FP3ALOP7MATRIX3); INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloVelocityVec__FP3ALOP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloVelocityXYZ__FP3ALOfff); +void SetAloVelocityXYZ(ALO *palo, float x, float y, float z) +{ + VECTOR vec; + + vec.x = x; + vec.y = y; + vec.z = z; + ((void (*)(ALO *, VECTOR *))STRUCT_OFFSET(palo->pvtlo, 0x90, void *))(palo, &vec); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloAngularVelocityVec__FP3ALOP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloAngularVelocityXYZ__FP3ALOfff); +void SetAloAngularVelocityXYZ(ALO *palo, float x, float y, float z) +{ + VECTOR w; + + w.x = x; + w.y = y; + w.z = z; + (*(void (**)(ALO *, VECTOR *))((char *)palo->pvtlo + 0x94))(palo, &w); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloVelocityLocal__FP3ALOP6VECTOR); @@ -131,7 +175,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", ConvertAloVec__FP3ALOT0P6VECTORT2); INCLUDE_ASM("asm/nonmatchings/P2/alo", ConvertAloMat__FP3ALOT0P7MATRIX3T2); -INCLUDE_ASM("asm/nonmatchings/P2/alo", FDrivenAlo__FP3ALO); +int FDrivenAlo(ALO *palo) +{ + ACT *pact; + + pact = STRUCT_OFFSET(palo, 0x1ec, ACT *); // palo->pactPos + if (pact != NULL && STRUCT_OFFSET(pact, 0x10, char) == ACK_Drive) + { + return 1; + } + + pact = STRUCT_OFFSET(palo, 0x1f0, ACT *); // palo->pactRot + if (pact != NULL && STRUCT_OFFSET(pact, 0x11, char) == ACK_Drive) + { + return 1; + } + + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", RetractAloDrive__FP3ALO); @@ -317,7 +378,11 @@ void GetAloShadowConeAngle(ALO *palo, float *pdegConeAngle) *pdegConeAngle = atan2f(pshadow->sNearRadius / pshadow->sNearCast, 1.0f) * RAD_TO_DEG * 2.0f; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloShadowFrustrumUp__FP3ALOP6VECTOR); +void GetAloShadowFrustrumUp(ALO *palo, VECTOR *pvecUp) +{ + SHADOW *pshadow = PshadowInferAlo(palo); + *(VU_VECTOR *)pvecUp = STRUCT_OFFSET(pshadow, 0x30, VU_VECTOR); // pshadow->vecFrustrumUp +} INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloEuler__FP3ALOP6VECTOR); @@ -401,7 +466,11 @@ extern "C" void FUN_0012a3c8(ALO *palo, int unk) FUN_0012a3e8(palo, unk != 0); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a3e8); +extern "C" void FUN_0012a3e8(ALO *palo, int n) +{ + STRUCT_OFFSET(palo, 0x2c8, uint64_t) = + (STRUCT_OFFSET(palo, 0x2c8, uint64_t) & ~((uint64_t)3 << 40)) | ((uint64_t)(n & 3) << 40); +} extern "C" void FUN_0012a418(ALO *palo, int *pn) { @@ -628,7 +697,11 @@ void SetAloSFull(ALO *palo, float sFull) STRUCT_OFFSET(palo, 0x2ac, SFX *)->sFull = sFull; // palo->psfx } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloSndRepeat__FP3ALOP2LM); +void SetAloSndRepeat(ALO *palo, LM *plm) +{ + EnsureAloSfx(palo); + STRUCT_OFFSET(palo, 0x2ac, SFX *)->lmRepeat = *plm; // palo->psfx +} void GetAloSFull(ALO *palo, float *psFull) { @@ -710,7 +783,19 @@ void GetAloUPitch(ALO *palo, float *puPitch) *puPitch = uPitch; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloSndRepeat__FP3ALOP2LM); +void GetAloSndRepeat(ALO *palo, LM *plmRepeat) +{ + // palo->psfx + if (STRUCT_OFFSET(palo, 0x2ac, SFX *)) + { + *plmRepeat = STRUCT_OFFSET(palo, 0x2ac, SFX *)->lmRepeat; + } + else + { + plmRepeat->gMin = -1.0f; + plmRepeat->gMax = -1.0f; + } +} INCLUDE_ASM("asm/nonmatchings/P2/alo", StartAloSound__FP3ALO5SFXIDfffP2LM); diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index ef602faa..061232f5 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -2,7 +2,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e410); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e480); +extern "C" { +extern char *D_002699C0[16]; +extern char D_0024B580[]; +extern char D_0024B588[]; +} + +extern "C" char *FUN_0018e480(int x) +{ + if ((uint)x < 16) + return D_002699C0[x]; + if (x == -1) + return D_0024B580; + return D_0024B588; +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e4c0); diff --git a/src/P2/so.c b/src/P2/so.c index 96495f24..db10560b 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -517,7 +517,18 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", FGetSoContactList__FP2SOPv); INCLUDE_ASM("asm/nonmatchings/P2/so", GetSoContacts__FP2SOPiPPP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/so", FSoInStsoList__FP4STSOP2SO); +int FSoInStsoList(STSO *pstsoFirst, SO *pso) +{ + while (pstsoFirst != NULL) + { + if (STRUCT_OFFSET(pstsoFirst, 0x0, SO *) == pso) // pso held by this STSO + { + return 1; + } + pstsoFirst = pstsoFirst->pstsoNext; + } + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/so", GenerateSoSpliceTouchingEvents__FP2SO); @@ -544,7 +555,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc4d8); INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc670); -INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc710); +extern "C" void FUN_001bc710(SO *pso, int f) +{ + uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); + grfso &= ~((uint64_t)1 << 52); + grfso |= (uint64_t)(f & 1) << 52; + STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; +} extern "C" void FUN_001bc748(SO *pso, int *pn) { diff --git a/src/P2/sound.c b/src/P2/sound.c index 64ee57e9..9b4f116f 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -197,7 +197,18 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", ScheduleNextIntermittentSound__FP3AMB); INCLUDE_ASM("asm/nonmatchings/P2/sound", StartSound__F5SFXIDPP3AMBP3ALOP6VECTORfffffP2LMT9); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001BFFC8); +extern "C" void FUN_001BFFC8(int err, u_long user_data) +{ + if (err == 0) + { + int iSerial = (int)(user_data >> 32); + AMB *pamb = (AMB *)(user_data & 0xFFFFFFFF); + if (pamb->iSerial == iSerial) + { + STRUCT_OFFSET(pamb, 0x48, int) = 1; // fStopped (real offset; compiled AMB::fStopped lands at 0x44) + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", HandleWipeHandleWipeVolumes__FifVolumes); @@ -238,7 +249,15 @@ void SetMvgkRvol(int channel, MVGK mvgk, float rvol) INCLUDE_ASM("asm/nonmatchings/P2/sound", MvgkUnknown2__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/sound", MvgkUnknown3); +extern "C" void MvgkUnknown3(int fMute) +{ + float rvol = 1.0f; + if (fMute != 0) + { + rvol = 0.0f; + } + SetMvgkRvol(3, MVGK_Music, rvol); +} extern "C" void MvgkUnknown4(int mode) { @@ -269,9 +288,30 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", SetSwDefaultReverb__FP2SW7REVERBKi); INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001C0A50); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001C0AB8); +struct SW; + +extern "C" void FUN_001C0AB8(SW *psw, float *pg) +{ + int c = STRUCT_OFFSET(psw, 0x1D80, int); // count of intermittent-sound entries (array of 0x14-byte entries at 0x1D84) + if (c != 0) + { + char *pisnd = (char *)psw + (c * 0x14 + 0x1D70); // last entry: 0x1D84 + (c-1)*0x14 + STRUCT_OFFSET(pisnd, 0xC, float) = 8000.0f - pg[1] * 50.0f; // lmRepDist.gMin + STRUCT_OFFSET(pisnd, 0x10, float) = 8000.0f - pg[0] * 50.0f; // lmRepDist.gMax + } +} + +struct SW; -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001C0B08); +extern "C" void FUN_001C0B08(SW *psw, LM *plm) +{ + int c = STRUCT_OFFSET(psw, 0x1D80, int); // count of intermittent-sound entries (array of 0x14-byte entries at 0x1D84) + if (c != 0) + { + char *pisnd = (char *)psw + (c * 0x14 + 0x1D70); // last entry: 0x1D84 + (c-1)*0x14 + STRUCT_OFFSET(pisnd, 0x4, LM) = *plm; // lmRepeat (unaligned 8-byte struct copy: ldl/ldr + sdl/sdr) + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", StartSwIntermittentSounds__FP2SW); diff --git a/src/P2/sw.c b/src/P2/sw.c index 271e9473..7453291f 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include extern SW *g_psw; extern int g_fLoadDebugInfo; @@ -45,7 +47,27 @@ void LoadBulkDataFromBrx(CBinaryInputStream *pbis) } } -INCLUDE_ASM("asm/nonmatchings/P2/sw", SetSwGravity__FP2SWf); +static inline VU_VECTOR VuVectorXyz(float x, float y, float z) +{ + VU_VECTOR v; + qword tmp; + asm("mfc1 %0, %2\n\tmfc1 %1, %3\n\tpextlw %0, %1, %0\n\tmfc1 %1, %4\n\tpcpyld %0, %1, %0" + : "=r"(v.data), "=r"(tmp) + : "f"(x), "f"(y), "f"(z)); + return v; +} + +void SetSwGravity(SW *psw, float z) +{ + union + { + qword q; + float af[4]; + } u; + + u.q = VuVectorXyz(0.0f, 0.0f, z).data; + STRUCT_OFFSET(psw, 0x1EE0, qword) = u.q; // vecGravity = (0, 0, z, junk) +} extern "C" void FUN_001dbac0(SW *psw, int reg, int value) { @@ -62,7 +84,18 @@ void FUN_001dbb00(SW *psw, int reg, int value) FUN_001c0c68(reg, value); } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FOverflowSwLo__FP2SWP2LOi); +int FOverflowSwLo(SW *psw, LO *plo, int fHiPri) +{ + int fOverflow = 0; + + if ((plo->pvtlo->grfcid & 2) && psw->cpsoRoot >= 247) + { + int fLow = (fHiPri == 0); + fOverflow = fLow; + } + + return fOverflow; +} XA *PxaAllocSw(SW *psw) { @@ -161,13 +194,39 @@ void FreeSwStsoList(SW *psw, STSO *pstsoFirst) INCLUDE_ASM("asm/nonmatchings/P2/sw", AddSwProxySource__FP2SWP2LOi); -INCLUDE_ASM("asm/nonmatchings/P2/sw", PloGetSwProxySource__FP2SWi); +LO *PloGetSwProxySource(SW *psw, int ipsl) +{ + // Proxy-source list at SW+0x1F00: array of 8-byte {int cplo; LO **aplo} pairs + // (count cpsl lives at 0x1EFC; see AddSwProxySource). + int *p = &STRUCT_OFFSET(psw, ipsl * 8 + 0x1F00, int); + int c = p[0] - 1; + LO **aplo = (LO **)p[1]; + int i = c * 4; + asm volatile(""); // zero-byte scheduling barrier: keeps the count store between the sll and addu, as in the original + p[0] = c; + return *(LO **)(i + (int)aplo); +} INCLUDE_ASM("asm/nonmatchings/P2/sw", IntersectSwBoundingBox__FP2SWP2SOP6VECTORT2PFPvP2SO_iPvPiPPP2SO); INCLUDE_ASM("asm/nonmatchings/P2/sw", IntersectSwBoundingSphere__FP2SWP2SOP6VECTORfPFPvP2SO_iPvPiPPP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/sw", RemoveOxa__FP3OXAPP3OXA); +void RemoveOxa(OXA *poxa, OXA **ppoxaFirst) +{ + if (poxa->poxaNext != NULL) + { + poxa->poxaNext->poxaPrev = poxa->poxaPrev; + } + + if (poxa->poxaPrev != NULL) + { + poxa->poxaPrev->poxaNext = poxa->poxaNext; + } + else + { + *ppoxaFirst = poxa->poxaNext; + } +} INCLUDE_ASM("asm/nonmatchings/P2/sw", InitSwAoxa__FP2SW); @@ -256,9 +315,40 @@ int FLevelSwTertiary(SW *psw, WID wid) INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd710); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd758); +extern "C" uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); + +extern "C" int FUN_001dd758(SW *psw, int wid) +{ + uint grfls = GrflsLevelCompletionFromWid(wid); + uint f = 0; + uint mask = grfls & 3; + + if (grfls & 4) + { + LS *pls = g_plsCur; + f = (mask & pls->fls) ^ mask; + f = f < 1; + } + + return f; +} + +extern "C" uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); + +extern "C" int FUN_001dd7a0(SW *psw, int wid) +{ + uint grfls = GrflsLevelCompletionFromWid(wid); + int f = 0; + uint mask = grfls & 7; -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7a0); + if (grfls & 8) + { + uint t = mask & g_plsCur->fls; + f = (t ^ mask) < 1; + } + + return f; +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7e8); @@ -279,7 +369,15 @@ int FUN_001dd928(SW *psw) return CalculatePercentCompletion(g_pgsCur); } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd950); +extern "C" void FUN_001dd950(SW *psw, int nLow, int nHigh, VECTOR *pposCenter) +{ + int cpdprize = NRandInRange(nLow, nHigh); + + if (cpdprize != 0) + { + CpdprizeAttractSwDprizes(g_psw, (CID)0x58, pposCenter, cpdprize, NULL); + } +} void FUN_001dd9a0(float nParam) { @@ -352,7 +450,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddb20); INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddb58); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddbb8); +extern BLOT D_002721D0; + +extern "C" void FUN_001ddbb8(SW *psw) +{ + if (--STRUCT_OFFSET(psw, 0x2320, int) == 0) + { + D_002721D0.pvtblot->pfnHideBlot(&D_002721D0); + } +} JUNK_WORD(0x0002102a); EXC *PexcSetExcitement(int gexc); @@ -374,7 +480,20 @@ void FUN_001ddc38(void *pv, void *pvBlot) STRUCT_OFFSET(pv, 0x2324, void *) = pvBlot; } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddc40); +extern "C" void FUN_001ddc40(void *pv) +{ + typedef void (*PFNBLOT)(void *); + + void *pvBlot = STRUCT_OFFSET(pv, 0x2324, void *); // blot/vtable'd object set by FUN_001ddc38 + if (pvBlot != NULL) + { + PFNBLOT pfn = STRUCT_OFFSET(STRUCT_OFFSET(pvBlot, 0x0, void *), 0xC8, PFNBLOT); + if (pfn != NULL) + { + pfn(pvBlot); + } + } +} void FUN_001ddc78(void *pv, int n) { From 159316c89e2ecd666b2a2637383460396cd45f40 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 12 Jun 2026 23:31:33 +0200 Subject: [PATCH 112/134] Match 33 more wave-2 functions (alo lookat/act setters, sound music/VAG/exc, mpeg oids, bq CbFill, so wkr) SetAloPosition/RotationSmooth reverted: scheduler diff vs ROM (false per-symbol match from flaky asm regen). Co-Authored-By: Claude Fable 5 --- src/P2/alo.c | 129 ++++++++++++++++++++++++++++++++++++++++++------- src/P2/bq.c | 36 +++++++++++++- src/P2/mpeg.c | 46 ++++++++++++++++-- src/P2/so.c | 27 ++++++++++- src/P2/sound.c | 112 ++++++++++++++++++++++++++++++++++++++---- src/P2/sw.c | 16 +++++- 6 files changed, 332 insertions(+), 34 deletions(-) diff --git a/src/P2/alo.c b/src/P2/alo.c index 8b123807..a9873edd 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -388,9 +388,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", GetAloEuler__FP3ALOP6VECTOR); INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloEuler__FP3ALOP6VECTOR); -INCLUDE_ASM("asm/nonmatchings/P2/alo", EnsureAloActRestore__FP3ALO); +extern VTACT D_00219560; -INCLUDE_ASM("asm/nonmatchings/P2/alo", EnsureAloActla__FP3ALO); +void EnsureAloActRestore(ALO *palo) +{ + if (STRUCT_OFFSET(palo, 0x1fc, ACT *) == NULL) // palo->pactRestore + { + ACT *pact = PactNew(palo->psw, palo, &D_00219560); + STRUCT_OFFSET(palo, 0x1fc, ACT *) = pact; + InsertAloAct(palo, pact); + } +} + +extern VTACT D_0021A790; + +void EnsureAloActla(ALO *palo) +{ + if (STRUCT_OFFSET(palo, 0x200, ACT *) == NULL) // palo->pactla + { + ACT *pact = PactNew(palo->psw, palo, &D_0021A790); + STRUCT_OFFSET(palo, 0x200, ACT *) = pact; + InsertAloAct(palo, pact); + } +} INCLUDE_ASM("asm/nonmatchings/P2/alo", RecacheAloActList__FP3ALO); @@ -477,20 +497,44 @@ extern "C" void FUN_0012a418(ALO *palo, int *pn) *pn = (int)(STRUCT_OFFSET(palo, 0x2c8, uint64_t) >> 40) & 3; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestorePositionAck__FP3ALO3ACK); +void SetAloRestorePositionAck(ALO *palo, ACK ack) +{ + EnsureAloActRestore(palo); + // palo->pactRestore (ACT at 0x1FC), ackPos byte at +0x10 + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x1fc, ACT *), 0x10, char) = ack; + (*(void (**)(ALO *))((char *)palo->pvtlo + 0xBC))(palo); +} void SetAloRestoreRotation(ALO *palo, int fRestore) { SetAloRestoreRotationAck(palo, fRestore ? ACK_Spring : ACK_Nil); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRestoreRotationAck__FP3ALO3ACK); +void SetAloRestoreRotationAck(ALO *palo, ACK ack) +{ + EnsureAloActRestore(palo); + // palo->pactRestore (ACT at 0x1FC), ackRot byte at +0x11 + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x1fc, ACT *), 0x11, char) = ack; + (*(void (**)(ALO *))((char *)palo->pvtlo + 0xBC))(palo); +} + +extern "C" void FUN_0012a4e8(ALO *palo, int n) +{ + void *pactrest; -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a4e8); + EnsureAloActRestore(palo); + pactrest = STRUCT_OFFSET(palo, 0x1fc, void *); + STRUCT_OFFSET(pactrest, 0x14, int) = n; + ResortAloActList(palo); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAt__FP3ALO3ACK); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtIgnore__FP3ALOf); +void SetAloLookAtIgnore(ALO *palo, float sIgnore) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x40, float) = sIgnore; +} void GetAloLookAtIgnore(ALO *palo, float *psIgnore) { @@ -503,7 +547,11 @@ void GetAloLookAtIgnore(ALO *palo, float *psIgnore) *psIgnore = sIgnore; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtPanFunction__FP3ALOP3CLQ); +void SetAloLookAtPanFunction(ALO *palo, CLQ *pclq) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x50, qword) = STRUCT_OFFSET(pclq, 0x0, qword); +} void GetAloLookAtPanFunction(ALO *palo, CLQ *pclq) { @@ -519,7 +567,11 @@ void GetAloLookAtPanFunction(ALO *palo, CLQ *pclq) *(VU_VECTOR *)pclq = *(VU_VECTOR *)pclqSrc; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtPanLimits__FP3ALOP2LM); +void SetAloLookAtPanLimits(ALO *palo, LM *plm) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x60, LM) = *plm; +} void GetAloLookAtPanLimits(ALO *palo, LM *plm) { @@ -534,7 +586,11 @@ void GetAloLookAtPanLimits(ALO *palo, LM *plm) *plm = *plmSrc; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtTiltFunction__FP3ALOP3CLQ); +void SetAloLookAtTiltFunction(ALO *palo, CLQ *pclq) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x70, qword) = STRUCT_OFFSET(pclq, 0x0, qword); +} extern qword D_00275C40; void GetAloLookAtTiltFunction(ALO *palo, CLQ *pclq) @@ -550,7 +606,11 @@ void GetAloLookAtTiltFunction(ALO *palo, CLQ *pclq) *(qword *)pclq = *pqSrc; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtTiltLimits__FP3ALOP2LM); +void SetAloLookAtTiltLimits(ALO *palo, LM *plm) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x80, LM) = *plm; +} void GetAloLookAtTiltLimits(ALO *palo, LM *plm) { @@ -565,7 +625,11 @@ void GetAloLookAtTiltLimits(ALO *palo, LM *plm) *plm = *plmSrc; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtEnabledPriority__FP3ALOi); +void SetAloLookAtEnabledPriority(ALO *palo, int nPriority) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x44, int) = nPriority; +} void GetAloLookAtEnabledPriority(ALO *palo, int *pnPriority) { @@ -578,7 +642,11 @@ void GetAloLookAtEnabledPriority(ALO *palo, int *pnPriority) *pnPriority = nPriority; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAtDisabledPriority__FP3ALOi); +void SetAloLookAtDisabledPriority(ALO *palo, int nPriority) +{ + EnsureAloActla(palo); + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x48, int) = nPriority; +} void GetAloLookAtDisabledPriority(ALO *palo, int *pnPriority) { @@ -591,7 +659,14 @@ void GetAloLookAtDisabledPriority(ALO *palo, int *pnPriority) *pnPriority = nPriority; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a810); +extern "C" void FUN_0012a810(ALO *palo, int n) +{ + void *pactla; + + EnsureAloActla(palo); + pactla = STRUCT_OFFSET(palo, 0x200, void *); + STRUCT_OFFSET(pactla, 0x20, int) = n; +} void FUN_0012a848(ALO *palo, int *pn) { @@ -610,7 +685,10 @@ extern "C" void FUN_0012a860(ALO *palo, ALO *paloTarget) SetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *), paloTarget, &D_00248D30); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", FUN_0012a888); +extern "C" void FUN_0012a888(ALO *palo, ALO **ppaloTarget) +{ + *ppaloTarget = PaloGetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *)); +} void FUN_0012a8b8(ALO *palo) { @@ -628,7 +706,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationMatchesVelocity__FP3ALOff3A INCLUDE_ASM("asm/nonmatchings/P2/alo", PtargetEnsureAlo__FP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloTargetAttacks__FP3ALOi); +void SetAloTargetAttacks(ALO *palo, GRFTAK grftak) +{ + TARGET *ptarget = PtargetEnsureAlo(palo); + if (grftak != -1) + { + STRUCT_OFFSET(ptarget, 0x88, GRFTAK) = grftak; // ptarget->grftak + } +} void SetAloTargetRadius(ALO *palo, float sRadiusTarget) { @@ -823,7 +908,12 @@ void GetAloThrobKind(ALO *palo, THROBK *pthrobk) *pthrobk = throbk; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloThrobInColor__FP3ALOP6VECTOR); +void SetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) +{ + EnsureAloThrob(palo); + // palo->pthrob->hsvInColor + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x288, THROB *), 0x10, VU_VECTOR) = *(VU_VECTOR *)phsvInColor; +} extern VU_VECTOR D_00248D30; void GetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) @@ -839,7 +929,12 @@ void GetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) *(VU_VECTOR *)phsvInColor = *pqSrc; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloThrobOutColor__FP3ALOP6VECTOR); +void SetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) +{ + EnsureAloThrob(palo); + // palo->pthrob->hsvOutColor + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x288, THROB *), 0x20, VU_VECTOR) = *(VU_VECTOR *)phsvOutColor; +} void GetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) { diff --git a/src/P2/bq.c b/src/P2/bq.c index 5f1763f9..113ad010 100644 --- a/src/P2/bq.c +++ b/src/P2/bq.c @@ -21,7 +21,41 @@ INCLUDE_ASM("asm/nonmatchings/P2/bq", CbFill__10CByteQueueiP11CQueueInput); INCLUDE_ASM("asm/nonmatchings/P2/bq", CbDrain__10CByteQueueiP12CQueueOutput); -INCLUDE_ASM("asm/nonmatchings/P2/bq", CbFill__10CByteQueueiPUc); +extern "C" int D_00249D98[]; + +int CByteQueue::CbFill(int cb, byte *pb) +{ + int cbRead; + + if (cb == 0) + { + cbRead = 0; + } + else + { + // Stack CQueueInputMemory: vtable ptr (D_00249D98 = __vt_17CQueueInputMemory in + // rodata), pb @0x4, cb @0x8, ib (read cursor) @0xC, cb remaining @0x10 + // (layout confirmed by CbRead__17CQueueInputMemoryiPv). The repo's + // CQueueInputMemory class declares no fields, so the object is built manually. + struct + { + void *pvt; + byte *pb; + int cb; + int ib; + int cbTotal; + } qim; + + qim.pb = pb; + qim.pvt = D_00249D98; + qim.cbTotal = cb; + qim.cb = cb; + qim.ib = 0; + cbRead = CbFill(cb, (CQueueInput *)&qim); + } + + return cbRead; +} void CByteQueue::FreeDrain(int cb) { diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 061232f5..45a2f14b 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e410); @@ -17,7 +18,13 @@ extern "C" char *FUN_0018e480(int x) return D_0024B588; } -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e4c0); +extern "C" void FUN_0018f0e8(CMpeg *pmpeg, void *pv); +extern uchar D_002484B0[16][32]; + +extern "C" void FUN_0018e4c0(int i) +{ + FUN_0018f0e8(&g_mpeg, D_002484B0[i]); +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e4f0); @@ -107,7 +114,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FAccept__10CMpegAudioiPUc); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__10CMpegAudio); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegAcceptVideo__FP7sceMpegP16sceMpegCbDataStrP5CMpeg); +struct sceMpeg; +struct sceMpegCbDataStr; + +int FMpegAcceptVideo(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) +{ + int cb = STRUCT_OFFSET(pcbdata, 0xC, int); // pcbdata->len + + // pmpeg+0x60 is the video CByteQueue; +0x70 is its m_cbFree + if ((uint)STRUCT_OFFSET(pmpeg, 0x70, int) < (uint)cb) + { + return 0; + } + + STRUCT_OFFSET(pmpeg, 0x60, CByteQueue).CbFill(cb, STRUCT_OFFSET(pcbdata, 0x8, byte *)); // pcbdata->data + return 1; +} struct sceMpeg; struct sceMpegCbDataStr; @@ -144,7 +166,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018ef78); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018f0e8); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", ExecuteOids__5CMpeg); +// Execute__5CMpeg's asm label mangles as a no-argument member (CMpeg::Execute()), but the +// function actually takes an OID* in $a1, so it must be called through an extern "C" +// declaration of the literal symbol until it is decompiled with a corrected signature. +extern "C" void Execute__5CMpeg(CMpeg *pmpeg, OID *poid); + +void CMpeg::ExecuteOids() +{ + OID *poidNext = STRUCT_OFFSET(this, 0x8, OID *); // queued second mpeg oid ptr + OID *poid = STRUCT_OFFSET(this, 0x4, OID *); // queued first mpeg oid ptr + + STRUCT_OFFSET(this, 0x4, OID *) = 0; + STRUCT_OFFSET(this, 0x8, OID *) = 0; + Execute__5CMpeg(this, poid); + + if (poidNext != 0) + { + Execute__5CMpeg(this, poidNext); + } +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Execute__5CMpeg); diff --git a/src/P2/so.c b/src/P2/so.c index db10560b..3e4d2cba 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -109,7 +109,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateGeomWorld__FP4GEOMT0G9VU_VECTORP7MAT INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateSoXfWorldHierarchy__FP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateSoXfWorld__FP2SO); +// alo.h declares the literal identifier `UpdateAloXfWorld__FP3ALO`, which both +// double-mangles if called and poisons the plain name `UpdateAloXfWorld` for +// GCC 2.95; bind a local alias to the real mangled symbol instead. +extern void _UpdateAloXfWorld(ALO *palo) __asm__("UpdateAloXfWorld__FP3ALO"); + +void UpdateSoXfWorld(SO *pso) +{ + SO *psoRoot; + void (*pfn)(SO *); + + _UpdateAloXfWorld(pso); + psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); // paloRoot + pfn = (void (*)(SO *))STRUCT_OFFSET(STRUCT_OFFSET(psoRoot, 0x0, void *), 0xD8, void *); + pfn(psoRoot); + InvalidateSwXpForObject(pso->psw, pso, 7); + InvalidateSwAaox(pso->psw); +} INCLUDE_ASM("asm/nonmatchings/P2/so", FIgnoreSoIntersection__FP2SOT0); @@ -547,7 +563,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", ApplySoImpulse__FP2SOP6VECTORT1f); INCLUDE_ASM("asm/nonmatchings/P2/so", CalculateSoTrajectoryApex__FP2SOP6VECTORfT1); -INCLUDE_ASM("asm/nonmatchings/P2/so", FAbsorbSoWkr__FP2SOP3WKR); +int FAbsorbSoWkr(SO *pso, WKR *pwkr) +{ + if (pwkr->grfic & 0x8) + { + ApplySoImpulse(pso, &STRUCT_OFFSET(pwkr, 0x20, VECTOR), &STRUCT_OFFSET(pwkr, 0x30, VECTOR), pwkr->sftMax); + } + return pwkr->grfic != 0; +} INCLUDE_ASM("asm/nonmatchings/P2/so", CloneSoPhys__FP2SOT0i); diff --git a/src/P2/sound.c b/src/P2/sound.c index 9b4f116f..17351772 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -1,6 +1,7 @@ #include #include <989snd.h> #include +#include extern uchar D_00604790[]; // temp @@ -22,7 +23,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", UnloadMusic__Fv); INCLUDE_ASM("asm/nonmatchings/P2/sound", SbpEnsureBank__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/sound", SbpEnsureBank__F5SFXID); +extern int D_00245020[][2]; +void SbpEnsureBank(SFXID sfxid) +{ + SbpEnsureBank(D_00245020[sfxid][0]); +} INCLUDE_ASM("asm/nonmatchings/P2/sound", NewSfx__FPP3SFX); @@ -52,7 +57,26 @@ extern "C" void FUN_001be708(void) INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadVag1); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FPauseForVag__Fv); +extern u_int D_00274744; +extern u_int D_0027472C; +extern int D_00274730; +int FPauseForVag() +{ + if (D_00274744 != 0) + { + return 0; + } + u_int handle = D_0027472C; + if (handle != 0) + { + if (D_00274730 != 0) + { + return 1; + } + snd_ContinueVAGStream(handle); + } + return 0; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", RefreshPambVolPan__FP3AMB); @@ -88,9 +112,35 @@ void ContinueVag() } } -INCLUDE_ASM("asm/nonmatchings/P2/sound", KillMusic__Fv); +extern int D_00274720; +extern u_int D_00274728; +void KillMusic() +{ + if (D_00274720 == 3) + { + snd_StopSound(D_00274728); + D_00274728 = 0; + D_00274720 = 2; + } +} -INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadMusidSongComplete__FUiUl); +extern int D_00274720; +extern int D_00274724; +extern u_int D_0027473C; +void PreloadMusidSongComplete(u_int handle, u_long unused) +{ + D_0027473C = handle; + if (handle != 0) + { + snd_ResolveBankXREFS(); + D_00274720 = 2; + } + else + { + D_00274724 = 0; + D_00274720 = 0; + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadMusidSong__F5MUSID); @@ -120,7 +170,11 @@ extern "C" void SfxhMusicUnknown2() INCLUDE_ASM("asm/nonmatchings/P2/sound", PexcAlloc__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/sound", RemoveExc__FP3EXC); +void RemoveExc(EXC *pexc) +{ + RemoveDlEntry(&STRUCT_OFFSET(g_psw, 0x1bc4, DL), pexc); + FreeSlotheapPv(&STRUCT_OFFSET(g_psw, 0x1bb8, SLOTHEAP), pexc); +} INCLUDE_ASM("asm/nonmatchings/P2/sound", KillExcitement__Fv); @@ -169,7 +223,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", SetDoppler__FP3AMB); INCLUDE_ASM("asm/nonmatchings/P2/sound", PfneardistGet__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/sound", SDistEar__FP6VECTOR); +VECTOR *PposEar(); +typedef float (*PFNSDIST)(VECTOR *, VECTOR *); +PFNSDIST PfneardistGet(); +float SDistEar(VECTOR *pvec) +{ + VECTOR *pposEar = PposEar(); + return PfneardistGet()(pposEar, pvec); +} INCLUDE_ASM("asm/nonmatchings/P2/sound", CalculateDistVolPan__FP6VECTORPfT1fff); @@ -187,7 +248,18 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", StopSound__FP3AMBi); INCLUDE_ASM("asm/nonmatchings/P2/sound", SetPambFrq__FP3AMBf); -INCLUDE_ASM("asm/nonmatchings/P2/sound", SetPambVol__FP3AMBf); +void RefreshPambVolPan(AMB *pamb); + +void SetPambVol(AMB *pamb, float uVolAtSource) +{ + if (pamb != 0) + { + float ratio = uVolAtSource / pamb->uVolAtSource; + pamb->uVolAtSource = uVolAtSource; + STRUCT_OFFSET(pamb, 0x50, float) *= ratio; // real volAttenuated (compiled AMB layout is shifted -8 here; named field at 0x50 is frq) + RefreshPambVolPan(pamb); + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", FillPamb__FP3AMBPP3AMBiP3ALOP6VECTORfffffP2LMT10_); @@ -316,7 +388,16 @@ extern "C" void FUN_001C0B08(SW *psw, LM *plm) INCLUDE_ASM("asm/nonmatchings/P2/sound", StartSwIntermittentSounds__FP2SW); // TODO: Verify signature. -INCLUDE_ASM("asm/nonmatchings/P2/sound", SetAMRegister__FiUc); +extern int D_006053E0[]; +extern u_int D_00274728; +extern "C" void SetAMRegister__FiUc(int n, int bReg) +{ + if (bReg != D_006053E0[n]) + { + D_006053E0[n] = bReg; + snd_SetMIDIRegister(D_00274728, n, bReg); + } +} extern int D_006053E0[]; extern "C" int FUN_001c0c50(int reg) @@ -324,9 +405,20 @@ extern "C" int FUN_001c0c50(int reg) return D_006053E0[reg]; } -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001c0c68); +extern int D_006053E0[]; +extern u_int D_00274728; +extern "C" void FUN_001c0c68(int reg, int value) +{ + D_006053E0[reg] = snd_GetMIDIRegister(D_00274728, reg); +} -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001c0cb0__Fv); +void FUN_001c0cb0() +{ + for (int i = 0; i < 8; i++) + { + SetAMRegister__FiUc(i, 0); + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", HsNextFootFall__Fv); diff --git a/src/P2/sw.c b/src/P2/sw.c index 7453291f..3a9470a9 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -11,6 +11,7 @@ #include #include #include +#include extern SW *g_psw; extern int g_fLoadDebugInfo; @@ -446,7 +447,20 @@ void CancelSwDialogPlaying(SW *psw) } } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddb20); +typedef struct +{ + int n; +} __attribute__((packed)) UNALIGNED_INT; + +extern PROMPT D_0026FF68; + +extern "C" void FUN_001ddb20(SW *psw, PRK prk, int oid) +{ + PROMPT *pprompt = &D_0026FF68; + + STRUCT_OFFSET(pprompt, 0x280, UNALIGNED_INT).n = oid; + SetPrompt(pprompt, PRP_Basic, prk); +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddb58); From 257e1ab2fc0391470d12e76a2065bf575ac1e383 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 20:07:13 +0200 Subject: [PATCH 113/134] Match 27 wave-3 functions (alo damping/spring/shadow/throb, sound alloc/stop, sw oxa, act/actseg goals, mpeg) Co-Authored-By: Claude Fable 5 --- src/P2/alo.c | 159 +++++++++++++++++++++++++++++++++++++++++++++---- src/P2/mpeg.c | 92 ++++++++++++++++++++++++++-- src/P2/so.c | 24 +++++++- src/P2/sound.c | 89 ++++++++++++++++++++++++--- src/P2/sw.c | 40 ++++++++++++- 5 files changed, 377 insertions(+), 27 deletions(-) diff --git a/src/P2/alo.c b/src/P2/alo.c index a9873edd..489640e6 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include extern VTACT g_vtactseg; extern SHADOW s_shadow; @@ -145,7 +147,22 @@ void SetAloVelocityXYZ(ALO *palo, float x, float y, float z) ((void (*)(ALO *, VECTOR *))STRUCT_OFFSET(palo->pvtlo, 0x90, void *))(palo, &vec); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloAngularVelocityVec__FP3ALOP6VECTOR); +void SetAloAngularVelocityVec(ALO *palo, VECTOR *pw) +{ + ACT *pactRot; + + STRUCT_OFFSET(palo, 0x160, VU_VECTOR) = *(VU_VECTOR *)pw; // palo->wWorld (angular velocity) + pactRot = STRUCT_OFFSET(palo, 0x1f0, ACT *); // palo->pactRot + if (pactRot != NULL) + { + AdaptAct(pactRot); + } + + if (!FIsZeroW(pw)) + { + ResolveAlo(palo); + } +} void SetAloAngularVelocityXYZ(ALO *palo, float x, float y, float z) { @@ -262,9 +279,38 @@ void GetAloFastShadowDepth(ALO *palo, float *psDepth) *psDepth = STRUCT_OFFSET(palo, 0x290, float) * 100.0f; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", PshadowAloEnsure__FP3ALO); +SHADOW *PshadowAloEnsure(ALO *palo) +{ + if (!STRUCT_OFFSET(palo, 0x284, SHADOW *)) + { + SHADOW *pshadow = (SHADOW *)PvAllocSlotheapClearImpl(&STRUCT_OFFSET(palo->psw, 0x1bf4, SLOTHEAP)); + STRUCT_OFFSET(palo, 0x284, SHADOW *) = pshadow; + InitShadow(pshadow); + AppendDlEntry(&STRUCT_OFFSET(palo->psw, 0x1c00, DL), STRUCT_OFFSET(palo, 0x284, SHADOW *)); + } + return STRUCT_OFFSET(palo, 0x284, SHADOW *); +} + +extern DL D_00262300; -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloCastShadow__FP3ALOi); +void SetAloCastShadow(ALO *palo, int fCastShadow) +{ + SHADOW *pshadow; + + if (fCastShadow) + { + PshadowAloEnsure(palo); + return; + } + + pshadow = STRUCT_OFFSET(palo, 0x284, SHADOW *); // palo->pshadow + if (pshadow != NULL) + { + RemoveDlEntry(&STRUCT_OFFSET(palo->psw, 0x1c00, DL), pshadow); + AppendDlEntry(&D_00262300, STRUCT_OFFSET(palo, 0x284, SHADOW *)); + STRUCT_OFFSET(palo, 0x284, SHADOW *) = NULL; + } +} void SetAloShadowShader(ALO *palo, OID oidShdShadow) { @@ -422,9 +468,35 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", PasegaFindAlo__FP3ALO3OID); INCLUDE_ASM("asm/nonmatchings/P2/alo", PsmaFindAlo__FP3ALO3OID); -INCLUDE_ASM("asm/nonmatchings/P2/alo", PasegaFindAloNearest__FP3ALO); +ASEGA *PasegaFindAloNearest(ALO *paloLeaf) +{ + while (paloLeaf != NULL) + { + ACT *pact = STRUCT_OFFSET(paloLeaf, 0x1ec, ACT *); + if (pact != NULL && pact->pvtact == &g_vtactseg) + return STRUCT_OFFSET(pact, 0x1c, ASEGA *); + + pact = STRUCT_OFFSET(paloLeaf, 0x1f0, ACT *); + if (pact != NULL && pact->pvtact == &g_vtactseg) + return STRUCT_OFFSET(pact, 0x1c, ASEGA *); + + paloLeaf = paloLeaf->paloParent; + } + return NULL; +} -INCLUDE_ASM("asm/nonmatchings/P2/alo", CreateAloActadj__FP3ALOiPP6ACTADJ); +extern VTACT D_002195D8; + +void CreateAloActadj(ALO *palo, int nPriority, ACTADJ **ppactadj) +{ + if (palo) + { + ACT *pact = PactNew(palo->psw, palo, &D_002195D8); + pact->nPriority = nPriority; + InsertAloAct(palo, pact); + *ppactadj = (ACTADJ *)pact; + } +} INCLUDE_ASM("asm/nonmatchings/P2/alo", FIsAloStatic__FP3ALO); @@ -438,11 +510,33 @@ void ResolveAlo(ALO *palo) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionSpring__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionSpringDetail__FP3ALOP3CLQ); +extern CLQ D_00260E70; +void SetAloPositionSpringDetail(ALO *palo, CLQ *pclq) +{ + CLQ *&pclqDst = STRUCT_OFFSET(palo, 0x20c, CLQ *); // palo->pclqPositionSpring (default &D_00260E70) + + if (pclqDst == &D_00260E70) + { + pclqDst = (CLQ *)PvAllocSwImpl(0x10); + } + + *(VU_VECTOR *)pclqDst = *(VU_VECTOR *)pclq; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionDamping__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionDampingDetail__FP3ALOP3CLQ); +extern CLQ D_00260E80; +void SetAloPositionDampingDetail(ALO *palo, CLQ *pclq) +{ + CLQ *&pclqDst = STRUCT_OFFSET(palo, 0x210, CLQ *); // palo->pclwPosDamping (real offset 0x210) + + if (pclqDst == &D_00260E80) + { + pclqDst = (CLQ *)PvAllocSwImpl(0x10); + } + + *(VU_VECTOR *)pclqDst = *(VU_VECTOR *)pclq; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSpring__FP3ALOf); @@ -450,11 +544,28 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSpringDetail__FP3ALOP3CLQ); INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationDamping__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationDampingDetail__FP3ALOP3CLQ); +extern CLQ D_00260EA0; +void SetAloRotationDampingDetail(ALO *palo, CLQ *pclq) +{ + CLQ *&pclqDst = STRUCT_OFFSET(palo, 0x218, CLQ *); // palo->pclqRotationDamping (default &D_00260EA0) + + if (pclqDst == &D_00260EA0) + { + pclqDst = (CLQ *)PvAllocSwImpl(0x10); + } + + *(VU_VECTOR *)pclqDst = *(VU_VECTOR *)pclq; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionSmooth__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionSmoothMaxAccel__FP3ALOf); +struct SMPA { float ag[4]; }; +void SetAloPositionSmoothMaxAccel(ALO *palo, float r) +{ + SMPA smpa = *STRUCT_OFFSET(palo, 0x21c, SMPA *); // copy palo->psmpaPos + smpa.ag[3] = r * (smpa.ag[0] - smpa.ag[1]) / smpa.ag[2]; + SetAloPositionSmoothDetail(palo, &smpa); +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionSmoothDetail__FP3ALOP4SMPA); @@ -704,7 +815,17 @@ extern "C" void FUN_0012a8c8(ALO *palo) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationMatchesVelocity__FP3ALOff3ACK); -INCLUDE_ASM("asm/nonmatchings/P2/alo", PtargetEnsureAlo__FP3ALO); +TARGET *PtargetEnsureAlo(ALO *palo) +{ + TARGET *ptarget = (TARGET *)PloFindSwObject(palo->psw, 0x102, (OID)0x22a, palo); + + if (ptarget == NULL) + { + ptarget = (TARGET *)PloNew((CID)0x75, palo->psw, palo, (OID)0x22a, -1); + } + + return ptarget; +} void SetAloTargetAttacks(ALO *palo, GRFTAK grftak) { @@ -893,7 +1014,23 @@ void StopAloSound(ALO *palo) } } -INCLUDE_ASM("asm/nonmatchings/P2/alo", EnsureAloThrob__FP3ALO); +extern qword D_00261000[4]; + +void EnsureAloThrob(ALO *palo) +{ + THROB *&pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); + + if (!pthrob) + { + qword *pdst = (qword *)PvAllocSwImpl(0x40); + pthrob = (THROB *)pdst; + pdst[0] = D_00261000[0]; + pdst[1] = D_00261000[1]; + pdst[2] = D_00261000[2]; + pdst[3] = D_00261000[3]; + pthrob->throbk = (THROBK)-1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloThrobKind__FP3ALO6THROBK); diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 45a2f14b..49df3573 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -1,7 +1,40 @@ #include #include +#include <989snd.h> +#include -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e410); +extern "C" uchar D_002484B0[16][32]; + +extern "C" int FUN_0018e410(void *pv) +{ + uchar (*pb)[32] = D_002484B0; + int i = 0; +loop: + { + int match; + if (pb == (uchar (*)[32])pv) + match = 1; + else if (pb == 0) + match = 0; + else if (pv == 0) + match = 0; + else + { + int *e = (int *)pb; + int *a = (int *)pv; + match = ((e[2] ^ e[6]) ^ (a[2] ^ a[6])) == 0; + } + if (match != 0) + return i; + } + i++; + if (i < 16) + { + pb++; + goto loop; + } + return -1; +} extern "C" { extern char *D_002699C0[16]; @@ -26,7 +59,19 @@ extern "C" void FUN_0018e4c0(int i) FUN_0018f0e8(&g_mpeg, D_002484B0[i]); } -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e4f0); +extern "C" uchar *D_00269A08; + +extern "C" void FUN_0018e4f0(int param1, int i) +{ + FUN_0018e4c0(param1); + D_00269A08 = D_002484B0[i]; + int bits; + if ((uint)i >= 16) + bits = 0; + else + bits = 1 << i; + STRUCT_OFFSET(g_pgsCur, 0x19F4, int) |= bits; +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018e558); @@ -106,9 +151,48 @@ extern "C" int FAsyncDrain__15CQueueOutputIpu() INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Init__10CMpegAudio); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Reset__10CMpegAudio); +#ifndef CMPEGAUDIO_DEFINED +#define CMPEGAUDIO_DEFINED +class CMpegAudio +{ +public: + int unk_0x0; + char pad_0x4[0x2C - 0x4]; + CByteQueue bqDemux; + char pad_0x40[0x4C - 0x2C - (int)sizeof(CByteQueue)]; + CByteQueue bqOut; + char pad_0x60[0x6C - 0x4C - (int)sizeof(CByteQueue)]; + CQueueOutputIop qoi; + + void Reset(); +}; +#endif // CMPEGAUDIO_DEFINED + +void CMpegAudio::Reset() +{ + if (unk_0x0 != 0) + { + snd_ResetMovieSound(); + unk_0x0 = 1; + bqDemux.Reset(); + bqOut.Reset(); + qoi.Reset(); + } +} + +struct SW; +extern "C" SW *g_psw; +void PopSwReverb(SW *psw); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Close__10CMpegAudio); +extern "C" void Close__10CMpegAudio(void *pthis) +{ + STRUCT_OFFSET(pthis, 0x0, int) = 0; + snd_CloseMovieSound(); + snd_SetMasterVolume(2, STRUCT_OFFSET(pthis, 0x8C, int)); + snd_SetMasterVolume(8, STRUCT_OFFSET(pthis, 0x90, int)); + PopSwReverb(g_psw); + snd_ContinueAllSoundsInGroup(0xFFFFFFFF); +} INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FAccept__10CMpegAudioiPUc); diff --git a/src/P2/so.c b/src/P2/so.c index 3e4d2cba..f6d2b19f 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -107,7 +107,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateSoBounds__FP2SO); INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateGeomWorld__FP4GEOMT0G9VU_VECTORP7MATRIX3); -INCLUDE_ASM("asm/nonmatchings/P2/so", UpdateSoXfWorldHierarchy__FP2SO); +void UpdateSoXfWorldHierarchy(SO *pso) +{ + UpdateAloXfWorldHierarchy(pso); + UpdateGeomWorld( + &STRUCT_OFFSET(pso, 0x380, GEOM), + &STRUCT_OFFSET(pso, 0x3A4, GEOM), + STRUCT_OFFSET(pso, 0x140, VU_VECTOR), + &STRUCT_OFFSET(pso, 0x110, MATRIX3)); + UpdateGeomWorld( + &STRUCT_OFFSET(pso, 0x4E8, GEOM), + &STRUCT_OFFSET(pso, 0x50C, GEOM), + STRUCT_OFFSET(pso, 0x140, VU_VECTOR), + &STRUCT_OFFSET(pso, 0x110, MATRIX3)); +} // alo.h declares the literal identifier `UpdateAloXfWorld__FP3ALO`, which both // double-mangles if called and poisons the plain name `UpdateAloXfWorld` for @@ -557,7 +570,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", EnsureSoLvo__FP2SO); INCLUDE_ASM("asm/nonmatchings/P2/so", ProjectSoLvo__FP2SOf); -INCLUDE_ASM("asm/nonmatchings/P2/so", ProjectSoTransform__FP2SOfi); +void ProjectSoTransform(SO *pso, float dt, int fForce) +{ + if (STRUCT_OFFSET(pso, 0x3C8, void *) != NULL) + { + ProjectSoLvo(pso, dt); + } + ProjectAloTransform(pso, dt, fForce); +} INCLUDE_ASM("asm/nonmatchings/P2/so", ApplySoImpulse__FP2SOP6VECTORT1f); diff --git a/src/P2/sound.c b/src/P2/sound.c index 17351772..e08e839a 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -2,6 +2,7 @@ #include <989snd.h> #include #include +#include extern uchar D_00604790[]; // temp @@ -31,7 +32,17 @@ void SbpEnsureBank(SFXID sfxid) INCLUDE_ASM("asm/nonmatchings/P2/sound", NewSfx__FPP3SFX); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FContinuousSound__F5SFXID); +extern int D_006047B0[]; +extern int D_006047D0[]; + +int FContinuousSound(SFXID sfxid) +{ + if (D_006047B0[D_00245020[sfxid][0]] == 0) + { + SbpEnsureBank(sfxid); + } + return D_006047D0[sfxid]; +} extern int D_00274730; extern "C" void FUN_001BE5D8(void) @@ -168,7 +179,16 @@ extern "C" void SfxhMusicUnknown2() snd_ContinueSound(D_00274728); } -INCLUDE_ASM("asm/nonmatchings/P2/sound", PexcAlloc__Fv); +EXC *PexcAlloc() +{ + EXC *pexc = (EXC *)PvAllocSlotheapUnsafe(&STRUCT_OFFSET(g_psw, 0x1bb8, SLOTHEAP)); + if (pexc != 0) + { + memset(pexc, 0, sizeof(EXC)); + AppendDlEntry(&STRUCT_OFFSET(g_psw, 0x1bc4, DL), pexc); + } + return pexc; +} void RemoveExc(EXC *pexc) { @@ -184,7 +204,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", SetIexcCurHigh__FP3EXC); INCLUDE_ASM("asm/nonmatchings/P2/sound", UnsetExcitement__FP3EXC); -INCLUDE_ASM("asm/nonmatchings/P2/sound", UnsetExcitementHyst__FP3EXC); +extern int D_00274734; +void SetIexcCurHigh(EXC *pexc); + +void UnsetExcitementHyst(EXC *pexc) +{ + if (pexc != 0) + { + int iexc = pexc->iexc; + RemoveExc(pexc); + if (iexc == D_00274734) + { + g_iexcHyst = iexc; + SetIexcCurHigh(pexc); + } + } +} void StartupSound() { @@ -234,7 +269,16 @@ float SDistEar(VECTOR *pvec) INCLUDE_ASM("asm/nonmatchings/P2/sound", CalculateDistVolPan__FP6VECTORPfT1fff); -INCLUDE_ASM("asm/nonmatchings/P2/sound", PambAlloc__Fv); +AMB *PambAlloc() +{ + AMB *pamb = (AMB *)PvAllocSlotheapUnsafe(&STRUCT_OFFSET(g_psw, 0x1ba0, SLOTHEAP)); + if (pamb != 0) + { + memset(pamb, 0, 0x90); + AppendDlEntry(&STRUCT_OFFSET(g_psw, 0x1bac, DL), pamb); + } + return pamb; +} void DropPamb(AMB **ppamb) { @@ -242,9 +286,30 @@ void DropPamb(AMB **ppamb) *ppamb = NULL; } -INCLUDE_ASM("asm/nonmatchings/P2/sound", RemoveAmb__FP3AMB); +void RemoveAmb(AMB *pamb) +{ + if (pamb->ppamb != NULL) + { + *pamb->ppamb = NULL; + } + pamb->iSerial = -1; + RemoveDlEntry(&STRUCT_OFFSET(g_psw, 0x1bac, DL), pamb); + FreeSlotheapPv(&STRUCT_OFFSET(g_psw, 0x1ba0, SLOTHEAP), pamb); +} -INCLUDE_ASM("asm/nonmatchings/P2/sound", StopSound__FP3AMBi); +void RemoveAmb(AMB *pamb); + +void StopSound(AMB *pamb, int msRampdown) +{ + if (pamb != 0) + { + if (msRampdown == 0) + snd_StopSound(pamb->sfxh); + else + snd_AutoVol(pamb->sfxh, -4, (int)((float)msRampdown * 0.24000001f), 2); + RemoveAmb(pamb); + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", SetPambFrq__FP3AMBf); @@ -422,4 +487,14 @@ void FUN_001c0cb0() INCLUDE_ASM("asm/nonmatchings/P2/sound", HsNextFootFall__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/sound", NextSneakyFootstep__Fv); +extern int D_002748EC; +int HsNextFootFall(); + +void NextSneakyFootstep() +{ + if (D_002748EC != 0) + { + int hs = HsNextFootFall(); + StartSound((SFXID)0x77, NULL, NULL, NULL, 0.0f, 0.0f, 0.5f, hs * 0.083333336f, 0.0f, NULL, NULL); + } +} diff --git a/src/P2/sw.c b/src/P2/sw.c index 3a9470a9..b57b972d 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -242,7 +242,14 @@ void AddOxa(OXA *poxa, OXA **ppoxaFirst) *ppoxaFirst = poxa; } -INCLUDE_ASM("asm/nonmatchings/P2/sw", PoxaAllocSw__FP2SWP2SO); +OXA *PoxaAllocSw(SW *psw, SO *pso) +{ + OXA *poxa = STRUCT_OFFSET(psw, 0x1AE4, OXA *); + RemoveOxa(poxa, &STRUCT_OFFSET(psw, 0x1AE4, OXA *)); + AddOxa(poxa, &STRUCT_OFFSET(psw, 0x1AE8, OXA *)); + poxa->pso = pso; + return poxa; +} INCLUDE_ASM("asm/nonmatchings/P2/sw", FreeSwPoxa__FP2SWP3OXA); @@ -353,7 +360,25 @@ extern "C" int FUN_001dd7a0(SW *psw, int wid) INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7e8); -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd888); +extern int *PlsFromWid(WID wid) __asm__("LsFromWid"); + +extern "C" int FUN_001dd888(SW *psw, WID wid, int nKey) +{ + int *pls = PlsFromWid(wid); + if (pls != NULL) + { + int *p = pls + 0x11; + int i = 0; + do + { + if (p[0] == nKey) + return p[1]; + i++; + p += 2; + } while ((unsigned)i < 4); + } + return 0; +} int FUN_001dd8e8(SW *psw, GAMEWORLD gameworld) { @@ -462,7 +487,16 @@ extern "C" void FUN_001ddb20(SW *psw, PRK prk, int oid) SetPrompt(pprompt, PRP_Basic, prk); } -INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001ddb58); +extern BLOT D_002721D0; + +extern "C" void FUN_001ddb58(SW *psw) +{ + if (++STRUCT_OFFSET(psw, 0x2320, int) == 1) + { + SetBlotDtVisible(&D_002721D0, 0.0f); + D_002721D0.pvtblot->pfnShowBlot(&D_002721D0); + } +} extern BLOT D_002721D0; From c436f8a5864627b18807d5efba2f6dfe3fcfd914 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 20:30:44 +0200 Subject: [PATCH 114/134] Match 13 wave-4 functions (po/dmas/sm/joy/util/xform/screen/break/act/jlo/mpeg cross-unit) Fix game.h: UnlockEndgameCutscenesFromFgs & PchzFriendlyFromWid are raw symbols (extern C). Co-Authored-By: Claude Fable 5 --- config/symbol_addrs.txt | 2 +- include/game.h | 4 ++-- src/P2/break.c | 28 +++++++++++++++++++++++++++- src/P2/chkpnt.c | 1 + src/P2/dmas.c | 25 ++++++++++++++++++++++++- src/P2/emitter.c | 21 ++++++++++++++++++++- src/P2/game.c | 22 +++++++++++++++++++++- src/P2/jlo.c | 19 ++++++++++++++++++- src/P2/joy.c | 36 ++++++++++++++++++++---------------- src/P2/po.c | 31 ++++++++++++++++++++++++++++++- src/P2/prompt.c | 1 + src/P2/puffer.c | 1 + src/P2/screen.c | 21 ++++++++++++++++++++- src/P2/sm.c | 23 ++++++++++++++++++++++- src/P2/sound.c | 15 ++++++++++++++- src/P2/spliceobj.c | 2 ++ src/P2/sw.c | 1 + src/P2/util.c | 38 +------------------------------------- src/P2/xform.c | 16 +++++++++++++++- 19 files changed, 241 insertions(+), 66 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index dcb1d81a..34b6f1f2 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3608,7 +3608,7 @@ FUN_001ac0e8 = 0x1AC0E8; // type:func PostNoteLoad__FP4NOTE = 0x1AC5C0; // type:func SetNoteAchzDraw__FP4NOTEPc = 0x1AC638; // type:func DrawNote__FP4NOTE = 0x1AC700; // type:func -FUN_001ac888 = 0x1AC888; // type:func +FUN_001ac888__FP4BLOT = 0x1AC888; // type:func FUN_001ac910 = 0x1AC910; // type:func FUN_001ac990 = 0x1AC990; // type:func FUN_001ac9e0 = 0x1AC9E0; // type:func diff --git a/include/game.h b/include/game.h index ac75bf85..96f61730 100644 --- a/include/game.h +++ b/include/game.h @@ -258,7 +258,7 @@ void StartupGame(); * * @param wid World ID. */ -char *PchzFriendlyFromWid(int wid); +extern "C" char *PchzFriendlyFromWid(int wid); // LevelLoadData *call_search_level_by_id(int level_id); @@ -304,7 +304,7 @@ void DefeatBossFromWid(int wid); * * @param fgs Completion flags. */ -void UnlockEndgameCutscenesFromFgs(FGS fgs); +extern "C" void UnlockEndgameCutscenesFromFgs(FGS fgs); /** * @brief Plays the ending cutscene based on the completion flags. diff --git a/src/P2/break.c b/src/P2/break.c index 45dfa177..05072254 100644 --- a/src/P2/break.c +++ b/src/P2/break.c @@ -215,7 +215,33 @@ void InitFragile(FRAGILE *pfragile) STRUCT_OFFSET(pfragile, 0x6c8, int) = -1; } -INCLUDE_ASM("asm/nonmatchings/P2/break", AdjustFragileNewXp__FP7FRAGILEP2XPi); +void AdjustFragileNewXp(FRAGILE *pfragile, XP *pxp, int ixpd) +{ + if (STRUCT_OFFSET(pfragile, 0x680, int)) + return; + + SO *psoRoot = pxp->axpd[1 - ixpd].psoRoot; + + if (STRUCT_OFFSET(pfragile, 0x678, int)) + return; + + if (!FCheckBrkTouchObject((BRK *)pfragile, psoRoot)) + return; + + CNSTR cnstrForce = STRUCT_OFFSET(pfragile, 0x6c4, CNSTR); + if (cnstrForce != (CNSTR)-1) + SetSoCnstrForce((SO *)pfragile, cnstrForce); + + CNSTR cnstrTorque = STRUCT_OFFSET(pfragile, 0x6c8, CNSTR); + if (cnstrTorque != (CNSTR)-1) + SetSoCnstrTorque((SO *)pfragile, cnstrTorque); + + float t = STRUCT_OFFSET(pfragile, 0x368, float); + float scale = STRUCT_OFFSET(pfragile, 0x6c0, float); + STRUCT_OFFSET(pfragile, 0x678, int) = 1; + STRUCT_OFFSET(pfragile, 0x6cc, SO *) = psoRoot; + STRUCT_OFFSET(pfragile, 0x368, float) = t * scale; +} void AdjustZapbreakNewXp(ZAPBREAK *pzapbreak, XP *pxp, int ixpd) { diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index b9d09c48..b3487ae1 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ResetChkmgrCheckpoints__FP6CHKMGR); #ifdef SKIP_ASM diff --git a/src/P2/dmas.c b/src/P2/dmas.c index cb8a14d7..946c8d82 100644 --- a/src/P2/dmas.c +++ b/src/P2/dmas.c @@ -91,7 +91,30 @@ void DMAS::AddDmaCnt() m_pqwCnt->aul[1] = 0; } -INCLUDE_ASM("asm/nonmatchings/P2/dmas", AddDmaRefs__4DMASiP2QW); +void DMAS::AddDmaRefs(int cqw, QW *aqw) +{ + int fCnt = 0; + + if (m_pqwCnt) + { + EndDmaCnt(); + fCnt = 1; + } + + uchar *pb = m_pb; + m_pb = pb + 0x10; + *(ulong *)pb = (cqw | 0x40000000) | ((ulong)(uint)aqw << 32); + *(ulong *)(pb + 8) = 0; + + if (fCnt) + { + QW *pqwCnt = (QW *)m_pb; + m_pqwCnt = pqwCnt; + m_pb += sizeof(QW); + pqwCnt->aul[0] = 0x10000000; + m_pqwCnt->aul[1] = 0; + } +} void DMAS::AddDmaCall(QW *pqw) { diff --git a/src/P2/emitter.c b/src/P2/emitter.c index d8b79961..0e8f26e9 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -293,7 +293,26 @@ void ExplodeExplExplso(EXPL *pexpl, EXPLSO *pexplso) INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadExplgFromBrx__FP5EXPLGP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", CloneExplg__FP5EXPLGT0); +void CloneExplg(EXPLG *pexplg, EXPLG *pexplgBase) +{ + int i = 0; + + CloneLo((LO *)pexplg, (LO *)pexplgBase); + + if (STRUCT_OFFSET(pexplg, 0x90, int) > 0) + { + LO **p = &STRUCT_OFFSET(pexplg, 0x94, LO *); + do + { + LO *plo = PloCloneLo(*p, STRUCT_OFFSET(pexplg, 0x14, SW *), STRUCT_OFFSET(pexplg, 0x18, ALO *)); + i++; + plo->pvtlo->pfnRemoveLo(plo); + *p = plo; + STRUCT_OFFSET(plo, 0x80, EXPLG *) = pexplg; + p++; + } while (i < STRUCT_OFFSET(pexplg, 0x90, int)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindExplg__FP5EXPLG); diff --git a/src/P2/game.c b/src/P2/game.c index aef12379..d16bc0ca 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -95,7 +95,27 @@ void UnlockIntroCutsceneFromWid(int wid) INCLUDE_ASM("asm/nonmatchings/P2/game", DefeatBossFromWid); -INCLUDE_ASM("asm/nonmatchings/P2/game", UnlockEndgameCutscenesFromFgs); +extern "C" void UnlockEndgameCutscenesFromFgs(FGS fgs) +{ + switch (fgs) + { + case FGS_HalfClues: + g_pgsCur->unlocked_cutscenes |= 0xA002; + g_pgsCur->fgs |= 0x2; + break; + case FGS_AllClues: + if (get_game_completion() & FGS_AllClues) + g_pgsCur->unlocked_cutscenes |= 0xC000; + break; + case FGS_FirstVault: + if (get_game_completion() & FGS_FirstVault) + { + g_pgsCur->unlocked_cutscenes |= 0xC; + g_pgsCur->fgs |= 0xC; + } + break; + } +} INCLUDE_ASM("asm/nonmatchings/P2/game", PlayEndingFromCompletionFlags); diff --git a/src/P2/jlo.c b/src/P2/jlo.c index 6ada8771..c8b89a56 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -69,7 +69,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", LandJlo__FP3JLO); INCLUDE_ASM("asm/nonmatchings/P2/jlo", JumpJlo__FP3JLO); -INCLUDE_ASM("asm/nonmatchings/P2/jlo", FUN_0016d928); +extern "C" void PreloadVag1(void *pv); +extern char D_002482D8[]; + +extern "C" void FUN_0016d928(JLO *pjlo) +{ + if (STRUCT_OFFSET(pjlo, 0x5c0, int) != 0) + { + if (!FVagPlaying()) + { + if (NRandInRange(0, 100) < 20) + { + int n = NRandInRange(0, 6); + PreloadVag1(&D_002482D8[n << 5]); + STRUCT_OFFSET(pjlo, 0x5cc, int) = 1; + } + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/jlo", FUN_0016d9a8); diff --git a/src/P2/joy.c b/src/P2/joy.c index cc7db82d..da9a8d64 100644 --- a/src/P2/joy.c +++ b/src/P2/joy.c @@ -439,21 +439,25 @@ void Chetkido() ((NOTE *)&g_note.unk278)->pvtnote->pfnShowBlot((NOTE *)&g_note.unk278); } -INCLUDE_ASM("asm/nonmatchings/P2/joy", StartupCodes__Fv); -#ifdef SKIP_ASM -/** - * @todo 4.38% matched. - */ +extern CODE D_00262A80; +extern CODE D_00262AB8; +extern CODE D_00262AF0; +extern CODE D_00262B28; +extern CODE D_00262B60; +extern CODE D_00262B98; +extern CODE D_00262BD0; +extern CODE D_00262C08; +extern CODE D_00262C48; + void StartupCodes() { - ////AddCode(&cheat_reload_level.pCodeSeq); - ////AddCode(&cheat_reload_no_cheats.pCodeSeq); - ////AddCode(&cheat_reload_slippery_movement.pCodeSeq); - ////AddCode(&cheat_slippery_objects.pCodeSeq); - ////AddCode(&cheat_infinite_charms.pCodeSeq); - ////AddCode(&cheat_collect_bottles.pCodeSeq); - ////AddCode(&cheat_unlock_pages.pCodeSeq); - ////AddCode(&cheat_unlock_all_worlds.pCodeSeq); - ////AddCode(&cheat_chetkido_password.pCodeSeq); -} -#endif // SKIP_ASM + AddCode(&D_00262A80); + AddCode(&D_00262AB8); + AddCode(&D_00262AF0); + AddCode(&D_00262B28); + AddCode(&D_00262B60); + AddCode(&D_00262B98); + AddCode(&D_00262BD0); + AddCode(&D_00262C08); + AddCode(&D_00262C48); +} // SKIP_ASM diff --git a/src/P2/po.c b/src/P2/po.c index c66f9d5b..a5207f63 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -156,7 +156,36 @@ INCLUDE_ASM("asm/nonmatchings/P2/po", PpoStart__Fv); INCLUDE_ASM("asm/nonmatchings/P2/po", _IppoFindPo__FP2PO); -INCLUDE_ASM("asm/nonmatchings/P2/po", AddPoToList__FP2PO); +extern int D_00269C90; + +void AddPoToList(PO *ppo) +{ + if (STRUCT_OFFSET(ppo, 0x550, int) == 0) + return; + + if (STRUCT_OFFSET(ppo, 0x18, ALO *) != 0) + return; + + if (!FIsLoInWorld(ppo)) + return; + + if (_IppoFindPo(ppo) >= 0) + return; + + if ((unsigned)D_00269C90 < 0x10) + { + int c = D_00269C90; + D_00269C90 = c + 1; + g_appo[c] = ppo; + } + else if (STRUCT_OFFSET(ppo, 0x8, int) == 5) + { + if (g_pjt == 0) + { + g_appo[0] = ppo; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/po", RemovePoFromList__FP2PO); diff --git a/src/P2/prompt.c b/src/P2/prompt.c index 449bdcff..e46190d9 100644 --- a/src/P2/prompt.c +++ b/src/P2/prompt.c @@ -4,6 +4,7 @@ #include #include #include +#include // TODO: Change to static when possible. extern char *s_mprespkachz[13]; diff --git a/src/P2/puffer.c b/src/P2/puffer.c index ab42519e..231ed807 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -3,6 +3,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/puffer", InitPuffer__FP6PUFFER); diff --git a/src/P2/screen.c b/src/P2/screen.c index ecaa4860..b0f5dd3c 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -289,7 +289,26 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", SetNoteAchzDraw__FP4NOTEPc); INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawNote__FP4NOTE); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac888); +extern CFont *D_002743F0; + +void FUN_001ac888(BLOT *pblot) +{ + CFont *pfont; + void *pv; + + PostBlotLoad(pblot); + pfont = STRUCT_OFFSET(pblot, 0x4, CFont *); + pv = STRUCT_OFFSET(pfont, 0x4c, void *); + STRUCT_OFFSET(pblot, 0x4, int) = + (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( + (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), 0.9f, 0.9f); + STRUCT_OFFSET(pblot, 0x208, unsigned int) = 0xDF7F7F7F; + if (FUN_0015c188(2)) + { + STRUCT_OFFSET(pblot, 0x210, CFont **) = &D_002743F0; + *STRUCT_OFFSET(pblot, 0x210, CFont **) = FUN_0015c1c0(2); + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac910); diff --git a/src/P2/sm.c b/src/P2/sm.c index 61b4ff3d..6b443b8f 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -111,4 +111,25 @@ void SendSmaMessage(SMA *psma, MSGID msgid, void *pv) INCLUDE_ASM("asm/nonmatchings/P2/sm", FUN_001b6df8); -INCLUDE_ASM("asm/nonmatchings/P2/sm", NotifySmaSpliceOnEnterState__FP3SMAii); +void NotifySmaSpliceOnEnterState(SMA *psma, int ismsFrom, int ismsTo) +{ + int oidFrom; + int oidTo; + void *apv[3]; + + if (ismsFrom >= 0) + oidFrom = psma->psm->asms[ismsFrom].oid; + else + oidFrom = -1; + + if (ismsTo >= 0) + oidTo = psma->psm->asms[ismsTo].oid; + else + oidTo = -1; + + apv[0] = &psma; + apv[1] = &oidFrom; + apv[2] = &oidTo; + + HandleLoSpliceEvent(psma->psm, 0xE, 3, apv); +} diff --git a/src/P2/sound.c b/src/P2/sound.c index e08e839a..faed5682 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -267,7 +267,20 @@ float SDistEar(VECTOR *pvec) return PfneardistGet()(pposEar, pvec); } -INCLUDE_ASM("asm/nonmatchings/P2/sound", CalculateDistVolPan__FP6VECTORPfT1fff); +void CalculateVolPan(float dist, VECTOR *pvec, float *pa, float *pb, float a, float b, float c); + +void CalculateDistVolPan(VECTOR *pvec, float *pa, float *pb, float a, float b, float c) +{ + if (pvec) + { + CalculateVolPan(SDistEar(pvec), pvec, pa, pb, a, b, c); + } + else + { + *pa = a; + *pb = 0; + } +} AMB *PambAlloc() { diff --git a/src/P2/spliceobj.c b/src/P2/spliceobj.c index 351eefea..03831fbe 100644 --- a/src/P2/spliceobj.c +++ b/src/P2/spliceobj.c @@ -1,4 +1,6 @@ #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", PeopidFind__FP5BASICi); diff --git a/src/P2/sw.c b/src/P2/sw.c index b57b972d..cb78c409 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -12,6 +12,7 @@ #include #include #include +#include extern SW *g_psw; extern int g_fLoadDebugInfo; diff --git a/src/P2/util.c b/src/P2/util.c index 3a0d6b29..f37c0906 100644 --- a/src/P2/util.c +++ b/src/P2/util.c @@ -137,43 +137,7 @@ int FFloatsNear(float g1, float g2, float gEpsilon) return (g2 / x) < gEpsilon; } -INCLUDE_ASM("asm/nonmatchings/P2/util", CSolveQuadratic__FfffPf); -#ifdef SKIP_ASM -/** - * @todo 95.96% matched. - * - * Compiler is using bc1f instead of bc1fl for (alpha < 0.0f) branch. - * - * https://decomp.me/scratch/A4VOu - */ -int CSolveQuadratic(float a, float b, float c, float *ax) -{ - float alpha; - float beta; - - alpha = b * b - 4.f * a * c; - a = a * 2; - - if (alpha < 0.0f) - { - return 0; - } - else - { - beta = b / a; - alpha = sqrtf(alpha) / a; - if (fabsf(alpha) < 0.0001f) - { - *ax = -beta; - return 1; - } - - *ax = -beta + alpha; - ax[1] = -beta - alpha; - return 2; - } -} -#endif // SKIP_ASM +INCLUDE_ASM("asm/nonmatchings/P2/util", CSolveQuadratic__FfffPf); // SKIP_ASM void PrescaleClq(CLQ *pclqSrc, float ru, float du, CLQ *pclqDst) { diff --git a/src/P2/xform.c b/src/P2/xform.c index cae3c070..b5076e2f 100644 --- a/src/P2/xform.c +++ b/src/P2/xform.c @@ -4,6 +4,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/xform", InitXfm__FP3XFM); @@ -43,7 +44,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/xform", PwarpFromOid__F3OIDT0); INCLUDE_ASM("asm/nonmatchings/P2/xform", LoadWarpFromBrx__FP4WARPP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/xform", CloneWarp__FP4WARPT0); +void CloneWarp(WARP *pwarp, WARP *pwarpBase) +{ + int i; + + CloneLo(pwarp, pwarpBase); + + STRUCT_OFFSET(pwarp, 0xa4, LO **) = (LO **)PvAllocSwImpl(STRUCT_OFFSET(pwarp, 0xa0, int) * 4); + + for (i = 0; i < STRUCT_OFFSET(pwarp, 0xa0, int); i++) + { + LO *ploClone = PloCloneLo(STRUCT_OFFSET(pwarpBase, 0xa4, LO **)[i], pwarp->psw, NULL); + STRUCT_OFFSET(pwarp, 0xa4, LO **)[i] = ploClone; + } +} void PostWarpLoad(WARP *pwarp) { From 29ed5aeacb08c2fb7357476160125c3e39447eda Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 20:57:57 +0200 Subject: [PATCH 115/134] Match 5 wave-5 functions (rog message/killed, emitter skeleton, jt stand, dartgun/screen) Co-Authored-By: Claude Fable 5 --- config/symbol_addrs.txt | 2 +- src/P2/dartgun.c | 37 ++++++++++++++++++++++++++++++- src/P2/emitter.c | 31 +++++++++++++++++++++++++- src/P2/jt.c | 48 ++++++++++++++++++++++++++++++++++++++++- src/P2/rog.c | 38 +++++++++++++++++++++++++++++++- src/P2/screen.c | 35 +++++++++++++++++++++++++++++- src/P2/so.c | 29 ++----------------------- src/P2/wm.c | 1 + 8 files changed, 188 insertions(+), 33 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 34b6f1f2..e236eb08 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3631,7 +3631,7 @@ FUN_001ad7b0 = 0x1AD7B0; // type:func FUN_001ad940__FP4BLOT = 0x1AD940; // type:func FUN_001ad970 = 0x1AD970; // type:func DrawLetterbox__FP9LETTERBOX = 0x1ADB00; // type:func -FUN_001adc60 = 0x1ADC60; // type:func +FUN_001adc60__FP4BLOT = 0x1ADC60; // type:func DrawLogo__FP4LOGO = 0x1ADD28; // type:func FUN_001adf28 = 0x1ADF28; // type:func FUN_001adff0 = 0x1ADFF0; // type:func diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 2192a8a6..dcf0fadc 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -2,6 +2,7 @@ #include #include #include +#include void InitDartgun(DARTGUN *pdartgun) { @@ -9,7 +10,41 @@ void InitDartgun(DARTGUN *pdartgun) STRUCT_OFFSET(pdartgun, 0x6c0, OID) = OID_Nil; // pdartgun->oidDart } -INCLUDE_ASM("asm/nonmatchings/P2/dartgun", HandleDartgunMessage__FP7DARTGUN5MSGIDPv); +void HandleDartgunMessage(DARTGUN *pdartgun, MSGID msgid, void *pv) +{ + OID oid; + ALO *palo; + + HandleAloMessage((ALO *)pdartgun, msgid, pv); + + if (msgid != (MSGID)0x14) + return; + + if (pv != STRUCT_OFFSET(pdartgun, 0x740, void *)) + return; + + GetSmaGoal((SMA *)pv, &oid); + if (oid != (OID)0x2B7) + return; + + if (STRUCT_OFFSET(pdartgun, 0x680, int) != 0) + { + RetractSma(STRUCT_OFFSET(pdartgun, 0x740, SMA *)); + STRUCT_OFFSET(pdartgun, 0x740, int) = 0; + } + else + { + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x4C, int) = 1; + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = 0; + + palo = STRUCT_OFFSET(pdartgun, 0x734, ALO *); + (*(void (**)(ALO *, void *))((char *)palo->pvtlo + 0x84))(palo, (char *)palo + 0x190); + palo = STRUCT_OFFSET(pdartgun, 0x734, ALO *); + (*(void (**)(ALO *, void *))((char *)palo->pvtlo + 0x88))(palo, (char *)palo + 0x1A0); + palo = STRUCT_OFFSET(pdartgun, 0x738, ALO *); + (*(void (**)(ALO *, void *))((char *)palo->pvtlo + 0x88))(palo, (char *)palo + 0x1A0); + } +} INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BindDartgun__FP7DARTGUN); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 0e8f26e9..02550eb1 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -266,7 +266,36 @@ void StockSplashSmall(VECTOR *ppos, float gScale, SO *psoTouch) } } -INCLUDE_ASM("asm/nonmatchings/P2/emitter", AddEmitoSkeleton__FP5EMITO3OIDT1ffffP2LO); +void AddEmitoSkeleton(EMITO *pemito, OID oid, OID oidOther, float sRadius, float gDensity, float sRadiusOther, float gDensityOther, LO *ploContext) +{ + STRUCT_OFFSET(pemito, 0x0, int) = 3; + + if (STRUCT_OFFSET(pemito, 0x14, void *) == 0) + STRUCT_OFFSET(pemito, 0x14, void *) = PvAllocSwClearImpl(0x500); + + if (STRUCT_OFFSET(pemito, 0x10, int) < 0x20) + { + int c = STRUCT_OFFSET(pemito, 0x10, int); + char *pentry = (char *)STRUCT_OFFSET(pemito, 0x14, void *) + c * 0x28; + + STRUCT_OFFSET(pemito, 0x10, int) = c + 1; + + STRUCT_OFFSET(pentry, 0x0, int) = oid; + STRUCT_OFFSET(pentry, 0x4, int) = oidOther; + + STRUCT_OFFSET(pentry, 0x8, float) = gDensity; + if (0.0f <= gDensityOther) + STRUCT_OFFSET(pentry, 0xc, float) = gDensityOther; + else + STRUCT_OFFSET(pentry, 0xc, float) = gDensity; + + STRUCT_OFFSET(pentry, 0x10, float) = sRadius; + if (0.0f <= sRadiusOther) + STRUCT_OFFSET(pentry, 0x14, float) = sRadiusOther; + else + STRUCT_OFFSET(pentry, 0x14, float) = sRadius; + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", BindEmitb__FP5EMITBP2LO); diff --git a/src/P2/jt.c b/src/P2/jt.c index 0f517095..5980af38 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -58,7 +58,53 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", RebuildJtXmg__FP2JTP3ALOfT1P6ACTADJP3XMG); INCLUDE_ASM("asm/nonmatchings/P2/jt", FMatchJtXmg__FP2JTP3XMGP6ACTADJ); -INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtStand__FP2JT); +struct XMG; + +int FTurnJtToTarget(JT *pjt); +void RebuildJtXmg(JT *pjt, ALO *palo, float s, ALO *palo2, ACTADJ *pactadj, XMG *pxmg); +int FMatchJtXmg(JT *pjt, XMG *pxmg, ACTADJ *pactadj); + +void UpdateJtStand(JT *pjt) +{ + if (FTurnJtToTarget(pjt) == 0) + { + if (STRUCT_OFFSET(pjt, 0x690, int) != 0) + { + VECTOR w; + float g; + + CalculateAloMovement(STRUCT_OFFSET(pjt, 0x6C0, ALO *), NULL, + (VECTOR *)((char *)pjt + 0x6A0), NULL, &w, NULL, NULL); + g = GLimitAbs(w.z, 10.0f); + w.z = g; + STRUCT_OFFSET(pjt, 0x638, float) += g * g_clock.dt; + } + } + + if (STRUCT_OFFSET(pjt, 0x250C, ACTADJ *) != NULL) + { + RebuildJtXmg(pjt, STRUCT_OFFSET(pjt, 0x628, ALO *), 5.0f, STRUCT_OFFSET(pjt, 0x620, ALO *), + STRUCT_OFFSET(pjt, 0x250C, ACTADJ *), (XMG *)((char *)pjt + 0x1190)); + RebuildJtXmg(pjt, STRUCT_OFFSET(pjt, 0x62C, ALO *), 5.0f, STRUCT_OFFSET(pjt, 0x624, ALO *), + STRUCT_OFFSET(pjt, 0x2510, ACTADJ *), (XMG *)((char *)pjt + 0x1290)); + + if (FMatchJtXmg(pjt, (XMG *)((char *)pjt + 0x1190), STRUCT_OFFSET(pjt, 0x250C, ACTADJ *))) + { + if (FMatchJtXmg(pjt, (XMG *)((char *)pjt + 0x1290), STRUCT_OFFSET(pjt, 0x2510, ACTADJ *))) + return; + } + + if (STRUCT_OFFSET(pjt, 0x118C, int) != 0) + return; + + if (STRUCT_OFFSET(pjt, 0x1188, SM *) != NULL) + { + if (IsmsFindSmOptional(STRUCT_OFFSET(pjt, 0x1188, SM *), (OID)0x148) >= 0) + SeekSma(STRUCT_OFFSET(pjt, 0x2234, SMA *), (OID)0x148); + STRUCT_OFFSET(pjt, 0x118C, int) = 1; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/jt", ThrowJt__FP2JTP6VECTORff); diff --git a/src/P2/rog.c b/src/P2/rog.c index 17f74ca8..f0e13fab 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -235,7 +235,43 @@ void ReturnedRobRoh(ROB *prob, ROH *proh) INCLUDE_ASM("asm/nonmatchings/P2/rog", ExitedRobRoh__FP3ROBP3ROH); -INCLUDE_ASM("asm/nonmatchings/P2/rog", KilledRobRoh__FP3ROBP3ROH); +void KilledRobRoh(ROB *prob, ROH *proh) +{ + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x384, DL), proh); + AppendDlEntry(&STRUCT_OFFSET(prob, 0x390, DL), proh); + + ROC *proc; + if (STRUCT_OFFSET(proh, 0x560, ROST *) != NULL) + { + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x3ac, DL), STRUCT_OFFSET(proh, 0x560, void *)); + AppendDlEntry(&STRUCT_OFFSET(prob, 0x3a0, DL), STRUCT_OFFSET(proh, 0x560, void *)); + SetRostRosts(STRUCT_OFFSET(proh, 0x560, ROST *), ROSTS_Close); + } + + proc = STRUCT_OFFSET(proh, 0x55c, ROC *); + if (proc != NULL) + { + if (STRUCT_OFFSET(proc, 0x18, ROH *) == proh) + { + DroppedRobRoh(prob, proh); + } + RemoveDlEntry(&STRUCT_OFFSET(prob, 0x35c, DL), proc); + AppendDlEntry(&STRUCT_OFFSET(prob, 0x368, DL), proc); + if (!FChooseRobRoh(prob, proc)) + STRUCT_OFFSET(proc, 0x55c, ROH *) = NULL; + } + + STRUCT_OFFSET(proh, 0x560, ROST *) = NULL; + STRUCT_OFFSET(proh, 0x55c, ROC *) = NULL; + (*(void (**)(ROH *))(STRUCT_OFFSET(proh, 0x0, uint8_t *) + 0x1c))(proh); + + if (STRUCT_OFFSET(prob, 0x39c, int) == STRUCT_OFFSET(prob, 0x628, int)) + { + STRUCT_OFFSET(prob, 0x640, float) = + g_clock.t + GRandInRange(STRUCT_OFFSET(prob, 0x638, float), STRUCT_OFFSET(prob, 0x63c, float)); + } + STRUCT_OFFSET(prob, 0x39c, int) -= 1; +} INCLUDE_ASM("asm/nonmatchings/P2/rog", FChooseRobRoc__FP3ROBP3ROH); diff --git a/src/P2/screen.c b/src/P2/screen.c index b0f5dd3c..383cdeb3 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -4,6 +4,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/screen", StartupScreen__Fv); @@ -420,7 +421,39 @@ void DrawLetterbox(LETTERBOX *pletterbox) g_gifs.PackXYZF(0x9400, 0x8700, 0xFFFFFF0, 0); } -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001adc60); +extern float D_00274448; +extern float D_0027444C; +extern CFont *D_00274450; +extern char D_0024CEF0[]; + +void FUN_001adc60(BLOT *pblot) +{ + CFont *pfont; + void *pv; + + PostBlotLoad(pblot); + pfont = STRUCT_OFFSET(pblot, 0x4, CFont *); + pv = STRUCT_OFFSET(pfont, 0x4c, void *); + STRUCT_OFFSET(pblot, 0x4, int) = + (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( + (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), D_00274448, D_0027444C); + if (FUN_0015c1c0(2)) + { + STRUCT_OFFSET(pblot, 0x210, CFont **) = &D_00274450; + *STRUCT_OFFSET(pblot, 0x210, CFont **) = FUN_0015c1c0(2); + } + + SHD *pshd = PshdFindShader((OID)0x493); + STRUCT_OFFSET(pblot, 0x260, SHD *) = pshd; + if (pshd != NULL) + { + ResizeBlot(pblot, 366.75f, 165.75f); + } + else + { + ((void (*)(BLOT *, char *))((VTBLOT *)pblot->pvtblot)->pfnSetBlotAchzDraw)(pblot, D_0024CEF0); + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawLogo__FP4LOGO); diff --git a/src/P2/so.c b/src/P2/so.c index f6d2b19f..9f745250 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -1,5 +1,7 @@ #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/so", InitSo__FP2SO); @@ -38,33 +40,6 @@ void OnSoAdd(SO *pso) // shifting the unit and failing the checksum. Keep it wrapped until the // surrounding functions are decompiled or the tooling quirk is fixed. INCLUDE_ASM("asm/nonmatchings/P2/so", OnSoRemove__FP2SO); -#ifdef SKIP_ASM -void OnSoRemove(SO *pso) -{ - SW *psw = pso->psw; - SO *psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); - - EnableSoPhys(pso, 0); - OnAloRemove(pso); - psw->cpsoAll = psw->cpsoAll - 1; - if (pso->paloParent == NULL) - { - RemoveSwAaobrObject(psw, pso); - FreeSwPoxa(psw, STRUCT_OFFSET(pso, 0x480, OXA *)); - psw->cpsoRoot = psw->cpsoRoot - 1; - RemoveDlEntry(&psw->dlRoot, pso); - } - FreeSwStsoList(psw, STRUCT_OFFSET(pso, 0x540, STSO *)); - STRUCT_OFFSET(pso, 0x540, STSO *) = NULL; // pstsoFirst - if ((STRUCT_OFFSET(pso, 0x538, uint64_t) & ((uint64_t)0x8000 << 39)) == 0) // locked, bit 54 - { - if (psoRoot != pso) - { - RecalcSoLocked(psoRoot); - } - } -} -#endif void EnableSoPhys(SO *pso, int fPhys) { diff --git a/src/P2/wm.c b/src/P2/wm.c index 49e2760c..e2213c12 100644 --- a/src/P2/wm.c +++ b/src/P2/wm.c @@ -1,5 +1,6 @@ #include #include +#include extern int D_00275BF0; From 57f0b8c00886e32ede8796ff1d2c307ed080ab8b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 21:17:19 +0200 Subject: [PATCH 116/134] Match 17 wave-6 functions (alo/font/sound/screen/rip/rog/sensor/step/coin/game/jt/blip/chkpnt) Co-Authored-By: Claude Fable 5 --- config/symbol_addrs.txt | 2 +- src/P2/alo.c | 32 ++++++++++++++++++++++- src/P2/chkpnt.c | 18 ++++++++++++- src/P2/coin.c | 22 ++++++++++++++-- src/P2/font.c | 50 +++++++++++++++++++++++++++++++++--- src/P2/game.c | 17 ++++++------- src/P2/jt.c | 26 ++++++++++++++++++- src/P2/rip.c | 12 ++++++++- src/P2/rog.c | 24 +++++++++++++++++- src/P2/screen.c | 18 ++++++++++++- src/P2/sensor.c | 24 +++++++++++++++++- src/P2/sound.c | 56 ++++++++++++++++++++++++++++++++++++++--- src/P2/step.c | 13 +++++++++- 13 files changed, 288 insertions(+), 26 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index e236eb08..0dc18f11 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -3625,7 +3625,7 @@ SetTotalsBlots__FP6TOTALS5BLOTS = 0x1AD320; // type:func ShowTotalsQMARK = 0x1AD378; // type:func HideTotalsQMARK = 0x1AD3B0; // type:func DrawTotals__FP6TOTALS = 0x1AD3F0; // type:func -FUN_001ad6a8 = 0x1AD6A8; // type:func +FUN_001ad6a8__FP4BLOT = 0x1AD6A8; // type:func FUN_001ad718 = 0x1AD718; // type:func FUN_001ad7b0 = 0x1AD7B0; // type:func FUN_001ad940__FP4BLOT = 0x1AD940; // type:func diff --git a/src/P2/alo.c b/src/P2/alo.c index 489640e6..8bd7083a 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include extern VTACT g_vtactseg; extern SHADOW s_shadow; @@ -498,7 +500,35 @@ void CreateAloActadj(ALO *palo, int nPriority, ACTADJ **ppactadj) } } -INCLUDE_ASM("asm/nonmatchings/P2/alo", FIsAloStatic__FP3ALO); +int FIsAloStatic(ALO *palo) +{ + ALO *paloChild; + + if (!FIsZeroV(&STRUCT_OFFSET(palo, 0x150, VECTOR))) + { + return 0; + } + + if (!FIsZeroW(&STRUCT_OFFSET(palo, 0x160, VECTOR))) + { + return 0; + } + + paloChild = (ALO *)palo->dlChild.head; + while (paloChild != NULL) + { + if (paloChild->pvtlo->grfcid & 1) + { + if (!FIsAloStatic(paloChild)) + { + return 0; + } + } + paloChild = (ALO *)paloChild->dleChild.next; + } + + return 1; +} void ResolveAlo(ALO *palo) { diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index b3487ae1..e8fbb768 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ResetChkmgrCheckpoints__FP6CHKMGR); #ifdef SKIP_ASM @@ -91,7 +94,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", CloneChkpnt__FP6CHKPNTT0); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", UpdateChkpnt__FP6CHKPNTf); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", FUN_001417f0); +extern void TriggerJoyRumbleRumk(JOY *pjoy, RUMK rumk, float dt); + +extern "C" int FUN_001417f0(CHKPNT *pchkpnt, WKR *pwkr) +{ + if ((PO *)pwkr->ploSource == PpoCur()) + { + if (!(pwkr->grftak & 0x10)) + TriggerJoyRumbleRumk(&g_joy, RUMK_MediumThrob, 0.2f); + TriggerChkpnt(pchkpnt); + return 1; + } + + return FAbsorbSoWkr((SO *)pchkpnt, pwkr); +} INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", TriggerChkpnt__FP6CHKPNT); diff --git a/src/P2/coin.c b/src/P2/coin.c index eb726bda..07dbe481 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -235,7 +235,14 @@ void FUN_00148748(void *param_1) INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148770); -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148828); +extern "C" void FUN_00148828(DPRIZE *pdprize, float dt) +{ + UpdateDprize(pdprize, dt); + if (pdprize->oidInitialState != OID_Unknown) + return; + if (STRUCT_OFFSET(pdprize->psw, 0x2308, float) <= g_clock.t) + (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, DPRIZES_Lose); +} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148888); @@ -261,7 +268,18 @@ void FUN_00148e18(void *param_1) INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148e40); -INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148ef8); +extern "C" void FUN_00148ef8(COIN *pcoin, float dt) +{ + UpdateDprize(pcoin, dt); + if (pcoin->oidInitialState != OID_Unknown) + return; + if (pcoin->fNeverReuse == 0) + return; + if (D_00270458 != 2) + pcoin->tLose -= g_clock.dt; + if (pcoin->tLose <= 0.0f) + (*(void (**)(COIN *, DPRIZES))((char *)pcoin->pvtlo + 0xCC))(pcoin, DPRIZES_Lose); +} INCLUDE_ASM("asm/nonmatchings/P2/coin", increment_and_show_life_count); diff --git a/src/P2/font.c b/src/P2/font.c index f69b7c8f..3f8ecbc7 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -67,14 +67,40 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", PopScaling__5CFont); INCLUDE_ASM("asm/nonmatchings/P2/font", PfontClone__8CFontBrxff); -INCLUDE_ASM("asm/nonmatchings/P2/font", CopyTo__8CFontBrxP8CFontBrx); +void CopyTo_CFontBrx(CFontBrx *self, CFontBrx *pfontDest) __asm__("CopyTo__8CFontBrxP8CFontBrx"); +void CopyTo_CFontBrx(CFontBrx *self, CFontBrx *pfontDest) +{ + self->CopyTo(pfontDest); + STRUCT_OFFSET(pfontDest, 0x50, int) = STRUCT_OFFSET(self, 0x50, int); + STRUCT_OFFSET(pfontDest, 0x54, int) = STRUCT_OFFSET(self, 0x54, int); + STRUCT_OFFSET(pfontDest, 0x58, int) = STRUCT_OFFSET(self, 0x58, int); + STRUCT_OFFSET(pfontDest, 0x60, uint64_t) = STRUCT_OFFSET(self, 0x60, uint64_t); + STRUCT_OFFSET(pfontDest, 0x68, int) = STRUCT_OFFSET(self, 0x68, int); + STRUCT_OFFSET(pfontDest, 0x6C, int) = STRUCT_OFFSET(self, 0x6C, int); + STRUCT_OFFSET(pfontDest, 0x70, int) = STRUCT_OFFSET(self, 0x70, int); + STRUCT_OFFSET(pfontDest, 0x74, int) = STRUCT_OFFSET(self, 0x74, int); + STRUCT_OFFSET(pfontDest, 0x78, int) = STRUCT_OFFSET(self, 0x78, int); + STRUCT_OFFSET(pfontDest, 0x7C, int) = STRUCT_OFFSET(self, 0x7C, int); + STRUCT_OFFSET(pfontDest, 0x80, int) = STRUCT_OFFSET(self, 0x80, int); +} bool CFontBrx::FValid(char ch) { return PglyffFromCh(ch) != 0; } -INCLUDE_ASM("asm/nonmatchings/P2/font", DxFromCh__8CFontBrxc); +float DxFromCh_CFontBrx(CFontBrx *self, char ch) __asm__("DxFromCh__8CFontBrxc"); +float DxFromCh_CFontBrx(CFontBrx *self, char ch) +{ + unsigned short *pglyff = (unsigned short *)self->PglyffFromCh(ch); + + if (pglyff != 0) + { + return (float)(int)(pglyff[3] + 1) * STRUCT_OFFSET(self, 0x44, float); + } + + return (float)STRUCT_OFFSET(self, 0x4, int) * STRUCT_OFFSET(self, 0x44, float); +} INCLUDE_ASM("asm/nonmatchings/P2/font", FEnsureLoaded__8CFontBrxP4GIFS); @@ -119,7 +145,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", Cch__9CRichText); INCLUDE_ASM("asm/nonmatchings/P2/font", Trim__9CRichTexti); -INCLUDE_ASM("asm/nonmatchings/P2/font", Dx__9CRichText); +extern "C" void Reset__9CRichText(CRichText *self); +extern "C" int ChNext__9CRichText(CRichText *self); + +extern "C" float Dx__9CRichText(CRichText *self) +{ + Reset__9CRichText(self); + + float dx = 0.0f; + int ch; + while ((ch = ChNext__9CRichText(self)) != 0) + { + CFont *pfont = STRUCT_OFFSET(self, 0x8, CFont *); + void *pv = STRUCT_OFFSET(pfont, 0x4c, void *); + dx += (*(float (**)(void *, int))((char *)pv + 0x1c))( + (char *)pfont + STRUCT_OFFSET(pv, 0x18, short), ch); + } + + return dx; +} INCLUDE_ASM("asm/nonmatchings/P2/font", ClineWrap__9CRichTextf); diff --git a/src/P2/game.c b/src/P2/game.c index d16bc0ca..44c127cd 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -154,22 +154,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", LsFromWid); INCLUDE_ASM("asm/nonmatchings/P2/game", GrflsFromWid__F3WID); -INCLUDE_ASM("asm/nonmatchings/P2/game", UnloadGame__Fv); -#ifdef SKIP_ASM -/** - * @todo 60.42% matched. - */ +extern "C" char D_00269984; +extern "C" char D_002623D8; + void UnloadGame() { + struct PACK { int v; } __attribute__((packed)); + InitGameState(g_pgsCur); - // unk_gs? = NULL; - // clr_8_bytes_1(&DAT_002623d8); + ((PACK *)&D_00269984)->v = 0; + clr_8_bytes_1(&D_002623D8); OnDifficultyGameLoad(&g_difficulty); g_grfcht = (GRFCHT)FCHT_None; g_worldlevelPrev = WORLDLEVEL_Nil; RetryGame(); -} -#endif // SKIP_ASM +} // SKIP_ASM void RetryGame() { diff --git a/src/P2/jt.c b/src/P2/jt.c index 5980af38..b1ee5839 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/jt", InitJt__FP2JT); @@ -18,7 +20,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", AdjustJtNewXp__FP2JTP2XPi); INCLUDE_ASM("asm/nonmatchings/P2/jt", AdjustJtDz__FP2JTiP2DZif); -INCLUDE_ASM("asm/nonmatchings/P2/jt", HandleJtGrfjtsc); +extern "C" void FUN_001d4c98(JT *pjt); + +extern "C" void HandleJtGrfjtsc(JT *pjt) +{ + int grfjtsc = STRUCT_OFFSET(pjt, 0x2254, int); + if (grfjtsc == 0) + return; + + if (grfjtsc & 0x8) + { + STRUCT_OFFSET(pjt, 0x2254, int) = grfjtsc & ~0x8; + STRUCT_OFFSET(pjt, 0x224C, int) = STRUCT_OFFSET(pjt, 0x2264, int); + } + + if (STRUCT_OFFSET(pjt, 0x2254, int) & 0x1) + SetJtJts(pjt, STRUCT_OFFSET(pjt, 0x2258, JTS), STRUCT_OFFSET(pjt, 0x225C, JTBS)); + + if (STRUCT_OFFSET(pjt, 0x2254, int) & 0x2) + SetJtJtcs(pjt, STRUCT_OFFSET(pjt, 0x2260, JTCS)); + + if (STRUCT_OFFSET(pjt, 0x2254, int) & 0x10) + FUN_001d4c98(pjt); +} INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtInternalXps__FP2JT); diff --git a/src/P2/rip.c b/src/P2/rip.c index 7a9f0f38..98488d7b 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -81,7 +81,17 @@ void TouchRip(RIP *prip, int fTouching) } } -INCLUDE_ASM("asm/nonmatchings/P2/rip", ForceRipFade__FP3RIPf); +void ForceRipFade(RIP *prip, float dtFade) +{ + float dtRemain = STRUCT_OFFSET(prip, 0x1c, float) - (g_clock.t - STRUCT_OFFSET(prip, 0x18, float)); + if (dtFade < dtRemain) + { + float ratio = dtRemain / STRUCT_OFFSET(prip, 0x1c, float); + float v = dtFade / ratio; + STRUCT_OFFSET(prip, 0x1c, float) = v; + STRUCT_OFFSET(prip, 0x18, float) = g_clock.t - (1.0f - ratio) * v; + } +} INCLUDE_ASM("asm/nonmatchings/P2/rip", FBounceRip__FP3RIPP2SOP6VECTORT2); diff --git a/src/P2/rog.c b/src/P2/rog.c index f0e13fab..006375c1 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -6,6 +6,7 @@ #include #include #include +#include extern SNIP s_asnipLoadRov[2]; @@ -145,7 +146,28 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", PostRobLoad__FP3ROB); INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRob__FP3ROBf); -INCLUDE_ASM("asm/nonmatchings/P2/rog", FUN_001a4d60); +extern int FUN_001e9970(); +extern BLOT g_unkblot0; + +extern "C" void FUN_001a4d60(ROB *prob) +{ + int fShow; + + fShow = 0; + if (STRUCT_OFFSET(prob, 0x650, int) == 2) + { + fShow = FUN_001e9970(); + } + + if (fShow) + { + g_unkblot0.pvtblot->pfnShowBlot(&g_unkblot0); + } + else + { + g_unkblot0.pvtblot->pfnHideBlot(&g_unkblot0); + } +} INCLUDE_ASM("asm/nonmatchings/P2/rog", RobsNextRob__FP3ROB); diff --git a/src/P2/screen.c b/src/P2/screen.c index 383cdeb3..cea7dafa 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -5,6 +5,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/screen", StartupScreen__Fv); @@ -392,7 +393,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", HideTotalsQMARK); INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawTotals__FP6TOTALS); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad6a8); +extern char D_0024CEE0[]; + +void FUN_001ad6a8(BLOT *pblot) +{ + CFont *pfont; + void *pv; + + PostBlotLoad(pblot); + pfont = FUN_0015c1c0(2); + pv = STRUCT_OFFSET(pfont, 0x4c, void *); + STRUCT_OFFSET(pblot, 0x4, int) = + (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( + (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), 1.0f, 1.0f); + ((VTBLOT *)pblot->pvtblot)->pfnSetBlotAchzDraw(pblot, D_0024CEE0); + STRUCT_OFFSET(pblot, 0x260, int) = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ad718); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 269886b3..a01594ce 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -3,6 +3,7 @@ #include #include #include +#include void InitSensor(SENSOR *psensor) { @@ -134,7 +135,28 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateBusyLasenSenseTimes__Fv); INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateLasen__FP5LASENf); -INCLUDE_ASM("asm/nonmatchings/P2/sensor", FreezeLasen__FP5LASENi); +extern "C" int D_002744D0; + +void FreezeLasen(LASEN *plasen, int fFreeze) +{ + FreezeSo(plasen, fFreeze); + + if (fFreeze) + { + if (STRUCT_OFFSET(plasen, 0xAF8, int)) + { + RemoveDlEntry((DL *)((char *)plasen->psw + 0x1ca8), plasen); + STRUCT_OFFSET(plasen, 0xAF8, int) = 0; + } + } + else + { + AppendDlEntry((DL *)((char *)plasen->psw + 0x1ca8), plasen); + STRUCT_OFFSET(plasen, 0xAF8, int) = 1; + } + + D_002744D0 = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/sensor", RenderLasenSelf__FP5LASENP2CMP2RO); diff --git a/src/P2/sound.c b/src/P2/sound.c index faed5682..4bd6730d 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include extern uchar D_00604790[]; // temp @@ -30,7 +32,18 @@ void SbpEnsureBank(SFXID sfxid) SbpEnsureBank(D_00245020[sfxid][0]); } -INCLUDE_ASM("asm/nonmatchings/P2/sound", NewSfx__FPP3SFX); +void NewSfx(SFX **ppsfx) +{ + *ppsfx = (SFX *)PvAllocSwClearImpl(sizeof(SFX)); + (*ppsfx)->sfxid = (SFXID)-1; + (*ppsfx)->sStart = 3000.0f; + (*ppsfx)->sFull = 300.0f; + (*ppsfx)->uVol = 1.0f; + (*ppsfx)->uPitch = 0.0f; + (*ppsfx)->pamb = NULL; + (*ppsfx)->lmRepeat.gMin = -1.0f; + (*ppsfx)->uDoppler = 0.0f; +} extern int D_006047B0[]; extern int D_006047D0[]; @@ -91,7 +104,31 @@ int FPauseForVag() INCLUDE_ASM("asm/nonmatchings/P2/sound", RefreshPambVolPan__FP3AMB); -INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001be8f8); +void RefreshPambVolPan(AMB *pamb); +void DropPamb(AMB **ppamb); + +extern "C" void FUN_001be8f8(ALO *palo, AMB **ppamb, float sStart, float sFull) +{ + AMB *pambLocal; + int fLocal = 0; + + if (ppamb == NULL) + { + fLocal = 1; + ppamb = &pambLocal; + } + + StartSound((SFXID)-2, ppamb, palo, NULL, sStart, sFull, 1.0f, 0.0f, 0.0f, NULL, NULL); + + if (*ppamb != NULL) + { + RefreshPambVolPan(*ppamb); + if (fLocal) + { + DropPamb(ppamb); + } + } +} extern u_int D_0027472C; int FVagPlaying() @@ -397,7 +434,20 @@ void SetMvgkRvol(int channel, MVGK mvgk, float rvol) MvgkUnknown1(mvgk); } -INCLUDE_ASM("asm/nonmatchings/P2/sound", MvgkUnknown2__Fv); +extern float D_00274758[10][4]; +extern "C" void MvgkUnknown3(int fMute); +extern "C" void MvgkUnknown4(int mode); +void MvgkUnknown2() +{ + CopyAb(D_00274838, D_00274758, 0xB0); + SetMvgkUvol(1.0f); + for (int i = 0; i < 4; ++i) + { + MvgkUnknown1((MVGK)i); + } + MvgkUnknown3(STRUCT_OFFSET(g_pgsCur, 0x19EC, int) & 0x80); + MvgkUnknown4(STRUCT_OFFSET(g_pgsCur, 0x19EC, int) & 0x40); +} extern "C" void MvgkUnknown3(int fMute) { diff --git a/src/P2/step.c b/src/P2/step.c index 96a72002..d5c24ed0 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -68,7 +68,18 @@ CT CtTorqueStep(STEP *pstep) return CT_Locked; } -INCLUDE_ASM("asm/nonmatchings/P2/step", PropagateStepForce__FP4STEPiP2XPiP2DZP2FX); +void PropagateSoForce(SO *psoRoot, GRFSG grfsg, XP *pxp, int ixpd, DZ *pdz, FX *afx); + +void PropagateStepForce(STEP *pstep, GRFSG grfsg, XP *pxp, int ixpd, DZ *pdz, FX *afx) +{ + CT ctSav; + + ctSav = STRUCT_OFFSET(pstep, 0x470, CT); + STRUCT_OFFSET(pstep, 0x470, CT) = + (*(CT (**)(STEP *))((uint8_t *)pstep->pvtlo + 0x164))(pstep); + PropagateSoForce(pstep, grfsg, pxp, ixpd, pdz, afx); + STRUCT_OFFSET(pstep, 0x470, CT) = ctSav; +} INCLUDE_ASM("asm/nonmatchings/P2/step", RotateStepToMat__FP4STEPP7MATRIX3); From 4ddec33d958c80007292666358c6576ce84829ae Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 21:39:15 +0200 Subject: [PATCH 117/134] Match 14 wave-7 functions (sound/cm/font/screen/emitter/puffer/spliceobj/jlo cross-unit) game.h: reload_post_death is a raw symbol (extern C). Co-Authored-By: Claude Fable 5 --- include/game.h | 2 +- src/P2/cm.c | 14 +++++++++++- src/P2/crusher.c | 26 ++++++++++++++++++++++- src/P2/emitter.c | 1 + src/P2/font.c | 17 ++++++++++++++- src/P2/jlo.c | 53 ++++++++++++++++++++++++++++++++++++++++++++-- src/P2/mb.c | 1 + src/P2/murray.c | 39 ++++++++++++++++++++++++++++++++-- src/P2/puffer.c | 18 +++++++++++++++- src/P2/rip.c | 1 + src/P2/screen.c | 40 ++++++++++++++++++++++++++++++++-- src/P2/sound.c | 28 ++++++++++++++++++++++-- src/P2/spliceobj.c | 9 +++++++- src/P2/stephide.c | 19 ++++++++++++++++- src/P2/suv.c | 1 + 15 files changed, 254 insertions(+), 15 deletions(-) diff --git a/include/game.h b/include/game.h index 96f61730..57aeaedb 100644 --- a/include/game.h +++ b/include/game.h @@ -460,7 +460,7 @@ int CcharmMost(); /** * @brief Reloads the game state after the player dies. */ -void reload_post_death(); +extern "C" void reload_post_death(); // todo these should be somewhere else? extern GS g_gsCur; diff --git a/src/P2/cm.c b/src/P2/cm.c index a61b770a..c7e1d486 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -236,7 +236,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertWorldToCylindVelocity); INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCylindToWorldVelocity); -INCLUDE_ASM("asm/nonmatchings/P2/cm", ResetCmLookAtSmooth); +extern "C" void ConvertCylindToWorldVelocity(void *a, void *b, void *c, float f0, float f1, float f2); +extern "C" void ConvertWorldToCylindVelocity(void *a, void *b, void *c, void *d, void *e, void *f); + +extern "C" void ResetCmLookAtSmooth(CM *pcm, void *pv) +{ + VECTOR4 vTmp; + + ConvertCylindToWorldVelocity(&STRUCT_OFFSET(pcm, 0x2d0, int), &STRUCT_OFFSET(pcm, 0x40, int), &vTmp, + STRUCT_OFFSET(pcm, 0x2b0, float), STRUCT_OFFSET(pcm, 0x2b4, float), STRUCT_OFFSET(pcm, 0x2b8, float)); + ConvertWorldToCylindVelocity(pv, &STRUCT_OFFSET(pcm, 0x40, int), &vTmp, + &STRUCT_OFFSET(pcm, 0x2b0, int), &STRUCT_OFFSET(pcm, 0x2b4, int), &STRUCT_OFFSET(pcm, 0x2b8, int)); + STRUCT_OFFSET(pcm, 0x2d0, qword) = *(qword *)pv; +} INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmLookAtSmooth); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index a946db83..81d91426 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -1,4 +1,6 @@ #include +#include +#include /** * @todo Rename. @@ -67,7 +69,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c2f0); INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c5e8); -INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c668); +// Shared: extern void *D_0027C00C; and a fwd decl of FUN_0014c5e8. +// Needs (GetSmaGoal/GetSmaCur/SetSmaGoal, SMA) and (OID) which are +// NOT transitively included by crusher.c yet. +extern void *D_0027C00C; +extern "C" void FUN_0014c5e8(void *p); + +extern "C" void FUN_0014c668(void *pv, int tnt) +{ + if (tnt == 1) + { + OID oidGoal; + OID oidCur; + + GetSmaGoal(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), &oidGoal); + GetSmaCur(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), &oidCur); + + if (oidGoal != (OID)0x3fe && oidCur != (OID)0x3fe) + { + SetSmaGoal(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), (OID)0x3ff); + FUN_0014c5e8(D_0027C00C); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 02550eb1..27f92b0a 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -8,6 +8,7 @@ #include #include #include +#include extern float DAT_0024a124; diff --git a/src/P2/font.c b/src/P2/font.c index 3f8ecbc7..ac5cc46f 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -1,6 +1,7 @@ #include #include #include +#include void StartupFont() { @@ -65,7 +66,21 @@ INCLUDE_ASM("asm/nonmatchings/P2/font", PushScaling__5CFontff); INCLUDE_ASM("asm/nonmatchings/P2/font", PopScaling__5CFont); -INCLUDE_ASM("asm/nonmatchings/P2/font", PfontClone__8CFontBrxff); +extern void *D_0024A220; +extern void *__builtin_new(unsigned int cb); + +void CopyTo_CFontBrx(CFontBrx *self, CFontBrx *pfontDest) __asm__("CopyTo__8CFontBrxP8CFontBrx"); + +CFontBrx *PfontClone_CFontBrx(CFontBrx *self, float rxScale, float ryScale) __asm__("PfontClone__8CFontBrxff"); +CFontBrx *PfontClone_CFontBrx(CFontBrx *self, float rxScale, float ryScale) +{ + CFontBrx *pfontNew = (CFontBrx *)__builtin_new(0x88); + STRUCT_OFFSET(pfontNew, 0x4c, void *) = &D_0024A220; + CopyTo_CFontBrx(self, pfontNew); + STRUCT_OFFSET(pfontNew, 0x44, float) = STRUCT_OFFSET(pfontNew, 0x44, float) * rxScale; + STRUCT_OFFSET(pfontNew, 0x48, float) = STRUCT_OFFSET(pfontNew, 0x48, float) * ryScale; + return pfontNew; +} void CopyTo_CFontBrx(CFontBrx *self, CFontBrx *pfontDest) __asm__("CopyTo__8CFontBrxP8CFontBrx"); void CopyTo_CFontBrx(CFontBrx *self, CFontBrx *pfontDest) diff --git a/src/P2/jlo.c b/src/P2/jlo.c index c8b89a56..dd92c9c7 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include extern JLO *g_pjloCur; extern VECTOR g_normalZ; // TODO: This should be elsewhere. @@ -61,11 +63,58 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", UpdateJlo__FP3JLOf); INCLUDE_ASM("asm/nonmatchings/P2/jlo", JlosNextJlo__FP3JLO); -INCLUDE_ASM("asm/nonmatchings/P2/jlo", SetJloJlovol__FP3JLOP6JLOVOL); +EXC *PexcSetExcitement(int gexc); +void UnsetExcitementHyst(EXC *pexc); + +void SetJloJlovol(JLO *pjlo, JLOVOL *pjlovol) +{ + if (pjlovol == STRUCT_OFFSET(pjlo, 0x558, JLOVOL *)) + return; + + void *p3 = NULL; + if (pjlovol != NULL) + p3 = STRUCT_OFFSET(pjlovol, 0x7AC, void *); + + if (p3 != STRUCT_OFFSET(pjlo, 0x5D0, void *)) + { + STRUCT_OFFSET(pjlo, 0x5D0, void *) = p3; + STRUCT_OFFSET(pjlo, 0x5D4, int) = 3; + } + + STRUCT_OFFSET(pjlo, 0x558, JLOVOL *) = pjlovol; + + if (p3 != NULL) + { + RWM *prwm = STRUCT_OFFSET(pjlo, 0x570, RWM *); + STRUCT_OFFSET(prwm, 0x44, int) = STRUCT_OFFSET(STRUCT_OFFSET(pjlovol, 0x7AC, void *), 0x318, int); + ReloadRwm(STRUCT_OFFSET(pjlo, 0x570, RWM *)); + if (STRUCT_OFFSET(pjlo, 0x5BC, EXC *) == NULL) + STRUCT_OFFSET(pjlo, 0x5BC, EXC *) = PexcSetExcitement(0x6B); + } + else + { + if (STRUCT_OFFSET(pjlo, 0x5BC, EXC *) != NULL) + { + UnsetExcitementHyst(STRUCT_OFFSET(pjlo, 0x5BC, EXC *)); + STRUCT_OFFSET(pjlo, 0x5BC, EXC *) = NULL; + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/jlo", FireJlo__FP3JLO); -INCLUDE_ASM("asm/nonmatchings/P2/jlo", LandJlo__FP3JLO); +void LandJlo(JLO *pjlo) +{ + extern VECTOR D_00248D30; + VECTOR pos; + + SetSoConstraints(pjlo, CT_Locked, NULL, CT_Locked, NULL); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)pjlo + 0x90))(pjlo, &D_00248D30); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)pjlo + 0x94))(pjlo, &D_00248D30); + GetPntPos(STRUCT_OFFSET(STRUCT_OFFSET(pjlo, 0x558, void *), 0x7A4, PNT *), &pos); + pos.z += STRUCT_OFFSET(pjlo, 0x56C, float); + (*(void (**)(ALO *, VECTOR *))(*(uint8_t **)pjlo + 0x84))(pjlo, &pos); +} INCLUDE_ASM("asm/nonmatchings/P2/jlo", JumpJlo__FP3JLO); diff --git a/src/P2/mb.c b/src/P2/mb.c index a1e66f54..5d4a72a3 100644 --- a/src/P2/mb.c +++ b/src/P2/mb.c @@ -1,5 +1,6 @@ #include #include +#include extern SNIP s_asnipLoadMbg[2]; diff --git a/src/P2/murray.c b/src/P2/murray.c index 29b2eb95..1e597754 100644 --- a/src/P2/murray.c +++ b/src/P2/murray.c @@ -1,4 +1,7 @@ #include +#include +#include +#include void InitMurray(MURRAY *pmurray) { @@ -28,9 +31,41 @@ INCLUDE_ASM("asm/nonmatchings/P2/murray", UpdateMurrayGoal__FP6MURRAYi); INCLUDE_ASM("asm/nonmatchings/P2/murray", UpdateMurraySgs__FP6MURRAY); -INCLUDE_ASM("asm/nonmatchings/P2/murray", FUN_001903f0); +extern "C" int FUN_001c9a48(STEPGUARD *pstepguard, void *pv); -INCLUDE_ASM("asm/nonmatchings/P2/murray", FUN_00190450); +extern "C" int FUN_001903f0(MURRAY *pmurray, void *pv) +{ + if ((g_grfcht & FCHT_Invulnerability) || IsSwHandsOff(STRUCT_OFFSET(pmurray, 0x14, SW *))) + { + return 1; + } + return FUN_001c9a48(pmurray, pv); +} + +extern "C" int FUN_00190450(MURRAY *pmurray, WKR *pwkr) +{ + LO **ppvtable = (LO **)STRUCT_OFFSET(pmurray, 0x0, void *); + int (*pfn)(MURRAY *, LO *) = (int (*)(MURRAY *, LO *))STRUCT_OFFSET(ppvtable, 0x13c, void *); + + if (pfn(pmurray, pwkr->ploSource)) + { + return 0; + } + + STRUCT_OFFSET(pmurray, 0xc34, int) = 0; + STRUCT_OFFSET(pmurray, 0xc30, LO *) = pwkr->ploSource; + + if (pwkr->ploSource == NULL && pwkr->ploTarget != NULL) + { + RWM *prwm = STRUCT_OFFSET(STRUCT_OFFSET(pmurray, 0xc2c, SO *), 0x618, RWM *); + if (FIsRwmAmmo(prwm, (SO *)pwkr->ploTarget)) + { + STRUCT_OFFSET(pmurray, 0xc34, int) = 1; + } + } + + return FTakeStepguardDamage(pmurray, (ZPR *)pwkr); +} INCLUDE_ASM("asm/nonmatchings/P2/murray", FAbsorbMurrayWkr__FP6MURRAYP3WKR); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 231ed807..16e7363e 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -106,7 +106,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001982a0); INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffcGoal__FP5PUFFCi); -INCLUDE_ASM("asm/nonmatchings/P2/puffer", OnPuffcExitingSgs__FP5PUFFC3SGS); +extern "C" void FUN_00197a08(void *pv1, void *pv2); + +void OnPuffcExitingSgs(PUFFC *ppuffc, SGS sgsNext) +{ + if (STRUCT_OFFSET(ppuffc, 0x724, int) == SGS_Stun) + { + VU_VECTOR vec; + + FUN_00197a08(PpoCur(), ppuffc); + + vec = STRUCT_OFFSET(ppuffc, 0x150, VU_VECTOR); + STRUCT_OFFSET((&vec), 0x8, int) = 0; + (*(void (**)(PUFFC *, VU_VECTOR *))((uint8_t *)STRUCT_OFFSET(ppuffc, 0x0, void *) + 0x90))(ppuffc, &vec); + } + + OnStepguardExitingSgs((STEPGUARD *)ppuffc, sgsNext); +} void OnPuffcEnteringSgs(PUFFC *ppuffc, SGS sgsPrev, ASEG *pasegOverride) { diff --git a/src/P2/rip.c b/src/P2/rip.c index 98488d7b..1755a776 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -4,6 +4,7 @@ #include #include #include +#include RIPG *PripgNew(SW *psw, RIPGT ripgt) { diff --git a/src/P2/screen.c b/src/P2/screen.c index cea7dafa..b717d82e 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -285,7 +285,25 @@ void FUN_001ac060(TIMER *ptimer) INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac0e8); -INCLUDE_ASM("asm/nonmatchings/P2/screen", PostNoteLoad__FP4NOTE); +extern CFont *D_002743D0; + +void PostNoteLoad(NOTE *pnote) +{ + CFont *pfont; + void *pv; + + PostBlotLoad(pnote); + pfont = STRUCT_OFFSET(pnote, 0x4, CFont *); + pv = STRUCT_OFFSET(pfont, 0x4c, void *); + STRUCT_OFFSET(pnote, 0x4, int) = + (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( + (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), 1.25f, 1.25f); + if (FUN_0015c188(2)) + { + STRUCT_OFFSET(pnote, 0x210, CFont **) = &D_002743D0; + *STRUCT_OFFSET(pnote, 0x210, CFont **) = FUN_0015c1c0(2); + } +} INCLUDE_ASM("asm/nonmatchings/P2/screen", SetNoteAchzDraw__FP4NOTEPc); @@ -489,7 +507,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae510); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae5e0); -INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae758); +extern "C" char FUN_001aea08(void); +extern float D_002744AC; + +extern "C" void FUN_001ae758(BLOT *pblot) +{ + char achz[2]; + + PostBlotLoad(pblot); + SetBlotDtAppear(pblot, 0.25f); + SetBlotDtDisappear(pblot, 0.25f); + SetBlotDtVisible(pblot, 0.0f); + pblot->pfont = FUN_0015c1c0(1); + SetBlotFontScale(pblot, D_002744AC); + + achz[0] = FUN_001aea08(); + achz[1] = 0; + ((void (*)(BLOT *, char *))((VTBLOT *)pblot->pvtblot)->pfnSetBlotAchzDraw)(pblot, achz); + pblot->achzDraw[0] = 0; +} void FUN_001ae7f8(CTR *pctr, BLOTS blots) { diff --git a/src/P2/sound.c b/src/P2/sound.c index 4bd6730d..2e9d1051 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -5,6 +5,7 @@ #include #include #include +#include extern uchar D_00604790[]; // temp @@ -102,7 +103,17 @@ int FPauseForVag() return 0; } -INCLUDE_ASM("asm/nonmatchings/P2/sound", RefreshPambVolPan__FP3AMB); +void RefreshPambVolPan(AMB *pamb) +{ + int vol = (int)(STRUCT_OFFSET(pamb, 0x50, float) * 1024.0f); + float pan = STRUCT_OFFSET(pamb, 0x54, float); + int panOut; + if (0.0f < pan) + panOut = (int)((pan + 2.0f) * 179.5f) - 359; + else + panOut = (int)((pan + 2.0f) * 179.5f); + snd_SetSoundVolPan(pamb->sfxh, vol, panOut); +} void RefreshPambVolPan(AMB *pamb); void DropPamb(AMB **ppamb); @@ -480,7 +491,20 @@ void KillSoundSystem() INCLUDE_ASM("asm/nonmatchings/P2/sound", KillSounds__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/sound", PushSwReverb__FP2SW7REVERBKi); +enum REVERBK {}; +extern int D_00274808[]; + +void PushSwReverb(SW *psw, REVERBK reverb, int depth) +{ + if ((unsigned)STRUCT_OFFSET(psw, 0x2348, int) < 4) + { + snd_SetReverbType(2, D_00274808[reverb]); + snd_SetReverbDepth(2, depth, depth); + STRUCT_OFFSET((char *)psw + (STRUCT_OFFSET(psw, 0x2348, int) << 3), 0x2328, int) = reverb; + STRUCT_OFFSET((char *)psw + (STRUCT_OFFSET(psw, 0x2348, int) << 3), 0x232c, int) = depth; + STRUCT_OFFSET(psw, 0x2348, int) = STRUCT_OFFSET(psw, 0x2348, int) + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/sound", PopSwReverb__FP2SW); diff --git a/src/P2/spliceobj.c b/src/P2/spliceobj.c index 03831fbe..55cf4570 100644 --- a/src/P2/spliceobj.c +++ b/src/P2/spliceobj.c @@ -37,6 +37,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefSetOption__FP5BASICiP4CRef); INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefAddOption__FP5BASICiP4CRef); -INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefEnsureOption__FP5BASICiP4CRef); +CRef RefEnsureOption(BASIC *pbasic, int optid, CRef *prefValue) +{ + EnsureBasicSidebag(pbasic); + if (pbasic->psidebag->FFindBinding(optid, NULL)) + return pbasic->psidebag->RefSetBinding(optid, prefValue); + else + return pbasic->psidebag->RefAddBinding(optid, prefValue); +} INCLUDE_ASM("asm/nonmatchings/P2/spliceobj", RefSetArgsFromSplice__FiP4CRefP4OTYPe); diff --git a/src/P2/stephide.c b/src/P2/stephide.c index a6721bad..c8209d83 100644 --- a/src/P2/stephide.c +++ b/src/P2/stephide.c @@ -1,4 +1,5 @@ #include +#include INCLUDE_ASM("asm/nonmatchings/P2/stephide", JtbsChooseJtHide__FP2JTP2LOP4JTHK); @@ -24,7 +25,23 @@ float GMeasureJumpRail(MJR *pmjr, float u) return gInteg; } -INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001cea58); +struct HPNT; +extern void GetHpntClosestHidePos(HPNT *phpnt, VECTOR *ppos, float *pf); + +extern "C" float FUN_001cea58(MJH *pmjh) +{ + VECTOR posTarget; + float gInteg; + + GetHpntClosestHidePos(STRUCT_OFFSET(pmjh, 0x4, HPNT *), &posTarget, 0); + + MeasureJtJumpToTarget(STRUCT_OFFSET(pmjh, 0x0, JT *), + (VECTOR *)((uint8_t *)pmjh + 0x10), + STRUCT_OFFSET(STRUCT_OFFSET(pmjh, 0x4, HPNT *), 0x18, ALO *), + &posTarget, 0, 0, &gInteg, 0, 0); + + return gInteg; +} struct HSHAPE; extern void GetHshapeHidePos(HSHAPE *phshape, float s, VECTOR *ppos, float *pf); diff --git a/src/P2/suv.c b/src/P2/suv.c index a9b58359..f69193d3 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/suv", InitSuv__FP3SUV); From e02bf9b8f1805647afdd76224a7f1bafdd6175f2 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 22:09:18 +0200 Subject: [PATCH 118/134] Match 25 wave-8 functions (alo/sound/sm/aseg/fly/gs/light/po/sw/tank/turret/vifs/wr etc.) Co-Authored-By: Claude Fable 5 --- src/P2/alo.c | 25 ++++++++++- src/P2/aseg.c | 22 +++++++++- src/P2/asega.c | 1 + src/P2/chkpnt.c | 21 ++++++++- src/P2/crv.c | 28 +++++++++++- src/P2/fader.c | 23 +++++++++- src/P2/fly.c | 20 ++++++++- src/P2/freeze.c | 23 +++++++++- src/P2/gifs.c | 16 ++++++- src/P2/gs.c | 15 ++++++- src/P2/light.c | 21 +-------- src/P2/mb.c | 3 ++ src/P2/po.c | 38 ++++++++++++++++- src/P2/rumble.c | 19 ++++++++- src/P2/rwm.c | 32 +++++++++++++- src/P2/sensor.c | 35 --------------- src/P2/shdanim.c | 1 + src/P2/sm.c | 17 +++++++- src/P2/smartguard.c | 32 +++++++++++++- src/P2/so.c | 26 +++++++++++- src/P2/sound.c | 101 +++++++++++++++++++++++++++++++++++++++++--- src/P2/stepcane.c | 18 +++++++- src/P2/tank.c | 33 ++++++++++++++- src/P2/turret.c | 1 + src/P2/ui.c | 2 + 25 files changed, 493 insertions(+), 80 deletions(-) diff --git a/src/P2/alo.c b/src/P2/alo.c index 8bd7083a..307ec8d5 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -597,7 +597,18 @@ void SetAloPositionSmoothMaxAccel(ALO *palo, float r) SetAloPositionSmoothDetail(palo, &smpa); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloPositionSmoothDetail__FP3ALOP4SMPA); +extern SMPA D_00260EB0; +void SetAloPositionSmoothDetail(ALO *palo, SMPA *psmpa) +{ + SMPA *&psmpaDst = STRUCT_OFFSET(palo, 0x21c, SMPA *); // palo->psmpaPos (default &D_00260EB0) + + if (psmpaDst == &D_00260EB0) + { + psmpaDst = (SMPA *)PvAllocSwImpl(0x10); + } + + *psmpaDst = *psmpa; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSmooth__FP3ALOf); @@ -669,7 +680,17 @@ extern "C" void FUN_0012a4e8(ALO *palo, int n) ResortAloActList(palo); } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloLookAt__FP3ALO3ACK); +void SetAloLookAt(ALO *palo, ACK ack) +{ + EnsureAloActla(palo); + + if (ack == ACK_Smooth) + { + ack = ACK_SmoothNoLock; + } + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x200, void *), 0x11, char) = ack; + ((void (*)(ALO *))STRUCT_OFFSET(palo->pvtlo, 0xbc, void *))(palo); +} void SetAloLookAtIgnore(ALO *palo, float sIgnore) { diff --git a/src/P2/aseg.c b/src/P2/aseg.c index 9910533e..801e5930 100644 --- a/src/P2/aseg.c +++ b/src/P2/aseg.c @@ -1,5 +1,6 @@ #include #include +#include void StartupAseg() { @@ -19,7 +20,26 @@ void CloneAseg(ASEG *paseg, LO *ploBase) INCLUDE_ASM("asm/nonmatchings/P2/aseg", PostAsegLoad__FP4ASEG); -INCLUDE_ASM("asm/nonmatchings/P2/aseg", PostAsegLoadCallback__FP4ASEG5MSGIDPv); +void PostAsegLoadCallback(ASEG *paseg, MSGID msgid, void *pvData) +{ + ASEGA *pasega; + LO *plo; + + if (STRUCT_OFFSET(paseg, 0x40, OID) != OID_Nil) + { + plo = PloFindSwObject(paseg->psw, 4, STRUCT_OFFSET(paseg, 0x40, OID), paseg); + if (!plo) + { + plo = PloFindSwObject(paseg->psw, 0x104, STRUCT_OFFSET(paseg, 0x40, OID), paseg); + } + } + else + { + plo = NULL; + } + + ApplyAseg(paseg, (ALO *)plo, 0.0f, 1.0f, 0, &pasega); +} INCLUDE_ASM("asm/nonmatchings/P2/aseg", ApplyAsegOvr__FP4ASEGP3ALOiP3OVRffiPP5ASEGA); diff --git a/src/P2/asega.c b/src/P2/asega.c index 26813d05..571bbb9c 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -1,5 +1,6 @@ #include #include +#include extern char D_002197B8[]; diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index e8fbb768..93861ff4 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -6,6 +6,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ResetChkmgrCheckpoints__FP6CHKMGR); #ifdef SKIP_ASM @@ -40,7 +41,25 @@ void ResetChkmgrCheckpoints(CHKMGR *pchkmgr) INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", SaveChkmgrCheckpoint__FP6CHKMGR3OIDT1); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", ReturnChkmgrToCheckpoint__FP6CHKMGR); +void ReturnChkmgrToCheckpoint(CHKMGR *pchkmgr) +{ + TRANS trans; + trans.fSet = 1; + trans.pchzWorld = (LevelTableStruct *)g_transition.m_achzWorldCur; + if (STRUCT_OFFSET(pchkmgr, 0x42c, int)) + { + trans.oidWarp = (OID)STRUCT_OFFSET(pchkmgr, 0x424, int); + trans.oidWarpContet = (OID)STRUCT_OFFSET(pchkmgr, 0x428, int); + trans.grftrans = 0x11; + } + else + { + trans.oidWarp = (OID)-1; + trans.oidWarpContet = (OID)-1; + trans.grftrans = 0x10; + } + ActivateWipe(&g_wipe, &trans, (WIPEK)1); +} void RestoreChkmgrFromCheckpoint(CHKMGR *pchkmgr) { diff --git a/src/P2/crv.c b/src/P2/crv.c index 1a0f1bc8..8f57fe63 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -37,7 +37,33 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FindAposClosestPointSegment__FP6VECTORP6C INCLUDE_ASM("asm/nonmatchings/P2/crv", ConvertApos__FiP6VECTORP7MATRIX4T2); -INCLUDE_ASM("asm/nonmatchings/P2/crv", PcrvNew__F4CRVK); +extern "C" char D_002176D0[]; +extern "C" char D_00217708[]; + +CRV *PcrvNew(CRVK crvk) +{ + CRV *pcrv; + + switch (crvk) + { + case CRVK_Linear: + pcrv = (CRV *)PvAllocSwClearImpl(0x1C); + pcrv->unknown = (undefined4)&D_002176D0; + break; + case CRVK_Cubic: + pcrv = (CRV *)PvAllocSwClearImpl(0x1D0); + pcrv->unknown = (undefined4)&D_00217708; + break; + default: + pcrv = NULL; + break; + } + + if (pcrv != NULL) + pcrv->crvk = crvk; + + return pcrv; +} float SFromCrvU(CRV *pcrv, float u) { diff --git a/src/P2/fader.c b/src/P2/fader.c index d066a416..20dd4556 100644 --- a/src/P2/fader.c +++ b/src/P2/fader.c @@ -1,7 +1,28 @@ #include +#include +#include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/fader", UpdateFader__FP5FADERf); -INCLUDE_ASM("asm/nonmatchings/P2/fader", PfaderNew__FP3ALO); +FADER *PfaderNew(ALO *palo) +{ + FADER *pfader; + + pfader = (FADER *)PvAllocSlotheapClearImpl(&STRUCT_OFFSET(g_psw, 0x1C18, SLOTHEAP)); + STRUCT_OFFSET(pfader, 0x0, ALO *) = palo; + + if (STRUCT_OFFSET(palo, 0x294, int) != 0) + { + AppendDlEntry(&STRUCT_OFFSET(g_psw, 0x1C30, DL), pfader); + } + else + { + AppendDlEntry(&STRUCT_OFFSET(g_psw, 0x1C24, DL), pfader); + } + + return pfader; +} INCLUDE_ASM("asm/nonmatchings/P2/fader", RemoveFader__FP5FADER); diff --git a/src/P2/fly.c b/src/P2/fly.c index f9ce9f6d..f196b2e0 100644 --- a/src/P2/fly.c +++ b/src/P2/fly.c @@ -8,7 +8,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/fly", CloneFly__FP3FLYT0); INCLUDE_ASM("asm/nonmatchings/P2/fly", FreezeFly__FP3FLYi); -INCLUDE_ASM("asm/nonmatchings/P2/fly", PostFlyLoad__FP3FLY); +void PostFlyLoad(FLY *pfly) +{ + extern SNIP D_002621E0; + + SnipAloObjects((ALO *)pfly, 2, &D_002621E0); + + if (STRUCT_OFFSET(pfly, 0x550, int) == 1) + { + STRUCT_OFFSET(pfly, 0x688, float) = g_clock.t + + GRandInRange(STRUCT_OFFSET(pfly, 0x63c, float), STRUCT_OFFSET(pfly, 0x640, float)); + STRUCT_OFFSET(pfly, 0x680, float) = g_clock.t + + GRandInRange(STRUCT_OFFSET(pfly, 0x670, float), STRUCT_OFFSET(pfly, 0x674, float)); + } + + SetFlyFlys(pfly, (FLYS)STRUCT_OFFSET(pfly, 0x560, int)); + PostAloLoad((ALO *)pfly); + STRUCT_OFFSET(pfly, 0x64c, float) = + STRUCT_OFFSET(pfly, 0x3cc, float) + STRUCT_OFFSET(pfly, 0x3cc, float); +} INCLUDE_ASM("asm/nonmatchings/P2/fly", PresetFlyAccel__FP3FLYf); diff --git a/src/P2/freeze.c b/src/P2/freeze.c index 6bd4b84c..ca42af90 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -40,7 +40,28 @@ void MergeSwGroup(SW *psw, MRG *pmrg) } } -INCLUDE_ASM("asm/nonmatchings/P2/freeze", AddSwMergeGroup__FP2SWP3MRG); +void AddSwMergeGroup(SW *psw, MRG *pmrg) +{ + int i; + + if (pmrg->cpalo < 2) + return; + + for (i = 0; i < pmrg->cpalo; i++) + { + ALO *palo = pmrg->apalo[i]; + int cpmrg = STRUCT_OFFSET(palo, 0x6c, int); + + if ((unsigned int)cpmrg < 4) + { + MRG **apmrg = &STRUCT_OFFSET(palo, 0x70, MRG *); + apmrg[cpmrg] = pmrg; + STRUCT_OFFSET(palo, 0x6c, int) = cpmrg + 1; + } + } + + MergeSwGroup(psw, pmrg); +} INCLUDE_ASM("asm/nonmatchings/P2/freeze", RemoveFromArray__FPiPPvPv); diff --git a/src/P2/gifs.c b/src/P2/gifs.c index 8115be35..8ca92dc3 100644 --- a/src/P2/gifs.c +++ b/src/P2/gifs.c @@ -73,7 +73,15 @@ void GIFS::PackXYZF(int x, int y, int z, int fog) pqw->an[3] = (fog & 0xff) << 4; } -INCLUDE_ASM("asm/nonmatchings/P2/gifs", PackXYZFNoKick__4GIFSiiii); +void GIFS::PackXYZFNoKick(int x, int y, int z, int fog) +{ + CheckReg(1, 4); + QW *pqw = ((QW *)m_pb)++; + pqw->an[0] = x; + pqw->an[1] = y; + pqw->an[2] = (z & 0xffffff) << 4; + pqw->an[3] = ((fog & 0xff) << 4) | 0x8000; +} void GIFS::PackAD(long int a, long int d) { @@ -97,7 +105,11 @@ void GIFS::ListUV(int u, int v) *((long *)m_pb)++ = u | (v << 16); } -INCLUDE_ASM("asm/nonmatchings/P2/gifs", ListXYZF__4GIFSiiii); +void GIFS::ListXYZF(int x, int y, int z, int fog) +{ + CheckReg(0, 4); + *((long *)m_pb)++ = x | (y << 16) | ((long)(z & 0xffffff) << 32) | ((long)fog << 56); +} JUNK_ADDIU(80); diff --git a/src/P2/gs.c b/src/P2/gs.c index cd4736ea..2fe719e9 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -24,7 +24,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", GS_Interrupt__Fi); INCLUDE_ASM("asm/nonmatchings/P2/gs", ResetGs__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/gs", SendDmaSyncGsFinish__FP10sceDmaChanP2QW); +extern "C" int func_00202120(); +extern "C" void func_00202058(int); +extern int D_002BE464; +extern int D_002BE468; + +void SendDmaSyncGsFinish(sceDmaChan *pdc, QW *pqw) +{ + D_002BE468 = 1; + *(volatile uint64_t *)0x12001000 |= 2; + func_00202058(func_00202120() & ~0x200); + FlushCache(0); + sceDmaSend(pdc, pqw); + WaitSema(D_002BE464); +} INCLUDE_ASM("asm/nonmatchings/P2/gs", BuildClearGifs__FP2QWG4RGBAi); diff --git a/src/P2/light.c b/src/P2/light.c index 3ed34495..802b789a 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -43,26 +43,7 @@ void OnLightRemove(LIGHT *plight) /** * @todo 98.75% match. */ -INCLUDE_ASM("asm/nonmatchings/P2/light", CloneLight__FP5LIGHTT0); -#ifdef SKIP_ASM -void CloneLight(LIGHT *plight, LIGHT *plightBase) -{ - int fDynamic = FIsLoInWorld(plight) && (STRUCT_OFFSET(plight, 0x304, int) != STRUCT_OFFSET(plightBase, 0x304, int)); - if (fDynamic) - { - RemoveLightFromSw(plight); - } - - DLE dleLight = STRUCT_OFFSET(plightBase, 0x410, DLE); - CloneAlo(plight, plightBase); - STRUCT_OFFSET(plight, 0x410, DLE) = dleLight; - - if (fDynamic) - { - AddLightToSw(plight); - } -} -#endif // SKIP_ASM +INCLUDE_ASM("asm/nonmatchings/P2/light", CloneLight__FP5LIGHTT0); // SKIP_ASM void FitLinearFunction(float x0, float y0, float x1, float y1, float *pdu, float *pru) { diff --git a/src/P2/mb.c b/src/P2/mb.c index 5d4a72a3..91166fa5 100644 --- a/src/P2/mb.c +++ b/src/P2/mb.c @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include extern SNIP s_asnipLoadMbg[2]; diff --git a/src/P2/po.c b/src/P2/po.c index a5207f63..9feb986b 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -152,7 +152,23 @@ PO *PpoCur() return g_appo[g_ippoCur]; } -INCLUDE_ASM("asm/nonmatchings/P2/po", PpoStart__Fv); +extern int D_00269C90; + +PO *PpoStart(void) +{ + PO *ppo = PpoCur(); + + if (ppo == NULL) + { + if (g_pjt != NULL && STRUCT_OFFSET(g_pjt, 0x550, int) != 0) + ppo = (PO *)g_pjt; + + if (ppo == NULL && D_00269C90 != 0) + ppo = g_appo[0]; + } + + return ppo; +} INCLUDE_ASM("asm/nonmatchings/P2/po", _IppoFindPo__FP2PO); @@ -187,7 +203,25 @@ void AddPoToList(PO *ppo) } } -INCLUDE_ASM("asm/nonmatchings/P2/po", RemovePoFromList__FP2PO); +extern "C" void *memmove(void *dst, const void *src, int cb); + +void RemovePoFromList(PO *ppo) +{ + int i = _IppoFindPo(ppo); + + if (i < 0) + return; + + if (i == g_ippoCur) + SwitchToIppo(-1); + + memmove(&g_appo[i], &g_appo[i + 1], (D_00269C90 - i) * sizeof(PO *) - sizeof(PO *)); + + if (i < g_ippoCur) + g_ippoCur = g_ippoCur - 1; + + D_00269C90 = D_00269C90 - 1; +} void OnPoAdd(PO *ppo) { diff --git a/src/P2/rumble.c b/src/P2/rumble.c index ef96472d..22cd76d1 100644 --- a/src/P2/rumble.c +++ b/src/P2/rumble.c @@ -1,6 +1,7 @@ #include #include #include +#include /** * @brief Rename. @@ -98,6 +99,22 @@ void FUN_001A7E70() INCLUDE_ASM("asm/nonmatchings/P2/rumble", FUN_001A7E90); -INCLUDE_ASM("asm/nonmatchings/P2/rumble", FUN_001A7EE8); +extern "C" int FUN_001A7EE8(GS *pgs) +{ + switch (DAT_0026c3dc) + { + case 1: + break; + case 2: + return 1; + case 3: + return 0; + case 0: + return 0; + default: + break; + } + return ((STRUCT_OFFSET(pgs, 0x19EC, int) >> 5) ^ 1) & 1; +} INCLUDE_ASM("asm/nonmatchings/P2/rumble", FUN_001A7F50); diff --git a/src/P2/rwm.c b/src/P2/rwm.c index 20b24568..de53eca7 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); @@ -195,6 +199,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", GetRwfiPosMat__FP4RWFIP6VECTORP7MATRIX3); INCLUDE_ASM("asm/nonmatchings/P2/rwm", GetRwtiPos__FP4RWTIP6VECTORT1); -INCLUDE_ASM("asm/nonmatchings/P2/rwm", GetRwacPan__FP4RWACPf); +void GetRwacPanImpl(RWAC *prwac, float *pradPan, ALO *palo) asm("GetRwacPan__FP4RWACPf"); + +void GetRwacPanImpl(RWAC *prwac, float *pradPan, ALO *palo) +{ + MATRIX3 mat; + + XFM *pxfm = STRUCT_OFFSET(prwac, 0x10, XFM *); + if (pxfm != 0) + { + GetXfmMat(pxfm, &mat); + ConvertAloMat(0, palo, &mat, &mat); + *pradPan = atan2f(mat.mat[0][1], mat.mat[0][0]); + } + else + { + MATRIX3 *pmat = STRUCT_OFFSET(prwac, 0x14, MATRIX3 *); + if (pmat != 0) + { + ConvertAloMat(0, palo, (MATRIX3 *)((uint8_t *)pmat + 0x110), &mat); + *pradPan = atan2f(mat.mat[0][1], mat.mat[0][0]); + } + else + { + *pradPan = STRUCT_OFFSET(prwac, 0x8, float); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/rwm", GetRwacTilt__FP4RWACPf); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index a01594ce..74a23abf 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -18,41 +18,6 @@ void SetSensorAlarm(SENSOR *psensor, ALARM *palarm) } INCLUDE_ASM("asm/nonmatchings/P2/sensor", SetSensorSensors__FP6SENSOR7SENSORS); -#ifdef SKIP_ASM -/** - * @todo 82.08% matched. - */ -void SetSensorSensors(SENSOR *psensor, SENSORS sensors) -{ - SENSORS sensorsCur = STRUCT_OFFSET(psensor, 0x558, SENSORS); // sensorsCur = psensor->sensors; - - if (sensorsCur == sensors) - { - return; - } - - if (sensorsCur == SENSORS_SenseEnabled && sensors == SENSORS_SenseTriggered) - { - ALARM *palarm = STRUCT_OFFSET(psensor, 0x550, ALARM *); - if (palarm) - { - TriggerAlarm(palarm, ALTK_Trigger); - } - - // Recheck current sensor state: if it's not SENSORS_SenseEnabled, - // override the current sensors with the new one. - sensorsCur = STRUCT_OFFSET(psensor, 0x558, SENSORS); - if (sensorsCur != SENSORS_SenseEnabled) - { - sensors = sensorsCur; - } - } - - HandleLoSpliceEvent(psensor, 2, 0, NULL); - STRUCT_OFFSET(psensor, 0x558, SENSORS) = sensors; // psensor->sensors = sensors; - STRUCT_OFFSET(psensor, 0x55C, float) = g_clock.t; -} -#endif INCLUDE_ASM("asm/nonmatchings/P2/sensor", FCheckSensorObject__FP6SENSORP2SO); diff --git a/src/P2/shdanim.c b/src/P2/shdanim.c index 043f24bc..07a6d15f 100644 --- a/src/P2/shdanim.c +++ b/src/P2/shdanim.c @@ -6,6 +6,7 @@ #include #include #include +#include #define TWO_PI 6.2831855f #define INV_TWO_PI 0.15915494f diff --git a/src/P2/sm.c b/src/P2/sm.c index 6b443b8f..2ace6936 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -1,6 +1,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/sm", LoadSmFromBrx__FP2SMP18CBinaryInputStream); @@ -32,7 +33,21 @@ OID OidFromSmIsms(SM *psm, int isms) return psm->asms[isms].oid; } -INCLUDE_ASM("asm/nonmatchings/P2/sm", RetractSma__FP3SMA); +void RetractSma(SMA *psma) +{ + SM *psm = psma->psm; + if (psma->pasegaCur) + { + RetractAsega(psma->pasegaCur); + psma->pasegaCur = 0; + } + FreeSwMqList(psma->psm->psw, psma->pmqFirst); + psma->pmqFirst = 0; + RemoveDlEntry(&psma->psm->dlSma, psma); + RemoveDlEntry(&STRUCT_OFFSET(psma->psm->psw, 0x1B94, DL), psma); + FreeSlotheapPv(&STRUCT_OFFSET(psma->psm->psw, 0x1B88, SLOTHEAP), psma); + HandleLoSpliceEvent(psm, 0x12, 0, 0); +} INCLUDE_ASM("asm/nonmatchings/P2/sm", SetSmaGoal__FP3SMA3OID); diff --git a/src/P2/smartguard.c b/src/P2/smartguard.c index 817b10f9..d2d4a75b 100644 --- a/src/P2/smartguard.c +++ b/src/P2/smartguard.c @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/smartguard", InitSmartguard__FP10SMARTGUARD); @@ -25,7 +26,36 @@ void FUN_001B7100(SMARTGUARD *p, int val) } } -INCLUDE_ASM("asm/nonmatchings/P2/smartguard", PostSmartguardLoad__FP10SMARTGUARD); +void PostSmartguardLoad(SMARTGUARD *psmartguard) +{ + int i; + int *poid; + int oidNearest; + int coid; + + PostStepguardLoad(psmartguard); + PostSmartguardLoadFlashlight(psmartguard); + + oidNearest = STRUCT_OFFSET(psmartguard, 0xc28, int); + if (oidNearest != -1) + { + STRUCT_OFFSET(psmartguard, 0xc2c, LO *) = + PloFindSwNearest(psmartguard->psw, (OID)oidNearest, (LO *)psmartguard); + } + + coid = STRUCT_OFFSET(psmartguard, 0xcd4, int); + if (coid > 0) + { + i = 0; + poid = &STRUCT_OFFSET(psmartguard, 0xcd8, int); + do + { + poid[1] = (int)PloFindSwObject(psmartguard->psw, 0x104, (OID)*poid, (LO *)psmartguard); + i++; + poid += 2; + } while (i < STRUCT_OFFSET(psmartguard, 0xcd4, int)); + } +} int FFilterSmartguardDetect(SMARTGUARD *psmartguard, SO *pso) { diff --git a/src/P2/so.c b/src/P2/so.c index 9f745250..716546c5 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -2,6 +2,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/so", InitSo__FP2SO); @@ -131,7 +132,30 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", AccelSoTowardPosSpring__FP2SOP6VECTORP3CLQ INCLUDE_ASM("asm/nonmatchings/P2/so", AccelSoTowardMatSpring__FP2SOP7MATRIX3P3CLQP6VECTORT2f); -INCLUDE_ASM("asm/nonmatchings/P2/so", PresetSoAccel__FP2SOf); +void PresetSoAccel(SO *pso, float dt) +{ + VECTOR v; + XA *pxa; + + if (pso->paloParent == NULL) + { + if ((STRUCT_OFFSET(pso, 0x538, uint64_t) & ((uint64_t)0x8000 << 36)) == 0) // fNoGravity, grfso bit 51 + { + ApplySoConstraintLocal(pso, (CONSTR *)((uint8_t *)pso + 0x440), + (VECTOR *)((uint8_t *)pso + 0x350), &v, NULL); + AddSoAcceleration(pso, &v); + } + } + pxa = STRUCT_OFFSET(pso, 0x4B0, XA *); // pxaFirst + while (pxa != NULL) + { + SO *psoXa = STRUCT_OFFSET(pxa, 0x0, SO *); + void (*pfn)(SO *, XA *, float) = + (void (*)(SO *, XA *, float))STRUCT_OFFSET(psoXa->pvtlo, 0xDC, void *); + pfn(psoXa, pxa, dt); + pxa = STRUCT_OFFSET(pxa, 0x8, XA *); + } +} INCLUDE_ASM("asm/nonmatchings/P2/so", RenderSoSelf__FP2SOP2CMP2RO); diff --git a/src/P2/sound.c b/src/P2/sound.c index 2e9d1051..ae7938a1 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -6,6 +6,7 @@ #include #include #include +#include extern uchar D_00604790[]; // temp @@ -23,7 +24,23 @@ struct MVG extern float D_00274838[10][4]; // temp -INCLUDE_ASM("asm/nonmatchings/P2/sound", UnloadMusic__Fv); +void UnloadMusic() +{ + extern u_int D_0027473C; + extern u_int D_00274728; + extern int D_00274720; + + if (D_0027473C != 0) + { + if (D_00274728 != 0) + snd_StopSound(D_00274728); + snd_UnloadBank((SoundBankPtr)D_0027473C); + while (snd_FlushSoundCommands()) {} + D_0027473C = 0; + } + D_00274720 = 0; + D_00274728 = 0; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", SbpEnsureBank__Fi); @@ -149,7 +166,26 @@ int FVagPlaying() JUNK_WORD(0x0080102D); -INCLUDE_ASM("asm/nonmatchings/P2/sound", StopVag__Fv); +void StopVag() +{ + if (D_00274744 == 0) + { + if (D_0027472C != 0) + { + snd_StopSound(D_0027472C); + while (snd_SoundIsStillPlaying(D_0027472C)) + { + int i = 0x4E1F; + do + { + i--; + } while (i >= 0); + } + D_0027472C = 0; + D_00274730 = 0; + } + } +} extern u_int D_0027472C; void PauseVag() @@ -203,7 +239,33 @@ void PreloadMusidSongComplete(u_int handle, u_long unused) INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadMusidSong__F5MUSID); -INCLUDE_ASM("asm/nonmatchings/P2/sound", StartMusidSong__F5MUSID); +enum MUSID {}; +void PreloadMusidSong(MUSID musid); + +void StartMusidSong(MUSID musid) +{ + extern int D_00274720; + extern u_int D_00274728; + extern u_int D_0027473C; + + PreloadMusidSong(musid); + if (musid != 0) + { + while (snd_FlushSoundCommands() != 0) + { + if (D_00274720 != 1) + break; + FlushCache(0); + } + if (D_00274720 == 2) + { + u_int handle = snd_PlaySoundVolPanPMPB((SoundBankPtr)D_0027473C, 0, 0x400, -1, 0, 0); + D_00274728 = handle; + if (handle != 0) + D_00274720 = 3; + } + } +} void PauseMusic() { @@ -250,7 +312,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", PexcSetExcitement__Fi); INCLUDE_ASM("asm/nonmatchings/P2/sound", SetIexcCurHigh__FP3EXC); -INCLUDE_ASM("asm/nonmatchings/P2/sound", UnsetExcitement__FP3EXC); +extern int D_00274734; +extern int D_002748EC; +void SetIexcCurHigh(EXC *pexc); + +void UnsetExcitement(EXC *pexc) +{ + if (pexc != 0) + { + int iexc = pexc->iexc; + RemoveExc(pexc); + if (iexc == D_00274734) + { + SetIexcCurHigh(pexc); + int iexcCur = D_00274734; + if (iexcCur >= 0) + D_002748EC = 0; + g_iexcHyst = iexcCur; + snd_SetGlobalExcite(iexcCur + 0x14); + SetMvgkRvol(7, MVGK_Music, 1.0f); + g_iexcHyst = -0x64; + } + } +} extern int D_00274734; void SetIexcCurHigh(EXC *pexc); @@ -508,7 +592,14 @@ void PushSwReverb(SW *psw, REVERBK reverb, int depth) INCLUDE_ASM("asm/nonmatchings/P2/sound", PopSwReverb__FP2SW); -INCLUDE_ASM("asm/nonmatchings/P2/sound", SetSwDefaultReverb__FP2SW7REVERBKi); +void SetSwDefaultReverb(SW *psw, REVERBK reverb, const int depth) +{ + snd_SetReverbType(2, D_00274808[reverb]); + snd_SetReverbDepth(2, depth, depth); + STRUCT_OFFSET(psw, 0x2328, int) = reverb; + STRUCT_OFFSET(psw, 0x232c, int) = depth; + STRUCT_OFFSET(psw, 0x2348, int) = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001C0A50); diff --git a/src/P2/stepcane.c b/src/P2/stepcane.c index ba6c83cf..c11bbbc8 100644 --- a/src/P2/stepcane.c +++ b/src/P2/stepcane.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/stepcane", SetJtJtcs__FP2JT4JTCS); @@ -11,7 +12,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtAttackTarget__FP2JTiP6VECTOR INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtSweepTarget__FP2JTP2BLP6ASEGBL); -INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtRushTarget__FP2JT); +void ChooseJtRushTarget(JT *pjt) +{ + extern VECTOR D_00274BF0; + VECTOR dposProj; + TARGET *ptarget; + + ChooseJtAttackTarget(pjt, 8, &D_00274BF0, 0.25f, 1.0f, &ptarget, &dposProj); + STRUCT_OFFSET(pjt, 0x2204, int) = 0; + STRUCT_OFFSET(pjt, 0x2200, TARGET *) = ptarget; + STRUCT_OFFSET(pjt, 0x2208, int) = 0; + if (ptarget != NULL) + { + STRUCT_OFFSET(pjt, 0x638, float) = atan2f(dposProj.y, dposProj.x); + FixStepAngularVelocity((STEP *)pjt); + } +} void ChooseJtSmashTarget(JT *pjt) { diff --git a/src/P2/tank.c b/src/P2/tank.c index 2b9361c4..a4244270 100644 --- a/src/P2/tank.c +++ b/src/P2/tank.c @@ -24,7 +24,38 @@ INCLUDE_ASM("asm/nonmatchings/P2/tank", PostTankLoad__FP4TANK); INCLUDE_ASM("asm/nonmatchings/P2/tank", UpdateTank__FP4TANKf); -INCLUDE_ASM("asm/nonmatchings/P2/tank", FUN_001deb30); +static inline VU_VECTOR VuVectorXyz(float x, float y, float z) +{ + VU_VECTOR v; + qword tmp; + asm("mfc1 %0, %2\n\tmfc1 %1, %3\n\tpextlw %0, %1, %0\n\tmfc1 %1, %4\n\tpcpyld %0, %1, %0" + : "=r"(v.data), "=r"(tmp) + : "f"(x), "f"(y), "f"(z)); + return v; +} + +extern "C" void FUN_001deb30(TANK *ptank) +{ + union + { + qword q; + float af[4]; + } u; + float radPanTarget; + float radTiltTarget; + float svTarget; + + CalculateAloDrive((ALO *)ptank, NULL, NULL, g_clock.dt, + STRUCT_OFFSET(ptank, 0x638, float), + &radPanTarget, &radTiltTarget, &svTarget); + + STRUCT_OFFSET(ptank, 0x638, float) = radPanTarget; + LoadRotateMatrixPanTilt(radPanTarget, radTiltTarget, + (MATRIX3 *)((uint8_t *)ptank + 0x660)); + + u.q = VuVectorXyz(-svTarget, 0.0f, 0.0f).data; + STRUCT_OFFSET(ptank, 0x640, qword) = u.q; +} void UseTankCharm(TANK *ptank) { diff --git a/src/P2/turret.c b/src/P2/turret.c index de347a24..ef67e8cd 100644 --- a/src/P2/turret.c +++ b/src/P2/turret.c @@ -5,6 +5,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/turret", InitTurret__FP6TURRET); diff --git a/src/P2/ui.c b/src/P2/ui.c index 649e5047..7989e5a1 100644 --- a/src/P2/ui.c +++ b/src/P2/ui.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include void StartupUi() { From 459b0b14730ac7439ac2ccd2b95fd70e55180e33 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Sat, 13 Jun 2026 22:41:44 +0200 Subject: [PATCH 119/134] Match wave-9 functions (alo rotation setters, aseg/crv/freeze/jlo/jt, dartgun, sky/tv/ub etc.) game.h: tally_world_completion is a raw symbol (extern C). Co-Authored-By: Claude Fable 5 --- include/game.h | 2 +- src/P2/989snd.c | 24 ----------------------- src/P2/alo.c | 50 +++++++++++++++++++++++++++++++++++++++++++---- src/P2/aseg.c | 20 ++++++++++++++++++- src/P2/cm.c | 20 ++++++++++++++++++- src/P2/crusher.c | 29 ++++++++++++++++++++++++++- src/P2/dartgun.c | 34 +++++++++++++++++++++++++++++++- src/P2/jlo.c | 1 + src/P2/jt.c | 17 +++++++++++++++- src/P2/pzo.c | 26 +++++++++++++++++++++++- src/P2/screen.c | 6 ++++++ src/P2/sensor.c | 36 ---------------------------------- src/P2/sky.c | 19 +++++++++++++++++- src/P2/steppipe.c | 22 ++++++++++++++++++++- src/P2/xform.c | 18 ++++++++++++++++- 15 files changed, 250 insertions(+), 74 deletions(-) diff --git a/include/game.h b/include/game.h index 57aeaedb..8fe92104 100644 --- a/include/game.h +++ b/include/game.h @@ -274,7 +274,7 @@ uint get_level_completion_by_id(int level_id); * @param cvault Result of the tally of vaults. * @param cmts Result of the tally of Master Thief Sprints */ -void tally_world_completion(int wid, int *ckey, int *cvault, int *cmts); +extern "C" void tally_world_completion(int wid, int *ckey, int *cvault, int *cmts); /** * @brief Get the game completion flags based on the current game state. diff --git a/src/P2/989snd.c b/src/P2/989snd.c index b210f5f3..ed56ff11 100644 --- a/src/P2/989snd.c +++ b/src/P2/989snd.c @@ -228,30 +228,6 @@ JUNK_ADDIU(10); JUNK_ADDIU(10); INCLUDE_ASM("asm/nonmatchings/P2/989snd", snd_GotReturns__Fv); -#ifdef SKIP_ASM -// Rodata -int snd_GotReturns(void) -{ - FlushCache(0); - if (gCommBusy == NULL) { - return 1; - } - - if (sceSifCheckStatRpc(&gSLClientData.rpcd)) { - return 0; - } - - if (*gCommBusy == -1 && (gCommBusy[gAwaitingInts + 1] == -1)) { - gCommBusy = NULL; - return 1; - } else { - printf("989snd.c: Sif says RPC isn\'t busy, but we still don\'t have returns from the IOP!\n"); - return 0; - } - - return 1; -} -#endif void snd_PrepareReturnBuffer(u_int* buffer, int num_ints) { diff --git a/src/P2/alo.c b/src/P2/alo.c index 307ec8d5..fda3291c 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -11,6 +11,7 @@ #include #include #include +#include extern VTACT g_vtactseg; extern SHADOW s_shadow; @@ -570,7 +571,18 @@ void SetAloPositionDampingDetail(ALO *palo, CLQ *pclq) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSpring__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSpringDetail__FP3ALOP3CLQ); +extern CLQ D_00260E90; +void SetAloRotationSpringDetail(ALO *palo, CLQ *pclq) +{ + CLQ *&pclqDst = STRUCT_OFFSET(palo, 0x214, CLQ *); // palo->pclqRotationSpring (default &D_00260E90) + + if (pclqDst == &D_00260E90) + { + pclqDst = (CLQ *)PvAllocSwImpl(0x10); + } + + *(VU_VECTOR *)pclqDst = *(VU_VECTOR *)pclq; +} INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationDamping__FP3ALOf); @@ -612,9 +624,25 @@ void SetAloPositionSmoothDetail(ALO *palo, SMPA *psmpa) INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSmooth__FP3ALOf); -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSmoothMaxAccel__FP3ALOf); +void SetAloRotationSmoothMaxAccel(ALO *palo, float r) +{ + SMPA smpa = *STRUCT_OFFSET(palo, 0x220, SMPA *); // copy palo->psmapaRot + smpa.ag[3] = r * (smpa.ag[0] - smpa.ag[1]) / smpa.ag[2]; + SetAloRotationSmoothDetail(palo, &smpa); +} + +extern SMPA D_00260EC0; +void SetAloRotationSmoothDetail(ALO *palo, SMPA *psmpa) +{ + SMPA *&psmpaDst = STRUCT_OFFSET(palo, 0x220, SMPA *); // palo->psmapaRot (default &D_00260EC0) + + if (psmpaDst == &D_00260EC0) + { + psmpaDst = (SMPA *)PvAllocSwImpl(0x10); + } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationSmoothDetail__FP3ALOP4SMPA); + *psmpaDst = *psmpa; +} void SetAloDefaultAckPos(ALO *palo, ACK ack) { @@ -864,7 +892,21 @@ extern "C" void FUN_0012a8c8(ALO *palo) STRUCT_OFFSET(pactla, 0x4C, int) = 1; } -INCLUDE_ASM("asm/nonmatchings/P2/alo", SetAloRotationMatchesVelocity__FP3ALOff3ACK); +extern VTACT D_00219600; +void SetAloRotationMatchesVelocity(ALO *palo, float uBank, float dtPredict, ACK ackRot) +{ + if (STRUCT_OFFSET(palo, 0x204, ACT *) == 0) + { + ACT *pact = PactNew(palo->psw, palo, &D_00219600); + STRUCT_OFFSET(palo, 0x204, ACT *) = pact; + InsertAloAct(palo, pact); + } + + STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x204, ACT *), 0x11, char) = ackRot; + ((ACTBANK *)STRUCT_OFFSET(palo, 0x204, ACT *))->uBank = uBank; + ((ACTBANK *)STRUCT_OFFSET(palo, 0x204, ACT *))->dtPredict = dtPredict; + (*(void (**)(ALO *))((char *)palo->pvtlo + 0xBC))(palo); +} TARGET *PtargetEnsureAlo(ALO *palo) { diff --git a/src/P2/aseg.c b/src/P2/aseg.c index 801e5930..c7488ed6 100644 --- a/src/P2/aseg.c +++ b/src/P2/aseg.c @@ -57,7 +57,25 @@ ASEGA *PasegaApplyAseg(ASEG *paseg, ALO *paloAsegRoot, float tLocal, float svtLo INCLUDE_ASM("asm/nonmatchings/P2/aseg", PasegaFindAseg__FP4ASEGP3ALO); -INCLUDE_ASM("asm/nonmatchings/P2/aseg", EnsureAseg__FP4ASEGP3ALO4SEEKffiPP5ASEGA); +void SeekAsega(ASEGA *pasega, SEEK seek, float t, float svt); + +void EnsureAseg(ASEG *paseg, ALO *paloRoot, SEEK seek, float t, float svt, GRFAPL grfapl, ASEGA **ppasega) +{ + ASEGA *pasega; + ASEGA **pp = ppasega ? ppasega : &pasega; + + pasega = PasegaFindAseg(paseg, paloRoot); + if (pasega != NULL) + { + *pp = pasega; + } + else + { + ApplyAseg(paseg, paloRoot, 0.0f, 1.0f, grfapl, pp); + } + + SeekAsega(*pp, seek, t, svt); +} ASEGA *PasegaEnsureAseg(ASEG *paseg, ALO *paloRoot, SEEK seek, float t, float svt, GRFAPL grfapl) { diff --git a/src/P2/cm.c b/src/P2/cm.c index c7e1d486..f9f01817 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include // todo fix data and rodata // VECTOR4 g_posEyeDefault = { 0.0f, -2000.0f, 500.0f, 0.0f }; @@ -206,7 +208,23 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCmScreenToWorld); INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCmWorldToScreen); -INCLUDE_ASM("asm/nonmatchings/P2/cm", SetupCm__FP2CM); +extern "C" void SetupCmRotateToCam(CM *pcm); + +void SetupCm(CM *pcm) +{ + VECTOR4 vTmp; + GRFZON grfzon; + + SetupCmRotateToCam(pcm); + + if (g_psw != NULL) + { + STRUCT_OFFSET(&vTmp, 0, qword) = STRUCT_OFFSET(pcm, 0x40, qword); + ClipVismapPointNoHop(g_psw->pvismap, (VECTOR *)&vTmp, &grfzon); + if (grfzon != 0) + pcm->field39_0x21c = grfzon; + } +} INCLUDE_ASM("asm/nonmatchings/P2/cm", CombineEyeLookAtProj); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index 81d91426..db7da015 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -95,7 +95,34 @@ extern "C" void FUN_0014c668(void *pv, int tnt) INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); -INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c788); +extern int FUN_001e9970(); +extern BLOT g_unkblot1; +extern BLOT g_unkblot9; + +extern "C" void FUN_0014c788(void *pv) +{ + OID oid; + int fShow; + + GetSmaCur(STRUCT_OFFSET(pv, 0x42c, SMA *), &oid); + + fShow = 0; + if (oid == (OID)0x3fd) + { + fShow = FUN_001e9970(); + } + + if (fShow) + { + g_unkblot1.pvtblot->pfnShowBlot(&g_unkblot1); + g_unkblot9.pvtblot->pfnShowBlot(&g_unkblot9); + } + else + { + g_unkblot1.pvtblot->pfnHideBlot(&g_unkblot1); + g_unkblot9.pvtblot->pfnHideBlot(&g_unkblot9); + } +} void *FUN_0014c820(void *p) { diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index dcf0fadc..378e14aa 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include void InitDartgun(DARTGUN *pdartgun) { @@ -73,7 +75,37 @@ int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) return FIgnoreSoIntersection((SO *)pdartgun, psoOther); } -INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BreakDartgun__FP7DARTGUN); +void BreakDartgun(DARTGUN *pdartgun) +{ + OID oidCur; + ALO *palo; + SMA *psma; + + palo = STRUCT_OFFSET(pdartgun, 0x6c8, ALO *); + if (palo != NULL) + { + (*(void (**)(ALO *, int))((char *)palo->pvtlo + 0x64))(palo, 0); + palo = STRUCT_OFFSET(pdartgun, 0x6c8, ALO *); + (*(void (**)(ALO *))((char *)palo->pvtlo + 0x1c))(palo); + } + + psma = STRUCT_OFFSET(pdartgun, 0x740, SMA *); + if (psma != NULL) + { + SeekSma(psma, (OID)0x2B7); + GetSmaCur(STRUCT_OFFSET(pdartgun, 0x740, SMA *), &oidCur); + if (oidCur == (OID)0x2B7) + { + RetractSma(STRUCT_OFFSET(pdartgun, 0x740, SMA *)); + STRUCT_OFFSET(pdartgun, 0x740, int) = 0; + } + } + + palo = STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, ALO *); + (*(void (**)(ALO *, int))((char *)palo->pvtlo + 0x8))(palo, 7); + + BreakBrk((BRK *)pdartgun); +} void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) { diff --git a/src/P2/jlo.c b/src/P2/jlo.c index dd92c9c7..ad98eeb5 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -3,6 +3,7 @@ #include #include #include +#include extern JLO *g_pjloCur; extern VECTOR g_normalZ; // TODO: This should be elsewhere. diff --git a/src/P2/jt.c b/src/P2/jt.c index b1ee5839..fb64407a 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -154,7 +154,22 @@ void UpdateJtPosWorldPrev(JT *pjt) INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172b08); -INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtBounds__FP2JT); +void UpdateJtBounds(JT *pjt) +{ + UpdateSoBounds(pjt); + + int i = 0; + if (STRUCT_OFFSET(pjt, 0x21CC, int) > 0) + { + VECTOR *ppos = (VECTOR *)((char *)pjt + 0x21D0); + do + { + ExtendSoBounds(pjt, ppos, STRUCT_OFFSET(pjt, 0x2420, float)); + i++; + ppos = (VECTOR *)((char *)ppos + 0x10); + } while (i < STRUCT_OFFSET(pjt, 0x21CC, int)); + } +} SO *PsoGetJtEffect(JT *pjt, int *pn) { diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 2db94090..ea034ca9 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include void InitSprize(SPRIZE *psprize) { @@ -192,7 +194,29 @@ void InitClue(CLUE *pclue) STRUCT_OFFSET(psw, 0x2300, int) = n + 1; } -INCLUDE_ASM("asm/nonmatchings/P2/pzo", LoadClueFromBrx__FP4CLUEP18CBinaryInputStream); +extern SNIP D_0026A948; + +void LoadClueFromBrx(CLUE *pclue, CBinaryInputStream *pbis) +{ + LoadSprizeFromBrx(pclue, pbis); + SnipAloObjects(pclue, 1, &D_0026A948); + STRUCT_OFFSET(pclue, 0x5b0, void *) = PvAllocSwImpl(0x80); + + int oid = 0x318; + while (oid < 0x338) + { + LO *plo = PloFindSwObject(STRUCT_OFFSET(pclue, 0x14, SW *), 1, (OID)oid, (LO *)pclue); + if (plo == NULL) + break; + + int c = STRUCT_OFFSET(pclue, 0x5ac, int); + LO **aplo = STRUCT_OFFSET(pclue, 0x5b0, LO **); + oid++; + aplo[c] = plo; + STRUCT_OFFSET(pclue, 0x5ac, int) = c + 1; + SnipLo(plo); + } +} void CloneClue(CLUE *pclue, CLUE *pclueBase) { diff --git a/src/P2/screen.c b/src/P2/screen.c index b717d82e..80db9450 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -491,6 +491,12 @@ void FUN_001adc60(BLOT *pblot) INCLUDE_ASM("asm/nonmatchings/P2/screen", DrawLogo__FP4LOGO); +extern float D_0027446C; +extern float D_00274470; +extern CFont *D_00274488; +extern void *D_00269988; + + INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001adf28); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001adff0); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 74a23abf..ea9a812b 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -126,42 +126,6 @@ void FreezeLasen(LASEN *plasen, int fFreeze) INCLUDE_ASM("asm/nonmatchings/P2/sensor", RenderLasenSelf__FP5LASENP2CMP2RO); INCLUDE_ASM("asm/nonmatchings/P2/sensor", FUN_001afaf8__FP6SENSORP2SO); -#ifdef SKIP_ASM -/** - * @todo 73.57% matched. - */ -int FUN_001afaf8(SENSOR *psensor, SO *pso) -{ - extern void *g_pjt; - unsigned long long mask; - uint tmp2cc; - - /* Mask: (0x8000 << 28) in 64-bits */ - mask = ((ulong)0x8000) << 28; - if (STRUCT_OFFSET(pso, 0x538, ulong) & mask) - return 0; - - if (STRUCT_OFFSET(pso, 0x50, uint) == STRUCT_OFFSET(psensor, 0x50, uint)) - return 0; - - if (FIgnoreSensorObject(psensor, pso)) - return 0; - - if (pso == g_pjt) - { - if (STRUCT_OFFSET(pso, 0x2220, uint) != 6) - return 0; - if (STRUCT_OFFSET(pso, 0x239C, uint) != 3) - return 0; - if (GetGrfvault_unknown() & 0x12000) - return 0; - } - - tmp2cc = STRUCT_OFFSET(pso, 0x2CC, uint); - /* Invert lowest bit and mask to 1 */ - return (int)(((tmp2cc ^ 1u) & 1u)); -} -#endif INCLUDE_ASM("asm/nonmatchings/P2/sensor", SenseLasen__FP5LASENP7SENSORS); diff --git a/src/P2/sky.c b/src/P2/sky.c index 0956156f..76c19dd7 100644 --- a/src/P2/sky.c +++ b/src/P2/sky.c @@ -1,5 +1,22 @@ #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/sky", PostSkyLoad__FP3SKY); -INCLUDE_ASM("asm/nonmatchings/P2/sky", UpdateSky__FP3SKYf); +void UpdateSky(SKY *psky, float dt) +{ + VU_VECTOR vec; + void (*pfn)(SKY *, VU_VECTOR *); + + UpdateAlo((ALO *)psky, dt); + + vec = STRUCT_OFFSET(g_pcm, 0x40, VU_VECTOR); + if (STRUCT_OFFSET(psky, 0x2D0, int) == 0) + { + STRUCT_OFFSET(&vec, 0x8, float) = STRUCT_OFFSET(psky, 0x148, float); + } + + pfn = (void (*)(SKY *, VU_VECTOR *))STRUCT_OFFSET(STRUCT_OFFSET(psky, 0x0, char *), 0x84, void *); + pfn(psky, &vec); +} diff --git a/src/P2/steppipe.c b/src/P2/steppipe.c index e3402430..eeea2221 100644 --- a/src/P2/steppipe.c +++ b/src/P2/steppipe.c @@ -10,6 +10,26 @@ INCLUDE_ASM("asm/nonmatchings/P2/steppipe", UpdateJtActivePipe__FP2JTP3JOY); INCLUDE_ASM("asm/nonmatchings/P2/steppipe", UpdateJtInternalXpsPipe__FP2JT); -INCLUDE_ASM("asm/nonmatchings/P2/steppipe", SetJtJtpdk__FP2JT5JTPDK); +extern "C" void FUN_001ddb58(SW *psw); +extern "C" void FUN_001ddbb8(SW *psw); + +void SetJtJtpdk(JT *pjt, JTPDK jtpdk) +{ + JTPDK jtpdkCur = STRUCT_OFFSET(pjt, 0x2718, JTPDK); + if (jtpdkCur != jtpdk) + { + if (jtpdkCur == JTPDK_Nil) + { + IncrementSwHandsOff(pjt->psw); + FUN_001ddb58(pjt->psw); + } + STRUCT_OFFSET(pjt, 0x2718, JTPDK) = jtpdk; + if (jtpdk == JTPDK_Nil) + { + DecrementSwHandsOff(pjt->psw); + FUN_001ddbb8(pjt->psw); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/steppipe", PlaceJtOnPipe__FP2JTP4PIPE); diff --git a/src/P2/xform.c b/src/P2/xform.c index b5076e2f..2780a943 100644 --- a/src/P2/xform.c +++ b/src/P2/xform.c @@ -5,6 +5,7 @@ #include #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/xform", InitXfm__FP3XFM); @@ -88,7 +89,22 @@ int FUN_001F4308(WARP *pwarp, float g) return 1; } -INCLUDE_ASM("asm/nonmatchings/P2/xform", TeleportSwPlayer__FP2SW3OIDT1); +void TeleportSwPlayer(SW *psw, OID oidWarp, OID oidWarpContext) +{ + WARP *pwarp = PwarpFromOid(oidWarp, oidWarpContext); + if (pwarp != NULL) + { + TriggerWarp(pwarp); + return; + } + + if (PpoCur() != NULL) + return; + + PO *ppo = PpoStart(); + if (ppo != NULL) + SwitchToPo(ppo); +} INCLUDE_ASM("asm/nonmatchings/P2/xform", PexitDefault__Fv); From 5a38764ad70ebe561e03be908078f2da2d042b62 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 17 Jun 2026 21:44:05 +0200 Subject: [PATCH 120/134] wip: more function matching --- src/P2/act.c | 28 +++++++++++++- src/P2/asega.c | 51 ++++++++++++++++++++++++- src/P2/barrier.c | 45 ++++++++++++++++++++++- src/P2/bbmark.c | 33 ++++++++++++++++- src/P2/brx.c | 36 +++++++++++++++++- src/P2/cd.c | 36 +++++++++++++++++- src/P2/chkpnt.c | 44 +++++++++++++++++++++- src/P2/cnvo.c | 23 +++++++++++- src/P2/credit.c | 56 +++++++++++++++++++++++++++- src/P2/crusher.c | 28 +++++++++++++- src/P2/difficulty.c | 37 ++++++------------- src/P2/emitter.c | 45 ++++++++++++++++++++++- src/P2/fly.c | 44 +++++++++++++++++++++- src/P2/font.c | 52 +++++++++++++++++++++++++- src/P2/frm.c | 46 ++++++++++++++++++++++- src/P2/game.c | 31 ++++++++++++---- src/P2/jsg.c | 27 +++++++++++++- src/P2/light.c | 23 +++++++++++- src/P2/missile.c | 35 +++++++++++++++++- src/P2/mpeg.c | 19 +++++++++- src/P2/po.c | 31 +++++++++++++++- src/P2/render.c | 4 +- src/P2/shadow.c | 28 +++++++++++++- src/P2/suv.c | 30 ++++++++++++++- src/P2/sw.c | 54 ++++++++++++++++++++++++++- src/P2/tank.c | 46 +++++++++++++++++++++++ src/P2/tn.c | 90 +++++++++++++++++++++++++++++++++++++++++++-- src/P2/ub.c | 32 ++++++++++++++++ src/P2/wipe.c | 13 +++---- 29 files changed, 991 insertions(+), 76 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index b48c1bd9..b138b4d3 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -143,7 +144,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/act", CalculateAloRotationSpring__FP3ALOfP7MATR INCLUDE_ASM("asm/nonmatchings/P2/act", ProjectActRotation__FP3ACT); -INCLUDE_ASM("asm/nonmatchings/P2/act", ProjectActPose__FP3ACTi); +extern SMP D_00260E60; + +void ProjectActPose(ACT *pact, int ipose) +{ + float g = (*(float (**)(ACT *))((char *)pact->pvtact + 0x20))(pact); + signed char actk = STRUCT_OFFSET(pact, 0x13, signed char); + + if (actk == 2) + { + float *ag = STRUCT_OFFSET(pact->palo, 0x270, float *); + ag[ipose] = g; + } + else if (actk == 3) + { + ALO *palo = pact->palo; + int off = ipose << 2; + float *ag = STRUCT_OFFSET(palo, 0x270, float *); + float dt; + if (STRUCT_OFFSET(palo, 0x294, int)) + dt = g_clock.dtReal; + else + dt = g_clock.dt; + *(float *)((char *)ag + off) = + GSmooth(*(float *)((char *)ag + off), g, dt, &D_00260E60, NULL); + } +} INCLUDE_ASM("asm/nonmatchings/P2/act", PredictAloPosition__FP3ALOfP6VECTORT2); diff --git a/src/P2/asega.c b/src/P2/asega.c index 571bbb9c..66eb436c 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -30,7 +30,56 @@ void SetAsegaHandsOff(ASEGA *pasega, int fHandsOff) pasega->fHandsOff = fHandsOff; } -INCLUDE_ASM("asm/nonmatchings/P2/asega", UpdateAsegaIeaCur__FP5ASEGA); +void UpdateAsegaIeaCur(ASEGA *pasega) +{ + void *paseg = STRUCT_OFFSET(pasega, 0x8, void *); + int c = STRUCT_OFFSET(paseg, 0x5C, int); + if (c == 0) + return; + + if (0.0f <= STRUCT_OFFSET(pasega, 0x18, float)) + { + int i = c - 1; + i = 0; + if (c > 0) + { + char *p = STRUCT_OFFSET(paseg, 0x60, char *); + float t = STRUCT_OFFSET(pasega, 0x14, float); + if (!(t <= *(float *)p)) + { + int cmax = c; + i = i + 1; + while (i < cmax) + { + p += 0x10; + if (t <= *(float *)p) + break; + i = i + 1; + } + } + } + STRUCT_OFFSET(pasega, 0x20, int) = i; + } + else + { + int i = c - 1; + if (i >= 0) + { + char *p = STRUCT_OFFSET(paseg, 0x60, char *) + (i << 4); + float t = STRUCT_OFFSET(pasega, 0x14, float); + while (1) + { + if (*(float *)p <= t) + break; + i = i - 1; + if (i < 0) + break; + p -= 0x10; + } + } + STRUCT_OFFSET(pasega, 0x20, int) = i + 1; + } +} INCLUDE_ASM("asm/nonmatchings/P2/asega", PactsegFindAsega__FP5ASEGA3OID); diff --git a/src/P2/barrier.c b/src/P2/barrier.c index c64e8550..8e6aa9c0 100644 --- a/src/P2/barrier.c +++ b/src/P2/barrier.c @@ -19,7 +19,50 @@ void CloneBarrier(BARRIER *pbarrier, BARRIER *pbarrierBase) INCLUDE_ASM("asm/nonmatchings/P2/barrier", PostBarrierLoad__FP7BARRIER); -INCLUDE_ASM("asm/nonmatchings/P2/barrier", UpdateBarrier__FP7BARRIERf); +extern VECTOR D_00248D30; + +void UpdateBarrier(BARRIER *pbarrier, float dt) +{ + UpdateSo(pbarrier, dt); + + SO *psoWarp = STRUCT_OFFSET(pbarrier, 0x5A0, SO *); + if (psoWarp) + { + VECTOR *pvecZero = &D_00248D30; + + (*(void (**)(SO *, VECTOR *))((char *)psoWarp->pvtlo + 0x90))(psoWarp, pvecZero); + + psoWarp = STRUCT_OFFSET(pbarrier, 0x5A0, SO *); + (*(void (**)(SO *, VECTOR *))((char *)psoWarp->pvtlo + 0x94))(psoWarp, pvecZero); + + int state = STRUCT_OFFSET(pbarrier, 0x580, int); + void *pvResult; + if (state == 1) + { + psoWarp = STRUCT_OFFSET(pbarrier, 0x5A0, SO *); + (*(void (**)(SO *, void *))((char *)psoWarp->pvtlo + 0x84))( + psoWarp, &STRUCT_OFFSET(pbarrier, 0x590, int)); + pvResult = STRUCT_OFFSET(pbarrier, 0x5A0, void *); + } + else if (state == 2) + { + SO *psoWarpSrc = STRUCT_OFFSET(pbarrier, 0x590, SO *); + VECTOR vec; + ConvertAloPos(STRUCT_OFFSET(psoWarpSrc, 0x18, ALO *), NULL, + (VECTOR *)((char *)psoWarpSrc + 0x40), &vec); + psoWarp = STRUCT_OFFSET(pbarrier, 0x5A0, SO *); + (*(void (**)(SO *, VECTOR *))((char *)psoWarp->pvtlo + 0x84))(psoWarp, &vec); + pvResult = STRUCT_OFFSET(pbarrier, 0x5A0, void *); + } + else + { + pvResult = STRUCT_OFFSET(pbarrier, 0x5A0, void *); + } + + STRUCT_OFFSET(pbarrier, 0x5A0, void *) = NULL; + STRUCT_OFFSET(pbarrier, 0x5A4, void *) = pvResult; + } +} INCLUDE_ASM("asm/nonmatchings/P2/barrier", FIgnoreBarrierIntersection__FP7BARRIERP2SO); diff --git a/src/P2/bbmark.c b/src/P2/bbmark.c index 89d6dc37..ff1d7b38 100644 --- a/src/P2/bbmark.c +++ b/src/P2/bbmark.c @@ -75,4 +75,35 @@ void InvalidateSwXpForObject(SW *psw, SO *pso, GRFPVA grfpvaInvalid) INCLUDE_ASM("asm/nonmatchings/P2/bbmark", RecalcSwXpAll__FP2SWi); -INCLUDE_ASM("asm/nonmatchings/P2/bbmark", RecalcSwOxfFilterForObject__FP2SWP2SO); +extern void UpdateSwPox(SW *, OXA *, OXA *, unsigned char, unsigned char); + +void RecalcSwOxfFilterForObject(SW *psw, SO *pso) +{ + OXA *poxa; + + STRUCT_OFFSET(pso, 0x4B8, int) = 0; + poxa = STRUCT_OFFSET(psw, 0x1AE8, OXA *); + while (poxa != NULL) + { + if (poxa->pso != pso) + { + int fHit = 0; + void **pvtbl = STRUCT_OFFSET(pso, 0x0, void **); + if (((int (*)(SO *))pvtbl[0xF0 / 4])(pso) != 0) + { + fHit = 1; + } + else + { + void **pvtblOther = STRUCT_OFFSET(poxa->pso, 0x0, void **); + if (((int (*)(SO *, SO *))pvtblOther[0xF0 / 4])(poxa->pso, pso) != 0) + { + fHit = 1; + } + } + UpdateSwPox(psw, STRUCT_OFFSET(pso, 0x480, OXA *), poxa, + fHit ? 0 : 8, fHit ? 8 : 0); + } + poxa = poxa->poxaNext; + } +} diff --git a/src/P2/brx.c b/src/P2/brx.c index a5b9e4ec..32b3de4a 100644 --- a/src/P2/brx.c +++ b/src/P2/brx.c @@ -53,4 +53,38 @@ uint IploFromStockOid(int oid) INCLUDE_ASM("asm/nonmatchings/P2/brx", LoadSwObjectsFromBrx__FP2SWP3ALOP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/brx", SetLoDefaults__FP2LO); +struct EOPIDENTRY +{ + void *unk; + EOPID *peopid; +}; + +struct LODEFTAB +{ + int ceopid; + EOPIDENTRY *prgeopidentry; +}; + +extern "C" LODEFTAB D_00244950[]; + +void SetLoDefaults(LO *plo) +{ + CID cid = plo->pvtlo->cid; + int ceopid = D_00244950[cid].ceopid; + if (ceopid > 0) + { + EOPIDENTRY *peopidentry = D_00244950[cid].prgeopidentry; + do + { + EOPID *peopid = peopidentry->peopid; + if (peopid->grfeopid & 0x800) + { + CBinaryInputStream bis(NULL, 0, 0); + bis.OpenMemory(4, &peopid->optdat); + LoadOptionFromBrx(plo, peopid, &bis); + } + ceopid--; + peopidentry++; + } while (ceopid != 0); + } +} diff --git a/src/P2/cd.c b/src/P2/cd.c index 4f99949c..77cf9091 100644 --- a/src/P2/cd.c +++ b/src/P2/cd.c @@ -1,4 +1,5 @@ #include +#include #include <989snd.h> #include @@ -41,7 +42,40 @@ void StartupCd() INCLUDE_ASM("asm/nonmatchings/P2/cd", UpdateCd__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/cd", CdPath__FPcT0i); +extern "C" char *strcpy1(char *pchzDst, char *pchzSrc); +extern short D_00249E20; +extern char D_00249E28[]; +extern char D_00249E30[]; +extern char D_00249E38[]; + +void CdPath(char *pchzDest, char *pchzPath, int fIncludeDevice) +{ + char achz[0x100]; + + *(short *)achz = D_00249E20; + strcpy1(achz, pchzPath); + int ctoken = ((int (*)(char *))CpchzTokenizePath)(achz); + if (1 < ctoken) + { + int itoken = ctoken - 1; + do + { + achz[strlen(achz)] = '\\'; + itoken--; + } while (itoken != 0); + } + + char *pchzDevice; + if (fIncludeDevice) + { + pchzDevice = D_00249E30; + } + else + { + pchzDevice = D_00249E38; + } + sprintf(pchzDest, D_00249E28, pchzDevice, achz); +} void ReadCd(uint isector, uint csector, void *pv) { diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index 93861ff4..6fb89601 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -39,7 +39,14 @@ void ResetChkmgrCheckpoints(CHKMGR *pchkmgr) } #endif -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", SaveChkmgrCheckpoint__FP6CHKMGR3OIDT1); +void SaveChkmgrCheckpoint(CHKMGR *pchkmgr, OID oidWarp, OID oidWarpContext) +{ + STRUCT_OFFSET(pchkmgr, 0x20C, int) = 0; + memcpy((char *)pchkmgr + 0x220, &pchkmgr->abitChk, 0x204); + STRUCT_OFFSET(pchkmgr, 0x42c, int) = 1; + STRUCT_OFFSET(pchkmgr, 0x424, int) = oidWarp; + STRUCT_OFFSET(pchkmgr, 0x428, int) = oidWarpContext; +} void ReturnChkmgrToCheckpoint(CHKMGR *pchkmgr) { @@ -109,7 +116,40 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", BindChkpnt__FP6CHKPNT); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", PostChkpntLoad__FP6CHKPNT); -INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", CloneChkpnt__FP6CHKPNTT0); +void CloneChkpnt(CHKPNT *pchkpnt, CHKPNT *pchkpntBase) +{ + int i = 0; + LO *plo0 = STRUCT_OFFSET(pchkpnt, 0x5B4, LO *); + LO *plo1 = STRUCT_OFFSET(pchkpnt, 0x5B0, LO *); + + CloneSo((SO *)pchkpnt, (SO *)pchkpntBase); + + STRUCT_OFFSET(pchkpnt, 0x5B0, LO *) = plo1; + STRUCT_OFFSET(pchkpnt, 0x5B4, LO *) = plo0; + + if (STRUCT_OFFSET(pchkpnt, 0x564, int) > 0) + { + LO **a = &STRUCT_OFFSET(pchkpnt, 0x568, LO *); + do + { + *a = PloCloneLo(*a, STRUCT_OFFSET(pchkpnt, 0x14, SW *), (ALO *)pchkpnt); + i++; + a++; + } while (i < STRUCT_OFFSET(pchkpnt, 0x564, int)); + } + + if (STRUCT_OFFSET(pchkpnt, 0x58C, int) > 0) + { + int j = 0; + LO **a = &STRUCT_OFFSET(pchkpnt, 0x590, LO *); + do + { + *a = PloCloneLo(*a, STRUCT_OFFSET(pchkpnt, 0x14, SW *), (ALO *)pchkpnt); + j++; + a++; + } while (j < STRUCT_OFFSET(pchkpnt, 0x58C, int)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", UpdateChkpnt__FP6CHKPNTf); diff --git a/src/P2/cnvo.c b/src/P2/cnvo.c index b1ff47bc..8ccdab79 100644 --- a/src/P2/cnvo.c +++ b/src/P2/cnvo.c @@ -33,4 +33,25 @@ void SetCnvoBeltSpeed(CNVO *pcnvo, float svBelt) ResolveAlo(pcnvo); } -INCLUDE_ASM("asm/nonmatchings/P2/cnvo", MatchCnvoScrollerToBeltSpeed__FP4CNVO); +void MatchCnvoScrollerToBeltSpeed(CNVO *pcnvo) +{ + int c = STRUCT_OFFSET(pcnvo, 0x27c, int); + if (c <= 0) + return; + + void **arr = &STRUCT_OFFSET(pcnvo, 0x280, void *); + int i = 0; + do + { + void *pelem = arr[i]; + if (STRUCT_OFFSET(pelem, 0x8, int) == 6) + { + STRUCT_OFFSET(pelem, 0x2c, float) = + -(STRUCT_OFFSET(pcnvo, 0x550, float) * STRUCT_OFFSET(pcnvo, 0x554, float)); + STRUCT_OFFSET(pelem, 0x30, float) = + -(STRUCT_OFFSET(pcnvo, 0x550, float) * STRUCT_OFFSET(pcnvo, 0x558, float)); + return; + } + i = i + 1; + } while (i < STRUCT_OFFSET(pcnvo, 0x27c, int)); +} diff --git a/src/P2/credit.c b/src/P2/credit.c index 80a06f51..cc0614a1 100644 --- a/src/P2/credit.c +++ b/src/P2/credit.c @@ -1,14 +1,66 @@ #include +#include +#include + +struct CREDIT; INCLUDE_ASM("asm/nonmatchings/P2/credit", InitCredit__FP6CREDIT5BLOTK); -INCLUDE_ASM("asm/nonmatchings/P2/credit", PostCreditLoad__FP6CREDIT); +void PostCreditLoad(CREDIT *pcredit) +{ + int i; + BLOT *pblot; + + PostBlotLoad((BLOT *)pcredit); + + pblot = (BLOT *)((char *)pcredit + 0x264); + for (i = 0; i < 4; i++) + { + pblot->pvtblot->pfnPostBlotLoad(pblot); + pblot->pte = 0; + STRUCT_OFFSET(pblot->pfont, 0x44, float) = 0.8f; + STRUCT_OFFSET(pblot->pfont, 0x48, float) = 0.8f; + SetBlotDtAppear(pblot, 1.0f); + SetBlotDtDisappear(pblot, 1.0f); + SetBlotDtVisible(pblot, 0.0f); + pblot = (BLOT *)((char *)pblot + 0x260); + } +} INCLUDE_ASM("asm/nonmatchings/P2/credit", SetCreditClock__FP6CREDITPf); INCLUDE_ASM("asm/nonmatchings/P2/credit", UpdateCredit__FP6CREDIT); -INCLUDE_ASM("asm/nonmatchings/P2/credit", DrawCredit__FP6CREDIT); +void DrawCredit(CREDIT *pcredit) +{ + extern int D_00275BEC; + + if (D_00275BEC == 1) + { + int i = 0; + float s = STRUCT_OFFSET(pcredit, 0x220, float); + + if (STRUCT_OFFSET(pcredit, 0x260, int) > 0) + { + char *pe = (char *)pcredit + 0x264; + do + { + float sSave = STRUCT_OFFSET(pe, 0x23C, float); + + STRUCT_OFFSET(pe, 0x220, float) = s; + STRUCT_OFFSET(pe, 0x21C, float) = STRUCT_OFFSET(pcredit, 0x21C, float); + STRUCT_OFFSET(pe, 0x23C, float) = sSave * g_rtClock; + + (*(void (**)(void *))(STRUCT_OFFSET(pe, 0x0, char *) + 0x24))(pe); + i++; + + STRUCT_OFFSET(pe, 0x23C, float) = sSave; + s = s + STRUCT_OFFSET(pe, 0x238, float); + pe += 0x260; + } while (i < STRUCT_OFFSET(pcredit, 0x260, int)); + } + } +} INCLUDE_ASM("asm/nonmatchings/P2/credit", PlaceCredit__FP6CREDITffi); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index db7da015..c285ee01 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -1,6 +1,7 @@ #include #include #include +#include /** * @todo Rename. @@ -93,7 +94,32 @@ extern "C" void FUN_0014c668(void *pv, int tnt) } } -INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); +extern "C" void FUN_0014c858(void *p); +extern "C" void FUN_0014cba8(void *p); + +void update_crbrain(CRBRAIN *p, float dt) +{ + OID oid; + + UpdateAlo(p, dt); + GetSmaCur(STRUCT_OFFSET(p, 0x42c, SMA *), &oid); + + if (oid == (OID)0x3fd) + { + CLOCK *pclock = &g_clock; + + if (STRUCT_OFFSET(p, 0x45c, float) < pclock->t) + FUN_0014c858(p); + + if (STRUCT_OFFSET(p, 0x460, float) < pclock->t) + FUN_0014cba8(p); + + PO *ppo = PpoCur(); + void *pvt = STRUCT_OFFSET(ppo, 0x0, void *); + void (*pfn)(PO *) = (void (*)(PO *))STRUCT_OFFSET(pvt, 0x144, void *); + pfn(ppo); + } +} extern int FUN_001e9970(); extern BLOT g_unkblot1; diff --git a/src/P2/difficulty.c b/src/P2/difficulty.c index 4fe892f3..208a7ae0 100644 --- a/src/P2/difficulty.c +++ b/src/P2/difficulty.c @@ -110,42 +110,27 @@ void OnDifficultyInitialTeleport(DIFFICULTY *pdifficulty) return; } -INCLUDE_ASM("asm/nonmatchings/P2/difficulty", OnDifficultyPlayerDeath); -#ifdef SKIP_ASM -/** - * @todo 88.43% matched. - */ -void OnDifficultyPlayerDeath(float scalar, DIFFICULTY* pdifficulty) +void OnDifficultyPlayerDeath(float scalar, DIFFICULTY *pdifficulty) { - DIFFICULTYLEVEL* pdifflevel = pdifficulty->pDifficultyLevel; - - // Get suck values for current level - float uSuckCur = g_plsCur->uSuck; - float duSuckDeath = pdifflevel->duSuckDeath; + DIFFICULTYLEVEL *pdifflevel = pdifficulty->pDifficultyLevel; - // Increase suck value - ChangeSuck(uSuckCur + scalar * duSuckDeath, pdifficulty); + ChangeSuck(g_plsCur->uSuck + scalar * STRUCT_OFFSET(pdifflevel, 0x10, float), pdifficulty); - // Update suckunknown_0x10 + int clife = g_pgsCur->clife; float result; - if (g_pgsCur->clife < 0) + if (clife < 0) { - // itgame over - result = pdifficulty->pDifficultyLevel->field18_0x40; + result = STRUCT_OFFSET(pdifficulty->pDifficultyLevel, 0x40, float); } else { - // not game over - result = pdifflevel->field17_0x3c; - if (g_pgsCur->clife <= pdifflevel->field21_0x4c) - { - result = result + pdifflevel->field22_0x50; - } + result = STRUCT_OFFSET(pdifflevel, 0x3c, float); + if (clife <= STRUCT_OFFSET(pdifflevel, 0x4c, int)) + result = result + STRUCT_OFFSET(pdifflevel, 0x50, float); } - result = GLimitLm(&g_lmZeroOne, g_plsCur->unk_suck_0x10 + scalar * result); - g_plsCur->unk_suck_0x10 = result; + + g_plsCur->unk_suck_0x10 = GLimitLm(&g_lmZeroOne, g_plsCur->unk_suck_0x10 + scalar * result); } -#endif INCLUDE_ASM("asm/nonmatchings/P2/difficulty", OnDifficultyTriggerCheckpoint__FP10DIFFICULTYP6CHKPNT); #ifdef SKIP_ASM diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 27f92b0a..0268817b 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -18,7 +18,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", InitEmitter__FP7EMITTER); INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitmeshFromBrx__FP8EMITMESHP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitblipColorsFromBrx__FP8EMITBLIPiP2LOP18CBinaryInputStream); +void LoadEmitblipColorsFromBrx(EMITBLIP *pemitblip, int crgba, LO *ploEmit, CBinaryInputStream *pbis) +{ + int i; + int cColor = (crgba > 0x1f) ? 0x20 : crgba; + + STRUCT_OFFSET(pemitblip, 0x4c, int) = cColor; + STRUCT_OFFSET(pemitblip, 0x50, RGBA *) = (RGBA *)PvAllocSwImpl(cColor * 4); + STRUCT_OFFSET(pemitblip, 0x54, int) = pbis->U8Read(); + + for (i = 0; i < crgba; i++) + { + uint rgba = pbis->U32Read(); + if (i < STRUCT_OFFSET(pemitblip, 0x4c, int)) + STRUCT_OFFSET(pemitblip, 0x50, RGBA *)[i] = (RGBA &)rgba; + } +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitterFromBrx__FP7EMITTERP18CBinaryInputStream); @@ -229,7 +244,33 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", ChooseEmitoPos__FP5EMITOiiP6VECTORT3) INCLUDE_ASM("asm/nonmatchings/P2/emitter", ConvertEmitoPosVec__FP5EMITOP6VECTORT1); -INCLUDE_ASM("asm/nonmatchings/P2/emitter", CalculateEmitvx__FiP2LMiP6EMITVX); +void CalculateEmitvx(int cParticlePerRing, LM *plmTilt, int cParticle, EMITVX *pemitvx) +{ + int cBatch; + int count; + float gNorm; + + if (cParticlePerRing > 0) + { + STRUCT_OFFSET(pemitvx, 0x0, int) = + (cParticlePerRing < cParticle) ? cParticlePerRing : cParticle; + } + else + { + STRUCT_OFFSET(pemitvx, 0x0, int) = cParticle; + } + + count = STRUCT_OFFSET(pemitvx, 0x0, int); + cBatch = (cParticle - 1 + count) / count; + + gNorm = RadNormalize(plmTilt->gMax - plmTilt->gMin); + + STRUCT_OFFSET(pemitvx, 0x8, float) = 6.2831855f / (float)STRUCT_OFFSET(pemitvx, 0x0, int); + STRUCT_OFFSET(pemitvx, 0x4, float) = gNorm / (float)cBatch; + STRUCT_OFFSET(pemitvx, 0xc, float) = + plmTilt->gMin + STRUCT_OFFSET(pemitvx, 0x4, float) * 0.5f; + STRUCT_OFFSET(pemitvx, 0x10, float) = GRandInRange(0.0f, 6.2831855f); +} INCLUDE_ASM("asm/nonmatchings/P2/emitter", ChooseEmitVelocity__FP6EMITVXffP2LMP6VECTORiT4); diff --git a/src/P2/fly.c b/src/P2/fly.c index f196b2e0..8e3974bb 100644 --- a/src/P2/fly.c +++ b/src/P2/fly.c @@ -1,10 +1,28 @@ #include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/fly", InitFly__FP3FLY); INCLUDE_ASM("asm/nonmatchings/P2/fly", LoadFlyFromBrx__FP3FLYP18CBinaryInputStream); -INCLUDE_ASM("asm/nonmatchings/P2/fly", CloneFly__FP3FLYT0); +void CloneFly(FLY *pfly, FLY *pflyBase) +{ + uint64_t tmp = STRUCT_OFFSET(pfly, 0x5dc, uint64_t); + CloneSo((SO *)pfly, (SO *)pflyBase); + STRUCT_OFFSET(pfly, 0x5dc, uint64_t) = tmp; + + if (STRUCT_OFFSET(pfly, 0x550, int) == 0) + { + StartSound((SFXID)0x41, (AMB **)((char *)pfly + 0x5e4), (ALO *)pfly, 0, + 700.0f, 10.0f, 1.0f, 0.0f, 0.0f, 0, 0); + } + else + { + if (FFindDlEntry((DL *)((char *)pfly->psw + 0x1c48), pfly)) + RemoveDlEntry((DL *)((char *)pfly->psw + 0x1c48), pfly); + } +} INCLUDE_ASM("asm/nonmatchings/P2/fly", FreezeFly__FP3FLYi); @@ -48,4 +66,26 @@ INCLUDE_ASM("asm/nonmatchings/P2/fly", FShouldFlyFlee__FP3FLY); INCLUDE_ASM("asm/nonmatchings/P2/fly", FFilterFly__FPvP2SO); -INCLUDE_ASM("asm/nonmatchings/P2/fly", FCheckFlyOpenSpaceBelow__FP3FLY); +int FCheckFlyOpenSpaceBelow(FLY *pfly) +{ + if (g_clock.t - STRUCT_OFFSET(pfly, 0x66c, float) < 0.05f) + return 0; + + int cpso; + SO **apso; + VECTOR *ppos = &STRUCT_OFFSET(pfly, 0x140, VECTOR); + + InitStackImpl(); + IntersectSwBoundingSphere(STRUCT_OFFSET(pfly, 0x14, SW *), NULL, ppos, + STRUCT_OFFSET(pfly, 0x64c, float), (PFNFILTER)FFilterFly, pfly, &cpso, &apso); + + qword qwBelow = STRUCT_OFFSET(pfly, 0x140, qword); + VECTOR *pposBelow = (VECTOR *)&qwBelow; + float zBelow = pposBelow->z - STRUCT_OFFSET(pfly, 0x64c, float); + pposBelow->z = zBelow; + SO *pso = PsoHitTestLineObjects(0, ppos, pposBelow, cpso, apso, NULL); + FreeStackImpl(); + + STRUCT_OFFSET(pfly, 0x66c, float) = g_clock.t; + return pso == NULL; +} diff --git a/src/P2/font.c b/src/P2/font.c index ac5cc46f..0cac1b12 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -2,6 +2,7 @@ #include #include #include +#include void StartupFont() { @@ -48,7 +49,29 @@ void CFont::CopyTo(CFont *pfontDest) pfontDest->m_z = this->m_z; } -INCLUDE_ASM("asm/nonmatchings/P2/font", SetupDraw__5CFontP8CTextBoxP4GIFS); +class CTextBox; + +void SetupDraw_CFont(CFont *self, CTextBox *ptb, GIFS *pgifs) __asm__("SetupDraw__5CFontP8CTextBoxP4GIFS"); +void SetupDraw_CFont(CFont *self, CTextBox *ptb, GIFS *pgifs) +{ + if (ptb) + { + float xLeft = STRUCT_OFFSET(ptb, 0x0, float); + float yTop = STRUCT_OFFSET(ptb, 0x4, float); + float xRight = xLeft + STRUCT_OFFSET(ptb, 0x8, float); + float yBottom = yTop + STRUCT_OFFSET(ptb, 0xc, float); + + int scaxRight = (int)xRight - 1; + int scayBottom = (int)(yBottom * 0.45454547f) - 1; + int scayTop = (int)(yTop * 0.45454547f); + int scaxLeft = (int)xLeft; + + pgifs->AddPrimPack(0, 1, 0xe); + pgifs->PackAD(0x40, + (ulong)scaxLeft | ((ulong)scaxRight << 16) | + ((ulong)scayTop << 32) | ((ulong)scayBottom << 48)); + } +} INCLUDE_ASM("asm/nonmatchings/P2/font", CleanupDraw__5CFontP8CTextBoxP4GIFS); @@ -117,7 +140,32 @@ float DxFromCh_CFontBrx(CFontBrx *self, char ch) return (float)STRUCT_OFFSET(self, 0x4, int) * STRUCT_OFFSET(self, 0x44, float); } -INCLUDE_ASM("asm/nonmatchings/P2/font", FEnsureLoaded__8CFontBrxP4GIFS); +int FEnsureLoaded_CFontBrx(CFontBrx *self, GIFS *pgifs) __asm__("FEnsureLoaded__8CFontBrxP4GIFS"); +int FEnsureLoaded_CFontBrx(CFontBrx *self, GIFS *pgifs) +{ + int fLoad = ((g_pfrmOpen->grffont & STRUCT_OFFSET(self, 0x80, int)) == 0); + + if (fLoad) + { + pgifs->EndDmaCnt(); + pgifs->AddDmaRefs(STRUCT_OFFSET(self, 0x68, int), STRUCT_OFFSET(self, 0x6c, QW *)); + + void *p54 = STRUCT_OFFSET(self, 0x54, void *); + pgifs->AddDmaRefs(STRUCT_OFFSET(p54, 0x14, int), STRUCT_OFFSET(p54, 0x10, QW *)); + + if (STRUCT_OFFSET(self, 0x58, void *) != 0) + { + pgifs->AddDmaRefs(STRUCT_OFFSET(self, 0x70, int), STRUCT_OFFSET(self, 0x74, QW *)); + void *p58 = STRUCT_OFFSET(self, 0x58, void *); + pgifs->AddDmaRefs(STRUCT_OFFSET(p58, 0xc, int), STRUCT_OFFSET(p58, 0x8, QW *)); + } + + pgifs->AddDmaCnt(); + g_pfrmOpen->grffont |= STRUCT_OFFSET(self, 0x80, int); + } + + return fLoad; +} INCLUDE_ASM("asm/nonmatchings/P2/font", SetupDraw__8CFontBrxP8CTextBoxP4GIFS); diff --git a/src/P2/frm.c b/src/P2/frm.c index ea7aff5a..733a1ecb 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -50,7 +50,24 @@ void EnsureVu1Code(VIFS *pvifs, void *pvStart, void *pvEnd) } } -INCLUDE_ASM("asm/nonmatchings/P2/frm", FinalizeFrameVifs__FP4VIFSPiPP2QW); +extern void *VU1_GlobMpg; +extern void *VU1_GlobMpgEnd; + +void FinalizeFrameVifs(VIFS *pvifs, int *pcqwVifs, QW **ppqwVifs) +{ + QW aqw[8]; + GIFS gifs = GIFS(); + + gifs.AllocStatic(8, aqw); + gifs.AddPrimPack(0, 1, 0x0e); + gifs.PackAD(0x61, 0); + gifs.AddPrimEnd(); + pvifs->AddVifFlush(); + pvifs->AddVifGifs(&gifs); + EnsureVu1Code(pvifs, &VU1_GlobMpg, &VU1_GlobMpgEnd); + pvifs->AddDmaEnd(); + pvifs->Detach(pcqwVifs, ppqwVifs); +} void FinalizeFrameGifs(GIFS *pgifs, int *pcqwGifs, QW **ppqwGifs) { @@ -100,7 +117,32 @@ void PrepareGsForFrameRender(FRM *pfrm) } } -INCLUDE_ASM("asm/nonmatchings/P2/frm", check_anticrack_antigrab__Fv); +extern "C" unsigned int D_002C3B00[]; +extern "C" unsigned int func_00100000[]; +extern "C" char D_00148D74[]; +extern "C" int D_00262310; + +void check_anticrack_antigrab() +{ + unsigned int *pwTable = D_002C3B00; + int cb = (int)D_00148D74; + unsigned int crc = 0xFFFFFFFF; + unsigned int *pw = func_00100000; + + while (cb > 0) + { + unsigned int w = *pw; + cb -= 4; + pw += 1; + crc = pwTable[(crc ^ w) & 0xFF] ^ (crc >> 8); + crc = pwTable[(crc ^ (w >> 8)) & 0xFF] ^ (crc >> 8); + crc = pwTable[(crc ^ (w >> 16)) & 0xFF] ^ (crc >> 8); + crc = pwTable[(crc ^ (w >> 24)) & 0xFF] ^ (crc >> 8); + } + + if (crc != 0) + D_00262310 = 1; +} INCLUDE_ASM("asm/nonmatchings/P2/frm", FrameRenderLoop__FPv); diff --git a/src/P2/game.c b/src/P2/game.c index 44c127cd..48ba8437 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -59,11 +59,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", tally_world_completion); INCLUDE_ASM("asm/nonmatchings/P2/game", get_game_completion__Fv); -INCLUDE_ASM("asm/nonmatchings/P2/game", UnlockIntroCutsceneFromWid__Fi); -#ifdef SKIP_ASM -/** - * @todo Close to matching but there's a problem with the rodata. - */ void UnlockIntroCutsceneFromWid(int wid) { /* Check the unlocked cutscene by setting the corresponding @@ -91,9 +86,31 @@ void UnlockIntroCutsceneFromWid(int wid) g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x1000; } } -#endif // SKIP_ASM -INCLUDE_ASM("asm/nonmatchings/P2/game", DefeatBossFromWid); +void DefeatBossFromWid(int wid) +{ + g_pgsCur->aws[wid].fws = (FWS)(g_pgsCur->aws[wid].fws | 0x20); + + switch (wid) + { + case 1: + g_pgsCur->unlocked_cutscenes |= 0x20; + break; + case 2: + g_pgsCur->unlocked_cutscenes |= 0x80; + break; + case 3: + g_pgsCur->unlocked_cutscenes |= 0x200; + g_pgsCur->grfvault |= 0x10000; + break; + case 4: + g_pgsCur->unlocked_cutscenes |= 0x800; + break; + case 5: + UnlockEndgameCutscenesFromFgs((FGS)0x2); + break; + } +} extern "C" void UnlockEndgameCutscenesFromFgs(FGS fgs) { diff --git a/src/P2/jsg.c b/src/P2/jsg.c index f472771e..e65b242c 100644 --- a/src/P2/jsg.c +++ b/src/P2/jsg.c @@ -49,7 +49,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/jsg", NextJsgJsge__FP3JSG); INCLUDE_ASM("asm/nonmatchings/P2/jsg", FIsJsgJsgeComplete__FP3JSGP4JSGE); -INCLUDE_ASM("asm/nonmatchings/P2/jsg", UpdateJsgJsge__FP3JSG); +void UpdateJsgJsge(JSG *pjsg) +{ + JSGE *pjsgeJoy; + + if (pjsg->ijsgeCur < 0) + { + if (pjsg->cjsge > 0) + NextJsgJsge(pjsg); + } + + while (pjsg->ijsgeCur < pjsg->cjsge) + { + JSGE *pjsge = &pjsg->ajsge[pjsg->ijsgeCur]; + if (pjsge->fAsync || FIsJsgJsgeComplete(pjsg, pjsge)) + NextJsgJsge(pjsg); + else + break; + } + + pjsgeJoy = pjsg->pjsgeJoy; + if (pjsgeJoy != NULL) + { + if (!FIsJsgJsgeComplete(pjsg, pjsgeJoy)) + pjsg->pjsgeJoy = NULL; + } +} INCLUDE_ASM("asm/nonmatchings/P2/jsg", ReadJsgJoystick__FP3JSGP3JOY); diff --git a/src/P2/light.c b/src/P2/light.c index 802b789a..207485f5 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -4,7 +4,28 @@ #include #include -INCLUDE_ASM("asm/nonmatchings/P2/light", InitLight__FP5LIGHT); +extern VU_VECTOR g_normalZ; +extern VU_VECTOR g_normalY; + +void InitLight(LIGHT *plight) +{ + uint64_t grfalo = STRUCT_OFFSET(plight, 0x2c8, uint64_t); + STRUCT_OFFSET(plight, 0x2d0, int) = 0; + STRUCT_OFFSET(plight, 0x2c8, uint64_t) = (grfalo & ~0x30000000000ULL) | (0x8000ULL << 0x19); + + STRUCT_OFFSET(plight, 0x320, VU_VECTOR) = g_normalZ; + STRUCT_OFFSET(plight, 0x340, VU_VECTOR) = g_normalY; + + STRUCT_OFFSET(plight, 0x330, float) = 200.0f; + STRUCT_OFFSET(plight, 0x334, float) = 2000.0f; + STRUCT_OFFSET(plight, 0x2fc, float) = 240.0f; + STRUCT_OFFSET(plight, 0x300, float) = 180.0f; + STRUCT_OFFSET(plight, 0x338, float) = 60.0f; + STRUCT_OFFSET(plight, 0x2f8, float) = 180.0f; + + RebuildLightFrustrum(plight); + InitAlo(plight); +} void UpdateLightXfWorldHierarchy(LIGHT *plight) { diff --git a/src/P2/missile.c b/src/P2/missile.c index 38b04b4a..86ced493 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -1,5 +1,6 @@ #include #include +#include void InitMissile(MISSILE *pmissile) { @@ -35,7 +36,39 @@ INCLUDE_ASM("asm/nonmatchings/P2/missile", FireMissile__FP7MISSILEP3ALOP6VECTOR) INCLUDE_ASM("asm/nonmatchings/P2/missile", RenderMissileAll__FP7MISSILEP2CMP2RO); -INCLUDE_ASM("asm/nonmatchings/P2/missile", FUN_0018dc88); +extern "C" int FUN_0018dc88(SO *pso, SO *psoOther) +{ + int i; + + if (psoOther == STRUCT_OFFSET(pso, 0x6e4, SO *)) + return 1; + + if (STRUCT_OFFSET(pso, 0x6bc, int) > 0) + { + OID *aoid = &STRUCT_OFFSET(pso, 0x6c0, OID); + i = 0; + do + { + if (FMatchesLoName((LO *)psoOther, aoid[i])) + return 1; + i++; + } while (i < STRUCT_OFFSET(pso, 0x6bc, int)); + } + + if (STRUCT_OFFSET(pso, 0x6d0, int) > 0) + { + CID *acid = &STRUCT_OFFSET(pso, 0x6d4, CID); + i = 0; + do + { + if (FIsBasicDerivedFrom((BASIC *)psoOther, acid[i])) + return 1; + i++; + } while (i < STRUCT_OFFSET(pso, 0x6d0, int)); + } + + return FIgnoreSoIntersection(pso, psoOther); +} extern "C" void FUN_0018dd50(void * p, int val) { diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 49df3573..e2a6325e 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -93,6 +93,7 @@ class CQueueOutputIop void Init(int nParam1, int nParam2); void Reset(); + void Update(); }; #endif // CQUEUEOUTPUTIOP_DEFINED @@ -196,7 +197,23 @@ extern "C" void Close__10CMpegAudio(void *pthis) INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FAccept__10CMpegAudioiPUc); -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__10CMpegAudio); +void CMpegAudio::Update() +{ + if (unk_0x0 == 2) + { + bqOut.CbDrain(qoi.unk_0x14, (CQueueOutput *)&qoi); + if (qoi.unk_0x14 == 0) + { + snd_StartMovieSound(qoi.unk_0x4, qoi.unk_0x8, qoi.unk_0x4, 0, 0); + unk_0x0 = 3; + } + } + else if (unk_0x0 == 3) + { + qoi.Update(); + bqOut.CbDrain(qoi.unk_0x14, (CQueueOutput *)&qoi); + } +} struct sceMpeg; struct sceMpegCbDataStr; diff --git a/src/P2/po.c b/src/P2/po.c index 9feb986b..9233f57c 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -28,7 +28,36 @@ void ClonePo(PO *ppo, PO *ppoBase) } } -INCLUDE_ASM("asm/nonmatchings/P2/po", HandlePoMessage__FP2PO5MSGIDPv); +void HandlePoMessage(PO *ppo, MSGID msgid, void *pv) +{ + HandleAloMessage((ALO *)ppo, msgid, pv); + + switch (msgid) + { + case MSGID_water_left: + StopSound(STRUCT_OFFSET(ppo, 0x574, AMB *), 0); + break; + case MSGID_rip_removed: + { + int i; + int c = STRUCT_OFFSET(ppo, 0x5D0, int); + void **a = &STRUCT_OFFSET(ppo, 0x5AC, void *); + + if (c > 0) + { + for (i = 0; i < c; i++) + { + if (a[i] == pv) + { + a[i] = 0; + break; + } + } + } + } + break; + } +} void OnPoActive(PO *ppo, int fActive, PO *ppoOther) { diff --git a/src/P2/render.c b/src/P2/render.c index 3b6e84a3..20db4519 100644 --- a/src/P2/render.c +++ b/src/P2/render.c @@ -75,8 +75,6 @@ void EnsureCameraGlobals() /** * @todo 95.71% match. Missing two instructions. */ -INCLUDE_ASM("asm/nonmatchings/P2/render", EnsureScreenCleared__Fv); -#ifdef SKIP_ASM void EnsureScreenCleared() { if (!s_fFBCleared) @@ -84,6 +82,7 @@ void EnsureScreenCleared() g_vifs.AddDmaCnt(); g_vifs.AddVifDirect(0x2c, g_aqwGifsClearAll, 0); g_vifs.EndDmaCnt(); + s_fZBCleared = 1; s_fFBCleared = 1; } else if (!s_fZBCleared) @@ -95,7 +94,6 @@ void EnsureScreenCleared() s_fZBCleared = 1; } } -#endif // SKIP_ASM void SetupRpDynamicTexture(RPL *prpl) { diff --git a/src/P2/shadow.c b/src/P2/shadow.c index 7cef73fb..fd653d27 100644 --- a/src/P2/shadow.c +++ b/src/P2/shadow.c @@ -4,7 +4,33 @@ INCLUDE_ASM("asm/nonmatchings/P2/shadow", InitShadow__FP6SHADOW); -INCLUDE_ASM("asm/nonmatchings/P2/shadow", PostShadowLoad__FP6SHADOW); +extern "C" int D_002626D0; +extern "C" SUR D_0027DC20[]; + +void PostShadowLoad(SHADOW *pshadow) +{ + if (pshadow->pshd == NULL) + { + SetShadowShader(pshadow, OID_shd_stock_shadow); + } + + if (!FShadowRadiusSet(pshadow)) + { + SetShadowNearRadius(pshadow, 100.0f); + SetShadowFarRadius(pshadow, 400.0f); + } + + if (!(pshadow->pshd->grfzon & 0x10000000)) + { + if (D_002626D0 < 0x4000) + { + SUR *psur = &D_0027DC20[D_002626D0]; + D_002626D0 += 1; + STRUCT_OFFSET(pshadow, 0x2D0, SUR *) = psur; + memset(psur, 0, sizeof(SUR)); + } + } +} void InvalidateShadowVifs(SHADOW *pshadow) { diff --git a/src/P2/suv.c b/src/P2/suv.c index f69193d3..d92f1cd2 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include INCLUDE_ASM("asm/nonmatchings/P2/suv", InitSuv__FP3SUV); @@ -31,7 +34,32 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvLine__FP3SUVPi); INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvHeading__FP3SUV); -INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvWheels__FP3SUV); +void UpdateSuvWheels(SUV *psuv) +{ + extern float D_002754F8; + extern float D_002754F4; + extern SMP D_002754E8; + float rad; + char *p; + int i; + + rad = atan2f(STRUCT_OFFSET(psuv, 0xD4, float), STRUCT_OFFSET(psuv, 0xD0, float)); + rad = RadNormalize(STRUCT_OFFSET(psuv, 0x694, float) - rad); + rad = GLimitAbs(D_002754F8 * rad, D_002754F4); + STRUCT_OFFSET(psuv, 0x69C, float) = RadSmooth(STRUCT_OFFSET(psuv, 0x69C, float), rad, g_clock.dt, &D_002754E8, NULL); + + p = (char *)psuv + 0x6B0; + for (i = 0; i < 4; i++) + { + float gDiv; + if (i < 2) + gDiv = STRUCT_OFFSET(psuv, 0x610, float); + else + gDiv = STRUCT_OFFSET(psuv, 0x614, float); + *(float *)(p + 0x50) = STRUCT_OFFSET(psuv, 0x698, float) / gDiv; + p += 0x60; + } +} INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvExpls__FP3SUV); diff --git a/src/P2/sw.c b/src/P2/sw.c index cb78c409..a15e0fda 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -13,6 +13,7 @@ #include #include #include +#include extern SW *g_psw; extern int g_fLoadDebugInfo; @@ -194,7 +195,39 @@ void FreeSwStsoList(SW *psw, STSO *pstsoFirst) } } -INCLUDE_ASM("asm/nonmatchings/P2/sw", AddSwProxySource__FP2SWP2LOi); +struct PSL +{ + int cplo; + LO **aplo; +} __attribute__((packed)); + +void AddSwProxySource(SW *psw, LO *ploProxySource, int cploClone) +{ + PSL psl; + + cploClone -= 1; + psl.cplo = cploClone; + + if (cploClone > 0) + { + LO **aplo = (LO **)PvAllocSwImpl(cploClone << 2); + psl.aplo = aplo; + + if (cploClone > 0) + { + int i = 0; + do + { + aplo[i] = PloCloneLo(ploProxySource, psw, NULL); + i++; + } while (i < cploClone); + } + } + + int cpsl = STRUCT_OFFSET(psw, 0x1EFC, int); + STRUCT_OFFSET(psw, cpsl * 8 + 0x1F00, PSL) = psl; + STRUCT_OFFSET(psw, 0x1EFC, int) = cpsl + 1; +} LO *PloGetSwProxySource(SW *psw, int ipsl) { @@ -280,7 +313,24 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FClipLineHomogeneous__FP7VECTOR4); INCLUDE_ASM("asm/nonmatchings/P2/sw", DrawLineWorld__FP6VECTORT0G4RGBAP2CMi); -INCLUDE_ASM("asm/nonmatchings/P2/sw", DrawAxesWorld__FP6VECTORP7MATRIX3fP2CMi); +void DrawLineWorld(VECTOR *ppos1, VECTOR *ppos2, RGBA rgba, CM *pcm, int fDepthTest); + +void DrawAxesWorld(VECTOR *ppos, MATRIX3 *pmat, float sScale, CM *pcm, int fDepthTest) +{ + VECTOR4 apos[10]; + RGBA rgba; + + TesselateBezier(sScale, 0.0f, sScale, ppos, (VECTOR *)pmat, + (VECTOR *)((char *)0), (VECTOR *)((char *)0), 10, (VECTOR *)apos); + + rgba = *(RGBA *)pcm; + + for (int i = 1; i < 10; i++) + { + DrawLineWorld((VECTOR *)&apos[i - 1], (VECTOR *)&apos[i], rgba, + (CM *)(long)fDepthTest, 1); + } +} void SetSwIllum(SW *psw, float uMidtone) { diff --git a/src/P2/tank.c b/src/P2/tank.c index a4244270..9715eaf3 100644 --- a/src/P2/tank.c +++ b/src/P2/tank.c @@ -88,7 +88,53 @@ INCLUDE_ASM("asm/nonmatchings/P2/tank", FUN_001dfa10); INCLUDE_ASM("asm/nonmatchings/P2/tank", AdjustTankNewXp__FP4TANKP2XPi); +#ifndef SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/tank", HandleTankMessage__FP4TANK5MSGIDPv); +#else +void HandleTankMessage(TANK *ptank, MSGID msgid, void *pv) +{ + OID oidCur; + OID oidGoal; + + switch (msgid) + { + case (MSGID)0x14: + if (pv == STRUCT_OFFSET(ptank, 0x75C, void *)) + { + GetSmaCur((SMA *)pv, &oidCur); + GetSmaGoal(STRUCT_OFFSET(ptank, 0x75C, SMA *), &oidGoal); + } + break; + + case (MSGID)0x13: + { + SMA *psma = STRUCT_OFFSET(ptank, 0x75C, SMA *); + if (psma != NULL) + { + if (STRUCT_OFFSET(pv, 0x0, ASEGA *) == psma->pasegaCur) + { + int label = STRUCT_OFFSET(pv, 0x8, int); + if (label != 0x15E) + { + if (label == 0x15F) + { + STRUCT_OFFSET(ptank, 0x738, int) = 0; + } + } + else + { + STRUCT_OFFSET(ptank, 0x738, int) = 1; + } + } + } + break; + } + } + + + HandlePoMessage(ptank, msgid, pv); +} +#endif JTHS JthsCurrentTank(TANK *ptank) { diff --git a/src/P2/tn.c b/src/P2/tn.c index 69eb59b3..ef4ab94c 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include extern TNFN D_00275980; @@ -13,7 +15,33 @@ TNFN *PtnfnFromTn(TN *ptn) INCLUDE_ASM("asm/nonmatchings/P2/tn", GetTnfnNose__FP4TNFNP6CPDEFIP6VECTORP2TN); -INCLUDE_ASM("asm/nonmatchings/P2/tn", InitTn__FP2TN); +struct TNFN_DATA { char rgb[0x90]; }; + +void InitTn(TN *ptn) +{ + extern VECTOR D_00275A10; + extern char D_00275A20[8]; + uint64_t flags; + + InitAlo(ptn); + + *(struct TNFN_DATA *)((char *)ptn + 0x2F0) = *(struct TNFN_DATA *)&D_00275980; + + flags = STRUCT_OFFSET(ptn, 0x2C8, uint64_t); + flags &= ~((uint64_t)0x300 << 32); + flags |= ((uint64_t)0x8000 << 25); + + STRUCT_OFFSET(ptn, 0x420, float) = 2.0f; + STRUCT_OFFSET(ptn, 0x424, float) = 1.0f; + STRUCT_OFFSET(ptn, 0x2C8, uint64_t) = flags; + STRUCT_OFFSET(ptn, 0x428, float) = 2.0f; + STRUCT_OFFSET(ptn, 0x42C, float) = 1.0f; + STRUCT_OFFSET(ptn, 0x430, int) = -1; + + *(VECTOR *)((char *)ptn + 0x450) = D_00275A10; + *(uint64_t *)((char *)ptn + 0x460) = *(uint64_t *)D_00275A20; + STRUCT_OFFSET(ptn, 0x398, int) = -1; +} void OnTnRemove(TN *ptn) { @@ -29,7 +57,32 @@ void PostTnLoad(TN *ptn) PostAloLoad(ptn); } -INCLUDE_ASM("asm/nonmatchings/P2/tn", SetTnTns__FP2TN3TNS); +void SetTnTns(TN *ptn, TNS tns) +{ + if (STRUCT_OFFSET(ptn, 0x394, TNS) == tns) + return; + + if (tns == TNS_Out) + { + RevokeCmPolicy(g_pcm, 8, CPP_Nil, NULL, NULL, ptn); + HandleLoSpliceEvent(ptn, 3, 0, NULL); + STRUCT_OFFSET(ptn, 0x394, TNS) = tns; + } + else if (tns == TNS_In) + { + SetCmPolicy(g_pcm, (CPP)(STRUCT_OFFSET(ptn, 0x388, int) + 2), + &STRUCT_OFFSET(g_pcm, 0x520, CPLCY), + STRUCT_OFFSET(ptn, 0x2D0, SO *), ptn); + HandleLoSpliceEvent(ptn, 2, 0, NULL); + STRUCT_OFFSET(ptn, 0x394, TNS) = tns; + } + else + { + STRUCT_OFFSET(ptn, 0x394, TNS) = tns; + } + + STRUCT_OFFSET(ptn, 0x39C, float) = g_clock.t; +} /** * @todo Rename. @@ -46,7 +99,38 @@ void FUN_001e2840(TN *ptn, TNS tns) UpdateTnCallback(ptn, MSGID_callback, NULL); } -INCLUDE_ASM("asm/nonmatchings/P2/tn", UpdateTnCallback__FP2TN5MSGIDPv); +void UpdateTnCallback(TN *ptn, MSGID msgid, void *pv) +{ + VECTOR posLocal; + TNS tns; + PO *ppo; + + ppo = PpoCur(); + if (ppo == NULL) + return; + + if (ppo != STRUCT_OFFSET(ptn, 0x2D0, PO *)) + { + SetTnTns(ptn, TNS_Out); + STRUCT_OFFSET(ptn, 0x2D0, PO *) = ppo; + } + + tns = STRUCT_OFFSET(ptn, 0x398, TNS); + if (tns == TNS_Nil) + { + ConvertAloPos(NULL, ptn, (VECTOR *)((char *)ppo + 0x140), &posLocal); + tns = (TNS)(FCheckTbspPoint(STRUCT_OFFSET(ptn, 0x2E0, TBSP *), &posLocal) != 0); + } + + if (STRUCT_OFFSET(ptn, 0x384, int) == 0 && ppo == (PO *)g_pjt && + STRUCT_OFFSET(ppo, 0x2220, int) == 2 && g_pcm->field41_0x224 == 0 && + STRUCT_OFFSET(ptn, 0x398, TNS) == TNS_Nil) + { + return; + } + + SetTnTns(ptn, tns); +} void UpdateTn(TN *ptn, float dt) { diff --git a/src/P2/ub.c b/src/P2/ub.c index ca3f7d3a..2cb390dc 100644 --- a/src/P2/ub.c +++ b/src/P2/ub.c @@ -2,7 +2,39 @@ INCLUDE_ASM("asm/nonmatchings/P2/ub", InitUbg__FP3UBG); +#ifndef SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/ub", PostUbgLoad__FP3UBG); +#else +extern SNIP D_00275B60; +void FUN_001ddc38(void *pv, void *pvBlot); + +void PostUbgLoad(UBG *pubg) +{ + SnipAloObjects((ALO *)pubg, 8, &D_00275B60); + FUN_001ddc38(STRUCT_OFFSET(pubg, 0x14, void *), pubg); + + if (STRUCT_OFFSET(pubg, 0xC50, void *) != NULL) + { + STRUCT_OFFSET(pubg, 0xC54, SMA *) = + PsmaApplySm(STRUCT_OFFSET(pubg, 0xC50, SM *), NULL, (OID)0x2D7, 0); + } + + STRUCT_OFFSET(pubg, 0xC90, int) = 4; + + { + int *pichk = &STRUCT_OFFSET(pubg, 0xC80, int); + int i = 0; + do + { + *pichk = IchkAllocChkmgr(&g_chkmgr); + i++; + pichk++; + } while ((uint)i < 4); + } + + PostGomerLoad(pubg); +} +#endif INCLUDE_ASM("asm/nonmatchings/P2/ub", PsoPadUbgClosest__FP3UBGP6VECTOR); diff --git a/src/P2/wipe.c b/src/P2/wipe.c index cf7a8d64..14e89a76 100644 --- a/src/P2/wipe.c +++ b/src/P2/wipe.c @@ -18,32 +18,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/wipe", UpdateWipe__FP4WIPEP3JOY); /** * @todo 94.58% match. The order of the checks might be wrong. */ -INCLUDE_ASM("asm/nonmatchings/P2/wipe", DrawWipe__FP4WIPE); -#ifdef SKIP_ASM void DrawWipe(WIPE *pwipe) { - if (!g_psw || !g_pwipe) + if (g_psw == NULL || g_pwipe == NULL) { return; } WIPEK wipek = pwipe->wipek; - if (wipek != WIPEK_Keyhole) + if (wipek == WIPEK_Keyhole) { - if (wipek > WIPEK_Keyhole || wipek == WIPEK_Fade) + if (g_pkeyhole != NULL) { + DrawKeyhole(g_pkeyhole, pwipe->uBlack); return; } } - if (g_pkeyhole) + else if (wipek >= WIPEK_WorldMap || wipek != WIPEK_Fade) { - DrawKeyhole(g_pkeyhole, pwipe->uBlack); return; } FillScreenRect(0, 0, 0, (int)(pwipe->uBlack * 255.0f), 0.0f, 0.0f, 640.0f, 492.80002f, &g_gifs); } -#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/wipe", ActivateWipe__FP4WIPEP5TRANS5WIPEK); From 11862c535633a9f7cd07ca7bede8f4f665ee65f8 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Thu, 18 Jun 2026 00:10:54 +0200 Subject: [PATCH 121/134] Recover green build from broken "wip" commit The previous commit (5a38764a "wip: more function matching") did not build and, once made to build, produced a binary ~64% different from the ROM: it "finished" 37 functions (deleted INCLUDE_ASM) of which most did not actually match, plus left several compile/link breakages. HEAD~1 (wave-9) builds byte-perfect, so the damage was isolated to that one commit. This restores out/SCUS_971.98: OK by: - Reverting all 37 finished functions to in-progress form (INCLUDE_ASM + #ifdef SKIP_ASM-wrapped C), preserving the C drafts as diff targets. The dual-build flagged 14 as matching, but 7 of those were false matches (size-shifters: ProjectActPose, UpdateBarrier, MatchCnvoScrollerToBeltSpeed, check_anticrack_antigrab, AddSwProxySource, InitTn, DrawWipe) and the rest caused residual rodata/assembler-state side effects, so all were reverted. - Reverting two game.c switch functions (UnlockIntroCutsceneFromWid, DefeatBossFromWid) whose ROM jump tables dangle when built from C. - Reverting header perturbations no longer needed (sw.h PFNFILTER, act.c clock.h include, difficulty.h extern "C") now that their callers are asm. - Keeping harmless build-enabling decls (mpeg CMpegAudio::Update, shadow memset include) so the wrapped drafts still dual-build. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/act.c | 4 +++- src/P2/asega.c | 3 +++ src/P2/barrier.c | 3 +++ src/P2/bbmark.c | 3 +++ src/P2/brx.c | 3 +++ src/P2/cd.c | 3 +++ src/P2/chkpnt.c | 6 +++++ src/P2/cnvo.c | 3 +++ src/P2/credit.c | 6 +++++ src/P2/crusher.c | 5 +++- src/P2/difficulty.c | 5 +++- src/P2/emitter.c | 6 +++++ src/P2/fly.c | 6 +++++ src/P2/font.c | 3 +++ src/P2/frm.c | 6 +++++ src/P2/game.c | 56 ++++----------------------------------------- src/P2/jsg.c | 3 +++ src/P2/light.c | 3 +++ src/P2/missile.c | 3 +++ src/P2/mpeg.c | 4 ++++ src/P2/po.c | 3 +++ src/P2/render.c | 3 +++ src/P2/shadow.c | 4 ++++ src/P2/suv.c | 3 +++ src/P2/sw.c | 6 +++++ src/P2/tn.c | 9 ++++++++ src/P2/wipe.c | 3 +++ 27 files changed, 111 insertions(+), 54 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index b138b4d3..f33e2aa2 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -146,6 +145,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/act", ProjectActRotation__FP3ACT); extern SMP D_00260E60; +INCLUDE_ASM("asm/nonmatchings/P2/act", ProjectActPose__FP3ACTi); +#ifdef SKIP_ASM void ProjectActPose(ACT *pact, int ipose) { float g = (*(float (**)(ACT *))((char *)pact->pvtact + 0x20))(pact); @@ -170,6 +171,7 @@ void ProjectActPose(ACT *pact, int ipose) GSmooth(*(float *)((char *)ag + off), g, dt, &D_00260E60, NULL); } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/act", PredictAloPosition__FP3ALOfP6VECTORT2); diff --git a/src/P2/asega.c b/src/P2/asega.c index 66eb436c..fae16ede 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -30,6 +30,8 @@ void SetAsegaHandsOff(ASEGA *pasega, int fHandsOff) pasega->fHandsOff = fHandsOff; } +INCLUDE_ASM("asm/nonmatchings/P2/asega", UpdateAsegaIeaCur__FP5ASEGA); +#ifdef SKIP_ASM void UpdateAsegaIeaCur(ASEGA *pasega) { void *paseg = STRUCT_OFFSET(pasega, 0x8, void *); @@ -80,6 +82,7 @@ void UpdateAsegaIeaCur(ASEGA *pasega) STRUCT_OFFSET(pasega, 0x20, int) = i + 1; } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/asega", PactsegFindAsega__FP5ASEGA3OID); diff --git a/src/P2/barrier.c b/src/P2/barrier.c index 8e6aa9c0..550fdd31 100644 --- a/src/P2/barrier.c +++ b/src/P2/barrier.c @@ -21,6 +21,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/barrier", PostBarrierLoad__FP7BARRIER); extern VECTOR D_00248D30; +INCLUDE_ASM("asm/nonmatchings/P2/barrier", UpdateBarrier__FP7BARRIERf); +#ifdef SKIP_ASM void UpdateBarrier(BARRIER *pbarrier, float dt) { UpdateSo(pbarrier, dt); @@ -63,6 +65,7 @@ void UpdateBarrier(BARRIER *pbarrier, float dt) STRUCT_OFFSET(pbarrier, 0x5A4, void *) = pvResult; } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/barrier", FIgnoreBarrierIntersection__FP7BARRIERP2SO); diff --git a/src/P2/bbmark.c b/src/P2/bbmark.c index ff1d7b38..85c57a9c 100644 --- a/src/P2/bbmark.c +++ b/src/P2/bbmark.c @@ -77,6 +77,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/bbmark", RecalcSwXpAll__FP2SWi); extern void UpdateSwPox(SW *, OXA *, OXA *, unsigned char, unsigned char); +INCLUDE_ASM("asm/nonmatchings/P2/bbmark", RecalcSwOxfFilterForObject__FP2SWP2SO); +#ifdef SKIP_ASM void RecalcSwOxfFilterForObject(SW *psw, SO *pso) { OXA *poxa; @@ -107,3 +109,4 @@ void RecalcSwOxfFilterForObject(SW *psw, SO *pso) poxa = poxa->poxaNext; } } +#endif // SKIP_ASM diff --git a/src/P2/brx.c b/src/P2/brx.c index 32b3de4a..94f8f3a4 100644 --- a/src/P2/brx.c +++ b/src/P2/brx.c @@ -67,6 +67,8 @@ struct LODEFTAB extern "C" LODEFTAB D_00244950[]; +INCLUDE_ASM("asm/nonmatchings/P2/brx", SetLoDefaults__FP2LO); +#ifdef SKIP_ASM void SetLoDefaults(LO *plo) { CID cid = plo->pvtlo->cid; @@ -88,3 +90,4 @@ void SetLoDefaults(LO *plo) } while (ceopid != 0); } } +#endif // SKIP_ASM diff --git a/src/P2/cd.c b/src/P2/cd.c index 77cf9091..3dc49bd3 100644 --- a/src/P2/cd.c +++ b/src/P2/cd.c @@ -48,6 +48,8 @@ extern char D_00249E28[]; extern char D_00249E30[]; extern char D_00249E38[]; +INCLUDE_ASM("asm/nonmatchings/P2/cd", CdPath__FPcT0i); +#ifdef SKIP_ASM void CdPath(char *pchzDest, char *pchzPath, int fIncludeDevice) { char achz[0x100]; @@ -76,6 +78,7 @@ void CdPath(char *pchzDest, char *pchzPath, int fIncludeDevice) } sprintf(pchzDest, D_00249E28, pchzDevice, achz); } +#endif // SKIP_ASM void ReadCd(uint isector, uint csector, void *pv) { diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index 6fb89601..3b8bbe5b 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -39,6 +39,8 @@ void ResetChkmgrCheckpoints(CHKMGR *pchkmgr) } #endif +INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", SaveChkmgrCheckpoint__FP6CHKMGR3OIDT1); +#ifdef SKIP_ASM void SaveChkmgrCheckpoint(CHKMGR *pchkmgr, OID oidWarp, OID oidWarpContext) { STRUCT_OFFSET(pchkmgr, 0x20C, int) = 0; @@ -47,6 +49,7 @@ void SaveChkmgrCheckpoint(CHKMGR *pchkmgr, OID oidWarp, OID oidWarpContext) STRUCT_OFFSET(pchkmgr, 0x424, int) = oidWarp; STRUCT_OFFSET(pchkmgr, 0x428, int) = oidWarpContext; } +#endif // SKIP_ASM void ReturnChkmgrToCheckpoint(CHKMGR *pchkmgr) { @@ -116,6 +119,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", BindChkpnt__FP6CHKPNT); INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", PostChkpntLoad__FP6CHKPNT); +INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", CloneChkpnt__FP6CHKPNTT0); +#ifdef SKIP_ASM void CloneChkpnt(CHKPNT *pchkpnt, CHKPNT *pchkpntBase) { int i = 0; @@ -150,6 +155,7 @@ void CloneChkpnt(CHKPNT *pchkpnt, CHKPNT *pchkpntBase) } while (j < STRUCT_OFFSET(pchkpnt, 0x58C, int)); } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", UpdateChkpnt__FP6CHKPNTf); diff --git a/src/P2/cnvo.c b/src/P2/cnvo.c index 8ccdab79..1147fd18 100644 --- a/src/P2/cnvo.c +++ b/src/P2/cnvo.c @@ -33,6 +33,8 @@ void SetCnvoBeltSpeed(CNVO *pcnvo, float svBelt) ResolveAlo(pcnvo); } +INCLUDE_ASM("asm/nonmatchings/P2/cnvo", MatchCnvoScrollerToBeltSpeed__FP4CNVO); +#ifdef SKIP_ASM void MatchCnvoScrollerToBeltSpeed(CNVO *pcnvo) { int c = STRUCT_OFFSET(pcnvo, 0x27c, int); @@ -55,3 +57,4 @@ void MatchCnvoScrollerToBeltSpeed(CNVO *pcnvo) i = i + 1; } while (i < STRUCT_OFFSET(pcnvo, 0x27c, int)); } +#endif // SKIP_ASM diff --git a/src/P2/credit.c b/src/P2/credit.c index cc0614a1..bca7f865 100644 --- a/src/P2/credit.c +++ b/src/P2/credit.c @@ -6,6 +6,8 @@ struct CREDIT; INCLUDE_ASM("asm/nonmatchings/P2/credit", InitCredit__FP6CREDIT5BLOTK); +INCLUDE_ASM("asm/nonmatchings/P2/credit", PostCreditLoad__FP6CREDIT); +#ifdef SKIP_ASM void PostCreditLoad(CREDIT *pcredit) { int i; @@ -26,11 +28,14 @@ void PostCreditLoad(CREDIT *pcredit) pblot = (BLOT *)((char *)pblot + 0x260); } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/credit", SetCreditClock__FP6CREDITPf); INCLUDE_ASM("asm/nonmatchings/P2/credit", UpdateCredit__FP6CREDIT); +INCLUDE_ASM("asm/nonmatchings/P2/credit", DrawCredit__FP6CREDIT); +#ifdef SKIP_ASM void DrawCredit(CREDIT *pcredit) { extern int D_00275BEC; @@ -61,6 +66,7 @@ void DrawCredit(CREDIT *pcredit) } } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/credit", PlaceCredit__FP6CREDITffi); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index c285ee01..8a02bf7c 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -97,7 +97,9 @@ extern "C" void FUN_0014c668(void *pv, int tnt) extern "C" void FUN_0014c858(void *p); extern "C" void FUN_0014cba8(void *p); -void update_crbrain(CRBRAIN *p, float dt) +INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); +#ifdef SKIP_ASM +extern "C" void update_crbrain(CRBRAIN *p, float dt) { OID oid; @@ -120,6 +122,7 @@ void update_crbrain(CRBRAIN *p, float dt) pfn(ppo); } } +#endif // SKIP_ASM extern int FUN_001e9970(); extern BLOT g_unkblot1; diff --git a/src/P2/difficulty.c b/src/P2/difficulty.c index 208a7ae0..81191349 100644 --- a/src/P2/difficulty.c +++ b/src/P2/difficulty.c @@ -110,7 +110,9 @@ void OnDifficultyInitialTeleport(DIFFICULTY *pdifficulty) return; } -void OnDifficultyPlayerDeath(float scalar, DIFFICULTY *pdifficulty) +INCLUDE_ASM("asm/nonmatchings/P2/difficulty", OnDifficultyPlayerDeath); +#ifdef SKIP_ASM +extern "C" void OnDifficultyPlayerDeath(float scalar, DIFFICULTY *pdifficulty) { DIFFICULTYLEVEL *pdifflevel = pdifficulty->pDifficultyLevel; @@ -131,6 +133,7 @@ void OnDifficultyPlayerDeath(float scalar, DIFFICULTY *pdifficulty) g_plsCur->unk_suck_0x10 = GLimitLm(&g_lmZeroOne, g_plsCur->unk_suck_0x10 + scalar * result); } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/difficulty", OnDifficultyTriggerCheckpoint__FP10DIFFICULTYP6CHKPNT); #ifdef SKIP_ASM diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 0268817b..25f57923 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -18,6 +18,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", InitEmitter__FP7EMITTER); INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitmeshFromBrx__FP8EMITMESHP18CBinaryInputStream); +INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitblipColorsFromBrx__FP8EMITBLIPiP2LOP18CBinaryInputStream); +#ifdef SKIP_ASM void LoadEmitblipColorsFromBrx(EMITBLIP *pemitblip, int crgba, LO *ploEmit, CBinaryInputStream *pbis) { int i; @@ -34,6 +36,7 @@ void LoadEmitblipColorsFromBrx(EMITBLIP *pemitblip, int crgba, LO *ploEmit, CBin STRUCT_OFFSET(pemitblip, 0x50, RGBA *)[i] = (RGBA &)rgba; } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitterFromBrx__FP7EMITTERP18CBinaryInputStream); @@ -244,6 +247,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", ChooseEmitoPos__FP5EMITOiiP6VECTORT3) INCLUDE_ASM("asm/nonmatchings/P2/emitter", ConvertEmitoPosVec__FP5EMITOP6VECTORT1); +INCLUDE_ASM("asm/nonmatchings/P2/emitter", CalculateEmitvx__FiP2LMiP6EMITVX); +#ifdef SKIP_ASM void CalculateEmitvx(int cParticlePerRing, LM *plmTilt, int cParticle, EMITVX *pemitvx) { int cBatch; @@ -271,6 +276,7 @@ void CalculateEmitvx(int cParticlePerRing, LM *plmTilt, int cParticle, EMITVX *p plmTilt->gMin + STRUCT_OFFSET(pemitvx, 0x4, float) * 0.5f; STRUCT_OFFSET(pemitvx, 0x10, float) = GRandInRange(0.0f, 6.2831855f); } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/emitter", ChooseEmitVelocity__FP6EMITVXffP2LMP6VECTORiT4); diff --git a/src/P2/fly.c b/src/P2/fly.c index 8e3974bb..3dbb3354 100644 --- a/src/P2/fly.c +++ b/src/P2/fly.c @@ -6,6 +6,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/fly", InitFly__FP3FLY); INCLUDE_ASM("asm/nonmatchings/P2/fly", LoadFlyFromBrx__FP3FLYP18CBinaryInputStream); +INCLUDE_ASM("asm/nonmatchings/P2/fly", CloneFly__FP3FLYT0); +#ifdef SKIP_ASM void CloneFly(FLY *pfly, FLY *pflyBase) { uint64_t tmp = STRUCT_OFFSET(pfly, 0x5dc, uint64_t); @@ -23,6 +25,7 @@ void CloneFly(FLY *pfly, FLY *pflyBase) RemoveDlEntry((DL *)((char *)pfly->psw + 0x1c48), pfly); } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/fly", FreezeFly__FP3FLYi); @@ -66,6 +69,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/fly", FShouldFlyFlee__FP3FLY); INCLUDE_ASM("asm/nonmatchings/P2/fly", FFilterFly__FPvP2SO); +INCLUDE_ASM("asm/nonmatchings/P2/fly", FCheckFlyOpenSpaceBelow__FP3FLY); +#ifdef SKIP_ASM int FCheckFlyOpenSpaceBelow(FLY *pfly) { if (g_clock.t - STRUCT_OFFSET(pfly, 0x66c, float) < 0.05f) @@ -89,3 +94,4 @@ int FCheckFlyOpenSpaceBelow(FLY *pfly) STRUCT_OFFSET(pfly, 0x66c, float) = g_clock.t; return pso == NULL; } +#endif // SKIP_ASM diff --git a/src/P2/font.c b/src/P2/font.c index 0cac1b12..2a0f2c39 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -51,6 +51,8 @@ void CFont::CopyTo(CFont *pfontDest) class CTextBox; +INCLUDE_ASM("asm/nonmatchings/P2/font", SetupDraw__5CFontP8CTextBoxP4GIFS); +#ifdef SKIP_ASM void SetupDraw_CFont(CFont *self, CTextBox *ptb, GIFS *pgifs) __asm__("SetupDraw__5CFontP8CTextBoxP4GIFS"); void SetupDraw_CFont(CFont *self, CTextBox *ptb, GIFS *pgifs) { @@ -72,6 +74,7 @@ void SetupDraw_CFont(CFont *self, CTextBox *ptb, GIFS *pgifs) ((ulong)scayTop << 32) | ((ulong)scayBottom << 48)); } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/font", CleanupDraw__5CFontP8CTextBoxP4GIFS); diff --git a/src/P2/frm.c b/src/P2/frm.c index 733a1ecb..e02e0eb0 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -53,6 +53,8 @@ void EnsureVu1Code(VIFS *pvifs, void *pvStart, void *pvEnd) extern void *VU1_GlobMpg; extern void *VU1_GlobMpgEnd; +INCLUDE_ASM("asm/nonmatchings/P2/frm", FinalizeFrameVifs__FP4VIFSPiPP2QW); +#ifdef SKIP_ASM void FinalizeFrameVifs(VIFS *pvifs, int *pcqwVifs, QW **ppqwVifs) { QW aqw[8]; @@ -68,6 +70,7 @@ void FinalizeFrameVifs(VIFS *pvifs, int *pcqwVifs, QW **ppqwVifs) pvifs->AddDmaEnd(); pvifs->Detach(pcqwVifs, ppqwVifs); } +#endif // SKIP_ASM void FinalizeFrameGifs(GIFS *pgifs, int *pcqwGifs, QW **ppqwGifs) { @@ -122,6 +125,8 @@ extern "C" unsigned int func_00100000[]; extern "C" char D_00148D74[]; extern "C" int D_00262310; +INCLUDE_ASM("asm/nonmatchings/P2/frm", check_anticrack_antigrab__Fv); +#ifdef SKIP_ASM void check_anticrack_antigrab() { unsigned int *pwTable = D_002C3B00; @@ -143,6 +148,7 @@ void check_anticrack_antigrab() if (crc != 0) D_00262310 = 1; } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/frm", FrameRenderLoop__FPv); diff --git a/src/P2/game.c b/src/P2/game.c index 48ba8437..915697f5 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -59,58 +59,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", tally_world_completion); INCLUDE_ASM("asm/nonmatchings/P2/game", get_game_completion__Fv); -void UnlockIntroCutsceneFromWid(int wid) -{ - /* Check the unlocked cutscene by setting the corresponding - flag on the unlocked_cutscenes in the game state */ - switch (wid) - { - case 1: - /* Unlock cutscene "Tide of Terror" */ - g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x10; - return; - case 2: - /* Unlock cutscene "Sunset Snake Eyes" */ - g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x40; - return; - case 3: - /* Unlock cutscene "Vicious Voodoo" */ - g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x100; - return; - case 4: - /* Unlock cutscene "Fire in the Sky" */ - g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x400; - return; - case 5: - /* Unlock cutscene "The Cold Heart of Hate" */ - g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x1000; - } -} +// TODO: switch matches but its rodata jump table dangles when built from C +// (the asm jtbl in 14B0F8.rodata.s references the function-local .L labels). +INCLUDE_ASM("asm/nonmatchings/P2/game", UnlockIntroCutsceneFromWid__Fi); -void DefeatBossFromWid(int wid) -{ - g_pgsCur->aws[wid].fws = (FWS)(g_pgsCur->aws[wid].fws | 0x20); - - switch (wid) - { - case 1: - g_pgsCur->unlocked_cutscenes |= 0x20; - break; - case 2: - g_pgsCur->unlocked_cutscenes |= 0x80; - break; - case 3: - g_pgsCur->unlocked_cutscenes |= 0x200; - g_pgsCur->grfvault |= 0x10000; - break; - case 4: - g_pgsCur->unlocked_cutscenes |= 0x800; - break; - case 5: - UnlockEndgameCutscenesFromFgs((FGS)0x2); - break; - } -} +// TODO: same rodata jump-table blocker as UnlockIntroCutsceneFromWid. +INCLUDE_ASM("asm/nonmatchings/P2/game", DefeatBossFromWid); extern "C" void UnlockEndgameCutscenesFromFgs(FGS fgs) { diff --git a/src/P2/jsg.c b/src/P2/jsg.c index e65b242c..2000b3d3 100644 --- a/src/P2/jsg.c +++ b/src/P2/jsg.c @@ -49,6 +49,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/jsg", NextJsgJsge__FP3JSG); INCLUDE_ASM("asm/nonmatchings/P2/jsg", FIsJsgJsgeComplete__FP3JSGP4JSGE); +INCLUDE_ASM("asm/nonmatchings/P2/jsg", UpdateJsgJsge__FP3JSG); +#ifdef SKIP_ASM void UpdateJsgJsge(JSG *pjsg) { JSGE *pjsgeJoy; @@ -75,6 +77,7 @@ void UpdateJsgJsge(JSG *pjsg) pjsg->pjsgeJoy = NULL; } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/jsg", ReadJsgJoystick__FP3JSGP3JOY); diff --git a/src/P2/light.c b/src/P2/light.c index 207485f5..b11e338e 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -7,6 +7,8 @@ extern VU_VECTOR g_normalZ; extern VU_VECTOR g_normalY; +INCLUDE_ASM("asm/nonmatchings/P2/light", InitLight__FP5LIGHT); +#ifdef SKIP_ASM void InitLight(LIGHT *plight) { uint64_t grfalo = STRUCT_OFFSET(plight, 0x2c8, uint64_t); @@ -26,6 +28,7 @@ void InitLight(LIGHT *plight) RebuildLightFrustrum(plight); InitAlo(plight); } +#endif // SKIP_ASM void UpdateLightXfWorldHierarchy(LIGHT *plight) { diff --git a/src/P2/missile.c b/src/P2/missile.c index 86ced493..50008b4f 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -36,6 +36,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/missile", FireMissile__FP7MISSILEP3ALOP6VECTOR) INCLUDE_ASM("asm/nonmatchings/P2/missile", RenderMissileAll__FP7MISSILEP2CMP2RO); +INCLUDE_ASM("asm/nonmatchings/P2/missile", FUN_0018dc88); +#ifdef SKIP_ASM extern "C" int FUN_0018dc88(SO *pso, SO *psoOther) { int i; @@ -69,6 +71,7 @@ extern "C" int FUN_0018dc88(SO *pso, SO *psoOther) return FIgnoreSoIntersection(pso, psoOther); } +#endif // SKIP_ASM extern "C" void FUN_0018dd50(void * p, int val) { diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index e2a6325e..b709232c 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -166,6 +166,7 @@ class CMpegAudio CQueueOutputIop qoi; void Reset(); + void Update(); }; #endif // CMPEGAUDIO_DEFINED @@ -197,6 +198,8 @@ extern "C" void Close__10CMpegAudio(void *pthis) INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FAccept__10CMpegAudioiPUc); +INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__10CMpegAudio); +#ifdef SKIP_ASM void CMpegAudio::Update() { if (unk_0x0 == 2) @@ -214,6 +217,7 @@ void CMpegAudio::Update() bqOut.CbDrain(qoi.unk_0x14, (CQueueOutput *)&qoi); } } +#endif // SKIP_ASM struct sceMpeg; struct sceMpegCbDataStr; diff --git a/src/P2/po.c b/src/P2/po.c index 9233f57c..63ab896c 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -28,6 +28,8 @@ void ClonePo(PO *ppo, PO *ppoBase) } } +INCLUDE_ASM("asm/nonmatchings/P2/po", HandlePoMessage__FP2PO5MSGIDPv); +#ifdef SKIP_ASM void HandlePoMessage(PO *ppo, MSGID msgid, void *pv) { HandleAloMessage((ALO *)ppo, msgid, pv); @@ -58,6 +60,7 @@ void HandlePoMessage(PO *ppo, MSGID msgid, void *pv) break; } } +#endif // SKIP_ASM void OnPoActive(PO *ppo, int fActive, PO *ppoOther) { diff --git a/src/P2/render.c b/src/P2/render.c index 20db4519..f61339c7 100644 --- a/src/P2/render.c +++ b/src/P2/render.c @@ -75,6 +75,8 @@ void EnsureCameraGlobals() /** * @todo 95.71% match. Missing two instructions. */ +INCLUDE_ASM("asm/nonmatchings/P2/render", EnsureScreenCleared__Fv); +#ifdef SKIP_ASM void EnsureScreenCleared() { if (!s_fFBCleared) @@ -94,6 +96,7 @@ void EnsureScreenCleared() s_fZBCleared = 1; } } +#endif // SKIP_ASM void SetupRpDynamicTexture(RPL *prpl) { diff --git a/src/P2/shadow.c b/src/P2/shadow.c index fd653d27..80e39182 100644 --- a/src/P2/shadow.c +++ b/src/P2/shadow.c @@ -1,5 +1,6 @@ #include #include +#include #include INCLUDE_ASM("asm/nonmatchings/P2/shadow", InitShadow__FP6SHADOW); @@ -7,6 +8,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/shadow", InitShadow__FP6SHADOW); extern "C" int D_002626D0; extern "C" SUR D_0027DC20[]; +INCLUDE_ASM("asm/nonmatchings/P2/shadow", PostShadowLoad__FP6SHADOW); +#ifdef SKIP_ASM void PostShadowLoad(SHADOW *pshadow) { if (pshadow->pshd == NULL) @@ -31,6 +34,7 @@ void PostShadowLoad(SHADOW *pshadow) } } } +#endif // SKIP_ASM void InvalidateShadowVifs(SHADOW *pshadow) { diff --git a/src/P2/suv.c b/src/P2/suv.c index d92f1cd2..90b0cbda 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -34,6 +34,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvLine__FP3SUVPi); INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvHeading__FP3SUV); +INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvWheels__FP3SUV); +#ifdef SKIP_ASM void UpdateSuvWheels(SUV *psuv) { extern float D_002754F8; @@ -60,6 +62,7 @@ void UpdateSuvWheels(SUV *psuv) p += 0x60; } } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvExpls__FP3SUV); diff --git a/src/P2/sw.c b/src/P2/sw.c index a15e0fda..836ba82a 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -201,6 +201,8 @@ struct PSL LO **aplo; } __attribute__((packed)); +INCLUDE_ASM("asm/nonmatchings/P2/sw", AddSwProxySource__FP2SWP2LOi); +#ifdef SKIP_ASM void AddSwProxySource(SW *psw, LO *ploProxySource, int cploClone) { PSL psl; @@ -228,6 +230,7 @@ void AddSwProxySource(SW *psw, LO *ploProxySource, int cploClone) STRUCT_OFFSET(psw, cpsl * 8 + 0x1F00, PSL) = psl; STRUCT_OFFSET(psw, 0x1EFC, int) = cpsl + 1; } +#endif // SKIP_ASM LO *PloGetSwProxySource(SW *psw, int ipsl) { @@ -315,6 +318,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", DrawLineWorld__FP6VECTORT0G4RGBAP2CMi); void DrawLineWorld(VECTOR *ppos1, VECTOR *ppos2, RGBA rgba, CM *pcm, int fDepthTest); +INCLUDE_ASM("asm/nonmatchings/P2/sw", DrawAxesWorld__FP6VECTORP7MATRIX3fP2CMi); +#ifdef SKIP_ASM void DrawAxesWorld(VECTOR *ppos, MATRIX3 *pmat, float sScale, CM *pcm, int fDepthTest) { VECTOR4 apos[10]; @@ -331,6 +336,7 @@ void DrawAxesWorld(VECTOR *ppos, MATRIX3 *pmat, float sScale, CM *pcm, int fDept (CM *)(long)fDepthTest, 1); } } +#endif // SKIP_ASM void SetSwIllum(SW *psw, float uMidtone) { diff --git a/src/P2/tn.c b/src/P2/tn.c index ef4ab94c..3273bb99 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -17,6 +17,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", GetTnfnNose__FP4TNFNP6CPDEFIP6VECTORP2TN); struct TNFN_DATA { char rgb[0x90]; }; +INCLUDE_ASM("asm/nonmatchings/P2/tn", InitTn__FP2TN); +#ifdef SKIP_ASM void InitTn(TN *ptn) { extern VECTOR D_00275A10; @@ -42,6 +44,7 @@ void InitTn(TN *ptn) *(uint64_t *)((char *)ptn + 0x460) = *(uint64_t *)D_00275A20; STRUCT_OFFSET(ptn, 0x398, int) = -1; } +#endif // SKIP_ASM void OnTnRemove(TN *ptn) { @@ -57,6 +60,8 @@ void PostTnLoad(TN *ptn) PostAloLoad(ptn); } +INCLUDE_ASM("asm/nonmatchings/P2/tn", SetTnTns__FP2TN3TNS); +#ifdef SKIP_ASM void SetTnTns(TN *ptn, TNS tns) { if (STRUCT_OFFSET(ptn, 0x394, TNS) == tns) @@ -83,6 +88,7 @@ void SetTnTns(TN *ptn, TNS tns) STRUCT_OFFSET(ptn, 0x39C, float) = g_clock.t; } +#endif // SKIP_ASM /** * @todo Rename. @@ -99,6 +105,8 @@ void FUN_001e2840(TN *ptn, TNS tns) UpdateTnCallback(ptn, MSGID_callback, NULL); } +INCLUDE_ASM("asm/nonmatchings/P2/tn", UpdateTnCallback__FP2TN5MSGIDPv); +#ifdef SKIP_ASM void UpdateTnCallback(TN *ptn, MSGID msgid, void *pv) { VECTOR posLocal; @@ -131,6 +139,7 @@ void UpdateTnCallback(TN *ptn, MSGID msgid, void *pv) SetTnTns(ptn, tns); } +#endif // SKIP_ASM void UpdateTn(TN *ptn, float dt) { diff --git a/src/P2/wipe.c b/src/P2/wipe.c index 14e89a76..3dc3160d 100644 --- a/src/P2/wipe.c +++ b/src/P2/wipe.c @@ -18,6 +18,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/wipe", UpdateWipe__FP4WIPEP3JOY); /** * @todo 94.58% match. The order of the checks might be wrong. */ +INCLUDE_ASM("asm/nonmatchings/P2/wipe", DrawWipe__FP4WIPE); +#ifdef SKIP_ASM void DrawWipe(WIPE *pwipe) { if (g_psw == NULL || g_pwipe == NULL) @@ -41,6 +43,7 @@ void DrawWipe(WIPE *pwipe) FillScreenRect(0, 0, 0, (int)(pwipe->uBlack * 255.0f), 0.0f, 0.0f, 640.0f, 492.80002f, &g_gifs); } +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/wipe", ActivateWipe__FP4WIPEP5TRANS5WIPEK); From 1cdd9cc4c6ce8262b19c9fe32d0190a9da98c161 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Thu, 18 Jun 2026 00:15:46 +0200 Subject: [PATCH 122/134] Apply decomp/p2-leaf-matches changes (AM register naming, SO 0x550 padding) Brings the two changes from decomp/p2-leaf-matches that fable did not already have (its water.c STRUCT_OFFSET refactor and TODO cleanup were already present and superseded). Both verified byte-identical to the prior green build. - Name FUN_001c0c50/68 as GetAMRegister/UpdateAMRegister and drop extern "C" (the functions are already decompiled; rename only, mangled symbols, no asm callers depend on the raw names). - Pad SO to its real 0x550 size (STRUCT_PADDING(160)) instead of carrying the 0x2d0..0x550 base gap in each subclass: WATER drops its leading 160-pad and JT's pad goes 1090 -> 930, both keeping their fields at the same absolute offsets. This is the root-cause fix requested in the PR #257 review. - Drop the verbose truncated-base / STRUCT_OFFSET explanatory comments in water.c per the same review (the STRUCT_OFFSET calls are self-documenting). Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 4 ++-- include/jt.h | 3 ++- include/so.h | 4 +++- include/sound.h | 21 +++++++++------------ include/water.h | 6 ------ src/P2/sound.c | 4 ++-- src/P2/sw.c | 4 ++-- src/P2/water.c | 4 ---- 8 files changed, 20 insertions(+), 30 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 0dc18f11..489b86b5 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -4113,8 +4113,8 @@ FUN_001C0AB8 = 0x1C0AB8; // type:func FUN_001C0B08 = 0x1C0B08; // type:func StartSwIntermittentSounds__FP2SW = 0x1C0B38; // type:func SetAMRegister__FiUc = 0x1C0C08; // type:func -FUN_001c0c50 = 0x1C0C50; // type:func -FUN_001c0c68 = 0x1C0C68; // type:func +GetAMRegister__Fi = 0x1C0C50; // type:func +UpdateAMRegister__Fii = 0x1C0C68; // type:func FUN_001c0cb0__Fv = 0x1C0CB0; // type:func HsNextFootFall__Fv = 0x1C0CF0; // type:func NextSneakyFootstep__Fv = 0x1C0EC0; // type:func diff --git a/include/jt.h b/include/jt.h index efc68047..dde9b7aa 100644 --- a/include/jt.h +++ b/include/jt.h @@ -142,7 +142,8 @@ enum JTPDK */ struct JT : public STEP { - STRUCT_PADDING(1090); + // 930 = 1090 - 160; SO now carries the 160-word (0x2d0..0x550) base gap. + STRUCT_PADDING(930); undefined2 padding0_extra; ALO *paloMine_0x1518; // 0x1518 diff --git a/include/so.h b/include/so.h index 162aff4b..37fe3c14 100644 --- a/include/so.h +++ b/include/so.h @@ -78,7 +78,9 @@ enum FSO */ struct SO : public ALO { - // ... + // SO's own fields (0x2d0..0x550) are not yet reversed; pad SO to its real + // size so subclasses inherit correct absolute offsets. + STRUCT_PADDING(160); // 0x2d0 .. 0x550 //* 0x368 */ float mass; }; diff --git a/include/sound.h b/include/sound.h index 5ab544e8..4c8f4b78 100644 --- a/include/sound.h +++ b/include/sound.h @@ -308,18 +308,15 @@ void KillSounds(int param_1); */ void FUN_001c0cb0(); -// Unmangled asm symbols (see INCLUDE_ASM in sound.c); require C linkage. -extern "C" -{ - /** - * @brief Unknown. - */ - int FUN_001c0c50(int reg); +/** + * @brief Returns the cached value of AM register `reg`. + */ +int GetAMRegister(int reg); - /** - * @brief Unknown. - */ - void FUN_001c0c68(int reg, int value); -} +/** + * @brief Refreshes the cached AM register `reg` from the live sequencer value. + * (`value` is unused by the body but kept for the caller's ABI.) + */ +void UpdateAMRegister(int reg, int value); #endif // SOUND_H diff --git a/include/water.h b/include/water.h index 75120d78..abcc361f 100644 --- a/include/water.h +++ b/include/water.h @@ -23,12 +23,6 @@ struct XP; */ struct WATER : public SO { - // The span 0x2d0..0x550 holds SO base fields that live past the currently - // truncated SO size. Rather than redeclare them here (which would pin this - // struct to the present sizeof(SO) and break the checksum if SO grows), - // they are reached via STRUCT_OFFSET from water.c until the base structs - // are fully reversed. WATER's own fields begin at 0x550. - STRUCT_PADDING(160); // 0x2d0 .. 0x550 /* 0x550 */ XA *pxaFirst; /* 0x554 */ MRG mrg; STRUCT_PADDING(3); // 0x564 .. 0x570 diff --git a/src/P2/sound.c b/src/P2/sound.c index ae7938a1..703376ca 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -643,14 +643,14 @@ extern "C" void SetAMRegister__FiUc(int n, int bReg) } extern int D_006053E0[]; -extern "C" int FUN_001c0c50(int reg) +int GetAMRegister(int reg) { return D_006053E0[reg]; } extern int D_006053E0[]; extern u_int D_00274728; -extern "C" void FUN_001c0c68(int reg, int value) +void UpdateAMRegister(int reg, int value) { D_006053E0[reg] = snd_GetMIDIRegister(D_00274728, reg); } diff --git a/src/P2/sw.c b/src/P2/sw.c index 836ba82a..984b23db 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -79,12 +79,12 @@ extern "C" void FUN_001dbac0(SW *psw, int reg, int value) int FUN_001dbae0(SW *psw, int reg) { - return FUN_001c0c50(reg); + return GetAMRegister(reg); } void FUN_001dbb00(SW *psw, int reg, int value) { - FUN_001c0c68(reg, value); + UpdateAMRegister(reg, value); } int FOverflowSwLo(SW *psw, LO *plo, int fHiPri) diff --git a/src/P2/water.c b/src/P2/water.c index 10ac11c9..72b0586b 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -13,8 +13,6 @@ void InitWater(WATER *pwater) { InitSo(pwater); - // grfso (0x538), unk_0x360 and unk_0x364 are SO base fields living past the - // truncated SO size; reach them via STRUCT_OFFSET (see WATER definition). STRUCT_OFFSET(pwater, 0x538, uint64_t) |= 0x80000000000; pwater->unk_0x584 = 1; STRUCT_OFFSET(pwater, 0x364, float) = 1.0f; @@ -70,8 +68,6 @@ void UpdateSwXaList(SW *psw, XA **ppxa) while (pxa != NULL) { SO *pso = pxa->pso; - // grfso is an SO flag word at 0x538, reached via STRUCT_OFFSET until - // the base structs are fully reversed (see WATER definition). uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); XA *pxaNext = pxa->pxaNextTarget; From 95b770e3bba8c2127d3d6575d9f07edfcfc0d9b5 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Mon, 22 Jun 2026 23:56:54 +0200 Subject: [PATCH 123/134] Drop extern "C" warts via pre-mangled symbols; trim decomp comments Remove the extern "C" shortcut from matched C++ functions by renaming their symbol_addrs.txt entries to the GCC2-mangled form, so a plain C++ decl/def emits the exact target symbol (manglings read from nm, not hand-computed). Symbol renames are checksum-neutral (stripped ELF); splat regenerates asm callers and linker scripts. 38 extern "C" removed, 0 added. - Data globals + __asm__ aliases: just drop extern "C" (C++ doesn't mangle namespace-scope variable names; the asm alias already forces the symbol). - Real-named free functions (OnRwmRemove, InitCplcy/FActiveCplcy/SetCpmanCpmt/ InitCplook, SetCmLookAt/ResetCmLookAtSmooth, HandleJtGrfjtsc, SfxhMusicUnknown1/2, MvgkUnknown3/4, UnlockEndgameCutscenesFromFgs): pre-mangle + convert owning-header/caller decls to plain C++. - UpdateAloXfWorld: fix alo.h (it declared the literal mangled identifier), drop the so.c _UpdateAloXfWorld __asm__ alias, call it directly. SetAMRegister and OnDifficultyPlayerDeath keep extern "C" -- both are load-bearing: they pass match.sh per-symbol but fail the full checksum when converted (caller-side uchar narrowing / a GCC 2.95 register-allocation flip). Also trim decomp/tooling-explanation, AI-process, and TODO/blocker comments this branch added; condense the load-bearing "kept wrapped (unwrapping breaks the checksum)" notes to one line each. Struct-field annotations and Doxygen kept. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 26 +++++++++++++------------- include/alo.h | 2 +- include/cm.h | 2 +- include/cplcy.h | 2 +- include/game.h | 2 +- src/P2/alo.c | 14 ++------------ src/P2/bq.c | 4 +--- src/P2/brx.c | 2 +- src/P2/cm.c | 4 ++-- src/P2/cplcy.c | 8 ++++---- src/P2/crusher.c | 3 --- src/P2/crv.c | 4 ++-- src/P2/frm.c | 8 ++++---- src/P2/game.c | 9 +++------ src/P2/jt.c | 2 +- src/P2/mpeg.c | 9 +++------ src/P2/rwm.c | 2 +- src/P2/sensor.c | 2 +- src/P2/shadow.c | 4 ++-- src/P2/so.c | 13 ++----------- src/P2/sound.c | 12 ++++++------ src/P2/splice/bif.cpp | 9 ++------- src/P2/sw.c | 6 +++--- src/P2/water.c | 7 +------ 24 files changed, 58 insertions(+), 98 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 489b86b5..0e71f174 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -1398,10 +1398,10 @@ BuildFrustrum = 0x1443C8; // type:func UpdateCmMat4 = 0x144540; // type:func DrawCm__FP2CM = 0x144848; // type:func SetCmPosMat__FP2CMP6VECTORP7MATRIX3 = 0x1448C8; // type:func -SetCmLookAt = 0x144938; // type:func +SetCmLookAt__FP2CMP6VECTORT1 = 0x144938; // type:func ConvertWorldToCylindVelocity = 0x144978; // type:func ConvertCylindToWorldVelocity = 0x144AA0; // type:func -ResetCmLookAtSmooth = 0x144B70; // type:func +ResetCmLookAtSmooth__FP2CMPv = 0x144B70; // type:func SetCmLookAtSmooth = 0x144BE8; // type:func AdjustCmJoy__FP2CMP3JOY5JOYIDPf = 0x144FF8; // type:func junk_00145080 = 0x145080; // type:func @@ -1528,9 +1528,9 @@ s_asnipDprize = 0x2619A0; // size:0x3c //////////////////////////////////////////////////////////////// // P2/cplcy.c //////////////////////////////////////////////////////////////// -InitCplcy = 0x149398; // type:func -FActiveCplcy = 0x1493A0; // type:func -SetCpmanCpmt = 0x1493B8; // type:func +InitCplcy__FP5CPLCYP2CM = 0x149398; // type:func +FActiveCplcy__FP5CPLCY = 0x1493A0; // type:func +SetCpmanCpmt__FP5CPMAN4CPMT = 0x1493B8; // type:func FUN_001493c0__Fv = 0x1493C0; // type:func PosCplookAnchor = 0x1493C8; // type:func FUN_00149458 = 0x149458; // type:func @@ -1538,7 +1538,7 @@ plays_binoc_sfx = 0x149508; // type:func PushCplookLookk__FP6CPLOOK5LOOKK = 0x1495E8; // type:func LookkPopCplook__FP6CPLOOK = 0x149610; // type:func LookkCurCplook__FP6CPLOOK = 0x149638; // type:func -InitCplook = 0x149660; // type:func +InitCplook__FP6CPLOOKP2CM = 0x149660; // type:func FUN_001496c0 = 0x1496C0; // type:func UpdateCplook = 0x149760; // type:func FUN_0014a7b8 = 0x14A7B8; // type:func @@ -2096,7 +2096,7 @@ tally_world_completion = 0x160208; // type:func get_game_completion__Fv = 0x1602A0; // type:func UnlockIntroCutsceneFromWid__Fi = 0x160340; // type:func DefeatBossFromWid = 0x1603E8; // type:func -UnlockEndgameCutscenesFromFgs = 0x1604B8; // type:func +UnlockEndgameCutscenesFromFgs__F3FGS = 0x1604B8; // type:func PlayEndingFromCompletionFlags = 0x160578; // type:func InitGameState__FP2GS = 0x1605E8; // type:func @@ -2409,7 +2409,7 @@ PresetJtAccelBase = 0x16FD70; // type:func PresetJtAccel__FP2JTf = 0x1701B0; // type:func AdjustJtNewXp__FP2JTP2XPi = 0x170410; // type:func AdjustJtDz__FP2JTiP2DZif = 0x170528; // type:func -HandleJtGrfjtsc = 0x1705C8; // type:func +HandleJtGrfjtsc__FP2JT = 0x1705C8; // type:func UpdateJtInternalXps__FP2JT = 0x170660; // type:func FCheckJtXpBase__FP2JTP2XPi = 0x170790; // type:func AdjustJtXpVelocity__FP2JTP2XPi = 0x170820; // type:func @@ -3510,7 +3510,7 @@ DAT_0026c3dc = 0x26C3DC; // P2/rwm.c //////////////////////////////////////////////////////////////// InitRwm__FP3RWM = 0x1A7FE8; // type:func -OnRwmRemove = 0x1A80E0; // type:func +OnRwmRemove__FP3RWM = 0x1A80E0; // type:func FUN_001a8110 = 0x1A8110; // type:func FUN_001a8150 = 0x1A8150; // type:func InitRwmCallback__FP3RWM5MSGIDPv = 0x1A8208; // type:func @@ -4063,8 +4063,8 @@ StartMusidSong__F5MUSID = 0x1BEC58; // type:func PauseMusic__Fv = 0x1BECF8; // type:func ContinueMusic__Fv = 0x1BED20; // type:func -SfxhMusicUnknown1 = 0x1BED48; // type:func -SfxhMusicUnknown2 = 0x1BED70; // type:func +SfxhMusicUnknown1__Fv = 0x1BED48; // type:func +SfxhMusicUnknown2__Fv = 0x1BED70; // type:func PexcAlloc__Fv = 0x1BED98; // type:func RemoveExc__FP3EXC = 0x1BEDF8; // type:func @@ -4101,8 +4101,8 @@ SetMvgkUvol__Ff = 0x1c05d0; // type:func MvgkUnknown1__F4MVGK = 0x1C0600; // type:func SetMvgkRvol__Fi4MVGKf = 0x1C06A0; // type:func MvgkUnknown2__Fv = 0x1C06D8; // type:func -MvgkUnknown3 = 0x1C0760; // type:func -MvgkUnknown4 = 0x1C0790; // type:func +MvgkUnknown3__Fi = 0x1C0760; // type:func +MvgkUnknown4__Fi = 0x1C0790; // type:func KillSoundSystem__Fv = 0x1C07B0; // type:func KillSounds__Fi = 0x1C0808; // type:func PushSwReverb__FP2SW7REVERBKi = 0x1C08B0; // type:func diff --git a/include/alo.h b/include/alo.h index 5704cdb9..40540d48 100644 --- a/include/alo.h +++ b/include/alo.h @@ -276,7 +276,7 @@ void UpdateAlo(ALO *palo, float dt); void InvalidateAloLighting(ALO *palo); -void UpdateAloXfWorld__FP3ALO(ALO * palo); +void UpdateAloXfWorld(ALO *palo); void UpdateAloXfWorldHierarchy(ALO *palo); diff --git a/include/cm.h b/include/cm.h index 97ac90f3..33292b92 100644 --- a/include/cm.h +++ b/include/cm.h @@ -553,6 +553,6 @@ extern int g_rgbaFog; //Just to get the code matching -Kestin // extern float D_0026198c; // extern CM* g_pcm; -extern "C" void ResetCmLookAtSmooth(CM *pcm, void *pv); +void ResetCmLookAtSmooth(CM *pcm, void *pv); #endif // CM_H diff --git a/include/cplcy.h b/include/cplcy.h index 09943f1c..4cd455e4 100644 --- a/include/cplcy.h +++ b/include/cplcy.h @@ -17,6 +17,6 @@ LOOKK LookkPopCplook(CPLOOK *pcplook); LOOKK LookkCurCplook(CPLOOK *pcplook); -extern "C" int FActiveCplcy(CPLCY *pcplcy); +int FActiveCplcy(CPLCY *pcplcy); #endif // CPLCY_H diff --git a/include/game.h b/include/game.h index 8fe92104..7baff13e 100644 --- a/include/game.h +++ b/include/game.h @@ -304,7 +304,7 @@ void DefeatBossFromWid(int wid); * * @param fgs Completion flags. */ -extern "C" void UnlockEndgameCutscenesFromFgs(FGS fgs); +void UnlockEndgameCutscenesFromFgs(FGS fgs); /** * @brief Plays the ending cutscene based on the completion flags. diff --git a/src/P2/alo.c b/src/P2/alo.c index fda3291c..b17a44e2 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -64,18 +64,8 @@ void InvalidateAloLighting(ALO *palo) } } -// alo.h declares `void UpdateAloXfWorld__FP3ALO(ALO *palo);` as a C++ function; with that -// declaration in scope, GCC 2.95 mangles a plain `void UpdateAloXfWorld(ALO *)` definition -// to UpdateAloXfWorld__FP3ALO__FP3ALO. Defining the literal symbol with C linkage (void* -// parameter so it does not conflict with the C++ declaration) emits the exact target symbol. -// If alo.h:279 is ever fixed to `void UpdateAloXfWorld(ALO *palo);`, this can become a plain -// C++ `void UpdateAloXfWorld(ALO *palo)` definition (verified to also match). -extern "C" void UpdateAloXfWorld__FP3ALO(void *pvalo) -{ - ALO *palo = (ALO *)pvalo; - // vtable slot at 0x5c: compiled offset of pfnUpdateLoXfWorldHierarchy in VTLO - // (the real game slot is probably "update xf world"; the header's VTLO has an extra - // pfnUpdateLo entry shifting the names, but the compiled offset is what matters). +void UpdateAloXfWorld(ALO *palo) +{ void (*pfn)(ALO *) = (void (*)(ALO *))palo->pvtlo->pfnUpdateLoXfWorldHierarchy; if (pfn != 0) diff --git a/src/P2/bq.c b/src/P2/bq.c index 113ad010..1a7e0580 100644 --- a/src/P2/bq.c +++ b/src/P2/bq.c @@ -21,7 +21,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/bq", CbFill__10CByteQueueiP11CQueueInput); INCLUDE_ASM("asm/nonmatchings/P2/bq", CbDrain__10CByteQueueiP12CQueueOutput); -extern "C" int D_00249D98[]; +extern int D_00249D98[]; int CByteQueue::CbFill(int cb, byte *pb) { @@ -35,8 +35,6 @@ int CByteQueue::CbFill(int cb, byte *pb) { // Stack CQueueInputMemory: vtable ptr (D_00249D98 = __vt_17CQueueInputMemory in // rodata), pb @0x4, cb @0x8, ib (read cursor) @0xC, cb remaining @0x10 - // (layout confirmed by CbRead__17CQueueInputMemoryiPv). The repo's - // CQueueInputMemory class declares no fields, so the object is built manually. struct { void *pvt; diff --git a/src/P2/brx.c b/src/P2/brx.c index 94f8f3a4..d27b3fee 100644 --- a/src/P2/brx.c +++ b/src/P2/brx.c @@ -65,7 +65,7 @@ struct LODEFTAB EOPIDENTRY *prgeopidentry; }; -extern "C" LODEFTAB D_00244950[]; +extern LODEFTAB D_00244950[]; INCLUDE_ASM("asm/nonmatchings/P2/brx", SetLoDefaults__FP2LO); #ifdef SKIP_ASM diff --git a/src/P2/cm.c b/src/P2/cm.c index f9f01817..30b3a3ce 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -245,7 +245,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmPosMat__FP2CMP6VECTORP7MATRIX3); extern "C" void SetCmLookAtSmooth(CM *pcm, int a1, VECTOR *pposEye, VECTOR *pposCenter, int a4, float u0, float u1, float u2, float u3, float u4, float u5); -extern "C" void SetCmLookAt(CM *pcm, VECTOR *pposEye, VECTOR *pposCenter) +void SetCmLookAt(CM *pcm, VECTOR *pposEye, VECTOR *pposCenter) { SetCmLookAtSmooth(pcm, 0, pposEye, pposCenter, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } @@ -257,7 +257,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCylindToWorldVelocity); extern "C" void ConvertCylindToWorldVelocity(void *a, void *b, void *c, float f0, float f1, float f2); extern "C" void ConvertWorldToCylindVelocity(void *a, void *b, void *c, void *d, void *e, void *f); -extern "C" void ResetCmLookAtSmooth(CM *pcm, void *pv) +void ResetCmLookAtSmooth(CM *pcm, void *pv) { VECTOR4 vTmp; diff --git a/src/P2/cplcy.c b/src/P2/cplcy.c index e0225f5d..1a912a91 100644 --- a/src/P2/cplcy.c +++ b/src/P2/cplcy.c @@ -3,17 +3,17 @@ */ #include -extern "C" void InitCplcy(CPLCY *pcplcy, CM *pcm) +void InitCplcy(CPLCY *pcplcy, CM *pcm) { pcplcy->pcm = pcm; } -extern "C" int FActiveCplcy(CPLCY *pcplcy) +int FActiveCplcy(CPLCY *pcplcy) { return STRUCT_OFFSET(pcplcy->pcm, 0x3D8, CPLCY *) == pcplcy; } -extern "C" void SetCpmanCpmt(CPMAN *pcpman, CPMT cpmt) +void SetCpmanCpmt(CPMAN *pcpman, CPMT cpmt) { pcpman->cpmt = cpmt; } @@ -59,7 +59,7 @@ LOOKK LookkCurCplook(CPLOOK *pcplook) return a[i]; } -extern "C" void InitCplook(CPLOOK *pcplook, CM *pcm) +void InitCplook(CPLOOK *pcplook, CM *pcm) { InitCplcy(pcplook, pcm); pcplook->fSoundPaused = 0; diff --git a/src/P2/crusher.c b/src/P2/crusher.c index 8a02bf7c..f6971f39 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -70,9 +70,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c2f0); INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c5e8); -// Shared: extern void *D_0027C00C; and a fwd decl of FUN_0014c5e8. -// Needs (GetSmaGoal/GetSmaCur/SetSmaGoal, SMA) and (OID) which are -// NOT transitively included by crusher.c yet. extern void *D_0027C00C; extern "C" void FUN_0014c5e8(void *p); diff --git a/src/P2/crv.c b/src/P2/crv.c index 8f57fe63..d1815ffd 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -37,8 +37,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FindAposClosestPointSegment__FP6VECTORP6C INCLUDE_ASM("asm/nonmatchings/P2/crv", ConvertApos__FiP6VECTORP7MATRIX4T2); -extern "C" char D_002176D0[]; -extern "C" char D_00217708[]; +extern char D_002176D0[]; +extern char D_00217708[]; CRV *PcrvNew(CRVK crvk) { diff --git a/src/P2/frm.c b/src/P2/frm.c index e02e0eb0..426558d5 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -120,10 +120,10 @@ void PrepareGsForFrameRender(FRM *pfrm) } } -extern "C" unsigned int D_002C3B00[]; -extern "C" unsigned int func_00100000[]; -extern "C" char D_00148D74[]; -extern "C" int D_00262310; +extern unsigned int D_002C3B00[]; +extern unsigned int func_00100000[]; +extern char D_00148D74[]; +extern int D_00262310; INCLUDE_ASM("asm/nonmatchings/P2/frm", check_anticrack_antigrab__Fv); #ifdef SKIP_ASM diff --git a/src/P2/game.c b/src/P2/game.c index 915697f5..df1ad3cd 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -59,14 +59,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", tally_world_completion); INCLUDE_ASM("asm/nonmatchings/P2/game", get_game_completion__Fv); -// TODO: switch matches but its rodata jump table dangles when built from C -// (the asm jtbl in 14B0F8.rodata.s references the function-local .L labels). INCLUDE_ASM("asm/nonmatchings/P2/game", UnlockIntroCutsceneFromWid__Fi); -// TODO: same rodata jump-table blocker as UnlockIntroCutsceneFromWid. INCLUDE_ASM("asm/nonmatchings/P2/game", DefeatBossFromWid); -extern "C" void UnlockEndgameCutscenesFromFgs(FGS fgs) +void UnlockEndgameCutscenesFromFgs(FGS fgs) { switch (fgs) { @@ -125,8 +122,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", LsFromWid); INCLUDE_ASM("asm/nonmatchings/P2/game", GrflsFromWid__F3WID); -extern "C" char D_00269984; -extern "C" char D_002623D8; +extern char D_00269984; +extern char D_002623D8; void UnloadGame() { diff --git a/src/P2/jt.c b/src/P2/jt.c index fb64407a..1f3fc49c 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -22,7 +22,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", AdjustJtDz__FP2JTiP2DZif); extern "C" void FUN_001d4c98(JT *pjt); -extern "C" void HandleJtGrfjtsc(JT *pjt) +void HandleJtGrfjtsc(JT *pjt) { int grfjtsc = STRUCT_OFFSET(pjt, 0x2254, int); if (grfjtsc == 0) diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index b709232c..54d8212e 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -3,7 +3,7 @@ #include <989snd.h> #include -extern "C" uchar D_002484B0[16][32]; +extern uchar D_002484B0[16][32]; extern "C" int FUN_0018e410(void *pv) { @@ -59,7 +59,7 @@ extern "C" void FUN_0018e4c0(int i) FUN_0018f0e8(&g_mpeg, D_002484B0[i]); } -extern "C" uchar *D_00269A08; +extern uchar *D_00269A08; extern "C" void FUN_0018e4f0(int param1, int i) { @@ -183,7 +183,7 @@ void CMpegAudio::Reset() } struct SW; -extern "C" SW *g_psw; +extern SW *g_psw; void PopSwReverb(SW *psw); extern "C" void Close__10CMpegAudio(void *pthis) @@ -271,9 +271,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018ef78); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018f0e8); -// Execute__5CMpeg's asm label mangles as a no-argument member (CMpeg::Execute()), but the -// function actually takes an OID* in $a1, so it must be called through an extern "C" -// declaration of the literal symbol until it is decompiled with a corrected signature. extern "C" void Execute__5CMpeg(CMpeg *pmpeg, OID *poid); void CMpeg::ExecuteOids() diff --git a/src/P2/rwm.c b/src/P2/rwm.c index de53eca7..1b3c015f 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -11,7 +11,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); extern "C" void FUN_001a93c8(RWM *prwm); -extern "C" void OnRwmRemove(RWM *prwm) +void OnRwmRemove(RWM *prwm) { OnLoRemove(prwm); FUN_001a93c8(prwm); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index ea9a812b..0f837054 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -100,7 +100,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateBusyLasenSenseTimes__Fv); INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateLasen__FP5LASENf); -extern "C" int D_002744D0; +extern int D_002744D0; void FreezeLasen(LASEN *plasen, int fFreeze) { diff --git a/src/P2/shadow.c b/src/P2/shadow.c index 80e39182..e55dec47 100644 --- a/src/P2/shadow.c +++ b/src/P2/shadow.c @@ -5,8 +5,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/shadow", InitShadow__FP6SHADOW); -extern "C" int D_002626D0; -extern "C" SUR D_0027DC20[]; +extern int D_002626D0; +extern SUR D_0027DC20[]; INCLUDE_ASM("asm/nonmatchings/P2/shadow", PostShadowLoad__FP6SHADOW); #ifdef SKIP_ASM diff --git a/src/P2/so.c b/src/P2/so.c index 716546c5..462d7748 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -35,11 +35,7 @@ void OnSoAdd(SO *pso) RebuildSoPhysHook(pso); } -// NOTE: This body per-symbol matches (match.sh), but enabling it trips an -// asm-emission bug in the build: the still-INCLUDE_ASM TranslateSoToPosSafe -// gets emitted 0x14 bytes too large (zero-filled words after its vadd.xyzw), -// shifting the unit and failing the checksum. Keep it wrapped until the -// surrounding functions are decompiled or the tooling quirk is fixed. +// Kept wrapped: unwrapping mis-sizes the still-asm TranslateSoToPosSafe and fails the checksum. INCLUDE_ASM("asm/nonmatchings/P2/so", OnSoRemove__FP2SO); void EnableSoPhys(SO *pso, int fPhys) @@ -98,17 +94,12 @@ void UpdateSoXfWorldHierarchy(SO *pso) &STRUCT_OFFSET(pso, 0x110, MATRIX3)); } -// alo.h declares the literal identifier `UpdateAloXfWorld__FP3ALO`, which both -// double-mangles if called and poisons the plain name `UpdateAloXfWorld` for -// GCC 2.95; bind a local alias to the real mangled symbol instead. -extern void _UpdateAloXfWorld(ALO *palo) __asm__("UpdateAloXfWorld__FP3ALO"); - void UpdateSoXfWorld(SO *pso) { SO *psoRoot; void (*pfn)(SO *); - _UpdateAloXfWorld(pso); + UpdateAloXfWorld(pso); psoRoot = STRUCT_OFFSET(pso, 0x50, SO *); // paloRoot pfn = (void (*)(SO *))STRUCT_OFFSET(STRUCT_OFFSET(psoRoot, 0x0, void *), 0xD8, void *); pfn(psoRoot); diff --git a/src/P2/sound.c b/src/P2/sound.c index 703376ca..b8739599 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -278,13 +278,13 @@ void ContinueMusic() } extern u_int D_00274728; -extern "C" void SfxhMusicUnknown1() +void SfxhMusicUnknown1() { snd_PauseSound(D_00274728); } extern u_int D_00274728; -extern "C" void SfxhMusicUnknown2() +void SfxhMusicUnknown2() { snd_ContinueSound(D_00274728); } @@ -530,8 +530,8 @@ void SetMvgkRvol(int channel, MVGK mvgk, float rvol) } extern float D_00274758[10][4]; -extern "C" void MvgkUnknown3(int fMute); -extern "C" void MvgkUnknown4(int mode); +void MvgkUnknown3(int fMute); +void MvgkUnknown4(int mode); void MvgkUnknown2() { CopyAb(D_00274838, D_00274758, 0xB0); @@ -544,7 +544,7 @@ void MvgkUnknown2() MvgkUnknown4(STRUCT_OFFSET(g_pgsCur, 0x19EC, int) & 0x40); } -extern "C" void MvgkUnknown3(int fMute) +void MvgkUnknown3(int fMute) { float rvol = 1.0f; if (fMute != 0) @@ -554,7 +554,7 @@ extern "C" void MvgkUnknown3(int fMute) SetMvgkRvol(3, MVGK_Music, rvol); } -extern "C" void MvgkUnknown4(int mode) +void MvgkUnknown4(int mode) { snd_SetPlaybackMode(mode != 0); } diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index 1c9057a2..b95c2311 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -483,9 +483,7 @@ CRef RefOpTruncate(int carg, CRef *aref, CFrame *pframe) return ref; } -// NOTE: matches per-symbol, but unwrapping it inflates the still-asm -// RefOpPredictAnimationEffect emission (same tooling bug as RefOpStopSound) -// and fails the checksum. Keep wrapped for now. +// Kept wrapped: unwrapping inflates the still-asm RefOpPredictAnimationEffect and fails the checksum. INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpAbs__FiP4CRefP6CFrame); #ifdef SKIP_ASM CRef RefOpAbs(int carg, CRef *aref, CFrame *pframe) @@ -651,10 +649,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpNearClipCenter__FiP4CRefP6CFr INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpStartSound__FiP4CRefP6CFrame); -// NOTE: matches per-symbol, but unwrapping it trips the asm-emission bug on -// the still-asm RefOpPredictAnimationEffect that follows (+0x14 of phantom -// bytes -> checksum fail), same as so.c OnSoRemove. Keep wrapped until the -// neighbor is decompiled. +// Kept wrapped: unwrapping inflates the still-asm RefOpPredictAnimationEffect and fails the checksum. INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpStopSound__FiP4CRefP6CFrame); #ifdef SKIP_ASM CRef RefOpStopSound(int carg, CRef *aref, CFrame *pframe) diff --git a/src/P2/sw.c b/src/P2/sw.c index 984b23db..ab67eb63 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -240,7 +240,7 @@ LO *PloGetSwProxySource(SW *psw, int ipsl) int c = p[0] - 1; LO **aplo = (LO **)p[1]; int i = c * 4; - asm volatile(""); // zero-byte scheduling barrier: keeps the count store between the sll and addu, as in the original + asm volatile(""); // scheduling barrier: preserve the original count-store ordering p[0] = c; return *(LO **)(i + (int)aplo); } @@ -380,7 +380,7 @@ int FLevelSwTertiary(SW *psw, WID wid) INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd710); -extern "C" uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); +uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); extern "C" int FUN_001dd758(SW *psw, int wid) { @@ -398,7 +398,7 @@ extern "C" int FUN_001dd758(SW *psw, int wid) return f; } -extern "C" uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); +uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); extern "C" int FUN_001dd7a0(SW *psw, int wid) { diff --git a/src/P2/water.c b/src/P2/water.c index 72b0586b..07cd8f03 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -135,12 +135,7 @@ void UpdateWaterMergeGroup(WATER *pwater) } /** - * @brief ~95% match. The VU0 transform, the LSG[16] clip workspace, the frame - * layout (fixed via LSG now being 16-byte-vector / 0x70) and the structure all - * match; only a few instructions in the g_pjt height branch differ (gcc - * schedules the g_pjt load into a delay slot, and the max.s/add.s operand order - * canonicalizes differently). Needs the permuter to settle. Kept under SKIP_ASM - * so the real build uses the asm and the checksum stays green. + * @brief ~95% match; kept under SKIP_ASM until the permuter settles the g_pjt height branch. */ INCLUDE_ASM("asm/nonmatchings/P2/water", UGetWaterSubmerged__FP5WATERP2SOP6VECTORT2); #ifdef SKIP_ASM From ab0cc5e23e91827a42bd2c01f59ec23f2a17f203 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Tue, 23 Jun 2026 00:03:24 +0200 Subject: [PATCH 124/134] Untrack CLAUDE.md and local-only .gitignore entries These were local agent/tooling artifacts that don't belong in the repo. The ignore patterns (CLAUDE.md, .claude/, docs/DECOMP_PROMPT.md, report_*.json) move to .git/info/exclude so they stay ignored locally without being tracked; .gitignore returns to its upstream form. CLAUDE.md stays on disk, untracked. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 7 ---- CLAUDE.md | 111 ----------------------------------------------------- 2 files changed, 118 deletions(-) delete mode 100644 CLAUDE.md diff --git a/.gitignore b/.gitignore index b6f4a9c9..dc71004c 100644 --- a/.gitignore +++ b/.gitignore @@ -88,10 +88,3 @@ __pycache__/ temp/ *.diff *.AppImage - -# Local Claude/agent tooling — keep out of git -CLAUDE.md -.claude/ -docs/DECOMP_PROMPT.md -report_old.json -report_premedium.json diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 3d737336..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,111 +0,0 @@ -# CLAUDE.md - -Guidance for working in this repo (a WIP decompilation of the PS2 game *Sly -Cooper and the Thievius Raccoonus*, NTSC-U `SCUS_971.98`). The goal is matching -C/C++ source: code that compiles (with the EE GCC 2.95 toolchain under Wine) to -bytes identical to the original executable. - -## Conventions & style - -Follow [docs/STYLEGUIDE.md](docs/STYLEGUIDE.md) for naming (Hungarian-style -prefixes: `p`ointer, `c`ount, `f`lag, `g_`lobal, `m_`ember…), capitalization -(`ALLCAPS` structs/enums, `UpperCamelCase` functions, `lowerCamelCase` -locals), brace-on-new-line + 4-space indent, and Doxygen comments. See -[docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for the end-to-end matching -workflow. Prefer official symbol names from the May 19 2002 prototype; when -unknown, use a clear descriptive name (offset-suffixed placeholders like -`unk_0x360` are acceptable for not-yet-understood struct fields). - -## Build & verify - -- Full build + checksum: `./scripts/build.sh` → expect `out/SCUS_971.98: OK`. - This (`sha1sum -c config/checksum.sha1`) is the ground-truth "did I break - anything" check — run it after touching shared headers. -- Per-function diff (interactive TUI): `./scripts/diff.sh [P2/unit]`. -- **Headless per-symbol match check** (the TUI needs a tty; use this for - automated/iterative work): `./scripts/match.sh `, e.g. - `./scripts/match.sh P2/water InitWater__FP5WATER`. It dual-builds and diffs the - symbol's instructions **and** relocations, printing `MATCH` or the diff. -- **Inspect a struct's real compiled layout**: - `./scripts/structoff.sh
'EXPR' ['EXPR' ...]`, e.g. - `./scripts/structoff.sh water.h 'sizeof(WATER)' '(int)(long)&((WATER*)0)->grfso'`. - Always probe with the EE compiler — host gcc gives wrong offsets (different - EABI alignment), and the `/* 0xNN */` header comments are not the compiled - offsets. -- Mechanics behind those scripts: the build defines `-DSKIP_ASM`, so the real - ELF is built from C; `INCLUDE_ASM` expands to nothing under `SKIP_ASM` and - pulls in the `.s` otherwise. Objdiff dual-builds `obj/target/*.o` (asm) vs - `obj/current/*.o` (your C) via `python3 configure.py --objects && ninja`. - objdump prints every unresolved call as `jal 0 `, so a real check must - compare the `R_MIPS_26` reloc rows too (`match.sh` does). - -## Suggested matching workflow - -1. Read the target `.s` in `asm/nonmatchings//.s` and the function - prototype in the header. Note every struct offset it touches. -2. Lay out the struct: probe sizes/offsets with `scripts/structoff.sh`, then add - fields to the (sub)struct via `STRUCT_PADDING` to land at absolute offsets — - **never grow the base structs** (see below). -3. Write the C under the `INCLUDE_ASM` line, wrapped in `#ifdef SKIP_ASM` / - `#endif`, so the asm is still available as the diff target. -4. Loop: edit → `scripts/match.sh ` → adjust for GCC 2.95 quirks - (see tips below) until it prints `MATCH`. -5. When matched, delete the `INCLUDE_ASM` line and the `#ifdef SKIP_ASM`/`#endif` - wrapper, leaving plain C. -6. After the file is done (or after any shared-header edit), run - `./scripts/build.sh` and confirm `out/SCUS_971.98: OK`. - -## Critical: do NOT grow engine base struct sizes - -The base classes `LO` → `ALO` → `SO` are intentionally **truncated**: -`sizeof(SO)` compiles to `0x2d0`, even though the real game's `SO` is `0x550`. -The `/* 0xNN */` offset comments in the base headers are aspirational targets, -**not** the compiled offsets (e.g. `ALO::grfzon` compiles to `0x7c`, documented -`0x88`). - -Each subclass instead places its own fields at correct **absolute** offsets -using explicit `STRUCT_PADDING(...)` **calibrated to the current truncated base -size** (e.g. `struct JT` pads ~1090 words to land `paloMine` at `0x1518`). - -Growing `SO`/`ALO`/`LO` to their "true" size shifts every subclass's fields and -**fails the checksum** — the breakage surfaces in compiled-C accessors of other -subclasses (e.g. `SetFsp` reading `JT`), not in your file. So when reversing a -new subclass: - -- Keep the base structs as-is. Lay out only the subclass's **own** fields inside - the subclass via leading `STRUCT_PADDING` from `sizeof(base)`. -- Do **not** redeclare base fields that live past the base's truncated end - (e.g. SO fields between `0x2d0` and a subclass's first own field) as members of - the subclass. Doing so pins the subclass layout to the *current* `sizeof(base)` - in two places, so when the base is later grown to its true size the redeclared - fields collide/shift and fail the checksum — and it misrepresents whose fields - they are. Reach such base fields via `STRUCT_OFFSET` instead, and delete the - redeclaration once it has no compiled users. -- For a base field accessed through a generic `SO*` (e.g. the `grfso` flag word - at `0x538`), reach it with `STRUCT_OFFSET(pSo, 0x538, int)` (defined in - `include/common.h`) — `STRUCT_OFFSET(ptr, off, type)` dereferences a typed - field at a raw byte offset, and `STRUCT_OFFSET_INDEX(ptr, off, type, i)` does - the same for an array element (it bakes in the `(i << 2) + off` ordering that - matches GCC's codegen). Prefer these over an ad-hoc cast or a redeclared - member so the offset access is self-documenting; note the field's meaning in a - comment. -- The subclass's leading `STRUCT_PADDING` is itself still calibrated to the - current `sizeof(base)` — that dependency is inherent to absolute-offset layout - and unavoidable; `STRUCT_OFFSET` only removes the *extra* coupling from - redeclaring base fields. - -## GCC 2.95 matching tips - -Matching is mostly about steering this old compiler's scheduler/allocator: - -- `x & ~A & ~B` with two constant masks gets folded into one `&` by the front - end / combiner. To force two separate ANDs (one load, two ANDs, one store), - load into a local and split into `tmp &= ~A; tmp &= ~B;`. -- Register choice is driven by variable live-ranges: reusing one variable pins - it to a register across its whole range; use a *fresh* local for a late block - to let the allocator pick the register the target uses. -- Mirror the original's pointer/index reuse — introduce locals like - `MRG *pmrg = &x->mrg;` or `int c = p->count;` when the asm keeps a value in a - register rather than reloading it. -- Store ordering: GCC may reverse independent store pairs; reorder the source - statements to compensate. From 3e67f3ace2339c215e53e3940b20cded65d43837 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Tue, 23 Jun 2026 00:12:54 +0200 Subject: [PATCH 125/134] Convert PchzFriendlyFromWid to plain C++; drop its extern "C" in game.h PchzFriendlyFromWid is an UpperCamelCase C++ function (its real symbol is mangled), so its extern "C" in game.h was only a still-asm shortcut, not a genuine requirement. Pre-mangle the symbol to PchzFriendlyFromWid__Fi (update symbol_addrs.txt + the INCLUDE_ASM label) and declare it plain C++; it has no C callers, so this is byte-neutral. The remaining extern "C" in game.h (tally_world_completion, reload_post_death, clr_8_bytes_1) are genuinely C-linkage exports of the level/save subsystem -- siblings of get_level_completion_by_id / LsFromWid, which are bound to their literal C symbols via __asm__(). Their real symbol IS the unmangled name, so extern "C" is the correct permanent declaration, not a wart. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 2 +- include/game.h | 2 +- src/P2/game.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 0e71f174..d9be152b 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -2086,7 +2086,7 @@ StartupGame__Fv = 0x160070; // type:func junk_00160090 = 0x160090; // type:func search_level_by_load_data = 0x1600A0; // type:func search_level_by_id = 0x160110; // type:func -PchzFriendlyFromWid = 0x160148; // type:func +PchzFriendlyFromWid__Fi = 0x160148; // type:func junk_00160178 = 0x160178; // type:func call_search_level_by_id = 0x160180; // type:func FFindLevel = 0x1601A0; // type:func diff --git a/include/game.h b/include/game.h index 7baff13e..6bf3c917 100644 --- a/include/game.h +++ b/include/game.h @@ -258,7 +258,7 @@ void StartupGame(); * * @param wid World ID. */ -extern "C" char *PchzFriendlyFromWid(int wid); +char *PchzFriendlyFromWid(int wid); // LevelLoadData *call_search_level_by_id(int level_id); diff --git a/src/P2/game.c b/src/P2/game.c index df1ad3cd..9febd8f9 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -38,7 +38,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", search_level_by_load_data); INCLUDE_ASM("asm/nonmatchings/P2/game", search_level_by_id); -INCLUDE_ASM("asm/nonmatchings/P2/game", PchzFriendlyFromWid); +INCLUDE_ASM("asm/nonmatchings/P2/game", PchzFriendlyFromWid__Fi); JUNK_WORD(0x24420010); From 4eab3dbb2569338d6657572d5d4adf8bac4c962a Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Tue, 23 Jun 2026 00:19:15 +0200 Subject: [PATCH 126/134] Strip decomp-noise comments from jt.h, so.h, sidebag.cpp Remove inline offset trailers, "// ..." placeholders, commented-out fields, and the padding/mangling/node-list rationale notes. Doxygen API blocks kept. Co-Authored-By: Claude Opus 4.8 (1M context) --- include/jt.h | 9 +++------ include/so.h | 11 +---------- src/P2/splice/sidebag.cpp | 3 --- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/include/jt.h b/include/jt.h index dde9b7aa..034d32a3 100644 --- a/include/jt.h +++ b/include/jt.h @@ -78,7 +78,6 @@ enum JTBS JTBS_Zap_Electric = 34, JTBS_Zap_Fire = 35, JTBS_Zap_Water = 36, - // ... JTBS_Unk_54 = 54, JTBS_Unk_55 = 55 @@ -103,7 +102,6 @@ enum JTHS */ enum JTCS { - // ... }; /** @@ -142,18 +140,17 @@ enum JTPDK */ struct JT : public STEP { - // 930 = 1090 - 160; SO now carries the 160-word (0x2d0..0x550) base gap. STRUCT_PADDING(930); undefined2 padding0_extra; - ALO *paloMine_0x1518; // 0x1518 + ALO *paloMine_0x1518; STRUCT_PADDING(832); undefined2 padding1_extra; - JTS jts; // 0x2220 + JTS jts; int unk_0x2224; - JTBS jtbs; // 0x2228 + JTBS jtbs; STRUCT_PADDING(328); undefined1 padding2_extra; diff --git a/include/so.h b/include/so.h index 37fe3c14..b593eb16 100644 --- a/include/so.h +++ b/include/so.h @@ -17,7 +17,6 @@ #include #include -// Forward. class CBinaryInputStream; struct XA; struct XP; @@ -31,7 +30,6 @@ struct WATER; */ enum CNSTR { - // ... }; struct CONSTR; @@ -43,7 +41,6 @@ typedef int GRFFSO; */ enum EGK { - // ... }; /** @@ -78,10 +75,7 @@ enum FSO */ struct SO : public ALO { - // SO's own fields (0x2d0..0x550) are not yet reversed; pad SO to its real - // size so subclasses inherit correct absolute offsets. - STRUCT_PADDING(160); // 0x2d0 .. 0x550 - //* 0x368 */ float mass; + STRUCT_PADDING(160); }; /** @@ -158,9 +152,6 @@ void SetSoMass(SO *pso, float m); void AdjustSoMomint(SO *pso, float r); -// The asm symbol has truncated GCC2 mangling (one declared param) but the -// function takes a discard mode in $a1 (0 = clear cache only, 1 = if-child, -// 2 = if-self, 3 = if-self strict); declare with the literal mangled name. extern "C" void DiscardSoXps__FP2SO(SO *pso, int mode); void UpdateSoPosWorldPrev(SO *pso); diff --git a/src/P2/splice/sidebag.cpp b/src/P2/splice/sidebag.cpp index 4ea49658..f244e4d4 100644 --- a/src/P2/splice/sidebag.cpp +++ b/src/P2/splice/sidebag.cpp @@ -40,9 +40,6 @@ CRef CSidebag::RefSetBinding(int n, CRef *pref) bool CSidebag::FFindBinding(int n, CRef *pref) { - // The sidebag is really a single pointer to a list of 0x10-byte nodes - // { int n; CRef ref; node *pNext } (see FUN_0011C498); reach the fields - // via STRUCT_OFFSET so the declared (placeholder) layout stays intact. void *psbb; for (psbb = STRUCT_OFFSET(this, 0x0, void *); psbb != NULL; psbb = STRUCT_OFFSET(psbb, 0xC, void *)) { From 0a6cc84a5827ac81d9a224318a132a5c9a52c681 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Tue, 23 Jun 2026 00:19:15 +0200 Subject: [PATCH 127/134] Untrack local decomp tooling scripts match.sh, structoff.sh, decomp_apply_drafts.py and decomp_lhf_draft.workflow.js are local agent/decomp tooling, not part of the game build (they were committed to main by an earlier session). Remove from tracking; they stay on disk via .git/info/exclude. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/decomp_apply_drafts.py | 152 --------------------------- scripts/decomp_lhf_draft.workflow.js | 73 ------------- scripts/match.sh | 49 --------- scripts/structoff.sh | 64 ----------- 4 files changed, 338 deletions(-) delete mode 100644 scripts/decomp_apply_drafts.py delete mode 100644 scripts/decomp_lhf_draft.workflow.js delete mode 100755 scripts/match.sh delete mode 100755 scripts/structoff.sh diff --git a/scripts/decomp_apply_drafts.py b/scripts/decomp_apply_drafts.py deleted file mode 100644 index 156686c1..00000000 --- a/scripts/decomp_apply_drafts.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python3 -# Apply workflow drafts one-at-a-time (isolated), build the unit object, diff -# against the target asm, and keep only byte-exact matches. Then apply all -# keepers together. Run: python3 /tmp/apply_drafts.py [verify|finalize] -import json, subprocess, os, re, sys - -REPO = "/home/johan/git/sly1" -os.chdir(REPO) -DRAFTS = json.load(open("/tmp/drafts.json")) - -def sh(cmd): - return subprocess.run(["bash", "-lc", cmd], capture_output=True, text=True) - -def cfile(unit): return f"src/{unit}.c" -def objbase(unit): return os.path.basename(unit) # P2/crv -> crv - -# ---- backup every file we might touch ---- -TOUCHED = set(cfile(d["unit"]) for d in DRAFTS) | {"config/symbol_addrs.txt"} -BAK = {f: open(f).read() for f in TOUCHED if os.path.exists(f)} - -def restore_all(): - for f, c in BAK.items(): - open(f, "w").write(c) - -def apply_one(unit, sym, code, includes, wrap=True): - f = cfile(unit) - s = open(f).read() - line = f'INCLUDE_ASM("asm/nonmatchings/{unit}", {sym});' - if line not in s: - return False, "INCLUDE_ASM line not found" - if wrap: - # keep INCLUDE_ASM (asm target) + add C under SKIP_ASM (current) - repl = line + "\n#ifdef SKIP_ASM\n" + code.rstrip() + "\n#endif" - else: - repl = code # finalize: plain C replaces the stub - s = s.replace(line, repl, 1) - for inc in includes or []: - tok = inc.strip() - if not tok: - continue - directive = f"#include {tok}" - if directive not in s: - ms = list(re.finditer(r'^#include .*$', s, re.M)) - if ms: - pos = ms[-1].end() - s = s[:pos] + "\n" + directive + s[pos:] - else: - s = directive + "\n" + s - open(f, "w").write(s) - return True, "" - -def norm_disasm(obj, sym): - r = sh(f"mips-linux-gnu-objdump -dr {obj} 2>/dev/null") - out, p = [], False - for ln in r.stdout.splitlines(): - if re.search(rf"<{re.escape(sym)}>:", ln): - p = True; continue - if p and ln.strip() == "": - break - if p: - ln = re.sub(r'^\s*[0-9a-f]+:\s+[0-9a-f]{8}\s+', '', ln) - ln = re.sub(r'^\s*[0-9a-f]+: (R_MIPS)', r'\1', ln) - ln = re.sub(r'[0-9a-f]+ <', '<', ln) - ln = ln.strip() - if ln: - out.append(ln) - return out - -def current_symname(unit, sym): - if "__" in sym: - return sym - obj = f"obj/current/{objbase(unit)}.o" - r = sh(f"mips-linux-gnu-objdump -t {obj} 2>/dev/null") - for ln in r.stdout.splitlines(): - m = re.search(rf"\b({re.escape(sym)}__\S+)", ln) - if m and (" F " in ln or " g " in ln): - return m.group(1) - return sym # maybe extern "C" / unchanged - -def has_asm_callers(sym): - # any other .s referencing this raw symbol? - r = sh(f"grep -rl '\\b{re.escape(sym)}\\b' asm/nonmatchings/ 2>/dev/null") - files = [x for x in r.stdout.split() if not x.endswith(f"/{sym}.s")] - return len(files) > 0 - -def data_sec_size(obj): - # total size of allocatable non-.text sections (rodata/data/bss/sdata...) - r = sh(f"mips-linux-gnu-objdump -h {obj} 2>/dev/null") - tot = 0 - for ln in r.stdout.splitlines(): - m = re.match(r'\s*\d+\s+(\.\S+)\s+([0-9a-f]{8})', ln) - if m: - name, sz = m.group(1), int(m.group(2), 16) - if name == ".text" or name.startswith((".pdr", ".reginfo", ".comment", ".gnu", ".mdebug", ".debug")): - continue - tot += sz - return tot - -def verify(): - sh("source env/bin/activate; python3 configure.py --objects >/dev/null 2>&1") - # cache clean data-section sizes per unit - restore_all() - units = sorted(set(d["unit"] for d in DRAFTS)) - sh("source env/bin/activate; ninja " + " ".join(f"obj/current/{objbase(u)}.o" for u in units) + " 2>&1") - clean_size = {u: data_sec_size(f"obj/current/{objbase(u)}.o") for u in units} - results = [] - for d in DRAFTS: - unit, sym = d["unit"], d["sym"] - restore_all() - ok, msg = apply_one(unit, sym, d["code"], d.get("includes")) - if not ok: - results.append([unit, sym, "SKIP", msg]); continue - oc, ot = f"obj/current/{objbase(unit)}.o", f"obj/target/{objbase(unit)}.o" - b = sh(f"source env/bin/activate; ninja {oc} {ot} 2>&1") - if b.returncode != 0: - err = b.stdout.strip().splitlines()[-1] if b.stdout.strip() else "compile failed" - results.append([unit, sym, "COMPILE_FAIL", err[:160]]); continue - if data_sec_size(oc) != clean_size[unit]: - results.append([unit, sym, "DATA_GROWTH", "adds rodata/data -> layout ripple"]); continue - cs = current_symname(unit, sym) - dt, dc = norm_disasm(ot, sym), norm_disasm(oc, cs) - if dt and dt == dc: - tag = "MATCH" if "__" in sym else ("MATCH_FUN_CALLERS" if has_asm_callers(sym) else "MATCH_FUN") - results.append([unit, sym, tag, cs]) - else: - results.append([unit, sym, "DIFFER", f"t={len(dt)} c={len(dc)}"]) - restore_all() - json.dump(results, open("/tmp/verify_results.json", "w"), indent=0) - from collections import Counter - print(Counter(r[2] for r in results)) - for r in results: - print(r) - -def finalize(): - results = json.load(open("/tmp/verify_results.json")) - keep = {(r[0], r[1]): r for r in results if r[2] in ("MATCH", "MATCH_FUN")} - restore_all() - sa = open("config/symbol_addrs.txt").read() - for d in DRAFTS: - key = (d["unit"], d["sym"]) - if key not in keep: - continue - apply_one(d["unit"], d["sym"], d["code"], d.get("includes"), wrap=False) - r = keep[key] - if r[2] == "MATCH_FUN": # rename raw FUN_ -> mangled in symbol_addrs - raw, mangled = d["sym"], r[3] - sa = re.sub(rf'^{re.escape(raw)}(\s)', mangled + r'\1', sa, flags=re.M) - open("config/symbol_addrs.txt", "w").write(sa) - print("applied", len(keep), "keepers") - -if __name__ == "__main__": - (verify if len(sys.argv) < 2 or sys.argv[1] == "verify" else finalize)() diff --git a/scripts/decomp_lhf_draft.workflow.js b/scripts/decomp_lhf_draft.workflow.js deleted file mode 100644 index b2c9bbb4..00000000 --- a/scripts/decomp_lhf_draft.workflow.js +++ /dev/null @@ -1,73 +0,0 @@ -export const meta = { - name: 'decomp-lhf-draft', - description: 'Draft matching C for tiny sly1 leaf functions (parallel, read-only)', - phases: [{ title: 'Draft' }], -} - -const cands = (typeof args === 'string' ? JSON.parse(args) : args) || [] -const BATCH = 4 -const batches = [] -for (let i = 0; i < cands.length; i += BATCH) batches.push(cands.slice(i, i + BATCH)) - -const SCHEMA = { - type: 'object', - additionalProperties: false, - properties: { - drafts: { - type: 'array', - items: { - type: 'object', - additionalProperties: false, - properties: { - unit: { type: 'string' }, - sym: { type: 'string' }, - code: { type: 'string' }, - includes: { type: 'array', items: { type: 'string' } }, - confidence: { type: 'number' }, - notes: { type: 'string' }, - }, - required: ['unit', 'sym', 'code', 'includes', 'confidence', 'notes'], - }, - }, - }, - required: ['drafts'], -} - -function draftPrompt(batch) { - const list = batch - .map((c) => `- unit "${c.unit}", symbol "${c.sym}" (asm: asm/nonmatchings/${c.unit}/${c.sym}.s, ~${c.n} instrs; source file: src/${c.unit}.c)`) - .join('\n') - return [ - 'You are decompiling TINY functions in the Sly 1 PS2 decomp at /home/johan/git/sly1 to C++ that compiles with EE GCC 2.95 to bytes IDENTICAL to the original MIPS assembly. Produce a matching C function for EACH candidate below.', - '', - 'Per candidate, do this:', - '1. Read asm/nonmatchings//.s. Work out EXACTLY what it does. Reg conventions: args $4=a0,$5=a1,$6=a2,$7=a3; float args $f12,$f14; int return in $2($v0); float return in $f0. daddu $2,$0,$0 => return 0; addiu $2,$0,1 => return 1.', - '2. Determine the signature. Demangle the symbol (e.g. Set...__FP9STEPGUARDf => void Set...(STEPGUARD*, float); __FP4ROST => (ROST*)). Cross-check the prototype in the unit header (grep the symbol base name under include/). For FUN_ names with no mangling, infer arg types from how regs are used and give the function the EXACT name FUN_xxxx; note that it will mangle (handled later).', - '3. Struct field access at offset 0xNN on a pointer: read the struct def. If a NAMED field already lands at that exact COMPILED offset, use it (verify with: scripts/structoff.sh \'(int)(long)&((TYPE*)0)->field\'). Otherwise use STRUCT_OFFSET(ptr, 0xNN, type) — macro in common.h: (*(type*)((uint8_t*)(ptr)+(offset))). MATCH THE WIDTH: lb=>char, lbu=>uchar, lh=>short, lhu=>ushort, lw/sw=>int (or a pointer/float type per use), ld/sd=>64-bit (use long long/uint64_t), lq/sq=>16-byte qword copy (use a 16-byte type; lower your confidence and explain in notes).', - '4. Float ops: a float field read/returned => float type. Compares/moves => mirror them.', - '5. Output the FULL C function definition that REPLACES this exact line in src/.c: INCLUDE_ASM("asm/nonmatchings/", );', - '6. In "includes": list ONLY header tokens (e.g. "") needed that are NOT already #included at the top of src/.c (read that file to check). Prefer adding nothing.', - '', - 'HARD RULES:', - '- DO NOT modify any struct/header, DO NOT add or grow struct fields. Use STRUCT_OFFSET for unnamed fields.', - '- DO NOT run ninja, configure.py, scripts/match.sh, or build/link ANYTHING (builds are serialized by the caller). You MAY run scripts/structoff.sh (it only writes /tmp) and read any file.', - '- Keep the C as direct as the asm (GCC 2.95 is literal). Mirror operation order.', - '- confidence: 0..1 (1 = you are sure it is a byte-exact match). Put any risk in notes (esp. lq/sq, float, or guessed FUN_ signatures).', - '', - 'Candidates:', - list, - '', - 'Return every candidate as a draft via the schema (one entry per candidate, even low-confidence ones).', - ].join('\n') -} - -phase('Draft') -const results = await parallel( - batches.map((b, i) => () => - agent(draftPrompt(b), { label: `draft#${i + 1} [${b.length}]`, phase: 'Draft', schema: SCHEMA }) - ) -) - -const drafts = results.filter(Boolean).flatMap((r) => (r && r.drafts) || []) -log(`drafted ${drafts.length} / ${cands.length} functions`) -return { drafts } diff --git a/scripts/match.sh b/scripts/match.sh deleted file mode 100755 index 345535dd..00000000 --- a/scripts/match.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# -# Headless per-symbol match check (no TUI). Builds the target (asm) and current -# (your C, -DSKIP_ASM) objects, then diffs a single symbol's instructions AND -# relocations. Prints "MATCH" or the instruction diff. -# -# Usage: scripts/match.sh -# splat unit path, e.g. P2/water (object: obj/{target,current}/water.o) -# -# Example: scripts/match.sh P2/water InitWater__FP5WATER -# -set -e - -if [ -z "$2" ]; then - echo "Usage: $0 (e.g. $0 P2/water InitWater__FP5WATER)" >&2 - exit 1 -fi - -cd "$(dirname "$0")/.." -if [ -z "$VIRTUAL_ENV" ]; then - source "env/bin/activate" -fi - -UNIT="$1" -SYM="$2" -OBJ="$(basename "$UNIT").o" - -python3 configure.py --objects >/dev/null -ninja "obj/target/$OBJ" "obj/current/$OBJ" >/dev/null - -for v in target current; do - mips-linux-gnu-objdump -dr "obj/$v/$OBJ" 2>/dev/null | awk -v s="<$SYM>:" ' - $0 ~ s {p=1} p && /^$/ {p=0} p {print}' \ - | sed -E 's/^\s*[0-9a-f]+:\s+[0-9a-f]{8}\s+//; s/^\s*[0-9a-f]+: (R_MIPS)/\1/; s/^[0-9a-f]+ "/tmp/match_$v.txt" -done - -if ! [ -s /tmp/match_target.txt ]; then - echo "error: symbol '$SYM' not found in obj/target/$OBJ" >&2 - exit 2 -fi - -if diff -q /tmp/match_target.txt /tmp/match_current.txt >/dev/null; then - echo "MATCH: $SYM" -else - echo "DIFFERS: $SYM" - diff /tmp/match_target.txt /tmp/match_current.txt - exit 1 -fi diff --git a/scripts/structoff.sh b/scripts/structoff.sh deleted file mode 100755 index 58081bc3..00000000 --- a/scripts/structoff.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -# -# Print REAL compiled struct offsets/sizes using the EE (GCC 2.95) toolchain. -# Host gcc gives wrong layout (different EABI alignment), so always probe with -# the actual compiler. Each EXPR must be an integer constant expression; use a -# null base for offsetof-style queries, e.g. (int)(long)&((WATER*)0)->grfso -# -# Usage: scripts/structoff.sh
'EXPR' ['EXPR' ...] -# -# Example: -# scripts/structoff.sh water.h 'sizeof(WATER)' \ -# '(int)(long)&((WATER*)0)->grfso' '(int)(long)&((WATER*)0)->zpd.cploThrow' -# -set -e - -if [ -z "$2" ]; then - echo "Usage: $0
'EXPR' ['EXPR' ...]" >&2 - exit 1 -fi - -cd "$(dirname "$0")/.." - -HDR="$1" -shift - -SRC="$(mktemp /tmp/structoff.XXXXXX.cpp)" -OBJ="${SRC%.cpp}.o" -trap 'rm -f "$SRC" "$OBJ"' EXIT - -{ - echo "#include <$HDR>" - i=0 - for e in "$@"; do - echo "int probe_$i(){ return (int)($e); }" - i=$((i + 1)) - done -} > "$SRC" - -WINEDEBUG=-all wine tools/cc/bin/ee-gcc.exe -c -Iinclude -isystem include/sdk/ee \ - -isystem include/gcc -x c++ -B"$PWD/tools/cc/lib/gcc-lib/ee/2.95.2/" \ - -O2 -G0 -ffast-math "$SRC" -o "$OBJ" 2>&1 | grep -viE 'warning|radv' || true - -if ! [ -s "$OBJ" ]; then - echo "error: compile failed (run without the grep filter to see why)" >&2 - exit 2 -fi - -DIS="$(mips-linux-gnu-objdump -d "$OBJ" 2>/dev/null)" -echo "# <$HDR>" -i=0 -for e in "$@"; do - # Each probe is a constant function: jr ra ; li v0,N (or move v0,zero for 0). - block="$(echo "$DIS" | awk -v f=" Date: Tue, 23 Jun 2026 23:49:57 +0200 Subject: [PATCH 128/134] Drop extern "C" from decompiled FUN_/func_ placeholders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The codebase compiles as C++, so functions whose binary symbol is unmangled needed an extern "C" wrapper. Many FUN_xxxx/func_xxxx placeholders, however, are already decompiled (real C body, no INCLUDE_ASM) and only kept the wrapper to emit the unmangled symbol_addrs label. Convert ~77 of them to plain C++: pre-mangle their config/symbol_addrs.txt entries to the GCC2-mangled form and drop extern "C". This is checksum-neutral (symbols are stripped from the final ELF; the compiled bytes are unchanged) — splat regenerates the asm callers, .s filenames, and auto linker scripts on the next configure. Also fix two latent SKIP_ASM build errors surfaced by the cleanup: - OnDifficultyPlayerDeath: header declared it plain C++ while the definition used extern "C"; drop the wrapper so both agree. - ub.c: declare PostGomerLoad in its owning header (gomer.h). Left as-is: functions still in assembly (INCLUDE_ASM / asm forward-decls), where extern "C" is correct scaffolding until they are reversed; plus FUN_001c9a48 (conflicting signatures across files) and the rwm/font mixed extern "C" blocks. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- config/symbol_addrs.txt | 152 ++++++++++++++++++++-------------------- include/gomer.h | 2 + src/P2/alo.c | 18 ++--- src/P2/binoc.c | 12 +--- src/P2/chkpnt.c | 6 +- src/P2/cm.c | 2 +- src/P2/coin.c | 12 +--- src/P2/crusher.c | 6 +- src/P2/dartgun.c | 2 - src/P2/difficulty.c | 2 +- src/P2/emitter.c | 2 - src/P2/font.c | 2 - src/P2/jlo.c | 4 +- src/P2/lgn.c | 2 +- src/P2/missile.c | 4 +- src/P2/mpeg.c | 10 ++- src/P2/murray.c | 4 +- src/P2/path.c | 2 +- src/P2/prompt.c | 2 - src/P2/puffer.c | 8 +-- src/P2/rog.c | 2 +- src/P2/rumble.c | 2 +- src/P2/screen.c | 5 +- src/P2/shd.c | 3 +- src/P2/so.c | 4 +- src/P2/sound.c | 12 ++-- src/P2/sqtr.c | 2 +- src/P2/step.c | 2 - src/P2/stepguard.c | 4 +- src/P2/stephide.c | 4 +- src/P2/steppipe.c | 4 +- src/P2/steprail.c | 2 +- src/P2/sw.c | 18 ++--- src/P2/tank.c | 3 +- src/P2/tn.c | 4 +- src/P2/wm.c | 2 +- 36 files changed, 145 insertions(+), 182 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index d9be152b..219aae97 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -778,13 +778,13 @@ SetAloRotationSmoothDetail__FP3ALOP4SMPA = 0x12A320; // type:f SetAloDefaultAckPos__FP3ALO3ACK = 0x12A390; // type:func SetAloDefaultAckRot__FP3ALO3ACK = 0x12A398; // type:func SetAloRestorePosition__FP3ALOi = 0x12A3A0; // type:func -FUN_0012a3c8 = 0x12A3C8; // type:func -FUN_0012a3e8 = 0x12A3E8; // type:func -FUN_0012a418 = 0x12A418; // type:func +FUN_0012a3c8__FP3ALOi = 0x12A3C8; // type:func +FUN_0012a3e8__FP3ALOi = 0x12A3E8; // type:func +FUN_0012a418__FP3ALOPi = 0x12A418; // type:func SetAloRestorePositionAck__FP3ALO3ACK = 0x12A430; // type:func SetAloRestoreRotation__FP3ALOi = 0x12A478; // type:func SetAloRestoreRotationAck__FP3ALO3ACK = 0x12A4A0; // type:func -FUN_0012a4e8 = 0x12A4E8; // type:func +FUN_0012a4e8__FP3ALOi = 0x12A4E8; // type:func SetAloLookAt__FP3ALO3ACK = 0x12A528; // type:func SetAloLookAtIgnore__FP3ALOf = 0x12A580; // type:func GetAloLookAtIgnore__FP3ALOPf = 0x12A5B8; // type:func @@ -800,12 +800,12 @@ SetAloLookAtEnabledPriority__FP3ALOi = 0x12A770; // type:f GetAloLookAtEnabledPriority__FP3ALOPi = 0x12A7A8; // type:func SetAloLookAtDisabledPriority__FP3ALOi = 0x12A7C0; // type:func GetAloLookAtDisabledPriority__FP3ALOPi = 0x12A7F8; // type:func -FUN_0012a810 = 0x12A810; // type:func +FUN_0012a810__FP3ALOi = 0x12A810; // type:func FUN_0012a848__FP3ALOPi = 0x12A848; // type:func -FUN_0012a860 = 0x12A860; // type:func -FUN_0012a888 = 0x12A888; // type:func +FUN_0012a860__FP3ALOT0 = 0x12A860; // type:func +FUN_0012a888__FP3ALOPP3ALO = 0x12A888; // type:func FUN_0012a8b8__FP3ALO = 0x12A8B8; // type:func -FUN_0012a8c8 = 0x12A8C8; // type:func +FUN_0012a8c8__FP3ALO = 0x12A8C8; // type:func SetAloRotationMatchesVelocity__FP3ALOff3ACK = 0x12A8D8; // type:func PtargetEnsureAlo__FP3ALO = 0x12A970; // type:func SetAloTargetAttacks__FP3ALOi = 0x12A9C8; // type:func @@ -997,19 +997,19 @@ FUN_00134b48 = 0x134B48; // type:func DrawBinocFilter = 0x135228; // type:func FUN_00135550 = 0x135550; // type:func open_close_binoc = 0x1356C0; // type:func -FUN_001357f0 = 0x1357F0; // type:func +FUN_001357f0__FPvT0 = 0x1357F0; // type:func FUN_00135858 = 0x135858; // type:func FUN_001358d0 = 0x1358D0; // type:func junk_00135E20 = 0x135E20; // type:func -FUN_00135E30 = 0x135E30; // type:func +FUN_00135E30__FPvN20 = 0x135E30; // type:func junk_00135E40 = 0x135E40; // type:func -FUN_00135E48 = 0x135E48; // type:func +FUN_00135E48__FPviP6VECTOR = 0x135E48; // type:func junk_00135E70 = 0x135E70; // type:func SetBinocBfk = 0x135E78; // type:func FUN_00135f48 = 0x135F48; // type:func FUN_00136040 = 0x136040; // type:func FUN_00136238 = 0x136238; // type:func -FUN_001363d0 = 0x1363D0; // type:func +FUN_001363d0__FP5BINOC = 0x1363D0; // type:func SetBinocAchzDraw = 0x136408; // type:func FDoneBinocAchz__FP5BINOC = 0x136530; // type:func SetBinocLookat__FP5BINOCP3ALO = 0x1365A0; // type:func @@ -1019,7 +1019,7 @@ FUN_00136648 = 0x136648; // type:func DrawBinoc = 0x1366A0; // type:func GetBinocReticleFocus__FP5BINOCPfT1 = 0x136EC8; // type:func FUN_00136ef8 = 0x136EF8; // type:func -FUN_00136fa8 = 0x136FA8; // type:func +FUN_00136fa8__FP5BINOC = 0x136FA8; // type:func binoc__static_initialization_and_destruction_0 = 0x136FE8; // type:func SetPos__8CTextBoxff = 0x137228; // type:func SetSize__8CTextBoxff = 0x137238; // type:func @@ -1305,10 +1305,10 @@ BindChkpnt__FP6CHKPNT = 0x141338; // type:func PostChkpntLoad__FP6CHKPNT = 0x141438; // type:func CloneChkpnt__FP6CHKPNTT0 = 0x1415D0; // type:func UpdateChkpnt__FP6CHKPNTf = 0x141690; // type:func -FUN_001417f0 = 0x1417F0; // type:func +FUN_001417f0__FP6CHKPNTP3WKR = 0x1417F0; // type:func TriggerChkpnt__FP6CHKPNT = 0x141870; // type:func -FUN_001419A0 = 0x1419A0; // type:func -FUN_001419C0 = 0x1419C0; // type:func +FUN_001419A0__FP6CHKPNTi = 0x1419A0; // type:func +FUN_001419C0__FP6CHKPNTi = 0x1419C0; // type:func FUN_001419E0__FPii = 0x1419E0; // type:func g_chkmgr = 0x261420; // size:0x430 @@ -1418,7 +1418,7 @@ SetCm = 0x145718; // type:func PsoEnemyStepguard = 0x145810; // type:func FUN_00145950 = 0x145950; // type:func FUN_00145b68 = 0x145B68; // type:func -FUN_00145DD8 = 0x145DD8; // type:func +FUN_00145DD8__FUiP2CM = 0x145DD8; // type:func FUN_00145de8 = 0x145DE8; // type:func FUN_00145e68 = 0x145E68; // type:func PushLookkCm__FP2CM5LOOKK = 0x145FB8; // type:func @@ -1492,7 +1492,7 @@ UpdateDprize__FP6DPRIZEf = 0x147428; // type:func RenderDprizeAll__FP6DPRIZEP2CMP2RO = 0x1478F0; // type:func SetDprizeDprizes__FP6DPRIZE7DPRIZES = 0x147AB0; // type:func InitCoin__FP4COIN = 0x147E40; // type:func -FUN_00147ed0 = 0x147ED0; // type:func +FUN_00147ed0__FP6DPRIZE = 0x147ED0; // type:func FUN_00147ef8 = 0x147EF8; // type:func UpdateCoin__FP4COINf = 0x147FB0; // type:func CreateSwCharm__FP2SW = 0x148038; // type:func @@ -1504,19 +1504,19 @@ SetCharmDprizes__FP5CHARM7DPRIZES = 0x148470; // type:func InitKey__FP3KEY = 0x148510; // type:func SetKeyDprizes__FP3KEY7DPRIZES = 0x148598; // type:func FUN_00148698 = 0x148698; // type:func -FUN_00148718 = 0x148718; // type:func -FUN_00148748 = 0x148748; // type:func +FUN_00148718__FP6DPRIZE = 0x148718; // type:func +FUN_00148748__FPv = 0x148748; // type:func FUN_00148770 = 0x148770; // type:func -FUN_00148828 = 0x148828; // type:func +FUN_00148828__FP6DPRIZEf = 0x148828; // type:func FUN_00148888 = 0x148888; // type:func FUN_00148910__FPfT0 = 0x148910; // type:func FUN_00148938 = 0x148938; // type:func CpdprizeAttractSwDprizes__FP2SW3CIDP6VECTORiPP6DPRIZE = 0x148AC0; // type:func RemoveSwExtraneousCharms__FP2SW = 0x148CE0; // type:func FUN_00148d90 = 0x148D90; // type:func -FUN_00148e18 = 0x148E18; // type:func +FUN_00148e18__FPv = 0x148E18; // type:func FUN_00148e40 = 0x148E40; // type:func -FUN_00148ef8 = 0x148EF8; // type:func +FUN_00148ef8__FP4COINf = 0x148EF8; // type:func increment_and_show_life_count = 0x148F80; // type:func CollectLifetkn__FP7LIFETKN = 0x148FF0; // type:func FUN_00149168__FP6DPRIZE = 0x149168; // type:func @@ -1593,14 +1593,14 @@ InitCrbrain__FP7CRBRAIN = 0x14C018; // type:func post_load_crbrain = 0x14C138; // type:func FUN_0014c2f0 = 0x14C2F0; // type:func FUN_0014c5e8 = 0x14C5E8; // type:func -FUN_0014c668 = 0x14C668; // type:func +FUN_0014c668__FPvi = 0x14C668; // type:func update_crbrain = 0x14C6E0; // type:func -FUN_0014c788 = 0x14C788; // type:func +FUN_0014c788__FPv = 0x14C788; // type:func FUN_0014c820__FPv = 0x14C820; // type:func FUN_0014c838__FPvi = 0x14C838; // type:func FUN_0014c858 = 0x14C858; // type:func FUN_0014cba8 = 0x14CBA8; // type:func -FUN_0014cd70 = 0x14CD70; // type:func +FUN_0014cd70__FPv = 0x14CD70; // type:func FUN_0014cdc8 = 0x14CDC8; // type:func handle_crbrain_message = 0x14CF30; // type:func @@ -1680,7 +1680,7 @@ s_asnipDart = 0x261CC8; InitDartgun__FP7DARTGUN = 0x14F740; // type:func HandleDartgunMessage__FP7DARTGUN5MSGIDPv = 0x14F770; // type:func BindDartgun__FP7DARTGUN = 0x14F850; // type:func -FUN_0014f900 = 0x14F900; // type:func +FUN_0014f900__FP7DARTGUN = 0x14F900; // type:func PostDartgunLoad__FP7DARTGUN = 0x14F920; // type:func UpdateDartgun__FP7DARTGUNf = 0x14FA88; // type:func FIgnoreDartgunIntersection__FP7DARTGUNP2SO = 0x14FBE0; // type:func @@ -1839,7 +1839,7 @@ PemitterEnsureEmitter__FP7EMITTER4ENSK = 0x1557B8; // AddEmitterSkeleton__FP7EMITTER3OIDT1ffff = 0x1557D0; // type:func ModifyEmitterParticles__FP7EMITTER = 0x155868; // type:func UpdateEmitter__FP7EMITTERf = 0x155AB0; // type:func -FUN_00155f28 = 0x155F28; // type:func +FUN_00155f28__FP2SO = 0x155F28; // type:func PauseEmitter__FP7EMITTERf = 0x155F78; // type:func PauseEmitterIndefinite__FP7EMITTER = 0x155F90; // type:func UnpauseEmitter__FP7EMITTER = 0x155FA0; // type:func @@ -2332,7 +2332,7 @@ SolveAloIK__FP3ALO = 0x16C528; // type:func InitJlo__FP3JLO = 0x16CE00; // type:func LoadJloFromBrx__FP3JLOP18CBinaryInputStream = 0x16CE80; // type:func PostJloLoad__FP3JLO = 0x16CF70; // type:func -FUN_0016d040 = 0x16D040; // type:func +FUN_0016d040__FP3JLO3OID = 0x16D040; // type:func PresetJloAccel__FP3JLOf = 0x16D0C0; // type:func UpdateJlo__FP3JLOf = 0x16D128; // type:func JlosNextJlo__FP3JLO = 0x16D1E0; // type:func @@ -2340,7 +2340,7 @@ SetJloJlovol__FP3JLOP6JLOVOL = 0x16D3F0; // type:func FireJlo__FP3JLO = 0x16D490; // type:func LandJlo__FP3JLO = 0x16D788; // type:func JumpJlo__FP3JLO = 0x16D828; // type:func -FUN_0016d928 = 0x16D928; // type:func +FUN_0016d928__FP3JLO = 0x16D928; // type:func FUN_0016d9a8 = 0x16D9A8; // type:func HandleJloMessage__FP3JLO5MSGIDPv = 0x16DA00; // type:func SetJloJlos__FP3JLO4JLOS = 0x16DAC0; // type:func @@ -2555,7 +2555,7 @@ UseLgnCharm__FP3LGN = 0x181AF0; // type:func ApplyLgnThrow__FP3LGNP2PO = 0x181B20; // type:func FTakeLgnDamage__FP3LGNP3ZPR = 0x181BC8; // type:func HandleLgnMessage__FP3LGN5MSGIDPv = 0x181D28; // type:func -FUN_00181d88 = 0x181D88; // type:func +FUN_00181d88__FPUc = 0x181D88; // type:func SetLgnLgns__FP3LGN4LGNS = 0x181DA8; // type:func UpdateLgnrAim__FP4LGNRP3JOY = 0x181ED0; // type:func DrawLgnr__FP4LGNR = 0x1821B0; // type:func @@ -2888,8 +2888,8 @@ ProjectMissileTransform__FP7MISSILEfi = 0x18D9B8; // type:func FireMissile__FP7MISSILEP3ALOP6VECTOR = 0x18DA40; // type:func RenderMissileAll__FP7MISSILEP2CMP2RO = 0x18DB20; // type:func FUN_0018dc88 = 0x18DC88; // type:func -FUN_0018dd50 = 0x18DD50; // type:func -FUN_0018dd78 = 0x18DD78; // type:func +FUN_0018dd50__FPvi = 0x18DD50; // type:func +FUN_0018dd78__FPvi = 0x18DD78; // type:func InitAccmiss__FP7ACCMISS = 0x18DDA0; // type:func FireAccmiss__FP7ACCMISSP3ALOP6VECTOR = 0x18DDD8; // type:func PresetAccmissAccel__FP7ACCMISSf = 0x18DE70; // type:func @@ -2902,10 +2902,10 @@ s_asnipMissile = 0x2699b0; //////////////////////////////////////////////////////////////// // P2/mpeg.c //////////////////////////////////////////////////////////////// -FUN_0018e410 = 0x18E410; // type:func -FUN_0018e480 = 0x18E480; // type:func -FUN_0018e4c0 = 0x18E4C0; // type:func -FUN_0018e4f0 = 0x18E4F0; // type:func +FUN_0018e410__FPv = 0x18E410; // type:func +FUN_0018e480__Fi = 0x18E480; // type:func +FUN_0018e4c0__Fi = 0x18E4C0; // type:func +FUN_0018e4f0__Fii = 0x18E4F0; // type:func FUN_0018e558 = 0x18E558; // type:func StartupMpeg__Fv = 0x18E5E8; // type:func Init__15CQueueOutputIopii = 0x18E678; // type:func @@ -2964,8 +2964,8 @@ FUN_0018ffb0 = 0x18FFB0; // type:func OnMurrayExitingSgs__FP6MURRAY3SGS = 0x1900A0; // type:func UpdateMurrayGoal__FP6MURRAYi = 0x190128; // type:func UpdateMurraySgs__FP6MURRAY = 0x190258; // type:func -FUN_001903f0 = 0x1903F0; // type:func -FUN_00190450 = 0x190450; // type:func +FUN_001903f0__FP6MURRAYPv = 0x1903F0; // type:func +FUN_00190450__FP6MURRAYP3WKR = 0x190450; // type:func FAbsorbMurrayWkr__FP6MURRAYP3WKR = 0x1904E0; // type:func FDetectMurray__FP6MURRAY = 0x190570; // type:func FCanMurrayAttack__FP6MURRAY = 0x190658; // type:func @@ -2996,7 +2996,7 @@ LoadPathzoneFromBrx__FP8PATHZONEP18CBinaryInputStream = 0x1916D0; // type:func HookupCg__FP2CG = 0x1919F8; // type:func CposFindPathzonePath__FP8PATHZONEP6VECTORT1iT1 = 0x191A68; // type:func FindPathzoneClosestPoint__FP8PATHZONEP6VECTORT1 = 0x191A88; // type:func -FUN_00191aa8 = 0x191AA8; // type:func +FUN_00191aa8__FPvP6VECTORT1iP3LSG = 0x191AA8; // type:func FUN_00191ac8 = 0x191AC8; // type:func ChoosePathzoneRandomPoint__FP8PATHZONEP6VECTOR = 0x191C78; // type:func @@ -3099,7 +3099,7 @@ FUN_00193ee8 = 0x193ee8; // type:func FUN_00193f88__Fv = 0x193f88; // type:func FUN_00193fb8 = 0x193fb8; // type:func OnPromptActive__FP6PROMPTi = 0x1940e8; // type:func -FUN_00194278 = 0x194278; // type:func +FUN_00194278__FP6PROMPTi5WIPEK = 0x194278; // type:func FUN_00194398__Fv = 0x194398; // type:func UpdatePromptActive__FP6PROMPTP3JOY = 0x1943e8; // type:func SetPrompt__FP6PROMPT3PRP3PRK = 0x194d30; // type:func @@ -3137,13 +3137,13 @@ FFilterPuffer__FP6PUFFERP2SO = 0x196E48; // type:func UpdatePuffer__FP6PUFFERf = 0x196EB0; // type:func PpufftChoosePuffer__FP6PUFFER = 0x1971B8; // type:func FUN_001973d8 = 0x1973D8; // type:func -FUN_00197458 = 0x197458; // type:func +FUN_00197458__FPvi = 0x197458; // type:func OnPufferActive__FP6PUFFERiP2PO = 0x1974D8; // type:func UpdatePufferActive__FP6PUFFERP3JOYf = 0x1974F8; // type:func FUN_00197788 = 0x197788; // type:func FUN_00197848 = 0x197848; // type:func -FUN_00197a08 = 0x197A08; // type:func -FUN_00197a68 = 0x197A68; // type:func +FUN_00197a08__FPvT0 = 0x197A08; // type:func +FUN_00197a68__FPvT0 = 0x197A68; // type:func AddPufferWaterAcceleration__FP6PUFFERP5WATERf = 0x197A88; // type:func HandlePufferMessage__FP6PUFFER5MSGIDPv = 0x197F10; // type:func PostPuffcLoad__FP5PUFFC = 0x198090; // type:func @@ -3433,7 +3433,7 @@ RobkCur__Fv = 0x1A4898; // type:func BindRob__FP3ROB = 0x1A48C0; // type:func PostRobLoad__FP3ROB = 0x1A4B30; // type:func UpdateRob__FP3ROBf = 0x1A4C48; // type:func -FUN_001a4d60 = 0x1A4D60; // type:func +FUN_001a4d60__FP3ROB = 0x1A4D60; // type:func RobsNextRob__FP3ROB = 0x1A4DC0; // type:func SetRobRobs__FP3ROB4ROBS = 0x1A4EF0; // type:func AddRobRoc__FP3ROB = 0x1A5120; // type:func @@ -3500,7 +3500,7 @@ SetRumbleRums__FP6RUMBLE4RUMS = 0x1A7D98; // type:func StopRumbleActuators__FP6RUMBLE = 0x1A7E40; // type:func FUN_001A7E70__Fv = 0x1A7E70; // type:func FUN_001A7E90 = 0x1A7E90; // type:func -FUN_001A7EE8 = 0x1A7EE8; // type:func +FUN_001A7EE8__FP2GS = 0x1A7EE8; // type:func FUN_001A7F50 = 0x1A7F50; // type:func DAT_0026c3dc = 0x26C3DC; @@ -3603,7 +3603,7 @@ DtVisibleTrunkctr__FP8TRUNKCTR = 0x1ABE40; // type:func DtVisibleCrusherctr__FP10CRUSHERCTR = 0x1ABE50; // type:func FUN_001ABE60__Fv = 0x1ABE60; // type:func FUN_001abe70 = 0x1ABE70; // type:func -FUN_001ac060 = 0x1AC060; // type:func +FUN_001ac060__FP5TIMER = 0x1AC060; // type:func FUN_001ac0e8 = 0x1AC0E8; // type:func PostNoteLoad__FP4NOTE = 0x1AC5C0; // type:func SetNoteAchzDraw__FP4NOTEPc = 0x1AC638; // type:func @@ -3641,7 +3641,7 @@ DrawAttract__FP7ATTRACT = 0x1AE220; // type:func DrawLineScreen__FUiUiUiUiUiUiG4RGBAi = 0x1AE3B8; // type:func FUN_001ae510 = 0x1AE510; // type:func FUN_001ae5e0 = 0x1AE5E0; // type:func -FUN_001ae758 = 0x1AE758; // type:func +FUN_001ae758__FP4BLOT = 0x1AE758; // type:func FUN_001ae7f8__FP3CTR5BLOTS = 0x1AE7F8; // type:func FUN_001ae820 = 0x1AE820; // type:func FUN_001aea08 = 0x1AEA08; // type:func @@ -4004,8 +4004,8 @@ FAbsorbSoWkr__FP2SOP3WKR = 0x1BC320; // type:func CloneSoPhys__FP2SOT0i = 0x1BC368; // type:func FUN_001bc4d8 = 0x1BC4D8; // type:func FUN_001bc670 = 0x1BC670; // type:func -FUN_001bc710 = 0x1BC710; // type:func -FUN_001bc748 = 0x1BC748; // type:func +FUN_001bc710__FP2SOi = 0x1BC710; // type:func +FUN_001bc748__FP2SOPi = 0x1BC748; // type:func //////////////////////////////////////////////////////////////// @@ -4039,17 +4039,17 @@ SbpEnsureBank__Fi = 0x1BE268; // type:func SbpEnsureBank__F5SFXID = 0x1BE4A8; // type:func NewSfx__FPP3SFX = 0x1BE4D8; // type:func FContinuousSound__F5SFXID = 0x1BE568; // type:func -FUN_001BE5D8 = 0x1BE5D8; // type:func +FUN_001BE5D8__Fv = 0x1BE5D8; // type:func SetVagUnpaused__Fv = 0x1BE5E8; // type:func PreloadVag__FPc2FK = 0x1BE5F8; // type:func -FUN_001be708 = 0x1BE708; // type:func +FUN_001be708__Fv = 0x1BE708; // type:func PreloadVag1 = 0x1BE728; // type:func FPauseForVag__Fv = 0x1BE810; // type:func RefreshPambVolPan__FP3AMB = 0x1BE860; // type:func -FUN_001be8f8 = 0x1BE8F8; // type:func +FUN_001be8f8__FP3ALOPP3AMBff = 0x1BE8F8; // type:func FVagPlaying__Fv = 0x1BE980; // type:func junk_001BE990 = 0x1BE990; // type:func @@ -4094,7 +4094,7 @@ FillPamb__FP3AMBPP3AMBiP3ALOP6VECTORfffffP2LMT10_ = 0x1BF920; // type:func ActivatePamb__FP3AMB5SFXID = 0x1BFAF8; // type:func ScheduleNextIntermittentSound__FP3AMB = 0x1BFBF8; // type:func StartSound__F5SFXIDPP3AMBP3ALOP6VECTORfffffP2LMT9 = 0x1BFCD8; // type:func -FUN_001BFFC8 = 0x1BFFC8; // type:func +FUN_001BFFC8__FiUl = 0x1BFFC8; // type:func HandleWipeHandleWipeVolumes__FifVolumes = 0x1C0000; // type:func UpdateSounds__Fv = 0x1C0070; // type:func SetMvgkUvol__Ff = 0x1c05d0; // type:func @@ -4109,8 +4109,8 @@ PushSwReverb__FP2SW7REVERBKi = 0x1C08B0; // type:func PopSwReverb__FP2SW = 0x1C0950; // type:func SetSwDefaultReverb__FP2SW7REVERBKi = 0x1C09D8; // type:func FUN_001C0A50 = 0x1C0A50; // type:func -FUN_001C0AB8 = 0x1C0AB8; // type:func -FUN_001C0B08 = 0x1C0B08; // type:func +FUN_001C0AB8__FP2SWPf = 0x1C0AB8; // type:func +FUN_001C0B08__FP2SWP2LM = 0x1C0B08; // type:func StartSwIntermittentSounds__FP2SW = 0x1C0B38; // type:func SetAMRegister__FiUc = 0x1C0C08; // type:func GetAMRegister__Fi = 0x1C0C50; // type:func @@ -4182,7 +4182,7 @@ _GLOBAL_$I$g_asprbuf = 0x1C29C8; // type:func //////////////////////////////////////////////////////////////// // P2/sqtr.c //////////////////////////////////////////////////////////////// -FUN_001c29e8 = 0x1C29E8; // type:func +FUN_001c29e8__FP5SQTRM = 0x1C29E8; // type:func UpdateSqtrm__FP5SQTRMP6VECTORP7MATRIX3ff = 0x1C29F8; // type:func RenderSqtrm__FP5SQTRMP2CM = 0x1C3028; // type:func DrawSqtrm__FP3RPL = 0x1C30E8; // type:func @@ -4195,7 +4195,7 @@ InitStep__FP4STEP = 0x1C4458; // type:func PostStepLoad__FP4STEP = 0x1C44F0; // type:func LimitStepHands__FP4STEPi = 0x1C4578; // type:func FUN_001c4618 = 0x1C4618; // type:func -FUN_001c4790 = 0x1C4790; // type:func +FUN_001c4790__FPvP2SOP3BSPT0 = 0x1C4790; // type:func FUN_001c4848 = 0x1C4848; // type:func RenderStepSelf__FP4STEPP2CMP2RO = 0x1C49C8; // type:func ReadStepJoystick__FP4STEPP3JOY = 0x1C49E8; // type:func @@ -4304,7 +4304,7 @@ LoadStepguardPhys__FP9STEPGUARD = 0x1CA8E8; // type:func AddStepguardEffect__FP9STEPGUARD3OID3ZPK = 0x1CA960; // type:func SetStepguardPathzone__FP9STEPGUARD3OID = 0x1CA998; // type:func PsoEnemyStepguard__FP9STEPGUARD = 0x1CAA08; // type:func -FUN_001caad0 = 0x1CAAD0; // type:func +FUN_001caad0__FP2SOPP2SO = 0x1CAAD0; // type:func SetStepguardEnemyObject__FP9STEPGUARDP2SO = 0x1CAB00; // type:func RebindStepguardEnemy__FP9STEPGUARD = 0x1CAB10; // type:func FUN_001cac28__FP9STEPGUARD = 0x1CAC28; // type:func @@ -4314,7 +4314,7 @@ SetStepguardAttackAngleMax__FP9STEPGUARDf = 0x1CAD28; // type:func AddStepguardAlarm__FP9STEPGUARDP5ALARM = 0x1CAD40; // type:func MatchStepguardAnimationPhase__FP9STEPGUARD3OIDN31 = 0x1CAD60; // type:func AddStepguardCustomXps__FP9STEPGUARDP2SOiP3BSPT3PP2XP = 0x1CAD98; // type:func -FUN_001caee0 = 0x1CAEE0; // type:func +FUN_001caee0__FP9STEPGUARDP2SO = 0x1CAEE0; // type:func UpdateStepguardEffect__FP9STEPGUARD = 0x1CAF38; // type:func SetStepguardPatrolAnimation__FP9STEPGUARDP4ASEG = 0x1CB328; // type:func FInflictStepguardZap__FP9STEPGUARDP2XPP3ZPR = 0x1CB3C0; // type:func @@ -4369,13 +4369,13 @@ JtbsChooseJtHide__FP2JTP2LOP4JTHK = 0x1CDFB8; // type:func MeasureJtJumpToTarget__FP2JTP6VECTORP3ALOT1T1PfT5T1T1 = 0x1CE590; // type:func GetJtRailLanding__FP2JTP4RAILfP6VECTORT3 = 0x1CE800; // type:func GMeasureJumpRail__FP3MJRf = 0x1CE9E8; // type:func -FUN_001cea58 = 0x1CEA58; // type:func +FUN_001cea58__FP3MJH = 0x1CEA58; // type:func GMeasureJumpHshape__FP3MJHf = 0x1CEAB8; // type:func FUN_001ceb18 = 0x1CEB18; // type:func FUN_001cedf8 = 0x1CEDF8; // type:func FUN_001cee30 = 0x1CEE30; // type:func FUN_001ceec8 = 0x1CEEC8; // type:func -FUN_001cf138 = 0x1CF138; // type:func +FUN_001cf138__FP2JTiff = 0x1CF138; // type:func FUN_001cf158 = 0x1CF158; // type:func UpdateJtActiveHide__FP2JTP3JOY = 0x1CFFD0; // type:func MatchJtXmgRail__FP2JTP3XMGP6ACTADJ = 0x1D0B20; // type:func @@ -4425,7 +4425,7 @@ func_001D32D8__FiP2JTl = 0x1D32D8; // type:func update_steprail = 0x1D3398; // type:func preset_steprail_accel = 0x1D3470; // type:func FUN_001d34e0__FPUc = 0x1D34E0; // type:func -FUN_001d3500 = 0x1D3500; // type:func +FUN_001d3500__FP2SOP3WKR = 0x1D3500; // type:func FUN_001d35a8 = 0x1D35A8; // type:func update_steprail_message = 0x1D3678; // type:func @@ -4547,7 +4547,7 @@ DeleteSw__FP2SW = 0x1DB838; // SetupBulkDataFromBrx__FiP18CBinaryInputStream = 0x1DB928; // type:func LoadBulkDataFromBrx__FP18CBinaryInputStream = 0x1DBA38; // type:func SetSwGravity__FP2SWf = 0x1DBA90; // type:func -FUN_001dbac0 = 0x1DBAC0; // type:func +FUN_001dbac0__FP2SWii = 0x1DBAC0; // type:func FUN_001dbae0__FP2SWi = 0x1DBAE0; // type:func FUN_001dbb00__FP2SWii = 0x1DBB00; // type:func FOverflowSwLo__FP2SWP2LOi = 0x1DBB20; // type:func @@ -4586,14 +4586,14 @@ FLevelSwPrimary__FP2SW3WID = 0x1DD6B0; // FLevelSwSecondary__FP2SW3WID = 0x1DD6D0; // type:func FLevelSwTertiary__FP2SW3WID = 0x1DD6F0; // type:func FUN_001dd710 = 0x1DD710; // type:func -FUN_001dd758 = 0x1DD758; // type:func -FUN_001dd7a0 = 0x1DD7A0; // type:func +FUN_001dd758__FP2SWi = 0x1DD758; // type:func +FUN_001dd7a0__FP2SWi = 0x1DD7A0; // type:func FUN_001dd7e8 = 0x1DD7E8; // type:func -FUN_001dd888 = 0x1DD888; // type:func +FUN_001dd888__FP2SW3WIDi = 0x1DD888; // type:func FUN_001dd8e8__FP2SW9GAMEWORLD = 0x1DD8E8; // type:func FUN_001dd908__FP2SW9GAMEWORLD = 0x1DD908; // type:func FUN_001dd928__FP2SW = 0x1DD928; // type:func -FUN_001dd950 = 0x1DD950; // type:func +FUN_001dd950__FP2SWiiP6VECTOR = 0x1DD950; // type:func FUN_001dd9a0__Ff = 0x1DD9A0; // type:func FUN_001dd9c0__FPvPf = 0x1DD9C0; // type:func SetSwPlayerSuck__FP2SWf = 0x1DD9D8; // type:func @@ -4605,13 +4605,13 @@ IsSwVagPlaying__FP2SWPi = 0x1DDA90; // SetSwDarken__FP2SWf = 0x1DDAB8; // type:func SetSwDarkenSmooth__FP2SWf = 0x1DDAC8; // type:func CancelSwDialogPlaying__FP2SW = 0x1DDAD0; // type:func -FUN_001ddb20 = 0x1DDB20; // type:func -FUN_001ddb58 = 0x1DDB58; // type:func -FUN_001ddbb8 = 0x1DDBB8; // type:func +FUN_001ddb20__FP2SW3PRKi = 0x1DDB20; // type:func +FUN_001ddb58__FP2SW = 0x1DDB58; // type:func +FUN_001ddbb8__FP2SW = 0x1DDBB8; // type:func FUN_001ddbf8__FP2SWi = 0x1DDBF8; // type:func FUN_001ddc18__FP2SWP3EXC = 0x1DDC18; // type:func FUN_001ddc38__FPvT0 = 0x1DDC38; // type:func -FUN_001ddc40 = 0x1DDC40; // type:func +FUN_001ddc40__FPv = 0x1DDC40; // type:func FUN_001ddc78__FPvi = 0x1DDC78; // type:func FUN_001ddc90__FPvi = 0x1DDC90; // type:func FUN_001ddcb0__FPvPi = 0x1DDCB0; // type:func @@ -4649,7 +4649,7 @@ MatchTailOtherObject__FP4TAILP3ALO = 0x1DE768; // type:func InitTank__FP4TANK = 0x1DE798; // type:func PostTankLoad__FP4TANK = 0x1DE808; // type:func UpdateTank__FP4TANKf = 0x1DE910; // type:func -FUN_001deb30 = 0x1DEB30; // type:func +FUN_001deb30__FP4TANK = 0x1DEB30; // type:func UseTankCharm__FP4TANK = 0x1DEBB8; // type:func UpdateTankActive__FP4TANKP3JOYf = 0x1DEBE8; // type:func OnTankActive__FP4TANKiP2PO = 0x1DF290; // type:func @@ -4743,7 +4743,7 @@ UpdateTnCallback__FP2TN5MSGIDPv = 0x1E2870; // type:f UpdateTn__FP2TNf = 0x1E2940; // type:func RenderTnSelf__FP2TNP2CMP2RO = 0x1E2988; // type:func FreezeTn__FP2TNi = 0x1E29A8; // type:func -FUN_001e29e8 = 0x1E29E8; // type:func +FUN_001e29e8__FP2TNf = 0x1E29E8; // type:func CalculateTnCrv__FP2TNP6VECTORN21 = 0x1E2A00; // type:func CalculateTnPos__FP2TNP6VECTORffP3CLQP2LM4FTNDT1 = 0x1E2BF0; // type:func ActivateCptn__FP4CPTNPv = 0x1E2E68; // type:func @@ -4753,7 +4753,7 @@ RevokeCptn__FP4CPTNPv = 0x1E30E0; // type:f FUN_001e30e8 = 0x1E30E8; // type:func UpdateCptn__FP4CPTNP6CPDEFIP3JOYf = 0x1E31F0; // type:func FUN_001e4578 = 0x1E4578; // type:func -FUN_001e4880 = 0x1E4880; // type:func +FUN_001e4880__FiiiPv = 0x1E4880; // type:func FUN_001e4888 = 0x1E4888; // type:func LoadTbspFromBrx__FP18CBinaryInputStreamPiPP5TSURFT1PP4TBSP = 0x1E4C48; // type:func FCheckTbspPoint__FP4TBSPP6VECTOR = 0x1E4DC0; // type:func @@ -5016,7 +5016,7 @@ g_pwipe = 0x275f84; //////////////////////////////////////////////////////////////// // P2/wm.c //////////////////////////////////////////////////////////////// -FUN_001f0468 = 0x1F0468; // type:func +FUN_001f0468__Fv = 0x1F0468; // type:func FUN_001f0490 = 0x1F0490; // type:func FUN_001f0580 = 0x1F0580; // type:func PostWmLoad__FP2WM = 0x1F0660; // type:func diff --git a/include/gomer.h b/include/gomer.h index cf78e710..029d7209 100644 --- a/include/gomer.h +++ b/include/gomer.h @@ -29,4 +29,6 @@ struct GOMER : public STEPGUARD /* 0xc40 */ int fAbandonExternal; }; +void PostGomerLoad(GOMER *pgomer); + #endif // GOMER_H diff --git a/src/P2/alo.c b/src/P2/alo.c index b17a44e2..49bfe399 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -649,20 +649,20 @@ void SetAloRestorePosition(ALO *palo, int fRestore) SetAloRestorePositionAck(palo, fRestore ? ACK_Spring : ACK_Nil); } -extern "C" void FUN_0012a3e8(ALO *palo, int unk); +void FUN_0012a3e8(ALO *palo, int unk); -extern "C" void FUN_0012a3c8(ALO *palo, int unk) +void FUN_0012a3c8(ALO *palo, int unk) { FUN_0012a3e8(palo, unk != 0); } -extern "C" void FUN_0012a3e8(ALO *palo, int n) +void FUN_0012a3e8(ALO *palo, int n) { STRUCT_OFFSET(palo, 0x2c8, uint64_t) = (STRUCT_OFFSET(palo, 0x2c8, uint64_t) & ~((uint64_t)3 << 40)) | ((uint64_t)(n & 3) << 40); } -extern "C" void FUN_0012a418(ALO *palo, int *pn) +void FUN_0012a418(ALO *palo, int *pn) { *pn = (int)(STRUCT_OFFSET(palo, 0x2c8, uint64_t) >> 40) & 3; } @@ -688,7 +688,7 @@ void SetAloRestoreRotationAck(ALO *palo, ACK ack) (*(void (**)(ALO *))((char *)palo->pvtlo + 0xBC))(palo); } -extern "C" void FUN_0012a4e8(ALO *palo, int n) +void FUN_0012a4e8(ALO *palo, int n) { void *pactrest; @@ -839,7 +839,7 @@ void GetAloLookAtDisabledPriority(ALO *palo, int *pnPriority) *pnPriority = nPriority; } -extern "C" void FUN_0012a810(ALO *palo, int n) +void FUN_0012a810(ALO *palo, int n) { void *pactla; @@ -859,13 +859,13 @@ void FUN_0012a848(ALO *palo, int *pn) *pn = n; } -extern "C" void FUN_0012a860(ALO *palo, ALO *paloTarget) +void FUN_0012a860(ALO *palo, ALO *paloTarget) { extern VECTOR D_00248D30; SetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *), paloTarget, &D_00248D30); } -extern "C" void FUN_0012a888(ALO *palo, ALO **ppaloTarget) +void FUN_0012a888(ALO *palo, ALO **ppaloTarget) { *ppaloTarget = PaloGetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *)); } @@ -876,7 +876,7 @@ void FUN_0012a8b8(ALO *palo) STRUCT_OFFSET(pactla, 0x4C, int) = 0; } -extern "C" void FUN_0012a8c8(ALO *palo) +void FUN_0012a8c8(ALO *palo) { void *pactla = STRUCT_OFFSET(palo, 0x200, void *); STRUCT_OFFSET(pactla, 0x4C, int) = 1; diff --git a/src/P2/binoc.c b/src/P2/binoc.c index bd0e3093..793326d9 100644 --- a/src/P2/binoc.c +++ b/src/P2/binoc.c @@ -108,7 +108,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00135550); INCLUDE_ASM("asm/nonmatchings/P2/binoc", open_close_binoc); -extern "C" { int FUN_001357f0(void *a, void *b) { if (!FIsLoInWorld(STRUCT_OFFSET(a, 0x0, LO *))) @@ -122,7 +121,6 @@ int FUN_001357f0(void *a, void *b) return 1; } -} INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00135858); @@ -131,23 +129,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_001358d0); JUNK_ADDIU(30); JUNK_WORD(0xE4C00000); -extern "C" { void FUN_00135E30(void *a0, void *a1, void *a2) { STRUCT_OFFSET(a1, 0x0, qword) = STRUCT_OFFSET(a0, 0x140, qword); STRUCT_OFFSET(a2, 0x0, int) = 0; } -} JUNK_ADDIU(A0); -extern "C" { int FUN_00135E48(void *param_1, int param_2, VECTOR *param_3) { *(qword *)param_3 = *(qword *)((uint8_t *)param_1 + 0x140); return ChpBuildConvexHullScreen(param_3, 1, (HP *)param_3); } -} JUNK_ADDIU(10); @@ -159,7 +153,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136040); INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136238); -extern "C" { void FUN_001363d0(BINOC *pbinoc) { OnBlotReset(pbinoc); @@ -167,7 +160,6 @@ void FUN_001363d0(BINOC *pbinoc) if (pdialog) SetDialogDialogs(pdialog, DIALOGS_Disabled); } -} INCLUDE_ASM("asm/nonmatchings/P2/binoc", SetBinocAchzDraw); @@ -222,8 +214,7 @@ void GetBinocReticleFocus(BINOC *binoc, float *dxReticle, float *dyReticle) INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136ef8); -extern "C" { -void open_close_binoc(BINOC *pbinoc, int state); +extern "C" void open_close_binoc(BINOC *pbinoc, int state); void FUN_00136fa8(BINOC *pbinoc) { @@ -233,7 +224,6 @@ void FUN_00136fa8(BINOC *pbinoc) else open_close_binoc(pbinoc, 0); } -} INCLUDE_ASM("asm/nonmatchings/P2/binoc", binoc__static_initialization_and_destruction_0); diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index 3b8bbe5b..dea6bf34 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -161,7 +161,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", UpdateChkpnt__FP6CHKPNTf); extern void TriggerJoyRumbleRumk(JOY *pjoy, RUMK rumk, float dt); -extern "C" int FUN_001417f0(CHKPNT *pchkpnt, WKR *pwkr) +int FUN_001417f0(CHKPNT *pchkpnt, WKR *pwkr) { if ((PO *)pwkr->ploSource == PpoCur()) { @@ -176,7 +176,7 @@ extern "C" int FUN_001417f0(CHKPNT *pchkpnt, WKR *pwkr) INCLUDE_ASM("asm/nonmatchings/P2/chkpnt", TriggerChkpnt__FP6CHKPNT); -extern "C" void FUN_001419A0(CHKPNT *pchkpnt, int n) +void FUN_001419A0(CHKPNT *pchkpnt, int n) { int c = STRUCT_OFFSET(pchkpnt, 0x578, int); int *a = &STRUCT_OFFSET(pchkpnt, 0x57c, int); @@ -184,7 +184,7 @@ extern "C" void FUN_001419A0(CHKPNT *pchkpnt, int n) STRUCT_OFFSET(pchkpnt, 0x578, int) = c + 1; } -extern "C" void FUN_001419C0(CHKPNT *pchkpnt, int n) +void FUN_001419C0(CHKPNT *pchkpnt, int n) { int c = STRUCT_OFFSET(pchkpnt, 0x550, int); int *a = &STRUCT_OFFSET(pchkpnt, 0x554, int); diff --git a/src/P2/cm.c b/src/P2/cm.c index 30b3a3ce..8df8363e 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -332,7 +332,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145950); INCLUDE_ASM("asm/nonmatchings/P2/cm", FUN_00145b68); -extern "C" bool FUN_00145DD8(undefined4 unused, CM *pcm) +bool FUN_00145DD8(undefined4 unused, CM *pcm) { return STRUCT_OFFSET(pcm, 0x538, int) != 0; } diff --git a/src/P2/coin.c b/src/P2/coin.c index 07dbe481..814a3114 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -87,12 +87,10 @@ void InitCoin(COIN *pcoin) pcoin->lmDtMaxLifetime.gMax = 10.0f; } -extern "C" { void FUN_00147ed0(DPRIZE *pdprize) { (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, DPRIZES_Removed); } -} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00147ef8); @@ -220,22 +218,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148698); void PostDprizeLoad(DPRIZE *pdprize); -extern "C" void FUN_00148718(DPRIZE *pdprize) +void FUN_00148718(DPRIZE *pdprize) { PostDprizeLoad(pdprize); STRUCT_OFFSET(&g_note, 0x270, DPRIZE *) = pdprize; } -extern "C" { void FUN_00148748(void *param_1) { (*(void (**)(void *, int))(*(int *)param_1 + 0xCC))(param_1, 2); } -} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148770); -extern "C" void FUN_00148828(DPRIZE *pdprize, float dt) +void FUN_00148828(DPRIZE *pdprize, float dt) { UpdateDprize(pdprize, dt); if (pdprize->oidInitialState != OID_Unknown) @@ -259,16 +255,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", RemoveSwExtraneousCharms__FP2SW); INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148d90); -extern "C" { void FUN_00148e18(void *param_1) { (*(void (**)(void *, int))(*(int *)param_1 + 0xCC))(param_1, 2); } -} INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148e40); -extern "C" void FUN_00148ef8(COIN *pcoin, float dt) +void FUN_00148ef8(COIN *pcoin, float dt) { UpdateDprize(pcoin, dt); if (pcoin->oidInitialState != OID_Unknown) diff --git a/src/P2/crusher.c b/src/P2/crusher.c index f6971f39..7cd84e14 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -73,7 +73,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c5e8); extern void *D_0027C00C; extern "C" void FUN_0014c5e8(void *p); -extern "C" void FUN_0014c668(void *pv, int tnt) +void FUN_0014c668(void *pv, int tnt) { if (tnt == 1) { @@ -125,7 +125,7 @@ extern int FUN_001e9970(); extern BLOT g_unkblot1; extern BLOT g_unkblot9; -extern "C" void FUN_0014c788(void *pv) +void FUN_0014c788(void *pv) { OID oid; int fShow; @@ -167,7 +167,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c858); INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014cba8); -extern "C" { void FUN_0014cd70(void *p) { int n; @@ -181,7 +180,6 @@ void FUN_0014cd70(void *p) n = STRUCT_OFFSET(p, 0x458, int); STRUCT_OFFSET(p, 0x458, int) = n - 1; } -} INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014cdc8); diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 378e14aa..ca15fd7f 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -50,7 +50,6 @@ void HandleDartgunMessage(DARTGUN *pdartgun, MSGID msgid, void *pv) INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BindDartgun__FP7DARTGUN); -extern "C" { void FUN_0014f900(DARTGUN* pdartgun) { if (g_pjt != NULL) @@ -58,7 +57,6 @@ void FUN_0014f900(DARTGUN* pdartgun) STRUCT_OFFSET(pdartgun, 0x6dc, int) = STRUCT_OFFSET(g_pjt, 0x24f8, int); } } -} INCLUDE_ASM("asm/nonmatchings/P2/dartgun", PostDartgunLoad__FP7DARTGUN); diff --git a/src/P2/difficulty.c b/src/P2/difficulty.c index 81191349..af3db692 100644 --- a/src/P2/difficulty.c +++ b/src/P2/difficulty.c @@ -112,7 +112,7 @@ void OnDifficultyInitialTeleport(DIFFICULTY *pdifficulty) INCLUDE_ASM("asm/nonmatchings/P2/difficulty", OnDifficultyPlayerDeath); #ifdef SKIP_ASM -extern "C" void OnDifficultyPlayerDeath(float scalar, DIFFICULTY *pdifficulty) +void OnDifficultyPlayerDeath(float scalar, DIFFICULTY *pdifficulty) { DIFFICULTYLEVEL *pdifflevel = pdifficulty->pDifficultyLevel; diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 25f57923..22cd150a 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -126,7 +126,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", ModifyEmitterParticles__FP7EMITTER); INCLUDE_ASM("asm/nonmatchings/P2/emitter", UpdateEmitter__FP7EMITTERf); -extern "C" { void FUN_00155f28(SO *pso) { SO *psoParent; @@ -153,7 +152,6 @@ void FUN_00155f28(SO *pso) STRUCT_OFFSET(pso, 0x88, int) = STRUCT_OFFSET(psoParent, 0x88, int); } -} void PauseEmitter(EMITTER *pemitter, float dtPause) { diff --git a/src/P2/font.c b/src/P2/font.c index 2a0f2c39..8742487e 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -11,7 +11,6 @@ void StartupFont() INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c188); -extern "C" { extern CFont *D_00262268[5]; CFont *FUN_0015c1c0(int i) @@ -31,7 +30,6 @@ CFont *FUN_0015c1c0(int i) return g_pfont; } -} INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c200); diff --git a/src/P2/jlo.c b/src/P2/jlo.c index ad98eeb5..81624f4b 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -30,7 +30,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", LoadJloFromBrx__FP3JLOP18CBinaryInputStre INCLUDE_ASM("asm/nonmatchings/P2/jlo", PostJloLoad__FP3JLO); -extern "C" { void FUN_0016d040(JLO *pjlo, OID oid) { JLOVOL *pjlovol; @@ -47,7 +46,6 @@ void FUN_0016d040(JLO *pjlo, OID oid) SetJloJlos(pjlo, JLOS_Taunt); } } -} void PresetJloAccel(JLO *pjlo, float dt) { @@ -122,7 +120,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", JumpJlo__FP3JLO); extern "C" void PreloadVag1(void *pv); extern char D_002482D8[]; -extern "C" void FUN_0016d928(JLO *pjlo) +void FUN_0016d928(JLO *pjlo) { if (STRUCT_OFFSET(pjlo, 0x5c0, int) != 0) { diff --git a/src/P2/lgn.c b/src/P2/lgn.c index f670187b..febd45b3 100644 --- a/src/P2/lgn.c +++ b/src/P2/lgn.c @@ -58,7 +58,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/lgn", FTakeLgnDamage__FP3LGNP3ZPR); INCLUDE_ASM("asm/nonmatchings/P2/lgn", HandleLgnMessage__FP3LGN5MSGIDPv); -extern "C" void FUN_00181d88(uint8_t *param_1) +void FUN_00181d88(uint8_t *param_1) { FUN_001bc4d8(param_1, param_1 + 0xC04); } diff --git a/src/P2/missile.c b/src/P2/missile.c index 50008b4f..94446ed8 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -73,7 +73,7 @@ extern "C" int FUN_0018dc88(SO *pso, SO *psoOther) } #endif // SKIP_ASM -extern "C" void FUN_0018dd50(void * p, int val) +void FUN_0018dd50(void * p, int val) { int c = STRUCT_OFFSET(p, 0x6bc, int); if ((unsigned int)c < 4) @@ -84,7 +84,7 @@ extern "C" void FUN_0018dd50(void * p, int val) } } -extern "C" void FUN_0018dd78(void * p, int val) +void FUN_0018dd78(void * p, int val) { int c = STRUCT_OFFSET(p, 0x6d0, int); if ((unsigned int)c < 4) diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 54d8212e..5d9e83cb 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -5,7 +5,7 @@ extern uchar D_002484B0[16][32]; -extern "C" int FUN_0018e410(void *pv) +int FUN_0018e410(void *pv) { uchar (*pb)[32] = D_002484B0; int i = 0; @@ -36,13 +36,11 @@ extern "C" int FUN_0018e410(void *pv) return -1; } -extern "C" { extern char *D_002699C0[16]; extern char D_0024B580[]; extern char D_0024B588[]; -} -extern "C" char *FUN_0018e480(int x) +char *FUN_0018e480(int x) { if ((uint)x < 16) return D_002699C0[x]; @@ -54,14 +52,14 @@ extern "C" char *FUN_0018e480(int x) extern "C" void FUN_0018f0e8(CMpeg *pmpeg, void *pv); extern uchar D_002484B0[16][32]; -extern "C" void FUN_0018e4c0(int i) +void FUN_0018e4c0(int i) { FUN_0018f0e8(&g_mpeg, D_002484B0[i]); } extern uchar *D_00269A08; -extern "C" void FUN_0018e4f0(int param1, int i) +void FUN_0018e4f0(int param1, int i) { FUN_0018e4c0(param1); D_00269A08 = D_002484B0[i]; diff --git a/src/P2/murray.c b/src/P2/murray.c index 1e597754..092d9387 100644 --- a/src/P2/murray.c +++ b/src/P2/murray.c @@ -33,7 +33,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/murray", UpdateMurraySgs__FP6MURRAY); extern "C" int FUN_001c9a48(STEPGUARD *pstepguard, void *pv); -extern "C" int FUN_001903f0(MURRAY *pmurray, void *pv) +int FUN_001903f0(MURRAY *pmurray, void *pv) { if ((g_grfcht & FCHT_Invulnerability) || IsSwHandsOff(STRUCT_OFFSET(pmurray, 0x14, SW *))) { @@ -42,7 +42,7 @@ extern "C" int FUN_001903f0(MURRAY *pmurray, void *pv) return FUN_001c9a48(pmurray, pv); } -extern "C" int FUN_00190450(MURRAY *pmurray, WKR *pwkr) +int FUN_00190450(MURRAY *pmurray, WKR *pwkr) { LO **ppvtable = (LO **)STRUCT_OFFSET(pmurray, 0x0, void *); int (*pfn)(MURRAY *, LO *) = (int (*)(MURRAY *, LO *))STRUCT_OFFSET(ppvtable, 0x13c, void *); diff --git a/src/P2/path.c b/src/P2/path.c index 18eb5035..22eb1aaf 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -71,7 +71,7 @@ void FindPathzoneClosestPoint(PATHZONE *ppathzone, VECTOR *pvec0, VECTOR *pvec1) int ClsgClipEdgeToCbsp(CBSP *pcbsp, VECTOR *pvec0, VECTOR *pvec1, int i, LSG *plsg); -extern "C" int FUN_00191aa8(void *p, VECTOR *pvec0, VECTOR *pvec1, int i, LSG *plsg) +int FUN_00191aa8(void *p, VECTOR *pvec0, VECTOR *pvec1, int i, LSG *plsg) { return ClsgClipEdgeToCbsp(STRUCT_OFFSET(p, 0x54, CBSP *), pvec0, pvec1, i, plsg); } diff --git a/src/P2/prompt.c b/src/P2/prompt.c index e46190d9..eb38c0c0 100644 --- a/src/P2/prompt.c +++ b/src/P2/prompt.c @@ -52,7 +52,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/prompt", FUN_00193fb8); INCLUDE_ASM("asm/nonmatchings/P2/prompt", OnPromptActive__FP6PROMPTi); -extern "C" { void FUN_00194278(PROMPT *pprompt, int fButton, WIPEK wipek) { int idLevel; @@ -97,7 +96,6 @@ void FUN_00194278(PROMPT *pprompt, int fButton, WIPEK wipek) } } } -} INCLUDE_ASM("asm/nonmatchings/P2/prompt", FUN_00194398__Fv); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 16e7363e..97ba5da4 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -39,7 +39,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001973d8); extern "C" void FUN_001973d8(void *p); extern void *D_0026A904; -extern "C" void FUN_00197458(void *p, int n) +void FUN_00197458(void *p, int n) { OID oidGoal; OID oidCur; @@ -71,7 +71,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197788); INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_00197848); -extern "C" void FUN_00197a08(void *pv1, void *pv2) +void FUN_00197a08(void *pv1, void *pv2) { ROST *prost = STRUCT_OFFSET(pv2, 0xC14, ROST *); SetRostRosts(prost, ROSTS_Close); @@ -83,7 +83,7 @@ extern "C" void FUN_00197a08(void *pv1, void *pv2) extern float D_0026A83C; extern float D_0026A840; -extern "C" void FUN_00197a68(void *pv, void *p) +void FUN_00197a68(void *pv, void *p) { float dx = D_0026A83C; float dy = D_0026A840; @@ -106,7 +106,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001982a0); INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffcGoal__FP5PUFFCi); -extern "C" void FUN_00197a08(void *pv1, void *pv2); +void FUN_00197a08(void *pv1, void *pv2); void OnPuffcExitingSgs(PUFFC *ppuffc, SGS sgsNext) { diff --git a/src/P2/rog.c b/src/P2/rog.c index 006375c1..1f285464 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -149,7 +149,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", UpdateRob__FP3ROBf); extern int FUN_001e9970(); extern BLOT g_unkblot0; -extern "C" void FUN_001a4d60(ROB *prob) +void FUN_001a4d60(ROB *prob) { int fShow; diff --git a/src/P2/rumble.c b/src/P2/rumble.c index 22cd76d1..aa0817d1 100644 --- a/src/P2/rumble.c +++ b/src/P2/rumble.c @@ -99,7 +99,7 @@ void FUN_001A7E70() INCLUDE_ASM("asm/nonmatchings/P2/rumble", FUN_001A7E90); -extern "C" int FUN_001A7EE8(GS *pgs) +int FUN_001A7EE8(GS *pgs) { switch (DAT_0026c3dc) { diff --git a/src/P2/screen.c b/src/P2/screen.c index 80db9450..0d9c4fc6 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -254,7 +254,6 @@ float FUN_001ABE60() INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001abe70); -extern "C" { void FUN_001ac060(TIMER *ptimer) { int n = STRUCT_OFFSET(ptimer, 0x270, int) - 1; @@ -281,7 +280,6 @@ void FUN_001ac060(TIMER *ptimer) STRUCT_OFFSET(ptimer, 0x27c, float) = g_clock.t; } } -} INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ac0e8); @@ -496,7 +494,6 @@ extern float D_00274470; extern CFont *D_00274488; extern void *D_00269988; - INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001adf28); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001adff0); @@ -516,7 +513,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae5e0); extern "C" char FUN_001aea08(void); extern float D_002744AC; -extern "C" void FUN_001ae758(BLOT *pblot) +void FUN_001ae758(BLOT *pblot) { char achz[2]; diff --git a/src/P2/shd.c b/src/P2/shd.c index d20f0c09..92f458ff 100644 --- a/src/P2/shd.c +++ b/src/P2/shd.c @@ -41,10 +41,9 @@ void UploadPermShaders() g_grfzonShaders = 0; } -extern "C" { extern GSB D_002626D8; extern int D_002626CC; -} + void PropagateSurs(); void PropagateShaders(GRFZON grfzonCamera) diff --git a/src/P2/so.c b/src/P2/so.c index 462d7748..769091ef 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -588,7 +588,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc4d8); INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc670); -extern "C" void FUN_001bc710(SO *pso, int f) +void FUN_001bc710(SO *pso, int f) { uint64_t grfso = STRUCT_OFFSET(pso, 0x538, uint64_t); grfso &= ~((uint64_t)1 << 52); @@ -596,7 +596,7 @@ extern "C" void FUN_001bc710(SO *pso, int f) STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; } -extern "C" void FUN_001bc748(SO *pso, int *pn) +void FUN_001bc748(SO *pso, int *pn) { *pn = (int)(STRUCT_OFFSET(pso, 0x538, uint64_t) >> 52) & 1; // grfso bit 52 (qword view) } diff --git a/src/P2/sound.c b/src/P2/sound.c index b8739599..3e302806 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -76,7 +76,7 @@ int FContinuousSound(SFXID sfxid) } extern int D_00274730; -extern "C" void FUN_001BE5D8(void) +void FUN_001BE5D8(void) { D_00274730 = 0; } @@ -91,7 +91,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadVag__FPc2FK); extern u_int D_00274744; void StopVag(); -extern "C" void FUN_001be708(void) +void FUN_001be708(void) { D_00274744 = 0; StopVag(); @@ -135,7 +135,7 @@ void RefreshPambVolPan(AMB *pamb) void RefreshPambVolPan(AMB *pamb); void DropPamb(AMB **ppamb); -extern "C" void FUN_001be8f8(ALO *palo, AMB **ppamb, float sStart, float sFull) +void FUN_001be8f8(ALO *palo, AMB **ppamb, float sStart, float sFull) { AMB *pambLocal; int fLocal = 0; @@ -479,7 +479,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", ScheduleNextIntermittentSound__FP3AMB); INCLUDE_ASM("asm/nonmatchings/P2/sound", StartSound__F5SFXIDPP3AMBP3ALOP6VECTORfffffP2LMT9); -extern "C" void FUN_001BFFC8(int err, u_long user_data) +void FUN_001BFFC8(int err, u_long user_data) { if (err == 0) { @@ -605,7 +605,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", FUN_001C0A50); struct SW; -extern "C" void FUN_001C0AB8(SW *psw, float *pg) +void FUN_001C0AB8(SW *psw, float *pg) { int c = STRUCT_OFFSET(psw, 0x1D80, int); // count of intermittent-sound entries (array of 0x14-byte entries at 0x1D84) if (c != 0) @@ -618,7 +618,7 @@ extern "C" void FUN_001C0AB8(SW *psw, float *pg) struct SW; -extern "C" void FUN_001C0B08(SW *psw, LM *plm) +void FUN_001C0B08(SW *psw, LM *plm) { int c = STRUCT_OFFSET(psw, 0x1D80, int); // count of intermittent-sound entries (array of 0x14-byte entries at 0x1D84) if (c != 0) diff --git a/src/P2/sqtr.c b/src/P2/sqtr.c index 37cdfc42..a733c87b 100644 --- a/src/P2/sqtr.c +++ b/src/P2/sqtr.c @@ -1,6 +1,6 @@ #include -extern "C" void FUN_001c29e8(SQTRM *psqtrm) +void FUN_001c29e8(SQTRM *psqtrm) { STRUCT_OFFSET(psqtrm, 0xc, int) = 0; STRUCT_OFFSET(psqtrm, 0x8, int) = 0; diff --git a/src/P2/step.c b/src/P2/step.c index d5c24ed0..1206a75b 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -12,7 +12,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/step", LimitStepHands__FP4STEPi); // TODO: This might be "RetractStepExtremity". Further research needed. INCLUDE_ASM("asm/nonmatchings/P2/step", FUN_001c4618); -extern "C" { void FUN_001c4790(void *p1, SO *pso, BSP *pbsp, void *p4) { LSG alsg[2]; @@ -40,7 +39,6 @@ void FUN_001c4790(void *p1, SO *pso, BSP *pbsp, void *p4) } } } -} INCLUDE_ASM("asm/nonmatchings/P2/step", FUN_001c4848); diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 86243193..17a6a9ac 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -256,7 +256,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", SetStepguardPathzone__FP9STEPGUARD3 INCLUDE_ASM("asm/nonmatchings/P2/stepguard", PsoEnemyStepguard__FP9STEPGUARD); -extern "C" void FUN_001caad0(SO *pso, SO **ppso) +void FUN_001caad0(SO *pso, SO **ppso) { void *pvt = STRUCT_OFFSET(pso, 0x0, void *); SO *(*fn)(SO *) = (SO *(*)(SO *))STRUCT_OFFSET(pvt, 0x198, void *); @@ -294,7 +294,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepguard", MatchStepguardAnimationPhase__FP9ST INCLUDE_ASM("asm/nonmatchings/P2/stepguard", AddStepguardCustomXps__FP9STEPGUARDP2SOiP3BSPT3PP2XP); -extern "C" { void FUN_001caee0(STEPGUARD *pstepguard, SO *pso) { (*(void (**)(SO *, void *))((char *)pso->pvtlo + 0x90))(pso, (char *)pstepguard + 0xAB0); @@ -304,7 +303,6 @@ void FUN_001caee0(STEPGUARD *pstepguard, SO *pso) SetJtJts((JT *)pso, JTS_Sidestep, (JTBS)0x2b); } } -} INCLUDE_ASM("asm/nonmatchings/P2/stepguard", UpdateStepguardEffect__FP9STEPGUARD); diff --git a/src/P2/stephide.c b/src/P2/stephide.c index c8209d83..1ac0e8a1 100644 --- a/src/P2/stephide.c +++ b/src/P2/stephide.c @@ -28,7 +28,7 @@ float GMeasureJumpRail(MJR *pmjr, float u) struct HPNT; extern void GetHpntClosestHidePos(HPNT *phpnt, VECTOR *ppos, float *pf); -extern "C" float FUN_001cea58(MJH *pmjh) +float FUN_001cea58(MJH *pmjh) { VECTOR posTarget; float gInteg; @@ -71,7 +71,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/stephide", FUN_001ceec8); extern float D_00274E3C; -extern "C" float FUN_001cf138(JT *pjt, int n, float a, float b) +float FUN_001cf138(JT *pjt, int n, float a, float b) { a = a + b; if (n == STRUCT_OFFSET(pjt, 0x2bdc, int)) diff --git a/src/P2/steppipe.c b/src/P2/steppipe.c index eeea2221..fed30c96 100644 --- a/src/P2/steppipe.c +++ b/src/P2/steppipe.c @@ -10,8 +10,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/steppipe", UpdateJtActivePipe__FP2JTP3JOY); INCLUDE_ASM("asm/nonmatchings/P2/steppipe", UpdateJtInternalXpsPipe__FP2JT); -extern "C" void FUN_001ddb58(SW *psw); -extern "C" void FUN_001ddbb8(SW *psw); +void FUN_001ddb58(SW *psw); +void FUN_001ddbb8(SW *psw); void SetJtJtpdk(JT *pjt, JTPDK jtpdk) { diff --git a/src/P2/steprail.c b/src/P2/steprail.c index f40453f5..8f635178 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -43,7 +43,7 @@ void FUN_001d34e0(uint8_t *param_1) FUN_001bc4d8(param_1, param_1 + 0x554); } -extern "C" int FUN_001d3500(SO *pso, WKR *pwkr) +int FUN_001d3500(SO *pso, WKR *pwkr) { int fAbsorbed = FAbsorbSoWkr(pso, pwkr); if (fAbsorbed != 0 && (pwkr->grfic & 0x20)) diff --git a/src/P2/sw.c b/src/P2/sw.c index ab67eb63..323ac572 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -72,7 +72,7 @@ void SetSwGravity(SW *psw, float z) STRUCT_OFFSET(psw, 0x1EE0, qword) = u.q; // vecGravity = (0, 0, z, junk) } -extern "C" void FUN_001dbac0(SW *psw, int reg, int value) +void FUN_001dbac0(SW *psw, int reg, int value) { SetAMRegister__FiUc(reg, value); } @@ -382,7 +382,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd710); uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); -extern "C" int FUN_001dd758(SW *psw, int wid) +int FUN_001dd758(SW *psw, int wid) { uint grfls = GrflsLevelCompletionFromWid(wid); uint f = 0; @@ -400,7 +400,7 @@ extern "C" int FUN_001dd758(SW *psw, int wid) uint GrflsLevelCompletionFromWid(int wid) __asm__("get_level_completion_by_id"); -extern "C" int FUN_001dd7a0(SW *psw, int wid) +int FUN_001dd7a0(SW *psw, int wid) { uint grfls = GrflsLevelCompletionFromWid(wid); int f = 0; @@ -419,7 +419,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7e8); extern int *PlsFromWid(WID wid) __asm__("LsFromWid"); -extern "C" int FUN_001dd888(SW *psw, WID wid, int nKey) +int FUN_001dd888(SW *psw, WID wid, int nKey) { int *pls = PlsFromWid(wid); if (pls != NULL) @@ -452,7 +452,7 @@ int FUN_001dd928(SW *psw) return CalculatePercentCompletion(g_pgsCur); } -extern "C" void FUN_001dd950(SW *psw, int nLow, int nHigh, VECTOR *pposCenter) +void FUN_001dd950(SW *psw, int nLow, int nHigh, VECTOR *pposCenter) { int cpdprize = NRandInRange(nLow, nHigh); @@ -536,7 +536,7 @@ typedef struct extern PROMPT D_0026FF68; -extern "C" void FUN_001ddb20(SW *psw, PRK prk, int oid) +void FUN_001ddb20(SW *psw, PRK prk, int oid) { PROMPT *pprompt = &D_0026FF68; @@ -546,7 +546,7 @@ extern "C" void FUN_001ddb20(SW *psw, PRK prk, int oid) extern BLOT D_002721D0; -extern "C" void FUN_001ddb58(SW *psw) +void FUN_001ddb58(SW *psw) { if (++STRUCT_OFFSET(psw, 0x2320, int) == 1) { @@ -557,7 +557,7 @@ extern "C" void FUN_001ddb58(SW *psw) extern BLOT D_002721D0; -extern "C" void FUN_001ddbb8(SW *psw) +void FUN_001ddbb8(SW *psw) { if (--STRUCT_OFFSET(psw, 0x2320, int) == 0) { @@ -585,7 +585,7 @@ void FUN_001ddc38(void *pv, void *pvBlot) STRUCT_OFFSET(pv, 0x2324, void *) = pvBlot; } -extern "C" void FUN_001ddc40(void *pv) +void FUN_001ddc40(void *pv) { typedef void (*PFNBLOT)(void *); diff --git a/src/P2/tank.c b/src/P2/tank.c index 9715eaf3..4f4ac4a1 100644 --- a/src/P2/tank.c +++ b/src/P2/tank.c @@ -34,7 +34,7 @@ static inline VU_VECTOR VuVectorXyz(float x, float y, float z) return v; } -extern "C" void FUN_001deb30(TANK *ptank) +void FUN_001deb30(TANK *ptank) { union { @@ -131,7 +131,6 @@ void HandleTankMessage(TANK *ptank, MSGID msgid, void *pv) } } - HandlePoMessage(ptank, msgid, pv); } #endif diff --git a/src/P2/tn.c b/src/P2/tn.c index 3273bb99..ad4c2585 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -164,7 +164,7 @@ void FreezeTn(TN *ptn, int fFreeze) } } -extern "C" void FUN_001e29e8(TN *ptn, float g) +void FUN_001e29e8(TN *ptn, float g) { STRUCT_OFFSET(ptn, 0x364, float) = g; STRUCT_OFFSET(ptn, 0x368, float) = 1.0f; @@ -206,7 +206,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", UpdateCptn__FP4CPTNP6CPDEFIP3JOYf); INCLUDE_ASM("asm/nonmatchings/P2/tn", FUN_001e4578); -extern "C" float FUN_001e4880(int a, int b, int c, void *p) +float FUN_001e4880(int a, int b, int c, void *p) { return STRUCT_OFFSET(p, 0x20, float); } diff --git a/src/P2/wm.c b/src/P2/wm.c index e2213c12..622f5740 100644 --- a/src/P2/wm.c +++ b/src/P2/wm.c @@ -4,7 +4,7 @@ extern int D_00275BF0; -extern "C" int FUN_001f0468(void) +int FUN_001f0468(void) { if (D_00275BF0 != 2) return STRUCT_OFFSET(g_pgsCur, 0x19DC, int); From 22dcd687cdce76ea15877b46332b63bb385fdd84 Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Wed, 24 Jun 2026 00:31:43 +0200 Subject: [PATCH 129/134] Drop unnecessary extern "C" on tally_world_completion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tally_world_completion has no C++ callers — it's only referenced asm-to-asm, so the declaration in game.h is inert and the extern "C" served no purpose (it only matters when C++ code emits a reference to an unmangled label). Our 459b0b14 added it defensively; revert to the plain declaration, matching upstream/base. A sweep of every extern "C" declaration (inline + brace-blocks) confirmed this was the only caller-less one; all others have real C++ callers. Verified: out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- include/game.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/game.h b/include/game.h index b034c75f..ac75bf85 100644 --- a/include/game.h +++ b/include/game.h @@ -274,7 +274,7 @@ uint get_level_completion_by_id(int level_id); * @param cvault Result of the tally of vaults. * @param cmts Result of the tally of Master Thief Sprints */ -extern "C" void tally_world_completion(int wid, int *ckey, int *cvault, int *cmts); +void tally_world_completion(int wid, int *ckey, int *cvault, int *cmts); /** * @brief Get the game completion flags based on the current game state. From 2b80af66b62959c7baba6953d46426f90e69149e Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Thu, 25 Jun 2026 00:23:19 +0200 Subject: [PATCH 130/134] Relocate inline forward-declarations to owning headers Per PR review (example: P2/cm.c): forward-declarations of functions defined elsewhere were scattered inline directly above the functions referencing them. Move each to its owning unit's header so declarations live in one logical place. - same-unit decls to that unit's header: cm.h, binoc.h, crusher.h, frm.h, mpeg.h, puffer.h, rwm.h (deduped a double-decl), screen.h - cross-unit to the owning unit's header: PreloadVag1 to sound.h, FUN_001d4c98 to stepzap.h, strcpy1 to text.h - new headers for units that lacked one: jp.h (func_001781E0), sce/libs.h (func_00202120/58, memmove) - drop frm.c's duplicate SignalSema decl (already in eekernel.h) - game.h: the relocated search_level_by_id replaces its stale commented-out line Declaration-only change. out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- include/binoc.h | 2 ++ include/cm.h | 5 +++++ include/crusher.h | 6 ++++++ include/frm.h | 2 ++ include/game.h | 2 +- include/jp.h | 14 ++++++++++++++ include/mpeg.h | 8 ++++++++ include/puffer.h | 2 ++ include/rwm.h | 2 ++ include/sce/libs.h | 13 +++++++++++++ include/screen.h | 4 ++++ include/sound.h | 2 ++ include/stepzap.h | 2 ++ include/text.h | 2 ++ src/P2/binoc.c | 2 -- src/P2/cd.c | 1 - src/P2/cm.c | 7 ------- src/P2/crusher.c | 5 ----- src/P2/frm.c | 4 ---- src/P2/game.c | 2 -- src/P2/gs.c | 3 +-- src/P2/jlo.c | 2 +- src/P2/jt.c | 3 +-- src/P2/mpeg.c | 7 ------- src/P2/po.c | 3 +-- src/P2/puffer.c | 1 - src/P2/pzo.c | 3 +-- src/P2/rwm.c | 4 ---- src/P2/screen.c | 3 --- 29 files changed, 70 insertions(+), 46 deletions(-) create mode 100644 include/jp.h create mode 100644 include/sce/libs.h diff --git a/include/binoc.h b/include/binoc.h index b4a44800..d88ba8a9 100644 --- a/include/binoc.h +++ b/include/binoc.h @@ -157,4 +157,6 @@ class CTextBox enum JV m_jv; // Vertical text justification; }; +extern "C" void open_close_binoc(BINOC *pbinoc, int state); + #endif /* BINOC_H */ diff --git a/include/cm.h b/include/cm.h index 33292b92..c20fbb1a 100644 --- a/include/cm.h +++ b/include/cm.h @@ -555,4 +555,9 @@ extern int g_rgbaFog; //Just to get the code matching -Kestin void ResetCmLookAtSmooth(CM *pcm, void *pv); +extern "C" void SetupCmRotateToCam(CM *pcm); +extern "C" void SetCmLookAtSmooth(CM *pcm, int a1, VECTOR *pposEye, VECTOR *pposCenter, int a4, float u0, float u1, float u2, float u3, float u4, float u5); +extern "C" void ConvertCylindToWorldVelocity(void *a, void *b, void *c, float f0, float f1, float f2); +extern "C" void ConvertWorldToCylindVelocity(void *a, void *b, void *c, void *d, void *e, void *f); + #endif // CM_H diff --git a/include/crusher.h b/include/crusher.h index 874c9e5f..d84fd1d4 100644 --- a/include/crusher.h +++ b/include/crusher.h @@ -73,4 +73,10 @@ void InitCrbrain(CRBRAIN *pcrbrain); // TODO: Add unknown functions here. +extern "C" void FUN_0014c5e8(void *p); + +extern "C" void FUN_0014c858(void *p); + +extern "C" void FUN_0014cba8(void *p); + #endif // CRUSHER_H diff --git a/include/frm.h b/include/frm.h index bde0c20b..9da8fb0e 100644 --- a/include/frm.h +++ b/include/frm.h @@ -63,4 +63,6 @@ extern FRM *g_pfrmOpen; extern uchar g_abRenderLoopStack[0x20000]; // TODO: Move elsewhere? +extern "C" void func_0015F618(int, int); + #endif // FRM_H diff --git a/include/game.h b/include/game.h index ac75bf85..8486c4bc 100644 --- a/include/game.h +++ b/include/game.h @@ -251,7 +251,7 @@ void StartupGame(); // LevelLoadData * search_level_by_load_data(LevelLoadData *search_level); -// LevelLoadData * search_level_by_id(int search_id); +extern "C" LevelLoadData *search_level_by_id(int search_id); /** * @brief Gets the friendly name of a level from its world ID. diff --git a/include/jp.h b/include/jp.h new file mode 100644 index 00000000..f5587359 --- /dev/null +++ b/include/jp.h @@ -0,0 +1,14 @@ +/** + * @file jp.h + */ +#ifndef JP_H +#define JP_H + +#include "common.h" + +struct JT; +struct LOCKG; + +extern "C" void func_001781E0(JT *pjt, LOCKG *plockg); + +#endif // JP_H diff --git a/include/mpeg.h b/include/mpeg.h index 8435d3db..aa489f0e 100644 --- a/include/mpeg.h +++ b/include/mpeg.h @@ -28,4 +28,12 @@ void StartupMpeg(); extern CMpeg g_mpeg; +extern "C" void FUN_0018f0e8(CMpeg *pmpeg, void *pv); + +extern "C" int FAccept__10CMpegAudioiPUc(void *pmpega, int cb, uchar *pb); + +extern "C" void CbDemuxed__5CMpegi(CMpeg *pmpeg, int nParam); + +extern "C" void Execute__5CMpeg(CMpeg *pmpeg, OID *poid); + #endif // MPEG_H diff --git a/include/puffer.h b/include/puffer.h index 23e6b4c2..0b23ef9f 100644 --- a/include/puffer.h +++ b/include/puffer.h @@ -96,4 +96,6 @@ int FCanPuffcAttack(PUFFC *ppuffc); void PostPuffbLoad(PUFFB *ppuffb); +extern "C" void FUN_001973d8(void *p); + #endif // PUFFER_H diff --git a/include/rwm.h b/include/rwm.h index 63f7fa0a..af03d5ac 100644 --- a/include/rwm.h +++ b/include/rwm.h @@ -94,4 +94,6 @@ void GetRwacPan(RWAC *prwac, float *pradPan); void GetRwacTilt(RWAC *prwac, float *pradTilt); +extern "C" void FUN_001a93c8(RWM *prwm); + #endif // RWM_H diff --git a/include/sce/libs.h b/include/sce/libs.h new file mode 100644 index 00000000..66a236fd --- /dev/null +++ b/include/sce/libs.h @@ -0,0 +1,13 @@ +/** + * @file sce/libs.h + * + * @brief Declarations for SDK library functions (asm/sce/libs.s). + */ +#ifndef SCE_LIBS_H +#define SCE_LIBS_H + +extern "C" int func_00202120(); +extern "C" void func_00202058(int); +extern "C" void *memmove(void *dst, const void *src, int cb); + +#endif // SCE_LIBS_H diff --git a/include/screen.h b/include/screen.h index 91bd34a1..f29ef76a 100644 --- a/include/screen.h +++ b/include/screen.h @@ -387,4 +387,8 @@ void UpdateAttract(ATTRACT *pattract); void DrawLineScreen(uint x1, uint y1, uint z1, uint x2, uint y2, uint z2, RGBA *rgba, int fDepthTest); +extern "C" char FUN_001aea08(void); + +extern "C" void FUN_001aea70(int, int); + #endif // SCREEN_H diff --git a/include/sound.h b/include/sound.h index 4c8f4b78..bb681abd 100644 --- a/include/sound.h +++ b/include/sound.h @@ -319,4 +319,6 @@ int GetAMRegister(int reg); */ void UpdateAMRegister(int reg, int value); +extern "C" void PreloadVag1(void *pv); + #endif // SOUND_H diff --git a/include/stepzap.h b/include/stepzap.h index 45c4afa8..0c4486f4 100644 --- a/include/stepzap.h +++ b/include/stepzap.h @@ -8,4 +8,6 @@ // ... +extern "C" void FUN_001d4c98(JT *pjt); + #endif // STEPZAP_H diff --git a/include/text.h b/include/text.h index 4180ebd5..6132bd66 100644 --- a/include/text.h +++ b/include/text.h @@ -156,4 +156,6 @@ extern "C" void UpperizePchz(char *pchz); +extern "C" char *strcpy1(char *pchzDst, char *pchzSrc); + #endif // TEXT_H diff --git a/src/P2/binoc.c b/src/P2/binoc.c index 793326d9..1e3a6d5f 100644 --- a/src/P2/binoc.c +++ b/src/P2/binoc.c @@ -214,8 +214,6 @@ void GetBinocReticleFocus(BINOC *binoc, float *dxReticle, float *dyReticle) INCLUDE_ASM("asm/nonmatchings/P2/binoc", FUN_00136ef8); -extern "C" void open_close_binoc(BINOC *pbinoc, int state); - void FUN_00136fa8(BINOC *pbinoc) { DIALOG *pdialog = STRUCT_OFFSET(pbinoc, 0x324, DIALOG *); diff --git a/src/P2/cd.c b/src/P2/cd.c index 3dc49bd3..c46e8a54 100644 --- a/src/P2/cd.c +++ b/src/P2/cd.c @@ -42,7 +42,6 @@ void StartupCd() INCLUDE_ASM("asm/nonmatchings/P2/cd", UpdateCd__Fv); -extern "C" char *strcpy1(char *pchzDst, char *pchzSrc); extern short D_00249E20; extern char D_00249E28[]; extern char D_00249E30[]; diff --git a/src/P2/cm.c b/src/P2/cm.c index 8df8363e..3773165a 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -208,8 +208,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCmScreenToWorld); INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCmWorldToScreen); -extern "C" void SetupCmRotateToCam(CM *pcm); - void SetupCm(CM *pcm) { VECTOR4 vTmp; @@ -243,8 +241,6 @@ void DrawCm(CM *pcm) INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmPosMat__FP2CMP6VECTORP7MATRIX3); -extern "C" void SetCmLookAtSmooth(CM *pcm, int a1, VECTOR *pposEye, VECTOR *pposCenter, int a4, float u0, float u1, float u2, float u3, float u4, float u5); - void SetCmLookAt(CM *pcm, VECTOR *pposEye, VECTOR *pposCenter) { SetCmLookAtSmooth(pcm, 0, pposEye, pposCenter, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); @@ -254,9 +250,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertWorldToCylindVelocity); INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCylindToWorldVelocity); -extern "C" void ConvertCylindToWorldVelocity(void *a, void *b, void *c, float f0, float f1, float f2); -extern "C" void ConvertWorldToCylindVelocity(void *a, void *b, void *c, void *d, void *e, void *f); - void ResetCmLookAtSmooth(CM *pcm, void *pv) { VECTOR4 vTmp; diff --git a/src/P2/crusher.c b/src/P2/crusher.c index 7cd84e14..5ae14c49 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -71,8 +71,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c2f0); INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c5e8); extern void *D_0027C00C; -extern "C" void FUN_0014c5e8(void *p); - void FUN_0014c668(void *pv, int tnt) { if (tnt == 1) @@ -91,9 +89,6 @@ void FUN_0014c668(void *pv, int tnt) } } -extern "C" void FUN_0014c858(void *p); -extern "C" void FUN_0014cba8(void *p); - INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); #ifdef SKIP_ASM extern "C" void update_crbrain(CRBRAIN *p, float dt) diff --git a/src/P2/frm.c b/src/P2/frm.c index 426558d5..eab50bde 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -81,8 +81,6 @@ void FinalizeFrameGifs(GIFS *pgifs, int *pcqwGifs, QW **ppqwGifs) pgifs->Detach(pcqwGifs, ppqwGifs); } -extern "C" int SignalSema(int sid); - extern DL D_002622E0; extern DL D_002622F0; extern DL D_00262300; @@ -174,8 +172,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/frm", BlendPrevFrame__Fv); * Once the appropriate functions are matched these can be removed. */ INCLUDE_ASM("asm/nonmatchings/P2/frm", func_0015F618); -extern "C" void func_0015F618(int, int); - extern "C" void func_0015F658(void) { func_0015F618(1, 0xFFFF); diff --git a/src/P2/game.c b/src/P2/game.c index d3ccabae..b23b59d6 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -42,8 +42,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", PchzFriendlyFromWid__Fi); JUNK_WORD(0x24420010); -extern "C" LevelLoadData *search_level_by_id(int search_id); - extern "C" LevelLoadData *call_search_level_by_id(int level_id) { return search_level_by_id(level_id); diff --git a/src/P2/gs.c b/src/P2/gs.c index 2fe719e9..16ed4ece 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -24,8 +25,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", GS_Interrupt__Fi); INCLUDE_ASM("asm/nonmatchings/P2/gs", ResetGs__Fv); -extern "C" int func_00202120(); -extern "C" void func_00202058(int); extern int D_002BE464; extern int D_002BE468; diff --git a/src/P2/jlo.c b/src/P2/jlo.c index 81624f4b..9c5507b7 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -117,7 +118,6 @@ void LandJlo(JLO *pjlo) INCLUDE_ASM("asm/nonmatchings/P2/jlo", JumpJlo__FP3JLO); -extern "C" void PreloadVag1(void *pv); extern char D_002482D8[]; void FUN_0016d928(JLO *pjlo) diff --git a/src/P2/jt.c b/src/P2/jt.c index 1f3fc49c..050154b4 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -20,8 +21,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", AdjustJtNewXp__FP2JTP2XPi); INCLUDE_ASM("asm/nonmatchings/P2/jt", AdjustJtDz__FP2JTiP2DZif); -extern "C" void FUN_001d4c98(JT *pjt); - void HandleJtGrfjtsc(JT *pjt) { int grfjtsc = STRUCT_OFFSET(pjt, 0x2254, int); diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 5d9e83cb..05dacdaa 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -49,7 +49,6 @@ char *FUN_0018e480(int x) return D_0024B588; } -extern "C" void FUN_0018f0e8(CMpeg *pmpeg, void *pv); extern uchar D_002484B0[16][32]; void FUN_0018e4c0(int i) @@ -236,8 +235,6 @@ int FMpegAcceptVideo(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) struct sceMpeg; struct sceMpegCbDataStr; -extern "C" int FAccept__10CMpegAudioiPUc(void *pmpega, int cb, uchar *pb); - int FMpegAcceptAudio(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) { return FAccept__10CMpegAudioiPUc((uint8_t *)pmpeg + 0x80, STRUCT_OFFSET(pcbdata, 0xC, int), STRUCT_OFFSET(pcbdata, 0x8, uchar *)); @@ -247,8 +244,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegDecodeVideo__FP7sceMpegP13sceMpegCb struct sceMpeg; struct sceMpegCbData; -extern "C" void CbDemuxed__5CMpegi(CMpeg *pmpeg, int nParam); - int FMpegDecoderIdle(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) { CbDemuxed__5CMpegi(pmpeg, 0); @@ -269,8 +264,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018ef78); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FUN_0018f0e8); -extern "C" void Execute__5CMpeg(CMpeg *pmpeg, OID *poid); - void CMpeg::ExecuteOids() { OID *poidNext = STRUCT_OFFSET(this, 0x8, OID *); // queued second mpeg oid ptr diff --git a/src/P2/po.c b/src/P2/po.c index 63ab896c..f453aa40 100644 --- a/src/P2/po.c +++ b/src/P2/po.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -235,8 +236,6 @@ void AddPoToList(PO *ppo) } } -extern "C" void *memmove(void *dst, const void *src, int cb); - void RemovePoFromList(PO *ppo) { int i = _IppoFindPo(ppo); diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 97ba5da4..d95f7824 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -36,7 +36,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", PpufftChoosePuffer__FP6PUFFER); INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001973d8); -extern "C" void FUN_001973d8(void *p); extern void *D_0026A904; void FUN_00197458(void *p, int n) diff --git a/src/P2/pzo.c b/src/P2/pzo.c index ea034ca9..2ce6045a 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -174,8 +175,6 @@ void AddLockgLock(LOCKG *plockg, OID oidLock) plockg->coidLock = ++ccur; } -extern "C" void func_001781E0(JT *pjt, LOCKG *plockg); - void TriggerLockg(LOCKG *plockg) { if (g_pjt) diff --git a/src/P2/rwm.c b/src/P2/rwm.c index 1b3c015f..3f89b04f 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -9,8 +9,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwm__FP3RWM); -extern "C" void FUN_001a93c8(RWM *prwm); - void OnRwmRemove(RWM *prwm) { OnLoRemove(prwm); @@ -120,8 +118,6 @@ void PostRwmLoad(RWM *prwm) } } -extern "C" void FUN_001a93c8(RWM *prwm); - void FUN_001a86f8(RWM *prwm, int f) { if (f != 0) diff --git a/src/P2/screen.c b/src/P2/screen.c index 0d9c4fc6..15ee0985 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -510,7 +510,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae510); INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001ae5e0); -extern "C" char FUN_001aea08(void); extern float D_002744AC; void FUN_001ae758(BLOT *pblot) @@ -547,8 +546,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", FUN_001aea70); JUNK_WORD(0xE48C0000); JUNK_WORD(0xE48C0008); -extern "C" void FUN_001aea70(int, int); - void FUN_001aec90(void) { FUN_001aea70(1, 0xFFFF); From c4e8657306a4af65aeb8c2e01e722a32e53c1dde Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Thu, 25 Jun 2026 00:23:19 +0200 Subject: [PATCH 131/134] Restore matches accidentally dropped by wave-N commits Three "Match wave-N" commits removed previously-matched functions while adding new ones (bad rebase/merge artifacts): c436f8a5 (wave-4), e02bf9b8 (wave-8), 459b0b14 (wave-9). The functions still exist upstream. Restore them -- all are #ifdef SKIP_ASM bodies, so the binary is unchanged: - 989snd.c: snd_GotReturns - util.c: CSolveQuadratic - light.c: CloneLight - sensor.c: SetSensorSensors, FUN_001afaf8 - game.c: UnlockIntroCutsceneFromWid out/SCUS_971.98: OK. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/P2/989snd.c | 24 +++++++++++++++++ src/P2/game.c | 32 ++++++++++++++++++++++ src/P2/light.c | 19 +++++++++++++ src/P2/sensor.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ src/P2/util.c | 38 +++++++++++++++++++++++++- 5 files changed, 183 insertions(+), 1 deletion(-) diff --git a/src/P2/989snd.c b/src/P2/989snd.c index ed56ff11..b210f5f3 100644 --- a/src/P2/989snd.c +++ b/src/P2/989snd.c @@ -228,6 +228,30 @@ JUNK_ADDIU(10); JUNK_ADDIU(10); INCLUDE_ASM("asm/nonmatchings/P2/989snd", snd_GotReturns__Fv); +#ifdef SKIP_ASM +// Rodata +int snd_GotReturns(void) +{ + FlushCache(0); + if (gCommBusy == NULL) { + return 1; + } + + if (sceSifCheckStatRpc(&gSLClientData.rpcd)) { + return 0; + } + + if (*gCommBusy == -1 && (gCommBusy[gAwaitingInts + 1] == -1)) { + gCommBusy = NULL; + return 1; + } else { + printf("989snd.c: Sif says RPC isn\'t busy, but we still don\'t have returns from the IOP!\n"); + return 0; + } + + return 1; +} +#endif void snd_PrepareReturnBuffer(u_int* buffer, int num_ints) { diff --git a/src/P2/game.c b/src/P2/game.c index b23b59d6..b78bbf3a 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -58,6 +58,38 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", tally_world_completion); INCLUDE_ASM("asm/nonmatchings/P2/game", get_game_completion__Fv); INCLUDE_ASM("asm/nonmatchings/P2/game", UnlockIntroCutsceneFromWid__Fi); +#ifdef SKIP_ASM +/** + * @todo Close to matching but there's a problem with the rodata. + */ +void UnlockIntroCutsceneFromWid(int wid) +{ + /* Check the unlocked cutscene by setting the corresponding + flag on the unlocked_cutscenes in the game state */ + switch (wid) + { + case 1: + /* Unlock cutscene "Tide of Terror" */ + g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x10; + return; + case 2: + /* Unlock cutscene "Sunset Snake Eyes" */ + g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x40; + return; + case 3: + /* Unlock cutscene "Vicious Voodoo" */ + g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x100; + return; + case 4: + /* Unlock cutscene "Fire in the Sky" */ + g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x400; + return; + case 5: + /* Unlock cutscene "The Cold Heart of Hate" */ + g_pgsCur->unlocked_cutscenes = g_pgsCur->unlocked_cutscenes | 0x1000; + } +} +#endif // SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/game", DefeatBossFromWid); diff --git a/src/P2/light.c b/src/P2/light.c index b11e338e..51895b30 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -68,6 +68,25 @@ void OnLightRemove(LIGHT *plight) * @todo 98.75% match. */ INCLUDE_ASM("asm/nonmatchings/P2/light", CloneLight__FP5LIGHTT0); // SKIP_ASM +#ifdef SKIP_ASM +void CloneLight(LIGHT *plight, LIGHT *plightBase) +{ + int fDynamic = FIsLoInWorld(plight) && (STRUCT_OFFSET(plight, 0x304, int) != STRUCT_OFFSET(plightBase, 0x304, int)); + if (fDynamic) + { + RemoveLightFromSw(plight); + } + + DLE dleLight = STRUCT_OFFSET(plightBase, 0x410, DLE); + CloneAlo(plight, plightBase); + STRUCT_OFFSET(plight, 0x410, DLE) = dleLight; + + if (fDynamic) + { + AddLightToSw(plight); + } +} +#endif // SKIP_ASM void FitLinearFunction(float x0, float y0, float x1, float y1, float *pdu, float *pru) { diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 0f837054..9d0fc299 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -18,6 +18,41 @@ void SetSensorAlarm(SENSOR *psensor, ALARM *palarm) } INCLUDE_ASM("asm/nonmatchings/P2/sensor", SetSensorSensors__FP6SENSOR7SENSORS); +#ifdef SKIP_ASM +/** + * @todo 82.08% matched. + */ +void SetSensorSensors(SENSOR *psensor, SENSORS sensors) +{ + SENSORS sensorsCur = STRUCT_OFFSET(psensor, 0x558, SENSORS); // sensorsCur = psensor->sensors; + + if (sensorsCur == sensors) + { + return; + } + + if (sensorsCur == SENSORS_SenseEnabled && sensors == SENSORS_SenseTriggered) + { + ALARM *palarm = STRUCT_OFFSET(psensor, 0x550, ALARM *); + if (palarm) + { + TriggerAlarm(palarm, ALTK_Trigger); + } + + // Recheck current sensor state: if it's not SENSORS_SenseEnabled, + // override the current sensors with the new one. + sensorsCur = STRUCT_OFFSET(psensor, 0x558, SENSORS); + if (sensorsCur != SENSORS_SenseEnabled) + { + sensors = sensorsCur; + } + } + + HandleLoSpliceEvent(psensor, 2, 0, NULL); + STRUCT_OFFSET(psensor, 0x558, SENSORS) = sensors; // psensor->sensors = sensors; + STRUCT_OFFSET(psensor, 0x55C, float) = g_clock.t; +} +#endif INCLUDE_ASM("asm/nonmatchings/P2/sensor", FCheckSensorObject__FP6SENSORP2SO); @@ -126,6 +161,42 @@ void FreezeLasen(LASEN *plasen, int fFreeze) INCLUDE_ASM("asm/nonmatchings/P2/sensor", RenderLasenSelf__FP5LASENP2CMP2RO); INCLUDE_ASM("asm/nonmatchings/P2/sensor", FUN_001afaf8__FP6SENSORP2SO); +#ifdef SKIP_ASM +/** + * @todo 73.57% matched. + */ +int FUN_001afaf8(SENSOR *psensor, SO *pso) +{ + extern void *g_pjt; + unsigned long long mask; + uint tmp2cc; + + /* Mask: (0x8000 << 28) in 64-bits */ + mask = ((ulong)0x8000) << 28; + if (STRUCT_OFFSET(pso, 0x538, ulong) & mask) + return 0; + + if (STRUCT_OFFSET(pso, 0x50, uint) == STRUCT_OFFSET(psensor, 0x50, uint)) + return 0; + + if (FIgnoreSensorObject(psensor, pso)) + return 0; + + if (pso == g_pjt) + { + if (STRUCT_OFFSET(pso, 0x2220, uint) != 6) + return 0; + if (STRUCT_OFFSET(pso, 0x239C, uint) != 3) + return 0; + if (GetGrfvault_unknown() & 0x12000) + return 0; + } + + tmp2cc = STRUCT_OFFSET(pso, 0x2CC, uint); + /* Invert lowest bit and mask to 1 */ + return (int)(((tmp2cc ^ 1u) & 1u)); +} +#endif INCLUDE_ASM("asm/nonmatchings/P2/sensor", SenseLasen__FP5LASENP7SENSORS); diff --git a/src/P2/util.c b/src/P2/util.c index f37c0906..3a0d6b29 100644 --- a/src/P2/util.c +++ b/src/P2/util.c @@ -137,7 +137,43 @@ int FFloatsNear(float g1, float g2, float gEpsilon) return (g2 / x) < gEpsilon; } -INCLUDE_ASM("asm/nonmatchings/P2/util", CSolveQuadratic__FfffPf); // SKIP_ASM +INCLUDE_ASM("asm/nonmatchings/P2/util", CSolveQuadratic__FfffPf); +#ifdef SKIP_ASM +/** + * @todo 95.96% matched. + * + * Compiler is using bc1f instead of bc1fl for (alpha < 0.0f) branch. + * + * https://decomp.me/scratch/A4VOu + */ +int CSolveQuadratic(float a, float b, float c, float *ax) +{ + float alpha; + float beta; + + alpha = b * b - 4.f * a * c; + a = a * 2; + + if (alpha < 0.0f) + { + return 0; + } + else + { + beta = b / a; + alpha = sqrtf(alpha) / a; + if (fabsf(alpha) < 0.0001f) + { + *ax = -beta; + return 1; + } + + *ax = -beta + alpha; + ax[1] = -beta - alpha; + return 2; + } +} +#endif // SKIP_ASM void PrescaleClq(CLQ *pclqSrc, float ru, float du, CLQ *pclqDst) { From fcf131e5e4de0f93643aebeaa06b485876ce779b Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Thu, 2 Jul 2026 23:12:05 +0200 Subject: [PATCH 132/134] Fix a bunch of review comments --- src/P2/act.c | 11 ++---- src/P2/alo.c | 39 +++++--------------- src/P2/asega.c | 3 +- src/P2/bomb.c | 3 +- src/P2/cd.c | 14 ++------ src/P2/chkpnt.c | 4 +-- src/P2/coin.c | 14 ++++---- src/P2/crusher.c | 5 ++- src/P2/crv.c | 71 +++++++++++++----------------------- src/P2/dartgun.c | 42 ++++++++++------------ src/P2/emitter.c | 7 ++-- src/P2/freeze.c | 11 ++---- src/P2/frm.c | 2 +- src/P2/game.c | 2 +- src/P2/glob.c | 13 +++---- src/P2/gs.c | 37 +++++++++---------- src/P2/hide.c | 13 +++---- src/P2/jlo.c | 14 +++----- src/P2/jt.c | 88 +++++++++++++++++---------------------------- src/P2/lgn.c | 4 +-- src/P2/mark.c | 6 ++-- src/P2/mb.c | 7 ++-- src/P2/missile.c | 6 ++-- src/P2/mpeg.c | 10 ++---- src/P2/path.c | 2 -- src/P2/prompt.c | 4 +-- src/P2/puffer.c | 7 ++-- src/P2/pzo.c | 19 +++++----- src/P2/rchm.c | 3 +- src/P2/rip.c | 30 +++++----------- src/P2/rog.c | 20 +++-------- src/P2/rwm.c | 6 ++-- src/P2/sb.c | 4 +-- src/P2/screen.c | 32 ++++++----------- src/P2/sensor.c | 40 ++++++++++----------- src/P2/shd.c | 24 ++++++------- src/P2/sm.c | 9 ++--- src/P2/smartguard.c | 3 +- src/P2/so.c | 2 +- src/P2/sound.c | 23 +++++------- src/P2/speaker.c | 4 +-- src/P2/splicemap.c | 4 +-- src/P2/step.c | 21 ++++------- src/P2/stepcane.c | 3 +- src/P2/stepguard.c | 2 +- src/P2/steprail.c | 5 ++- src/P2/suv.c | 14 +++----- src/P2/sw.c | 10 ------ src/P2/tank.c | 5 +-- src/P2/tn.c | 17 ++++----- src/P2/turret.c | 4 +-- src/P2/ub.c | 16 ++++----- src/P2/ui.c | 2 -- src/P2/xform.c | 1 + 54 files changed, 267 insertions(+), 495 deletions(-) diff --git a/src/P2/act.c b/src/P2/act.c index 863838c2..5336431b 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -163,10 +163,7 @@ void ProjectActPose(ACT *pact, int ipose) int off = ipose << 2; float *ag = STRUCT_OFFSET(palo, 0x270, float *); float dt; - if (STRUCT_OFFSET(palo, 0x294, int)) - dt = g_clock.dtReal; - else - dt = g_clock.dt; + dt = STRUCT_OFFSET(palo, 0x294, int) ? g_clock.dtReal : g_clock.dt; *(float *)((char *)ag + off) = GSmooth(*(float *)((char *)ag + off), g, dt, &D_00260E60, NULL); } @@ -232,8 +229,6 @@ extern VECTOR D_00248D30; void InitActref(ACTREF *pactref, ALO *palo) { - uint8_t *psen; - InitAct(pactref, palo); STRUCT_OFFSET(pactref, 0x1c, uint8_t *) = (uint8_t *)palo + 0x190; STRUCT_OFFSET(pactref, 0x24, uint8_t *) = (uint8_t *)palo + 0x1a0; @@ -241,8 +236,8 @@ void InitActref(ACTREF *pactref, ALO *palo) STRUCT_OFFSET(pactref, 0x20, VECTOR *) = &D_00248D30; STRUCT_OFFSET(pactref, 0x28, VECTOR *) = &D_00248D30; STRUCT_OFFSET(pactref, 0x3c, float *) = STRUCT_OFFSET(palo, 0x274, float *); - psen = STRUCT_OFFSET(palo, 0x224, uint8_t *); - if (psen != 0 && (STRUCT_OFFSET(psen, 0xb0, int) & 0x20)) + uint8_t *psen = STRUCT_OFFSET(palo, 0x224, uint8_t *); + if (psen != nullptr && (STRUCT_OFFSET(psen, 0xb0, int) & 0x20)) { STRUCT_OFFSET(pactref, 0x30, VECTOR *) = &D_00248D30; STRUCT_OFFSET(pactref, 0x2c, uint8_t *) = psen + 0x8c; diff --git a/src/P2/alo.c b/src/P2/alo.c index 5ca12e06..8fba73c3 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -68,7 +68,7 @@ void UpdateAloXfWorld(ALO *palo) { void (*pfn)(ALO *) = (void (*)(ALO *))palo->pvtlo->pfnUpdateLoXfWorldHierarchy; - if (pfn != 0) + if (pfn != nullptr) { pfn(palo); } @@ -508,12 +508,9 @@ int FIsAloStatic(ALO *palo) paloChild = (ALO *)palo->dlChild.head; while (paloChild != NULL) { - if (paloChild->pvtlo->grfcid & 1) + if (paloChild->pvtlo->grfcid & 1 && !FIsAloStatic(paloChild)) { - if (!FIsAloStatic(paloChild)) - { - return 0; - } + return 0; } paloChild = (ALO *)paloChild->dleChild.next; } @@ -795,12 +792,7 @@ void SetAloLookAtTiltLimits(ALO *palo, LM *plm) void GetAloLookAtTiltLimits(ALO *palo, LM *plm) { void *pactla = STRUCT_OFFSET(palo, 0x200, void *); - LM *plmSrc; - - if (pactla) - plmSrc = &STRUCT_OFFSET(pactla, 0x80, LM); - else - plmSrc = &g_lmZeroOne; + LM *plmSrc = pactla ? &STRUCT_OFFSET(pactla, 0x80, LM) : &g_lmZeroOne; *plm = *plmSrc; } @@ -861,7 +853,7 @@ void FUN_0012a848(ALO *palo, int *pn) void FUN_0012a860(ALO *palo, ALO *paloTarget) { - extern VECTOR D_00248D30; + VECTOR D_00248D30; SetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *), paloTarget, &D_00248D30); } @@ -1139,12 +1131,9 @@ extern VU_VECTOR D_00248D30; void GetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) { THROB *pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); // palo->pthrob - VU_VECTOR *pqSrc; - - if (pthrob) - pqSrc = &STRUCT_OFFSET(pthrob, 0x10, VU_VECTOR); // pthrob->hsvInColor - else - pqSrc = &D_00248D30; + VU_VECTOR *pqSrc = pthrob + ? &STRUCT_OFFSET(pthrob, 0x10, VU_VECTOR) // pthrob->hsvInColor + : &D_00248D30; *(VU_VECTOR *)phsvInColor = *pqSrc; } @@ -1159,17 +1148,7 @@ void SetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) void GetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) { THROB *pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); // palo->throb - VU_VECTOR *pvuvec; - - if (pthrob != 0) - { - pvuvec = &STRUCT_OFFSET(pthrob, 0x20, VU_VECTOR); - } - else - { - pvuvec = &D_00248D30; - } - + VU_VECTOR *pvuvec = pthrob ? &STRUCT_OFFSET(pthrob, 0x20, VU_VECTOR) : &D_00248D30; *(VU_VECTOR *)phsvOutColor = *pvuvec; } diff --git a/src/P2/asega.c b/src/P2/asega.c index fae16ede..4930a147 100644 --- a/src/P2/asega.c +++ b/src/P2/asega.c @@ -41,8 +41,7 @@ void UpdateAsegaIeaCur(ASEGA *pasega) if (0.0f <= STRUCT_OFFSET(pasega, 0x18, float)) { - int i = c - 1; - i = 0; + int i = 0; if (c > 0) { char *p = STRUCT_OFFSET(paseg, 0x60, char *); diff --git a/src/P2/bomb.c b/src/P2/bomb.c index 675d8bbb..5bf4140a 100644 --- a/src/P2/bomb.c +++ b/src/P2/bomb.c @@ -28,8 +28,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/bomb", PostBombLoad__FP4BOMB); void HandleBombMessage(BOMB *pbomb, MSGID msgid, void *pv) { HandleAloMessage((ALO *)pbomb, msgid, pv); - - if (msgid == 0xA) { + if (msgid == MSGID_water_entered) { if (*(int *)((uint8_t *)pv + 0x4) == (int)pbomb) { if (!STRUCT_OFFSET(pbomb, 0x550, int)) { PrimeBomb(pbomb, 0.0f); diff --git a/src/P2/cd.c b/src/P2/cd.c index c46e8a54..0df446cc 100644 --- a/src/P2/cd.c +++ b/src/P2/cd.c @@ -51,9 +51,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/cd", CdPath__FPcT0i); #ifdef SKIP_ASM void CdPath(char *pchzDest, char *pchzPath, int fIncludeDevice) { - char achz[0x100]; - - *(short *)achz = D_00249E20; + char achz[0x100] = D_00249E20; strcpy1(achz, pchzPath); int ctoken = ((int (*)(char *))CpchzTokenizePath)(achz); if (1 < ctoken) @@ -66,15 +64,7 @@ void CdPath(char *pchzDest, char *pchzPath, int fIncludeDevice) } while (itoken != 0); } - char *pchzDevice; - if (fIncludeDevice) - { - pchzDevice = D_00249E30; - } - else - { - pchzDevice = D_00249E38; - } + char *pchzDevice = fIncludeDevice ? D_00249E30 : D_00249E38; sprintf(pchzDest, D_00249E28, pchzDevice, achz); } #endif // SKIP_ASM diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index dea6bf34..95284c4a 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -64,8 +64,8 @@ void ReturnChkmgrToCheckpoint(CHKMGR *pchkmgr) } else { - trans.oidWarp = (OID)-1; - trans.oidWarpContet = (OID)-1; + trans.oidWarp = OID_NIL; + trans.oidWarpContet = OID_NIL; trans.grftrans = 0x10; } ActivateWipe(&g_wipe, &trans, (WIPEK)1); diff --git a/src/P2/coin.c b/src/P2/coin.c index 814a3114..73117e45 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -40,19 +40,16 @@ void CloneDprize(DPRIZE *pdprize, DPRIZE *pdprizeBase) void PostDprizeLoad(DPRIZE *pdprize) { - LO *plo; - PostAloLoad(pdprize); - plo = PloFindSwObjectByClass(pdprize->psw, 1, (CID)0x75, (LO *)pdprize); + LO *plo = PloFindSwObjectByClass(pdprize->psw, 1, (CID)0x75, (LO *)pdprize); pdprize->ptarget = (TARGET *)plo; if (plo != NULL) { (*(void (**)(LO *))((char *)plo->pvtlo + 0x1C))(plo); } - if (((STRUCT_OFFSET(g_pgsCur, 0x19D8, int) << 8) | STRUCT_OFFSET(g_pgsCur, 0x19DC, int)) != 0x308) + if (((STRUCT_OFFSET(g_pgsCur, 0x19D8, int) << 8) | STRUCT_OFFSET(g_pgsCur, 0x19DC, int)) != 0x308 && FGetChkmgrIchk(&g_chkmgr, pdprize->ichkCollected)) { - if (FGetChkmgrIchk(&g_chkmgr, pdprize->ichkCollected)) - pdprize->dprizesInit = DPRIZES_Removed; + pdprize->dprizesInit = DPRIZES_Removed; } (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, pdprize->dprizesInit); } @@ -89,6 +86,7 @@ void InitCoin(COIN *pcoin) void FUN_00147ed0(DPRIZE *pdprize) { + // @todo: fix this vtable call (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, DPRIZES_Removed); } @@ -236,6 +234,7 @@ void FUN_00148828(DPRIZE *pdprize, float dt) UpdateDprize(pdprize, dt); if (pdprize->oidInitialState != OID_Unknown) return; + // @todo clean up this vtable call if (STRUCT_OFFSET(pdprize->psw, 0x2308, float) <= g_clock.t) (*(void (**)(DPRIZE *, DPRIZES))((char *)pdprize->pvtlo + 0xCC))(pdprize, DPRIZES_Lose); } @@ -257,6 +256,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", FUN_00148d90); void FUN_00148e18(void *param_1) { + // @todo clean up this vtable call (*(void (**)(void *, int))(*(int *)param_1 + 0xCC))(param_1, 2); } @@ -271,7 +271,7 @@ void FUN_00148ef8(COIN *pcoin, float dt) return; if (D_00270458 != 2) pcoin->tLose -= g_clock.dt; - if (pcoin->tLose <= 0.0f) + if (pcoin->tLose <= 0.0f) // @todo clean up this vtable call (*(void (**)(COIN *, DPRIZES))((char *)pcoin->pvtlo + 0xCC))(pcoin, DPRIZES_Lose); } diff --git a/src/P2/crusher.c b/src/P2/crusher.c index 5ae14c49..31ee543f 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -91,7 +91,7 @@ void FUN_0014c668(void *pv, int tnt) INCLUDE_ASM("asm/nonmatchings/P2/crusher", update_crbrain); #ifdef SKIP_ASM -extern "C" void update_crbrain(CRBRAIN *p, float dt) +void update_crbrain(CRBRAIN *p, float dt) { OID oid; @@ -123,11 +123,10 @@ extern BLOT g_unkblot9; void FUN_0014c788(void *pv) { OID oid; - int fShow; GetSmaCur(STRUCT_OFFSET(pv, 0x42c, SMA *), &oid); - fShow = 0; + int fShow = 0; if (oid == (OID)0x3fd) { fShow = FUN_001e9970(); diff --git a/src/P2/crv.c b/src/P2/crv.c index d1815ffd..554d081e 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -8,7 +8,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureApos__FiP6VECTORPf); float GWrapApos(float g, int cpos, float *mpiposg, int fClosed) { float f0 = g; - if (fClosed == 0) { + if (!fClosed) { return f0; } @@ -101,20 +101,17 @@ JUNK_ADDIU(A0); float SMeasureCrvSegmentU(CRVMS *pcrvms, float u) { - VECTOR pos; - float du, ps; - void *pcrv; - void **pvtbl; - void (*pfn)(void *, VECTOR *, int); - pcrv = STRUCT_OFFSET(pcrvms, 0x0, void *); - pvtbl = STRUCT_OFFSET(pcrv, 0x0, void **); - pfn = (void (*)(void *, VECTOR *, int))pvtbl[1]; + void *pcrv = STRUCT_OFFSET(pcrvms, 0x0, void *); + void **pvtbl = STRUCT_OFFSET(pcrv, 0x0, void **); + void (*pfn)(void *, VECTOR *, int) = (void (*)(void *, VECTOR *, int))pvtbl[1]; + VECTOR pos; if (pfn != NULL) { pfn(pcrv, &pos, 0); } + float du, ps; FindClosestPointOnLineSegment(&pos, STRUCT_OFFSET(pcrvms, 0x4, VECTOR *), STRUCT_OFFSET(pcrvms, 0x8, VECTOR *), &du, &ps); return ps; } @@ -165,29 +162,21 @@ float SFromCrvlU(CRVL *pcrvl, float u) { float du; float duSeg; - int icv; - float frac; - float *mpicvs; - icv = IcvFindCrvU((CRV *)pcrvl, u, &du, &duSeg); - frac = du / duSeg; - mpicvs = ((CRV *)pcrvl)->mpicvs; + int icv = IcvFindCrvU((CRV *)pcrvl, u, &du, &duSeg); + float frac = du / duSeg; + float *mpicvs = ((CRV *)pcrvl)->mpicvs; return (1.0f - frac) * mpicvs[icv] + frac * mpicvs[icv + 1]; } float UFromCrvlS(CRVL *pcrvl, float s) { float ds, dsSeg; - int icv; - float *mpicvu; - float u0, u1; - float result; - - icv = IcvFindCrvS((CRV *)pcrvl, s, &ds, &dsSeg); - mpicvu = STRUCT_OFFSET(pcrvl, 0x10, float *); - u0 = mpicvu[icv]; - u1 = mpicvu[icv + 1]; - result = (1.0f - (ds / dsSeg)) * u0 + (ds / dsSeg) * u1; + int icv = IcvFindCrvS((CRV *)pcrvl, s, &ds, &dsSeg); + float *mpicvu = STRUCT_OFFSET(pcrvl, 0x10, float *); + float u0 = mpicvu[icv]; + float u1 = mpicvu[icv + 1]; + float result = (1.0f - (ds / dsSeg)) * u0 + (ds / dsSeg) * u1; return result; } @@ -204,11 +193,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", FindCrvlClosestPointFromS__FP4CRVLP6VECTO void LoadCrvcFromBrx(CRVC *pcrvc, CBinaryInputStream *pbis) { - int icv; - int ccv; - STRUCT_OFFSET(pcrvc, 0x8, int) = pbis->U8Read(); - ccv = pbis->U8Read(); + int ccv = pbis->U8Read(); STRUCT_OFFSET(pcrvc, 0xC, int) = ccv; STRUCT_OFFSET(pcrvc, 0x10, void *) = PvAllocSwImpl(ccv * 4); STRUCT_OFFSET(pcrvc, 0x14, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 4); @@ -216,7 +202,7 @@ void LoadCrvcFromBrx(CRVC *pcrvc, CBinaryInputStream *pbis) STRUCT_OFFSET(pcrvc, 0x1C, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 16); STRUCT_OFFSET(pcrvc, 0x20, void *) = PvAllocSwImpl(STRUCT_OFFSET(pcrvc, 0xC, int) * 16); - for (icv = 0; icv < STRUCT_OFFSET(pcrvc, 0xC, int); icv++) + for (int icv = 0; icv < STRUCT_OFFSET(pcrvc, 0xC, int); icv++) { STRUCT_OFFSET(pcrvc, 0x10, float *)[icv] = pbis->F32Read(); pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x18, void *) + icv * 16)); @@ -243,9 +229,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", EvaluateCrvcFromU__FP4CRVCfP6VECTORT2); void EvaluateCrvcFromS(CRVC *pcrvc, float s, VECTOR *ppos, VECTOR *pnormTangent) { - float u; - - u = ((float (*)(CRVC *, float))STRUCT_OFFSET(*(void **)pcrvc, 0x18, void *))(pcrvc, s); + float u = ((float (*)(CRVC *, float))STRUCT_OFFSET(*(void **)pcrvc, 0x18, void *))(pcrvc, s); if (STRUCT_OFFSET(*(void **)pcrvc, 0x4, void *)) { ((void (*)(CRVC *, float, VECTOR *, VECTOR *))STRUCT_OFFSET(*(void **)pcrvc, 0x4, void *))(pcrvc, u, ppos, pnormTangent); @@ -260,9 +244,8 @@ float SFromCrvcU(CRVC *pcrvc, float u) { float du; float duSeg; - int icv; - icv = IcvFindCrvU((CRV *)pcrvc, u, &du, &duSeg); + int icv = IcvFindCrvU((CRV *)pcrvc, u, &du, &duSeg); return SBezierPosLength( duSeg, @@ -276,19 +259,13 @@ float SFromCrvcU(CRVC *pcrvc, float u) float UFromCrvcS(CRVC *pcrvc, float s) { - int icv; - int ipos; - float g; - float dg; - float dgSeg; - float u; - float *pmp; - - icv = IcvFindCrvS((CRV *)pcrvc, s, &g, NULL); + float g, dg, dgSeg; + + int icv = IcvFindCrvS((CRV *)pcrvc, s, &g, NULL); FillCrvcCache(pcrvc, icv); - ipos = IposFindAposG(g, 0x14, &STRUCT_OFFSET(pcrvc, 0x170, float), 0, &dg, &dgSeg); - pmp = STRUCT_OFFSET(pcrvc, 0x10, float *); - u = ((float)ipos + dg / dgSeg) * (1.0f / 19.0f); + int ipos = IposFindAposG(g, 0x14, &STRUCT_OFFSET(pcrvc, 0x170, float), 0, &dg, &dgSeg); + float *pmp = STRUCT_OFFSET(pcrvc, 0x10, float *); + float u = ((float)ipos + dg / dgSeg) * (1.0f / 19.0f); return (1.0f - u) * pmp[icv] + u * pmp[icv + 1]; } diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index ca15fd7f..b11b93b5 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -39,6 +39,7 @@ void HandleDartgunMessage(DARTGUN *pdartgun, MSGID msgid, void *pv) STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x4C, int) = 1; STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = 0; + // @todo check these vtable call palo = STRUCT_OFFSET(pdartgun, 0x734, ALO *); (*(void (**)(ALO *, void *))((char *)palo->pvtlo + 0x84))(palo, (char *)palo + 0x190); palo = STRUCT_OFFSET(pdartgun, 0x734, ALO *); @@ -52,10 +53,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/dartgun", BindDartgun__FP7DARTGUN); void FUN_0014f900(DARTGUN* pdartgun) { - if (g_pjt != NULL) - { - STRUCT_OFFSET(pdartgun, 0x6dc, int) = STRUCT_OFFSET(g_pjt, 0x24f8, int); - } + if (g_pjt == NULL) + return; + + STRUCT_OFFSET(pdartgun, 0x6dc, int) = STRUCT_OFFSET(g_pjt, 0x24f8, int); } INCLUDE_ASM("asm/nonmatchings/P2/dartgun", PostDartgunLoad__FP7DARTGUN); @@ -66,8 +67,7 @@ int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) { if (FIsBasicDerivedFrom(psoOther, CID_RAT)) { - if (STRUCT_OFFSET(psoOther, 0x588, SO *) == (SO *)pdartgun) - return 1; + return 1; } return FIgnoreSoIntersection((SO *)pdartgun, psoOther); @@ -75,11 +75,7 @@ int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) void BreakDartgun(DARTGUN *pdartgun) { - OID oidCur; - ALO *palo; - SMA *psma; - - palo = STRUCT_OFFSET(pdartgun, 0x6c8, ALO *); + ALO *palo = STRUCT_OFFSET(pdartgun, 0x6c8, ALO *); if (palo != NULL) { (*(void (**)(ALO *, int))((char *)palo->pvtlo + 0x64))(palo, 0); @@ -87,7 +83,8 @@ void BreakDartgun(DARTGUN *pdartgun) (*(void (**)(ALO *))((char *)palo->pvtlo + 0x1c))(palo); } - psma = STRUCT_OFFSET(pdartgun, 0x740, SMA *); + SMA *psma = STRUCT_OFFSET(pdartgun, 0x740, SMA *); + OID oidCur; if (psma != NULL) { SeekSma(psma, (OID)0x2B7); @@ -100,6 +97,7 @@ void BreakDartgun(DARTGUN *pdartgun) } palo = STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, ALO *); + // @todo clean up this vtable call (*(void (**)(ALO *, int))((char *)palo->pvtlo + 0x8))(palo, 7); BreakBrk((BRK *)pdartgun); @@ -121,14 +119,11 @@ void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x4C, int) = 0; } - if (oidStateGoal < (OID)0x2BA) + if (oidStateGoal < (OID)0x2BA && oidStateGoal >= (OID)0x2B8) { - if (oidStateGoal >= (OID)0x2B8) - { - STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = (oidStateGoal == (OID)0x2B9); - if ((unsigned int)(oidCur - 0x2BA) >= 2) - STRUCT_OFFSET(pdartgun, 0x6D8, int) = 0; - } + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = (oidStateGoal == (OID)0x2B9); + if ((unsigned int)(oidCur - 0x2BA) >= 2) + STRUCT_OFFSET(pdartgun, 0x6D8, int) = 0; } SetSmaGoal(STRUCT_OFFSET(pdartgun, 0x740, SMA *), oidStateGoal); @@ -136,7 +131,7 @@ void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) void TrackDartgun(DARTGUN *pdartgun, OID *poidStateGoal) { - extern VECTOR D_00248D30; + VECTOR D_00248D30; if (*poidStateGoal == (OID)0x2B8) { @@ -150,7 +145,7 @@ void TrackDartgun(DARTGUN *pdartgun, OID *poidStateGoal) else { LO *plo = STRUCT_OFFSET(pdartgun, 0x6E0, LO *); - if (plo == NULL || FIsLoInWorld(plo) == 0 || + if (plo == NULL || !FIsLoInWorld(plo) || STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x6E0, SO *), 0x550, int) == 3 || STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x6E0, SO *), 0x550, int) == 4) { @@ -161,10 +156,9 @@ void TrackDartgun(DARTGUN *pdartgun, OID *poidStateGoal) { SetActlaTarget((ACTLA *)STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), (ALO *)STRUCT_OFFSET(pdartgun, 0x6E0, ALO *), &D_00248D30); - if (STRUCT_OFFSET(pdartgun, 0x6D0, float) < g_clock.t - STRUCT_OFFSET(pdartgun, 0x6D8, float)) + if (STRUCT_OFFSET(pdartgun, 0x6D0, float) < g_clock.t - STRUCT_OFFSET(pdartgun, 0x6D8, float) && FPrepareDartgunToFire(pdartgun)) { - if (FPrepareDartgunToFire(pdartgun)) - *poidStateGoal = (OID)0x2BB; + *poidStateGoal = (OID)0x2BB; } } } diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 22cd150a..9df51302 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -370,13 +370,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadExplgFromBrx__FP5EXPLGP18CBinaryI void CloneExplg(EXPLG *pexplg, EXPLG *pexplgBase) { - int i = 0; CloneLo((LO *)pexplg, (LO *)pexplgBase); if (STRUCT_OFFSET(pexplg, 0x90, int) > 0) { LO **p = &STRUCT_OFFSET(pexplg, 0x94, LO *); + int i = 0; do { LO *plo = PloCloneLo(*p, STRUCT_OFFSET(pexplg, 0x14, SW *), STRUCT_OFFSET(pexplg, 0x18, ALO *)); @@ -415,7 +415,7 @@ void BindExplo(EXPLO *pexplo) EMITB *pemitbCur = STRUCT_OFFSET(pexplo, 0x90, EMITB *); if (STRUCT_OFFSET(pemitbCur, 0x120, int) != 0) - goto bind; + goto done; if (STRUCT_OFFSET(pemitbCur, 0x188, int) == -1) goto done; @@ -437,9 +437,8 @@ void BindExplo(EXPLO *pexplo) STRUCT_OFFSET(pemitbNew, 0x20, int) = STRUCT_OFFSET(plo, 0x34, int); STRUCT_OFFSET(pemitbNew, 0x7C, int) = STRUCT_OFFSET(plo, 0x18, int); } - + // @todo try to do this without goto done: -bind: BindEmitb(STRUCT_OFFSET(pexplo, 0x90, EMITB *), (LO *)pexplo); } diff --git a/src/P2/freeze.c b/src/P2/freeze.c index bc185a98..3f3960b4 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -21,8 +21,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/freeze", SplinterSwFreezeGroup__FP2SWP3ALO); void MergeSwGroup(SW *psw, MRG *pmrg) { int i = 0; - int iFirst; - while (i < pmrg->cpalo) { if (FIsLoInWorld((LO *)pmrg->apalo[i])) @@ -30,8 +28,7 @@ void MergeSwGroup(SW *psw, MRG *pmrg) i++; } - iFirst = i; - for (; i < pmrg->cpalo; i++) + for (int iFirst = i; i < pmrg->cpalo; i++) { if (FIsLoInWorld((LO *)pmrg->apalo[i])) { @@ -42,12 +39,10 @@ void MergeSwGroup(SW *psw, MRG *pmrg) void AddSwMergeGroup(SW *psw, MRG *pmrg) { - int i; - if (pmrg->cpalo < 2) return; - for (i = 0; i < pmrg->cpalo; i++) + for (int i = 0; i < pmrg->cpalo; i++) { ALO *palo = pmrg->apalo[i]; int cpmrg = STRUCT_OFFSET(palo, 0x6c, int); @@ -78,7 +73,7 @@ void GetAloFrozen(ALO *palo, int *pf) void FreezeAlo(ALO *palo, int fFreeze) { - extern VECTOR D_00248D30; + VECTOR D_00248D30; if (fFreeze) { diff --git a/src/P2/frm.c b/src/P2/frm.c index eab50bde..9234670c 100644 --- a/src/P2/frm.c +++ b/src/P2/frm.c @@ -172,7 +172,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/frm", BlendPrevFrame__Fv); * Once the appropriate functions are matched these can be removed. */ INCLUDE_ASM("asm/nonmatchings/P2/frm", func_0015F618); -extern "C" void func_0015F658(void) +void func_0015F658(void) { func_0015F618(1, 0xFFFF); } diff --git a/src/P2/game.c b/src/P2/game.c index b78bbf3a..a1e3e49d 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -42,7 +42,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/game", PchzFriendlyFromWid__Fi); JUNK_WORD(0x24420010); -extern "C" LevelLoadData *call_search_level_by_id(int level_id) +LevelLoadData *call_search_level_by_id(int level_id) { return search_level_by_id(level_id); } diff --git a/src/P2/glob.c b/src/P2/glob.c index 644a5ae4..34586517 100644 --- a/src/P2/glob.c +++ b/src/P2/glob.c @@ -5,19 +5,14 @@ void BuildGlobsetSaaArray(GLOBSET *pglobset) { - void **psaa; - int i; - int iDst; - psaa = (void **)PvAllocSwImpl(STRUCT_OFFSET(pglobset, 0x50, int) * 4); + void **psaa = (void **)PvAllocSwImpl(STRUCT_OFFSET(pglobset, 0x50, int) * 4); STRUCT_OFFSET(pglobset, 0x54, void **) = psaa; - iDst = 0; - for (i = 0; i < STRUCT_OFFSET(pglobset, 0xc, int); i++) + int iDst = 0; + for (int i = 0; i < STRUCT_OFFSET(pglobset, 0xc, int); i++) { - void *p; - - p = STRUCT_OFFSET((uint8_t *)STRUCT_OFFSET(pglobset, 0x10, uint8_t *) + i * 0x70, 0x38, void *); + void *p = STRUCT_OFFSET((uint8_t *)STRUCT_OFFSET(pglobset, 0x10, uint8_t *) + i * 0x70, 0x38, void *); if (p != 0) STRUCT_OFFSET(pglobset, 0x54, void **)[iDst++] = p; } diff --git a/src/P2/gs.c b/src/P2/gs.c index 16ed4ece..c63c2a9a 100644 --- a/src/P2/gs.c +++ b/src/P2/gs.c @@ -124,32 +124,29 @@ INCLUDE_ASM("asm/nonmatchings/P2/gs", FBuildUploadBitmapGifs__FiP3GSBP4GIFS); extern int g_cclutUpload; extern int g_cbmpUpload; -int FBuildUploadBitmapGifs(int grfzon, GSB *pgsb, GIFS *pgifs); void UploadBitmaps(GRFZON grfzon, GSB *pgsb) { if (grfzon == 0) return; + GIFS gifs; + QW *pqw; + + InitStackImpl(); + gifs.AllocStack(((g_cclutUpload * 3 + g_cbmpUpload) << 3) | 4); + gifs.AddDmaCnt(); + if (FBuildUploadBitmapGifs(grfzon, pgsb, &gifs)) { - GIFS gifs; - QW *pqw; - - InitStackImpl(); - gifs.AllocStack(((g_cclutUpload * 3 + g_cbmpUpload) << 3) | 4); - gifs.AddDmaCnt(); - if (FBuildUploadBitmapGifs(grfzon, pgsb, &gifs)) - { - gifs.AddPrimPack(0, 1, 0xE); - gifs.PackAD(0x3F, 0); - gifs.PackAD(0x61, 0); - gifs.AddPrimEnd(); - gifs.AddDmaEnd(); - gifs.Detach(NULL, &pqw); - SendDmaSyncGsFinish(g_pdcGif, pqw); - } - FreeStackImpl(); + gifs.AddPrimPack(0, 1, 0xE); + gifs.PackAD(0x3F, 0); + gifs.PackAD(0x61, 0); + gifs.AddPrimEnd(); + gifs.AddDmaEnd(); + gifs.Detach(NULL, &pqw); + SendDmaSyncGsFinish(g_pdcGif, pqw); } + FreeStackImpl(); } INCLUDE_ASM("asm/nonmatchings/P2/gs", PqwGifsBitmapUpload__Fi); @@ -183,9 +180,7 @@ extern SUR D_0027DC20[]; void PropagateSurs() { - int isur; - - for (isur = 0; isur < D_002626D0; isur++) + for (int isur = 0; isur < D_002626D0; isur++) { PropagateSur(&D_0027DC20[isur]); } diff --git a/src/P2/hide.c b/src/P2/hide.c index 935ffe4d..93af4b24 100644 --- a/src/P2/hide.c +++ b/src/P2/hide.c @@ -71,15 +71,16 @@ extern qword D_002483D0[3]; void LoadHbskFromBrx(HBSK *phbsk, CBinaryInputStream *pbis) { LoadSoFromBrx((SO *)phbsk, pbis); + if (STRUCT_OFFSET(phbsk, 0x224, void *) == 0) STRUCT_OFFSET(phbsk, 0x224, void *) = PvAllocSwClearImpl(0xC0); + STRUCT_OFFSET(STRUCT_OFFSET(phbsk, 0x224, void *), 0xB0, int) |= 1; - { - void *pv = STRUCT_OFFSET(phbsk, 0x224, void *); - STRUCT_OFFSET(pv, 0x0, qword) = D_002483D0[0]; - STRUCT_OFFSET(pv, 0x10, qword) = D_002483D0[1]; - STRUCT_OFFSET(pv, 0x20, qword) = D_002483D0[2]; - } + + void *pv = STRUCT_OFFSET(phbsk, 0x224, void *); + STRUCT_OFFSET(pv, 0x0, qword) = D_002483D0[0]; + STRUCT_OFFSET(pv, 0x10, qword) = D_002483D0[1]; + STRUCT_OFFSET(pv, 0x20, qword) = D_002483D0[2]; } void OnHbskAdd(HBSK *phbsk) diff --git a/src/P2/jlo.c b/src/P2/jlo.c index 9c5507b7..043dbe2a 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -33,10 +33,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", PostJloLoad__FP3JLO); void FUN_0016d040(JLO *pjlo, OID oid) { - JLOVOL *pjlovol; - STRUCT_OFFSET(pjlo, 0x578, OID) = oid; - pjlovol = (JLOVOL *)PloFindSwNearest(pjlo->psw, oid, pjlo); + JLOVOL *pjlovol = (JLOVOL *)PloFindSwNearest(pjlo->psw, oid, pjlo); if (pjlovol != NULL) { SetJloJlovol(pjlo, pjlovol); @@ -64,7 +62,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", UpdateJlo__FP3JLOf); INCLUDE_ASM("asm/nonmatchings/P2/jlo", JlosNextJlo__FP3JLO); EXC *PexcSetExcitement(int gexc); -void UnsetExcitementHyst(EXC *pexc); void SetJloJlovol(JLO *pjlo, JLOVOL *pjlovol) { @@ -91,13 +88,10 @@ void SetJloJlovol(JLO *pjlo, JLOVOL *pjlovol) if (STRUCT_OFFSET(pjlo, 0x5BC, EXC *) == NULL) STRUCT_OFFSET(pjlo, 0x5BC, EXC *) = PexcSetExcitement(0x6B); } - else + else if (STRUCT_OFFSET(pjlo, 0x5BC, EXC *) != NULL) { - if (STRUCT_OFFSET(pjlo, 0x5BC, EXC *) != NULL) - { - UnsetExcitementHyst(STRUCT_OFFSET(pjlo, 0x5BC, EXC *)); - STRUCT_OFFSET(pjlo, 0x5BC, EXC *) = NULL; - } + UnsetExcitementHyst(STRUCT_OFFSET(pjlo, 0x5BC, EXC *)); + STRUCT_OFFSET(pjlo, 0x5BC, EXC *) = NULL; } } diff --git a/src/P2/jt.c b/src/P2/jt.c index 050154b4..e77a7c1b 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -47,7 +47,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtInternalXps__FP2JT); int FCheckJtXpBase(JT *pjt, XP *pxp, int ixpd) { - extern float D_00274AD0[]; + float D_00274AD0[]; if (pjt->jts != JTS_Max) { @@ -85,7 +85,6 @@ struct XMG; int FTurnJtToTarget(JT *pjt); void RebuildJtXmg(JT *pjt, ALO *palo, float s, ALO *palo2, ACTADJ *pactadj, XMG *pxmg); -int FMatchJtXmg(JT *pjt, XMG *pxmg, ACTADJ *pactadj); void UpdateJtStand(JT *pjt) { @@ -175,53 +174,38 @@ SO *PsoGetJtEffect(JT *pjt, int *pn) SO *pso; pso = STRUCT_OFFSET(pjt, 0x25D8, SO *); - if (pso != NULL) + if (pso != NULL && FIsLoInWorld(pso)) { - if (FIsLoInWorld(pso)) - { - *pn = 0; - return STRUCT_OFFSET(pjt, 0x25D8, SO *); - } + *pn = 0; + return STRUCT_OFFSET(pjt, 0x25D8, SO *); } pso = STRUCT_OFFSET(pjt, 0x25E0, SO *); - if (pso != NULL) + if (pso != NULL && FIsLoInWorld(pso)) { - if (FIsLoInWorld(pso)) - { - *pn = 1; - return STRUCT_OFFSET(pjt, 0x25E0, SO *); - } + *pn = 1; + return STRUCT_OFFSET(pjt, 0x25E0, SO *); } pso = STRUCT_OFFSET(pjt, 0x25DC, SO *); - if (pso != NULL) + if (pso != NULL && FIsLoInWorld(pso)) { - if (FIsLoInWorld(pso)) - { - *pn = 2; - return STRUCT_OFFSET(pjt, 0x25DC, SO *); - } + *pn = 2; + return STRUCT_OFFSET(pjt, 0x25DC, SO *); } pso = STRUCT_OFFSET(pjt, 0x25E4, SO *); - if (pso != NULL) + if (pso != NULL && FIsLoInWorld(pso)) { - if (FIsLoInWorld(pso)) - { - *pn = 2; - return STRUCT_OFFSET(pjt, 0x25E4, SO *); - } + *pn = 2; + return STRUCT_OFFSET(pjt, 0x25E4, SO *); } pso = STRUCT_OFFSET(pjt, 0x25E8, SO *); - if (pso != NULL) + if (pso != NULL && FIsLoInWorld(pso)) { - if (FIsLoInWorld(pso)) - { - *pn = 1; - return STRUCT_OFFSET(pjt, 0x25E8, SO *); - } + *pn = 1; + return STRUCT_OFFSET(pjt, 0x25E8, SO *); } return NULL; @@ -229,11 +213,8 @@ SO *PsoGetJtEffect(JT *pjt, int *pn) INCLUDE_ASM("asm/nonmatchings/P2/jt", AddJtCustomXps__FP2JTP2SOiP3BSPT3PP2XP); -int CtTorqueJt(JT *pjt) -{ - if (pjt->jts == 3 || pjt->jts == 0xD) - return 0; - return 3; +int CtTorqueJt(JT *pjt) { + return pjt->jts == JTS_Zap || pjt->jts == JTS_Max ? 0 : 3; } INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172ee0); @@ -254,25 +235,22 @@ INCLUDE_ASM("asm/nonmatchings/P2/jt", ChooseJtPhys__FP2JT); void EnableJtActadj(JT *pjt, int grf) { - int a0; - int a2; + if (STRUCT_OFFSET(pjt, 0x2500, void *) == NULL) + return; - if (STRUCT_OFFSET(pjt, 0x2500, void *) != NULL) - { - a0 = grf & 0x1; - STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2500, char *), 0x10, char) = a0 ? 9 : -1; - STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2504, char *), 0x10, char) = a0 ? 9 : -1; - STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2508, char *), 0x10, char) = a0 ? 9 : -1; - a2 = grf & 0x2; - STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x250C, char *), 0x10, char) = a2 ? 9 : -1; - STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2510, char *), 0x10, char) = a2 ? 9 : -1; - - (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x24F8, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x24F8, void *)); - (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x618, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x618, void *)); - (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x61C, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x61C, void *)); - (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x610, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x610, void *)); - (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x614, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x614, void *)); - } + int a0 = grf & 0x1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2500, char *), 0x10, char) = a0 ? 9 : -1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2504, char *), 0x10, char) = a0 ? 9 : -1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2508, char *), 0x10, char) = a0 ? 9 : -1; + int a2 = grf & 0x2; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x250C, char *), 0x10, char) = a2 ? 9 : -1; + STRUCT_OFFSET(STRUCT_OFFSET(pjt, 0x2510, char *), 0x10, char) = a2 ? 9 : -1; + + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x24F8, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x24F8, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x618, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x618, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x61C, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x61C, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x610, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x610, void *)); + (*(*(void (***)(void *))STRUCT_OFFSET(pjt, 0x614, void *))[0x2F])(STRUCT_OFFSET(pjt, 0x614, void *)); } INCLUDE_ASM("asm/nonmatchings/P2/jt", SetJtJts__FP2JT3JTS4JTBS); diff --git a/src/P2/lgn.c b/src/P2/lgn.c index febd45b3..9720fd97 100644 --- a/src/P2/lgn.c +++ b/src/P2/lgn.c @@ -75,13 +75,11 @@ extern SNIP D_00264230; void PostSwpLoad(SWP *pswp) { - ACG *pacg; - PostBrkLoad((BRK *)pswp); SnipAloObjects((ALO *)pswp, 2, &D_00264230); STRUCT_OFFSET(pswp, 0x6c8, SMA *) = PsmaApplySm(STRUCT_OFFSET(pswp, 0x6c4, SM *), (ALO *)pswp, (OID)0x36e, 0); - pacg = PacgNew((ACGK)0); + ACG *pacg = PacgNew((ACGK) 0); STRUCT_OFFSET(pswp, 0x6e8, ACG *) = pacg; STRUCT_OFFSET(pacg, 0x8, int) = 0; STRUCT_OFFSET(STRUCT_OFFSET(pswp, 0x6e8, ACG *), 0xc, void *) = PvAllocSwImpl(0xc00); diff --git a/src/P2/mark.c b/src/P2/mark.c index e38e95db..fba6ef24 100644 --- a/src/P2/mark.c +++ b/src/P2/mark.c @@ -5,10 +5,8 @@ extern float D_00264840[][2]; float MuFromAmtlk(MTLK *amtlk) { - float mu; - - mu = (D_00264840[amtlk[0]][1] + D_00264840[amtlk[1]][1]) / - (D_00264840[amtlk[0]][0] + D_00264840[amtlk[1]][0]); + float mu = (D_00264840[amtlk[0]][1] + D_00264840[amtlk[1]][1]) / + (D_00264840[amtlk[0]][0] + D_00264840[amtlk[1]][0]); if (mu < 0.0f) { mu = 0.0f; diff --git a/src/P2/mb.c b/src/P2/mb.c index 91166fa5..65d374d3 100644 --- a/src/P2/mb.c +++ b/src/P2/mb.c @@ -45,12 +45,9 @@ SGS FUN_0018abf0(int param) if (STRUCT_OFFSET(pstepguard, 0x724, int) == 4) { GetSmaCur((SMA *)STRUCT_OFFSET(pstepguard, 0xE10, int), &oid); - if (oid == (OID)0x438) + if (oid == (OID)0x438 && SggsGetStepguard(pstepguard) == 0) { - if (SggsGetStepguard(pstepguard) == 0) - { - return (SGS)2; - } + return (SGS)2; } } diff --git a/src/P2/missile.c b/src/P2/missile.c index 94446ed8..8a99038b 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -12,11 +12,9 @@ extern SNIP s_asnipMissile; void LoadMissileFromBrx(MISSILE *pmissile, CBinaryInputStream *pbis) { - uint64_t grfalo; - LoadBombFromBrx(pmissile, pbis); SnipAloObjects(pmissile, 1, &s_asnipMissile); - grfalo = STRUCT_OFFSET(pmissile, 0x2c8, uint64_t); + uint64_t grfalo = STRUCT_OFFSET(pmissile, 0x2c8, uint64_t); STRUCT_OFFSET(pmissile, 0x2c8, uint64_t) = (grfalo & ~0x30000000000ULL) | (0x8000ULL << 0x19); } @@ -38,7 +36,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/missile", RenderMissileAll__FP7MISSILEP2CMP2RO) INCLUDE_ASM("asm/nonmatchings/P2/missile", FUN_0018dc88); #ifdef SKIP_ASM -extern "C" int FUN_0018dc88(SO *pso, SO *psoOther) +int FUN_0018dc88(SO *pso, SO *psoOther) { int i; diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index 05dacdaa..cc9939df 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -33,6 +33,7 @@ int FUN_0018e410(void *pv) pb++; goto loop; } + // @todo try to do this without goto return -1; } @@ -135,14 +136,14 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbSend__15CQueueOutputIopiPv); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__15CQueueOutputIop); -extern "C" int FAsyncDrain__15CQueueOutputIop() +int FAsyncDrain__15CQueueOutputIop() { return 0; } INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbWrite__15CQueueOutputIpuiPv); -extern "C" int FAsyncDrain__15CQueueOutputIpu() +int FAsyncDrain__15CQueueOutputIpu() { return 1; } @@ -233,8 +234,6 @@ int FMpegAcceptVideo(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) return 1; } -struct sceMpeg; -struct sceMpegCbDataStr; int FMpegAcceptAudio(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) { return FAccept__10CMpegAudioiPUc((uint8_t *)pmpeg + 0x80, STRUCT_OFFSET(pcbdata, 0xC, int), STRUCT_OFFSET(pcbdata, 0x8, uchar *)); @@ -242,7 +241,6 @@ int FMpegAcceptAudio(sceMpeg *pmp, sceMpegCbDataStr *pcbdata, CMpeg *pmpeg) INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegDecodeVideo__FP7sceMpegP13sceMpegCbDataP5CMpeg); -struct sceMpeg; struct sceMpegCbData; int FMpegDecoderIdle(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) { @@ -250,8 +248,6 @@ int FMpegDecoderIdle(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) return 1; } -struct sceMpeg; -struct sceMpegCbData; int FMpegDecoderError(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) { diff --git a/src/P2/path.c b/src/P2/path.c index 22eb1aaf..719b56a4 100644 --- a/src/P2/path.c +++ b/src/P2/path.c @@ -55,14 +55,12 @@ INCLUDE_ASM("asm/nonmatchings/P2/path", HookupCg__FP2CG); struct PATHZONE; struct VECTOR; -extern int CposFindPath(CG *pcg, VECTOR *pvec0, VECTOR *pvec1, int n, VECTOR *pvec2); int CposFindPathzonePath(PATHZONE *ppathzone, VECTOR *pvec0, VECTOR *pvec1, int n, VECTOR *pvec2) { return CposFindPath((CG *)((char *)ppathzone + 0x34), pvec0, pvec1, n, pvec2); } -void FindClosestPointInCg(CG *pcg, VECTOR *pvec0, VECTOR *pvec1); void FindPathzoneClosestPoint(PATHZONE *ppathzone, VECTOR *pvec0, VECTOR *pvec1) { diff --git a/src/P2/prompt.c b/src/P2/prompt.c index eb38c0c0..8234810e 100644 --- a/src/P2/prompt.c +++ b/src/P2/prompt.c @@ -54,11 +54,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/prompt", OnPromptActive__FP6PROMPTi); void FUN_00194278(PROMPT *pprompt, int fButton, WIPEK wipek) { - int idLevel; - SetPrompt(pprompt, (PRP)0, (PRK)-1); - idLevel = (STRUCT_OFFSET(g_pgsCur, 0x19d8, int) << 8) | STRUCT_OFFSET(g_pgsCur, 0x19dc, int); + int idLevel = (STRUCT_OFFSET(g_pgsCur, 0x19d8, int) << 8) | STRUCT_OFFSET(g_pgsCur, 0x19dc, int); if (idLevel == 0x106) { diff --git a/src/P2/puffer.c b/src/P2/puffer.c index d95f7824..698b9ee8 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -111,11 +111,10 @@ void OnPuffcExitingSgs(PUFFC *ppuffc, SGS sgsNext) { if (STRUCT_OFFSET(ppuffc, 0x724, int) == SGS_Stun) { - VU_VECTOR vec; FUN_00197a08(PpoCur(), ppuffc); - vec = STRUCT_OFFSET(ppuffc, 0x150, VU_VECTOR); + VU_VECTOR vec = STRUCT_OFFSET(ppuffc, 0x150, VU_VECTOR); STRUCT_OFFSET((&vec), 0x8, int) = 0; (*(void (**)(PUFFC *, VU_VECTOR *))((uint8_t *)STRUCT_OFFSET(ppuffc, 0x0, void *) + 0x90))(ppuffc, &vec); } @@ -149,11 +148,9 @@ extern SNIP D_0026A8E0; void PostPuffbLoad(PUFFB *ppuffb) { - LO *plo; - SnipAloObjects(ppuffb, 3, &D_0026A8E0); PostAloLoad(ppuffb); - plo = PloFindSwObjectByClass(ppuffb->psw, FSO_FindAll, CID_TURRET, NULL); + LO *plo = PloFindSwObjectByClass(ppuffb->psw, FSO_FindAll, CID_TURRET, NULL); if (plo != NULL) { STRUCT_OFFSET(plo, 0x684, int)++; diff --git a/src/P2/pzo.c b/src/P2/pzo.c index 2ce6045a..a0d40450 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -59,8 +59,8 @@ void CloneScprize(SCPRIZE *pscprize, SCPRIZE *pscprizeBase) PCS PcsFromScprize(SCPRIZE *pscprize) { - extern int FGetChkmgrIchk(CHKMGR *pchkmgr, int ichk); - extern CHKMGR g_chkmgr; + int FGetChkmgrIchk(CHKMGR *pchkmgr, int ichk); + CHKMGR g_chkmgr; PCS pcs = PcsFromSprize((SPRIZE *)pscprize); @@ -80,12 +80,12 @@ void CollectScprize(SCPRIZE *pscprize) CollectSprize(pscprize); } -extern SNIP D_0026A918; +extern SNIP s_asnip; void LoadLockFromBrx(LOCK *plock, CBinaryInputStream *pbis) { LoadAloFromBrx(plock, pbis); - SnipAloObjects(plock, 1, &D_0026A918); + SnipAloObjects(plock, 1, &s_asnip); } extern SNIP D_0026A928; @@ -183,12 +183,9 @@ void TriggerLockg(LOCKG *plockg) void InitClue(CLUE *pclue) { - SW *psw; - int n; - InitSprize(pclue); - psw = pclue->psw; - n = STRUCT_OFFSET(psw, 0x2300, int); + SW *psw = pclue->psw; + int n = STRUCT_OFFSET(psw, 0x2300, int); STRUCT_OFFSET(pclue, 0x5a0, int) = n; STRUCT_OFFSET(psw, 0x2300, int) = n + 1; } @@ -232,7 +229,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", OnClueSmack__FP4CLUE); void CollectClue(CLUE *pclue) { - extern char D_0026A970; + char D_0026A970; RIP *pripg; VECTOR vec; @@ -259,6 +256,7 @@ void CollectClue(CLUE *pclue) void BreakClue(CLUE *pclue) { + // @todo clean up this vtable call ((void (*)(CLUE *))STRUCT_OFFSET(pclue->pvtlo, 0x134, void *))(pclue); } @@ -273,6 +271,7 @@ void ImpactClue(CLUE *pclue, int fParentDirty) int FAbsorbClueWkr(CLUE *pclue, WKR *pwkr) { + // @todo clean up these vtable calls if (pwkr->grfic & 0x8) { ((void (*)(CLUE *, int))STRUCT_OFFSET(pclue->pvtlo, 0x64, void *))(pclue, 0); diff --git a/src/P2/rchm.c b/src/P2/rchm.c index 9dbfd0f8..b7500afc 100644 --- a/src/P2/rchm.c +++ b/src/P2/rchm.c @@ -47,12 +47,11 @@ void TrackJtTarget(JT *pjt, RCHM *prchm, TARGET *ptarget) VECTOR posClosest; TWR *ptwr; float s; - float dt; if (ptarget == NULL) return; - dt = STRUCT_OFFSET(pjt, 0x2424, float) - g_clock.t; + float dt = STRUCT_OFFSET(pjt, 0x2424, float) - g_clock.t; if (dt < g_clock.dt) dt = g_clock.dt; diff --git a/src/P2/rip.c b/src/P2/rip.c index 1755a776..c12fe637 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -8,17 +8,12 @@ RIPG *PripgNew(SW *psw, RIPGT ripgt) { - RIPG *pripg; - - if (ripgt == RIPGT_Default) + if (ripgt == RIPGT_Default && STRUCT_OFFSET(psw, 0x1B3C, RIPG *) != NULL) { - if (STRUCT_OFFSET(psw, 0x1B3C, RIPG *) != NULL) - { - return STRUCT_OFFSET(psw, 0x1B3C, RIPG *); - } + return STRUCT_OFFSET(psw, 0x1B3C, RIPG *); } - pripg = STRUCT_OFFSET(psw, 0x1B38, RIPG *); + RIPG *pripg = STRUCT_OFFSET(psw, 0x1B38, RIPG *); if (pripg != NULL) { STRUCT_OFFSET(psw, 0x1B38, RIPG *) = STRUCT_OFFSET(pripg, 0x564, RIPG *); @@ -100,16 +95,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectRipTransform__FP3RIPf); void UpdateRip(RIP *prip, float dt) { - int fInBsp; - RIPG *pripg; - if (STRUCT_OFFSET(prip, 0x1c, float) < g_clock.t - STRUCT_OFFSET(prip, 0x18, float)) { RemoveRip(prip); return; } - pripg = prip->pripg; + RIPG *pripg = prip->pripg; if (STRUCT_OFFSET(pripg, 0x550, int) == 1) return; @@ -118,7 +110,7 @@ void UpdateRip(RIP *prip, float dt) if (STRUCT_OFFSET(STRUCT_OFFSET(prip, 0x24, ALO *), 0x3f8, BSP *) == NULL) return; - fInBsp = 0; + int fInBsp = 0; if (FIsLoInWorld((LO *)STRUCT_OFFSET(prip, 0x24, ALO *))) { if (PbspPointInBspQuick(&STRUCT_OFFSET(prip, 0x80, VECTOR), STRUCT_OFFSET(STRUCT_OFFSET(prip, 0x24, ALO *), 0x3f8, BSP *))) @@ -138,8 +130,7 @@ void RenderRip(RIP *prip, CM *pcm) MATRIX3 *pmat; WR *pwr; - pwr = STRUCT_OFFSET(prip, 0x114, WR *); - if (pwr != NULL) + if (STRUCT_OFFSET(prip, 0x114, WR *) != NULL) { WarpWrTransform(pwr, 50.0f, &STRUCT_OFFSET(prip, 0x80, VECTOR), @@ -316,11 +307,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderRose__FP4ROSEP2CM); INCLUDE_ASM("asm/nonmatchings/P2/rip", SetRoseRoses__FP4ROSE5ROSES); -int SgnCmpHp(const void *pv0, const void *pv1) -{ - if (STRUCT_OFFSET(pv0, 0x20, float) < STRUCT_OFFSET(pv1, 0x20, float)) - return -1; - return 1; +int SgnCmpHp(const void *pv0, const void *pv1) { + return STRUCT_OFFSET(pv0, 0x20, float) < STRUCT_OFFSET(pv1, 0x20, float) ? -1 : 1; } INCLUDE_ASM("asm/nonmatchings/P2/rip", ChpBuildConvexHullScreen__FP6VECTORiP2HP); @@ -357,13 +345,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", ProjectLeafTransform__FP4LEAFf); int FBounceLeaf(LEAF *pleaf, SO *psoOther, VECTOR *ppos, VECTOR *pnormal) { - STUCK *pstuck; if (FIsBasicDerivedFrom(STRUCT_OFFSET(psoOther, 0x50, BASIC *), CID_MISSILE)) return 0; if (FIsBasicDerivedFrom(STRUCT_OFFSET(psoOther, 0x50, BASIC *), CID_STEP)) return 0; + STUCK *pstuck; CreateStuck((RIP *)pleaf, STRUCT_OFFSET(pleaf, 0x20, ALO *), psoOther, ppos, pnormal, &pstuck); if (pstuck != NULL) { diff --git a/src/P2/rog.c b/src/P2/rog.c index 1f285464..1d5fc8c6 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -53,9 +53,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", SetRovRovs__FP3ROV4ROVS); ROVTS RovtsNextRov(ROV *prov) { - ROVTS rovts; - - rovts = STRUCT_OFFSET(prov, 0x614, ROVTS); + ROVTS rovts = STRUCT_OFFSET(prov, 0x614, ROVTS); switch (rovts) { @@ -151,9 +149,7 @@ extern BLOT g_unkblot0; void FUN_001a4d60(ROB *prob) { - int fShow; - - fShow = 0; + int fShow = 0; if (STRUCT_OFFSET(prob, 0x650, int) == 2) { fShow = FUN_001e9970(); @@ -181,9 +177,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/rog", AdjustRobDifficulty__FP3ROBf); void DestroyedRobRoc(ROB *prob, ROC *proc) { - int cRoc; - - cRoc = STRUCT_OFFSET(prob, 0x3c4, int) + 1; + int cRoc = STRUCT_OFFSET(prob, 0x3c4, int) + 1; STRUCT_OFFSET(prob, 0x3c4, int) = cRoc; AdjustRobDifficulty(prob, (float)cRoc / (float)STRUCT_OFFSET(prob, 0x3b8, int)); @@ -208,6 +202,7 @@ void DestroyedRobRoc(ROB *prob, ROC *proc) } STRUCT_OFFSET(proc, 0x55c, ROH *) = NULL; + // @todo clean up this vtable call (*(void (**)(ROC *))((char *)((LO *)proc)->pvtlo + 0x1c))(proc); if (STRUCT_OFFSET(prob, 0x380, int) == STRUCT_OFFSET(prob, 0x624, int)) @@ -228,8 +223,6 @@ void SpawnedRobRoh(ROB *prob, ROH *proh) void GrabbedRobRoh(ROB *prob, ROH *proh) { - extern VECTOR D_00248D30; - (*(void (**)(SO *))(*(uint8_t **)STRUCT_OFFSET(proh, 0x55c, SO *) + 0x64))(STRUCT_OFFSET(proh, 0x55c, SO *)); (*(void (**)(SO *, VECTOR *))(*(uint8_t **)STRUCT_OFFSET(proh, 0x55c, SO *) + 0x90))(STRUCT_OFFSET(proh, 0x55c, SO *), &D_00248D30); (*(void (**)(SO *, VECTOR *))(*(uint8_t **)STRUCT_OFFSET(proh, 0x55c, SO *) + 0x94))(STRUCT_OFFSET(proh, 0x55c, SO *), &D_00248D30); @@ -239,8 +232,6 @@ void GrabbedRobRoh(ROB *prob, ROH *proh) void DroppedRobRoh(ROB *prob, ROH *proh) { - extern VECTOR D_00248D30; - extern VECTOR g_normalZ; SO *pso = STRUCT_OFFSET(proh, 0x55c, SO *); @@ -262,7 +253,6 @@ void KilledRobRoh(ROB *prob, ROH *proh) RemoveDlEntry(&STRUCT_OFFSET(prob, 0x384, DL), proh); AppendDlEntry(&STRUCT_OFFSET(prob, 0x390, DL), proh); - ROC *proc; if (STRUCT_OFFSET(proh, 0x560, ROST *) != NULL) { RemoveDlEntry(&STRUCT_OFFSET(prob, 0x3ac, DL), STRUCT_OFFSET(proh, 0x560, void *)); @@ -270,7 +260,7 @@ void KilledRobRoh(ROB *prob, ROH *proh) SetRostRosts(STRUCT_OFFSET(proh, 0x560, ROST *), ROSTS_Close); } - proc = STRUCT_OFFSET(proh, 0x55c, ROC *); + ROC *proc = STRUCT_OFFSET(proh, 0x55c, ROC *); if (proc != NULL) { if (STRUCT_OFFSET(proc, 0x18, ROH *) == proh) diff --git a/src/P2/rwm.c b/src/P2/rwm.c index 3f89b04f..4b148bd3 100644 --- a/src/P2/rwm.c +++ b/src/P2/rwm.c @@ -15,7 +15,6 @@ void OnRwmRemove(RWM *prwm) FUN_001a93c8(prwm); } -extern "C" { void *FUN_001a8110(RWM *prwm) { if (STRUCT_OFFSET(prwm, 0x3c, void *) == 0) @@ -26,13 +25,12 @@ void *FUN_001a8110(RWM *prwm) } return STRUCT_OFFSET(prwm, 0x3c, void *); } -} INCLUDE_ASM("asm/nonmatchings/P2/rwm", FUN_001a8150); INCLUDE_ASM("asm/nonmatchings/P2/rwm", InitRwmCallback__FP3RWM5MSGIDPv); -extern "C" void FUN_001a84c8(RWM *prwmDst, RWM *prwmSrc) +void FUN_001a84c8(RWM *prwmDst, RWM *prwmSrc) { CloneLo((LO *)prwmDst, (LO *)prwmSrc); if (STRUCT_OFFSET(prwmDst, 0x3c, void *) != 0 && @@ -162,7 +160,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/rwm", FEnsureRwmLoaded__FP3RWM); INCLUDE_ASM("asm/nonmatchings/P2/rwm", FFireRwm__FP3RWMi); -extern "C" void FUN_001a93c8(RWM *prwm) +void FUN_001a93c8(RWM *prwm) { int *p = STRUCT_OFFSET(prwm, 0x3c, int *); STRUCT_OFFSET(prwm, 0x48, int) = 0; diff --git a/src/P2/sb.c b/src/P2/sb.c index edf7fc0e..9ba54c68 100644 --- a/src/P2/sb.c +++ b/src/P2/sb.c @@ -42,11 +42,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/sb", OnSbgEnteringSgs__FP3SBG3SGSP4ASEG); void UpdateSbg(SBG *psbg, float dt) { - ASEGA *pasega; - UpdateStepguard(psbg, dt); - pasega = STRUCT_OFFSET(psbg, 0xC20, ASEGA *); + ASEGA *pasega = STRUCT_OFFSET(psbg, 0xC20, ASEGA *); if (pasega != NULL) { if (STRUCT_OFFSET(pasega, 0x18, float) == 0.0f) diff --git a/src/P2/screen.c b/src/P2/screen.c index 15ee0985..5c965967 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -357,12 +357,9 @@ extern CFont *D_00274410; void PostTotalsLoad(TOTALS *ptotals) { - CFont *pfont; - void *pv; - PostBlotLoad((BLOT *)ptotals); - pfont = FUN_0015c1c0(0); - pv = STRUCT_OFFSET(pfont, 0x4c, void *); + CFont *pfont = FUN_0015c1c0(0); + void *pv = STRUCT_OFFSET(pfont, 0x4c, void *); STRUCT_OFFSET(ptotals, 0x4, int) = (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), 1.0f, 1.0f); @@ -387,14 +384,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", render_hideout_world_info); void SetTotalsBlots(TOTALS *ptotals, BLOTS blots) { - if (ptotals->fReshow) + if (ptotals->fReshow && blots == BLOTS_Hidden) { - if (blots == BLOTS_Hidden) - { - ptotals->fReshow = 0; - SetBlotAchzDraw(ptotals, (char *)&ptotals->grflsReshow); - blots = BLOTS_Appearing; - } + ptotals->fReshow = 0; + SetBlotAchzDraw(ptotals, (char *)&ptotals->grflsReshow); + blots = BLOTS_Appearing; } if (blots == BLOTS_Hidden) @@ -413,12 +407,9 @@ extern char D_0024CEE0[]; void FUN_001ad6a8(BLOT *pblot) { - CFont *pfont; - void *pv; - PostBlotLoad(pblot); - pfont = FUN_0015c1c0(2); - pv = STRUCT_OFFSET(pfont, 0x4c, void *); + CFont *pfont = FUN_0015c1c0(2); + void *pv = STRUCT_OFFSET(pfont, 0x4c, void *); STRUCT_OFFSET(pblot, 0x4, int) = (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), 1.0f, 1.0f); @@ -460,12 +451,9 @@ extern char D_0024CEF0[]; void FUN_001adc60(BLOT *pblot) { - CFont *pfont; - void *pv; - PostBlotLoad(pblot); - pfont = STRUCT_OFFSET(pblot, 0x4, CFont *); - pv = STRUCT_OFFSET(pfont, 0x4c, void *); + CFont *pfont = STRUCT_OFFSET(pblot, 0x4, CFont *); + void *pv = STRUCT_OFFSET(pfont, 0x4c, void *); STRUCT_OFFSET(pblot, 0x4, int) = (*(int (**)(void *, float, float))((uint8_t *)pv + 0xc))( (uint8_t *)pfont + STRUCT_OFFSET(pv, 0x8, short), D_00274448, D_0027444C); diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 9d0fc299..8933cf5b 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -75,33 +75,30 @@ INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateSensor__FP6SENSORf); void AddSensorTriggerObject(SENSOR * p, OID oid) { - int c = STRUCT_OFFSET(p, 0x564, int); - if ((unsigned int)c < 4) - { - OID *a = &STRUCT_OFFSET(p, 0x568, OID); - a[c] = oid; - STRUCT_OFFSET(p, 0x564, int) = c + 1; - } + uint ccur = psensor->ctriggerObjects; + if (ccur >= 4) + return; + + psensor->atriggerObjects[ccur] = oid; + psensor->ctriggerObjects = ccur + 1; } void AddSensorNoTriggerObject(SENSOR * p, OID oid) { - int c = STRUCT_OFFSET(p, 0x578, int); - if ((unsigned int)c < 4) - { - OID *a = &STRUCT_OFFSET(p, 0x57c, OID); - a[c] = oid; - STRUCT_OFFSET(p, 0x578, int) = c + 1; - } + uint ccur = psensor->cnoTriggerObjects; + if (ccur >= 4) + return; + + psensor->anoTriggerObjects[ccur] = oid; + psensor->cnoTriggerObjects = ccur + 1; } void AddSensorTriggerClass(SENSOR * p, CID cid) { - int c = STRUCT_OFFSET(p, 0x58c, int); - if ((unsigned int)c < 4) - { - CID *a = &STRUCT_OFFSET(p, 0x590, CID); - a[c] = cid; - STRUCT_OFFSET(p, 0x58c, int) = c + 1; - } + uint ccur = psensor->ctriggerClasses; + if (ccur >= 4) + return; + + psensor->atriggerClasses[ccur] = cid; + psensor->ctriggerClasses = ccur + 1; } void AddSensorNoTriggerClass(SENSOR * p, CID cid) { @@ -230,7 +227,6 @@ void PostCamsenLoad(CAMSEN *pcamsen) { void *pvt; void (*pfn)(CAMSEN *, int); - extern SNIP D_002744D8[2]; PostAloLoad(pcamsen); SnipAloObjects(pcamsen, 2, D_002744D8); diff --git a/src/P2/shd.c b/src/P2/shd.c index 92f458ff..f352e737 100644 --- a/src/P2/shd.c +++ b/src/P2/shd.c @@ -49,16 +49,16 @@ void PropagateSurs(); void PropagateShaders(GRFZON grfzonCamera) { PropagateSais(); - if (grfzonCamera != g_grfzonShaders) - { - ResetGsb(&D_002626D8); - UploadBitmaps(grfzonCamera, &D_002626D8); - FillShaders(grfzonCamera); - PropagateSurs(); - PropagateBlipgShaders(grfzonCamera); - D_002626CC = 2; - g_grfzonShaders = grfzonCamera; - } + if (grfzonCamera == g_grfzonShaders) + return; + + ResetGsb(&D_002626D8); + UploadBitmaps(grfzonCamera, &D_002626D8); + FillShaders(grfzonCamera); + PropagateSurs(); + PropagateBlipgShaders(grfzonCamera); + D_002626CC = 2; + g_grfzonShaders = grfzonCamera; } INCLUDE_ASM("asm/nonmatchings/P2/shd", FillShaders__Fi); @@ -89,8 +89,6 @@ extern SAI *g_psaiUpdateTail; void SetSaiDuDv(SAI *psai, float du, float dv) { - SAI *psaiNext; - if (!STRUCT_OFFSET(psai, 0x4, int)) return; @@ -98,7 +96,7 @@ void SetSaiDuDv(SAI *psai, float du, float dv) STRUCT_OFFSET(psai, 0x10, float) == dv) return; - psaiNext = STRUCT_OFFSET(psai, 0x18, SAI *); + SAI *psaiNext = STRUCT_OFFSET(psai, 0x18, SAI *); STRUCT_OFFSET(psai, 0xc, float) = du; STRUCT_OFFSET(psai, 0x10, float) = dv; diff --git a/src/P2/sm.c b/src/P2/sm.c index 2ace6936..d88c094f 100644 --- a/src/P2/sm.c +++ b/src/P2/sm.c @@ -75,11 +75,9 @@ void EndSmaTransition(SMA *psma) void HandleSmaMessage(SMA *psma, MSGID msgid, void *pv) { - if (msgid == MSGID_asega_limit) { - if ((ASEGA*)pv == psma->pasegaCur) { - EndSmaTransition(psma); - ChooseSmaTransition(psma); - } + if (msgid == MSGID_asega_limit && (ASEGA*)pv == psma->pasegaCur) { + EndSmaTransition(psma); + ChooseSmaTransition(psma); } } @@ -112,7 +110,6 @@ void SendSmaMessage(SMA *psma, MSGID msgid, void *pv) } MQ *pmq = psma->pmqFirst; - while (pmq) { PFNMQ pfnmq = pmq->pfnmq; diff --git a/src/P2/smartguard.c b/src/P2/smartguard.c index d2d4a75b..5a36a370 100644 --- a/src/P2/smartguard.c +++ b/src/P2/smartguard.c @@ -59,8 +59,7 @@ void PostSmartguardLoad(SMARTGUARD *psmartguard) int FFilterSmartguardDetect(SMARTGUARD *psmartguard, SO *pso) { - int i; - int c; + int i, c; if (STRUCT_OFFSET(pso, 0x538, long long) & 0x80000000000LL) { diff --git a/src/P2/so.c b/src/P2/so.c index 769091ef..223376e3 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -26,7 +26,7 @@ void OnSoAdd(SO *pso) pfn(pso); if ((STRUCT_OFFSET(pso, 0x538, uint64_t) & ((uint64_t)0x8000 << 39)) == 0) // locked, bit 54 { - RecalcSoLocked(STRUCT_OFFSET(pso, 0x50, SO *)); + RecalcSoLocked(STRUCT_OFFSET(pso, 0x50, SO *)); // pso->paloRoot } else { diff --git a/src/P2/sound.c b/src/P2/sound.c index f07f4ca3..0582b9f6 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -29,7 +29,6 @@ void UnloadMusic() { extern u_int D_0027473C; extern u_int D_00274728; - extern int D_00274720; if (D_0027473C != 0) { @@ -91,7 +90,6 @@ int SetVagUnpaused() INCLUDE_ASM("asm/nonmatchings/P2/sound", PreloadVag__FPc2FK); extern u_int D_00274744; -void StopVag(); void FUN_001be708(void) { D_00274744 = 0; @@ -169,22 +167,19 @@ JUNK_WORD(0x0080102D); void StopVag() { - if (D_00274744 == 0) + if (D_00274744 == 0 && D_0027472C != 0) { - if (D_0027472C != 0) + snd_StopSound(D_0027472C); + while (snd_SoundIsStillPlaying(D_0027472C)) { - snd_StopSound(D_0027472C); - while (snd_SoundIsStillPlaying(D_0027472C)) + int i = 0x4E1F; + do { - int i = 0x4E1F; - do - { - i--; - } while (i >= 0); - } - D_0027472C = 0; - D_00274730 = 0; + i--; + } while (i >= 0); } + D_0027472C = 0; + D_00274730 = 0; } } diff --git a/src/P2/speaker.c b/src/P2/speaker.c index 0e93ba47..04f271f6 100644 --- a/src/P2/speaker.c +++ b/src/P2/speaker.c @@ -8,15 +8,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/speaker", PostSpeakerLoad__FP7SPEAKER); void SetSpeakerSmIdle(SPEAKER *pspeaker, OID oid) { - SM *psm; - if (STRUCT_OFFSET(pspeaker, 0x334, SMA *) != NULL) { RetractSma(STRUCT_OFFSET(pspeaker, 0x334, SMA *)); STRUCT_OFFSET(pspeaker, 0x334, SMA *) = NULL; } - psm = (SM *)PloFindSwObject(pspeaker->psw, 0x101, oid, pspeaker); + SM *psm = (SM *) PloFindSwObject(pspeaker->psw, 0x101, oid, pspeaker); STRUCT_OFFSET(pspeaker, 0x330, SM *) = psm; if (psm != NULL) diff --git a/src/P2/splicemap.c b/src/P2/splicemap.c index 3d56da0c..15e21e45 100644 --- a/src/P2/splicemap.c +++ b/src/P2/splicemap.c @@ -5,12 +5,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/splicemap", LoadSwSpliceFromBrx__FP2SWP18CBinar CFrame *PframeFromIsplice(int isplice, SW *psw) { - CFrame *pframe; - if (isplice == -1) return NULL; - pframe = *(CFrame **)((uint8_t *)STRUCT_OFFSET(psw, 0x1EF4, void *) + isplice * 8 + 4); + CFrame *pframe = *(CFrame **)((uint8_t *)STRUCT_OFFSET(psw, 0x1EF4, void *) + isplice * 8 + 4); if (pframe != NULL) g_gc.AddRootFrame(pframe); diff --git a/src/P2/step.c b/src/P2/step.c index 1206a75b..414e8dba 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -14,17 +14,15 @@ INCLUDE_ASM("asm/nonmatchings/P2/step", FUN_001c4618); void FUN_001c4790(void *p1, SO *pso, BSP *pbsp, void *p4) { - LSG alsg[2]; - int clsg; - int i; if (STRUCT_OFFSET(p4, 0x50, int) == 0) return; - clsg = ClsgClipEdgeToObjectPruned(pso, pbsp, (VECTOR *)((uint8_t *)p4 + 0x70), + LSG alsg[2]; + int clsg = ClsgClipEdgeToObjectPruned(pso, pbsp, (VECTOR *)((uint8_t *)p4 + 0x70), (VECTOR *)((uint8_t *)p4 + 0x60), 2, alsg); - i = 0; + int i = 0; if (clsg > 0) { if (alsg[0].au[0] == 0.0f) @@ -70,9 +68,7 @@ void PropagateSoForce(SO *psoRoot, GRFSG grfsg, XP *pxp, int ixpd, DZ *pdz, FX * void PropagateStepForce(STEP *pstep, GRFSG grfsg, XP *pxp, int ixpd, DZ *pdz, FX *afx) { - CT ctSav; - - ctSav = STRUCT_OFFSET(pstep, 0x470, CT); + CT ctSav = STRUCT_OFFSET(pstep, 0x470, CT); STRUCT_OFFSET(pstep, 0x470, CT) = (*(CT (**)(STEP *))((uint8_t *)pstep->pvtlo + 0x164))(pstep); PropagateSoForce(pstep, grfsg, pxp, ixpd, pdz, afx); @@ -107,7 +103,7 @@ void AdjustStepDzBase(STEP *pstep, GRFADJ grfadj, DZ *pdz, int ixpd) void UpdateStepMatTarget(STEP *pstep) { - extern VECTOR g_normalZ; + VECTOR g_normalZ; LoadRotateMatrixRad(*(float *)((uint8_t *)(pstep) + 0x638), &g_normalZ, (MATRIX3 *)((uint8_t *)(pstep) + 0x660)); } @@ -132,11 +128,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/step", AddStepCustomXpsBase__FP4STEPP2SOP3BSPPP void FixStepAngularVelocity(STEP *pstep) { - qword local; - float radTarget; - - local = STRUCT_OFFSET(pstep, 0x160, qword); - radTarget = atan2f(STRUCT_OFFSET(pstep, 0xd4, float), STRUCT_OFFSET(pstep, 0xd0, float)); + qword local = STRUCT_OFFSET(pstep, 0x160, qword); + float radTarget = atan2f(STRUCT_OFFSET(pstep, 0xd4, float), STRUCT_OFFSET(pstep, 0xd0, float)); RadSmooth(radTarget, STRUCT_OFFSET(pstep, 0x638, float), 0.0f, (SMP *)((uint8_t *)pstep + 0x6e0), (float *)((uint8_t *)&local + 8)); (*(void (**)(STEP *, qword *))((uint8_t *)pstep->pvtlo + 0x94))(pstep, &local); diff --git a/src/P2/stepcane.c b/src/P2/stepcane.c index c11bbbc8..8f8d6c2e 100644 --- a/src/P2/stepcane.c +++ b/src/P2/stepcane.c @@ -14,7 +14,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtSweepTarget__FP2JTP2BLP6ASEG void ChooseJtRushTarget(JT *pjt) { - extern VECTOR D_00274BF0; + VECTOR D_00274BF0; VECTOR dposProj; TARGET *ptarget; @@ -31,7 +31,6 @@ void ChooseJtRushTarget(JT *pjt) void ChooseJtSmashTarget(JT *pjt) { - extern VECTOR D_00274C00; VECTOR dposProj; TARGET *ptarget; diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 11f30bc9..4fb7e809 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -271,7 +271,7 @@ void SetStepguardEnemyObject(STEPGUARD *pstepguard, SO *psoEnemy) INCLUDE_ASM("asm/nonmatchings/P2/stepguard", RebindStepguardEnemy__FP9STEPGUARD); -extern "C" void FUN_001cac28__FP9STEPGUARD(STEPGUARD *pstepguard, int n) +void FUN_001cac28__FP9STEPGUARD(STEPGUARD *pstepguard, int n) { STRUCT_OFFSET(pstepguard, 0xB50, int) = n; } diff --git a/src/P2/steprail.c b/src/P2/steprail.c index 8f635178..5934edfd 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -4,9 +4,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D31D0__FP2LOi); -extern "C" void post_load_steprail(ALO *palo) +void post_load_steprail(ALO *palo) { - extern SNIP D_00274F90; PostAloLoad(palo); SnipAloObjects(palo, 1, &D_00274F90); void **ppvtable = (void **)STRUCT_OFFSET(palo, 0x0, void*); @@ -18,7 +17,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D32D8__FiP2JTl); INCLUDE_ASM("asm/nonmatchings/P2/steprail", update_steprail); -extern "C" void preset_steprail_accel(SO *pso, float dt) +void preset_steprail_accel(SO *pso, float dt) { MATRIX3 mat; extern VECTOR D_00248D30; diff --git a/src/P2/suv.c b/src/P2/suv.c index 90b0cbda..ebbc9185 100644 --- a/src/P2/suv.c +++ b/src/P2/suv.c @@ -41,17 +41,13 @@ void UpdateSuvWheels(SUV *psuv) extern float D_002754F8; extern float D_002754F4; extern SMP D_002754E8; - float rad; - char *p; - int i; - - rad = atan2f(STRUCT_OFFSET(psuv, 0xD4, float), STRUCT_OFFSET(psuv, 0xD0, float)); + float rad = atan2f(STRUCT_OFFSET(psuv, 0xD4, float), STRUCT_OFFSET(psuv, 0xD0, float)); rad = RadNormalize(STRUCT_OFFSET(psuv, 0x694, float) - rad); rad = GLimitAbs(D_002754F8 * rad, D_002754F4); STRUCT_OFFSET(psuv, 0x69C, float) = RadSmooth(STRUCT_OFFSET(psuv, 0x69C, float), rad, g_clock.dt, &D_002754E8, NULL); - p = (char *)psuv + 0x6B0; - for (i = 0; i < 4; i++) + char *p = (char *)psuv + 0x6B0; + for (int i = 0; i < 4; i++) { float gDiv; if (i < 2) @@ -99,9 +95,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/suv", UpdateSuvBounds__FP3SUV); void CollectSuvPrize(SUV *psuv, PCK pck, ALO *paloOther) { - STEPGUARD *pstepguard; - - pstepguard = STRUCT_OFFSET(psuv, 0xb78, STEPGUARD *); + STEPGUARD *pstepguard = STRUCT_OFFSET(psuv, 0xb78, STEPGUARD *); if (pstepguard != NULL) { SetStepguardPatrolAnimation(pstepguard, NULL); diff --git a/src/P2/sw.c b/src/P2/sw.c index 323ac572..7dc418b5 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -417,7 +417,6 @@ int FUN_001dd7a0(SW *psw, int wid) INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7e8); -extern int *PlsFromWid(WID wid) __asm__("LsFromWid"); int FUN_001dd888(SW *psw, WID wid, int nKey) { @@ -529,11 +528,6 @@ void CancelSwDialogPlaying(SW *psw) } } -typedef struct -{ - int n; -} __attribute__((packed)) UNALIGNED_INT; - extern PROMPT D_0026FF68; void FUN_001ddb20(SW *psw, PRK prk, int oid) @@ -566,15 +560,11 @@ void FUN_001ddbb8(SW *psw) } JUNK_WORD(0x0002102a); -EXC *PexcSetExcitement(int gexc); - EXC *FUN_001ddbf8(SW *psw, int gexc) { return PexcSetExcitement(gexc); } -void UnsetExcitementHyst(EXC *pexc); - void FUN_001ddc18(SW *psw, EXC *pexc) { UnsetExcitementHyst(pexc); diff --git a/src/P2/tank.c b/src/P2/tank.c index 4f4ac4a1..5fca9efa 100644 --- a/src/P2/tank.c +++ b/src/P2/tank.c @@ -5,13 +5,10 @@ void InitTank(TANK *ptank) { - extern VECTOR g_normalZ; - extern qword D_00275740; - float rad; InitStep((STEP *)ptank); - rad = atan2f(STRUCT_OFFSET(ptank, 0xD4, float), STRUCT_OFFSET(ptank, 0xD0, float)); + float rad = atan2f(STRUCT_OFFSET(ptank, 0xD4, float), STRUCT_OFFSET(ptank, 0xD0, float)); STRUCT_OFFSET(ptank, 0x638, float) = rad; LoadRotateMatrixRad(rad, &g_normalZ, (MATRIX3 *)((uint8_t *)ptank + 0x660)); diff --git a/src/P2/tn.c b/src/P2/tn.c index ad4c2585..35f78299 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -8,9 +8,7 @@ extern TNFN D_00275980; TNFN *PtnfnFromTn(TN *ptn) { - if (ptn == NULL) - return &D_00275980; - return (TNFN *)((uint8_t *)ptn + 0x2F0); + return ptn == NULL ? &D_00275980 : (TNFN *)((uint8_t *)ptn + 0x2F0); } INCLUDE_ASM("asm/nonmatchings/P2/tn", GetTnfnNose__FP4TNFNP6CPDEFIP6VECTORP2TN); @@ -21,8 +19,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", InitTn__FP2TN); #ifdef SKIP_ASM void InitTn(TN *ptn) { - extern VECTOR D_00275A10; - extern char D_00275A20[8]; + VECTOR D_00275A10; + char D_00275A20[8]; uint64_t flags; InitAlo(ptn); @@ -109,11 +107,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", UpdateTnCallback__FP2TN5MSGIDPv); #ifdef SKIP_ASM void UpdateTnCallback(TN *ptn, MSGID msgid, void *pv) { - VECTOR posLocal; - TNS tns; - PO *ppo; - - ppo = PpoCur(); + PO *ppo = PpoCur(); if (ppo == NULL) return; @@ -123,7 +117,8 @@ void UpdateTnCallback(TN *ptn, MSGID msgid, void *pv) STRUCT_OFFSET(ptn, 0x2D0, PO *) = ppo; } - tns = STRUCT_OFFSET(ptn, 0x398, TNS); + VECTOR posLocal; + TNS tns = STRUCT_OFFSET(ptn, 0x398, TNS); if (tns == TNS_Nil) { ConvertAloPos(NULL, ptn, (VECTOR *)((char *)ppo + 0x140), &posLocal); diff --git a/src/P2/turret.c b/src/P2/turret.c index ef67e8cd..afd4ec16 100644 --- a/src/P2/turret.c +++ b/src/P2/turret.c @@ -78,8 +78,6 @@ void GetTurretDiapi(TURRET *pturret, DIALOG *pdialog, DIAPI *pdiapi) int FUN_001e5e60(int n) { - int v; - - v = STRUCT_OFFSET(n, 0x620, int); + int v = STRUCT_OFFSET(n, 0x620, int); return v != 0 ? v : n; } diff --git a/src/P2/ub.c b/src/P2/ub.c index 2cb390dc..f93f1b58 100644 --- a/src/P2/ub.c +++ b/src/P2/ub.c @@ -21,16 +21,14 @@ void PostUbgLoad(UBG *pubg) STRUCT_OFFSET(pubg, 0xC90, int) = 4; + int *pichk = &STRUCT_OFFSET(pubg, 0xC80, int); + int i = 0; + do { - int *pichk = &STRUCT_OFFSET(pubg, 0xC80, int); - int i = 0; - do - { - *pichk = IchkAllocChkmgr(&g_chkmgr); - i++; - pichk++; - } while ((uint)i < 4); - } + *pichk = IchkAllocChkmgr(&g_chkmgr); + i++; + pichk++; + } while ((uint)i < 4); PostGomerLoad(pubg); } diff --git a/src/P2/ui.c b/src/P2/ui.c index 7989e5a1..649e5047 100644 --- a/src/P2/ui.c +++ b/src/P2/ui.c @@ -2,8 +2,6 @@ #include #include #include -#include -#include void StartupUi() { diff --git a/src/P2/xform.c b/src/P2/xform.c index 2780a943..804c4d6d 100644 --- a/src/P2/xform.c +++ b/src/P2/xform.c @@ -69,6 +69,7 @@ void PostWarpLoad(WARP *pwarp) for (i = 0; i < STRUCT_OFFSET(pwarp, 0xa0, int); i++) { LO *plo = STRUCT_OFFSET(pwarp, 0xa4, LO **)[i]; + // @todo clean up this vtable call (*(void (**)(LO *, ALO *))((char *)plo->pvtlo + 0x64))(plo, pwarp->paloParent); SnipLo(plo); } From 4804054b33e3fc9000b6cd05b6d652ef8664a90f Mon Sep 17 00:00:00 2001 From: Johan Lindskogen Date: Fri, 3 Jul 2026 00:47:36 +0200 Subject: [PATCH 133/134] Restore matching status after review fixes Fix compile/link breakage from the review-comment pass, move remaining extern declarations into headers, and drop extern "C" via pre-mangled symbol names. Verified: out/SCUS_971.98 checksum OK. Co-Authored-By: Claude Fable 5 --- config/symbol_addrs.txt | 40 +++++++++++++++------------- include/cm.h | 8 +++--- include/font.h | 8 +++--- include/game.h | 2 +- include/glbs.h | 2 +- include/gs.h | 6 +++++ include/hide.h | 11 ++++++++ include/jt.h | 5 ++++ include/path.h | 7 ++++- include/rumble.h | 2 ++ include/sensor.h | 3 --- include/so.h | 4 +-- include/sound.h | 17 +++++++++++- include/splice/splotheap.h | 4 +-- include/sw.h | 6 +++++ include/vec.h | 10 +++++++ src/P2/act.c | 5 +--- src/P2/alo.c | 8 +++--- src/P2/chkpnt.c | 4 +-- src/P2/cm.c | 8 +++--- src/P2/dartgun.c | 16 ++++++----- src/P2/dialog.c | 2 -- src/P2/emitter.c | 2 +- src/P2/font.c | 4 +-- src/P2/freeze.c | 2 -- src/P2/game.c | 8 +++--- src/P2/glbs.c | 4 +-- src/P2/hide.c | 2 -- src/P2/jlo.c | 2 -- src/P2/jt.c | 11 +++++--- src/P2/light.c | 3 +-- src/P2/missile.c | 4 +-- src/P2/mpeg.c | 39 ++++++++++----------------- src/P2/puffer.c | 2 -- src/P2/pzo.c | 6 ++--- src/P2/rip.c | 10 ++++--- src/P2/rog.c | 2 -- src/P2/rumble.c | 2 -- src/P2/screen.c | 10 ++----- src/P2/sensor.c | 53 +++++++++++++++++++------------------ src/P2/shd.c | 7 ++--- src/P2/so.c | 10 +++---- src/P2/sound.c | 5 ++-- src/P2/splice/bif.cpp | 2 +- src/P2/splice/splotheap.cpp | 4 +-- src/P2/step.c | 1 - src/P2/stepcane.c | 4 ++- src/P2/stepguard.c | 2 +- src/P2/stephide.c | 7 +---- src/P2/steppipe.c | 3 --- src/P2/steprail.c | 3 ++- src/P2/sw.c | 9 +++++-- src/P2/tank.c | 3 ++- src/P2/tn.c | 4 +-- src/P2/ub.c | 7 +++-- src/P2/water.c | 8 +++--- 56 files changed, 222 insertions(+), 201 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 5bd8dcca..89b7680f 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -334,8 +334,8 @@ PvFromPsplot__FP5SPLOT = 0x11C3B8; // type:func PsplotFromPv__FPv = 0x11C3C0; // type:func FIsPvGarbage__FPv = 0x11C3C8; // type:func MarkPvAlive__FPv = 0x11C3F0; // type:func -FUN_0011C418 = 0x11C418; // type:func -FUN_0011C498 = 0x11C498; // type:func +FUN_0011C418__FPvT0P6CFrame = 0x11C418; // type:func +FUN_0011C498__Fv = 0x11C498; // type:func FUN_0011C4E8 = 0x11C4E8; // type:func g_splotheapPair = 0x25C250; // size:0x1C @@ -1392,7 +1392,7 @@ RemoveCmFadeObject = 0x143B20; // type:func FUN_00143BA8 = 0x143BA8; // type:func UpdateCmFade = 0x143BE0; // type:func UpdateCmLast = 0x143E40; // type:func -SetupCmRotateToCam = 0x144008; // type:func +SetupCmRotateToCam__FP2CM = 0x144008; // type:func ConvertCmScreenToWorld = 0x144128; // type:func ConvertCmWorldToScreen = 0x1441C0; // type:func SetupCm__FP2CM = 0x144270; // type:func @@ -1402,10 +1402,10 @@ UpdateCmMat4 = 0x144540; // type:func DrawCm__FP2CM = 0x144848; // type:func SetCmPosMat__FP2CMP6VECTORP7MATRIX3 = 0x1448C8; // type:func SetCmLookAt__FP2CMP6VECTORT1 = 0x144938; // type:func -ConvertWorldToCylindVelocity = 0x144978; // type:func -ConvertCylindToWorldVelocity = 0x144AA0; // type:func +ConvertWorldToCylindVelocity__FPvN50 = 0x144978; // type:func +ConvertCylindToWorldVelocity__FPvN20fff = 0x144AA0; // type:func ResetCmLookAtSmooth__FP2CMPv = 0x144B70; // type:func -SetCmLookAtSmooth = 0x144BE8; // type:func +SetCmLookAtSmooth__FP2CMiP6VECTORT2iffffff = 0x144BE8; // type:func AdjustCmJoy__FP2CMP3JOY5JOYIDPf = 0x144FF8; // type:func junk_00145080 = 0x145080; // type:func SetCmPolicy__FP2CM3CPPP5CPLCYP2SOPv = 0x145088; // type:func @@ -1983,8 +1983,8 @@ FCheckFlyOpenSpaceBelow__FP3FLY = 0x15C0A0; // type:func // P2/font.c //////////////////////////////////////////////////////////////// StartupFont__Fv = 0x15C178; // type:func -FUN_0015c188 = 0x15C188; // type:func -FUN_0015c1c0 = 0x15C1C0; // type:func +FUN_0015c188__Fi = 0x15C188; // type:func +FUN_0015c1c0__Fi = 0x15C1C0; // type:func FUN_0015c200 = 0x15C200; // type:func CopyTo__5CFontP5CFont = 0x15C260; // type:func SetupDraw__5CFontP8CTextBoxP4GIFS = 0x15C2E8; // type:func @@ -2093,7 +2093,7 @@ search_level_by_load_data = 0x1600A0; // type:func search_level_by_id = 0x160110; // type:func PchzFriendlyFromWid__Fi = 0x160148; // type:func junk_00160178 = 0x160178; // type:func -call_search_level_by_id = 0x160180; // type:func +call_search_level_by_id__Fi = 0x160180; // type:func FFindLevel = 0x1601A0; // type:func junk_001601D0 = 0x1601D0; // type:func get_level_completion_by_id = 0x1601D8; // type:func @@ -2111,7 +2111,7 @@ FUN_00160650 = 0x160650; // type:func SetupGame__FPci = 0x160690; // type:func UpdateGameState__Ff = 0x1607D0; // type:func -LsFromWid = 0x160810; // type:func +LsFromWid__F3WID = 0x160810; // type:func GrflsFromWid__F3WID = 0x160850; // type:func UnloadGame__Fv = 0x160880; // type:func @@ -2199,7 +2199,7 @@ DrawThreeWay__4GLBS = 0x161F70; // type:func EndStrip__4GLBS = 0x162508; // type:func SetNormal__4GLBSP6VECTOR = 0x162680; // type:func junk_001626A0 = 0x1626A0; // type:func -SetRgba__4GLBSG4RGBA = 0x1626A8; // type:func +SetRgba__4GLBSP4RGBA = 0x1626A8; // type:func SetUv__4GLBSP3UVF = 0x1626C0; // type:func AddVtx__4GLBSi = 0x1626D8; // type:func @@ -3493,6 +3493,8 @@ UpdateRop__FP3ROPf = 0x1A7800; // type:func SetRopRops__FP3ROP4ROPS = 0x1A7998; // type:func RopsNextRop__FP3ROP = 0x1A7AA0; // type:func +s_asnip = 0x26A918; +s_asnipLoadUbg = 0x275B60; s_asnipLoadRov = 0x26B778; @@ -3518,10 +3520,10 @@ DAT_0026c3dc = 0x26C3DC; //////////////////////////////////////////////////////////////// InitRwm__FP3RWM = 0x1A7FE8; // type:func OnRwmRemove__FP3RWM = 0x1A80E0; // type:func -FUN_001a8110 = 0x1A8110; // type:func +FUN_001a8110__FP3RWM = 0x1A8110; // type:func FUN_001a8150 = 0x1A8150; // type:func InitRwmCallback__FP3RWM5MSGIDPv = 0x1A8208; // type:func -FUN_001a84c8 = 0x1A84C8; // type:func +FUN_001a84c8__FP3RWMT0 = 0x1A84C8; // type:func PostRwmLoad__FP3RWM = 0x1A8590; // type:func FUN_001a86f8__FP3RWMi = 0x1A86F8; // type:func PrwcFindRwm__FP3RWM3OID = 0x1A8718; // type:func @@ -3949,7 +3951,7 @@ RenderSoSelf__FP2SOP2CMP2RO = 0x1B93D8; // type:func UpdateSo__FP2SOf = 0x1B93F8; // type:func SetSoMass__FP2SOf = 0x1B9418; // type:func AdjustSoMomint__FP2SOf = 0x1B9448; // type:func -DiscardSoXps__FP2SO = 0x1B94F0; // type:func +DiscardSoXps__FP2SOi = 0x1B94F0; // type:func UpdateSoPosWorldPrev__FP2SO = 0x1B9680; // type:func TranslateSoToPos__FP2SOP6VECTOR = 0x1B9690; // type:func RotateSoToMat__FP2SOP7MATRIX3 = 0x1B97E0; // type:func @@ -4009,7 +4011,7 @@ ApplySoImpulse__FP2SOP6VECTORT1f = 0x1BC0E0; // type:func CalculateSoTrajectoryApex__FP2SOP6VECTORfT1 = 0x1BC260; // type:func FAbsorbSoWkr__FP2SOP3WKR = 0x1BC320; // type:func CloneSoPhys__FP2SOT0i = 0x1BC368; // type:func -FUN_001bc4d8 = 0x1BC4D8; // type:func +FUN_001bc4d8__FPUcT0 = 0x1BC4D8; // type:func FUN_001bc670 = 0x1BC670; // type:func FUN_001bc710__FP2SOi = 0x1BC710; // type:func FUN_001bc748__FP2SOPi = 0x1BC748; // type:func @@ -4119,7 +4121,7 @@ FUN_001C0A50 = 0x1C0A50; // type:func FUN_001C0AB8__FP2SWPf = 0x1C0AB8; // type:func FUN_001C0B08__FP2SWP2LM = 0x1C0B08; // type:func StartSwIntermittentSounds__FP2SW = 0x1C0B38; // type:func -SetAMRegister__FiUc = 0x1C0C08; // type:func +SetAMRegister__Fii = 0x1C0C08; // type:func GetAMRegister__Fi = 0x1C0C50; // type:func UpdateAMRegister__Fii = 0x1C0C68; // type:func FUN_001c0cb0__Fv = 0x1C0CB0; // type:func @@ -4314,7 +4316,7 @@ PsoEnemyStepguard__FP9STEPGUARD = 0x1CAA08; // type:func FUN_001caad0__FP2SOPP2SO = 0x1CAAD0; // type:func SetStepguardEnemyObject__FP9STEPGUARDP2SO = 0x1CAB00; // type:func RebindStepguardEnemy__FP9STEPGUARD = 0x1CAB10; // type:func -FUN_001cac28__FP9STEPGUARD = 0x1CAC28; // type:func +FUN_001cac28__FP9STEPGUARDi = 0x1CAC28; // type:func FUN_001cac30 = 0x1CAC30; // type:func AdjustStepguardDz__FP9STEPGUARDiP2DZif = 0x1CACB0; // type:func SetStepguardAttackAngleMax__FP9STEPGUARDf = 0x1CAD28; // type:func @@ -4427,10 +4429,10 @@ s_mpfspgrfvault = 0x274F38; // size:0x1c // TODO: Mangle the function names. //////////////////////////////////////////////////////////////// func_001D31D0__FP2LOi = 0x1D31D0; // type:func -post_load_steprail = 0x1D3290; // type:func +post_load_steprail__FP3ALO = 0x1D3290; // type:func func_001D32D8__FiP2JTl = 0x1D32D8; // type:func update_steprail = 0x1D3398; // type:func -preset_steprail_accel = 0x1D3470; // type:func +preset_steprail_accel__FP2SOf = 0x1D3470; // type:func FUN_001d34e0__FPUc = 0x1D34E0; // type:func FUN_001d3500__FP2SOP3WKR = 0x1D3500; // type:func FUN_001d35a8 = 0x1D35A8; // type:func diff --git a/include/cm.h b/include/cm.h index c20fbb1a..80d23598 100644 --- a/include/cm.h +++ b/include/cm.h @@ -555,9 +555,9 @@ extern int g_rgbaFog; //Just to get the code matching -Kestin void ResetCmLookAtSmooth(CM *pcm, void *pv); -extern "C" void SetupCmRotateToCam(CM *pcm); -extern "C" void SetCmLookAtSmooth(CM *pcm, int a1, VECTOR *pposEye, VECTOR *pposCenter, int a4, float u0, float u1, float u2, float u3, float u4, float u5); -extern "C" void ConvertCylindToWorldVelocity(void *a, void *b, void *c, float f0, float f1, float f2); -extern "C" void ConvertWorldToCylindVelocity(void *a, void *b, void *c, void *d, void *e, void *f); +void SetupCmRotateToCam(CM *pcm); +void SetCmLookAtSmooth(CM *pcm, int a1, VECTOR *pposEye, VECTOR *pposCenter, int a4, float u0, float u1, float u2, float u3, float u4, float u5); +void ConvertCylindToWorldVelocity(void *a, void *b, void *c, float f0, float f1, float f2); +void ConvertWorldToCylindVelocity(void *a, void *b, void *c, void *d, void *e, void *f); #endif // CM_H diff --git a/include/font.h b/include/font.h index 70cf41b9..c3fcc9aa 100644 --- a/include/font.h +++ b/include/font.h @@ -124,11 +124,9 @@ extern CFont *g_pfont; void StartupFont(); -extern "C" -{ - CFont *FUN_0015c1c0(int i); - int FUN_0015c188(int i); -} +CFont *FUN_0015c1c0(int i); + +int FUN_0015c188(int i); void PostFontsLoad(); diff --git a/include/game.h b/include/game.h index 8486c4bc..579b7e97 100644 --- a/include/game.h +++ b/include/game.h @@ -401,7 +401,7 @@ bool FCharmAvailable(); * @param pls Pointer to level state. * @param param_2 OID of the dialog. */ -//int PfLookupDialog(LS *pls, OID oidDialog); +int *PfLookupDialog(LS *pls, OID oidDialog); /** * @brief Clears 8 bytes of memory. diff --git a/include/glbs.h b/include/glbs.h index dc7fd5c8..0d9cb568 100644 --- a/include/glbs.h +++ b/include/glbs.h @@ -93,7 +93,7 @@ struct GLBS void SetNormal(VECTOR *ppos); // Might be SetPos? - void SetRgba(RGBA &rgba); // Might not be correct. + void SetRgba(RGBA *prgba); void SetUv(UVF *puv); diff --git a/include/gs.h b/include/gs.h index dd3f975a..908f48dd 100644 --- a/include/gs.h +++ b/include/gs.h @@ -55,4 +55,10 @@ void ClearFrameBuffers(); void UploadBitmaps(GRFZON grfzon, GSB *pgsb); +struct GIFS; + +int FBuildUploadBitmapGifs(GRFZON grfzon, GSB *pgsb, GIFS *pgifs); + +void PropagateSurs(); + #endif // GS_H diff --git a/include/hide.h b/include/hide.h index 9f32c925..3b33b77a 100644 --- a/include/hide.h +++ b/include/hide.h @@ -6,8 +6,19 @@ #include "common.h" +/** + * @todo Implement the HPNT and HSHAPE structs. + */ +struct HPNT; +struct HSHAPE; +struct VECTOR; + // ... void StartupHide(); +void GetHshapeHidePos(HSHAPE *phshape, float s, VECTOR *ppos, float *pf); + +void GetHpntClosestHidePos(HPNT *phpnt, VECTOR *ppos, float *pf); + #endif // HIDE_H diff --git a/include/jt.h b/include/jt.h index 034d32a3..5f644a51 100644 --- a/include/jt.h +++ b/include/jt.h @@ -177,6 +177,11 @@ void SetJtJts(JT *pjt, JTS jts, JTBS jtbs); */ void ProfileJt(JT *pjt, int fProfile); +struct XMG; +struct ACTADJ; + +int FMatchJtXmg(JT *pjt, XMG *pxmg, ACTADJ *pactadj); + extern JT *g_pjt; #endif // JT_H diff --git a/include/path.h b/include/path.h index e3366aa0..f19dba35 100644 --- a/include/path.h +++ b/include/path.h @@ -6,6 +6,11 @@ #include "common.h" -// ... +struct CG; +struct VECTOR; + +int CposFindPath(CG *pcg, VECTOR *pvec0, VECTOR *pvec1, int n, VECTOR *pvec2); + +void FindClosestPointInCg(CG *pcg, VECTOR *pvec0, VECTOR *pvec1); #endif // PATH_H diff --git a/include/rumble.h b/include/rumble.h index f9a8bffa..4906fa5e 100644 --- a/include/rumble.h +++ b/include/rumble.h @@ -88,6 +88,8 @@ void TriggerRumbleRumk(RUMBLE *prumble, RUMK rumk, float dt); void SetRumbleRums(RUMBLE *prumble, RUMS rums); +void TriggerRumbleRumpat(RUMBLE *prumble, RUMPAT *prumpat, float dt); + void StopRumbleActuators(RUMBLE *prumble); #endif // RUMBLE_H diff --git a/include/sensor.h b/include/sensor.h index 72113037..953be25c 100644 --- a/include/sensor.h +++ b/include/sensor.h @@ -65,13 +65,10 @@ struct SENSOR : public SO STRUCT_PADDING(2); /* 0x564 */ uint ctriggerObjects; // Current count of trigger object IDs. /* 0x568 */ OID atriggerObjects[4]; // Array of trigger object IDs. - STRUCT_PADDING(4); /* 0x578 */ uint cnoTriggerObjects; // Current count of no-trigger object IDs. /* 0x57C */ OID anoTriggerObjects[4]; // Array of no-trigger object IDs. - STRUCT_PADDING(4); /* 0x58c */ uint ctriggerClasses; // Current count of trigger class IDs. /* 0x590 */ CID atriggerClasses[4]; // Array of trigger class IDs. - STRUCT_PADDING(4); /* 0x5a0 */ uint cnoTriggerClasses; // Current count of no-trigger class IDs. /* 0x5a4 */ CID anoTriggerClasses[4]; // Array of no-trigger class IDs. }; diff --git a/include/so.h b/include/so.h index 0e34271e..9df8b7d4 100644 --- a/include/so.h +++ b/include/so.h @@ -166,7 +166,7 @@ void SetSoMass(SO *pso, float m); void AdjustSoMomint(SO *pso, float r); -extern "C" void DiscardSoXps__FP2SO(SO *pso, int mode); +void DiscardSoXps(SO *pso, int mode); void UpdateSoPosWorldPrev(SO *pso); @@ -290,6 +290,6 @@ int FAbsorbSoWkr(SO *pso, WKR *pwkr); void CloneSoPhys(SO *pso, SO *psoPhys, int cposExtra); -extern "C" void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); +void FUN_001bc4d8(uint8_t *param_1, uint8_t *param_2); #endif // SO_H diff --git a/include/sound.h b/include/sound.h index bb681abd..30a47ad3 100644 --- a/include/sound.h +++ b/include/sound.h @@ -209,11 +209,26 @@ int FVagPlaying(); */ int SetVagUnpaused(); +/** + * @brief Stop the currently playing VAG. + */ +void StopVag(); + /** * @brief Unknown. */ void UnsetExcitement(EXC *pexc); +/** + * @brief Unknown. + */ +void UnsetExcitementHyst(EXC *pexc); + +/** + * @brief Unknown. + */ +EXC *PexcSetExcitement(int gexc); + /** * @brief Unknown. */ @@ -259,7 +274,7 @@ void StopSound(AMB *pamb, int msRampdown); // The symbol's GCC2 mangling says (int, unsigned char), but the ROM call // sites pass the second argument as a plain word with no narrowing, so the // in-game declaration must have taken ints; bind by literal symbol name. -extern "C" void SetAMRegister__FiUc(int n, int bReg); +void SetAMRegister(int n, int bReg); /** * @brief TODO diff --git a/include/splice/splotheap.h b/include/splice/splotheap.h index bc57c8b1..92f7314f 100644 --- a/include/splice/splotheap.h +++ b/include/splice/splotheap.h @@ -46,8 +46,8 @@ extern CSplotheap g_splotheapMethod; // Sidebag binding-node helpers: allocate a node {int n; CRef ref; pNext} // from g_splotheapUnk1, and recursively clone a node list. class CFrame; -extern "C" void *FUN_0011C498(); -extern "C" void FUN_0011C418(void *psbbFrom, void *psbbTo, CFrame *pframe); +void *FUN_0011C498(); +void FUN_0011C418(void *psbbFrom, void *psbbTo, CFrame *pframe); static void *PvFromPsplot(SPLOT *psplot); static SPLOT *PsplotFromPv(void *pv); diff --git a/include/sw.h b/include/sw.h index 20f1900d..f97510f6 100644 --- a/include/sw.h +++ b/include/sw.h @@ -111,6 +111,12 @@ extern SW *g_psw; void InitSwDlHash(SW *psw); +void FUN_001ddb58(SW *psw); + +void FUN_001ddbb8(SW *psw); + +void FUN_001ddc38(void *pv, void *pvBlot); + void InitSw(SW *psw); void DeleteSw(SW *psw); diff --git a/include/vec.h b/include/vec.h index 6d8ca2de..7d00aa9a 100644 --- a/include/vec.h +++ b/include/vec.h @@ -39,6 +39,16 @@ struct VU_VECTOR VU_VECTOR(const VECTOR &vec); }; +/** + * @brief Unit Z-axis normal (0, 0, 1). + */ +extern VECTOR g_normalZ; + +/** + * @brief Zero vector constant (16 zero bytes; also read as a VU_VECTOR qword). + */ +extern VECTOR D_00248D30; + /** * @brief Sets the coordinates of a vector using cylindrical coordinates. * diff --git a/src/P2/act.c b/src/P2/act.c index 5336431b..7a4893cb 100644 --- a/src/P2/act.c +++ b/src/P2/act.c @@ -47,7 +47,6 @@ void RetractAct(ACT *pact, GRFRA grfra) ALO *palo = pact->palo; ACT *pactPos; ACT *pactRot; - extern VECTOR D_00248D30; RemoveDlEntry((DL *)((uint8_t *)palo + 0x1E0), pact); @@ -225,8 +224,6 @@ float GGetActvalPoseGoal(ACTVAL *pactval, int ipose) return pactval->agPoses[ipose]; } -extern VECTOR D_00248D30; - void InitActref(ACTREF *pactref, ALO *palo) { InitAct(pactref, palo); @@ -237,7 +234,7 @@ void InitActref(ACTREF *pactref, ALO *palo) STRUCT_OFFSET(pactref, 0x28, VECTOR *) = &D_00248D30; STRUCT_OFFSET(pactref, 0x3c, float *) = STRUCT_OFFSET(palo, 0x274, float *); uint8_t *psen = STRUCT_OFFSET(palo, 0x224, uint8_t *); - if (psen != nullptr && (STRUCT_OFFSET(psen, 0xb0, int) & 0x20)) + if (psen != NULL && (STRUCT_OFFSET(psen, 0xb0, int) & 0x20)) { STRUCT_OFFSET(pactref, 0x30, VECTOR *) = &D_00248D30; STRUCT_OFFSET(pactref, 0x2c, uint8_t *) = psen + 0x8c; diff --git a/src/P2/alo.c b/src/P2/alo.c index 8fba73c3..d191a0e1 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -68,7 +68,7 @@ void UpdateAloXfWorld(ALO *palo) { void (*pfn)(ALO *) = (void (*)(ALO *))palo->pvtlo->pfnUpdateLoXfWorldHierarchy; - if (pfn != nullptr) + if (pfn != NULL) { pfn(palo); } @@ -853,7 +853,6 @@ void FUN_0012a848(ALO *palo, int *pn) void FUN_0012a860(ALO *palo, ALO *paloTarget) { - VECTOR D_00248D30; SetActlaTarget(STRUCT_OFFSET(palo, 0x200, ACTLA *), paloTarget, &D_00248D30); } @@ -1127,13 +1126,12 @@ void SetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) STRUCT_OFFSET(STRUCT_OFFSET(palo, 0x288, THROB *), 0x10, VU_VECTOR) = *(VU_VECTOR *)phsvInColor; } -extern VU_VECTOR D_00248D30; void GetAloThrobInColor(ALO *palo, VECTOR *phsvInColor) { THROB *pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); // palo->pthrob VU_VECTOR *pqSrc = pthrob ? &STRUCT_OFFSET(pthrob, 0x10, VU_VECTOR) // pthrob->hsvInColor - : &D_00248D30; + : (VU_VECTOR *)&D_00248D30; *(VU_VECTOR *)phsvInColor = *pqSrc; } @@ -1148,7 +1146,7 @@ void SetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) void GetAloThrobOutColor(ALO *palo, VECTOR *phsvOutColor) { THROB *pthrob = STRUCT_OFFSET(palo, 0x288, THROB *); // palo->throb - VU_VECTOR *pvuvec = pthrob ? &STRUCT_OFFSET(pthrob, 0x20, VU_VECTOR) : &D_00248D30; + VU_VECTOR *pvuvec = pthrob ? &STRUCT_OFFSET(pthrob, 0x20, VU_VECTOR) : (VU_VECTOR *)&D_00248D30; *(VU_VECTOR *)phsvOutColor = *pvuvec; } diff --git a/src/P2/chkpnt.c b/src/P2/chkpnt.c index 95284c4a..e3b926d9 100644 --- a/src/P2/chkpnt.c +++ b/src/P2/chkpnt.c @@ -64,8 +64,8 @@ void ReturnChkmgrToCheckpoint(CHKMGR *pchkmgr) } else { - trans.oidWarp = OID_NIL; - trans.oidWarpContet = OID_NIL; + trans.oidWarp = OID_Nil; + trans.oidWarpContet = OID_Nil; trans.grftrans = 0x10; } ActivateWipe(&g_wipe, &trans, (WIPEK)1); diff --git a/src/P2/cm.c b/src/P2/cm.c index 3773165a..557adac8 100644 --- a/src/P2/cm.c +++ b/src/P2/cm.c @@ -202,7 +202,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/cm", UpdateCmFade); INCLUDE_ASM("asm/nonmatchings/P2/cm", UpdateCmLast); -INCLUDE_ASM("asm/nonmatchings/P2/cm", SetupCmRotateToCam); +INCLUDE_ASM("asm/nonmatchings/P2/cm", SetupCmRotateToCam__FP2CM); INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCmScreenToWorld); @@ -246,9 +246,9 @@ void SetCmLookAt(CM *pcm, VECTOR *pposEye, VECTOR *pposCenter) SetCmLookAtSmooth(pcm, 0, pposEye, pposCenter, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); } -INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertWorldToCylindVelocity); +INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertWorldToCylindVelocity__FPvN50); -INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCylindToWorldVelocity); +INCLUDE_ASM("asm/nonmatchings/P2/cm", ConvertCylindToWorldVelocity__FPvN20fff); void ResetCmLookAtSmooth(CM *pcm, void *pv) { @@ -261,7 +261,7 @@ void ResetCmLookAtSmooth(CM *pcm, void *pv) STRUCT_OFFSET(pcm, 0x2d0, qword) = *(qword *)pv; } -INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmLookAtSmooth); +INCLUDE_ASM("asm/nonmatchings/P2/cm", SetCmLookAtSmooth__FP2CMiP6VECTORT2iffffff); void AdjustCmJoy(CM *pcm, JOY *pjoy, JOYID joyid, float *prad) { diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index b11b93b5..6a11d28a 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -67,7 +67,8 @@ int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) { if (FIsBasicDerivedFrom(psoOther, CID_RAT)) { - return 1; + if (STRUCT_OFFSET(psoOther, 0x588, SO *) == (SO *)pdartgun) + return 1; } return FIgnoreSoIntersection((SO *)pdartgun, psoOther); @@ -119,11 +120,14 @@ void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x4C, int) = 0; } - if (oidStateGoal < (OID)0x2BA && oidStateGoal >= (OID)0x2B8) + if (oidStateGoal < (OID)0x2BA) { - STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = (oidStateGoal == (OID)0x2B9); - if ((unsigned int)(oidCur - 0x2BA) >= 2) - STRUCT_OFFSET(pdartgun, 0x6D8, int) = 0; + if (oidStateGoal >= (OID)0x2B8) + { + STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = (oidStateGoal == (OID)0x2B9); + if ((unsigned int)(oidCur - 0x2BA) >= 2) + STRUCT_OFFSET(pdartgun, 0x6D8, int) = 0; + } } SetSmaGoal(STRUCT_OFFSET(pdartgun, 0x740, SMA *), oidStateGoal); @@ -131,8 +135,6 @@ void SetDartgunGoalState(DARTGUN *pdartgun, OID oidStateGoal) void TrackDartgun(DARTGUN *pdartgun, OID *poidStateGoal) { - VECTOR D_00248D30; - if (*poidStateGoal == (OID)0x2B8) { STRUCT_OFFSET(STRUCT_OFFSET(STRUCT_OFFSET(pdartgun, 0x734, char *), 0x200, char *), 0x1C, int) = 0; diff --git a/src/P2/dialog.c b/src/P2/dialog.c index 568d242e..68423161 100644 --- a/src/P2/dialog.c +++ b/src/P2/dialog.c @@ -26,8 +26,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/dialog", LoadDialogEventsFromBrx__FP6DIALOGP18C void PostDialogLoad(DIALOG *pdialog) { - extern int *PfLookupDialog(LS *pls, OID oid); - PostAloLoad(pdialog); if (STRUCT_OFFSET(pdialog, 0x30c, OID) == OID_Nil) diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 9df51302..0c02f869 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -370,13 +370,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadExplgFromBrx__FP5EXPLGP18CBinaryI void CloneExplg(EXPLG *pexplg, EXPLG *pexplgBase) { + int i = 0; CloneLo((LO *)pexplg, (LO *)pexplgBase); if (STRUCT_OFFSET(pexplg, 0x90, int) > 0) { LO **p = &STRUCT_OFFSET(pexplg, 0x94, LO *); - int i = 0; do { LO *plo = PloCloneLo(*p, STRUCT_OFFSET(pexplg, 0x14, SW *), STRUCT_OFFSET(pexplg, 0x18, ALO *)); diff --git a/src/P2/font.c b/src/P2/font.c index f088ac34..25f2874a 100644 --- a/src/P2/font.c +++ b/src/P2/font.c @@ -10,9 +10,9 @@ void StartupFont() g_pfont = NULL; } -INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c188); +INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c188__Fi); -INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c1c0); +INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c1c0__Fi); INCLUDE_ASM("asm/nonmatchings/P2/font", FUN_0015c200); diff --git a/src/P2/freeze.c b/src/P2/freeze.c index 3f3960b4..93a0c86d 100644 --- a/src/P2/freeze.c +++ b/src/P2/freeze.c @@ -73,8 +73,6 @@ void GetAloFrozen(ALO *palo, int *pf) void FreezeAlo(ALO *palo, int fFreeze) { - VECTOR D_00248D30; - if (fFreeze) { SFX *psfx; diff --git a/src/P2/game.c b/src/P2/game.c index a1e3e49d..a44988c9 100644 --- a/src/P2/game.c +++ b/src/P2/game.c @@ -148,7 +148,7 @@ void UpdateGameState(float dt) g_plsCur->dt += dt; } -INCLUDE_ASM("asm/nonmatchings/P2/game", LsFromWid); +INCLUDE_ASM("asm/nonmatchings/P2/game", LsFromWid__F3WID); INCLUDE_ASM("asm/nonmatchings/P2/game", GrflsFromWid__F3WID); @@ -311,14 +311,14 @@ bool FCharmAvailable() INCLUDE_ASM("asm/nonmatchings/P2/game", FUN_00160C90); -int PfLookupDialog(LS *pls, OID oidDialog) +int *PfLookupDialog(LS *pls, OID oidDialog) { // todo figure out what these magic numbers represent if (oidDialog - 0x33bU >= 0xc) { - return 0; + return NULL; } - return -0xcd8 + (int)pls + (oidDialog * 4); + return (int *)(-0xcd8 + (int)pls + (oidDialog * 4)); } // TODO: Come up with a name and mangle it. diff --git a/src/P2/glbs.c b/src/P2/glbs.c index 4ee33e9d..490a07f1 100644 --- a/src/P2/glbs.c +++ b/src/P2/glbs.c @@ -55,10 +55,10 @@ void GLBS::SetNormal(VECTOR *ppos) JUNK_NOP(); JUNK_WORD(0xE4800110); -extern "C" void SetRgba__4GLBSG4RGBA(GLBS *pglbs, RGBA *prgba) +void GLBS::SetRgba(RGBA *prgba) { struct PACK { int v; } __attribute__((packed)); - *(PACK *)((char *)pglbs + 0x114) = *(PACK *)prgba; + *(PACK *)((char *)this + 0x114) = *(PACK *)prgba; } void GLBS::SetUv(UVF *puv) diff --git a/src/P2/hide.c b/src/P2/hide.c index 93af4b24..19776896 100644 --- a/src/P2/hide.c +++ b/src/P2/hide.c @@ -99,8 +99,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/hide", CloneHbsk__FP4HBSKT0); INCLUDE_ASM("asm/nonmatchings/P2/hide", FIgnoreHbskIntersection__FP4HBSKP2SO); -extern VECTOR D_00248D30; - void PresetHbskAccel(HBSK *phbsk, float dt) { MATRIX3 matUpright; diff --git a/src/P2/jlo.c b/src/P2/jlo.c index 043dbe2a..fb7207cb 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -7,7 +7,6 @@ #include extern JLO *g_pjloCur; -extern VECTOR g_normalZ; // TODO: This should be elsewhere. void InitJlo(JLO *pjlo) { @@ -99,7 +98,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/jlo", FireJlo__FP3JLO); void LandJlo(JLO *pjlo) { - extern VECTOR D_00248D30; VECTOR pos; SetSoConstraints(pjlo, CT_Locked, NULL, CT_Locked, NULL); diff --git a/src/P2/jt.c b/src/P2/jt.c index e77a7c1b..d5a51e60 100644 --- a/src/P2/jt.c +++ b/src/P2/jt.c @@ -45,10 +45,10 @@ void HandleJtGrfjtsc(JT *pjt) INCLUDE_ASM("asm/nonmatchings/P2/jt", UpdateJtInternalXps__FP2JT); +extern float D_00274AD0[]; + int FCheckJtXpBase(JT *pjt, XP *pxp, int ixpd) { - float D_00274AD0[]; - if (pjt->jts != JTS_Max) { return FCheckStepXpBase(pjt, pxp, ixpd); @@ -213,8 +213,11 @@ SO *PsoGetJtEffect(JT *pjt, int *pn) INCLUDE_ASM("asm/nonmatchings/P2/jt", AddJtCustomXps__FP2JTP2SOiP3BSPT3PP2XP); -int CtTorqueJt(JT *pjt) { - return pjt->jts == JTS_Zap || pjt->jts == JTS_Max ? 0 : 3; +int CtTorqueJt(JT *pjt) +{ + if (pjt->jts == JTS_Zap || pjt->jts == JTS_Max) + return 0; + return 3; } INCLUDE_ASM("asm/nonmatchings/P2/jt", FUN_00172ee0); diff --git a/src/P2/light.c b/src/P2/light.c index 51895b30..658c5975 100644 --- a/src/P2/light.c +++ b/src/P2/light.c @@ -4,7 +4,6 @@ #include #include -extern VU_VECTOR g_normalZ; extern VU_VECTOR g_normalY; INCLUDE_ASM("asm/nonmatchings/P2/light", InitLight__FP5LIGHT); @@ -15,7 +14,7 @@ void InitLight(LIGHT *plight) STRUCT_OFFSET(plight, 0x2d0, int) = 0; STRUCT_OFFSET(plight, 0x2c8, uint64_t) = (grfalo & ~0x30000000000ULL) | (0x8000ULL << 0x19); - STRUCT_OFFSET(plight, 0x320, VU_VECTOR) = g_normalZ; + STRUCT_OFFSET(plight, 0x320, VU_VECTOR) = *(VU_VECTOR *)&g_normalZ; STRUCT_OFFSET(plight, 0x340, VU_VECTOR) = g_normalY; STRUCT_OFFSET(plight, 0x330, float) = 200.0f; diff --git a/src/P2/missile.c b/src/P2/missile.c index 8a99038b..1e282c96 100644 --- a/src/P2/missile.c +++ b/src/P2/missile.c @@ -93,12 +93,10 @@ void FUN_0018dd78(void * p, int val) } } -extern qword D_00248D30; - void InitAccmiss(ACCMISS *paccmiss) { InitMissile(paccmiss); - *(qword *)((char *)paccmiss + 0x350) = D_00248D30; + *(qword *)((char *)paccmiss + 0x350) = *(qword *)&D_00248D30; } INCLUDE_ASM("asm/nonmatchings/P2/missile", FireAccmiss__FP7ACCMISSP3ALOP6VECTOR); diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index cc9939df..b29f7423 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -92,6 +92,7 @@ class CQueueOutputIop void Init(int nParam1, int nParam2); void Reset(); void Update(); + int FAsyncDrain(); }; #endif // CQUEUEOUTPUTIOP_DEFINED @@ -102,25 +103,6 @@ void CQueueOutputIop::Init(int nParam1, int nParam2) Reset(); } -#ifndef CQUEUEOUTPUTIOP_DEFINED -#define CQUEUEOUTPUTIOP_DEFINED -class CQueueOutputIop -{ -public: - int unk_0x0; - int unk_0x4; - int unk_0x8; - int unk_0xc; - int unk_0x10; - int unk_0x14; - int unk_0x18; - int unk_0x1c; - - void Init(int nParam1, int nParam2); - void Reset(); -}; -#endif // CQUEUEOUTPUTIOP_DEFINED - void CQueueOutputIop::Reset() { unk_0x14 = unk_0x8; @@ -136,14 +118,20 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbSend__15CQueueOutputIopiPv); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Update__15CQueueOutputIop); -int FAsyncDrain__15CQueueOutputIop() +int CQueueOutputIop::FAsyncDrain() { return 0; } +class CQueueOutputIpu +{ +public: + int FAsyncDrain(); +}; + INCLUDE_ASM("asm/nonmatchings/P2/mpeg", CbWrite__15CQueueOutputIpuiPv); -int FAsyncDrain__15CQueueOutputIpu() +int CQueueOutputIpu::FAsyncDrain() { return 1; } @@ -165,6 +153,7 @@ class CMpegAudio void Reset(); void Update(); + void Close(); }; #endif // CMPEGAUDIO_DEFINED @@ -184,12 +173,12 @@ struct SW; extern SW *g_psw; void PopSwReverb(SW *psw); -extern "C" void Close__10CMpegAudio(void *pthis) +void CMpegAudio::Close() { - STRUCT_OFFSET(pthis, 0x0, int) = 0; + unk_0x0 = 0; snd_CloseMovieSound(); - snd_SetMasterVolume(2, STRUCT_OFFSET(pthis, 0x8C, int)); - snd_SetMasterVolume(8, STRUCT_OFFSET(pthis, 0x90, int)); + snd_SetMasterVolume(2, STRUCT_OFFSET(this, 0x8C, int)); + snd_SetMasterVolume(8, STRUCT_OFFSET(this, 0x90, int)); PopSwReverb(g_psw); snd_ContinueAllSoundsInGroup(0xFFFFFFFF); } diff --git a/src/P2/puffer.c b/src/P2/puffer.c index 698b9ee8..69f5b9dc 100644 --- a/src/P2/puffer.c +++ b/src/P2/puffer.c @@ -105,8 +105,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/puffer", FUN_001982a0); INCLUDE_ASM("asm/nonmatchings/P2/puffer", UpdatePuffcGoal__FP5PUFFCi); -void FUN_00197a08(void *pv1, void *pv2); - void OnPuffcExitingSgs(PUFFC *ppuffc, SGS sgsNext) { if (STRUCT_OFFSET(ppuffc, 0x724, int) == SGS_Stun) diff --git a/src/P2/pzo.c b/src/P2/pzo.c index a0d40450..ca8a0e68 100644 --- a/src/P2/pzo.c +++ b/src/P2/pzo.c @@ -59,9 +59,6 @@ void CloneScprize(SCPRIZE *pscprize, SCPRIZE *pscprizeBase) PCS PcsFromScprize(SCPRIZE *pscprize) { - int FGetChkmgrIchk(CHKMGR *pchkmgr, int ichk); - CHKMGR g_chkmgr; - PCS pcs = PcsFromSprize((SPRIZE *)pscprize); if (pcs == PCS_Collectible) { @@ -227,9 +224,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/pzo", UpdateClue); INCLUDE_ASM("asm/nonmatchings/P2/pzo", OnClueSmack__FP4CLUE); +extern char D_0026A970; + void CollectClue(CLUE *pclue) { - char D_0026A970; RIP *pripg; VECTOR vec; diff --git a/src/P2/rip.c b/src/P2/rip.c index c12fe637..c6c883e7 100644 --- a/src/P2/rip.c +++ b/src/P2/rip.c @@ -130,7 +130,8 @@ void RenderRip(RIP *prip, CM *pcm) MATRIX3 *pmat; WR *pwr; - if (STRUCT_OFFSET(prip, 0x114, WR *) != NULL) + pwr = STRUCT_OFFSET(prip, 0x114, WR *); + if (pwr != NULL) { WarpWrTransform(pwr, 50.0f, &STRUCT_OFFSET(prip, 0x80, VECTOR), @@ -307,8 +308,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/rip", RenderRose__FP4ROSEP2CM); INCLUDE_ASM("asm/nonmatchings/P2/rip", SetRoseRoses__FP4ROSE5ROSES); -int SgnCmpHp(const void *pv0, const void *pv1) { - return STRUCT_OFFSET(pv0, 0x20, float) < STRUCT_OFFSET(pv1, 0x20, float) ? -1 : 1; +int SgnCmpHp(const void *pv0, const void *pv1) +{ + if (STRUCT_OFFSET(pv0, 0x20, float) < STRUCT_OFFSET(pv1, 0x20, float)) + return -1; + return 1; } INCLUDE_ASM("asm/nonmatchings/P2/rip", ChpBuildConvexHullScreen__FP6VECTORiP2HP); diff --git a/src/P2/rog.c b/src/P2/rog.c index 1d5fc8c6..acebafcc 100644 --- a/src/P2/rog.c +++ b/src/P2/rog.c @@ -341,8 +341,6 @@ RODD *ProddCurRob(ROB *prob, ENSK ensk) return (RODD *)((uint8_t *)prob + (irodd * 0xC0 + 0x3E0)); } -extern VECTOR g_normalZ; - void InitRoh(ROH *proh) { InitSo(proh); diff --git a/src/P2/rumble.c b/src/P2/rumble.c index aa0817d1..2f64085a 100644 --- a/src/P2/rumble.c +++ b/src/P2/rumble.c @@ -27,8 +27,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/rumble", UpdateRumble__FP6RUMBLE); extern RUMPAT D_0026B8B0[]; -void TriggerRumbleRumpat(RUMBLE *prumble, RUMPAT *prumpat, float dt); - void TriggerRumbleRumk(RUMBLE *prumble, RUMK rumk, float dt) { TriggerRumbleRumpat(prumble, &D_0026B8B0[rumk], dt); diff --git a/src/P2/screen.c b/src/P2/screen.c index 5c965967..a2b2a344 100644 --- a/src/P2/screen.c +++ b/src/P2/screen.c @@ -7,12 +7,12 @@ #include #include +extern BLOT *D_002486B0[]; + INCLUDE_ASM("asm/nonmatchings/P2/screen", StartupScreen__Fv); void PostBlotsLoad() { - extern BLOT *D_002486B0[]; - for (int i = 0x24; i >= 0; i--) { BLOT *pblot = D_002486B0[i]; @@ -24,8 +24,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/screen", UpdateBlots__Fv); void ForceHideBlots() { - extern BLOT *D_002486B0[]; - for (int i = 0x24; i >= 0; i--) { BLOT *pblot = D_002486B0[i]; @@ -35,8 +33,6 @@ void ForceHideBlots() void ResetBlots(void) { - extern BLOT *D_002486B0[]; - for (int i = 0; i < 0x25; i++) { BLOT *pblot = D_002486B0[i]; @@ -46,8 +42,6 @@ void ResetBlots(void) void RenderBlots() { - extern BLOT *D_002486B0[]; - BLOT **ppblot = D_002486B0; for (int i = 0x24; i >= 0; i--) diff --git a/src/P2/sensor.c b/src/P2/sensor.c index 8933cf5b..c3cd5a9c 100644 --- a/src/P2/sensor.c +++ b/src/P2/sensor.c @@ -73,42 +73,41 @@ void PauseSensor(SENSOR *psensor) INCLUDE_ASM("asm/nonmatchings/P2/sensor", UpdateSensor__FP6SENSORf); -void AddSensorTriggerObject(SENSOR * p, OID oid) +void AddSensorTriggerObject(SENSOR *psensor, OID oid) { - uint ccur = psensor->ctriggerObjects; - if (ccur >= 4) - return; + uint ccur = psensor->ctriggerObjects; + if (ccur >= 4) + return; - psensor->atriggerObjects[ccur] = oid; - psensor->ctriggerObjects = ccur + 1; + psensor->atriggerObjects[ccur] = oid; + psensor->ctriggerObjects = ccur + 1; } -void AddSensorNoTriggerObject(SENSOR * p, OID oid) +void AddSensorNoTriggerObject(SENSOR *psensor, OID oid) { - uint ccur = psensor->cnoTriggerObjects; - if (ccur >= 4) - return; + uint ccur = psensor->cnoTriggerObjects; + if (ccur >= 4) + return; - psensor->anoTriggerObjects[ccur] = oid; - psensor->cnoTriggerObjects = ccur + 1; + psensor->anoTriggerObjects[ccur] = oid; + psensor->cnoTriggerObjects = ccur + 1; } -void AddSensorTriggerClass(SENSOR * p, CID cid) +void AddSensorTriggerClass(SENSOR *psensor, CID cid) { - uint ccur = psensor->ctriggerClasses; - if (ccur >= 4) - return; + uint ccur = psensor->ctriggerClasses; + if (ccur >= 4) + return; - psensor->atriggerClasses[ccur] = cid; - psensor->ctriggerClasses = ccur + 1; + psensor->atriggerClasses[ccur] = cid; + psensor->ctriggerClasses = ccur + 1; } -void AddSensorNoTriggerClass(SENSOR * p, CID cid) +void AddSensorNoTriggerClass(SENSOR *psensor, CID cid) { - int c = STRUCT_OFFSET(p, 0x5a0, int); - if ((unsigned int)c < 4) - { - CID *a = &STRUCT_OFFSET(p, 0x5a4, CID); - a[c] = cid; - STRUCT_OFFSET(p, 0x5a0, int) = c + 1; - } + uint ccur = psensor->cnoTriggerClasses; + if (ccur >= 4) + return; + + psensor->anoTriggerClasses[ccur] = cid; + psensor->cnoTriggerClasses = ccur + 1; } void InitLasen(LASEN *plasen) { @@ -223,6 +222,8 @@ void InitCamsen(CAMSEN *pcamsen) STRUCT_OFFSET(pcamsen, 0x5D8, int) = -1; } +extern SNIP D_002744D8[2]; + void PostCamsenLoad(CAMSEN *pcamsen) { void *pvt; diff --git a/src/P2/shd.c b/src/P2/shd.c index f352e737..fc6c1489 100644 --- a/src/P2/shd.c +++ b/src/P2/shd.c @@ -4,6 +4,8 @@ extern GRFZON g_grfzonShaders; extern byte *g_pbBulkData; +extern GSB D_002626D8; +extern int D_002626CC; INCLUDE_ASM("asm/nonmatchings/P2/shd", Tex0FromTexIframeCtk__FP3TEXi3CTK); @@ -41,11 +43,6 @@ void UploadPermShaders() g_grfzonShaders = 0; } - extern GSB D_002626D8; - extern int D_002626CC; - -void PropagateSurs(); - void PropagateShaders(GRFZON grfzonCamera) { PropagateSais(); diff --git a/src/P2/so.c b/src/P2/so.c index 223376e3..263be810 100644 --- a/src/P2/so.c +++ b/src/P2/so.c @@ -171,7 +171,7 @@ void SetSoMass(SO *pso, float mass) INCLUDE_ASM("asm/nonmatchings/P2/so", AdjustSoMomint__FP2SOf); -INCLUDE_ASM("asm/nonmatchings/P2/so", DiscardSoXps__FP2SO); +INCLUDE_ASM("asm/nonmatchings/P2/so", DiscardSoXps__FP2SOi); void UpdateSoPosWorldPrev(SO *pso) { @@ -451,7 +451,7 @@ void SetSoNoXpsAll(SO *pso, int fNoXps) grfso &= mask; grfso |= bit; STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; - DiscardSoXps__FP2SO(pso, fNoXps != 0); + DiscardSoXps(pso, fNoXps != 0); } void SetSoNoXpsSelf(SO *pso, int fNoXps) @@ -461,7 +461,7 @@ void SetSoNoXpsSelf(SO *pso, int fNoXps) grfso &= ~((uint64_t)1 << 43); grfso |= bit; STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; - DiscardSoXps__FP2SO(pso, fNoXps ? 2 : 0); + DiscardSoXps(pso, fNoXps ? 2 : 0); } void SetSoNoXpsCenter(SO *pso, int fNoXps) @@ -471,7 +471,7 @@ void SetSoNoXpsCenter(SO *pso, int fNoXps) grfso &= ~((uint64_t)1 << 44); grfso |= bit; STRUCT_OFFSET(pso, 0x538, uint64_t) = grfso; - DiscardSoXps__FP2SO(pso, fNoXps ? 3 : 0); + DiscardSoXps(pso, fNoXps ? 3 : 0); } void RebuildSoPhysHook(SO *pso) @@ -584,7 +584,7 @@ int FAbsorbSoWkr(SO *pso, WKR *pwkr) INCLUDE_ASM("asm/nonmatchings/P2/so", CloneSoPhys__FP2SOT0i); -INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc4d8); +INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc4d8__FPUcT0); INCLUDE_ASM("asm/nonmatchings/P2/so", FUN_001bc670); diff --git a/src/P2/sound.c b/src/P2/sound.c index 0582b9f6..fd105eed 100644 --- a/src/P2/sound.c +++ b/src/P2/sound.c @@ -24,6 +24,7 @@ struct MVG }; extern float D_00274838[10][4]; // temp +extern int D_00274720; void UnloadMusic() { @@ -628,7 +629,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sound", StartSwIntermittentSounds__FP2SW); // TODO: Verify signature. extern u_int D_00274728; -extern "C" void SetAMRegister__FiUc(int n, int bReg) +void SetAMRegister(int n, int bReg) { if (bReg != D_006053E0[n]) { @@ -652,7 +653,7 @@ void FUN_001c0cb0() { for (int i = 0; i < 8; i++) { - SetAMRegister__FiUc(i, 0); + SetAMRegister(i, 0); } } diff --git a/src/P2/splice/bif.cpp b/src/P2/splice/bif.cpp index b95c2311..c65bdd7a 100644 --- a/src/P2/splice/bif.cpp +++ b/src/P2/splice/bif.cpp @@ -280,7 +280,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/splice/bif", RefOpMatrix__FiP4CRefP6CFrame); CRef RefOpSetMusicRegister(int carg, CRef *aref, CFrame *pframe) { - SetAMRegister__FiUc(aref[0].m_tag.m_n, aref[1].m_tag.m_n); + SetAMRegister(aref[0].m_tag.m_n, aref[1].m_tag.m_n); CRef ref; ref.SetTag(TAGK_Void); return ref; diff --git a/src/P2/splice/splotheap.cpp b/src/P2/splice/splotheap.cpp index 48be3c2a..107ef20a 100644 --- a/src/P2/splice/splotheap.cpp +++ b/src/P2/splice/splotheap.cpp @@ -105,8 +105,8 @@ void MarkPvAlive(void *pv) psplot->fAlive = 1; } -INCLUDE_ASM("asm/nonmatchings/P2/splice/splotheap", FUN_0011C418); +INCLUDE_ASM("asm/nonmatchings/P2/splice/splotheap", FUN_0011C418__FPvT0P6CFrame); -INCLUDE_ASM("asm/nonmatchings/P2/splice/splotheap", FUN_0011C498); +INCLUDE_ASM("asm/nonmatchings/P2/splice/splotheap", FUN_0011C498__Fv); INCLUDE_ASM("asm/nonmatchings/P2/splice/splotheap", FUN_0011C4E8); diff --git a/src/P2/step.c b/src/P2/step.c index 414e8dba..a6aeeca9 100644 --- a/src/P2/step.c +++ b/src/P2/step.c @@ -103,7 +103,6 @@ void AdjustStepDzBase(STEP *pstep, GRFADJ grfadj, DZ *pdz, int ixpd) void UpdateStepMatTarget(STEP *pstep) { - VECTOR g_normalZ; LoadRotateMatrixRad(*(float *)((uint8_t *)(pstep) + 0x638), &g_normalZ, (MATRIX3 *)((uint8_t *)(pstep) + 0x660)); } diff --git a/src/P2/stepcane.c b/src/P2/stepcane.c index 8f8d6c2e..055b0ae7 100644 --- a/src/P2/stepcane.c +++ b/src/P2/stepcane.c @@ -12,9 +12,11 @@ INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtAttackTarget__FP2JTiP6VECTOR INCLUDE_ASM("asm/nonmatchings/P2/stepcane", ChooseJtSweepTarget__FP2JTP2BLP6ASEGBL); +extern VECTOR D_00274BF0; +extern VECTOR D_00274C00; + void ChooseJtRushTarget(JT *pjt) { - VECTOR D_00274BF0; VECTOR dposProj; TARGET *ptarget; diff --git a/src/P2/stepguard.c b/src/P2/stepguard.c index 4fb7e809..5c458bed 100644 --- a/src/P2/stepguard.c +++ b/src/P2/stepguard.c @@ -271,7 +271,7 @@ void SetStepguardEnemyObject(STEPGUARD *pstepguard, SO *psoEnemy) INCLUDE_ASM("asm/nonmatchings/P2/stepguard", RebindStepguardEnemy__FP9STEPGUARD); -void FUN_001cac28__FP9STEPGUARD(STEPGUARD *pstepguard, int n) +void FUN_001cac28(STEPGUARD *pstepguard, int n) { STRUCT_OFFSET(pstepguard, 0xB50, int) = n; } diff --git a/src/P2/stephide.c b/src/P2/stephide.c index 1ac0e8a1..127222f3 100644 --- a/src/P2/stephide.c +++ b/src/P2/stephide.c @@ -1,5 +1,6 @@ #include #include +#include INCLUDE_ASM("asm/nonmatchings/P2/stephide", JtbsChooseJtHide__FP2JTP2LOP4JTHK); @@ -25,9 +26,6 @@ float GMeasureJumpRail(MJR *pmjr, float u) return gInteg; } -struct HPNT; -extern void GetHpntClosestHidePos(HPNT *phpnt, VECTOR *ppos, float *pf); - float FUN_001cea58(MJH *pmjh) { VECTOR posTarget; @@ -43,9 +41,6 @@ float FUN_001cea58(MJH *pmjh) return gInteg; } -struct HSHAPE; -extern void GetHshapeHidePos(HSHAPE *phshape, float s, VECTOR *ppos, float *pf); - float GMeasureJumpHshape(MJH *pmjh, float s) { VECTOR posTarget; diff --git a/src/P2/steppipe.c b/src/P2/steppipe.c index fed30c96..c55e84cd 100644 --- a/src/P2/steppipe.c +++ b/src/P2/steppipe.c @@ -10,9 +10,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/steppipe", UpdateJtActivePipe__FP2JTP3JOY); INCLUDE_ASM("asm/nonmatchings/P2/steppipe", UpdateJtInternalXpsPipe__FP2JT); -void FUN_001ddb58(SW *psw); -void FUN_001ddbb8(SW *psw); - void SetJtJtpdk(JT *pjt, JTPDK jtpdk) { JTPDK jtpdkCur = STRUCT_OFFSET(pjt, 0x2718, JTPDK); diff --git a/src/P2/steprail.c b/src/P2/steprail.c index 5934edfd..f8a47cca 100644 --- a/src/P2/steprail.c +++ b/src/P2/steprail.c @@ -4,6 +4,8 @@ INCLUDE_ASM("asm/nonmatchings/P2/steprail", func_001D31D0__FP2LOi); +extern SNIP D_00274F90; + void post_load_steprail(ALO *palo) { PostAloLoad(palo); @@ -20,7 +22,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/steprail", update_steprail); void preset_steprail_accel(SO *pso, float dt) { MATRIX3 mat; - extern VECTOR D_00248D30; PresetSoAccel(pso, dt); diff --git a/src/P2/sw.c b/src/P2/sw.c index 7dc418b5..3cef699e 100644 --- a/src/P2/sw.c +++ b/src/P2/sw.c @@ -74,7 +74,7 @@ void SetSwGravity(SW *psw, float z) void FUN_001dbac0(SW *psw, int reg, int value) { - SetAMRegister__FiUc(reg, value); + SetAMRegister(reg, value); } int FUN_001dbae0(SW *psw, int reg) @@ -420,7 +420,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/sw", FUN_001dd7e8); int FUN_001dd888(SW *psw, WID wid, int nKey) { - int *pls = PlsFromWid(wid); + int *pls = LsFromWid(wid); if (pls != NULL) { int *p = pls + 0x11; @@ -528,6 +528,11 @@ void CancelSwDialogPlaying(SW *psw) } } +typedef struct +{ + int n; +} __attribute__((packed)) UNALIGNED_INT; + extern PROMPT D_0026FF68; void FUN_001ddb20(SW *psw, PRK prk, int oid) diff --git a/src/P2/tank.c b/src/P2/tank.c index 5fca9efa..0e7ec8eb 100644 --- a/src/P2/tank.c +++ b/src/P2/tank.c @@ -3,9 +3,10 @@ #include #include +extern qword D_00275740; + void InitTank(TANK *ptank) { - InitStep((STEP *)ptank); float rad = atan2f(STRUCT_OFFSET(ptank, 0xD4, float), STRUCT_OFFSET(ptank, 0xD0, float)); diff --git a/src/P2/tn.c b/src/P2/tn.c index 35f78299..41f5bcea 100644 --- a/src/P2/tn.c +++ b/src/P2/tn.c @@ -5,6 +5,8 @@ #include extern TNFN D_00275980; +extern VECTOR D_00275A10; +extern char D_00275A20[8]; TNFN *PtnfnFromTn(TN *ptn) { @@ -19,8 +21,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/tn", InitTn__FP2TN); #ifdef SKIP_ASM void InitTn(TN *ptn) { - VECTOR D_00275A10; - char D_00275A20[8]; uint64_t flags; InitAlo(ptn); diff --git a/src/P2/ub.c b/src/P2/ub.c index f93f1b58..e92aaca9 100644 --- a/src/P2/ub.c +++ b/src/P2/ub.c @@ -1,16 +1,15 @@ #include +extern SNIP s_asnipLoadUbg[8]; // @todo migrate from asm/data/P2/ub.data.s and make static + INCLUDE_ASM("asm/nonmatchings/P2/ub", InitUbg__FP3UBG); #ifndef SKIP_ASM INCLUDE_ASM("asm/nonmatchings/P2/ub", PostUbgLoad__FP3UBG); #else -extern SNIP D_00275B60; -void FUN_001ddc38(void *pv, void *pvBlot); - void PostUbgLoad(UBG *pubg) { - SnipAloObjects((ALO *)pubg, 8, &D_00275B60); + SnipAloObjects((ALO *)pubg, 8, s_asnipLoadUbg); FUN_001ddc38(STRUCT_OFFSET(pubg, 0x14, void *), pubg); if (STRUCT_OFFSET(pubg, 0xC50, void *) != NULL) diff --git a/src/P2/water.c b/src/P2/water.c index 07cd8f03..645e96ba 100644 --- a/src/P2/water.c +++ b/src/P2/water.c @@ -6,8 +6,6 @@ struct JT; extern JT *g_pjt; -extern VU_VECTOR D_00248D30; -extern VU_VECTOR g_normalZ; void InitWater(WATER *pwater) { @@ -37,7 +35,7 @@ void CalculateWaterCurrent(WATER *pwater, VECTOR *ppos, VECTOR *pv, VECTOR *pw) ConvertAloVec(NULL, pwater, ppos, (VECTOR *)&vec0); *(int *)((char *)&vec0 + 8) = 0; vecPos = pwater->vecCurrent; - vecCur = D_00248D30; + vecCur = *(VU_VECTOR *)&D_00248D30; CalculateAloTransformAdjust(pwater, NULL, (VECTOR *)&vec0, NULL, (VECTOR *)&vecPos, (VECTOR *)&vecCur); void *p278 = STRUCT_OFFSET(pwater, 0x278, void *); @@ -201,7 +199,7 @@ float UGetWaterSubmerged(WATER *pwater, SO *pso, VECTOR *pposSurface, VECTOR *pn if (ClsgClipEdgeToBsp(STRUCT_OFFSET(pwater, 0x3F8, BSP *), (VECTOR *)&aedge[0], (VECTOR *)&aedge[1], NULL, 0x10, alsg) == 0) { if (pnormalSurface != NULL) - *(VU_VECTOR *)pnormalSurface = g_normalZ; + *(VU_VECTOR *)pnormalSurface = *(VU_VECTOR *)&g_normalZ; return 0.0f; } @@ -214,7 +212,7 @@ float UGetWaterSubmerged(WATER *pwater, SO *pso, VECTOR *pposSurface, VECTOR *pn if (pn != NULL) *(VU_VECTOR *)pnormalSurface = *(VU_VECTOR *)pn; else - *(VU_VECTOR *)pnormalSurface = g_normalZ; + *(VU_VECTOR *)pnormalSurface = *(VU_VECTOR *)&g_normalZ; } return alsg[0].au[1] - alsg[0].au[0]; From 3297fe1aec136e4025b74738370a06acfca14f15 Mon Sep 17 00:00:00 2001 From: theonlyzac Date: Wed, 8 Jul 2026 20:31:06 -0400 Subject: [PATCH 134/134] Resolve a handful of review comments --- config/symbol_addrs.txt | 4 ++-- include/mpeg.h | 4 +--- src/P2/alo.c | 21 +++++---------------- src/P2/coin.c | 6 +++--- src/P2/crusher.c | 26 ++++++++++++-------------- src/P2/crv.c | 22 +++++++++++++--------- src/P2/dartgun.c | 6 +++--- src/P2/emitter.c | 17 +++++------------ src/P2/glob.c | 13 +++---------- src/P2/jlo.c | 18 ++++++------------ src/P2/mpeg.c | 9 +++++---- 11 files changed, 58 insertions(+), 88 deletions(-) diff --git a/config/symbol_addrs.txt b/config/symbol_addrs.txt index 89b7680f..eb72f967 100644 --- a/config/symbol_addrs.txt +++ b/config/symbol_addrs.txt @@ -2935,7 +2935,7 @@ BuildMpegGifs__FP2QWP11sceIpuRGB32iiiii = 0x18EDA8; // type:func FUN_0018ef78 = 0x18EF78; // type:func FUN_0018f0e8 = 0x18F0E8; // type:func ExecuteOids__5CMpeg = 0x18F148; // type:func -Execute__5CMpeg = 0x18F198; // type:func +Execute__5CMpegP3OID = 0x18F198; // type:func Start__5CMpegP18CBinaryAsyncStream = 0x18F448; // type:func FUN_0018f610__5CMpeg = 0x18F610; // type:func Update__5CMpeg = 0x18F6E8; // type:func @@ -2981,7 +2981,7 @@ CollectMurrayPrize__FP6MURRAY3PCKP3ALO = 0x1906F8; // type:func CheckMurrayStunOrDying__FP6MURRAY = 0x190740; // type:func HandleMurrayMessage__FP6MURRAY5MSGIDPv = 0x190770; // type:func -D_00269B60 = 0x269B60; +D_00269B60 = 0x269B60; //////////////////////////////////////////////////////////////// diff --git a/include/mpeg.h b/include/mpeg.h index aa489f0e..cdd3e1a9 100644 --- a/include/mpeg.h +++ b/include/mpeg.h @@ -22,6 +22,7 @@ class CMpeg void Start(CBinaryAsyncStream *pbas); void Update(); void Finish(); + void CbDemuxed(int nParam); }; void StartupMpeg(); @@ -32,8 +33,5 @@ extern "C" void FUN_0018f0e8(CMpeg *pmpeg, void *pv); extern "C" int FAccept__10CMpegAudioiPUc(void *pmpega, int cb, uchar *pb); -extern "C" void CbDemuxed__5CMpegi(CMpeg *pmpeg, int nParam); - -extern "C" void Execute__5CMpeg(CMpeg *pmpeg, OID *poid); #endif // MPEG_H diff --git a/src/P2/alo.c b/src/P2/alo.c index d191a0e1..183b5bec 100644 --- a/src/P2/alo.c +++ b/src/P2/alo.c @@ -54,10 +54,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", UpdateAlo__FP3ALOf); void InvalidateAloLighting(ALO *palo) { - int iglobi; - - // palo->globset: count at +0xc, GLOBI array (stride 0x28) at +0x14; invalidate lighting frame at +0x8 - for (iglobi = 0; iglobi < STRUCT_OFFSET(palo, 0x238, int); iglobi++) + for (int iglobi = 0; iglobi < STRUCT_OFFSET(palo, 0x238, int); iglobi++) { char *pb = STRUCT_OFFSET(palo, 0x240, char *) + iglobi * 0x28; *(int *)(pb + 8) = -1; @@ -142,10 +139,8 @@ void SetAloVelocityXYZ(ALO *palo, float x, float y, float z) void SetAloAngularVelocityVec(ALO *palo, VECTOR *pw) { - ACT *pactRot; - STRUCT_OFFSET(palo, 0x160, VU_VECTOR) = *(VU_VECTOR *)pw; // palo->wWorld (angular velocity) - pactRot = STRUCT_OFFSET(palo, 0x1f0, ACT *); // palo->pactRot + ACT *pactRot = STRUCT_OFFSET(palo, 0x1f0, ACT *); // palo->pactRot if (pactRot != NULL) { AdaptAct(pactRot); @@ -187,9 +182,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/alo", ConvertAloMat__FP3ALOT0P7MATRIX3T2); int FDrivenAlo(ALO *palo) { - ACT *pact; - - pact = STRUCT_OFFSET(palo, 0x1ec, ACT *); // palo->pactPos + ACT *pact = STRUCT_OFFSET(palo, 0x1ec, ACT *); // palo->pactPos if (pact != NULL && STRUCT_OFFSET(pact, 0x10, char) == ACK_Drive) { return 1; @@ -288,15 +281,13 @@ extern DL D_00262300; void SetAloCastShadow(ALO *palo, int fCastShadow) { - SHADOW *pshadow; - if (fCastShadow) { PshadowAloEnsure(palo); return; } - pshadow = STRUCT_OFFSET(palo, 0x284, SHADOW *); // palo->pshadow + SHADOW *pshadow = STRUCT_OFFSET(palo, 0x284, SHADOW *); // palo->pshadow if (pshadow != NULL) { RemoveDlEntry(&STRUCT_OFFSET(palo->psw, 0x1c00, DL), pshadow); @@ -493,8 +484,6 @@ void CreateAloActadj(ALO *palo, int nPriority, ACTADJ **ppactadj) int FIsAloStatic(ALO *palo) { - ALO *paloChild; - if (!FIsZeroV(&STRUCT_OFFSET(palo, 0x150, VECTOR))) { return 0; @@ -505,7 +494,7 @@ int FIsAloStatic(ALO *palo) return 0; } - paloChild = (ALO *)palo->dlChild.head; + ALO *paloChild = (ALO *)palo->dlChild.head; while (paloChild != NULL) { if (paloChild->pvtlo->grfcid & 1 && !FIsAloStatic(paloChild)) diff --git a/src/P2/coin.c b/src/P2/coin.c index 73117e45..e72336bd 100644 --- a/src/P2/coin.c +++ b/src/P2/coin.c @@ -279,10 +279,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/coin", increment_and_show_life_count); INCLUDE_ASM("asm/nonmatchings/P2/coin", CollectLifetkn__FP7LIFETKN); -void FUN_00149168(DPRIZE *param_1) +void FUN_00149168(DPRIZE *pdprize) { - InitDprize(param_1); - *(int *)((uint8_t *)param_1 + 0x340) = 0; + InitDprize(pdprize); + STRUCT_OFFSET(pdprize, 0x340, int) = 0; } INCLUDE_ASM("asm/nonmatchings/P2/coin", break_bottle); diff --git a/src/P2/crusher.c b/src/P2/crusher.c index 31ee543f..c50be68c 100644 --- a/src/P2/crusher.c +++ b/src/P2/crusher.c @@ -73,19 +73,19 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014c5e8); extern void *D_0027C00C; void FUN_0014c668(void *pv, int tnt) { - if (tnt == 1) - { - OID oidGoal; - OID oidCur; + if (tnt != 1) + return; + + OID oidGoal; + OID oidCur; - GetSmaGoal(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), &oidGoal); - GetSmaCur(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), &oidCur); + GetSmaGoal(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), &oidGoal); + GetSmaCur(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), &oidCur); - if (oidGoal != (OID)0x3fe && oidCur != (OID)0x3fe) - { - SetSmaGoal(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), (OID)0x3ff); - FUN_0014c5e8(D_0027C00C); - } + if (oidGoal != (OID)0x3fe && oidCur != (OID)0x3fe) + { + SetSmaGoal(STRUCT_OFFSET(D_0027C00C, 0x42c, SMA *), (OID)0x3ff); + FUN_0014c5e8(D_0027C00C); } } @@ -163,15 +163,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/crusher", FUN_0014cba8); void FUN_0014cd70(void *p) { - int n; - if (STRUCT_OFFSET(p, 0x458, int) == STRUCT_OFFSET(p, 0x450, int)) { float g = GRandInRange(STRUCT_OFFSET(p, 0x43c, float), STRUCT_OFFSET(p, 0x440, float)); STRUCT_OFFSET(p, 0x45c, float) = g_clock.t + g; } - n = STRUCT_OFFSET(p, 0x458, int); + int n = STRUCT_OFFSET(p, 0x458, int); STRUCT_OFFSET(p, 0x458, int) = n - 1; } diff --git a/src/P2/crv.c b/src/P2/crv.c index 554d081e..9cddebda 100644 --- a/src/P2/crv.c +++ b/src/P2/crv.c @@ -8,22 +8,25 @@ INCLUDE_ASM("asm/nonmatchings/P2/crv", SMeasureApos__FiP6VECTORPf); float GWrapApos(float g, int cpos, float *mpiposg, int fClosed) { float f0 = g; - if (!fClosed) { + if (!fClosed) + { return f0; } - + float f1 = mpiposg[0]; float f3 = mpiposg[cpos - 1]; float f2 = f3 - f1; - - while (f0 < f1) { + + while (f0 < f1) + { f0 = f0 + f2; } - - while (f3 < f0) { + + while (f3 < f0) + { f0 = f0 - f2; } - + return f0; } @@ -101,11 +104,11 @@ JUNK_ADDIU(A0); float SMeasureCrvSegmentU(CRVMS *pcrvms, float u) { - void *pcrv = STRUCT_OFFSET(pcrvms, 0x0, void *); void **pvtbl = STRUCT_OFFSET(pcrv, 0x0, void **); void (*pfn)(void *, VECTOR *, int) = (void (*)(void *, VECTOR *, int))pvtbl[1]; VECTOR pos; + if (pfn != NULL) { pfn(pcrv, &pos, 0); @@ -204,7 +207,8 @@ void LoadCrvcFromBrx(CRVC *pcrvc, CBinaryInputStream *pbis) for (int icv = 0; icv < STRUCT_OFFSET(pcrvc, 0xC, int); icv++) { - STRUCT_OFFSET(pcrvc, 0x10, float *)[icv] = pbis->F32Read(); + STRUCT_OFFSET(pcrvc, 0x10, float *) + [icv] = pbis->F32Read(); pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x18, void *) + icv * 16)); pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x1C, void *) + icv * 16)); pbis->ReadVector((VECTOR *)((char *)STRUCT_OFFSET(pcrvc, 0x20, void *) + icv * 16)); diff --git a/src/P2/dartgun.c b/src/P2/dartgun.c index 6a11d28a..61ebf60f 100644 --- a/src/P2/dartgun.c +++ b/src/P2/dartgun.c @@ -65,10 +65,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/dartgun", UpdateDartgun__FP7DARTGUNf); int FIgnoreDartgunIntersection(DARTGUN *pdartgun, SO *psoOther) { - if (FIsBasicDerivedFrom(psoOther, CID_RAT)) + if (FIsBasicDerivedFrom(psoOther, CID_RAT) + && STRUCT_OFFSET(psoOther, 0x588, SO *) == (SO *)pdartgun) { - if (STRUCT_OFFSET(psoOther, 0x588, SO *) == (SO *)pdartgun) - return 1; + return 1; } return FIgnoreSoIntersection((SO *)pdartgun, psoOther); diff --git a/src/P2/emitter.c b/src/P2/emitter.c index 0c02f869..2d32dfac 100644 --- a/src/P2/emitter.c +++ b/src/P2/emitter.c @@ -22,14 +22,13 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadEmitblipColorsFromBrx__FP8EMITBLI #ifdef SKIP_ASM void LoadEmitblipColorsFromBrx(EMITBLIP *pemitblip, int crgba, LO *ploEmit, CBinaryInputStream *pbis) { - int i; int cColor = (crgba > 0x1f) ? 0x20 : crgba; STRUCT_OFFSET(pemitblip, 0x4c, int) = cColor; STRUCT_OFFSET(pemitblip, 0x50, RGBA *) = (RGBA *)PvAllocSwImpl(cColor * 4); STRUCT_OFFSET(pemitblip, 0x54, int) = pbis->U8Read(); - for (i = 0; i < crgba; i++) + for (int i = 0; i < crgba; i++) { uint rgba = pbis->U32Read(); if (i < STRUCT_OFFSET(pemitblip, 0x4c, int)) @@ -249,10 +248,6 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", CalculateEmitvx__FiP2LMiP6EMITVX); #ifdef SKIP_ASM void CalculateEmitvx(int cParticlePerRing, LM *plmTilt, int cParticle, EMITVX *pemitvx) { - int cBatch; - int count; - float gNorm; - if (cParticlePerRing > 0) { STRUCT_OFFSET(pemitvx, 0x0, int) = @@ -263,10 +258,9 @@ void CalculateEmitvx(int cParticlePerRing, LM *plmTilt, int cParticle, EMITVX *p STRUCT_OFFSET(pemitvx, 0x0, int) = cParticle; } - count = STRUCT_OFFSET(pemitvx, 0x0, int); - cBatch = (cParticle - 1 + count) / count; - - gNorm = RadNormalize(plmTilt->gMax - plmTilt->gMin); + int count = STRUCT_OFFSET(pemitvx, 0x0, int); + int cBatch = (cParticle - 1 + count) / count; + float gNorm = RadNormalize(plmTilt->gMax - plmTilt->gMin); STRUCT_OFFSET(pemitvx, 0x8, float) = 6.2831855f / (float)STRUCT_OFFSET(pemitvx, 0x0, int); STRUCT_OFFSET(pemitvx, 0x4, float) = gNorm / (float)cBatch; @@ -370,10 +364,9 @@ INCLUDE_ASM("asm/nonmatchings/P2/emitter", LoadExplgFromBrx__FP5EXPLGP18CBinaryI void CloneExplg(EXPLG *pexplg, EXPLG *pexplgBase) { - int i = 0; - CloneLo((LO *)pexplg, (LO *)pexplgBase); + int i = 0; if (STRUCT_OFFSET(pexplg, 0x90, int) > 0) { LO **p = &STRUCT_OFFSET(pexplg, 0x94, LO *); diff --git a/src/P2/glob.c b/src/P2/glob.c index 34586517..b7d6865b 100644 --- a/src/P2/glob.c +++ b/src/P2/glob.c @@ -59,17 +59,10 @@ INCLUDE_ASM("asm/nonmatchings/P2/glob", UpdateGlobset__FP7GLOBSETP3ALOf); void UpdateAloConstraints(ALO *palo) { void *p = STRUCT_OFFSET(palo, 0x224, void *); + if (p == NULL || !(STRUCT_OFFSET(p, 0xb0, int) & 0x10) || STRUCT_OFFSET(p, 0x64, int) == 0) + return; - if (p != NULL) - { - if (STRUCT_OFFSET(p, 0xb0, int) & 0x10) - { - if (STRUCT_OFFSET(p, 0x64, int) != 0) - { - SolveAloIK(STRUCT_OFFSET(p, 0x60, ALO *)); - } - } - } + SolveAloIK(STRUCT_OFFSET(p, 0x60, ALO *)); } INCLUDE_ASM("asm/nonmatchings/P2/glob", UpdateAloInfluences__FP3ALOP2RO); diff --git a/src/P2/jlo.c b/src/P2/jlo.c index fb7207cb..a20fc4af 100644 --- a/src/P2/jlo.c +++ b/src/P2/jlo.c @@ -114,18 +114,12 @@ extern char D_002482D8[]; void FUN_0016d928(JLO *pjlo) { - if (STRUCT_OFFSET(pjlo, 0x5c0, int) != 0) - { - if (!FVagPlaying()) - { - if (NRandInRange(0, 100) < 20) - { - int n = NRandInRange(0, 6); - PreloadVag1(&D_002482D8[n << 5]); - STRUCT_OFFSET(pjlo, 0x5cc, int) = 1; - } - } - } + if (STRUCT_OFFSET(pjlo, 0x5c0, int) == 0 || FVagPlaying() || NRandInRange(0, 100) >= 20) + return; + + int n = NRandInRange(0, 6); + PreloadVag1(&D_002482D8[n << 5]); + STRUCT_OFFSET(pjlo, 0x5cc, int) = 1; } INCLUDE_ASM("asm/nonmatchings/P2/jlo", FUN_0016d9a8); diff --git a/src/P2/mpeg.c b/src/P2/mpeg.c index b29f7423..0a465c70 100644 --- a/src/P2/mpeg.c +++ b/src/P2/mpeg.c @@ -206,6 +206,7 @@ void CMpegAudio::Update() } #endif // SKIP_ASM +// @todo Move these to a header struct sceMpeg; struct sceMpegCbDataStr; @@ -233,7 +234,7 @@ INCLUDE_ASM("asm/nonmatchings/P2/mpeg", FMpegDecodeVideo__FP7sceMpegP13sceMpegCb struct sceMpegCbData; int FMpegDecoderIdle(sceMpeg *pmp, sceMpegCbData *pcbdata, CMpeg *pmpeg) { - CbDemuxed__5CMpegi(pmpeg, 0); + pmpeg->CbDemuxed((OID)0); return 1; } @@ -256,15 +257,15 @@ void CMpeg::ExecuteOids() STRUCT_OFFSET(this, 0x4, OID *) = 0; STRUCT_OFFSET(this, 0x8, OID *) = 0; - Execute__5CMpeg(this, poid); + Execute(poid); if (poidNext != 0) { - Execute__5CMpeg(this, poidNext); + Execute(poidNext); } } -INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Execute__5CMpeg); +INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Execute__5CMpegP3OID); INCLUDE_ASM("asm/nonmatchings/P2/mpeg", Start__5CMpegP18CBinaryAsyncStream);