diff --git a/config/symbols.extern.txt b/config/symbols.extern.txt index dad6faa8..e739faae 100644 --- a/config/symbols.extern.txt +++ b/config/symbols.extern.txt @@ -83,6 +83,7 @@ SetSprt = 0x8004D6E4; SetTile = 0x8004D704; SetDrawTPage = 0x8004D724; SetDrawMove = 0x8004D754; +deactivateBattleCmd = 0x800308B0; SetDrawLoad = 0x8004D7B4; g_gameState = 0x80077378; g_characterMagic = 0x80077818; diff --git a/include/battle.h b/include/battle.h index 4a705463..3bb86793 100644 --- a/include/battle.h +++ b/include/battle.h @@ -5,7 +5,7 @@ #include "psxsdk/libgpu.h" #include "psxsdk/libgte.h" #include "tim.h" -#include "battle_anim.h" /* AnimFrame, BattleAnimEntity, BattleAnimState, g_battleAnims */ +#include "battle_anim.h" /** @brief Battle result values (BattleConfig.result). */ #define BATTLE_RESULT_UNDETERMINED 0 diff --git a/include/field/fe_object1.h b/include/field/fe_object1.h index 838242b4..b186f996 100644 --- a/include/field/fe_object1.h +++ b/include/field/fe_object1.h @@ -22,8 +22,6 @@ extern CdFileDesc D_800C0910[]; /**< Streaming table, third descriptor (passed /** @brief Field id currently being streamed in (compared against @c D_8005F100). */ extern s16 D_8005F14E; -/** @brief Field render/present state halfword; the loader spins while it reads 4. */ -extern volatile s16 D_8005F146; /** @brief Section-pointer table bases published by the loaded field bundle. */ extern u8 **D_800C7208; /**< Event-queue block; assigned to @c D_8005F0F8. */ diff --git a/include/main.h b/include/main.h index 86d608f2..be57103f 100644 --- a/include/main.h +++ b/include/main.h @@ -2,8 +2,8 @@ #define MAIN_H #include "common.h" -#include "cd.h" /* CdFileDesc */ -#include "psxsdk/libgpu.h" /* TILE */ +#include "cd.h" +#include "psxsdk/libgpu.h" /* =============================================================== * * Public interface — functions in main.c called by other units. * @@ -53,6 +53,9 @@ extern u8 g_vsyncSkip; extern volatile s32 D_8005F154; /**< VSync frame-counter timing accumulator (+0x88F/VSync). */ extern volatile s32 D_8005F15C; /**< VSync countdown-timer timing accumulator (+0x88F/VSync). */ extern u16 D_8005F11E; /**< VSync-done / status flag. */ +/** Scene-transition handshake driven by the VSync path; shared by the field, + * world and battle engines (each spins on it with its own sentinel value). */ +extern volatile s16 D_8005F146; /* CD file-table descriptors + scratch buffers loaded/managed by main.c. */ extern CdFileDesc g_fileTableDesc[]; diff --git a/include/menuitem.h b/include/menuitem.h index 8df7641b..df0d7cdb 100644 --- a/include/menuitem.h +++ b/include/menuitem.h @@ -9,8 +9,8 @@ #define MENUITEM_H #include "common.h" -#include "gamestate.h" /* g_gameState */ -#include "menumain.h" /* D_801F889C and the rest of the resident menu image */ +#include "gamestate.h" +#include "menumain.h" extern s32 D_80083850; extern s32 D_801ECC10; diff --git a/include/overlay.h b/include/overlay.h index 5fabf01f..10e27df7 100644 --- a/include/overlay.h +++ b/include/overlay.h @@ -2,6 +2,7 @@ #define OVERLAY_H #include "common.h" +#include "world/we_object0.h" /** * @brief Overlay command queue entry (D_80085168, 8-slot ring buffer). @@ -57,8 +58,4 @@ extern s32 func_8003646C(); /* K&R: called with 1 or 2 args */ /** @brief Run the loaded overlay's entry point (init / execute). */ extern void func_80098000(void); -/** @brief Query the loaded overlay; returns a status code (main checks @c == 1). - * @note Purpose uncertain - undecompiled; appears to report the overlay's - * load/ready result. */ -extern s32 func_800987D8(void); #endif /* OVERLAY_H */ diff --git a/include/tim.h b/include/tim.h index eb1355e7..a54082f6 100644 --- a/include/tim.h +++ b/include/tim.h @@ -2,7 +2,7 @@ #define TIM_H #include "common.h" -#include "psxsdk/libgpu.h" /* RECT */ +#include "psxsdk/libgpu.h" /** * @brief One section of a PS1 TIM image file (CLUT block or pixel block). diff --git a/include/tripletriad.h b/include/tripletriad.h index d1cb2909..c6f0fb95 100644 --- a/include/tripletriad.h +++ b/include/tripletriad.h @@ -2,9 +2,9 @@ #define TRIPLETRIAD_H #include "common.h" -#include "psxsdk/libgpu.h" /* TSPRT (drawCardOverlaySprite) */ -#include "psxsdk/libgte.h" /* SVECTOR / MATRIX (CardRenderWork, CardAnimNode) */ -#include "main.h" /* g_activeDrawEnv */ +#include "psxsdk/libgpu.h" +#include "psxsdk/libgte.h" +#include "main.h" /* Types, constants, and globals for the Triple Triad card mini-game. Its code is the `tripletriad` overlay, which loads at the same VRAM address diff --git a/include/tripletriad/be_object1.h b/include/tripletriad/be_object1.h index 8267380b..0e9809ae 100644 --- a/include/tripletriad/be_object1.h +++ b/include/tripletriad/be_object1.h @@ -3,7 +3,7 @@ #include "common.h" #include "tripletriad.h" -#include "tim.h" /* Tim / TimSection (queued VRAM image uploads) */ +#include "tim.h" /* Declarations for be_object1.c (Triple Triad board/card setup, draw-buffer init, deferred VRAM transfers, the object-list system, debug text, and the diff --git a/include/tripletriad/be_object1b.h b/include/tripletriad/be_object1b.h index dfbda4b4..b208acaa 100644 --- a/include/tripletriad/be_object1b.h +++ b/include/tripletriad/be_object1b.h @@ -2,7 +2,7 @@ #define TRIPLETRIAD_BE_OBJECT1B_H #include "common.h" -#include "psxsdk/libgte.h" /* SVECTOR (layoutCardSlot) */ +#include "psxsdk/libgte.h" /* Declarations for be_object1b.c (Triple Triad match-flow controller, the per-frame update-list callbacks, and card-object search helpers). */ diff --git a/include/tripletriad/be_object2.h b/include/tripletriad/be_object2.h index bdea05c8..6dc7c3ce 100644 --- a/include/tripletriad/be_object2.h +++ b/include/tripletriad/be_object2.h @@ -2,7 +2,7 @@ #define TRIPLETRIAD_BE_OBJECT2_H #include "common.h" -#include "tripletriad.h" /* board/card types, SVECTOR / CVECTOR / VECTOR */ +#include "tripletriad.h" /* Declarations for be_object2.c (Triple Triad card objects, the rules engine, the menu/cursor sub-machine, and the AI move search). */ diff --git a/include/tripletriad/be_object4.h b/include/tripletriad/be_object4.h index b827592b..046f134e 100644 --- a/include/tripletriad/be_object4.h +++ b/include/tripletriad/be_object4.h @@ -3,7 +3,7 @@ #include "common.h" #include "tripletriad.h" -#include "battle_anim.h" /* BattleAnimState / BattleAnimEntity (func_800A29D4 prototype) */ +#include "battle_anim.h" /* Public interface of be_object4.c: the Triple Triad SFX request queue, the card-detail popup buffers, the rule-description string table, and the message-gate / menu helpers diff --git a/include/world.h b/include/world.h index f2645dc7..5d2465fd 100644 --- a/include/world.h +++ b/include/world.h @@ -5,6 +5,7 @@ #include "psxsdk/libgpu.h" #include "psxsdk/libgte.h" #include "battle.h" +#include "gamestate.h" #include "sound.h" /** View of the sentinel ctx exposing the DISPENV template that sits past the @@ -204,14 +205,8 @@ extern s32 D_800DCB48; * @brief 8-byte world-transform block — four packed halfwords. * * Every field is read/written as @c lh / @c sh at a fixed offset. Only - * @c angle has an identified role (input to rotation helper @c getAngleDelta). */ -typedef struct { - /* 0x00 */ s16 unk0; - /* 0x02 */ s16 angle; - /* 0x04 */ s16 unk4; - /* 0x06 */ s16 unk6; -} WorldXformBlock; /* 0x08 */ + /** * @brief 16-byte world-transform record at @c D_800D2390 (pair of blocks). @@ -220,8 +215,8 @@ typedef struct { * snapshots @c tail, adjusts its @c angle, and forwards the modified copy. */ typedef struct { - /* 0x00 */ WorldXformBlock head; - /* 0x08 */ WorldXformBlock tail; + /* 0x00 */ SVECTOR head; + /* 0x08 */ SVECTOR tail; } WorldXform; /* 0x10 */ /* Shared world-overlay state referenced by more than one we_object*.c. @@ -261,7 +256,8 @@ extern s32 D_800C97F4; /**< World camera angle. Stored as a wo angular-delta helpers in we_object9 read only its low half — hence the (u16) cast at those sites. */ extern MATRIX D_800C9838; /**< World-to-screen matrix loaded into the GTE. */ -extern WorldPos D_800C9868; /**< Source camera world position (cast to VECTOR* for GTE transform func_800BC544). */ +extern VECTOR D_800C9868; /**< Source camera world position. 16 bytes: the world entry loop copies + it whole into @c D_800C9858 and hands it straight to func_800BC544. */ extern SVECTOR D_800C9770[2]; /**< Camera scratch: [0] is a position offset, [1] a rotation. */ extern s32 *D_800C9744; /**< Texture-strip animation block: a NULL-terminated s32 offset table; each offset, relative to this pointer, locates one @@ -527,7 +523,11 @@ typedef struct { typedef struct { /* 0x00 */ u8 pad00[0x18]; /* 0x18 */ Track tracks[2]; /**< Track A at 0x18, Track B at 0x24. */ - /* 0x30 */ u8 pad30[0x3C]; + /* 0x30 */ u8 pad30[0x38]; + /* 0x68 */ SceneState scene; /**< Saved scene state; the world entry loop + saves the whole record here on a cold + start and restores @c cmd from it on a + warm one. */ /* 0x6C */ s32 unk6C; /**< Flags word; see SLOT_FLAG_CMD_MIRROR. */ /* 0x70 */ u8 pad70[0x4]; /* 0x74 */ u32 flags[2]; /**< 64-bit flag set (low/high). */ @@ -565,7 +565,6 @@ typedef struct { extern BattleSceneCtx D_800CA040; /**< Worldmap "no-battle" sentinel — also functions as an empty BattleSceneCtx. */ extern s16 D_800C53B8[]; /**< Bone-id table (used by we_object4). */ -extern ScriptOp *func_800AF004(u8 *base, s32 flag); extern s32 func_800AF28C(ScriptOp *p); extern s32 func_800BEFC4(void); extern void func_800BD82C(u8 *actor, SlotEntry *slot, s32 marker, s32 flag, SVECTOR *rot, VECTOR *trans); diff --git a/include/world/we_object0.h b/include/world/we_object0.h new file mode 100644 index 00000000..b88988eb --- /dev/null +++ b/include/world/we_object0.h @@ -0,0 +1,9 @@ +#ifndef WORLD_WE_OBJECT0_H +#define WORLD_WE_OBJECT0_H + +#include "common.h" +#include "overlay.h" + +extern s32 func_800987D8(void); + +#endif /* WORLD_WE_OBJECT0_H */ diff --git a/include/world/we_object1.h b/include/world/we_object1.h index 31d278fd..ab86fe28 100644 --- a/include/world/we_object1.h +++ b/include/world/we_object1.h @@ -6,7 +6,7 @@ #include "gamestate.h" #include "psxsdk/libgpu.h" #include "psxsdk/libgte.h" -#include "main.h" /* g_activeDrawEnv */ +#include "main.h" /* Projection scratch: worldPosToCell writes @c proj and returns @c angle. The trailing @c pad keeps the buffer 0x20 bytes (gcc reserves the full slot). @@ -104,8 +104,6 @@ extern POLY_FT4 D_800C8648[2]; /* double-buffered worldmap quad primitive */ extern void func_8009C528(s32 rc); extern void func_8009FEDC(u8 *work, u8 type); extern s32 func_80042634(s32 a); -extern void func_800A5F78(s32 screen); -extern void func_800A5FD4(s32 screen); extern void func_800A5D10(void); extern s32 getCurrentFieldMusic(void); /* defined u16 in btl_sfx; used full-width here */ extern void setSfxPitch(s32 idx, s32 val); @@ -125,17 +123,10 @@ extern void func_80039678(s32 a, s32 b, s32 c); extern void func_8009CDC4(s32 a, s32 b); extern void func_8009CE40(void); extern s32 func_8009D7D8(s32 a); -extern s32 func_800ACD38(MATRIX *out); extern void func_8003FD84(MATRIX *xform, VECTOR *in, VECTOR *out); -extern void func_800BC544(VECTOR *src, VECTOR *dst); extern void func_8009C478(s32 *src, s32 x, s32 y); extern CmdDesc *glyphAt(GlyphQuery *v, AngleSlot *out); extern s32 func_800BEC1C(s32 kind); -extern void func_8009D630(void); -extern void func_800B3FD4(Slot *slot, s32 arg); -extern void fadeOutSfxFast(s32 idx); -extern void renderAndUpdateDisplay(s32 frames); -extern s32 renderBattleDisplayList(s32 *colorTag); extern void sndSeqSetTempoAlt(s32 tempo); extern void sndSetMasterVolume(s32 vol); extern void sndCmdF1(void); @@ -144,4 +135,14 @@ extern void sndSeqStartPan(s32 a0, s32 a1, s32 a2, s32 a3); extern void sndSeqPlayPan7bit(s32 a0, s32 a1, s32 a2, s32 a3); extern void func_8004D604(POLY_FT4 *prim, s32 frame); +extern s32 func_800997E8(u16 *out); +extern void func_80099F78(void); +extern void func_8009A954(void); +extern void func_8009AEE4(s32 id); +extern void func_8009B954(s32 a, s32 b, s32 c); + +extern s32 func_8009B358(s32 slotIdx, s32 strIdx, u8 *text); + +extern s32 func_8009CC3C(void); + #endif /* WORLD_WE_OBJECT1_H */ diff --git a/include/world/we_object10.h b/include/world/we_object10.h index 0ebe18ef..270f395d 100644 --- a/include/world/we_object10.h +++ b/include/world/we_object10.h @@ -3,6 +3,7 @@ #include "common.h" #include "world.h" +#include "world/we_object3.h" #include "psxsdk/libgte.h" /** @brief 32-byte record used by func_800BE5F8's table walker. */ @@ -57,20 +58,14 @@ extern u8 *D_800C9E34; extern void func_800BAC84(u8 *p); extern s32 func_800BA870(u8 *p); -extern s32 func_800B0010(void); -extern void func_800AC0A0(s32 marker, VECTOR *position, SVECTOR *vec, s32 zero); extern void *func_80047CE4(void *dst, s32 c, u32 n); extern s32 func_800BEF6C(void); -extern s32 func_8009CC3C(void); extern void func_800AEB58(XformEntry *entry, XformGroup *group); extern void func_8009C5FC(s32 *data); -extern void func_800BC51C(VECTOR *src, VECTOR *dst); -extern void func_800BC544(VECTOR *src, VECTOR *dst); -extern ScriptOp *func_800AF004(u8 *base, s32 flag); -extern s32 func_8009B358(s32 slotIdx, s32 strIdx, u8 *text); -extern void func_8009D8A8(s32 a0); -extern void fadeOutSfxFast(s32 idx); -extern void renderAndUpdateDisplay(s32 frameCount); -extern s32 renderBattleDisplayList(s32 *colorTag); + +extern void func_800BEC60(u8 *flags); + +extern void func_800BF20C(CmdDesc *p, s32 kind, s32 arg); +extern void func_800BF2E8(GlyphHeader *p, s32 *ot, WorldPrimBank *pools); #endif /* WORLD_WE_OBJECT10_H */ diff --git a/include/world/we_object11.h b/include/world/we_object11.h new file mode 100644 index 00000000..74f8f3ab --- /dev/null +++ b/include/world/we_object11.h @@ -0,0 +1,11 @@ +#ifndef WORLD_WE_OBJECT11_H +#define WORLD_WE_OBJECT11_H + +#include "common.h" +#include "world.h" +#include "world/we_object3.h" + +extern void func_800BF80C(GlyphHeader *p, s32 *ot, WorldPrimBank *pools); +extern void func_800BFBFC(s32 kind); + +#endif /* WORLD_WE_OBJECT11_H */ diff --git a/include/world/we_object13.h b/include/world/we_object13.h index 2ee96342..62fc6af6 100644 --- a/include/world/we_object13.h +++ b/include/world/we_object13.h @@ -44,4 +44,6 @@ extern s32 func_800C4480(s32 src, s32 len, u32 *buf); /* Reset the streaming controller; returns its status word. */ extern s32 func_800C4450(void); +extern void func_800C4AE4(s32 a); + #endif /* WORLD_WE_OBJECT13_H */ diff --git a/include/world/we_object2.h b/include/world/we_object2.h index 5dbc0d12..4fe95c91 100644 --- a/include/world/we_object2.h +++ b/include/world/we_object2.h @@ -4,6 +4,7 @@ #include "common.h" #include "world.h" #include "psxsdk/libgte.h" +#include "psxsdk/libetc.h" typedef struct { s16 a; @@ -48,17 +49,8 @@ extern u16 D_800C5346; /* per-map yaw target (func_8009F6EC b extern s32 D_800C9730; /* GTE projection-plane distance (SetGeomScreen arg). */ extern s32 D_800D2448; /* world-ready gate flag (func_8009F6EC bit 0x10). */ -/* VSync is declared here with a void-returning view for this file's - * matching codegen (psxsdk/libetc.h's s32-returning prototype is not used). */ -extern void VSync(s32 mode); - -extern void func_800A5F78(s32 screen); -extern void func_800A5FD4(s32 screen); extern void func_80099EDC(s32 idx); -extern void func_800B3FD4(Slot *a0, s32 a1); extern void func_8009D630(void); -extern void renderAndUpdateDisplay(s32 mode); -extern s32 renderBattleDisplayList(s32 *colorTag); extern s32 func_800BD380(s16 *outLow, s16 *outHigh); extern s32 func_800BD2A0(s16 *outLow, s16 *outHigh); extern s32 func_800BD460(s16 *outLow, s16 *outHigh); @@ -78,4 +70,9 @@ extern void sndDisableReverb(u32 a); /* Defined in we_object2.c — shortest signed angular difference (0x1000 == 360°). */ extern s32 getAngleDelta(s32 a, s32 b); +extern void func_8009DB88(u8 *p); +extern void func_8009E5C8(VECTOR *pos, u8 *p, SVECTOR *ang, void *x); + +extern void func_8009D8A8(s32 a0); + #endif /* WORLD_WE_OBJECT2_H */ diff --git a/include/world/we_object3.h b/include/world/we_object3.h index 5495f418..83b7e8a4 100644 --- a/include/world/we_object3.h +++ b/include/world/we_object3.h @@ -102,10 +102,6 @@ extern s32 func_800A358C(s32 kind, SlotEntry *slot, SVECTOR *angles, s32 flag); code @p b (only b's low 16 bits are examined; D_800C4D20 == 0 force-passes). */ extern s32 func_800A45D8(u32 a, s32 b); -/* The seven entry points below are called from the world entry loop - * func_800987D8 (we_object0), which is still assembly: it reaches them - * through the linker rather than this header. */ - /* Per-frame world setup: advance the frame clock, run the renderers and flip the scene context. */ extern void func_800A01DC(s32 skipPresent); @@ -129,4 +125,92 @@ extern void initWorldDoubleBuffer(void); color matrix. */ extern void setupWorldRenderParams(void); +/* The primitive pools. Public because the world entry loop (we_object0) + is what points D_800C9720 at a bank each frame; the glyph renderers + then draw out of whichever one it selected. */ +typedef struct { + POLY_GT3 *cur; /* 0x00 */ + POLY_GT3 *base; /* 0x04 */ + POLY_GT3 *end; /* 0x08 */ +} Gt3Pool; /* 0x0C */ + +typedef struct { + POLY_FT3 *cur; /* 0x00 */ + POLY_FT3 *base; /* 0x04 */ + POLY_FT3 *end; /* 0x08 */ +} Ft3Pool; /* 0x0C */ + +typedef struct { + POLY_FT4 *cur; /* 0x00 */ + POLY_FT4 *base; /* 0x04 */ + POLY_FT4 *end; /* 0x08 */ +} Ft4Pool; /* 0x0C */ + +/** The three pools of one bank, one per primitive kind. Both banks are laid out + at start-up by @c func_800A246C, and the world entry loop (@c func_800987D8 + in we_object0) re-points @c D_800C9720 at one of them every frame: bank 1 + while the active scene context is the no-battle sentinel @c D_800CA040, + bank 0 otherwise. The glyph renderers then draw out of whichever it picked. + (Not @c D_800C53A4 — that one indexes the sprite record banks + @c D_800D2508.) */ +typedef struct { + Gt3Pool gt3; /* 0x00 */ + Ft3Pool ft3; /* 0x0C */ + Ft4Pool ft4; /* 0x18 */ +} WorldPrimBank; /* 0x24 */ + +extern WorldPrimBank D_800C9E88[2]; /**< The two banks. @c func_800A246C lays + them out; the world entry loop indexes + this array directly to choose one, and + everything else reaches the chosen bank + through @c D_800C9720. */ +extern WorldPrimBank *D_800C9720; /**< The bank the glyph renderers allocate + from this frame. The world entry loop + (@c func_800987D8) re-points it every + frame; we_object6 and we_object7 + read it. */ + +extern s32 D_800C972C; /**< Accumulated glyph-entry count. */ +extern s32 D_800C9ED0; /**< Pad 0's raw frame parameter. */ +extern SVECTOR D_800CA038; /**< Reference offset fed to the pool placer. */ +extern s32 D_800D2238; + +extern void func_800A5F78(s32 screen); + +extern void func_800A5FD4(s32 screen); + +/** + * @brief One placed world-map sprite produced by @c placeWorldSpriteFan (0x2C stride). + * + * @c pos is the final world position; @c cell receives the @c worldPosToCell + * projection; @c cellId/flag are the projected grid-cell id and a fixed marker. + * @note Field purpose partly uncertain — named from the access pattern. + */ +typedef struct { + VECTOR pos; /* 0x00 */ + SVECTOR cell; /* 0x10 — worldPosToCell output */ + u8 pad18[0x4]; /* 0x18 */ + CmdDesc *cmd; /* 0x1C — installed as the current descriptor D_800C4D64 */ + s16 cellId; /* 0x20 — worldPosToCell return */ + s16 flag; /* 0x22 — one of WORLD_SPRITE_* below */ + s16 angle; /* 0x24 — heading used to bias the camera track */ + s16 code; /* 0x26 — packed type | flag<<8 of the installed descriptor */ + u16 unk28; /* 0x28 — published to D_800C4D48; its readers are still asm */ + u8 pad2A[0x2]; /* 0x2A */ +} WorldSprite; /* 0x2C */ + +/** @c WorldSprite::flag states. */ +#define WORLD_SPRITE_FREE 0 /**< Slot unused. */ +#define WORLD_SPRITE_PENDING 1 /**< Re-probed this pass but matched no descriptor. */ +#define WORLD_SPRITE_PLACED 2 /**< Given a position this pass. */ +#define WORLD_SPRITE_CLAIMED 3 /**< Matched a glyph this frame. */ + +/** Sprites in one pool record: an anchor plus the four spread around it. */ +#define WORLD_FAN_SPRITES 5 + +/** A pool record: five sprites placed together as one fan. */ +typedef struct { + WorldSprite sprite[WORLD_FAN_SPRITES]; +} WorldSpriteRec; /* 0xDC */ + #endif /* WORLD_WE_OBJECT3_H */ diff --git a/include/world/we_object4.h b/include/world/we_object4.h index f635627c..4941bacf 100644 --- a/include/world/we_object4.h +++ b/include/world/we_object4.h @@ -6,9 +6,7 @@ #include "world.h" /* we_object4's public surface. Everything else the unit owns is private to - * src/world/we_object4.c and declared at the top of that file. The callers - * below are still assembly, so they reach these through the linker rather - * than this header -- it is here for when they are decompiled. */ + * src/world/we_object4.c. */ extern s32 D_800D2264; /**< Counter increment per update (read by we_object3, we_object6). */ @@ -23,7 +21,7 @@ extern void func_800A7CD0(s32 *block); /**< Load a VRAM row animation extern void func_800A8400(void); /**< Draw the map-view HUD layer (panel, stars, gradient). */ extern void func_800A8C1C(void); /**< Re-blend the world palette for the camera's position. */ extern void func_800A9300(void); /**< Draw the D_800D9CB0 particle pool. */ -extern void func_800A9F54(WorldPos *pos, s32 x, s32 y); /**< Draw the world-map inset mesh at @p pos. */ +extern void func_800A9F54(VECTOR *pos, s32 x, s32 y); /**< Draw the world-map inset mesh at @p pos. */ /** The camera-follow reference is written as a word but published as its low * half by we_object3, so both views need a name. */ @@ -46,4 +44,8 @@ extern void func_800AB2D4(VECTOR *pos); extern TILE_1 D_800D4FB0[2][96]; /**< Night-sky star pool, also primed by we_object5 (func_800A84D0). */ +/* Steps the texture-strip animations. @p ctx is passed by its only caller but + the body works entirely off globals and never reads it. */ +extern void func_800A7E74(BattleSceneCtx *ctx); + #endif /* WORLD_WE_OBJECT4_H */ diff --git a/include/world/we_object5.h b/include/world/we_object5.h index 3a2ef52e..7671a2ce 100644 --- a/include/world/we_object5.h +++ b/include/world/we_object5.h @@ -61,7 +61,6 @@ extern VECTOR D_800DD658; /* source position for func_800BC51C extern void func_800A84D0(void); extern s32 func_8003F9F4(CVECTOR *input, CVECTOR *cue, s32 w1, s32 w2, CVECTOR *out); -extern s32 func_8009CC3C(void); extern s32 func_800A4700(s32 a, s32 b); extern s32 func_800A475C(s32 a, s32 b); extern void func_800423DC(VECTOR *a, s32 *b_pos, VECTOR *out); @@ -69,15 +68,15 @@ extern void func_800423DC(VECTOR *a, s32 *b_pos, VECTOR *out); * the four packed screen points and @c outOTZ their average depth. */ extern void func_800ABEF0(SVECTOR *src, SVECTOR *rot, SVECTOR *trans, DVECTOR *outSXY, u32 *outOTZ); -extern void func_800ACC68(MATRIX *out_mat, SVECTOR *angles, - SVECTOR *rotBuf, SVECTOR *offset); extern void func_800B5C60(s32 ctx, s16 count, MATRIX *outMat, SVECTOR *outAngles, SVECTOR *rotBuf, u8 *xform, ActorRecord *recs); -extern void func_800BC51C(VECTOR *src, VECTOR *dst); -extern void func_800BC544(VECTOR *src, VECTOR *dst); /* Depth-cue a CVECTOR run into BGR555 halfwords (see the definition for the per-pixel blend and the STP-bit packing). */ extern void func_800ABDD8(CVECTOR *input, u16 *output, s32 z, s16 count); +extern s32 func_800AC0A0(s32 type, VECTOR *pos, SVECTOR *vec, u16 flags); + +extern void func_800AC2B8(void); + #endif /* WORLD_WE_OBJECT5_H */ diff --git a/include/world/we_object6.h b/include/world/we_object6.h index ef01922a..a40f26fa 100644 --- a/include/world/we_object6.h +++ b/include/world/we_object6.h @@ -2,9 +2,35 @@ #define WORLD_WE_OBJECT6_H #include "world.h" -#include "world/we_object2.h" /* getAngleDelta */ +#include "world/we_object3.h" +#include "world/we_object2.h" -/* Defined in this file (via INCLUDE_ASM). */ -extern void func_800ACC68(s32 a, WorldXformBlock *buf, u8 *p1, WorldXform *xform); +extern void func_800ACC68(MATRIX *outMat, SVECTOR *angles, SVECTOR *rotBuf, + SVECTOR *offset); + +extern void func_800AD698(SceneState *st, u8 *flags); +extern void func_800AE31C(u8 *flags); +extern s32 func_800AE518(u8 *flags); +extern void func_800AEEB0(u8 *flags, void *a, void *b, void *c); +extern void func_800B04CC(SVECTOR *ang, MATRIX *m, u8 *flags, s32 v); +extern void func_800B164C(SceneState *st, Slot *slot, u8 *flags, VECTOR *pos); +extern void func_800B18B8(u8 *flags, VECTOR *pos, SVECTOR *ang); +extern s32 func_800B1BCC(u8 *p); + +extern s32 func_800B0010(u32 kind); + +extern void func_800ACD38(MATRIX *outMat); + +/* Projects @p pos to screen space in @p screenOut and returns a status of + -1, 0 or 1. @p byteOut and @p halfOut are optional outputs; both are + NULL-checked. */ +extern s32 func_800B01A0(s16 viewY, s16 viewX, VECTOR *pos, SVECTOR *screenOut, + s8 *byteOut, s16 *halfOut); + +extern void func_800ACDC4(GlyphHeader *p, BattleSceneCtx *ctx, WorldPrimBank *pools); + +extern ScriptOp *func_800AF004(u8 *base, s32 flag); + +extern s32 func_800B21EC(WorldSpriteRec *rec, s32 mode, s32 c, s32 d); #endif /* WORLD_WE_OBJECT6_H */ diff --git a/include/world/we_object7.h b/include/world/we_object7.h index 0b8de17f..4df2a8a1 100644 --- a/include/world/we_object7.h +++ b/include/world/we_object7.h @@ -8,21 +8,18 @@ * @brief 0x34-byte tracking entry — one world-space target with screen-space * projection state and a relative neighbour link. * - * Populated by @c func_800B01A0 (which fills the screen-space @c posX/Y/Z - * fields plus @c unk30 and @c unk2C from the world transform pipeline) and + * Populated by @c func_800B01A0 (which fills @c screen plus @c unk30 and + * @c unk2C from the world transform pipeline) and * consumed by @c func_800B3868 to compute pitch/yaw to a chained target. */ typedef struct { - u8 pad00[0x10]; - u16 posX; /**< 0x10: projected screen-space X. */ - u16 posY; /**< 0x12: projected screen-space Y. */ - u16 posZ; /**< 0x14: projected screen-space Z. */ - u8 pad16[0x02]; + VECTOR pos; /**< 0x00: world position; func_800B01A0 projects it. */ + SVECTOR screen; /**< 0x10: projected screen-space position (x, y, z). */ s16 unk18; /**< 0x18: roll/twist angle — zeroed when target valid. */ s16 yaw; /**< 0x1A: yaw angle to target (atan2 + 0x800 bias). */ s16 pitch; /**< 0x1C: pitch angle to target. */ u8 pad1E[0x0E]; - u8 unk2C[0x02]; /**< 0x2C: scratch byte pair filled by func_800B01A0. */ + s16 unk2C; /**< 0x2C: scratch halfword filled by func_800B01A0. */ s8 targetIdx; /**< 0x2E: relative index of the chained target entry (0 = none). */ s8 status; /**< 0x2F: -1 = uninitialized, 1 = visible/active. */ s8 unk30; /**< 0x30: secondary status byte. */ @@ -41,13 +38,18 @@ typedef struct { extern u8 *D_800C96C8; /* func_8009B358/func_8009B550 are defined in we_object1, func_8009D8A8 in - * we_object2; addItemToInventory and the func_800A5DC8/func_800B01A0/ - * func_80041E84 helpers are main-binary. Caller-local prototypes. */ -extern s8 func_800B01A0(s16 viewY, s16 viewX, TrackEntry *e, u16 *posOut, s8 *unk30Out, u8 *unk2COut); + * we_object2; addItemToInventory, func_800A5DC8 and func_80041E84 are + * main-binary. Caller-local prototypes. */ extern s32 func_80041E84(s32 y, s32 x); -extern s32 func_8009B358(s32 slotIdx, s32 strIdx, u8 *text); extern void func_8009B550(s32 a0, s32 a1, s32 a2, s32 a3, s32 a4, s32 a5, s32 a6); -extern void func_8009D8A8(s32 a0); extern void addItemToInventory(s32 itemId, s32 count); +extern s32 func_800B4AA0(void); +extern void func_800B56A0(void); +extern void func_800B7240(s8 v); +extern void func_800B881C(void); +extern void func_800B893C(void); + +extern void func_800B3FD4(Slot *slot, s32 mode); + #endif /* WORLD_WE_OBJECT7_H */ diff --git a/include/world/we_object8.h b/include/world/we_object8.h new file mode 100644 index 00000000..3dbccc87 --- /dev/null +++ b/include/world/we_object8.h @@ -0,0 +1,13 @@ +#ifndef WORLD_WE_OBJECT8_H +#define WORLD_WE_OBJECT8_H + +#include "common.h" +#include "world.h" + +extern void func_800B8C70(void); +extern s32 func_800B99A4(u16 *p); /**< Picks a world cell and checks its + terrain glyph; one of the two world + battle triggers. */ +extern void func_800B9D38(void); + +#endif /* WORLD_WE_OBJECT8_H */ diff --git a/include/world/we_object9.h b/include/world/we_object9.h index d6a94f49..69b17ebd 100644 --- a/include/world/we_object9.h +++ b/include/world/we_object9.h @@ -5,26 +5,13 @@ #include "world.h" #include "psxsdk/libgte.h" +/* Particle source: position + velocity (with 4-byte gap between). Stride 0x28. + func_800AC0A0 takes these two as VECTOR/SVECTOR; the spawner reads .vy of + each as the heading and .vz of the velocity as the height. */ typedef struct { - u32 pad0; - AngleSlot pos; - u32 pad8; - u32 padC; -} PosDesc; - -/* 8-byte unaligned velocity (copied via lwl/lwr to spawner's slot[0x18..0x1F]) */ -typedef struct { - u16 pad0; - u16 angle; - u16 height; - u16 pad6; -} Velocity; - -/* Particle source: position + velocity (with 4-byte gap between). Stride 0x28. */ -typedef struct { - PosDesc pos; - u32 pad10; - Velocity vel; + VECTOR pos; + u32 pad10; + SVECTOR vel; } ParticleSource; typedef struct { @@ -95,8 +82,6 @@ extern s32 D_800C971C; /* Per-scene angle bias applied to a placed sprite fan. */ extern s32 func_800BC5E0(s32 ctx); -extern s32 func_8009CC3C(void); -extern s32 func_800AC0A0(s32 type, PosDesc *pos, Velocity *vel, s32 flags); extern void func_800BFFEC(void); extern void func_800C2C00(s32 a, s32 b, s32 c, s32 d, s32 e, U64 *f, s32 g, U64 *h); extern u8 *func_800BC8D8(u8 *buf, s32 magicId); @@ -106,4 +91,11 @@ extern u8 *getStatName(s32 statId); extern u8 *func_800BCE74(u8 *buf, s32 statId); extern s32 func_800B00D8(s32 a); +extern void func_800BB150(Slot *slot); +extern void func_800BB4E8(void); + +extern void func_800BC51C(VECTOR *src, VECTOR *dst); + +extern void func_800BC544(VECTOR *src, VECTOR *dst); + #endif /* WORLD_WE_OBJECT9_H */ diff --git a/src/battle/bc_object1.c b/src/battle/bc_object1.c index 94be1120..614cd9a9 100644 --- a/src/battle/bc_object1.c +++ b/src/battle/bc_object1.c @@ -1,4 +1,5 @@ #include "common.h" +#include "main.h" #include "battle.h" #include "gf.h" #include "battle/bc_object1.h" @@ -37,7 +38,6 @@ extern void func_800D0F74(void); extern SoundCmd* func_800B8564(s16, u8); /* bc_object9.c */ -extern volatile s16 D_8005F146; void func_80099D30(void) { s32 i; diff --git a/src/world/we_object0.c b/src/world/we_object0.c index 9b2930ee..565521c2 100644 --- a/src/world/we_object0.c +++ b/src/world/we_object0.c @@ -1,9 +1,472 @@ #include "common.h" +#include "gamestate.h" +#include "btl_color.h" +#include "psxsdk/libgpu.h" +#include "psxsdk/libgte.h" +#include "psxsdk/libetc.h" +#include "world.h" +#include "world/we_object0.h" +#include "world/we_object1.h" +#include "world/we_object2.h" +#include "world/we_object3.h" +#include "world/we_object4.h" +#include "world/we_object5.h" +#include "world/we_object6.h" +#include "world/we_object7.h" +#include "world/we_object8.h" +#include "world/we_object9.h" +#include "world/we_object10.h" +#include "world/we_object13.h" +#include "main.h" +#include "thread.h" +#include "btl_anim.h" -/* The world overlay's entry unit: one ~4.1KB function, called from main.s as - * the overlay's main loop. It sat inside the leading rodata blob until - * 2026-08-31, hidden from the split — which is why its callees (the render - * callback registration, the object-list machinery) once looked like dead - * islands. */ +#define SP_SAVE_SCRATCH(slot) \ + asm volatile("addu $t0, %0, $zero\n\t" \ + "sw $sp, 0($t0)\n\t" \ + "addiu $t0, $t0, -4\n\t" \ + "addu $sp, $t0, $zero" : : "r"(slot) : "$8") -INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object0", func_800987D8); +#define SP_RESTORE() \ + asm volatile("addiu $sp, $sp, 4\n\t" \ + "lw $sp, 0($sp)") + +/* Screen size, used to calculate where to place the maps on screen. */ +#define WORLD_SCREEN_W 320 +#define WORLD_SCREEN_H 224 + +/* Frames the streamer is given to settle before the loop starts drawing; + * mode 4 (a warm re-entry) gets the short count. */ +#define WORLD_SETTLE_FRAMES 0x18 +#define WORLD_SETTLE_FRAMES_WARM 8 + +/* D_800C9ED0 holding this value for two consecutive frames ends the loop. */ +#define WORLD_STALL_CODE 0x90F +#define WORLD_STALL_FRAMES 2 + +/** Map display mode held in @c D_800C4D28. Mutually exclusive modes, + * not flags: the loop dispatches on the exact value. */ +typedef enum { + MAP_DISPLAY_OFF = 0, // No map at all + MAP_DISPLAY_GLOBE = 1, // Globe in the bottom right corner + MAP_DISPLAY_TRANSPARENT = 2, // Transparent square map in bottom right corner + MAP_DISPLAY_FULL = 3 // Full screen map with hand pointer and locations etc. +} MapDisplayMode; + +/* Edge-detected bits of the world pad word @c D_800D2278, tested as + cur & (cur ^ prev) -- "went set this frame". Which physical buttons these + are is not established, so each is named for what the loop does when it + fires; the pad word is FF8's own, not the raw PSX button mask. */ +#define WORLD_PAD_HANDOFF 0x20 /* runs the scene-change checks */ +#define WORLD_PAD_REDRAW 0x800 /* re-runs setupWorldRender() */ + +/* Columns the linear tile index from func_800A5DC8 decomposes into. */ +#define MAP_DISPLAY_COLS 128 + +/* Screen position of the corner globe; the other modes derive theirs from + the current screen size instead. */ +#define MAP_DISPLAY_GLOBE_X 0x104 +#define MAP_DISPLAY_GLOBE_Y 0xB4 + +/* The transparent map sits this far in from the screen's right/bottom edge. */ +#define MAP_DISPLAY_TRANSPARENT_DX 0x86 +#define MAP_DISPLAY_TRANSPARENT_DY 0x64 + +/* The full-screen map is this size, centred on the screen. */ +#define MAP_DISPLAY_FULL_W 0x100 +#define MAP_DISPLAY_FULL_H 0xC0 + +/* Globals this unit is the first C code to touch. Nothing else in the tree + names them yet, so they are file-local declarations here rather than a + header's public surface. */ +extern s32 D_800C4D08; /**< Hand-off action code published on the way out. */ +extern s32 D_800C4D28; /**< Map display mode; see MAP_DISPLAY_*. */ +extern s32 D_800C4D80; /**< Last render-callback status. */ +extern s32 D_800C4F0C[]; +extern s32 D_800C4FC4; /**< Frames left in the settle countdown. */ +extern SVECTOR D_800C5400; +extern MATRIX D_800C5408; +extern s32 D_800C8638; /**< Frames spent waiting for the streamer. */ +extern s32 D_800C973C; +extern u8 D_800C9762; +extern u8 *D_800C9768; +extern s32 D_800C97D8; +extern s32 D_800C9828[]; +extern SVECTOR D_800C9E60; /**< Scratch copy of the camera's second angle triple. */ +extern u8 *D_800C9E74; +extern u8 *D_800C9E78; +extern s32 D_800C9E7C; +extern s32 *D_800C9FEC; +extern s32 D_800C9FF0[]; +extern s32 D_800D2130[]; +extern s32 *D_800D2230; +extern s32 *D_800D2268; +extern s32 D_800D2270; +extern s32 D_800D2290[]; +extern u8 D_800D23DC; /**< Same byte as @c D_800D23D8[4]. */ +extern SVECTOR D_800D2450; +extern s32 *D_800D245C; + +extern Slot D_800785D8; /**< Slot-state record the loop publishes at D_800D226C. */ + +s32 func_800987D8(void) +{ + s32 trigger; + s8 code; + s32 transparentTile; + s32 fullMapTile; + s16 mapX; + s16 mapY; + s32 reqKind; + s32 padBank; + s32 mode; + s32 cmd; + s32 firstPass; + s32 stall; + u16 sceneCmd; + u16 hitCmd; + u16 objMarker; + s32 result; + + firstPass = 1; + stall = 0; + result = 0; + + if (D_80082C8C.mode == 2) { + func_8009A7C0(); + func_8009CAE0(D_800C4F2C, NULL); + while (D_8005F146 == 4) { + } + } + func_800C4644(); + sndResetState(); + D_800C97EA = WORLD_SCREEN_W; + D_800C97E8 = WORLD_SCREEN_H; + D_800D226C = &D_800785D8; + if (D_80082C8C.mode != 0) { + D_80082C8C.cmd = D_800D226C->scene.cmd; + } else { + D_800D226C->scene = D_80082C8C; + } + D_800D2238 = 0; + D_800C971C = 0; + D_800C9762 = 1; + func_8009CCC8(func_80042634(-1)); + func_8009C8CC(func_80042634(-1)); + func_8009CCDC(0); + InitGeom(); + setupWorldRenderParams(); + initWorldDoubleBuffer(); + func_8009D0F0(); + + if (D_80082C8C.mode != 4) { + func_8009A638(); + func_800B7178(); + func_800AD688(); + func_800BC44C(); + if (D_80082C8C.mode != 2) { + func_8009A7C0(); + func_8009CAE0(D_800C4F2C, func_800A5D10); + } + func_8009A954(); + func_800AD698(&D_80082C8C, D_800D23D8); + func_80099C84(); + func_800B7240(D_80082C8C.unk02); + func_800AEEB0(D_800D23D8, D_800D2290, D_800D2130, D_800C9FF0); + func_800A581C(); + loadImageScript(D_800C9FEC); + loadImageScript(D_800D2268); + D_800D2270 = D_800C9E7C; + func_80099B48(D_800D23D8, D_800D245C); + func_800A7CD0(D_800D2230); + func_800BE7FC(D_800D23D8, D_800C9768); + D_800C9714 = 1; + D_800D2458 = 1; + func_8009CB70(D_800D23D8, &D_800C4F0C, D_800C9E74, D_800C9E78); + func_8009CC34(); + + if (D_800C4FBC != 0) { + if (sndGetStatus() != 0) { + while (sndGetMaxVolume(1) != 0) { + func_80042634(2); + } + } + sndCmdC0(0, 0); + sndCmd11(0); + func_80042634(2); + sndProcessAudio(D_800C4FC0, 1); + func_8009CDFC(D_800C4FBC, 0x7F); + } else { + D_800C4D88 = pickAudioTransition(D_80082C8C.cmd, D_800D23D8[0x6A]); + } + + func_800A40C0(); + func_800AE31C(D_800D23D8); + func_800ABD54(); + func_800ABC98(); + func_800A9ED4(); + func_800A9254(); + func_800B164C(&D_80082C8C, D_800D226C, D_800D23D8, &D_800C9868); + setupWorldMapView(&D_800C9868, D_800C9770, &D_800D2390, &D_800C9828); + D_800C9858 = D_800C9868; + D_800C97F8[0] = D_800C9770[0]; + D_800C9858.vz -= 0x100; + func_800AC468(D_800C9770, &D_800D2390, &D_800C9828, 0); + func_8009C070(); + func_800BC570(&D_800D2290, &D_800D2130, &D_800C9FF0); + + while ((D_800C4D88 >> 31 & 1) < (D_800C4D80 = func_800A47A4())) { + func_80042634(2); + func_800A5D10(); + D_800C8638++; + } + + func_8009C1A4(); + func_800BEECC(); + D_800C4D54 = (D_800C4D38 == 0x31) ? 5 : 0; + D_800C4D58 = 0; + func_800B881C(); + if (D_800C4D88 >= 0) { + D_800C4D84 = 1; + do { + func_80042634(2); + func_8009AEE4(D_800C4D88); + } while (D_800C4D84 != 0); + } + } + + func_800A64DC(); + func_800A6BE0(); + func_800A246C(); + SetGeomScreen(D_800C9730); + setCameraVibrateIntensity(0x1000); + activateBattleAnim(0); + func_80042634(0); + SetDispMask(1); + + while (1) { + func_800A01DC(firstPass); + + D_800C9720 = (D_800D244C == &D_800CA040) ? &D_800C9E88[1] : &D_800C9E88[0]; + g_activeDrawEnv = &D_800D244C->drawEnv; + + if (firstPass) { + D_800C4FC4 = (D_80082C8C.mode == 4) ? WORLD_SETTLE_FRAMES_WARM + : WORLD_SETTLE_FRAMES; + } + if (D_800C4FC4 != 0) { + func_8009A4DC(D_800C4FC4); + D_800C4FC4--; + } + + D_800C9E60 = D_800C9770[1]; + if (D_800C4FC4 == 0) { + func_8009DB88(D_800C9758); + } else { + func_8009FEDC(D_800C9758, 1); + } + func_800BE8B0(D_800D23D8, &D_800C9868, D_800C9770); + func_8009E5C8(&D_800C9868, D_800C9758, D_800C9770, &D_800D2390); + func_8009FEBC(&D_800C9868, D_800C9770); + func_800AC468(D_800C9770, &D_800D2390, &D_800C9828, 0); + func_8009C070(); + func_800A8C1C(); + func_8009FE80(&D_800C5400, &D_800C5408); + func_800A8270(&D_800D2450); + + trigger = func_800AE518(D_800D23D8); + if (trigger != 0) { + code = -1; + if (D_800D23D8[0] == 1 || D_800D23D8[0] == 2) { + code = D_800D23D8[4]; + } else if (D_800D23D8[0] == 3 && (trigger & 1)) { + code = func_800BEB84(0); + } else if (D_800D23D8[0] == 4 && (trigger & 2)) { + code = func_800BEB84(1); + } + if (code >= 0) { + D_80082C8C.mode = 1; + D_80082C8C.unk02 = code; + D_80082C8C.unk03 = -1; + D_80082C8C.cmd = D_800C4D38; + func_800B3FD4(D_800D226C, 1); + D_800C987C = 0; + D_800C4D08 = D_800D23DC; + func_8009D954(); + break; + } + } + + func_800B8C70(); + D_800C9720->ft3.base = D_800C9720->ft3.cur; + D_800C9720->ft4.base = D_800C9720->ft4.cur; + if (D_800D23D8[0] != 12) { + func_800B04CC(D_800C9770, &D_800C9838, D_800D23D8, D_800C973C); + if (D_800D23D8[0] != 12) { + func_800BB4E8(); + func_800A9300(); + } + } + if (D_800C4FC4 <= 0) { + func_800B4AA0(); + } + func_800BEED4(); + func_800BC544(&D_800C9868, &D_800C9748); + + D_800C97D8 = 0; + D_800C972C = 0; + D_800D2448 = 0; + D_800C9720->gt3.base = D_800C9720->gt3.cur; + + SP_SAVE_SCRATCH(getScratchAddr(255)); + if (D_800D23D8[0] != 12) { + renderWorldMapFrame(); + } + SP_RESTORE(); + + D_800C4D50 = SquareRoot0(D_800C9E38.vx * D_800C9E38.vx + + D_800C9E38.vy * D_800C9E38.vy + + D_800C9E38.vz * D_800C9E38.vz); + D_800C4D4C = SquareRoot0(D_800CA038.vx * D_800CA038.vx + + D_800CA038.vy * D_800CA038.vy + + D_800CA038.vz * D_800CA038.vz); + + func_800B18B8(D_800D23D8, &D_800C9868, D_800C9770); + func_800B893C(); + func_800BEC60(D_800D23D8); + func_800B9D38(); + func_800BB150(D_800D226C); + + if (D_800C4D84 != 0) { + func_8009AEE4(D_800C4D88); + } else { + D_800C4D80 = func_800A47A4(); + if (D_800C4D80 == 0 && D_800C4D88 >= 0) { + D_800C4D84 = 1; + } + } + + if (D_800C4FC4 <= 0) { + reqKind = func_800B85DC(&sceneCmd); + if (reqKind == 1) { + func_8009C294(sceneCmd); + break; + } + if (reqKind == 3) { + func_8009D44C(sceneCmd); + break; + } + } + + if (D_800C4FC4 <= 0) { + if (D_800D23D8[0] == 0) { + if (func_800BC46C(&hitCmd)) { + func_8009C294(hitCmd); + break; + } + if (func_800997E8(&objMarker) || func_800B99A4(&objMarker)) { + func_8009D44C(objMarker); + break; + } + } + } + + if (D_800C4FC4 <= 0) { + func_800BE9F8(func_800B1BCC(D_800D23D8)); + func_800B56A0(); + + padBank = D_800C4D04; + if ((D_800D2278[padBank] & (D_800D2278[padBank] ^ D_800D2278[(padBank + 1) % 2]) & WORLD_PAD_HANDOFF) != 0) { + if (((u32)D_800C4D38 < 0xA || D_800C4D38 == 0x80) && + D_800C4D88 == -1 && D_800D23D8[0] == 0) { + func_8009D3F4(); + func_8009D954(); + break; + } + + padBank = D_800C4D04; + if ((D_800D2278[padBank] & (D_800D2278[padBank] ^ D_800D2278[(padBank + 1) % 2]) & WORLD_PAD_HANDOFF) != 0) { + mode = D_800C4D38; + if ((mode == 0x30 || mode == 0x32) && + D_800C4D88 == -1 && D_800D23D8[0] == 0) { + func_8009C294(mode == 0x32 ? 0x2C : 0x41); + func_8009D954(); + break; + } + } + } + + if (D_800C9ED0 == 0x90F) { + stall++; + } else { + stall = 0; + } + if (stall >= 2) { + func_8009D630(); + result = 1; + func_8009D954(); + break; + } + + padBank = D_800C4D04; + if ((D_800D2278[padBank] & (D_800D2278[padBank] ^ D_800D2278[(padBank + 1) % 2]) & WORLD_PAD_REDRAW) != 0 && + D_800C4D84 == 0 && D_800C4D88 == -1) { + setupWorldRender(); + } + } + + cmd = D_800C4D38; + if ((u32)cmd < 0xA || cmd == 0x80 || (u32)(cmd - 0x20) < 9 || + cmd == 0x84 || cmd == 0x31) { + func_800C4AE4(D_800C4D50 / 8); + } + + func_800A63F0(); + func_800A7590(D_800D244C); + func_800A735C(D_800D244C); + func_800A6A74(D_800D244C); + + if (D_800C4D28 == MAP_DISPLAY_GLOBE) { + SP_SAVE_SCRATCH(getScratchAddr(255)); + func_800AB540(MAP_DISPLAY_GLOBE_X, MAP_DISPLAY_GLOBE_Y, (u32)(D_800D23D8[0] - 1) >= 4); + func_800A9F54(&D_800C9868, MAP_DISPLAY_GLOBE_X, MAP_DISPLAY_GLOBE_Y); + SP_RESTORE(); + } else if (D_800C4D28 == MAP_DISPLAY_TRANSPARENT) { + transparentTile = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); + mapX = D_800C97EA - MAP_DISPLAY_TRANSPARENT_DX; + mapY = D_800C97E8 - MAP_DISPLAY_TRANSPARENT_DY; + func_800AB540(transparentTile % MAP_DISPLAY_COLS + mapX, transparentTile / MAP_DISPLAY_COLS + mapY, (u32)(D_800D23D8[0] - 1) >= 4); + func_8009C8E0(mapX, mapY, 1, 1); + } else if (D_800C4D28 == MAP_DISPLAY_FULL) { + fullMapTile = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); + mapX = (D_800C97EA - MAP_DISPLAY_FULL_W) >> 1; + mapY = (D_800C97E8 - MAP_DISPLAY_FULL_H) >> 1; + func_800AB540((fullMapTile % MAP_DISPLAY_COLS) * 2 + mapX, (fullMapTile / MAP_DISPLAY_COLS) * 2 + mapY, 1); + func_8009B954(mapX, mapY, 0); + func_8009C8E0(mapX, mapY, 2, 0); + } + + if (D_800D23D8[0] != 0xC) { + func_800A8400(); + } + firstPass = 0; + func_80099F78(); + func_800AD690(); + func_8009B748(); + renderAndUpdateDisplay(D_800D2264); + renderBattleDisplayList(&D_800D244C->primList[BSC_COLORTAG_IDX]); + } + + func_800A9E24(D_800D244C); + func_8009C6CC(30, 0); + func_800C4450(); + flushCdAndWait(); + func_800A6358(); + deactivateBattleCmd(-1); + func_80027448(); + func_80048C50(0); + func_800488D4(3); + func_8009AD3C(); + + return result; +} diff --git a/src/world/we_object1.c b/src/world/we_object1.c index e7dfe12c..1b65fadc 100644 --- a/src/world/we_object1.c +++ b/src/world/we_object1.c @@ -5,11 +5,17 @@ #include "world.h" #include "gamestate.h" #include "world/we_object1.h" -#include "world/we_object2.h" /* getAngleDelta */ -#include "world/we_object3.h" /* func_800A2D50 */ +#include "world/we_object2.h" +#include "world/we_object3.h" #include "psxsdk/libapi.h" #include "psxsdk/libgpu.h" #include "psxsdk/libc.h" +#include "btl_sfx.h" +#include "btl_anim.h" +#include "world/we_object9.h" +//#include "world/we_object6.h" // Deliberately not included for matching reasons, original code likely forgot to include this + + INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object1", func_800997E8); @@ -633,8 +639,6 @@ void func_8009BFA0(DVECTOR *coords, s16 count) { } -/* func_800ACD38 is void func_800ACD38(s32) in we_object6; this call site sees an - int-returning function (K&R-era view), which the matching codegen requires. */ /** * @brief Compose the world-map view transform and the resulting camera position. @@ -670,8 +674,8 @@ void func_8009C070(void) { func_8003FD84(&D_800C9838, &localA, &localB); } D_800D23C0.z = 0; - D_800D23C0.x = D_800C9868.x + localB.vx; - D_800D23C0.y = D_800C9868.y + localB.vz; + D_800D23C0.x = D_800C9868.vx + localB.vx; + D_800D23C0.y = D_800C9868.vy + localB.vz; SetRotMatrix(&D_800C9838); SetTransMatrix(&D_800C9838); } diff --git a/src/world/we_object10.c b/src/world/we_object10.c index ad1b01e4..73fe0970 100644 --- a/src/world/we_object10.c +++ b/src/world/we_object10.c @@ -2,10 +2,19 @@ #include "battle.h" #include "gamestate.h" #include "world.h" +#include "world/we_object5.h" +#include "world/we_object6.h" #include "world/we_object10.h" -#include "world/we_object3.h" /* worldPosToCell */ +#include "world/we_object3.h" +#include "btl_sfx.h" +#include "btl_anim.h" +#include "world/we_object1.h" +#include "world/we_object9.h" + + + + -/* Defined below; the reset path above is its only caller. */ static void func_800BEFEC(u8 *base); @@ -13,17 +22,18 @@ static void func_800BEFEC(u8 *base); * @brief Search @c D_800DBFB8 for the slot whose @c marker matches the * value returned by @c func_800B0010. * - * Calls @c func_800B0010 to get a marker byte, then linearly scans the + * Classifies @p kind via @c func_800B0010 to get a marker byte, then scans * first @c D_800C5B50 entries of @c D_800DBFB8 for the first slot whose * @c marker matches. Returns the slot index or @c -1 if not found. * - * Twin of @c func_800BD754 — same scan loop but the search key is - * sourced from @c func_800B0010 instead of an explicit argument. + * Twin of @c func_800BD754 — same scan loop, but the search key comes + * from classifying @p kind through @c func_800B0010. * + * @param kind Scene/map kind to classify. * @return Matching slot index, or @c -1 on no match. */ -s32 func_800BD6EC(void) { - s32 target = func_800B0010(); +s32 func_800BD6EC(u32 kind) { + s32 target = func_800B0010(kind); s32 i = 0; s32 count = D_800C5B50; if (count > 0) { diff --git a/src/world/we_object2.c b/src/world/we_object2.c index 3798edf9..201f1afb 100644 --- a/src/world/we_object2.c +++ b/src/world/we_object2.c @@ -8,6 +8,7 @@ #include "world/we_object2.h" #include "world/we_object3.h" #include "world/we_object13.h" +#include "btl_anim.h" /** * @brief Walk a world-engine image script and blit each record to VRAM. @@ -754,11 +755,11 @@ INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object2", func_8009F594); * - @c 0x1: projection distance @c D_800C9730 (±8), then @c SetGeomScreen. * - @c 0x2: zoom/scale @c D_800C4D30 (±0x80). * - @c 0x4: set @c D_800C4D40 / @c D_800C4D44 from the map id (immediate, no step). - * - @c 0x8: yaw @c D_800D2390.tail.angle — shortest-arc angle step (±0x20). - * - @c 0x10: pitch @c D_800D2390.tail.unk0 (±0x10); for map 0x32 the target is + * - @c 0x8: yaw @c D_800D2390.tail.vy — shortest-arc angle step (±0x20). + * - @c 0x10: pitch @c D_800D2390.tail.vx (±0x10); for map 0x32 the target is * @c -D_800C97F4 / 24 - 0x100. - * - @c 0x20: per-map scroll triple element [2] → @c D_800D2390.head.unk4 (±0x200). - * - @c 0x80: per-map scroll triple element [1] → @c D_800D2390.head.angle (±0x200). + * - @c 0x20: per-map scroll triple element [2] → @c D_800D2390.head.vz (±0x200). + * - @c 0x80: per-map scroll triple element [1] → @c D_800D2390.head.vy (±0x200). * * @c D_800C4D38 is the map id selecting targets; @c D_800C4D3C is a secondary * selector. Field roles are partly inferred. @@ -854,17 +855,17 @@ void func_8009F6EC(void) { } else { target = D_800D239A; } - cur = D_800D2390.tail.angle; + cur = D_800D2390.tail.vy; raw = target - cur; d = (s16)raw; if ((d < 0 ? -d : d) >= 0x21) { if ((u16)(raw - 1) < 0x7FF || d < -0x7FF) { - D_800D2390.tail.angle = cur + 0x20; + D_800D2390.tail.vy = cur + 0x20; } else { - D_800D2390.tail.angle = cur - 0x20; + D_800D2390.tail.vy = cur - 0x20; } } else { - D_800D2390.tail.angle = target; + D_800D2390.tail.vy = target; D_800C4D2C ^= 0x8; } } @@ -886,14 +887,14 @@ void func_8009F6EC(void) { } else if (d3c == 1) { target = D_800C5344; } - cur = D_800D2390.tail.unk0; + cur = D_800D2390.tail.vx; d = (s16)(cur - target); if (d < -0x10) { - D_800D2390.tail.unk0 = cur + 0x10; + D_800D2390.tail.vx = cur + 0x10; } else if (d >= 0x11) { - D_800D2390.tail.unk0 = cur - 0x10; + D_800D2390.tail.vx = cur - 0x10; } else { - D_800D2390.tail.unk0 = target; + D_800D2390.tail.vx = target; D_800C4D2C ^= 0x10; } if ((u32)D_800C4D38 < 0xA || D_800C4D38 == 0x80) { @@ -928,14 +929,14 @@ void func_8009F6EC(void) { buf[2] = D_800C5354[2]; } target = sp10[2]; - cur = D_800D2390.head.unk4; + cur = D_800D2390.head.vz; d = (s16)(cur - target); if (d < -0x200) { - D_800D2390.head.unk4 = cur + 0x200; + D_800D2390.head.vz = cur + 0x200; } else if (d >= 0x201) { - D_800D2390.head.unk4 = cur - 0x200; + D_800D2390.head.vz = cur - 0x200; } else { - D_800D2390.head.unk4 = target; + D_800D2390.head.vz = target; D_800C4D2C ^= 0x20; } } @@ -964,14 +965,14 @@ void func_8009F6EC(void) { sp18[2] = D_800C5354[2]; } target = sp18[1]; - cur = D_800D2390.head.angle; + cur = D_800D2390.head.vy; d = (s16)(cur - target); if (d < -0x200) { - D_800D2390.head.angle = cur + 0x200; + D_800D2390.head.vy = cur + 0x200; } else if (d >= 0x201) { - D_800D2390.head.angle = cur - 0x200; + D_800D2390.head.vy = cur - 0x200; } else { - D_800D2390.head.angle = target; + D_800D2390.head.vy = target; D_800C4D2C ^= 0x80; } } diff --git a/src/world/we_object3.c b/src/world/we_object3.c index 6f2ff801..3fcc0a07 100644 --- a/src/world/we_object3.c +++ b/src/world/we_object3.c @@ -4,8 +4,11 @@ #include "world/we_object1.h" #include "world/we_object3.h" #include "world/we_object4.h" -#include "world/we_object5.h" /* D_800D23D0 */ -#include "world/we_object9.h" /* func_800BC5E0 */ +#include "world/we_object5.h" +#include "world/we_object6.h" +#include "world/we_object10.h" +#include "world/we_object11.h" +#include "world/we_object9.h" #include "thread.h" /* ---- private to renderWorldMapFrame ------------------------------------- @@ -71,34 +74,6 @@ extern s32 D_800D34E8; /** World-engine mode flags; bit 0 picks the alternate code table. */ extern u16 D_800D241E; -/* None of the declarations below are referenced outside this unit either. */ - -/** - * @brief One placed world-map sprite produced by @c placeWorldSpriteFan (0x2C stride). - * - * @c pos is the final world position; @c cell receives the @c worldPosToCell - * projection; @c cellId/flag are the projected grid-cell id and a fixed marker. - * @note Field purpose partly uncertain — named from the access pattern. - */ -typedef struct { - VECTOR pos; /* 0x00 */ - SVECTOR cell; /* 0x10 — worldPosToCell output */ - u8 pad18[0x4]; /* 0x18 */ - CmdDesc *cmd; /* 0x1C — installed as the current descriptor D_800C4D64 */ - s16 cellId; /* 0x20 — worldPosToCell return */ - s16 flag; /* 0x22 — one of WORLD_SPRITE_* below */ - s16 angle; /* 0x24 — heading used to bias the camera track */ - s16 code; /* 0x26 — packed type | flag<<8 of the installed descriptor */ - u16 unk28; /* 0x28 — published to D_800C4D48; its readers are still asm */ - u8 pad2A[0x2]; /* 0x2A */ -} WorldSprite; /* 0x2C */ - -/** @c WorldSprite::flag states. */ -#define WORLD_SPRITE_FREE 0 /**< Slot unused. */ -#define WORLD_SPRITE_PENDING 1 /**< Re-probed this pass but matched no descriptor. */ -#define WORLD_SPRITE_PLACED 2 /**< Given a position this pass. */ -#define WORLD_SPRITE_CLAIMED 3 /**< Matched a glyph this frame. */ - /** @brief Probe vector: three unsigned halfword components plus padding. * * Unsigned because the cell deltas wrap modulo 0x10000 as they are added @@ -193,38 +168,6 @@ extern WorldZone D_800C59BC[]; The packets are tagged once at start-up, so allocating one is a pointer bump and the renderers need only fill in vertices. One struct per kind, because the packet type is what gives each pool its stride. */ -typedef struct { - POLY_GT3 *cur; /* 0x00 */ - POLY_GT3 *base; /* 0x04 */ - POLY_GT3 *end; /* 0x08 */ -} Gt3Pool; /* 0x0C */ - -typedef struct { - POLY_FT3 *cur; /* 0x00 */ - POLY_FT3 *base; /* 0x04 */ - POLY_FT3 *end; /* 0x08 */ -} Ft3Pool; /* 0x0C */ - -typedef struct { - POLY_FT4 *cur; /* 0x00 */ - POLY_FT4 *base; /* 0x04 */ - POLY_FT4 *end; /* 0x08 */ -} Ft4Pool; /* 0x0C */ - -/** The three pools of one bank, one per primitive kind. Both banks are laid out - at start-up and @c D_800C9720 is pointed at the table; picking a bank out of - it is left to the glyph renderers, which are still asm, so what drives that - choice is not yet known. (Not @c D_800C53A4 — that one indexes the sprite - record banks @c D_800D2508.) */ -typedef struct { - Gt3Pool gt3; /* 0x00 */ - Ft3Pool ft3; /* 0x0C */ - Ft4Pool ft4; /* 0x18 */ -} WorldPrimBank; /* 0x24 */ - -extern WorldPrimBank D_800C9E88[2]; /**< The two banks. No other code in the - tree names this array; everything - reaches it through @c D_800C9720. */ /** Work RAM the pools are carved from: one contiguous run per primitive kind, each split between the two banks — @c BASE starts bank 0, @c MID is bank 0's @@ -256,13 +199,6 @@ extern WorldPrimBank D_800C9E88[2]; /**< The two banks. No other code in the #define WORLD_PRIM_GT3_MID ((POLY_GT3 *)0x801D0000) #define WORLD_PRIM_GT3_TOP ((POLY_GT3 *)WORLD_STAGE_ADDR) -/** Sprites in one pool record: an anchor plus the four spread around it. */ -#define WORLD_FAN_SPRITES 5 - -/** A pool record: five sprites placed together as one fan. */ -typedef struct { - WorldSprite sprite[WORLD_FAN_SPRITES]; -} WorldSpriteRec; /* 0xDC */ /** Records in one pool bank. */ #define WORLD_BANK_RECORDS 8 @@ -272,7 +208,6 @@ typedef struct { WorldSpriteRec rec[WORLD_BANK_RECORDS]; } WorldSpriteBank; /* 0x6E0 */ -extern SVECTOR D_800CA038; /**< Reference offset fed to the pool placer. */ /** Six probe-corner offsets, used as two batches of three by @c func_800A1678. It stays an extern rather than a file-scope @c const because the struct copy tests the source alignment at run time, which only happens when the compiler @@ -288,19 +223,12 @@ extern GlyphHeader *D_800C9740; /**< Glyph used when worldObjectById finds extern s32 D_800C53A4; /**< Active pool bank (0 or 1). */ extern s32 D_800C53A8; /**< Cleared when a record is placed, bumped by the fallback; the pass loop stops below 4. */ -extern WorldPrimBank *D_800C9720; /**< Primitive banks the glyph renderers - allocate from. @c func_800A246C is the - only writer in the tree and points it at - the table once; the readers (we_object6, - we_object7) are still asm. */ -extern s32 D_800C972C; /**< Accumulated glyph-entry count. */ extern s32 D_800C96D8[WORLD_PAD_AXES]; /**< Analog axes sampled this frame; element 0 is pad 0's X, compared against 0x7F +- 0x2D/0x2E to pick a bank. */ extern s32 D_800D2240[WORLD_PAD_AXES]; /**< Previous frame's copy of @c D_800C96D8, tested the same way. */ extern s32 D_800C9724; /**< Frames elapsed this tick; drives the repeat timers. */ -extern s32 D_800C9ED0; /**< Pad 0's raw frame parameter. */ extern s32 D_800C9ED4; /**< Pad 1's raw frame parameter, packed into the high half. */ extern s32 D_800D2470; /**< Repeat delay accumulator. */ extern s32 D_800D2474; /**< Repeat step counter. */ @@ -318,7 +246,6 @@ extern s16 D_800C9772; /**< Receives the low half of the camera-f for the call-site ABI. */ static void func_800A1F10(); static WorldObject *worldObjectById(s16 id, WorldObject *head); -/* All defined below; the render callback is the first caller in the file. */ static void buildViewportCellList(WorldPos *cam, WorldObject *out, MATRIX *m); static void func_800A6030(WorldObject **pp); static WorldObject *func_800A60B4(s32 key, WorldObject *head); @@ -347,8 +274,6 @@ extern void func_80048DD4(BattleSceneCtx *ctx, s32 r, s32 g, s32 b); extern void func_80049244(s32 *tag); extern void func_800492B4(BattleSceneCtx *ctx); extern void func_80049480(void *disp); -extern void func_800A7E74(BattleSceneCtx *ctx); -extern void func_800AC2B8(void); static s32 func_800A5B48(void); /* Writes exactly one word through its out-parameter. */ extern s32 func_800A50A0(s32 *runs); @@ -356,14 +281,6 @@ static void func_800A568C(void); /* func_800A5B48 is the only reference in the tree: when non-zero it skips the func_800A50A0 scan, admits a single node and zeroes the out-word. What sets it, and what it means, is unknown. */ -extern s32 D_800D2238; -extern s32 func_800B21EC(WorldSpriteRec *rec, s32 mode, s32 c, s32 d); -/* Both below are declared in we_object10.h, which this unit cannot include: - * its func_800B0010 prototype is (void) to serve a no-argument caller there, - * conflicting with the true (u32 kind) definition in we_object6.c that - * func_800A2D50 relies on. */ -extern void *func_80047CE4(void *dst, s32 c, u32 n); -extern s32 func_800B0010(u32 kind); static void func_800A1678(s32 col, s32 mode); static void func_800A0388(void); static void func_800A39BC(WorldSprite *out, s16 h); @@ -371,11 +288,6 @@ static void placeWorldSpriteFan(WorldSprite *out, VECTOR *v, SVECTOR s32 arg3, s32 arg4, VECTOR *origin); static s32 func_800A6254(WorldObject *head); static void func_800A62E0(s16 val, u16 *coarse, u16 *fine); -extern void func_800ACDC4(GlyphHeader *p, BattleSceneCtx *ctx, WorldPrimBank *pools); -extern void func_800BF80C(GlyphHeader *p, s32 *ot, WorldPrimBank *pools); -extern void func_800BF2E8(GlyphHeader *p, s32 *ot, WorldPrimBank *pools); -extern void func_800BF20C(CmdDesc *p, s32 kind, s32 arg); -extern void func_800BFBFC(s32 kind); /** @@ -598,7 +510,7 @@ void renderWorldMapFrame(void) { newHead = emptyHead; newTail = emptyTail; func_800A1F10(&D_800C9868, &D_800C9838); - xo = D_800C9868.x + 0x60000; + xo = D_800C9868.vx + 0x60000; { s32 rnd = xo; if (xo < 0) { @@ -607,7 +519,7 @@ void renderWorldMapFrame(void) { rnd = (rnd >> 18) << 18; xm = xo - rnd; } - coord = (xm / 0x800) + ((((D_800C9868.y + 0x48000) % 0x30000) / 0x800) << 7); + coord = (xm / 0x800) + ((((D_800C9868.vy + 0x48000) % 0x30000) / 0x800) << 7); ref = &D_800CA038; modeBias = mode - 0x20; for (bank = 0; bank < 2; bank++) { @@ -818,7 +730,7 @@ void renderWorldMapFrame(void) { if (((v >= 0) && (((u32) (D_800D23D8[0] - 1)) >= 2)) && (D_800D23D8[0] != 0xD)) { D_800C4D7C = v; - D_800C9770[0].vy = D_800C9868.z; + D_800C9770[0].vy = D_800C9868.vz; if (D_800C4D38 == 0x32) { D_800C4D40 = 0; } @@ -829,7 +741,7 @@ void renderWorldMapFrame(void) { if ((mode == 0x30) && (D_800D23D8[0] != 8)) { /* The (u16)/(s16) casts below pick the load width and signedness the heading comparison needs; each one changes the emitted code. */ - s16 cur = D_800C9868.z; + s16 cur = D_800C9868.vz; s32 want = (u16) rec->sprite[0].angle; s32 back = ((u16) rec->sprite[0].angle) - 0x80; u16 lo = rec->sprite[0].angle - 0x100; @@ -870,14 +782,14 @@ void renderWorldMapFrame(void) { if (D_800C4DC8 == 0) { cmdp = rec->sprite[0].cmd; if ((D_800D23D8[0] == 0) || (D_800D23D8[0] == 0xD)) { - t = (D_800C9868.z = h); + t = (D_800C9868.vz = h); D_800C9770[0].vy = t; D_800C9770[0].vx += - ((u16) rec->sprite[0].pos.vx) - ((u16) D_800C9868.x); - vyu = (u16) D_800C9868.y; + ((u16) rec->sprite[0].pos.vx) - ((u16) D_800C9868.vx); + vyu = (u16) D_800C9868.vy; D_800C9770[0].vz += vyu + rec->sprite[0].pos.vz; - D_800C9868.x = rec->sprite[0].pos.vx; - D_800C9868.y = -rec->sprite[0].pos.vz; + D_800C9868.vx = rec->sprite[0].pos.vx; + D_800C9868.vy = -rec->sprite[0].pos.vz; } D_800C4D74 = D_800C4D64; if (D_800C4D64 != NULL) { @@ -1498,7 +1410,7 @@ static WorldSpriteRec *func_800A26E8(GlyphHeader *p, WorldSpriteRec *rec, s32 v) continue; } if (sp->cellId == key) { - angle = D_800C9868.z; + angle = D_800C9868.vz; sp->angle = angle; if (D_800C4D64->type < 6) { sp->angle = angle - 0x140; @@ -1651,7 +1563,7 @@ static s32 func_800A2920(GlyphHeader *glyph, WorldSprite *st, s16 key, CmdDesc * continue; } if (mode == 0x32 - || (mode == 0x30 && ((g->type >= 0x1E && g->type < 0x23) || D_800C9868.z <= 0)) + || (mode == 0x30 && ((g->type >= 0x1E && g->type < 0x23) || D_800C9868.vz <= 0)) || g->type < 6 || D_800C4D64->type < 6 || (mode != 0x30 && mode != 0x32 @@ -1836,9 +1748,9 @@ s32 func_800A2D50(s32 code, s32 angZ, SVECTOR *angles, VECTOR *hitPos, s32 arg4, index compared below, and holding it in a callee-saved register is what lets the flag store share the constant. */ two = 2; - e->pos.vx = D_800C9868.x + xf.vx; - e->pos.vy = D_800C9868.z + xf.vy; - camY = D_800C9868.y; + e->pos.vx = D_800C9868.vx + xf.vx; + e->pos.vy = D_800C9868.vz + xf.vy; + camY = D_800C9868.vy; e->pos.vz = xf.vz - camY; if (j != 0) { if (j == 1) { @@ -2601,9 +2513,9 @@ void func_800A4420(WorldSpriteRec *rec, SVECTOR *ref, SVECTOR *ang, s32 size) { gte_stlvnl(&xf); for (i = 0; i < WORLD_FAN_SPRITES; i++, e++) { - e->pos.vx = D_800C9868.x + xf.vx; - e->pos.vy = D_800C9868.z + xf.vy; - depth = D_800C9868.y; + e->pos.vx = D_800C9868.vx + xf.vx; + e->pos.vy = D_800C9868.vz + xf.vy; + depth = D_800C9868.vy; e->pos.vz = xf.vz - depth; if (i != 0) { if (i == 1) { diff --git a/src/world/we_object4.c b/src/world/we_object4.c index 12e24528..d1022937 100644 --- a/src/world/we_object4.c +++ b/src/world/we_object4.c @@ -6,6 +6,7 @@ #include "world/we_object3.h" #include "world/we_object5.h" #include "world/we_object10.h" +#include "world/we_object6.h" #include "world/we_object4.h" extern TILE_1 D_800D5430[96]; /**< Second half of the star pool (== &D_800D4FB0[1][0]). */ @@ -827,8 +828,11 @@ void func_800A7CD0(s32 *block) { * differs from the slot's last blitted one (@c D_800D4EB0), the 256x1 * source row at (u, v + frame) is copied to the slot's destination * (x, y) via @c MoveImage and the new frame is cached. + * + * @param ctx Scene context. The sole caller loads @c D_800D244C into it, but + * the body works entirely off globals and never reads it. */ -void func_800A7E74(void) { +void func_800A7E74(BattleSceneCtx *ctx) { WorldTexAnim *anim; s32 i; u32 n; @@ -913,8 +917,8 @@ static void func_800A8024(void) { s16 w; s32 h; - x = D_800C9868.x; - y = D_800C9868.y; + x = D_800C9868.vx; + y = D_800C9868.vy; // Matching hack, but it's fine since it's all dead code, i.e. function is never called uninitReg(dx); @@ -922,8 +926,8 @@ static void func_800A8024(void) { func_800A5E40(x, y); ofs.vz = 0; - ofs.vx = MARKER_WORLD_X - D_800C9868.x; - ofs.vy = MARKER_WORLD_Y - D_800C9868.y; + ofs.vx = MARKER_WORLD_X - D_800C9868.vx; + ofs.vy = MARKER_WORLD_Y - D_800C9868.vy; falloff = MARKER_RANGE_SQ - (dx * dx + dy * dy); if (falloff == 0) { return; @@ -975,7 +979,7 @@ static void func_800A8024(void) { * @brief Project the world-map view centre to screen space. * * Builds a rotation matrix from the world transform's tail angle - * (@c D_800D2390.tail.angle) with no translation, turns the map's zoom + * (@c D_800D2390.tail.vy) with no translation, turns the map's zoom * distance (@c D_800C4D30 * 4, biased by the transform's head field) into * a view-space offset through @c ApplyMatrixSV, shifts it by the camera * offset in @c D_800C9770, and runs the result through the GTE with the @@ -994,7 +998,7 @@ void func_800A8270(SVECTOR *out) { rot.vx = 0; rot.vz = 0; - rot.vy = D_800D2390.tail.angle; + rot.vy = D_800D2390.tail.vy; RotMatrix(&rot, &m); m.t[2] = 0; @@ -1003,7 +1007,7 @@ void func_800A8270(SVECTOR *out) { rot.vx = 0; rot.vy = 0; rot.vz = (u16)D_800C4D30 * 4; - rot.vz = rot.vz + D_800D2390.head.unk4; + rot.vz = rot.vz + D_800D2390.head.vz; ApplyMatrixSV(&m, &rot, &rot); rot.vx += D_800C9770[0].vx; @@ -1016,7 +1020,7 @@ void func_800A8270(SVECTOR *out) { gte_stsxy(&screen); gte_stsz(&depth); - screen.vy -= abs(D_800D2390.head.unk4) / 300; + screen.vy -= abs(D_800D2390.head.vz) / 300; if (out != NULL) { out->vx = screen.vx; out->vy = screen.vy; @@ -1408,8 +1412,8 @@ void func_800A8C1C(void) { SVECTOR *np; VECTOR *wp; - camX = D_800C9868.x; - camY = D_800C9868.y; + camX = D_800C9868.vx; + camY = D_800C9868.vy; /* The block is s32 offsets up front and WorldZone records behind them, so * reaching a record means stepping the base by a byte count and retyping. */ def = (WorldZone *)((u8 *)D_800C9EE8 + D_800C9EE8[0]); @@ -1537,8 +1541,6 @@ void func_800A9254(void) { /* Projects a slot into camera space. Declared here rather than pulled in from * we_object7.h: that unit prototypes it over its own TrackEntry view of the * same memory, which conflicts with Slot30. */ -extern s32 func_800B01A0(s16 headingA, s16 headingB, Slot30 *slot, - SVECTOR *viewOut, s32 unused4, s32 unused5); /** Depth past which a particle is dropped rather than linked into the OT. */ #define PARTICLE_MAX_OTZ 0x2000 @@ -1602,7 +1604,7 @@ void func_800A9300(void) { tile = &D_800DA8D0[bank][0]; headingA = func_800A5DC8(D_800D23C0.x, D_800D23C0.y); - headingB = func_800A5DC8(D_800C9868.x, D_800C9868.y); + headingB = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); gte_sttr(&savedTrans); gte_ReadRotMatrix(&savedMat); @@ -1616,7 +1618,7 @@ void func_800A9300(void) { gte_SetRotMatrix(&D_800C9838); gte_SetTransVector(D_800C9838.t); - if (!func_800B01A0(headingB, headingA, slot, &slot->view, 0, 0)) { + if (!func_800B01A0(headingB, headingA, &slot->pos, &slot->view, NULL, NULL)) { continue; } @@ -1911,7 +1913,7 @@ void func_800A9ED4(void) { * @param x Screen x of the mesh's top-left corner. * @param y Screen y of the mesh's top-left corner. */ -void func_800A9F54(WorldPos *pos, s32 x, s32 y) { +void func_800A9F54(VECTOR *pos, s32 x, s32 y) { WorldTessVert verts[4]; BattleSceneCtx *ctx; WorldPolyGT4 *gt4; @@ -1919,8 +1921,8 @@ void func_800A9F54(WorldPos *pos, s32 x, s32 y) { s32 mapX, mapY; s32 i, c; - mapX = (pos->x + MAP_ORIGIN_X) / MAP_CELL_SIZE; - mapY = (pos->y + MAP_ORIGIN_Y) / MAP_CELL_SIZE; + mapX = (pos->vx + MAP_ORIGIN_X) / MAP_CELL_SIZE; + mapY = (pos->vy + MAP_ORIGIN_Y) / MAP_CELL_SIZE; D_800D8808 = x + MESH_CENTRE_BIAS; D_800D880C = y + MESH_CENTRE_BIAS; diff --git a/src/world/we_object5.c b/src/world/we_object5.c index a42c63ac..6c70d920 100644 --- a/src/world/we_object5.c +++ b/src/world/we_object5.c @@ -1,11 +1,16 @@ #include "common.h" #include "world.h" #include "world/we_object5.h" -#include "world/we_object3.h" /* worldPosToCell */ +#include "world/we_object6.h" +#include "world/we_object3.h" #include "battle.h" #include "psxsdk/libgpu.h" #include "psxsdk/libgte.h" #include "psxsdk/libc.h" +#include "world/we_object1.h" +#include "world/we_object9.h" + + /** * @brief Spawn a pair of POLY_FT4 quads into one of two world-scene icon @@ -594,28 +599,28 @@ void func_800AC468(void *unused_a0, WorldViewXform *oa, WorldViewXform *mh, s32 func_800BC51C(&D_800DD658, &D_800C9858); } else { /* Critically damp delta-X to [-0x20000, 0x20000] with ±0x40000 wraparound. */ - delta = D_800C9858.vx - D_800C9868.x; + delta = D_800C9858.vx - D_800C9868.vx; if (delta > 0x20000) D_800C9858.vx -= 0x40000; if (delta < -0x20000) D_800C9858.vx += 0x40000; /* Critically damp delta-Y to [-0x18000, 0x18000] with ±0x30000 wraparound. */ - delta = D_800C9858.vy - D_800C9868.y; + delta = D_800C9858.vy - D_800C9868.vy; if (delta > 0x18000) D_800C9858.vy -= 0x30000; if (delta < -0x18000) D_800C9858.vy += 0x30000; /* Blend XY 1:1 with the target. */ - D_800C9858.vx = ((D_800C9858.vx + D_800C9868.x) << 1) >> 2; - D_800C9858.vy = ((D_800C9858.vy + D_800C9868.y) << 1) >> 2; + D_800C9858.vx = ((D_800C9858.vx + D_800C9868.vx) << 1) >> 2; + D_800C9858.vy = ((D_800C9858.vy + D_800C9868.vy) << 1) >> 2; /* Blend Z 3:1 with a -0x100 bias (gated by D_800C5924 being 0). */ if (D_800C5924 == 0) { s32 z3 = D_800C9858.vz * 3; z3 -= 0x100; - z3 += D_800C9868.z; + z3 += D_800C9868.vz; D_800C9858.vz = z3 >> 2; } - viewAngle = func_800A5DC8(D_800C9868.x, D_800C9868.y); + viewAngle = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); { VECTOR *vp = &viewPos; func_800BC544(&D_800C9858, vp); @@ -804,7 +809,7 @@ void func_800ACA70(VECTOR *out, Input32 *input) { func_800423DC(&local.a, &local.b_x, &result); - angle = func_800A5DC8(D_800C9868.x, D_800C9868.y); + angle = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); func_800ACB70(angle, &vec); if (out != 0) { @@ -861,7 +866,7 @@ void func_800ACBD0(VECTOR *out, SVECTOR *in) { VECTOR vec; s16 angle; - angle = func_800A5DC8(D_800C9868.x, D_800C9868.y); + angle = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); func_800ACB70(angle, &vec); if (out != 0) { diff --git a/src/world/we_object6.c b/src/world/we_object6.c index 36d2cd86..4024c0fd 100644 --- a/src/world/we_object6.c +++ b/src/world/we_object6.c @@ -11,8 +11,8 @@ INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object6", func_800ACC68); * * Steps: * 1. Compute @c delta = @c getAngleDelta(@c D_800C977A, - * @c D_800D2390.tail.angle) @c >> @c 1 — half the signed result. - * 2. Snapshot @c D_800D2390.tail into a local @ref WorldXformBlock via + * @c D_800D2390.tail.vy) @c >> @c 1 — half the signed result. + * 2. Snapshot @c D_800D2390.tail into a local SVECTOR via * @c memcpy. The source is cast to @c (u8 @c *) so the compiler * emits @c lwl / @c lwr (matching the target's byte-granular 8-byte * copy). @@ -24,19 +24,19 @@ INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object6", func_800ACC68); * cached transform/rotation payload before dispatching world-render * work. * - * @param arg First arg forwarded verbatim to @c func_800ACC68. + * @param outMat Destination matrix, forwarded to @c func_800ACC68. */ -void func_800ACD38(s32 arg) { - WorldXformBlock buf; +void func_800ACD38(MATRIX *outMat) { + SVECTOR buf; s32 delta; - delta = getAngleDelta(D_800C977A, D_800D2390.tail.angle) >> 1; + delta = getAngleDelta(D_800C977A, D_800D2390.tail.vy) >> 1; memcpy(&buf, (u8 *)&D_800D2390.tail, sizeof(buf)); - buf.angle += delta; + buf.vy += delta; - func_800ACC68(arg, &buf, (u8 *)D_800C97F8, &D_800D2390); + func_800ACC68(outMat, &buf, D_800C97F8, &D_800D2390.head); } INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object6", func_800ACDC4); diff --git a/src/world/we_object7.c b/src/world/we_object7.c index 491febde..c3bf7f5f 100644 --- a/src/world/we_object7.c +++ b/src/world/we_object7.c @@ -1,7 +1,9 @@ #include "common.h" #include "world.h" +#include "world/we_object6.h" #include "world/we_object7.h" -#include "world/we_object3.h" /* func_800A5DC8 */ +#include "world/we_object3.h" +#include "world/we_object1.h" /* ActorRecord now lives in world.h (shared across world TUs). */ @@ -38,7 +40,7 @@ void func_800B3868(TrackObj *obj) { s32 i; viewX = func_800A5DC8(D_800D23C0.x, D_800D23C0.y); - viewY = func_800A5DC8(D_800C9868.x, D_800C9868.y); + viewY = func_800A5DC8(D_800C9868.vx, D_800C9868.vy); SetRotMatrix(&D_800C9838); SetTransMatrix(&D_800C9838); @@ -50,16 +52,16 @@ void func_800B3868(TrackObj *obj) { for (i = 0, current = obj->entries; i < obj->count; i++, current++) { if (current->status == -1) { - current->status = func_800B01A0(viewY, viewX, current, ¤t->posX, ¤t->unk30, current->unk2C); + current->status = func_800B01A0(viewY, viewX, ¤t->pos, ¤t->screen, ¤t->unk30, ¤t->unk2C); } if (current->targetIdx != 0 && current->status == 1) { target = current + current->targetIdx; if (target->status == -1) { - target->status = func_800B01A0(viewY, viewX, target, &target->posX, &target->unk30, target->unk2C); + target->status = func_800B01A0(viewY, viewX, &target->pos, &target->screen, &target->unk30, &target->unk2C); } - diff.vx = target->posX - current->posX; - diff.vy = target->posY - current->posY; - diff.vz = target->posZ - current->posZ; + diff.vx = target->screen.vx - current->screen.vx; + diff.vy = target->screen.vy - current->screen.vy; + diff.vz = target->screen.vz - current->screen.vz; current->unk18 = 0; horizDist = SquareRoot0(diff.vz * diff.vz + diff.vx * diff.vx); current->pitch = func_80041E84(-diff.vy, horizDist); diff --git a/src/world/we_object9.c b/src/world/we_object9.c index 75c7e243..41dc5257 100644 --- a/src/world/we_object9.c +++ b/src/world/we_object9.c @@ -2,8 +2,13 @@ #include "psxsdk/libc.h" #include "gamestate.h" #include "world.h" +#include "world/we_object5.h" #include "world/we_object9.h" -#include "world/we_object3.h" /* worldPosToCell */ +#include "world/we_object3.h" +#include "world/we_object1.h" +#include "world/we_object6.h" + + #define SPAWN_FLAG_LIFETIME_JITTER 1 #define SPAWN_FLAG_SIZE_JITTER 2 @@ -136,8 +141,8 @@ INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object9", func_800BB4E8); * @param visRange Visibility threshold (higher = farther allowed). */ void func_800BBD74(ParticleSource *src, s32 visRange) { - Velocity localVel; - PosDesc localPos; + SVECTOR localVel; + VECTOR localPos; s32 jitter; s32 absdx; s16 dx; @@ -145,29 +150,29 @@ void func_800BBD74(ParticleSource *src, s32 visRange) { worldCam = D_800C97F4; localPos = src->pos; - dx = ((u16) D_800C97F4) - src->pos.pos.half; - localPos.pos.word = worldCam; + dx = ((u16) D_800C97F4) - (u16)src->pos.vy; + localPos.vy = worldCam; if ((func_8009CC3C() + (dx >> 2)) >= visRange) return; absdx = (dx >= 0) ? dx : -dx; if (absdx >= 0x258) return; /* Left-side spawn: +0x320 angle offset + RNG jitter on angle/height */ localVel = src->vel; - localVel.angle += 0x320; + localVel.vy += 0x320; jitter = (func_8009CC3C() - 0x80) * 8; - localVel.angle += jitter; + localVel.vy += jitter; jitter = (func_8009CC3C() - 0x80) * 4; - localVel.height += jitter; + localVel.vz += jitter; func_800AC0A0(0x13, &localPos, &localVel, SPAWN_FLAG_SIZE_JITTER | SPAWN_FLAG_LIFETIME_JITTER); /* Right-side spawn: -0x320 angle offset + RNG jitter on angle/height */ localVel = src->vel; - localVel.angle -= 0x320; + localVel.vy -= 0x320; jitter = (func_8009CC3C() - 0x80) * 8; - localVel.angle += jitter; + localVel.vy += jitter; jitter = (func_8009CC3C() - 0x80) * 4; - localVel.height += jitter; + localVel.vz += jitter; func_800AC0A0(0x13, &localPos, &localVel, SPAWN_FLAG_SIZE_JITTER | SPAWN_FLAG_LIFETIME_JITTER); } @@ -199,24 +204,24 @@ void func_800BBD74(ParticleSource *src, s32 visRange) { * * worldCam = D_800C97F4; * localPos = src->pos; - * dx = ((u16) D_800C97F4) - src->pos.pos.half; - * localPos.pos.word = worldCam; + * dx = ((u16) D_800C97F4) - (u16)src->pos.vy; + * localPos.vy = worldCam; * if (D_800C4D4C <= (func_8009CC3C() + (dx >> 2))) return; * absdx = (dx >= 0) ? dx : -dx; * if (absdx >= 0x1A4) return; * * localVel = src->vel; - * localVel.angle += 0x320; + * localVel.vy += 0x320; * jitter = (func_8009CC3C() - 0x80) * 8; - * localVel.angle += jitter; - * localVel.height += func_8009CC3C() - 0x80; + * localVel.vy += jitter; + * localVel.vz += func_8009CC3C() - 0x80; * func_800AC0A0(0xF, &localPos, &localVel, 3); * * localVel = src->vel; - * localVel.angle -= 0x320; + * localVel.vy -= 0x320; * jitter = (func_8009CC3C() - 0x80) * 8; - * localVel.angle += jitter; - * localVel.height += func_8009CC3C() - 0x80; + * localVel.vy += jitter; + * localVel.vz += func_8009CC3C() - 0x80; * func_800AC0A0(0xF, &localPos, &localVel, 3); * } */ @@ -226,7 +231,7 @@ INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object9", func_800BBF0C); * @brief Spawn a mirrored particle pair (type 0x14) gated on a word-angle delta. * * Sibling of @c func_800BBD74 but with word-scale angle math instead of - * halfword: computes @c (D_800C97F4 - src->pos.pos.word) >> 4 and + * halfword: computes @c (D_800C97F4 - src->pos.vy) >> 4 and * rejects the spawn when @c (rnd + delta) >= @c (D_800C4D4C / 2). When * the visibility gate opens, emits two particles via @c func_800AC0A0 * with symmetric ±0x320 angle offsets and RNG jitter on angle/height. @@ -239,8 +244,8 @@ INCLUDE_ASM("asm/ovl/world/nonmatchings/we_object9", func_800BBF0C); * @param src Particle source (position descriptor + velocity template). */ void func_800BC09C(ParticleSource *src) { - Velocity localVel; - PosDesc localPos; + SVECTOR localVel; + VECTOR localPos; s32 jitter; s32 threshold; u32 worldCam; @@ -248,25 +253,25 @@ void func_800BC09C(ParticleSource *src) { worldCam = D_800C97F4; localPos = src->pos; threshold = D_800C4D4C >> 1; - localPos.pos.word = worldCam; - if ((func_8009CC3C() + ((s32)(D_800C97F4 - src->pos.pos.word) >> 4)) >= threshold) return; + localPos.vy = worldCam; + if ((func_8009CC3C() + ((s32)(D_800C97F4 - src->pos.vy) >> 4)) >= threshold) return; /* Left-side spawn: +0x320 angle offset + RNG jitter on angle/height */ localVel = src->vel; - localVel.angle += 0x320; + localVel.vy += 0x320; jitter = (func_8009CC3C() - 0x80) * 8; - localVel.angle += jitter; + localVel.vy += jitter; jitter = (func_8009CC3C() - 0x80) * 4; - localVel.height += jitter; + localVel.vz += jitter; func_800AC0A0(0x14, &localPos, &localVel, 3); /* Right-side spawn: -0x320 angle offset + RNG jitter on angle/height */ localVel = src->vel; - localVel.angle -= 0x320; + localVel.vy -= 0x320; jitter = (func_8009CC3C() - 0x80) * 8; - localVel.angle += jitter; + localVel.vy += jitter; jitter = (func_8009CC3C() - 0x80) * 4; - localVel.height += jitter; + localVel.vz += jitter; func_800AC0A0(0x14, &localPos, &localVel, 3); } @@ -1062,9 +1067,9 @@ s32 func_800BD09C(SlotEntry *slot, s32 arg1, CmdDesc *cmd, s32 worldAngle) { * * No-op when the @c D_800C4DC8 flag is zero. Otherwise copies: * - @c D_800DD698 → @c D_800C4D38 (primary cmd byte) - * - @c D_800DD680.vx → @c D_800C9868.x - * - @c D_800DD680.vy → @c D_800C9868.z (Y/Z swap for PS1 coord system) - * - -@c D_800DD680.vz → @c D_800C9868.y (Z negated) + * - @c D_800DD680.vx → @c D_800C9868.vx + * - @c D_800DD680.vy → @c D_800C9868.vz (Y/Z swap for PS1 coord system) + * - -@c D_800DD680.vz → @c D_800C9868.vy (Z negated) * - @c D_800DD690[0..8] → @c D_800C9770[1] (the rotation slot) * - @c D_800DD69C → @c D_800C4D3C (secondary cmd byte) * and calls @c worldPosToCell with the source vector and @c D_800C9770 buffer. @@ -1072,9 +1077,9 @@ s32 func_800BD09C(SlotEntry *slot, s32 arg1, CmdDesc *cmd, s32 worldAngle) { void func_800BD180(void) { if (D_800C4DC8 != 0) { D_800C4D38 = D_800DD698; - D_800C9868.x = D_800DD680.vx; - D_800C9868.z = D_800DD680.vy; - D_800C9868.y = -D_800DD680.vz; + D_800C9868.vx = D_800DD680.vx; + D_800C9868.vz = D_800DD680.vy; + D_800C9868.vy = -D_800DD680.vz; worldPosToCell(&D_800DD680, D_800C9770); memcpy(&D_800C9770[1], D_800DD690, 8); D_800C4D3C = D_800DD69C;