From 6646fb6135e26973dd8205007ee272baa5afdf3a Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 12 May 2025 00:38:29 +0200 Subject: [PATCH 1/6] fi_context OK (also cleanup dFlow_c) --- config/SOUE01/splits.txt | 2 + config/SOUE01/symbols.txt | 34 +- configure.py | 2 +- include/d/d_message.h | 2 +- include/d/d_pouch.h | 2 + include/d/lyt/meter/d_lyt_meter.h | 16 + include/d/lyt/meter/d_lyt_meter_cross_btn.h | 2 +- .../d/lyt/meter/d_lyt_meter_shield_gauge.h | 4 + include/toBeSorted/fi_context.h | 126 +++-- include/toBeSorted/file_manager.h | 4 +- include/toBeSorted/unk_save_time.h | 8 +- src/REL/d/d_s_boot.cpp | 14 +- src/d/d_message.cpp | 93 +++- src/d/lyt/meter/d_lyt_meter_cross_btn.cpp | 10 +- src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp | 2 +- src/d/lyt/msg_window/d_lyt_msg_window.cpp | 8 +- src/toBeSorted/d_emitter.cpp | 2 + src/toBeSorted/fi_context.cpp | 439 ++++++++++++++++++ src/toBeSorted/file_manager.cpp | 4 +- 19 files changed, 686 insertions(+), 88 deletions(-) create mode 100644 src/toBeSorted/fi_context.cpp diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index a1900414..f41d3819 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -1010,7 +1010,9 @@ d/lyt/d_lyt_cursor_stick.cpp: toBeSorted/fi_context.cpp: .text start:0x8016BCE0 end:0x8016CBD8 align:16 .data start:0x80527BC0 end:0x80527BD0 + .sdata start:0x80572A08 end:0x80572A10 .sbss start:0x80575500 end:0x80575508 + .sdata2 start:0x8057A1A8 end:0x8057A1D8 toBeSorted/item_mdl_name.cpp: .text start:0x8016CBE0 end:0x8016CC34 align:16 diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index 726257d4..f11f1d97 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -9329,30 +9329,30 @@ LytCursorStick__dtor = .text:0x8016BBF0; // type:function size:0x58 fn_8016BC50 = .text:0x8016BC50; // type:function size:0x88 isValid__16FiAnalysisHandleCFv = .text:0x8016BCE0; // type:function size:0x14 getAreaIndexForFiAreaName__16FiAnalysisHandleCFv = .text:0x8016BD00; // type:function size:0x44 -fn_8016BD50 = .text:0x8016BD50; // type:function size:0x68 +getCurrentFocus__16FiAnalysisHandleFv = .text:0x8016BD50; // type:function size:0x68 getEquipmentFocus__16FiAnalysisHandleCFv = .text:0x8016BDC0; // type:function size:0x68 -getSuitabilityArg__16FiAnalysisHandleCFv = .text:0x8016BE30; // type:function size:0x4C -getSuitabilityLabel__16FiAnalysisHandleCFv = .text:0x8016BE80; // type:function size:0x50 -shieldRelated__16FiAnalysisHandleFv = .text:0x8016BED0; // type:function size:0x44 +getSuitabilityPercentageArg__16FiAnalysisHandleCFv = .text:0x8016BE30; // type:function size:0x4C +getEquipmentRecommendation__16FiAnalysisHandleCFv = .text:0x8016BE80; // type:function size:0x50 +getThreatenedShield__16FiAnalysisHandleFv = .text:0x8016BED0; // type:function size:0x44 getShieldMessage__16FiAnalysisHandleFv = .text:0x8016BF20; // type:function size:0x44 -initializeNaviTable = .text:0x8016BF70; // type:function size:0x88 +initialize__9FiContextFPv = .text:0x8016BF70; // type:function size:0x88 getNaviTableProgressSummary__9FiContextFv = .text:0x8016C000; // type:function size:0xB8 getFiAdviceHintEntry__9FiContextFv = .text:0x8016C0C0; // type:function size:0xC4 -getUnkObjectiveValue__9FiContextFv = .text:0x8016C190; // type:function size:0x1CC +getObjective__9FiContextFv = .text:0x8016C190; // type:function size:0x1CC getNaviTableEquipmentCheckEntry__9FiContextFv = .text:0x8016C360; // type:function size:0x9C -FiContext__setTargetedActorTextId = .text:0x8016C400; // type:function size:0x9C +setTargetedActorTextId__9FiContextFl = .text:0x8016C400; // type:function size:0x9C rateBattlePerformance__9FiContextFUc = .text:0x8016C4A0; // type:function size:0x148 -prepareFiHelpIndex = .text:0x8016C5F0; // type:function size:0x288 +prepareFiHelpIndex__9FiContextFv = .text:0x8016C5F0; // type:function size:0x288 getGlobalFiInfo0__9FiContextFl = .text:0x8016C880; // type:function size:0x20 -getTextMessage__9FiContextFl = .text:0x8016C8A0; // type:function size:0x54 +getButtonText__9FiContextFl = .text:0x8016C8A0; // type:function size:0x54 create__9FiContextFv = .text:0x8016C900; // type:function size:0x2C -FiContext__init = .text:0x8016C930; // type:function size:0xB4 -fn_8016C9F0 = .text:0x8016C9F0; // type:function size:0xC -fn_8016CA00__9FiContextFv = .text:0x8016CA00; // type:function size:0xFC -fn_8016CB00__9FiContextFl = .text:0x8016CB00; // type:function size:0x1C -fn_8016CB20__9FiContextFv = .text:0x8016CB20; // type:function size:0x1C +reset__9FiContextFv = .text:0x8016C930; // type:function size:0xB4 +resetSaveTimeRelated__9FiContextFv = .text:0x8016C9F0; // type:function size:0xC +prepareFiCallOptions__9FiContextFv = .text:0x8016CA00; // type:function size:0xFC +setAdviceOptions__9FiContextFl = .text:0x8016CB00; // type:function size:0x1C +resetAdviceOptions__9FiContextFv = .text:0x8016CB20; // type:function size:0x1C fn_8016CB40__9FiContextFv = .text:0x8016CB40; // type:function size:0x1C -fn_8016CB60 = .text:0x8016CB60; // type:function size:0x78 +isInLeviasFightMaybe__9FiContextFv = .text:0x8016CB60; // type:function size:0x78 AcItem__isItemThatHasStruct = .text:0x8016CBE0; // type:function size:0x3C AcItem__getIndex = .text:0x8016CC20; // type:function size:0x14 checkedAdd__7CounterFl = .text:0x8016CC40; // type:function size:0xF0 @@ -10091,7 +10091,7 @@ adventurePouchFindItemSlot__F7ITEM_ID = .text:0x8018A650; // type:function size: adventurePouchCountItem__F7ITEM_ID = .text:0x8018A6E0; // type:function size:0x74 convertLytPouchSlot__Fl = .text:0x8018A760; // type:function size:0x1C convertFilePouchSlot__Fl = .text:0x8018A780; // type:function size:0xAC -fn_8018A830 = .text:0x8018A830; // type:function size:0x16C +summarizePouchContents__FPlPlPl = .text:0x8018A830; // type:function size:0x16C hasAnyShields__Fv = .text:0x8018A9A0; // type:function size:0x7C changeItemPouchExtensionCounter = .text:0x8018AA20; // type:function size:0x10C getExtraAmmoInPouchByType = .text:0x8018AB30; // type:function size:0x98 @@ -10903,7 +10903,7 @@ setField0x3C__7dFlow_cFv = .text:0x801B1C60; // type:function size:0xC checkField0x3C__7dFlow_cCFv = .text:0x801B1C70; // type:function size:0x14 start__7dFlow_cFUs = .text:0x801B1C90; // type:function size:0xA4 advanceUntil__7dFlow_cFllPl = .text:0x801B1D40; // type:function size:0x1C8 -shouldActorShowKillCount__7dFlow_cCFl = .text:0x801B1F10; // type:function size:0x38 +shouldHideKillCountForActor__7dFlow_cCFl = .text:0x801B1F10; // type:function size:0x38 clear__7dFlow_cFv = .text:0x801B1F50; // type:function size:0x2C createLytMiniGame__7dFlow_cFv = .text:0x801B1F80; // type:function size:0xD8 clearMinigame__7dFlow_cFv = .text:0x801B2060; // type:function size:0x98 diff --git a/configure.py b/configure.py index 8a823cf8..a52f71aa 100644 --- a/configure.py +++ b/configure.py @@ -532,7 +532,7 @@ config.libs = [ Object(Matching, "d/lyt/d_lyt_common_arrow.cpp"), Object(NonMatching, "d/lyt/d_lyt_common_title.cpp"), Object(NonMatching, "d/lyt/d_lyt_cursor_stick.cpp"), - Object(NonMatching, "toBeSorted/fi_context.cpp"), + Object(Matching, "toBeSorted/fi_context.cpp"), Object(NonMatching, "toBeSorted/item_mdl_name.cpp"), Object(Matching, "toBeSorted/counters/counter.cpp"), Object(NonMatching, "toBeSorted/counters/counters.cpp"), diff --git a/include/d/d_message.h b/include/d/d_message.h index 5e402e7b..358e7bbc 100644 --- a/include/d/d_message.h +++ b/include/d/d_message.h @@ -171,7 +171,7 @@ protected: void setNext(u16 next); void setField0x3C(); bool checkField0x3C() const; - bool shouldActorShowKillCount(s32 id) const; + bool shouldHideKillCountForActor(s32 id) const; static void playSound(u32); void createLytMiniGame(); void clearMinigame(); diff --git a/include/d/d_pouch.h b/include/d/d_pouch.h index 80d671d1..b1d064c1 100644 --- a/include/d/d_pouch.h +++ b/include/d/d_pouch.h @@ -4,6 +4,8 @@ #include "common.h" #include "d/a/d_a_itembase.h" +s32 summarizePouchContents(s32 *, s32 *, s32 *); + u32 convertFilePouchSlot(s32 fileSlot); s32 convertLytPouchSlot(s32 fileSlot); s32 getPouchSlotCount(bool unk); diff --git a/include/d/lyt/meter/d_lyt_meter.h b/include/d/lyt/meter/d_lyt_meter.h index 0e3c1068..45586773 100644 --- a/include/d/lyt/meter/d_lyt_meter.h +++ b/include/d/lyt/meter/d_lyt_meter.h @@ -421,6 +421,22 @@ public: } } + static f32 getShieldLevel() { + if (sInstance != nullptr) { + return sInstance->mMain.mShield.getLevel(); + } else { + return 0.0f; + } + } + + static f32 getShieldGaugePercentMaybe() { + if (sInstance != nullptr) { + return sInstance->mMain.mShield.getGaugePercentMaybe(); + } else { + return 0.0f; + } + } + private: /* 0x00004 */ d2d::ResAccIf_c mResAcc; /* 0x00374 */ dLytMeterEventSkip_c *mpEventSkip; diff --git a/include/d/lyt/meter/d_lyt_meter_cross_btn.h b/include/d/lyt/meter/d_lyt_meter_cross_btn.h index 571de597..a9c48dde 100644 --- a/include/d/lyt/meter/d_lyt_meter_cross_btn.h +++ b/include/d/lyt/meter/d_lyt_meter_cross_btn.h @@ -95,7 +95,7 @@ private: /* 0x420 */ dLytMeterCrossBtnParts_c mParts[4]; /* 0x620 */ s32 field_0x620; /* 0x624 */ s32 field_0x624; - /* 0x628 */ u16 field_0x628; + /* 0x628 */ u16 mSavedFiFlow; /* 0x62C */ s32 mCallCount0; /* 0x630 */ s32 mCallCount1; /* 0x634 */ u8 field_0x634; diff --git a/include/d/lyt/meter/d_lyt_meter_shield_gauge.h b/include/d/lyt/meter/d_lyt_meter_shield_gauge.h index 50c95115..c5e94895 100644 --- a/include/d/lyt/meter/d_lyt_meter_shield_gauge.h +++ b/include/d/lyt/meter/d_lyt_meter_shield_gauge.h @@ -43,6 +43,10 @@ public: return field_0x31D; } + f32 getLevel() const { + return field_0x2F0; + } + private: s32 getLytFrameForShield(s32) const; void setLevel(f32 level); diff --git a/include/toBeSorted/fi_context.h b/include/toBeSorted/fi_context.h index 6f3f8cd7..ef79ddfc 100644 --- a/include/toBeSorted/fi_context.h +++ b/include/toBeSorted/fi_context.h @@ -3,40 +3,65 @@ #include "common.h" -struct FiAnalysisEntry { - /* 0x00 */ const char *mStageName; - /* 0x04 */ u16 mStoryFlag; - /* 0x06 */ s16 mKen3MonsterPresenceEntry; - /* 0x08 */ u8 mSuitabilityPercent[4]; - /* 0x0C */ u16 mKen3SuitabilityAnalysis[4]; - /* 0x14 */ s16 mShieldType; - /* 0x16 */ s16 mShieldMessage; -}; +struct AnalysisEntry; class FiAnalysisHandle { public: + FiAnalysisHandle(AnalysisEntry *entry) : mpEntry(entry) {} s16 getEquipmentFocus() const; s16 getAreaIndexForFiAreaName() const; - s32 getSuitabilityArg() const; - s16 getSuitabilityLabel() const; + s32 getSuitabilityPercentageArg() const; + s16 getEquipmentRecommendation() const; s16 getShieldMessage(); - s16 shieldRelated(); + s16 getThreatenedShield(); bool isValid() const; private: - FiAnalysisEntry *mpEntry; + enum FiAnalysisEquipmentFocus_e { + FOCUS_COMBAT, + FOCUS_SURVIVAL, + FOCUS_TREASURE, + FOCUS_BALANCED, + }; + + static FiAnalysisEquipmentFocus_e getCurrentFocus(); + + AnalysisEntry *mpEntry; }; class FiContext { public: + enum KEN8_Button_e { + KEN8_Summary = 0, + KEN8_Hint = 1, + KEN8_Objective = 2, + KEN8_Analysis = 3, + KEN8_PlayTime = 4, + KEN8_Rumors = 5, + KEN8_Other = 6, + KEN8_Nevermind = 7, + KEN8_Advice = 9, + KEN8_None = 10, + }; + static void create(); + static void initialize(void *data); static s32 getGlobalFiInfo0(s32); - static FiAnalysisHandle getNaviTableEquipmentCheckEntry(); static u8 rateBattlePerformance(u8 enemyActorId); + + /** KEN0 - player progress */ static s16 getNaviTableProgressSummary(); + /** KEN1 - hint */ static s16 getFiAdviceHintEntry(); - static s16 getUnkObjectiveValue(); + /** KEN2 - objective */ + static s16 getObjective(); + /* KEN3 - analysis*/ + static FiAnalysisHandle getNaviTableEquipmentCheckEntry(); + + static s32 setTargetedActorTextId(s32 id); + + static u16 prepareFiHelpIndex(); bool getDoSpecialFiMenuHandling() const { return mDoSpecialFiMenuHandling; @@ -57,25 +82,49 @@ public: } static const wchar_t *getMessageForFiInfo(s32 arg) { - return getTextMessage(getGlobalFiInfo0(arg)); + return getButtonText(getGlobalFiInfo0(arg)); } static FiContext *GetInstance() { return sInstance; } + static bool getField_0x47() { + if (sInstance != nullptr) { + return sInstance->field_0x47; + } else { + return false; + } + } + static void setField_0x48(bool val) { if (sInstance != nullptr) { sInstance->field_0x48 = val; } } + static bool getField_0x48() { + if (sInstance != nullptr) { + return sInstance->field_0x48; + } else { + return false; + } + } + static void setField_0x4A(bool val) { if (sInstance != nullptr) { sInstance->field_0x4A = val; } } + static bool getField_0x4A() { + if (sInstance != nullptr) { + return sInstance->field_0x4A; + } else { + return false; + } + } + static s32 getHelpIndex() { if (sInstance != nullptr) { return sInstance->mFiHelpIndex; @@ -92,9 +141,9 @@ public: } } - static void do_fn_8016CB00(s32 arg) { + static void do_setAdviceOptions(s32 arg) { if (sInstance != nullptr) { - sInstance->fn_8016CB00(arg); + sInstance->setAdviceOptions(arg); } } @@ -104,34 +153,53 @@ public: } } - static void do_fn_8016CA00() { + static void do_prepareFiCallOptions() { if (sInstance != nullptr) { - sInstance->fn_8016CA00(); + sInstance->prepareFiCallOptions(); } } - static void do_fn_8016CB20() { + static void do_resetAdviceOptions() { if (sInstance != nullptr) { - sInstance->fn_8016CB20(); + sInstance->resetAdviceOptions(); } } - void resetField_0x3C(); + void reset(); + void resetSaveTimeRelated(); + void setAdviceOptions(s32 unused); + void resetAdviceOptions(); - static const wchar_t *getTextMessage(s32 idx); + static const wchar_t *getButtonText(s32 idx); private: + static void setTargetActorId(s32 id) { + if (sInstance != nullptr) { + sInstance->mTargetActorId = id; + } + } + + static void setHelpIndex(s32 idx) { + if (sInstance != nullptr) { + sInstance->mFiHelpIndex = idx; + } + } + static FiContext *sInstance; - void fn_8016CB00(s32); void fn_8016CB40(); - void fn_8016CA00(); - void fn_8016CB20(); + void prepareFiCallOptions(); + bool isInLeviasFightMaybe(); - /* 0x00 */ u8 _0x00[0x34 - 0x00]; + /* 0x00 */ s32 mFiButtonOptions[10]; // correspond to KEN8 with an offset of +1 + /* 0x28 */ s32 field_0x28; + /* 0x2C */ s32 field_0x2C; + /* 0x30 */ s32 field_0x30; /* 0x34 */ s32 mTargetActorId; /* 0x38 */ s32 mFiHelpIndex; - /* 0x3C */ u8 _0x3C[0x48 - 0x3C]; + /* 0x3C */ u8 mSaveTimeRelated; + /* 0x3D */ u8 field_0x3D[10]; + /* 0x47 */ bool field_0x47; /* 0x48 */ bool field_0x48; /* 0x49 */ bool field_0x49; /* 0x4A */ bool field_0x4A; diff --git a/include/toBeSorted/file_manager.h b/include/toBeSorted/file_manager.h index 6d92c6a3..5011684c 100644 --- a/include/toBeSorted/file_manager.h +++ b/include/toBeSorted/file_manager.h @@ -108,9 +108,9 @@ public: /* 8000AAA0 */ void initFile(int fileNum); /* 8000ABD0 */ void setCurrentHealthCapacity(s16 health); - /* 8000AC00 */ s16 getCurrentHealthCapacity(); + /* 8000AC00 */ u16 getCurrentHealthCapacity(); /* 8000AC50 */ void setCurrentHealth(s16 health); - /* 8000AC80 */ s16 getCurrentHealth(); + /* 8000AC80 */ u16 getCurrentHealth(); /* 8000ACD0 */ u16 getLoadRoomT1(); /* 8000AD20 */ u16 getLoadRoomT2(); diff --git a/include/toBeSorted/unk_save_time.h b/include/toBeSorted/unk_save_time.h index ef947c35..0cc5ec8d 100644 --- a/include/toBeSorted/unk_save_time.h +++ b/include/toBeSorted/unk_save_time.h @@ -13,6 +13,10 @@ public: return field_0x08; } + s64 getField_0x30() const { + return field_0x30; + } + s64 fn_801907D0(); void fn_801907F0(); void fn_801909A0(); @@ -21,7 +25,9 @@ private: static SaveTimeRelated *sInstance; /* 0x00 */ u8 _0x00[0x08 - 0x00]; - /* 0x08 */ u64 field_0x08; + /* 0x08 */ s64 field_0x08; + /* 0x10 */ u8 field_0x10[0x30 - 0x10]; + /* 0x30 */ s64 field_0x30; }; #endif diff --git a/src/REL/d/d_s_boot.cpp b/src/REL/d/d_s_boot.cpp index 75b1ed25..7cec6c7b 100644 --- a/src/REL/d/d_s_boot.cpp +++ b/src/REL/d/d_s_boot.cpp @@ -28,6 +28,9 @@ #include "toBeSorted/arc_managers/oarc_manager.h" #include "toBeSorted/d_d3d.h" #include "toBeSorted/d_hbm.h" +#include "toBeSorted/d_emitter.h" +#include "toBeSorted/d_particle.h" +#include "toBeSorted/fi_context.h" #include "toBeSorted/reload_color_fader.h" #include "toBeSorted/save_manager.h" #include "toBeSorted/save_related.h" @@ -276,10 +279,13 @@ sFPhaseBase::sFPhaseState dScBoot_c::cb7() { return sFPhaseBase::PHASE_RETRY; } - // TODO JParticle monkaS - OarcManager::GetInstance()->getData("System", "dat/navi_table.dat"); - OarcManager::GetInstance()->getData("JpaCommon", "dat/Common.jpc"); - OarcManager::GetInstance()->getData("JpaCommon", "dat/Common.jpn"); + void *naviDat = OarcManager::GetInstance()->getData("System", "dat/navi_table.dat"); + FiContext::initialize(naviDat); + dParticle::mgr_c::create(dHeap::work1Heap.heap, 0xBB8, 0xFA, 0xF); + dJEffManager_c::createEffManagers(); + void *jpc = OarcManager::GetInstance()->getData("JpaCommon", "dat/Common.jpc"); + void *jpn = OarcManager::GetInstance()->getData("JpaCommon", "dat/Common.jpn"); + dParticle::mgr_c::GetInstance()->createResource(dHeap::workExHeap.heap, 0, jpc, jpn); return sFPhaseBase::PHASE_NEXT; } diff --git a/src/d/d_message.cpp b/src/d/d_message.cpp index 2fb2b1a2..b500ef92 100644 --- a/src/d/d_message.cpp +++ b/src/d/d_message.cpp @@ -285,7 +285,7 @@ bool dFlow_c::handleEventInternal(const MsbFlowInfo *element) { case 2: { hi = 6; lo = 200; - field_0x5C = FiContext::getUnkObjectiveValue(); + field_0x5C = FiContext::getObjective(); break; } case 3: { @@ -319,7 +319,7 @@ bool dFlow_c::handleEventInternal(const MsbFlowInfo *element) { lo = 900; break; } - FiContext::do_fn_8016CB00(FiContext::getGlobalFiInfo0(selectedOption)); + FiContext::do_setAdviceOptions(FiContext::getGlobalFiInfo0(selectedOption)); field_0x46 = lo + hi * 1000; } else { triggerEntryPoint((params1n2 >> 16) & 0xFFFF, params1n2 & 0xFFFF); @@ -549,21 +549,29 @@ bool dFlow_c::handleMessage() { // Does this make sense? Result is unused... LMS_GetAttribute(dMessage_c::getMsbtInfoForIndex(dMessage_c::getInstance()->getCurrentTextFileNumber()), hasLabel); 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; } mCurrentTextLabelName.sprintf("KEN0_%02d", field_0x5C); } else if (mCurrentTextLabelName == "KEN1_000") { + // "This is Skyloft..." + // Area analysis - use value from FiContext::??? if (field_0x5C < 0) { field_0x5C = 0; } mCurrentTextLabelName.sprintf("KEN1_%03d", field_0x5C); } else if (mCurrentTextLabelName == "KEN2_000") { + // "To search for Zelda..." + // Hint - use value from FiContext::getFiAdviceHintEntry? if (field_0x5C < 0) { field_0x5C = 2; } mCurrentTextLabelName.sprintf("KEN2_%03d", field_0x5C); } else if (mCurrentTextLabelName == "KEN3_500") { + // "Master, your current selection of pouch items is..." + // Equipment focus FiAnalysisHandle analysis = FiContext::getNaviTableEquipmentCheckEntry(); SizedString<16> label; label.sprintf("KEN3_%03d", analysis.getEquipmentFocus()); @@ -571,6 +579,8 @@ bool dFlow_c::handleMessage() { dMessage_c::getTextMessageByLabel(label, true, nullptr, nullptr), 0 ); } else if (mCurrentTextLabelName == "KEN3_000") { + // "You are located in the Sealed Grounds..." + // Threat assessment FiAnalysisHandle analysis = FiContext::getNaviTableEquipmentCheckEntry(); s16 value = analysis.getAreaIndexForFiAreaName(); if (value < 0) { @@ -578,17 +588,23 @@ bool dFlow_c::handleMessage() { } mCurrentTextLabelName.sprintf("KEN3_%03d", value); } else if (mCurrentTextLabelName == "KEN3_501") { + // "Suitability to current location is..." + // Suitability analysis FiAnalysisHandle analysis = FiContext::getNaviTableEquipmentCheckEntry(); - s32 arg = analysis.getSuitabilityArg(); + s32 arg = analysis.getSuitabilityPercentageArg(); dLytMsgWindow_c::getInstance()->setNumericArg0(arg); } else if (mCurrentTextLabelName == "KEN3_100") { + // "My projections indicate that equipping..." + // Equipment recommendation FiAnalysisHandle analysis = FiContext::getNaviTableEquipmentCheckEntry(); - s16 value = analysis.getSuitabilityLabel(); + s16 value = analysis.getEquipmentRecommendation(); if (value < 0) { value = 0; } mCurrentTextLabelName.sprintf("KEN3_%03d", value); } else if (mCurrentTextLabelName == "KEN3_200") { + // "To make matters worse, your Wooden Shield..." + // Shield danger (wooden vs fire, iron vs electrical) FiAnalysisHandle analysis = FiContext::getNaviTableEquipmentCheckEntry(); s16 value = analysis.getShieldMessage(); if (value < 0) { @@ -596,6 +612,7 @@ bool dFlow_c::handleMessage() { } mCurrentTextLabelName.sprintf("KEN3_%03d", value); } else if (mCurrentTextLabelName == "KEN4_000") { + // Your hearts have decreased quite dramatically... s32 fiHelpIndex = FiContext::getHelpIndex(); if (fiHelpIndex < 0) { fiHelpIndex = 0; @@ -605,6 +622,7 @@ bool dFlow_c::handleMessage() { } mCurrentTextLabelName.sprintf("KEN4_%03d", fiHelpIndex); } else if (mCurrentTextLabelName == "KEN5_000") { + // This is... s32 targetActorId = FiContext::getTargetActorId(); if (targetActorId < 0) { targetActorId = 0; @@ -612,9 +630,12 @@ bool dFlow_c::handleMessage() { if (targetActorId <= 480) { mCurrentTextLabelName.sprintf("KEN5_%03d", targetActorId); } else { + // "My apologies. I have no relevant information on the subject in my sizable memory." + // FiHead mCurrentTextLabelName.sprintf("KEN7_000"); } } else if (mCurrentTextLabelName == "KEN6_000") { + // "Target lock: ..." s32 targetActorId = FiContext::getTargetActorId(); if (targetActorId < 0) { targetActorId = 0; @@ -625,6 +646,7 @@ bool dFlow_c::handleMessage() { mCurrentTextLabelName.sprintf("KEN7_000"); } } else if (mCurrentTextLabelName == "KEN6_107") { + // "You have defeated of this type of enemy. My analysis shows that your battle performance..." s32 targetActorId = FiContext::getTargetActorId(); if (targetActorId < 0) { targetActorId = 0; @@ -633,26 +655,31 @@ bool dFlow_c::handleMessage() { u8 performance = FiContext::rateBattlePerformance(targetActorId); if (performance == 0xFF) { dLytMsgWindow_c::getInstance()->setNumericArg0(killCount); + // "You have defeated of this enemy type. I am unable to analyze your battle performance..." mCurrentTextLabelName.sprintf("KEN6_108"); } else { dLytMsgWindow_c::getInstance()->setNumericArg0(killCount); SizedString<16> tmpLabel; + // "very strong, ..., very weak" tmpLabel.sprintf("KEN6_1%02d", performance); dLytMsgWindow_c::getInstance()->getTagProcessor()->setStringArg( dMessage_c::getTextMessageByLabel(tmpLabel, true, nullptr, nullptr), 0 ); } } else if (mCurrentTextLabelName == "KEN7_000") { + // "My apologies. I have no relevant information on the subject in my sizable memory." s32 targetActorId = FiContext::getTargetActorId(); if (targetActorId < 0) { targetActorId = 0; } if (targetActorId <= 561) { + // object info mCurrentTextLabelName.sprintf("KEN7_%03d", targetActorId); } else { mCurrentTextLabelName.sprintf("KEN7_000"); } } else if (mCurrentTextLabelName == "KEN8_000" || mCurrentTextLabelName == "KEN2_096") { + // "Current Session Play Time: ... Total Play Time: ..." s32 seconds = OS_TICKS_TO_SEC(SaveTimeRelated::GetInstance()->getField_0x08()); s32 minutes_ = seconds / 60; s32 minutes = minutes_ % 60; @@ -672,12 +699,16 @@ bool dFlow_c::handleMessage() { s32 time[4] = {hours, minutes, hours1, minutes1}; dLytMsgWindow_c::getInstance()->setNumericArgs(time, 4); } else if (mCurrentTextLabelName == "KEN9_000") { + // Random hint s32 v; if (StoryflagManager::sInstance->getCounterOrFlag(530)) { + // "When you require my analysis..." v = 200; } else if (dStageMgr_c::GetInstance()->getSTIFbyte4() == 0) { + // Sky rumor v = cM::rndInt(30); } else { + // Elsewhere rumor v = cM::rndInt(30) + 30; } mCurrentTextLabelName.sprintf("KEN9_%03d", v); @@ -705,14 +736,14 @@ u16 dFlow_c::getSwitchChoice(const MsbFlowInfo *element, u16 param) const { return result; } -inline void setTagProcessorFiArgument(s32 a1, s32 a2) { +inline void setTagProcessorFiArgument(s32 argIdx, s32 btnIdx) { dTagProcessor_c *p = dLytMsgWindow_c::getInstance()->getTagProcessor(); - p->setStringArg(FiContext::getMessageForFiInfo(a1), a2); + p->setStringArg(FiContext::getMessageForFiInfo(argIdx), btnIdx); } -inline void setTagProcessorArgument(s32 a1, s32 a2) { +inline void setTagProcessorArgument(s32 textLabel, s32 btnIdx) { dTagProcessor_c *p = dLytMsgWindow_c::getInstance()->getTagProcessor(); - p->setStringArg(FiContext::getTextMessage(a1), a2); + p->setStringArg(FiContext::getButtonText(textLabel), btnIdx); } u16 dFlow_c::branchHandler00(const MsbFlowInfo *element) const { @@ -726,7 +757,7 @@ 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) { - FiContext::do_fn_8016CB20(); + FiContext::do_resetAdviceOptions(); setTagProcessorFiArgument(0, 0); setTagProcessorFiArgument(1, 1); setTagProcessorFiArgument(2, 2); @@ -849,7 +880,7 @@ u16 dFlow_c::branchHandler19(const MsbFlowInfo *element) const { break; case 6: { FiAnalysisHandle handle = FiContext::getNaviTableEquipmentCheckEntry(); - switch (handle.shieldRelated()) { + switch (handle.getThreatenedShield()) { case 0: if (dAcPy_c::getCurrentlyEquippedShieldType() == 0) { ret = 0; @@ -892,7 +923,7 @@ u16 dFlow_c::branchHandler20(const MsbFlowInfo *element) const { u16 dFlow_c::branchHandler21(const MsbFlowInfo *element) const { u16 ret = 0; - if (shouldActorShowKillCount(FiContext::getTargetActorId())) { + if (shouldHideKillCountForActor(FiContext::getTargetActorId())) { ret = 1; } return ret; @@ -965,20 +996,20 @@ void dFlow_c::triggerEntryPoint(s32 labelPart1, s32 labelPart2) { if (labelPart1 == 6 && labelPart2 == 801) { // "You called for me, Master?" - FiContext::do_fn_8016CA00(); + FiContext::do_prepareFiCallOptions(); FiContext::setDoSpecialFiMenuHandling(true); FiContext::do_fn_8016CB40(); setTagProcessorFiArgument(0, 0); setTagProcessorFiArgument(1, 1); setTagProcessorFiArgument(2, 2); - setTagProcessorArgument(7, 3); + setTagProcessorArgument(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(7, 3); + setTagProcessorArgument(FiContext::KEN8_Nevermind, 3); } u16 entry = findEntryPoint(labelPart1, labelPart2); start(entry); @@ -1086,13 +1117,35 @@ bool dFlow_c::advanceUntil(s32 searchType, s32 searchParam3, s32 *pOutParams1n2) return 0; } -// TODO: Where are these IDs from? -static const s32 sActorsWithKillCount[] = {0, 1, 10, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 65, 67, 77, 81, 87, 88, 89, 90, -1}; +// TODO: Used KEN6 as reference, will be set from dAcBase_c::targetFiTextId (0x114) +static const s32 sActorsWithoutKillCount[] = { + 0, // Remlit (Day) + 1, // Remlit (Night) + 10, // Moldarach + 46, // Stalmaster + 47, // LD-002S Scervo + 48, // Koloktos + 49, // Ghirahim (G1) + 50, // Ghirahim (G2) + 51, // Ghirahim (G3.1) + 52, // The Imprisoned + 53, // The Imprisoned + 54, // The Imprisoned + 55, // Demise + 65, // Scaldera + 67, // + 77, // Tentalus + 81, // Peahat + 87, // Sentrobe Bomb + 88, // LD-003D Dreadfuse + 89, // Ghirahim (G3.2) + 90, // Ghirahim (G3.3) + -1 // +}; -bool dFlow_c::shouldActorShowKillCount(s32 id) const { - for (s32 i = 0; sActorsWithKillCount[i] >= 0; i++) { - if (sActorsWithKillCount[i] == id) { +bool dFlow_c::shouldHideKillCountForActor(s32 id) const { + for (s32 i = 0; sActorsWithoutKillCount[i] >= 0; i++) { + if (sActorsWithoutKillCount[i] == id) { return true; } } diff --git a/src/d/lyt/meter/d_lyt_meter_cross_btn.cpp b/src/d/lyt/meter/d_lyt_meter_cross_btn.cpp index 010656f3..427cda47 100644 --- a/src/d/lyt/meter/d_lyt_meter_cross_btn.cpp +++ b/src/d/lyt/meter/d_lyt_meter_cross_btn.cpp @@ -8,6 +8,7 @@ #include "d/lyt/d_lyt_unknowns.h" #include "d/lyt/meter/d_lyt_meter.h" #include "toBeSorted/event_manager.h" +#include "toBeSorted/fi_context.h" #include "toBeSorted/small_sound_mgr.h" STATE_DEFINE(dLytMeterCrossBtnParts_c, Wait); @@ -406,7 +407,7 @@ bool dLytMeterCrossBtn_c::build(d2d::ResAccIf_c *resAcc) { field_0x635 = 0; field_0x636 = 0; - field_0x628 = 0xFFFF; + mSavedFiFlow = 0xFFFF; mCallCount0 = 0; mCallCount1 = 0; field_0x620 = 6; @@ -457,11 +458,10 @@ bool dLytMeterCrossBtn_c::remove() { return true; } -extern "C" u16 prepareFiHelpIndex(); bool dLytMeterCrossBtn_c::execute() { - u16 newFiValue = prepareFiHelpIndex(); - if (newFiValue != field_0x628) { - field_0x628 = newFiValue; + u16 newFiFlow = FiContext::prepareFiHelpIndex(); + if (newFiFlow != mSavedFiFlow) { + mSavedFiFlow = newFiFlow; mCallCount0 = 0; } diff --git a/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp b/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp index 09afec6b..df5b4ad4 100644 --- a/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp +++ b/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp @@ -278,7 +278,7 @@ bool dLytMeterShieldGauge_c::execute() { } if (mAnm[SHIELD_ANIM_BREAK].isEnabled()) { - if (field_0x318 == 0 && field_0x2E0 > 0) { + if (field_0x318 == 0 && field_0x2E0 > 0.0f) { mAnm[SHIELD_ANIM_BREAK].setFrame(0.0f); mAnm[SHIELD_ANIM_BREAK].setAnimEnable(true); // redundant? field_0x30C = 0; 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 53431f92..d7c4efb6 100644 --- a/src/d/lyt/msg_window/d_lyt_msg_window.cpp +++ b/src/d/lyt/msg_window/d_lyt_msg_window.cpp @@ -90,7 +90,7 @@ bool dLytMsgWindow_c::build() { mpMsgWindowUnk = new TextWindowUnk(mpTagProcessor); if (FiContext::GetInstance() != nullptr) { - FiContext::GetInstance()->resetField_0x3C(); + FiContext::GetInstance()->resetSaveTimeRelated(); } mpWindowTalk = nullptr; @@ -105,7 +105,7 @@ bool dLytMsgWindow_c::build() { mpCurrentSubtype = nullptr; mTextOptionSelection = 0; - mSpecialFiMenuValue = 7; + mSpecialFiMenuValue = FiContext::KEN8_Nevermind; field_0x1220 = 0; @@ -199,7 +199,7 @@ void dLytMsgWindow_c::executeState_Invisible() { } else { createSubMsgManager(mpTagProcessor->getMsgWindowSubtype()); field_0x828 = nullptr; - mSpecialFiMenuValue = 7; + mSpecialFiMenuValue = FiContext::KEN8_Nevermind; if (mpTagProcessor->getMsgWindowSubtype() == 6) { mpCurrentSubtype = mpWindowWood; dTextBox_c *box = mpCurrentSubtype->getTextBox(); @@ -523,7 +523,7 @@ void dLytMsgWindow_c::executeState_WaitKeySelectQuestion() { case 0: mSpecialFiMenuValue = FiContext::getGlobalFiInfo0(0); break; case 1: mSpecialFiMenuValue = FiContext::getGlobalFiInfo0(1); break; case 2: mSpecialFiMenuValue = FiContext::getGlobalFiInfo0(2); break; - case 3: mSpecialFiMenuValue = 7; break; + case 3: mSpecialFiMenuValue = FiContext::KEN8_Nevermind; break; } } diff --git a/src/toBeSorted/d_emitter.cpp b/src/toBeSorted/d_emitter.cpp index 8af6a5a3..e003f3e3 100644 --- a/src/toBeSorted/d_emitter.cpp +++ b/src/toBeSorted/d_emitter.cpp @@ -116,6 +116,7 @@ dEmitterBase_c::~dEmitterBase_c() { } JPABaseEmitter *dEmitterBase_c::GetNextEmitter(JPABaseEmitter *head) { + // Portability hazard: u32->pointer cast return reinterpret_cast(head->getUserWork()); } @@ -132,6 +133,7 @@ bool dEmitterBase_c::createEmitters( ); if (last != nullptr) { if (head != nullptr) { + // Portability hazard: pointer->u32 cast head->setUserWork(reinterpret_cast(last)); } else { mpEmitterHead = last; diff --git a/src/toBeSorted/fi_context.cpp b/src/toBeSorted/fi_context.cpp new file mode 100644 index 00000000..7a5831f8 --- /dev/null +++ b/src/toBeSorted/fi_context.cpp @@ -0,0 +1,439 @@ +#include "toBeSorted/fi_context.h" + +#include "common.h" +#include "d/a/d_a_item.h" +#include "d/d_message.h" +#include "d/d_pouch.h" +#include "d/d_sc_game.h" +#include "d/d_stage_mgr.h" +#include "d/flag/itemflag_manager.h" +#include "d/flag/storyflag_manager.h" +#include "d/lyt/meter/d_lyt_meter.h" +#include "sized_string.h" +#include "toBeSorted/file_manager.h" +#include "toBeSorted/unk_save_time.h" + +// https://github.com/lepelog/skywardsword-tools/wiki/Navi-Table-(Fi-Advice) + +// Portability hazard, only works for 32 bit architectures + +struct AdviceSummaryEntry { + /* 0x00 */ u16 storyflag; + /* 0x02 */ u16 KEN0_entry_num; +}; + +struct AdviceHintEntry { + /* 0x00 */ char *stage_name_ptr; + /* 0x04 */ s16 storyflag; + /* 0x06 */ u16 KEN1_entry_num; +}; + +struct ObjectiveEntry { + /* 0x00 */ u16 storyflag; + /* 0x02 */ u16 KEN2_entry_num; +}; + +struct AnalysisEntry { + /* 0x00 */ char *stage_name_ptr; + /* 0x04 */ s16 storyflag; + /* 0x06 */ u16 KEN3_danger_entry_num; + /* 0x08 */ u8 sutability_percent[4]; + /* 0x0C */ u16 KEN3_sutability_entry_num[4]; + /* 0x14 */ u16 area_shield_danger; // -1-no danger, 0-wooden burns, 1- iron electrifies + /* 0x16 */ u16 KEN3_shield_entry_num; +}; + +struct FileHeader { + /* 0x00 */ u32 magic; // Is `V001` + /* 0x04 */ u16 summary_count; + /* 0x06 */ u16 hint_count; + /* 0x08 */ u16 objective_count; + /* 0x0A */ u16 analysis_count; + /* 0x0C */ AdviceSummaryEntry *summary; // ptr to AdviceSummaryEntry[summary_count] + /* 0x10 */ AdviceHintEntry *hint; // ptr to AdviceHintEntry[hint_count] + /* 0x14 */ ObjectiveEntry *objective; // ptr to ObjectiveEntry[objective_count] + /* 0x18 */ AnalysisEntry *analysis; // ptr to AnalysisEntry[analysis_count] +}; + +bool FiAnalysisHandle::isValid() const { + return mpEntry != nullptr; +} + +s16 FiAnalysisHandle::getAreaIndexForFiAreaName() const { + if (isValid()) { + return mpEntry->KEN3_danger_entry_num; + } else { + return -1; + } +} + +FiAnalysisHandle::FiAnalysisEquipmentFocus_e FiAnalysisHandle::getCurrentFocus() { + s32 pouchContents = summarizePouchContents(nullptr, nullptr, nullptr); + if (pouchContents == 0) { + return FOCUS_COMBAT; + } else if (pouchContents == 1) { + return FOCUS_BALANCED; + } else if (pouchContents == 2) { + return FOCUS_TREASURE; + } else if (pouchContents == 3) { + return FOCUS_SURVIVAL; + } + return FOCUS_COMBAT; +} + +s16 FiAnalysisHandle::getEquipmentFocus() const { + static const s16 sEquipmentFocuses[] = {400, 403, 402, 401}; + if (!isValid()) { + return -1; + } else { + if (StoryflagManager::sInstance->getCounterOrFlag(530)) { + // "I cannot offer my usual analysis because you are currently engaged in a challenge created by the Thunder + // Dragon Lanayru." + return 180; + } + return sEquipmentFocuses[getCurrentFocus()]; + } +} + +s32 FiAnalysisHandle::getSuitabilityPercentageArg() const { + if (!isValid()) { + return -1; + } else { + return mpEntry->sutability_percent[getCurrentFocus()]; + } +} + +s16 FiAnalysisHandle::getEquipmentRecommendation() const { + if (!isValid()) { + return -1; + } else { + return mpEntry->KEN3_sutability_entry_num[getCurrentFocus()]; + } +} + +s16 FiAnalysisHandle::getThreatenedShield() { + if (isValid()) { + return mpEntry->area_shield_danger; + } else { + return -1; + } +} + +s16 FiAnalysisHandle::getShieldMessage() { + if (isValid()) { + return mpEntry->KEN3_shield_entry_num; + } else { + return -1; + } +} + +FiContext *FiContext::sInstance; +static FileHeader *sNaviTable; + +#define BIND_PTR(type, header, pointer) \ + pointer = reinterpret_cast(reinterpret_cast(header) + reinterpret_cast(pointer)) + +void FiContext::initialize(void *data) { + FileHeader *header = reinterpret_cast(data); + BIND_PTR(AdviceSummaryEntry, header, header->summary); + BIND_PTR(AdviceHintEntry, header, header->hint); + AdviceHintEntry *hint = header->hint; + for (s32 i = 0; i < header->hint_count; i++) { + BIND_PTR(char, header, hint[i].stage_name_ptr); + } + BIND_PTR(ObjectiveEntry, header, header->objective); + BIND_PTR(AnalysisEntry, header, header->analysis); + AnalysisEntry *analysis = header->analysis; + for (s32 i = 0; i < header->analysis_count; i++) { + BIND_PTR(char, header, analysis[i].stage_name_ptr); + } + sNaviTable = header; +} + +s16 FiContext::getNaviTableProgressSummary() { + if (StoryflagManager::sInstance->getFlag(530)) { + // When in boss rush, no progress is available since story flags + // are unreliable here. + // "You are currently reliving some of your previous battles within the Thunder Dragon's Lightning Round..." + return 40; + } else { + // Find the last entry with a set story flag + AdviceSummaryEntry *last = sNaviTable->summary + (sNaviTable->summary_count - 1); + for (s32 i = 0; i < sNaviTable->summary_count; i++) { + if (StoryflagManager::sInstance->getFlag(last->storyflag)) { + return last->KEN0_entry_num; + } + last--; + } + return -1; + } +} + +s16 FiContext::getFiAdviceHintEntry() { + if (StoryflagManager::sInstance->getFlag(530)) { + // When in boss rush, no hint since location doesn't make sense + // "Master, this is a world built from your memories by Lanayru, the Thunder Dragon" + return 37; + } else { + // Find the first entry that matches the current stage, if its story flag matches (if any) + AdviceHintEntry *first = sNaviTable->hint; + for (s32 i = 0; i < sNaviTable->hint_count; i++) { + if (dScGame_c::isCurrentStage(first->stage_name_ptr) && + (first->storyflag < 0 || StoryflagManager::sInstance->getFlag(first->storyflag))) { + return first->KEN1_entry_num; + } + first++; + } + // "This place has no name registered in my memory, and I have no useful data..." + return 31; + } +} + +s16 FiContext::getObjective() { + if (StoryflagManager::sInstance->getFlag(530)) { + // When in boss rush, objective is to beat the mode + // "Master, your primary objective is to defeat the enemy here and overcome the grueling task the Thunder + // Dragon, Lanayru, has set before you..." + return 92; + } else { + if (StoryflagManager::sInstance->getFlag(136) && StoryflagManager::sInstance->getFlag(143) && + StoryflagManager::sInstance->getFlag(144) && StoryflagManager::sInstance->getFlag(145) && + !StoryflagManager::sInstance->getFlag(133)) { + // "Demise has once again broken the seal that binds him..." + return 70; + } + + if (!StoryflagManager::sInstance->getCounterOrFlag(21)) { + if (ItemflagManager::sInstance->getFlagDirect(0xC5) && !ItemflagManager::sInstance->getFlagDirect(0xC6)) { + // "I project that the soil in Lanayru Province will not provide enough nourishment for the Life Tree + // Seedling..." + return 90; + } + + if (ItemflagManager::sInstance->getFlagDirect(0xC6)) { + // "Master, I recommend you take the Life Tree Fruit to the Thunder Dragon..." + return 91; + } + } + + // Find the last entry with a set story flag + ObjectiveEntry *last = sNaviTable->objective + (sNaviTable->objective_count - 1); + for (s32 i = 0; i < sNaviTable->objective_count; i++) { + if (StoryflagManager::sInstance->getFlag(last->storyflag)) { + return last->KEN2_entry_num; + } + last--; + } + return -1; + } +} + +FiAnalysisHandle FiContext::getNaviTableEquipmentCheckEntry() { + AnalysisEntry *first = sNaviTable->analysis; + for (s32 i = 0; i < sNaviTable->analysis_count; i++) { + // Find the first entry that matches the current stage, if its story flag matches (if any) + if (dScGame_c::isCurrentStage(first->stage_name_ptr) && + (first->storyflag < 0 || StoryflagManager::sInstance->getFlag(first->storyflag))) { + return FiAnalysisHandle(first); + } + first++; + } + return FiAnalysisHandle(nullptr); +} + +s32 FiContext::setTargetedActorTextId(s32 id) { + setTargetActorId(-1); + s32 ret; + if (id < 256) { + ret = 6600; // Flow? + setTargetActorId(id); + } else if (id < 512) { + ret = 6500; // Flow? + setTargetActorId(id - 256); + } else if (id < 768) { + ret = 6700; // Flow? + setTargetActorId(id - 512); + } else { + ret = 6500; // Flow? + setTargetActorId(id - 668); + } + return ret; +} + +u8 FiContext::rateBattlePerformance(u8 id) { + u8 ret = 0xFF; + u16 killCount = FileManager::GetInstance()->getEnemyKillCount(id); + u16 enemyHitCount = FileManager::GetInstance()->getHitCountFromEnemy(id); + if (killCount > 3 || enemyHitCount > 5) { + if (killCount == 0) { + ret = 6; + } else { + f32 ratio = (f32)enemyHitCount / (f32)killCount; + if (ratio <= 0.2f) { + ret = 0; + } else if (ratio <= (1.0f / 3.0f)) { + ret = 1; + } else if (ratio <= 1.0f) { + ret = 2; + } else if (ratio <= 1.5f) { + ret = 3; + } else if (ratio <= 2.5f) { + ret = 4; + } else if (ratio <= 4.0f) { + ret = 5; + } else { + ret = 6; + } + } + } + return ret; +} + +extern "C" bool isLowBattery1(); +extern "C" bool isLowBattery2(); + +u16 FiContext::prepareFiHelpIndex() { + u16 ret = 0xFFFF; + setHelpIndex(-1); + + if (dLytMeter_c::getShieldLevel() > 0.0f && dLytMeter_c::getShieldGaugePercentMaybe() > 0.0f) { + if (dLytMeter_c::getShieldGaugePercentMaybe() <= 6.0f) { + if (!getField_0x4A()) { + ret = 6402; + // "The integrity of your shield has weakened..." + setHelpIndex(1); + } + } else { + if (getField_0x4A()) { + setField_0x4A(false); + } + } + } + + if (FileManager::GetInstance()->getCurrentHealth() <= 12 && !StoryflagManager::sInstance->getCounterOrFlag(808)) { + ret = 6401; + // "Your hearts have decreased quite dramatically..." + setHelpIndex(0); + } + + if (isLowBattery2() || isLowBattery1()) { + if (!getField_0x48()) { + ret = 6400; + if (isLowBattery1()) { + // "Master, the batteries in your Wii Remote will be depleted any moment." + setHelpIndex(3); + } else { + // "Master, the batteries in your Wii Remote are nearly depleted." + setHelpIndex(2); + } + } + } else { + if (getField_0x48()) { + setField_0x48(false); + } + } + + u32 numRupees = dAcItem_c::getRupeeCounter(); + u32 walletCapacity = dAcItem_c::getCurrentWalletCapacity(); + + if (!StoryflagManager::sInstance->getFlag(727) && walletCapacity != 0 && numRupees == walletCapacity && + !getField_0x47()) { + ret = 6400; + // "Master, your wallet is full..." + setHelpIndex(5); + } + + return ret; +} + +s32 FiContext::getGlobalFiInfo0(s32 idx) { + if (sInstance != nullptr) { + return sInstance->mFiButtonOptions[idx]; + } + return KEN8_None; +} + +const wchar_t *FiContext::getButtonText(s32 idx) { + SizedString<16> str; + str.sprintf("KEN8_1%02d", idx + 1); + return dMessage_c::getTextMessageByLabel(str, true, nullptr, 0); +} + +void FiContext::create() { + sInstance = new FiContext(); + sInstance->reset(); +} + +void FiContext::reset() { + for (s32 i = 0; i < 10; i++) { + mFiButtonOptions[i] = KEN8_None; + field_0x3D[i] = 0xFF; + } + field_0x47 = false; + field_0x48 = false; + field_0x49 = false; + field_0x4A = false; + mSaveTimeRelated = 0xFF; + + fn_8016CB40(); + + mTargetActorId = -1; + mFiHelpIndex = -1; + mDoSpecialFiMenuHandling = false; +} + +void FiContext::resetSaveTimeRelated() { + mSaveTimeRelated = 0xFF; +} + +extern "C" bool isInAnySkyKeepRoom(); + +void FiContext::prepareFiCallOptions() { + s32 seconds1 = OS_TICKS_TO_SEC(SaveTimeRelated::GetInstance()->getField_0x30()); + s32 seconds2 = OS_TICKS_TO_SEC(SaveTimeRelated::GetInstance()->getField_0x08()); + u8 val = 2; + if (seconds2 < 300) { + val = 0; + } else if (seconds1 < 300) { + val = 1; + } + if (mSaveTimeRelated != val) { + mSaveTimeRelated = val; + } + + mFiButtonOptions[0] = KEN8_Advice; + if (dStageMgr_c::GetInstance()->getSTIFbyte4() == 0 && !isInAnySkyKeepRoom() && !isInLeviasFightMaybe()) { + // In the Sky, show play time + mFiButtonOptions[1] = KEN8_PlayTime; + } else { + // Elswhere, and in Sky Keep and Levias fight, present analysis + mFiButtonOptions[1] = KEN8_Analysis; + } + mFiButtonOptions[2] = KEN8_Objective; +} + +void FiContext::setAdviceOptions(s32 unused) { + mFiButtonOptions[0] = KEN8_Hint; + mFiButtonOptions[1] = KEN8_Rumors; + mFiButtonOptions[2] = KEN8_Summary; +} + +void FiContext::resetAdviceOptions() { + mFiButtonOptions[0] = KEN8_Hint; + mFiButtonOptions[1] = KEN8_Rumors; + mFiButtonOptions[2] = KEN8_Summary; +} + +void FiContext::fn_8016CB40() { + field_0x28 = 0; + field_0x2C = 1; + field_0x30 = 2; +} + +bool FiContext::isInLeviasFightMaybe() { + if (dScGame_c::isCurrentStage("F023") && StoryflagManager::sInstance->getFlag(368) && + !StoryflagManager::sInstance->getFlag(200)) { + return true; + } + return false; +} diff --git a/src/toBeSorted/file_manager.cpp b/src/toBeSorted/file_manager.cpp index 5939075d..3f8fdb5e 100644 --- a/src/toBeSorted/file_manager.cpp +++ b/src/toBeSorted/file_manager.cpp @@ -133,9 +133,9 @@ u16 *FileManager::getStoryFlagsMut() { } /* 8000ABD0 */ void FileManager::setCurrentHealthCapacity(s16 health) {} -/* 8000AC00 */ s16 FileManager::getCurrentHealthCapacity() {} +/* 8000AC00 */ u16 FileManager::getCurrentHealthCapacity() {} /* 8000AC50 */ void FileManager::setCurrentHealth(s16 health) {} -/* 8000AC80 */ s16 FileManager::getCurrentHealth() {} +/* 8000AC80 */ u16 FileManager::getCurrentHealth() {} /* 8000ACD0 */ u16 FileManager::getLoadRoomT1() {} /* 8000AD20 */ u16 FileManager::getLoadRoomT2() {} From c9cbe416d8ae6de7317605c757310dd0e06b6e7c Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 12 May 2025 00:46:01 +0200 Subject: [PATCH 2/6] Use item enum --- src/toBeSorted/fi_context.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/toBeSorted/fi_context.cpp b/src/toBeSorted/fi_context.cpp index 7a5831f8..47a76c94 100644 --- a/src/toBeSorted/fi_context.cpp +++ b/src/toBeSorted/fi_context.cpp @@ -204,13 +204,14 @@ s16 FiContext::getObjective() { } if (!StoryflagManager::sInstance->getCounterOrFlag(21)) { - if (ItemflagManager::sInstance->getFlagDirect(0xC5) && !ItemflagManager::sInstance->getFlagDirect(0xC6)) { + if (ItemflagManager::sInstance->getFlagDirect(ITEM_LIFE_TREE_SEED) && + !ItemflagManager::sInstance->getFlagDirect(ITEM_LIFE_TREE_FRUIT)) { // "I project that the soil in Lanayru Province will not provide enough nourishment for the Life Tree // Seedling..." return 90; } - if (ItemflagManager::sInstance->getFlagDirect(0xC6)) { + if (ItemflagManager::sInstance->getFlagDirect(ITEM_LIFE_TREE_FRUIT)) { // "Master, I recommend you take the Life Tree Fruit to the Thunder Dragon..." return 91; } From c241dbe301f94839175504f24d70615d67bac8d7 Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 12 May 2025 00:48:19 +0200 Subject: [PATCH 3/6] Constify --- include/toBeSorted/fi_context.h | 4 ++-- src/toBeSorted/fi_context.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/toBeSorted/fi_context.h b/include/toBeSorted/fi_context.h index ef79ddfc..949c067d 100644 --- a/include/toBeSorted/fi_context.h +++ b/include/toBeSorted/fi_context.h @@ -12,8 +12,8 @@ public: s16 getAreaIndexForFiAreaName() const; s32 getSuitabilityPercentageArg() const; s16 getEquipmentRecommendation() const; - s16 getShieldMessage(); - s16 getThreatenedShield(); + s16 getShieldMessage() const; + s16 getThreatenedShield() const; bool isValid() const; diff --git a/src/toBeSorted/fi_context.cpp b/src/toBeSorted/fi_context.cpp index 47a76c94..1f5b3647 100644 --- a/src/toBeSorted/fi_context.cpp +++ b/src/toBeSorted/fi_context.cpp @@ -111,7 +111,7 @@ s16 FiAnalysisHandle::getEquipmentRecommendation() const { } } -s16 FiAnalysisHandle::getThreatenedShield() { +s16 FiAnalysisHandle::getThreatenedShield() const { if (isValid()) { return mpEntry->area_shield_danger; } else { @@ -119,7 +119,7 @@ s16 FiAnalysisHandle::getThreatenedShield() { } } -s16 FiAnalysisHandle::getShieldMessage() { +s16 FiAnalysisHandle::getShieldMessage() const { if (isValid()) { return mpEntry->KEN3_shield_entry_num; } else { From 33efdfeec9be71687d07c3a4ab460703c2b7e93a Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 12 May 2025 21:35:03 +0200 Subject: [PATCH 4/6] 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() { From c7a094982dfe90272966e035c9ec2e2e109d2ac7 Mon Sep 17 00:00:00 2001 From: robojumper Date: Wed, 14 May 2025 21:15:10 +0200 Subject: [PATCH 5/6] Symbols --- config/SOUE01/symbols.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index a832ccdd..f2cbc469 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -9333,8 +9333,8 @@ getCurrentFocus__16FiAnalysisHandleFv = .text:0x8016BD50; // type:function size: getEquipmentFocus__16FiAnalysisHandleCFv = .text:0x8016BDC0; // type:function size:0x68 getSuitabilityPercentageArg__16FiAnalysisHandleCFv = .text:0x8016BE30; // type:function size:0x4C getEquipmentRecommendation__16FiAnalysisHandleCFv = .text:0x8016BE80; // type:function size:0x50 -getThreatenedShield__16FiAnalysisHandleFv = .text:0x8016BED0; // type:function size:0x44 -getShieldMessage__16FiAnalysisHandleFv = .text:0x8016BF20; // type:function size:0x44 +getThreatenedShield__16FiAnalysisHandleCFv = .text:0x8016BED0; // type:function size:0x44 +getShieldMessage__16FiAnalysisHandleCFv = .text:0x8016BF20; // type:function size:0x44 initialize__9FiContextFPv = .text:0x8016BF70; // type:function size:0x88 getNaviTableProgressSummary__9FiContextFv = .text:0x8016C000; // type:function size:0xB8 getFiAdviceHintEntry__9FiContextFv = .text:0x8016C0C0; // type:function size:0xC4 From b10472dac9d90688bd69c09d5b5faf4dc2dc0a6c Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 15 May 2025 19:30:39 +0200 Subject: [PATCH 6/6] A bit of shield gauge cleanup --- include/d/a/d_a_itembase.h | 15 ++ include/d/lyt/meter/d_lyt_meter.h | 8 +- .../d/lyt/meter/d_lyt_meter_shield_gauge.h | 22 +-- src/d/lyt/meter/d_lyt_meter.cpp | 6 +- src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp | 132 +++++++++--------- src/toBeSorted/fi_context.cpp | 4 +- 6 files changed, 104 insertions(+), 83 deletions(-) diff --git a/include/d/a/d_a_itembase.h b/include/d/a/d_a_itembase.h index 70950f06..90e81c14 100644 --- a/include/d/a/d_a_itembase.h +++ b/include/d/a/d_a_itembase.h @@ -2,6 +2,7 @@ #define D_A_ITEMBASE_H #include "d/a/obj/d_a_obj_base.h" +#include "m/m_vec.h" enum ITEM_ID { /* 0x000 */ ITEM_NONE = 0, @@ -210,6 +211,20 @@ enum ITEM_ID { /* 0x1FF */ MAX_ITEM_ID = 511 }; +enum SHIELD_TYPE_e { + /* 0x00 */ SHIELD_WOODEN_SHIELD = 0, + /* 0x01 */ SHIELD_BANDED_SHIELD = 1, + /* 0x02 */ SHIELD_BRACED_SHIELD = 2, + /* 0x03 */ SHIELD_IRON_SHIELD = 3, + /* 0x04 */ SHIELD_REINFORCED_SHIELD = 4, + /* 0x05 */ SHIELD_FORTIFIED_SHIELD = 5, + /* 0x06 */ SHIELD_SACRED_SHIELD = 6, + /* 0x07 */ SHIELD_DIVINE_SHIELD = 7, + /* 0x08 */ SHIELD_GODDESS_SHIELD = 8, + /* 0x09 */ SHIELD_HYLIAN_SHIELD = 9, + /* 0x0A */ SHIELD_NONE = 10, +}; + struct ItemFlagStruct { u8 mField_0x00; u8 mField_0x01; diff --git a/include/d/lyt/meter/d_lyt_meter.h b/include/d/lyt/meter/d_lyt_meter.h index 45586773..5f71f75e 100644 --- a/include/d/lyt/meter/d_lyt_meter.h +++ b/include/d/lyt/meter/d_lyt_meter.h @@ -421,17 +421,17 @@ public: } } - static f32 getShieldLevel() { + static f32 getShieldMaxDurability() { if (sInstance != nullptr) { - return sInstance->mMain.mShield.getLevel(); + return sInstance->mMain.mShield.getMaxDurability(); } else { return 0.0f; } } - static f32 getShieldGaugePercentMaybe() { + static f32 getShieldCurrentDurability() { if (sInstance != nullptr) { - return sInstance->mMain.mShield.getGaugePercentMaybe(); + return sInstance->mMain.mShield.getCurrentDurability(); } else { return 0.0f; } diff --git a/include/d/lyt/meter/d_lyt_meter_shield_gauge.h b/include/d/lyt/meter/d_lyt_meter_shield_gauge.h index c5e94895..ec012a83 100644 --- a/include/d/lyt/meter/d_lyt_meter_shield_gauge.h +++ b/include/d/lyt/meter/d_lyt_meter_shield_gauge.h @@ -31,8 +31,8 @@ public: mpOwnerPane = pane; } - f32 getGaugePercentMaybe() const { - return field_0x2E0; + f32 getCurrentDurability() const { + return mCurrentDurability; } void setfield_0x318(s32 v) { @@ -43,8 +43,8 @@ public: return field_0x31D; } - f32 getLevel() const { - return field_0x2F0; + f32 getMaxDurability() const { + return mMaxDurability; } private: @@ -63,22 +63,22 @@ private: /* 0x0D8 */ d2d::AnmGroup_c mAnm[8]; /* 0x2D8 */ d2d::AnmGroup_c *mpContainerAnmGroup; /* 0x2DC */ nw4r::lyt::Pane *mpOwnerPane; - /* 0x2E0 */ f32 field_0x2E0; + /* 0x2E0 */ f32 mCurrentDurability; /* 0x2E4 */ f32 field_0x2E4; - /* 0x2E8 */ f32 field_0x2E8; - /* 0x2EC */ f32 field_0x2EC; - /* 0x2F0 */ f32 field_0x2F0; + /* 0x2E8 */ f32 mSavedDurability; + /* 0x2EC */ f32 mAnimatingDurability; + /* 0x2F0 */ f32 mMaxDurability; /* 0x2F4 */ f32 field_0x2F4; /* 0x2F8 */ f32 field_0x2F8; /* 0x2FC */ s32 field_0x2FC; /* 0x300 */ f32 field_0x300; /* 0x304 */ f32 field_0x304; - /* 0x308 */ s32 field_0x308; + /* 0x308 */ s32 mCurrentShieldPouchSlot; /* 0x30C */ u8 field_0x30C; /* 0x30D */ u8 field_0x30D; /* 0x30E */ u8 field_0x30E; - /* 0x310 */ s32 field_0x310; - /* 0x314 */ s32 field_0x314; + /* 0x310 */ s32 mShieldType; + /* 0x314 */ s32 mSavedShieldType; /* 0x318 */ s32 field_0x318; /* 0x31C */ u8 field_0x31C; /* 0x31D */ u8 field_0x31D; diff --git a/src/d/lyt/meter/d_lyt_meter.cpp b/src/d/lyt/meter/d_lyt_meter.cpp index c52fe168..f4f5c0db 100644 --- a/src/d/lyt/meter/d_lyt_meter.cpp +++ b/src/d/lyt/meter/d_lyt_meter.cpp @@ -1267,7 +1267,7 @@ void dLytMeterMain_c::checkPaneVisibility() { mPanesVisible[METER_ANIM_NUN_BG] = false; } - if ((!isNotSilentRealmOrLoftwing() || (mShield.getGaugePercentMaybe() == 0.0f && mShield.getField_0x31D()) || + if ((!isNotSilentRealmOrLoftwing() || (mShield.getCurrentDurability() == 0.0f && mShield.getField_0x31D()) || dAcPy_c::GetLink()->getCurrentAction() == 0x8C || fn_800D5380(false) || field_0x13770 != 3 || MinigameManager::isInMinigameState(MinigameManager::FUN_FUN_ISLAND) || MinigameManager::isInMinigameState(MinigameManager::THRILL_DIGGER) || @@ -1533,7 +1533,7 @@ bool dLytMeterMain_c::execute() { if (mHeart.getCurrentHealthCapacity() / 4 <= 10) { heartsHeight = 0; - if (mShield.getGaugePercentMaybe() > 0.0f && + if (mShield.getCurrentDurability() > 0.0f && (mLyt.findPane("N_shieldAll_00")->IsVisible() || isNotSilentRealmOrLoftwing())) { rupeePos = 0; kakeraKeyPos = 1; @@ -1547,7 +1547,7 @@ bool dLytMeterMain_c::execute() { } } else { heartsHeight = 1; - if (mShield.getGaugePercentMaybe() > 0.0f && + if (mShield.getCurrentDurability() > 0.0f && (mLyt.findPane("N_shieldAll_00")->IsVisible() || isNotSilentRealmOrLoftwing())) { rupeePos = 1; kakeraKeyPos = 1; diff --git a/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp b/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp index df5b4ad4..8c811edc 100644 --- a/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp +++ b/src/d/lyt/meter/d_lyt_meter_shield_gauge.cpp @@ -1,6 +1,7 @@ #include "d/lyt/meter/d_lyt_meter_shield_gauge.h" #include "common.h" +#include "d/a/d_a_itembase.h" #include "d/d_pouch.h" #include "d/lyt/d2d.h" #include "d/lyt/d_lyt_meter_configuration.h" @@ -58,16 +59,16 @@ bool dLytMeterShieldGauge_c::build(d2d::ResAccIf_c *resAcc) { mpOwnerPane = nullptr; field_0x31D = 1; - field_0x2E0 = 0.0f; + mCurrentDurability = 0.0f; field_0x2E4 = 0.0f; - field_0x2E8 = 0.0f; - field_0x2EC = 0.0f; + mSavedDurability = 0.0f; + mAnimatingDurability = 0.0f; - field_0x308 = convertFilePouchSlot(FileManager::GetInstance()->getShieldPouchSlot()); - field_0x300 = field_0x2EC; - field_0x304 = field_0x2E0; + mCurrentShieldPouchSlot = convertFilePouchSlot(FileManager::GetInstance()->getShieldPouchSlot()); + field_0x300 = mAnimatingDurability; + field_0x304 = mCurrentDurability; field_0x2FC = dLytMeterConfiguration_c::GetInstance()->getField_0x1C8(); - field_0x2F0 = 80.0f; + mMaxDurability = 80.0f; field_0x2F4 = 80.0f; field_0x2F8 = mAnm[SHIELD_ANIM_USE].getAnimDuration() - 1.0f; @@ -77,15 +78,15 @@ bool dLytMeterShieldGauge_c::build(d2d::ResAccIf_c *resAcc) { field_0x31F = 0; field_0x31E = 0; field_0x318 = 0; - field_0x310 = 0; - field_0x314 = -1; + mShieldType = 0; + mSavedShieldType = -1; - mAnm[SHIELD_ANIM_UPDOWN].setFrame(field_0x2E0); + mAnm[SHIELD_ANIM_UPDOWN].setFrame(mCurrentDurability); mAnm[SHIELD_ANIM_UPDOWN].setAnimEnable(true); - field_0x2E4 = calcUpdownRatio(field_0x2E0); + field_0x2E4 = calcUpdownRatio(mCurrentDurability); mAnm[SHIELD_ANIM_USE].setFrame(field_0x2F8 - field_0x2E4); mAnm[SHIELD_ANIM_USE].setAnimEnable(true); - setLevel(field_0x2F0); + setLevel(mMaxDurability); mAnm[SHIELD_ANIM_LEVEL].setAnimEnable(true); mAnm[SHIELD_ANIM_TYPE].setFrame(getLytFrameForShield(0)); mAnm[SHIELD_ANIM_TYPE].setAnimEnable(true); @@ -124,83 +125,87 @@ bool dLytMeterShieldGauge_c::execute() { return true; } - if (field_0x2E0 == 0.0f) { + if (mCurrentDurability == 0.0f) { field_0x318 = 2; } - bool b1 = false; + bool bIsAnimatingDurability = false; bool b2 = true; bool b3 = false; bool b4 = false; - if (field_0x310 != field_0x314 || - field_0x308 != convertFilePouchSlot(FileManager::GetInstance()->getShieldPouchSlot())) { + if (mShieldType != mSavedShieldType || + mCurrentShieldPouchSlot != convertFilePouchSlot(FileManager::GetInstance()->getShieldPouchSlot())) { mLyt.findPane("N_alpha_00")->SetVisible(true); - field_0x314 = field_0x310; - mAnm[SHIELD_ANIM_TYPE].setFrame(getLytFrameForShield(field_0x310)); + mSavedShieldType = mShieldType; + mAnm[SHIELD_ANIM_TYPE].setFrame(getLytFrameForShield(mShieldType)); mAnm[SHIELD_ANIM_TYPE].setAnimEnable(true); mAnm[SHIELD_ANIM_LOOP_0].setFrame(0.0f); field_0x31D = 1; b2 = false; b3 = true; - field_0x2E8 = field_0x2E0; - field_0x308 = convertFilePouchSlot(FileManager::GetInstance()->getShieldPouchSlot()); + mSavedDurability = mCurrentDurability; + mCurrentShieldPouchSlot = convertFilePouchSlot(FileManager::GetInstance()->getShieldPouchSlot()); } - if (field_0x2E0 != field_0x2E8 || field_0x31D) { - if (field_0x2E0 < field_0x2E8) { - f32 f = calcUpdownRatio(field_0x2E0); - field_0x2E8 = field_0x2E0; + if (mCurrentDurability != mSavedDurability || field_0x31D) { + if (mCurrentDurability < mSavedDurability) { + f32 f = calcUpdownRatio(mCurrentDurability); + mSavedDurability = mCurrentDurability; mAnm[SHIELD_ANIM_UPDOWN].setFrame(f); mAnm[SHIELD_ANIM_UPDOWN].setAnimEnable(true); - b1 = true; + bIsAnimatingDurability = true; if (field_0x31F && field_0x31D) { field_0x31F = 0; - b1 = false; + bIsAnimatingDurability = false; } field_0x31E = 0; b4 = true; } else { - b1 = true; - field_0x2EC += 1.0f; + bIsAnimatingDurability = true; + mAnimatingDurability += 1.0f; if (field_0x31F && field_0x31D) { field_0x31F = 0; - b1 = false; + bIsAnimatingDurability = false; } - if (field_0x2EC >= field_0x2E0 || field_0x31D) { - field_0x2EC = field_0x2E0; + if (mAnimatingDurability >= mCurrentDurability || field_0x31D) { + mAnimatingDurability = mCurrentDurability; } - if (field_0x2E0 < field_0x2EC) { + if (mCurrentDurability < mAnimatingDurability) { + // @bug (?) Unreachable: `mCurrentDurability < mAnimatingDurability` => `mAnimatingDurability >= mCurrentDurability`, + // so the above block sets `mAnimatingDurability = mCurrentDurability` and this condition will never be hit. field_0x31E = 1; } if (!field_0x31D) { - if (field_0x2E0 >= field_0x2F0) { + if (mCurrentDurability >= mMaxDurability) { if (field_0x31E) { + // Unreachable? SmallSoundManager::GetInstance()->playSoundWithPitch(SE_S_GAUGE_SHIELD_UP_LV, 1.0f); } SmallSoundManager::GetInstance()->playSound(SE_S_GAUGE_SHIELD_UP_MAX); } else { if (field_0x31E) { + // Unreachable? SmallSoundManager::GetInstance()->playSoundWithPitch( - SE_S_GAUGE_SHIELD_UP_LV, field_0x2E0 / field_0x2F0 + SE_S_GAUGE_SHIELD_UP_LV, mCurrentDurability / mMaxDurability ); } } } - f32 tmp = calcUpdownRatio(field_0x2EC); + f32 tmp = calcUpdownRatio(mAnimatingDurability); field_0x2E4 = tmp; if (!field_0x31F) { mAnm[SHIELD_ANIM_USE].setFrame(field_0x2F8 - field_0x2E4); mAnm[SHIELD_ANIM_USE].setAnimEnable(true); } - field_0x2E8 = field_0x2EC; + mSavedDurability = mAnimatingDurability; mAnm[SHIELD_ANIM_UPDOWN].setFrame(tmp); mAnm[SHIELD_ANIM_UPDOWN].setAnimEnable(true); } if (FileManager::GetInstance()->getShieldPouchSlot() == 8) { - if (field_0x2E0 <= 0.0f && b4) { + if (mCurrentDurability <= 0.0f && b4) { mAnm[SHIELD_ANIM_BREAK].setFrame(0.0f); mAnm[SHIELD_ANIM_BREAK].setAnimEnable(true); field_0x30D = 1; @@ -212,11 +217,11 @@ bool dLytMeterShieldGauge_c::execute() { field_0x30C = 1; } } else { - if (field_0x2E0 <= 0.0f && b4) { + if (mCurrentDurability <= 0.0f && b4) { mAnm[SHIELD_ANIM_BREAK].setFrame(0.0f); mAnm[SHIELD_ANIM_BREAK].setAnimEnable(true); field_0x30D = 1; - } else if (b2 && field_0x2E0 >= field_0x2F0) { + } else if (b2 && mCurrentDurability >= mMaxDurability) { mAnm[SHIELD_ANIM_TO_MAX].setFrame(0.0f); mAnm[SHIELD_ANIM_TO_MAX].setAnimEnable(true); field_0x30E = 1; @@ -228,14 +233,14 @@ bool dLytMeterShieldGauge_c::execute() { f32 f2 = dLytMeterConfiguration_c::GetInstance()->getField_0x1D0() * 40.0f / 4.0f; f32 f3 = dLytMeterConfiguration_c::GetInstance()->getField_0x1C4() * 40.0f / 4.0f; - (void)calcUpdownRatio(field_0x2E0); + (void)calcUpdownRatio(mCurrentDurability); if (field_0x31F) { - if (field_0x2E0 < field_0x304 && field_0x2E0 < field_0x2EC - f1) { + if (mCurrentDurability < field_0x304 && mCurrentDurability < mAnimatingDurability - f1) { field_0x2FC = dLytMeterConfiguration_c::GetInstance()->getField_0x1C8(); - field_0x300 = field_0x2EC; - field_0x304 = field_0x2E0; - field_0x2E4 = calcUpdownRatio(field_0x2EC); + field_0x300 = mAnimatingDurability; + field_0x304 = mCurrentDurability; + field_0x2E4 = calcUpdownRatio(mAnimatingDurability); mAnm[SHIELD_ANIM_USE].setFrame(field_0x2F8 - field_0x2E4); mAnm[SHIELD_ANIM_USE].setAnimEnable(true); } else { @@ -244,41 +249,41 @@ bool dLytMeterShieldGauge_c::execute() { } if (field_0x2FC == 0) { field_0x300 = field_0x300 - f2; - if (field_0x300 < field_0x2E0) { + if (field_0x300 < mCurrentDurability) { field_0x31F = 0; - field_0x300 = field_0x2E0; + field_0x300 = mCurrentDurability; } mAnm[SHIELD_ANIM_USE].setAnimEnable(true); field_0x2E4 = calcUpdownRatio(field_0x300); mAnm[SHIELD_ANIM_USE].setFrame(field_0x2F8 - field_0x2E4); } } - } else if (!field_0x31D && field_0x2E0 < field_0x2EC - f3) { + } else if (!field_0x31D && mCurrentDurability < mAnimatingDurability - f3) { field_0x31F = 1; - field_0x300 = field_0x2EC; - field_0x304 = field_0x2E0; + field_0x300 = mAnimatingDurability; + field_0x304 = mCurrentDurability; field_0x2FC = dLytMeterConfiguration_c::GetInstance()->getField_0x1C8(); - field_0x2E4 = calcUpdownRatio(field_0x2EC); + field_0x2E4 = calcUpdownRatio(mAnimatingDurability); mAnm[SHIELD_ANIM_USE].setFrame(field_0x2F8 - field_0x2E4); mAnm[SHIELD_ANIM_USE].setAnimEnable(true); - } else if (!b1) { - field_0x2E4 = calcUpdownRatio(field_0x2EC); + } else if (!bIsAnimatingDurability) { + field_0x2E4 = calcUpdownRatio(mAnimatingDurability); mAnm[SHIELD_ANIM_USE].setFrame(field_0x2F8 - field_0x2E4); mAnm[SHIELD_ANIM_USE].setAnimEnable(true); } - if (!b1) { - field_0x2EC = field_0x2E0; + if (!bIsAnimatingDurability) { + mAnimatingDurability = mCurrentDurability; } field_0x31D = 0; - if (field_0x2F0 != field_0x2F4 || b3) { - setLevel(field_0x2F0); + if (mMaxDurability != field_0x2F4 || b3) { + setLevel(mMaxDurability); mAnm[SHIELD_ANIM_LEVEL].setAnimEnable(true); - field_0x2F4 = field_0x2F0; + field_0x2F4 = mMaxDurability; } if (mAnm[SHIELD_ANIM_BREAK].isEnabled()) { - if (field_0x318 == 0 && field_0x2E0 > 0.0f) { + if (field_0x318 == 0 && mCurrentDurability > 0.0f) { mAnm[SHIELD_ANIM_BREAK].setFrame(0.0f); mAnm[SHIELD_ANIM_BREAK].setAnimEnable(true); // redundant? field_0x30C = 0; @@ -290,7 +295,7 @@ bool dLytMeterShieldGauge_c::execute() { } else { mAnm[SHIELD_ANIM_BREAK].play(); } - } else if (field_0x30C && !field_0x318 && field_0x2E0 > 0.0f) { + } else if (field_0x30C && !field_0x318 && mCurrentDurability > 0.0f) { mAnm[SHIELD_ANIM_BREAK].setFrame(0.0f); mAnm[SHIELD_ANIM_BREAK].setAnimEnable(true); field_0x30C = 0; @@ -308,8 +313,9 @@ bool dLytMeterShieldGauge_c::execute() { mStateMgr.executeState(); - if ((field_0x314 == 6 || field_0x314 == 7 || field_0x314 == 8) && mAnm[SHIELD_ANIM_USE].getFrame() == 0.0f && - mAnm[SHIELD_ANIM_LOOP_0].getFrame() == 0.0f) { + if ((mSavedShieldType == SHIELD_SACRED_SHIELD || mSavedShieldType == SHIELD_DIVINE_SHIELD || + mSavedShieldType == SHIELD_GODDESS_SHIELD) && + mAnm[SHIELD_ANIM_USE].getFrame() == 0.0f && mAnm[SHIELD_ANIM_LOOP_0].getFrame() == 0.0f) { if (mAnm[SHIELD_ANIM_LOOP_0].isEnabled()) { mAnm[SHIELD_ANIM_LOOP_0].setAnimEnable(false); } @@ -364,7 +370,7 @@ void dLytMeterShieldGauge_c::setLevel(f32 lv) { s32 dLytMeterShieldGauge_c::getLytFrameForShield(s32 shield) const { static const int table[] = {0, 4, 7, 1, 5, 8, 2, 6, 9, 3}; - if (shield == 10) { + if (shield == SHIELD_NONE) { shield = 0; } return table[shield]; @@ -373,6 +379,6 @@ s32 dLytMeterShieldGauge_c::getLytFrameForShield(s32 shield) const { f32 dLytMeterShieldGauge_c::calcUpdownRatio(f32 f) const { f32 duration = mAnm[SHIELD_ANIM_UPDOWN].getAnimDuration() - 1.0f; f32 bound = 0.0f; - f32 b = (field_0x2F0 > bound ? f / field_0x2F0 : bound); + f32 b = (mMaxDurability > bound ? f / mMaxDurability : bound); return b * duration; } diff --git a/src/toBeSorted/fi_context.cpp b/src/toBeSorted/fi_context.cpp index e20f69c6..cf4584d8 100644 --- a/src/toBeSorted/fi_context.cpp +++ b/src/toBeSorted/fi_context.cpp @@ -297,8 +297,8 @@ u16 FiContext::prepareFiHelpIndex() { u16 ret = 0xFFFF; setHelpIndex(-1); - if (dLytMeter_c::getShieldLevel() > 0.0f && dLytMeter_c::getShieldGaugePercentMaybe() > 0.0f) { - if (dLytMeter_c::getShieldGaugePercentMaybe() <= 6.0f) { + if (dLytMeter_c::getShieldMaxDurability() > 0.0f && dLytMeter_c::getShieldCurrentDurability() > 0.0f) { + if (dLytMeter_c::getShieldCurrentDurability() <= 6.0f) { if (!getField_0x4A()) { ret = 6402; // "The integrity of your shield has weakened..."