From 33efdfeec9be71687d07c3a4ab460703c2b7e93a Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 12 May 2025 21:35:03 +0200 Subject: [PATCH] More docs --- config/SOUE01/symbols.txt | 2 +- include/d/d_message.h | 26 ++-- include/toBeSorted/fi_context.h | 14 +-- src/d/d_message.cpp | 142 +++++++++++++--------- src/d/lyt/msg_window/d_lyt_msg_window.cpp | 2 +- src/toBeSorted/fi_context.cpp | 2 +- 6 files changed, 109 insertions(+), 79 deletions(-) diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index f11f1d97..a832ccdd 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -10897,7 +10897,7 @@ handleJump__7dFlow_cFv = .text:0x801B18D0; // type:function size:0x8 triggerEntryPoint__7dFlow_cFll = .text:0x801B18E0; // type:function size:0x298 triggerEntryPoint__7dFlow_cFPCc = .text:0x801B1B80; // type:function size:0x3C getField_0x44__7dFlow_cCFv = .text:0x801B1BC0; // type:function size:0x8 -getField_0x46__7dFlow_cCFv = .text:0x801B1BD0; // type:function size:0x8 +getNextFiFlow__7dFlow_cCFv = .text:0x801B1BD0; // type:function size:0x8 triggerEntryPointChecked__7dFlow_cFll = .text:0x801B1BE0; // type:function size:0x80 setField0x3C__7dFlow_cFv = .text:0x801B1C60; // type:function size:0xC checkField0x3C__7dFlow_cCFv = .text:0x801B1C70; // type:function size:0x14 diff --git a/include/d/d_message.h b/include/d/d_message.h index 358e7bbc..47c2d84d 100644 --- a/include/d/d_message.h +++ b/include/d/d_message.h @@ -38,11 +38,11 @@ public: // Ghidra: ActorEventFlowManager class dFlow_c : dFlowBase_c { enum BranchValue_e { - BRANCH_00, - BRANCH_01, - BRANCH_02, + BRANCH_SELECTED_OPTION_0, + BRANCH_SELECTED_OPTION_1, + BRANCH_SELECTED_OPTION_FI, BRANCH_STORYFLAG, - BRANCH_04, + BRANCH_NONE, BRANCH_ZONEFLAG, BRANCH_SCENEFLAG, BRANCH_EVENT_COUNTER_THRESHOLD_1, @@ -52,9 +52,9 @@ class dFlow_c : dFlowBase_c { BRANCH_RAND_2, BRANCH_RAND_3, BRANCH_RAND_4, - BRANCH_14, - BRANCH_15, - BRANCH_16, + BRANCH_14, // skipped + BRANCH_15, // skipped + BRANCH_16, // skipped BRANCH_FREE_SPACE_IN_POUCH, BRANCH_18, BRANCH_19, @@ -71,7 +71,7 @@ class dFlow_c : dFlowBase_c { EVENT_SET_ZONEFLAG = 4, EVENT_UNSET_ZONEFLAG = 5, EVENT_DELAY = 6, - EVENT_07 = 7, + EVENT_LOAD_FI_FLOW = 7, EVENT_RUPEES = 8, EVENT_SET_ITEM = 9, EVENT_EXIT = 10, @@ -129,11 +129,15 @@ public: /* vt 0x3C */ virtual u16 getSwitchChoice(const MsbFlowInfo *element, u16 param) const; /* vt 0x40 */ virtual bool triggerEntryPointChecked(s32 labelPart1, s32 labelPart2); + /** + * "Speculatively" evaluate a flow until a given event gets hit, and write + * its parameters into the provided pointer. Probably has no side effects. + */ bool advanceUntilEvent(s32 searchParam3, s32 *pOutParams1n2); bool advanceUntil(s32 searchType, s32 searchParam3, s32 *pOutParams1n2); u16 getField_0x44() const; - u16 getField_0x46() const; + u16 getNextFiFlow() const; protected: static s32 sExitId; @@ -188,10 +192,10 @@ protected: /* 0x3C */ u8 field_0x3C; /* 0x40 */ s32 field_0x40; /* 0x44 */ u16 field_0x44; - /* 0x46 */ u16 field_0x46; + /* 0x46 */ u16 mNextFiFlow; /* 0x48 */ s32 mDelayTimer; /* 0x4C */ MsbFlowInfo mFlowInfo; - /* 0x5C */ s32 field_0x5C; + /* 0x5C */ s32 mFiSpeechArgument; /* 0x60 */ s32 mFiInfo0; }; diff --git a/include/toBeSorted/fi_context.h b/include/toBeSorted/fi_context.h index 949c067d..5dde4c4c 100644 --- a/include/toBeSorted/fi_context.h +++ b/include/toBeSorted/fi_context.h @@ -63,21 +63,21 @@ public: static u16 prepareFiHelpIndex(); - bool getDoSpecialFiMenuHandling() const { - return mDoSpecialFiMenuHandling; + bool getIsInFiMainMenu() const { + return mIsInFiMainMenu; } - static bool getDoSpecialFiMenuHandlingChecked() { + static bool getIsInFiMainMenuChecked() { if (sInstance != nullptr) { - return sInstance->getDoSpecialFiMenuHandling(); + return sInstance->getIsInFiMainMenu(); } else { return false; } } - static void setDoSpecialFiMenuHandling(bool val) { + static void setIsInFiMainMenu(bool val) { if (sInstance != nullptr) { - sInstance->mDoSpecialFiMenuHandling = val; + sInstance->mIsInFiMainMenu = val; } } @@ -203,7 +203,7 @@ private: /* 0x48 */ bool field_0x48; /* 0x49 */ bool field_0x49; /* 0x4A */ bool field_0x4A; - /* 0x4B */ bool mDoSpecialFiMenuHandling; + /* 0x4B */ bool mIsInFiMainMenu; }; #endif diff --git a/src/d/d_message.cpp b/src/d/d_message.cpp index b500ef92..83add314 100644 --- a/src/d/d_message.cpp +++ b/src/d/d_message.cpp @@ -58,9 +58,9 @@ dFlow_c::dFlow_c() { field_0x3C = 0; field_0x40 = -1; field_0x44 = -1; - field_0x46 = -1; + mNextFiFlow = -1; mDelayTimer = 0; - field_0x5C = -1; + mFiSpeechArgument = -1; } dFlow_c::~dFlow_c() {} @@ -265,30 +265,32 @@ bool dFlow_c::handleEventInternal(const MsbFlowInfo *element) { } mDelayTimer = 0; break; - case EVENT_07: + case EVENT_LOAD_FI_FLOW: if (params1n2 == -1) { s32 hi, lo; s32 selectedOption = dLytMsgWindow_c::getInstance()->getTextOptionSelection(); mFiInfo0 = FiContext::getGlobalFiInfo0(selectedOption); switch (mFiInfo0) { - case 0: { + case FiContext::KEN8_Summary: { hi = 6; lo = 1; - field_0x5C = FiContext::getNaviTableProgressSummary(); + mFiSpeechArgument = FiContext::getNaviTableProgressSummary(); break; } case 11: + // TODO: Is this one actually used? It completely duplicates + // KEN8_Hint (case 1) down below... hi = 6; lo = 100; - field_0x5C = FiContext::getFiAdviceHintEntry(); + mFiSpeechArgument = FiContext::getFiAdviceHintEntry(); break; - case 2: { + case FiContext::KEN8_Objective: { hi = 6; lo = 200; - field_0x5C = FiContext::getObjective(); + mFiSpeechArgument = FiContext::getObjective(); break; } - case 3: { + case FiContext::KEN8_Analysis: { FiAnalysisHandle handle = FiContext::getNaviTableEquipmentCheckEntry(); if (handle.isValid()) { hi = 6; @@ -297,30 +299,30 @@ bool dFlow_c::handleEventInternal(const MsbFlowInfo *element) { hi = 6; lo = 301; } - field_0x5C = 5; + mFiSpeechArgument = 5; break; } - case 4: + case FiContext::KEN8_PlayTime: hi = 6; lo = 800; break; - case 9: + case FiContext::KEN8_Advice: hi = 6; lo = 802; break; - case 1: { + case FiContext::KEN8_Hint: { hi = 6; lo = 100; - field_0x5C = FiContext::getFiAdviceHintEntry(); + mFiSpeechArgument = FiContext::getFiAdviceHintEntry(); break; } - case 5: + case FiContext::KEN8_Rumors: hi = 6; lo = 900; break; } FiContext::do_setAdviceOptions(FiContext::getGlobalFiInfo0(selectedOption)); - field_0x46 = lo + hi * 1000; + mNextFiFlow = lo + hi * 1000; } else { triggerEntryPoint((params1n2 >> 16) & 0xFFFF, params1n2 & 0xFFFF); field_0x0F = 1; @@ -441,6 +443,7 @@ bool dFlow_c::handleEventInternal(const MsbFlowInfo *element) { break; } case EVENT_LIGHT_PILLAR_34: { + // TODO what do these modes do? if (params1n2 == 1) { if (!dLytControlGame_c::getInstance()->isNotInStateMap()) { dLytControlGame_c::getInstance()->fn_802CCD40(true); @@ -551,24 +554,24 @@ bool dFlow_c::handleMessage() { if (mCurrentTextLabelName == "KEN0_08") { // "After winning the race in the Wing Ceremony..." // Current objective - use value from FiContext::getObjective? - if (field_0x5C < 0) { - field_0x5C = 8; + if (mFiSpeechArgument < 0) { + mFiSpeechArgument = 8; } - mCurrentTextLabelName.sprintf("KEN0_%02d", field_0x5C); + mCurrentTextLabelName.sprintf("KEN0_%02d", mFiSpeechArgument); } else if (mCurrentTextLabelName == "KEN1_000") { // "This is Skyloft..." // Area analysis - use value from FiContext::??? - if (field_0x5C < 0) { - field_0x5C = 0; + if (mFiSpeechArgument < 0) { + mFiSpeechArgument = 0; } - mCurrentTextLabelName.sprintf("KEN1_%03d", field_0x5C); + mCurrentTextLabelName.sprintf("KEN1_%03d", mFiSpeechArgument); } else if (mCurrentTextLabelName == "KEN2_000") { // "To search for Zelda..." // Hint - use value from FiContext::getFiAdviceHintEntry? - if (field_0x5C < 0) { - field_0x5C = 2; + if (mFiSpeechArgument < 0) { + mFiSpeechArgument = 2; } - mCurrentTextLabelName.sprintf("KEN2_%03d", field_0x5C); + mCurrentTextLabelName.sprintf("KEN2_%03d", mFiSpeechArgument); } else if (mCurrentTextLabelName == "KEN3_500") { // "Master, your current selection of pouch items is..." // Equipment focus @@ -730,18 +733,18 @@ bool dFlow_c::handleMessage() { u16 dFlow_c::getSwitchChoice(const MsbFlowInfo *element, u16 param) const { u16 result = 0; - if (param < 14 || param > 16) { + if (param < BRANCH_14 || param > BRANCH_16) { result = (this->*(sBranchHandlers[param]))(element); } return result; } -inline void setTagProcessorFiArgument(s32 argIdx, s32 btnIdx) { +inline void syncFiButtonText(s32 argIdx, s32 btnIdx) { dTagProcessor_c *p = dLytMsgWindow_c::getInstance()->getTagProcessor(); p->setStringArg(FiContext::getMessageForFiInfo(argIdx), btnIdx); } -inline void setTagProcessorArgument(s32 textLabel, s32 btnIdx) { +inline void setFiButtonTextDirectly(s32 textLabel, s32 btnIdx) { dTagProcessor_c *p = dLytMsgWindow_c::getInstance()->getTagProcessor(); p->setStringArg(FiContext::getButtonText(textLabel), btnIdx); } @@ -755,14 +758,18 @@ u16 dFlow_c::branchHandler01(const MsbFlowInfo *element) const { } u16 dFlow_c::branchHandler02(const MsbFlowInfo *element) const { - if (FiContext::getDoSpecialFiMenuHandlingChecked()) { - if (dLytMsgWindow_c::getInstance()->getTextOptionSelection() == 0 && FiContext::getGlobalFiInfo0(0) == 9) { + if (FiContext::getIsInFiMainMenuChecked()) { + if (dLytMsgWindow_c::getInstance()->getTextOptionSelection() == 0 && + FiContext::getGlobalFiInfo0(0) == FiContext::KEN8_Advice) { + // HACK (?): If the user presses "Advice" on the Fi main menu, + // which is known to be button 0, update Fi's buttons since that + // menu isn't entirely integrated into the flow FiContext::do_resetAdviceOptions(); - setTagProcessorFiArgument(0, 0); - setTagProcessorFiArgument(1, 1); - setTagProcessorFiArgument(2, 2); + syncFiButtonText(0, 0); + syncFiButtonText(1, 1); + syncFiButtonText(2, 2); } else { - FiContext::setDoSpecialFiMenuHandling(false); + FiContext::setIsInFiMainMenu(false); } } return dLytMsgWindow_c::getInstance()->getTextOptionSelection(); @@ -938,12 +945,29 @@ u16 dFlow_c::branchHandler22(const MsbFlowInfo *element) const { } dFlow_c::BranchHandler dFlow_c::sBranchHandlers[] = { - &dFlow_c::branchHandler00, &dFlow_c::branchHandler01, &dFlow_c::branchHandler02, &dFlow_c::branchHandler03, - &dFlow_c::branchHandler04, &dFlow_c::branchHandler05, &dFlow_c::branchHandler06, &dFlow_c::branchHandler07, - &dFlow_c::branchHandler08, &dFlow_c::branchHandler09, &dFlow_c::branchHandler10, &dFlow_c::branchHandler11, - &dFlow_c::branchHandler12, &dFlow_c::branchHandler13, &dFlow_c::branchHandler14, &dFlow_c::branchHandler15, - &dFlow_c::branchHandler16, &dFlow_c::branchHandler17, &dFlow_c::branchHandler18, &dFlow_c::branchHandler19, - &dFlow_c::branchHandler20, &dFlow_c::branchHandler21, &dFlow_c::branchHandler22, + &dFlow_c::branchHandler00, // BRANCH_SELECTED_OPTION_0 + &dFlow_c::branchHandler01, // BRANCH_SELECTED_OPTION_1 + &dFlow_c::branchHandler02, // BRANCH_SELECTED_OPTION_FI + &dFlow_c::branchHandler03, // BRANCH_STORYFLAG + &dFlow_c::branchHandler04, // BRANCH_NONE + &dFlow_c::branchHandler05, // BRANCH_ZONEFLAG + &dFlow_c::branchHandler06, // BRANCH_SCENEFLAG + &dFlow_c::branchHandler07, // BRANCH_EVENT_COUNTER_THRESHOLD_1 + &dFlow_c::branchHandler08, // BRANCH_EVENT_COUNTER_THRESHOLD_2 + &dFlow_c::branchHandler09, // BRANCH_TEMPFLAG + &dFlow_c::branchHandler10, // BRANCH_CURRENT_RUPEES + &dFlow_c::branchHandler11, // BRANCH_RAND_2 + &dFlow_c::branchHandler12, // BRANCH_RAND_3 + &dFlow_c::branchHandler13, // BRANCH_RAND_4 + &dFlow_c::branchHandler14, // BRANCH_14 + &dFlow_c::branchHandler15, // BRANCH_15 + &dFlow_c::branchHandler16, // BRANCH_16 + &dFlow_c::branchHandler17, // BRANCH_FREE_SPACE_IN_POUCH + &dFlow_c::branchHandler18, // BRANCH_18 + &dFlow_c::branchHandler19, // BRANCH_19 + &dFlow_c::branchHandler20, // BRANCH_FREE_SPACE_IN_ITEM_CHECK + &dFlow_c::branchHandler21, // BRANCH_TARGET_ACTOR_HAS_KILL_COUNT + &dFlow_c::branchHandler22, // BRANCH_22 }; bool dFlow_c::handleBranch() { @@ -997,19 +1021,19 @@ void dFlow_c::triggerEntryPoint(s32 labelPart1, s32 labelPart2) { if (labelPart1 == 6 && labelPart2 == 801) { // "You called for me, Master?" FiContext::do_prepareFiCallOptions(); - FiContext::setDoSpecialFiMenuHandling(true); + FiContext::setIsInFiMainMenu(true); FiContext::do_fn_8016CB40(); - setTagProcessorFiArgument(0, 0); - setTagProcessorFiArgument(1, 1); - setTagProcessorFiArgument(2, 2); - setTagProcessorArgument(FiContext::KEN8_Nevermind, 3); + syncFiButtonText(0, 0); + syncFiButtonText(1, 1); + syncFiButtonText(2, 2); + setFiButtonTextDirectly(FiContext::KEN8_Nevermind, 3); } else if (labelPart1 == 6 && labelPart2 == 802) { // Doesn't seem to exist in the files - FiContext::setDoSpecialFiMenuHandling(true); - setTagProcessorFiArgument(0, 0); - setTagProcessorFiArgument(1, 1); - setTagProcessorFiArgument(2, 2); - setTagProcessorArgument(FiContext::KEN8_Nevermind, 3); + FiContext::setIsInFiMainMenu(true); + syncFiButtonText(0, 0); + syncFiButtonText(1, 1); + syncFiButtonText(2, 2); + setFiButtonTextDirectly(FiContext::KEN8_Nevermind, 3); } u16 entry = findEntryPoint(labelPart1, labelPart2); start(entry); @@ -1024,8 +1048,8 @@ u16 dFlow_c::getField_0x44() const { return field_0x44; } -u16 dFlow_c::getField_0x46() const { - return field_0x46; +u16 dFlow_c::getNextFiFlow() const { + return mNextFiFlow; } bool dFlow_c::triggerEntryPointChecked(s32 labelPart1, s32 labelPart2) { @@ -1053,7 +1077,7 @@ void dFlow_c::start(u16 entry) { field_0x3C = 0; field_0x40 = -1; field_0x44 = -1; - field_0x46 = -1; + mNextFiFlow = -1; mDelayTimer = 0; std::memset(&mFlowInfo, 0, sizeof(MsbFlowInfo)); CURRENT_ACTOR_EVENT_FLOW_MANAGER = this; @@ -1087,18 +1111,20 @@ bool dFlow_c::advanceUntil(s32 searchType, s32 searchParam3, s32 *pOutParams1n2) keepGoing = true; break; case FLOW_BRANCH: - if (element->param3 <= 2) { + if (element->param3 <= BRANCH_SELECTED_OPTION_FI) { + // Skip evaluating if next branch depends on user input keepGoing = false; } else { + // Otherwise keepGoing = handleBranch(); } break; case FLOW_EVENT: switch (element->param3) { - case 7: - case 23: - case 27: keepGoing = handleEvent(); continue; - case 34: + case EVENT_LOAD_FI_FLOW: + case EVENT_COUNTER_THRESHOLD: + case 27: keepGoing = handleEvent(); continue; + case EVENT_LIGHT_PILLAR_34: if (element->params1n2 == 2) { keepGoing = false; continue; diff --git a/src/d/lyt/msg_window/d_lyt_msg_window.cpp b/src/d/lyt/msg_window/d_lyt_msg_window.cpp index d7c4efb6..6317e712 100644 --- a/src/d/lyt/msg_window/d_lyt_msg_window.cpp +++ b/src/d/lyt/msg_window/d_lyt_msg_window.cpp @@ -515,7 +515,7 @@ void dLytMsgWindow_c::executeState_WaitKeySelectQuestion() { mTextOptionSelection = selection; field_0x1220 = 0; if (FiContext::GetInstance() != nullptr) { - doFiThing = FiContext::GetInstance()->getDoSpecialFiMenuHandling(); + doFiThing = FiContext::GetInstance()->getIsInFiMainMenu(); } if (doFiThing) { diff --git a/src/toBeSorted/fi_context.cpp b/src/toBeSorted/fi_context.cpp index 1f5b3647..e20f69c6 100644 --- a/src/toBeSorted/fi_context.cpp +++ b/src/toBeSorted/fi_context.cpp @@ -380,7 +380,7 @@ void FiContext::reset() { mTargetActorId = -1; mFiHelpIndex = -1; - mDoSpecialFiMenuHandling = false; + mIsInFiMainMenu = false; } void FiContext::resetSaveTimeRelated() {