From a7e8f1308f2fd14ed93756e314c8ae38c78583fd Mon Sep 17 00:00:00 2001 From: EstexNT Date: Thu, 26 Mar 2026 22:38:23 +0300 Subject: [PATCH] Decompile misc GameUtil functions --- config/SOME01/splits.txt | 5 + config/SOME01/symbols.txt | 10 +- include/nw4r/math/arithmetic.h | 4 + src/Game/ExFlow.cpp | 121 +++++++- src/GameUtil/CellAnim.hpp | 2 + src/GameUtil/CellAnimManager.cpp | 62 +++- src/GameUtil/CellAnimStr.hpp | 8 + src/GameUtil/CheckPointManager.hpp | 12 +- src/GameUtil/DebugPrint.cpp | 2 +- src/GameUtil/InputCheckManager.cpp | 6 +- src/GameUtil/InputCheckManager.hpp | 5 +- src/GameUtil/Sound.hpp | 2 +- src/GameUtil/TickFlow.cpp | 445 +++++++++++++++++++++++++++-- src/GameUtil/TickFlowDecl.hpp | 1 + src/GameUtil/TickFlowManager.hpp | 5 + src/GameUtil/TimeRatio.cpp | 65 ++--- src/GameUtil/TimeRatio.hpp | 26 ++ src/nw4r/math/math_arithmetic.cpp | 1 + src/nw4r/math/math_triangular.cpp | 1 + 19 files changed, 702 insertions(+), 81 deletions(-) diff --git a/config/SOME01/splits.txt b/config/SOME01/splits.txt index abb8413..dd5a242 100644 --- a/config/SOME01/splits.txt +++ b/config/SOME01/splits.txt @@ -3073,6 +3073,7 @@ GameUtil/TickFlow.cpp: .text start:0x801DD6F4 end:0x801DEFE4 .rodata start:0x802E4CA0 end:0x802E4D50 .data start:0x8031E748 end:0x8031E8B0 + .sdata2 start:0x80329670 end:0x80329698 .bss start:0x803D5D38 end:0x803D5D78 GameUtil/TickFlowManager.cpp: @@ -3106,6 +3107,10 @@ GameUtil/InputCheckManager.cpp: GameUtil/TimeRatio.cpp: .text start:0x801E9D90 end:0x801EAA7C + .rodata start:0x802E50A4 end:0x802E50C0 + .data start:0x8031E9B8 end:0x8031EA40 + .sdata start:0x803200A0 end:0x803200B8 + .sdata2 start:0x80329770 end:0x803297A0 GameUtil/List.cpp: .text start:0x801EAA7C end:0x801EAC38 diff --git a/config/SOME01/symbols.txt b/config/SOME01/symbols.txt index 52bf50d..f99aa00 100644 --- a/config/SOME01/symbols.txt +++ b/config/SOME01/symbols.txt @@ -7919,14 +7919,14 @@ _08__16CCellAnimManagerFv = .text:0x801DABCC; // type:function size:0x90 _14__16CCellAnimManagerFv = .text:0x801DAC5C; // type:function size:0x138 _18__16CCellAnimManagerFv = .text:0x801DAD94; // type:function size:0x8C _1C__16CCellAnimManagerFPFv_vPFv_v = .text:0x801DAE20; // type:function size:0x178 -fn_801DAF98 = .text:0x801DAF98; // type:function size:0x190 -fn_801DB128 = .text:0x801DB128; // type:function size:0x164 +_20__16CCellAnimManagerFlPFv_vPFv_v = .text:0x801DAF98; // type:function size:0x190 +_24__16CCellAnimManagerFlPFv_vPFv_v = .text:0x801DB128; // type:function size:0x164 fn_801DB28C__16CCellAnimManagerFv = .text:0x801DB28C; // type:function size:0x14C fn_801DB3D8__16CCellAnimManagerFUcP16CellAnim_CellOBJil = .text:0x801DB3D8; // type:function size:0x180 fn_801DB558__16CCellAnimManagerFUc = .text:0x801DB558; // type:function size:0x10 fn_801DB568__16CCellAnimManagerFPvPvUc = .text:0x801DB568; // type:function size:0x304 -fn_801DB86C = .text:0x801DB86C; // type:function size:0x154 -fn_801DB9C0 = .text:0x801DB9C0; // type:function size:0xD8 +fn_801DB86C__16CCellAnimManagerFP9_GXTexObjllffUc = .text:0x801DB86C; // type:function size:0x154 +fn_801DB9C0__16CCellAnimManagerFP9_GXTexObjUc = .text:0x801DB9C0; // type:function size:0xD8 fn_801DBA98__16CCellAnimManagerFUc = .text:0x801DBA98; // type:function size:0xC0 fn_801DBB58__16CCellAnimManagerFP9CCellAnim = .text:0x801DBB58; // type:function size:0x104 fn_801DBC5C__16CCellAnimManagerFP9CCellAnim = .text:0x801DBC5C; // type:function size:0x20 @@ -8173,7 +8173,7 @@ _14__8CTRFloatFv = .text:0x801EA6A4; // type:function size:0x1C __ct__11CTRParabolaFv = .text:0x801EA6C0; // type:function size:0x1C4 __dt__11CTRParabolaFv = .text:0x801EA884; // type:function size:0x5C fn_801EA8E0__11CTRParabolaFfffffff = .text:0x801EA8E0; // type:function size:0x150 -fn_801EAA30 = .text:0x801EAA30; // type:function size:0x4C +_14__11CTRParabolaFv = .text:0x801EAA30; // type:function size:0x4C finalDestroy__5CListFv = .text:0x801EAA7C; // type:function size:0x4 finalInsert__5CListFv = .text:0x801EAA80; // type:function size:0x4 __ct__5CListFv = .text:0x801EAA84; // type:function size:0x1C diff --git a/include/nw4r/math/arithmetic.h b/include/nw4r/math/arithmetic.h index d282062..0809dfb 100644 --- a/include/nw4r/math/arithmetic.h +++ b/include/nw4r/math/arithmetic.h @@ -77,6 +77,10 @@ inline f32 FModf(f32 x, f32* pY) { } inline f32 FSqrt(f32 x) { + if (!(x >= 0.0f)) { + NW4R_WARNING(627, "FSqrt: Input is out of the domain."); + } + return x <= 0.0f ? 0.0f : x * FrSqrt(x); } diff --git a/src/Game/ExFlow.cpp b/src/Game/ExFlow.cpp index 3d33366..3cc6d14 100644 --- a/src/Game/ExFlow.cpp +++ b/src/Game/ExFlow.cpp @@ -2,6 +2,15 @@ #include "Mem.hpp" +#include "SceneManager.hpp" +#include "GameManager.hpp" +#include "CheckPointManager.hpp" +#include "MyCanvas.hpp" + +#include "ExScene.hpp" + +#include "ExFlowDecl.hpp" + CExFlow::CExFlow(const TickFlowCode *code, f32 initRest) : CTickFlow(code, initRest) {} @@ -10,8 +19,118 @@ TICKFLOW_IMPL_CREATE_FN(CExFlow) CExFlow::~CExFlow(void) {} +// TODO: many many commands bool CExFlow::_1C(u32 opcode, u32 arg0, const s32 *args) { - // TODO: implement + switch (opcode) { + case TF_SET_SCENE: { + if (arg0 == 0) { + gSceneManager->fn_80089FE0(static_cast(args[0]), reinterpret_cast(args[1])); + } else + if (arg0 == 1) { + gSceneManager->setUnk404(true); + } + } break; + case TF_SET_SCENE_VER: { + gSceneManager->fn_8008A4DC(static_cast(args[0]), args[1]); + } break; + case TF_SCENE_ASSETS: { + if (arg0 == 0) { + gSceneManager->fn_8008A704(static_cast(args[0])); + } else + if (arg0 == 1) { + gSceneManager->fn_8008A82C(static_cast(args[0])); + } + } break; + case TF_CHECK_SCENE_HIST: { + if (arg0 == 0) { + mCondvar = gSceneManager->fn_8008B0FC(args[0], args[1]); + } else + if (arg0 == 1) { + mCondvar = gSceneManager->fn_8008B118(static_cast(args[0])); + } + } break; + case TF_GET_SCENE_RUNNING: { + if (gGameManager->getCurrentScene()->getState() == CScene::eState_Active) { + mCondvar = true; + } else { + mCondvar = false; + } + } break; + + case TF_CHECKPOINT_SET_CRITERIA: { + gCheckPointManager->setUnkC5(args[0]); + } break; + case TF_CHECKPOINT_ENABLE_SCORING: { + gCheckPointManager->setUnkDD(args[0]); + } break; + case TF_11B: { + gCheckPointManager->setUnkCC(args[0]); + gCheckPointManager->setUnkD0(args[0]); + } break; + + case TF_125: { + if (arg0 == 0) { + gMyCanvasManager->fn_8007BF6C(args[0], + static_cast(args[1]) / 256.0f, static_cast(args[2]) / 256.0f); + } else + if (arg0 == 1) { + gMyCanvasManager->fn_8007C000(args[0], args[1], (u8)args[2], args[3], + static_cast(args[4]) / 256.0f, static_cast(args[5]) / 256.0f); + } else + if (arg0 == 2) { + gMyCanvasManager->fn_8007C200(args[0]); + } + } break; + + case TF_LOAD_SND_GROUP: { + fn_8008364C(args[0], static_cast(arg0)); + } break; + case TF_CLEAR_SND_HEAP: { + fn_80083668(static_cast(arg0)); + } break; + case TF_RESET_SND_GROUP_HEAP: { + fn_800836C0(static_cast(arg0)); + } break; + case TF_SND_LOADING: { + if (arg0 == 0) { + fn_800836E0(args[0]); + } else + if (arg0 == 1) { + mCondvar = lbl_80320440; + } + } break; + + case TF_REMIX8_MASK: { + if (arg0 == 0) { + CExScene::fn_8000A084(); + } else + if (arg0 == 1) { + CExScene::fn_8000A0A4(); + } else + if (arg0 == 2) { + mCondvar = CExScene::fn_8000A0EC(); + } else + if (arg0 == 3) { + CExScene::fn_8000A0F8(); + } else + if (arg0 == 4) { + CExScene::fn_8000A1D4(args[0]); + } else + if (arg0 == 5) { + CExScene::fn_8000A1E0(args[0]); + } + } break; + + case TF_141: { + if (arg0 == 0) { + mCondvar = SCGetAspectRatio() == args[0]; + } + } break; + + default: { + return CTickFlow::_1C(opcode, arg0, args); + } + } return false; } diff --git a/src/GameUtil/CellAnim.hpp b/src/GameUtil/CellAnim.hpp index 8eca072..b4df753 100644 --- a/src/GameUtil/CellAnim.hpp +++ b/src/GameUtil/CellAnim.hpp @@ -92,6 +92,8 @@ class CCellAnim : public CList { bool getPlaybackReverse(void) const { return mReversePlayback; } void setPlaybackReverse(bool reversed) { mReversePlayback = reversed; } + void setDestroyAtEnd(bool destroy) { mDestroyAtEnd = destroy; } + CCellAnim *getBaseAnim(void) const { return mBaseAnim; } CCellAnim *getBaseLinkedHead(void) const { return mBaseLinkedHead; } diff --git a/src/GameUtil/CellAnimManager.cpp b/src/GameUtil/CellAnimManager.cpp index 2817447..16fab91 100644 --- a/src/GameUtil/CellAnimManager.cpp +++ b/src/GameUtil/CellAnimManager.cpp @@ -75,6 +75,7 @@ void CCellAnimManager::_18(void) { } } +// not matching (argument passing via stack/high registers, maybe a struct?) static void setupProj(Mtx44 mtx, f32 left, f32 top, f32 right, f32 bottom, f32 near, f32 far, f32 wWide, f32 wStd) { if (SCGetAspectRatio() == SC_ASPECT_STD) { C_MTXOrtho(mtx, top, bottom, left, right, near, far); @@ -116,6 +117,61 @@ void CCellAnimManager::_1C(DrawSetupFn setupFn, DrawRestoreFn endFn) { } } +void CCellAnimManager::_20(s32 lastLayer, DrawSetupFn setupFn, DrawRestoreFn endFn) { + if (setupFn) { + setupFn(); + } + else { + fn_801DB28C(); + } + + Mtx44 projMtx; + setupProj(projMtx, -304.0f, -228.0f, 304.0f, 228.0f, 0.0f, 10000.0f, 832.0f, 608.0f); + GXSetProjection(projMtx, GX_ORTHOGRAPHIC); + + for (CCellAnim *cellAnim = mCellAnimHead; cellAnim != NULL; cellAnim = cellAnim->getNext()) { + cellAnim->makeMtx(TRUE, NULL); + } + for (CCellAnim *cellAnim = mCellAnimHead; cellAnim != NULL; cellAnim = cellAnim->getNext()) { + if (cellAnim->getLayer() < lastLayer) { + break; + } + if (cellAnim->getEnabled()) { + cellAnim->draw(FALSE); + } + } + + if (endFn) { + endFn(); + } +} + +void CCellAnimManager::_24(s32 lastLayer, DrawSetupFn setupFn, DrawRestoreFn endFn) { + if (setupFn) { + setupFn(); + } + else { + fn_801DB28C(); + } + + Mtx44 projMtx; + setupProj(projMtx, -304.0f, -228.0f, 304.0f, 228.0f, 0.0f, 10000.0f, 832.0f, 608.0f); + GXSetProjection(projMtx, GX_ORTHOGRAPHIC); + + for (CCellAnim *cellAnim = mCellAnimHead; cellAnim != NULL; cellAnim = cellAnim->getNext()) { + if (!(cellAnim->getLayer() < lastLayer)) { + continue; + } + if (cellAnim->getEnabled()) { + cellAnim->draw(FALSE); + } + } + + if (endFn) { + endFn(); + } +} + void CCellAnimManager::fn_801DB28C(void) { GXSetTevDirect(GX_TEVSTAGE0); GXClearVtxDesc(); @@ -141,6 +197,7 @@ bool CCellAnimManager::fn_801DB558(u8 bankID) { return mBank[bankID].loaded; } +// not matching (messy function) void CCellAnimManager::fn_801DB568(void *brcadAddr, void *tplAddr, u8 bankID) { CellAnim_Bank *bank = &mBank[bankID]; @@ -307,17 +364,20 @@ void CCellAnimManager::fn_801DBA98(u8 bankID) { } u16 CCellAnimManager::fn_801DBB58(CCellAnim *cellAnim) { - return 0; + CellAnim_Anim *anim = fn_801DBC5C(cellAnim); + return anim->getTotalFrameCount(); } CellAnim_Anim *CCellAnimManager::fn_801DBC5C(CCellAnim *cellAnim) { return &mBank[cellAnim->getBankID()].animArr[cellAnim->getAnimID()]; } +// not matching (regswap in lol) CellAnim_AnimKey *CCellAnimManager::fn_801DBC7C(CCellAnim *cellAnim) { return lol(cellAnim); } +// not matching (regswap in lol) CellAnim_Cell *CCellAnimManager::fn_801DBD38(CCellAnim *cellAnim) { CellAnim_Bank *bank = &mBank[cellAnim->getBankID()]; diff --git a/src/GameUtil/CellAnimStr.hpp b/src/GameUtil/CellAnimStr.hpp index 1bc9a51..70b3685 100644 --- a/src/GameUtil/CellAnimStr.hpp +++ b/src/GameUtil/CellAnimStr.hpp @@ -60,6 +60,14 @@ struct CellAnim_Anim { return frame; } + + u16 getTotalFrameCount(void) const { + u16 frameCount = 0; + for (s32 i = 0; i < keyCount; i++) { + frameCount += keyArr[i].frameCount; + } + return frameCount; + } }; struct CellAnim_Bank { diff --git a/src/GameUtil/CheckPointManager.hpp b/src/GameUtil/CheckPointManager.hpp index e723974..77eefed 100644 --- a/src/GameUtil/CheckPointManager.hpp +++ b/src/GameUtil/CheckPointManager.hpp @@ -97,11 +97,21 @@ class CCheckPointManager : public TSingleton { void setUnkC4(u8 arg0) { unkC4 = arg0; } + void setUnkC5(u8 arg0) { + unkC5 = arg0; + } u8 getUnkC5(void) { return unkC5; } - void setUnkDD(u8 unk) { unkDD = unk; } + void setUnkCC(s32 arg0) { + unkCC = arg0; + } + void setUnkD0(u32 arg0) { + unkD0 = arg0; + } + + void setUnkDD(bool unk) { unkDD = unk; } u8 getUnkDD(void) const { return unkDD; } bool doUnkCheck(u16 arg0, u16 arg1, f32 arg2) { diff --git a/src/GameUtil/DebugPrint.cpp b/src/GameUtil/DebugPrint.cpp index 7238ed7..f9d743f 100644 --- a/src/GameUtil/DebugPrint.cpp +++ b/src/GameUtil/DebugPrint.cpp @@ -56,7 +56,7 @@ void CDebugPrint::fn_801EC674(s32 x, s32 y, s32 frames, const char *format, ...) va_end(args); } -// non matching: data +// not matching (data; // ptmfs are misplaced, may have something // to do with the pool data hack below // (needed to match fn_801EC850) diff --git a/src/GameUtil/InputCheckManager.cpp b/src/GameUtil/InputCheckManager.cpp index dff5b8d..f267b4a 100644 --- a/src/GameUtil/InputCheckManager.cpp +++ b/src/GameUtil/InputCheckManager.cpp @@ -3,7 +3,7 @@ static u8 lbl_803D5D78[16]; -// regswaps +// not matching (regswaps) void CInputCheckManager::fn_801E8118(void) { static const u32 lbl_802E4FE0[] = { WPAD_BUTTON_UP, WPAD_BUTTON_DOWN, WPAD_BUTTON_LEFT, WPAD_BUTTON_RIGHT, @@ -205,6 +205,7 @@ void CInputCheckManager::_14(void) { unk48D = false; } +// not matching (see updateUnk0C) void CInputCheckManager::fn_801E8A08(void) { if (mGamePaused) { return; @@ -215,12 +216,11 @@ void CInputCheckManager::fn_801E8A08(void) { } fn_801E8BD0(); updateUnk10(); - // not matching in updateUnk0C updateUnk0C(); } -// regswaps, missing code (may be nonequivalent) +// not matching (regswap between i and next) void CInputCheckManager::fn_801E8BD0(void) { u32 temp_r23; CInputChecker *cur; diff --git a/src/GameUtil/InputCheckManager.hpp b/src/GameUtil/InputCheckManager.hpp index 3a5a0fd..f21443d 100644 --- a/src/GameUtil/InputCheckManager.hpp +++ b/src/GameUtil/InputCheckManager.hpp @@ -116,6 +116,9 @@ class CInputCheckManager : public TSingleton { void setUnk429(bool allow) { mAllowInput = allow; } + void setUnk42A(bool allow, s32 controller) { + mAllowInputController[controller] = allow; + } void setUnk42A(bool allow) { mAllowInputController[0] = allow; } @@ -203,7 +206,7 @@ class CInputCheckManager : public TSingleton { } void updateUnk0C(void) { - // not matching: regswap cur/next + // not matching (regswap cur/next) for (CInputChecker *cur = mCheckerHead, *next; cur != NULL; cur = next) { next = cur->getNext(); if (!cur->_18()) { diff --git a/src/GameUtil/Sound.hpp b/src/GameUtil/Sound.hpp index 0dc8657..3f5f072 100644 --- a/src/GameUtil/Sound.hpp +++ b/src/GameUtil/Sound.hpp @@ -222,7 +222,7 @@ class CSoundManager : public TSingleton { static bool fn_801E4D4C(void); static void fn_801E4D54(void); - u16 get_wave_tempo(u16 soundID) { + f32 get_wave_tempo(u16 soundID) { WaveInfo *waveInfo = fn_801E73D4(soundID); return fn_801E74EC(waveInfo); } diff --git a/src/GameUtil/TickFlow.cpp b/src/GameUtil/TickFlow.cpp index d2496b2..fac3758 100644 --- a/src/GameUtil/TickFlow.cpp +++ b/src/GameUtil/TickFlow.cpp @@ -6,8 +6,14 @@ #include "Sound.hpp" +#include "InputCheckManager.hpp" + #include "Controller.hpp" +#include "Random.hpp" + +#include "CellAnimManager.hpp" + #include "TickFlowDecl.hpp" TFD_BEGIN(lbl_802E4CA0) @@ -67,6 +73,30 @@ CTickFlow::CTickFlow(const TickFlowCode *code, f32 initRest) { CTickFlow::~CTickFlow(void) {} +void CTickFlow::_18(CTickFlow *other) { +#define COPY(member) other->member = member +#define COPYARR(member, count) for (s32 i = 0; i < count; i++) COPY(member[i]) + COPY(mCode); + COPY(mInstanceCount); + COPY(mCategory); + COPY(mNextInstructionPos); + COPY(mCurrentRest); + COPY(mExecPaused); + COPY(mCondvar); + COPY(mCondvarStackPos); + COPYARR(mCondvarStack, (s32)ARRAY_LENGTH(mCondvarStack)); + COPYARR(mExecStack, (s32)ARRAY_LENGTH(mExecStack)); + COPY(mExecStackPos); + COPY(mButtonPromptControllerIdx); + COPY(mButtonPromptIsReleased); + COPY(mButtonPromptIsPressed); + COPY(mButtonPromptButton); + COPY(mButtonPromptPressSfx); + COPY(mButtonPromptReleaseSfx); +#undef COPYARR +#undef COPY +} + bool CTickFlow::fn_801DD9E8(void) { if (mExecPaused) { return false; @@ -114,15 +144,15 @@ bool CTickFlow::fn_801DD9E8(void) { } } +// not matching (see TF_CALL, TF_01E, TF_MESG_PANE_VISIBLE, TF_BUTTON_PROMPT) bool CTickFlow::_1C(u32 opcode, u32 arg0, const s32 *args) { switch (opcode) { case TF_ASYNC_CALL: { - const TickFlowCode *code = reinterpret_cast(args[0]); - f32 rest = (u32)args[1]; - f32 initRest = rest + mCurrentRest + gTickFlowManager->fn_801E2698(); - gTickFlowManager->fn_801E1CC0(code, initRest); + gTickFlowManager->fn_801E1CC0(reinterpret_cast(args[0]), + mCurrentRest + gTickFlowManager->fn_801E2698() + static_cast(args[1])); } break; case TF_CALL: + // instruction swap between args[0] and mCode fn_801DEF8C(reinterpret_cast(args[0])); break; case TF_RETURN: @@ -142,10 +172,12 @@ bool CTickFlow::_1C(u32 opcode, u32 arg0, const s32 *args) { mCondvar += args[0]; break; case TF_PUSH_CONDVAR: - mCondvarStack[mCondvarStackPos++] = mCondvar; + mCondvarStack[mCondvarStackPos] = mCondvar; + mCondvarStackPos++; break; case TF_POP_CONDVAR: - mCondvar = mCondvarStack[--mCondvarStackPos]; + mCondvarStackPos--; + mCondvar = mCondvarStack[mCondvarStackPos]; break; case TF_REST: mCurrentRest += arg0; @@ -173,28 +205,28 @@ bool CTickFlow::_1C(u32 opcode, u32 arg0, const s32 *args) { mNextInstructionPos = fn_801DECFC(mCode, arg0); break; case TF_IF: { - s32 value = args[0]; s32 condvar = mCondvar; + s32 value = args[0]; bool condPass = false; switch (arg0) { case 0: - condPass = value == condvar; + condPass = condvar == value; break; case 1: - condPass = value != condvar; + condPass = condvar != value; break; case 2: - condPass = value < condvar; + condPass = condvar < value; break; case 3: - condPass = value <= condvar; + condPass = condvar <= value; break; case 4: - condPass = value > condvar; + condPass = condvar > value; break; case 5: - condPass = value >= condvar; + condPass = condvar >= value; break; } @@ -270,57 +302,383 @@ bool CTickFlow::_1C(u32 opcode, u32 arg0, const s32 *args) { gTickFlowManager->fn_801E2B9C(seqTempoInt); } break; case TF_TEMPO_WAVE: { - WaveInfo *waveInfo = gSoundManager->fn_801E73D4(arg0); - f32 waveTempo = gSoundManager->fn_801E74EC(waveInfo); - gTickFlowManager->fn_801E2B9C(waveTempo); + gTickFlowManager->fn_801E2B9C(gSoundManager->get_wave_tempo(arg0)); } break; case TF_SPEED: { gTickFlowManager->fn_801E2C04(arg0 / 256.0f); } break; case TF_01E: { - + // regswap inside CLAMP + f32 a2 = static_cast(args[2]) / 256.0f; + f32 a1 = static_cast(args[1]) / 256.0f; + f32 x = (gTickFlowManager->getSpeed() * static_cast(args[0])) / 256.0f; + gTickFlowManager->fn_801E2C04(CLAMP(a1, a2, x)); } break; case TF_01F: { + u16 soundID = args[0]; + f32 temp_f31; + if (arg0 == 0) { + temp_f31 = static_cast(args[1]); + } + if (arg0 == 1) { + temp_f31 = gSoundManager->fn_801E75C0(args[1]); + } + gTickFlowManager->fn_801E2C04(gSoundManager->get_wave_tempo(soundID) / temp_f31); } break; - case TF_020: { - + f32 temp_f31; + f32 temp_f1; + switch (arg0) { + case 0: + temp_f31 = gSoundManager->fn_801E75C0(args[0]); + temp_f1 = static_cast(args[1]); + break; + case 1: + temp_f31 = gSoundManager->fn_801E75C0(args[0]); + temp_f1 = gSoundManager->get_wave_tempo(args[1]); + break; + } + if (temp_f31 == 0.0f) { + temp_f31 = 120.0f; + } + if (temp_f1 == 0.0f) { + temp_f1 = 120.0f; + } + gTickFlowManager->fn_801E2C04(temp_f1 / temp_f31); } break; + case TF_SPAWN_CELLANIM: { + f32 scaleX = args[5] / 256.0f; + f32 scaleY = args[6] / 256.0f; + + s32 posX = args[2]; + s32 posY = args[3]; + + s32 layer = args[4]; + + CCellAnim *cellAnim = gCellAnimManager->fn_801DBE7C(args[0], args[1]); + if ((arg0 == 3) || (arg0 == 4) || (arg0 == 5)) { + cellAnim->setPlaybackReverse(true); + } + if ((arg0 == 1) || (arg0 == 4)) { + cellAnim->setLooping(true); + } + if ((arg0 == 2) || (arg0 == 5)) { + cellAnim->setDestroyAtEnd(true); + } + cellAnim->setPos(posX, posY); + cellAnim->fn_801DCF94(layer); + cellAnim->setScale(scaleX, scaleY); + + cellAnim->fn_801DCF18(); } break; + case TF_PLAY_SFX_VOL: { SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); - f32 volume = args[1] / 256.0f; + f32 volume = static_cast(args[1]) / 256.0f; gSoundManager->play(args[0], 0.0f, soundHandle); gSoundManager->fn_801E65F4(volume, 0, soundHandle); } break; case TF_PLAY_SFX: { SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); - + f32 volume = 1.0f; + f32 pitch = 1.0f; + f32 pan = 0.0f; + f32 delay = 0.0f; + u16 soundID; + + switch (arg0) { + case 5: + delay = static_cast(args[5]) / 256.0f; + // case 4: + // // nothing + case 3: + pan = static_cast(args[3]) / 256.0f; + case 2: + pitch = static_cast(args[2]) / 256.0f; + case 1: + volume = static_cast(args[1]) / 256.0f; + case 0: + soundID = args[0]; + break; + } + + gSoundManager->play(soundID, (f32)(s32)delay, soundHandle); + gSoundManager->fn_801E65F4(volume, 0, soundHandle); + gSoundManager->fn_801E676C(pitch, soundHandle); + gSoundManager->fn_801E68E0(pan, soundHandle); } break; case TF_024: { SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); f32 volume = arg0 / 256.0f; - f32 fadeTicks = (u32)args[0]; - s32 fadeFrames = gTickFlowManager->fn_801E26B4(fadeTicks); + s32 fadeFrames = gTickFlowManager->fn_801E26B4(static_cast(args[0])); gSoundManager->fn_801E65F4(volume, fadeFrames, soundHandle); } break; + case TF_025: { + SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); + + gSoundManager->fn_801E676C(static_cast(args[0]) / 256.0f, soundHandle); + } break; + case TF_026: { + SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); + + gSoundManager->fn_801E68E0(args[0] / 256.0f, soundHandle); + } break; + case TF_027: { + SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); + + gSoundManager->fn_801E6A54(static_cast(args[0]) / 256.0f, soundHandle); + } break; + case TF_028: { + SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); + if (arg0 == 0) { + gSoundManager->fn_801E6BC8(static_cast(args[0]), soundHandle); + } else + if (arg0 == 1) { + gSoundManager->fn_801E6BC8((u16)gSoundManager->get_wave_tempo(args[0]), soundHandle); + } + } break; + case TF_029: { + SNDHandle *soundHandle = gTickFlowManager->fn_801E415C(); + + gSoundManager->fn_801E62B8(gTickFlowManager->fn_801E26B4(arg0), soundHandle); + } break; + case TF_02A: { + gTickFlowManager->fn_801E4154(gSoundManager->fn_801E7B30(arg0)); + } break; + + case TF_PREPARE_SEQ: { + gTickFlowManager->prepareSeq(arg0); + } break; + case TF_START_SEQ: { + gTickFlowManager->playSeq(arg0); + } break; + case TF_START_PREPARED_SEQ: { + gTickFlowManager->playPreparedSeq(); + } break; + case TF_STOP_SEQ: { + gTickFlowManager->stopSeq((u16)arg0); + } break; + case TF_SET_SEQ_VOLUME: { + gTickFlowManager->fn_801E334C(args[0] / 256.0, args[1]); + } break; + case TF_030: { + gTickFlowManager->fn_801E33C0(args[0]); + } break; + + case TF_PREPARE_STRM: { + gTickFlowManager->prepareStrm(arg0); + } break; + case TF_START_STRM: { + gTickFlowManager->playStrm(arg0); + } break; + case TF_START_PREPARED_STRM: { + gTickFlowManager->playPreparedStrm(); + } break; + case TF_STOP_STRM: { + gTickFlowManager->stopStrm((u16)arg0); + } break; + case TF_SET_STRM_VOLUME: { + gTickFlowManager->fn_801E38BC(args[0] / 256.0, args[1]); + } break; + case TF_GET_STRM_PREPARED: { + mCondvar = gTickFlowManager->fn_801E38CC(); + } break; + + case TF_PREPARE_WAVE: { + gTickFlowManager->prepareWave(arg0); + } break; + case TF_START_WAVE: { + gTickFlowManager->playWave(arg0); + } break; + case TF_START_PREPARED_WAVE: { + gTickFlowManager->playPreparedWave(); + } break; + case TF_STOP_WAVE: { + gTickFlowManager->stopWave((u16)arg0); + } break; + case TF_SET_WAVE_VOLUME: { + gTickFlowManager->fn_801E3E2C(args[0] / 256.0, args[1]); + } break; + case TF_GET_WAVE_PREPARED: { + mCondvar = gTickFlowManager->fn_801E3E3C(); + } break; + + case TF_SET_PLAYER_VOLUME: { + f32 volume = static_cast(args[0]) / 256.0f; + if (arg0 == 0) { + gSoundManager->fn_801E6E08(volume); + } + if (arg0 == 1) { + gSoundManager->fn_801E6E4C(volume); + } + if (arg0 == 2) { + gSoundManager->fn_801E6ECC(volume); + } + } break; + case TF_SET_PLAYER_VOLUME_FADE: { + if (arg0 == 0) { + f32 volume = static_cast(args[0]) / 256.0f; + s32 fadeFrames; + if (args[1]) { + fadeFrames = args[2]; + } else { + fadeFrames = gTickFlowManager->fn_801E26B4(args[2]); + } + gSoundManager->fn_801E7114(volume, fadeFrames); + } else + if (arg0 == 1) { + gSoundManager->fn_801E71C0(); + } + } break; + case TF_GET_GROUP_LOADING: { + mCondvar = gSoundManager->fn_801E7334(); + } break; + + case TF_MESG_PANE_VISIBLE: { + // kind of odd asm (maybe some inline?) + lbl_803D5D38[arg0]->SetVisible(args[0]); + nw4r::lyt::Pane *pane = lbl_803D5D58[arg0]; + if (pane != NULL) { + pane->SetVisible(args[0]); + } + } break; + case TF_MESG_PANE_SET_STRING: { + lbl_803D5D38[arg0]->SetString(reinterpret_cast(args[0])); + } break; + + case TF_SET_INPUT_ALLOW: { + if (arg0 == 0) { + gInputCheckManager->setUnk429(args[0]); + } else + if (arg0 == 1) { + gInputCheckManager->setUnk42A(args[1], args[0]); + } + } break; + case TF_043: { + gInputCheckManager->setUnk42E(args[0]); + } break; + case TF_044: { + if (arg0 == 0) { + gInputCheckManager->setUnk484(args[0]); + } else + if (arg0 == 1) { + gInputCheckManager->fn_801E923C(args[0]); + } + } break; + case TF_045: { + if (arg0 == 0) { + gInputCheckManager->fn_801E9C30(args[0]); + } else + if (arg0 == 1) { + gInputCheckManager->fn_801E9C38(static_cast(args[0]) / 256.0f); + } + } break; + + case TF_BUTTON_PROMPT: { + switch (arg0) { + case 0: + mButtonPromptControllerIdx = args[0]; + break; + case 1: + // instruction order + mButtonPromptIsReleased = true; + mButtonPromptIsPressed = false; + mButtonPromptButton = args[0]; + mButtonPromptPressSfx = args[1]; + mButtonPromptReleaseSfx = args[2]; + break; + case 2: + mCondvar = getButtonPromptIsPressedOrReleased(); + break; + } + } break; + + case TF_047: { + if (arg0 == 0) { + gInputCheckManager->fn_801E9C40(); + } else + if (arg0 == 1) { + gInputCheckManager->fn_801E9D58(args[0], args[1]); + } + } break; + case TF_SET_BUTTON_COOLDOWN: { + gControllerManager->fn_801D5FF0(args[0])->fn_801D5500(args[1], args[2]); + } break; + + case TF_SET_SKIPPABLE: { + gTickFlowManager->setUnkFC(arg0); + } break; + case TF_SET_SKIP_HANDLER: { + gTickFlowManager->setUnkF4(reinterpret_cast(args[0])); + } break; + case TF_SET_SKIP_CONTROLLER: { + gTickFlowManager->setUnkFD(args[0]); + } break; + case TF_SET_SKIP_INPUT: { + gTickFlowManager->setUnk100(args[0]); + } break; + + case TF_ICI_CTRL: { + char buf[32]; + + if (arg0 == 0) { + gInputCheckManager->fn_801E9D84(); + } else + if (arg0 == 1) { + sprintf(buf, "%s_%d.ici", reinterpret_cast(args[0]), args[1]); + gInputCheckManager->fn_801E9D80(buf); + } + } break; + + case TF_CONTROLLER_DO_MOTOR_SEQ: { + gControllerManager->fn_801D5FF0(args[0])->_40(reinterpret_cast(args[1]), false); + } break; + + case TF_RANDOM: { + mCondvar = sRandom.nextU32(arg0); + } break; } return false; } -/* +// not matching (regswaps, weird loads, temp_r7 not generating) u32 CTickFlow::fn_801DECFC(const TickFlowCode *code, u32 labelId) { - +#define FINDONE() \ + opcode = BYTECODE_GET_OPCODE(code[idx]); \ + argc = BYTECODE_GET_ARGC(code[idx]); \ + arg0 = BYTECODE_GET_ARG0(code[idx]); \ + if ((opcode == TF_LABEL) && (arg0 == labelId)) { \ + return idx; \ + } \ + if (opcode == TF_STOP) { \ + break; \ + } \ + idx += argc + 1 + + u32 idx = 0; + u32 temp_r7 = 0; + + for (s32 i = 0; i < 0x4000; i++) { + u32 opcode; + u32 argc; + u32 arg0; + FINDONE(); + FINDONE(); + FINDONE(); + FINDONE(); + temp_r7 += 3; + } + return 0; +#undef FINDONE } -*/ -/* +// not matching (regswaps, weird loads) u32 CTickFlow::fn_801DEDFC( const TickFlowCode *code, u32 elseOp, u32 elseArg0, @@ -330,9 +688,40 @@ u32 CTickFlow::fn_801DEDFC( u32 instrOffs, bool skipOneInstr ) { + s32 nestDepth = 0; + + for (s32 i = 0; i < 0x10000; i++) { + u32 op, argc, arg0; + op = BYTECODE_GET_OPCODE(code[instrOffs]); + argc = BYTECODE_GET_ARGC(code[instrOffs]); + arg0 = BYTECODE_GET_ARG0(code[instrOffs]); + + if ( + nestDepth == 0 && ( + (op == elseOp && arg0 == elseArg0) || + (op == defaultOp && arg0 == defaultArg0) || + (op == endOp && arg0 == endArg0) + ) + ) { + if (skipOneInstr) { + return instrOffs + 1 + argc; + } + return instrOffs; + } + + if (op == beginNestedBlockOp) { + nestDepth++; + } + if (op == endNestedBlockOp) { + nestDepth--; + } + + instrOffs += 1 + argc; + } + return 0; } -*/ + void CTickFlow::finalInsert(void) {} diff --git a/src/GameUtil/TickFlowDecl.hpp b/src/GameUtil/TickFlowDecl.hpp index bdc36a9..cbf34ed 100644 --- a/src/GameUtil/TickFlowDecl.hpp +++ b/src/GameUtil/TickFlowDecl.hpp @@ -89,6 +89,7 @@ enum { TF_SET_SKIP_INPUT, TF_ICI_CTRL, TF_CONTROLLER_DO_MOTOR_SEQ, + TF_04F, TF_RANDOM, ///< Set the condvar to a random value. Arg0: upper bound of random value /* ExFlow opcodes (0x100 to 0x141) are found in Game/ExFlowDecl.hpp */ diff --git a/src/GameUtil/TickFlowManager.hpp b/src/GameUtil/TickFlowManager.hpp index a7c5226..bb134ab 100644 --- a/src/GameUtil/TickFlowManager.hpp +++ b/src/GameUtil/TickFlowManager.hpp @@ -104,10 +104,15 @@ class CTickFlowManager : public TSingleton { EBGMType getCurrentBGMType(void) { return mCurrentBGMType; } + f32 getSpeed(void) { + return mSpeed; + } bool getPaused(void) { return mPaused; } + void setUnkF4(const TickFlowCode *code) { mSkipHandler = code; } + void setUnkF8(const TickFlowCode *code) { mSceneTransHandler = code; } bool getUnkFC(void) const { return mSkipAllowed; } diff --git a/src/GameUtil/TimeRatio.cpp b/src/GameUtil/TimeRatio.cpp index 46910ba..75ba787 100644 --- a/src/GameUtil/TimeRatio.cpp +++ b/src/GameUtil/TimeRatio.cpp @@ -28,8 +28,7 @@ void CTimeRatio::fn_801E9DE8(BOOL unk) { fn_801E9EBC(); // Calculate mEasedT .. again? } -// TODO: match -// https://decomp.me/scratch/ov8q0 +// not matching (regswaps) void CTimeRatio::fn_801E9EBC(void) { f32 easedT = 0.0f; if (mMaxT != 0.0f) { @@ -70,8 +69,6 @@ void CTimeRatio::fn_801E9EBC(void) { f32 invNormT = 1.0f - ((doubleT * mEasingScale) / mMaxT); f32 invEasedT = invNormT * powerFactor; easedT = 1.0f - invEasedT; - - // easedT = 1.0f - (1.0f - power) * (1.0f - (mLinearT * mEasingScale * 2.0f) / mMaxT); } else { f32 powered = 1.0f; @@ -127,14 +124,18 @@ void CTimeRatio::fn_801E9EBC(void) { power *= easedT; } - f32 linearT = (mEasingScale * -((mLinearT * 2.0f) - mMaxT)); - - easedT = -(1.0f - (1.0f - power) * (1.0f - linearT / mMaxT)); + f32 f5 = -((2.0 * mLinearT) - mMaxT); + + f32 f4 = (1.0f - power); + f32 f2 = mEasingScale * f5; + f4 *= (1.0f - (f2 / mMaxT)); + f32 f1 = -(1.0f - f4); + easedT = (1.0 + f1); } else { f32 powered = 1.0f; - easedT -= 2.0f; + easedT -= 1.0f; if (easedT < 0.0f) { easedT *= -1.0f; } @@ -149,14 +150,10 @@ void CTimeRatio::fn_801E9EBC(void) { f32 invEasedT = invNormT * powerFactor; easedT = 1.0f - invEasedT; - // JUN 30 01:04: I GIVE UP! - - // f32 linearT = (mEasingScale * ((mLinearT * 2.0f) - mMaxT)); - - // easedT = 1.0f - (1.0f - power) * (1.0f - linearT / mMaxT); + easedT += 1.0f; } - easedT = (easedT + 1.0f) / 2.0f; + easedT = easedT / 2.0f; } break; default: @@ -200,6 +197,7 @@ void CTimeRatio::fn_801EA550(f32 newTime, f32 newMaxTime, bool stopAtMaxTime) { mTicking = true; } + CTRFloat::CTRFloat(void) : CTimeRatio() { @@ -227,10 +225,18 @@ void CTRFloat::_14(void) { mOutputStart = a + delta * t; } -// TODO: match -void CTRParabola::fn_801EA8E0(f32 x0, f32 y0, f32 velY0, f32 x1, f32 y1, f32 velY1, f32 curvature) { - f32 yDelta = y1 - y0; +CTRParabola::CTRParabola(void) { + fn_801EA8E0(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); + mMaxT = 48.0f; + mLinearT = 0.0f; + fn_801E9EBC(); // Calculate initial mEasedT. + mTicking = false; +} + +CTRParabola::~CTRParabola(void) {} +// not matching (float regswap in the else block) +void CTRParabola::fn_801EA8E0(f32 x0, f32 y0, f32 velY0, f32 x1, f32 y1, f32 velY1, f32 curvature) { mOutputStart = x0; mY0 = y0; mZ0 = velY0; @@ -238,30 +244,11 @@ void CTRParabola::fn_801EA8E0(f32 x0, f32 y0, f32 velY0, f32 x1, f32 y1, f32 vel mOutputEnd = x1; mY1 = y1; mZ1 = velY1; - - mCurvature = curvature; - - if ((curvature < 0.0f) && (curvature < yDelta)) { - mCurvature = yDelta; - } - if ((mCurvature < 0.0f) && (yDelta < mCurvature)) { - mCurvature = yDelta; - } - - if (mCurvature != 0.0f) { - f32 ratio = 1.0 - yDelta / mCurvature; - f32 sqrtTerm = nw4r::math::FSqrt(ratio); - - mB = mCurvature * 2.0f * (sqrtTerm + 1.0); - mA = -(mB * mB) / (mCurvature * 4.0f); - } - else { - mA = 0.0f; - mB = mY1 - mY0; - } + + calcParabola(curvature, mY1 - mY0); } -// TODO: match +// not matching (needs shuffling around) void CTRParabola::_14(void) { f32 t = mEasedT; diff --git a/src/GameUtil/TimeRatio.hpp b/src/GameUtil/TimeRatio.hpp index 9aaf71e..0355fc3 100644 --- a/src/GameUtil/TimeRatio.hpp +++ b/src/GameUtil/TimeRatio.hpp @@ -3,6 +3,9 @@ #include +#include +#include + #include "List.hpp" class CTimeRatio : public CList { @@ -128,6 +131,29 @@ class CTRParabola : public CTimeRatio { f32 getCurrentY(void) const { return mCurrentY; } f32 getCurrentZ(void) const { return mCurrentZ; } + void calcParabola(f32 curvature, f32 yDelta) { + mCurvature = curvature; + + if ((mCurvature > 0.0f) && (mCurvature < yDelta)) { + mCurvature = yDelta; + } + if ((mCurvature < 0.0f) && (mCurvature > yDelta)) { + mCurvature = yDelta; + } + + if (mCurvature == 0.0f) { + mA = 0.0f; + mB = mY1 - mY0; + } + else { + f32 ratio = 1.0 - yDelta / mCurvature; + f32 sqrtTerm = 1.0 + nw4r::math::FSqrt(ratio); + f32 curve = mCurvature * 2.0f; + + mB = curve * sqrtTerm; + mA = -(mB * mB) / (mCurvature * 4.0f); + } + } private: f32 mCurrentX; f32 mY0; // Parabola C diff --git a/src/nw4r/math/math_arithmetic.cpp b/src/nw4r/math/math_arithmetic.cpp index 9803a7c..95e089f 100644 --- a/src/nw4r/math/math_arithmetic.cpp +++ b/src/nw4r/math/math_arithmetic.cpp @@ -1,3 +1,4 @@ +#include #include namespace nw4r { diff --git a/src/nw4r/math/math_triangular.cpp b/src/nw4r/math/math_triangular.cpp index 2cb3118..ccc1de0 100644 --- a/src/nw4r/math/math_triangular.cpp +++ b/src/nw4r/math/math_triangular.cpp @@ -1,3 +1,4 @@ +#include #include namespace nw4r {