From 180eab5360cc7fb7564d90ea4c41cb4e80b67293 Mon Sep 17 00:00:00 2001 From: robojumper Date: Thu, 22 May 2025 10:20:49 +0200 Subject: [PATCH] Some matches --- config/SOUE01/symbols.txt | 20 ++--- include/d/a/d_a_player.h | 35 +++++---- include/d/d_pouch.h | 1 + include/m/m3d/m_anmchr.h | 5 ++ src/d/d_player_mdl.cpp | 135 ++++++++++++++++++++++++++++++---- src/d/lyt/d_lyt_do_button.cpp | 2 +- 6 files changed, 153 insertions(+), 45 deletions(-) diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index 9f74df7c..e5423c1f 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -2655,10 +2655,10 @@ loadHandsModels__19daPlayerModelBase_cFv = .text:0x8005DE40; // type:function si setSwordAnm__19daPlayerModelBase_cFPCc = .text:0x8005E090; // type:function size:0x64 initSwordModel__19daPlayerModelBase_cFv = .text:0x8005E100; // type:function size:0x1F0 updateSwordModel__19daPlayerModelBase_cFv = .text:0x8005E2F0; // type:function size:0xA8 -getCurrentShieldPouchSlot = .text:0x8005E3A0; // type:function size:0x50 +getCurrentShieldPouchSlot__19daPlayerModelBase_cFv = .text:0x8005E3A0; // type:function size:0x50 isInBambooCuttingMinigame__7dAcPy_cFv = .text:0x8005E3F0; // type:function size:0x8 -getCurrentlyEquippedShieldId = .text:0x8005E400; // type:function size:0x4C -getShieldSubtype = .text:0x8005E450; // type:function size:0x3C +getCurrentlyEquippedShieldId__19daPlayerModelBase_cFv = .text:0x8005E400; // type:function size:0x4C +getShieldType__19daPlayerModelBase_cFl = .text:0x8005E450; // type:function size:0x3C initShieldModel__19daPlayerModelBase_cFv = .text:0x8005E490; // type:function size:0x2C0 updateShieldModel__19daPlayerModelBase_cFv = .text:0x8005E750; // type:function size:0xC8 createGenericSmdl__19daPlayerModelBase_cFQ34nw4r3g3d6ResMdlRQ23m3d6smdl_cP12mAllocator_cUl = .text:0x8005E820; // type:function size:0x68 @@ -2697,11 +2697,11 @@ getExternalAnmTexPat__19daPlayerModelBase_cFPCcPvUl = .text:0x80060450; // type: getExternalAnmTexSrt__19daPlayerModelBase_cFPCcPvUl = .text:0x80060530; // type:function size:0x94 canStart__19daPlayerModelBase_cCFbUsUsPUsPUs = .text:0x800605D0; // type:function size:0x30 setFaceTexPat__19daPlayerModelBase_cFlb = .text:0x80060600; // type:function size:0xEC -fn_800606F0 = .text:0x800606F0; // type:function size:0x38 +checkFaceTexPat__19daPlayerModelBase_cFv = .text:0x800606F0; // type:function size:0x38 setFaceTexSrt__19daPlayerModelBase_cFlb = .text:0x80060730; // type:function size:0xAC -fn_800607E0 = .text:0x800607E0; // type:function size:0x38 +checkFaceTexSrt__19daPlayerModelBase_cFv = .text:0x800607E0; // type:function size:0x38 setFaceAnmChr__19daPlayerModelBase_cFlb = .text:0x80060820; // type:function size:0xF0 -fn_80060910 = .text:0x80060910; // type:function size:0x38 +checkFaceAnmChr__19daPlayerModelBase_cFv = .text:0x80060910; // type:function size:0x38 loadAnmChr__19daPlayerModelBase_cFllPvUl = .text:0x80060950; // type:function size:0x164 removeAnmChr__19daPlayerModelBase_cFl = .text:0x80060AC0; // type:function size:0x6C loadSound__19daPlayerModelBase_cFRQ34nw4r3g3d7ResFilePCcl = .text:0x80060B30; // type:function size:0xCC @@ -2737,7 +2737,7 @@ __dt__13daPlBaseMdl_cFv = .text:0x800619C0; // type:function size:0x6C __dt__21daPlBaseMdlCallback_cFv = .text:0x80061A30; // type:function size:0x58 ExecCallbackB__Q34nw4r3g3d18ICalcWorldCallbackFPQ34nw4r3g3d13WorldMtxManipQ34nw4r3g3d6ResMdlPQ34nw4r3g3d16FuncObjCalcWorld = .text:0x80061A90; // type:function size:0x4 ExecCallbackA__Q34nw4r3g3d18ICalcWorldCallbackFPQ34nw4r3g3d12ChrAnmResultQ34nw4r3g3d6ResMdlPQ34nw4r3g3d16FuncObjCalcWorld = .text:0x80061AA0; // type:function size:0x4 -__sinit_\d_player_mdl_cpp = .text:0x80061AB0; // type:function size:0x5C scope:local +__sinit_\d_player_guide_colors_cpp = .text:0x80061AB0; // type:function size:0x5C scope:local computeChecksumInner__FPvUl = .text:0x80061B10; // type:function size:0x88 computeChecksum__FPvUl = .text:0x80061BA0; // type:function size:0x34 setPrefix__FP18ArcCallbackHandlerPCcUl = .text:0x80061BE0; // type:function size:0x10 @@ -10072,7 +10072,7 @@ fn_80189E10 = .text:0x80189E10; // type:function size:0xF4 fn_80189F10 = .text:0x80189F10; // type:function size:0x8C getPouchSlotCount__Fb = .text:0x80189FA0; // type:function size:0x6C isPouchItem = .text:0x8018A010; // type:function size:0x88 -isItemShield = .text:0x8018A0A0; // type:function size:0x18 +isItemShield__Fl = .text:0x8018A0A0; // type:function size:0x18 isItemExtraAmmo__Fl = .text:0x8018A0C0; // type:function size:0x18 fn_8018A0E0 = .text:0x8018A0E0; // type:function size:0x20 fn_8018A100 = .text:0x8018A100; // type:function size:0x20 @@ -17048,7 +17048,7 @@ TgSirenTag__stateWaitUpdate = .text:0x802D7030; // type:function size:0x4E4 fn_802D7520 = .text:0x802D7520; // type:function size:0x88 outOfTimeMaybe = .text:0x802D75B0; // type:function size:0x74 fn_802D7630 = .text:0x802D7630; // type:function size:0x8 -hasCollectedAllTears = .text:0x802D7640; // type:function size:0x3C +_hasCollectedAllTears__10dTgSiren_cFv = .text:0x802D7640; // type:function size:0x3C fn_802D7680 = .text:0x802D7680; // type:function size:0x90 fn_802D7710 = .text:0x802D7710; // type:function size:0x90 setSilentRealmToPeaceful = .text:0x802D77A0; // type:function size:0x118 @@ -41301,7 +41301,7 @@ lbl_8057520A = .sbss:0x8057520A; // type:object size:0x1 data:byte lbl_8057520B = .sbss:0x8057520B; // type:object size:0x5 data:byte sGuideColor1__19daPlayerModelBase_c = .sbss:0x80575210; // type:object size:0x4 data:4byte sGuideColor2__19daPlayerModelBase_c = .sbss:0x80575214; // type:object size:0x4 data:4byte -sGuideColor3__19daPlayerModelBase_c = .sbss:0x80575218; // type:object size:0x8 data:4byte +sGuideColor3__19daPlayerModelBase_c = .sbss:0x80575218; // type:object size:0x4 data:4byte RootActorParams = .sbss:0x80575220; // type:object size:0x4 scope:local data:4byte ms_configuration_p__6dSys_c = .sbss:0x80575228; // type:object size:0x4 data:4byte dSys_c__ms_RootHeapMem1 = .sbss:0x8057522C; // type:object size:0x4 data:4byte diff --git a/include/d/a/d_a_player.h b/include/d/a/d_a_player.h index c379de1b..305e9363 100644 --- a/include/d/a/d_a_player.h +++ b/include/d/a/d_a_player.h @@ -30,6 +30,7 @@ #include "nw4r/g3d/res/g3d_resmdl.h" #include "nw4r/math/math_types.h" #include "toBeSorted/file_manager.h" +#include "toBeSorted/minigame_mgr.h" #include "toBeSorted/stage_render_stuff.h" // See Below for some info @@ -58,7 +59,7 @@ struct PlayerAnimation { */ // Vtable at 80533128, no differences to dAcObjBase_c? - +// Name unknown, though this name exists in NSMBW class daPlBase_c : public dAcObjBase_c { public: virtual ~daPlBase_c() {} @@ -190,16 +191,8 @@ private: daPlayerModelBase_c *mpPlayer; }; -class UnkPlayerClass { -public: - UnkPlayerClass() {} - ~UnkPlayerClass() {} - -private: - /* 0x00 */ u8 _0x00[0x10 - 0x00]; -}; - // Does this one have a vtable? +// Name unknown class daPlayerActBase_c : public daPlBase_c { public: daPlayerActBase_c() : field_0x334(120.0f), mCurrentAction(187) {} @@ -800,8 +793,6 @@ public: static s32 getCurrentSwordType(); static const char *getSwordName(s32); static s32 getCurrentlyEquippedShieldType(); - static s32 getCurrentlyEquippedShieldId(); - static u32 getCurrentShieldPouchSlot(); static const mColor &getEarringsColor(); @@ -833,7 +824,7 @@ protected: }; // Vtable at 8050da00, dtor reveals two superclasses -// until dAcObjBase_c +// until dAcObjBase_c. Name unknown class daPlayerModelBase_c : public daPlayerActBase_c { public: daPlayerModelBase_c() @@ -920,7 +911,7 @@ public: void fn_8005F890(nw4r::math::MTX34 *); void fn_8005FB90(nw4r::math::MTX34 *); - void fn_80061410(); + bool fn_80061410(); static void freeFrmHeap(mHeapAllocator_c *allocator); static void allocFrmHeap(mHeapAllocator_c *allocator, u32 size, const char *name); @@ -942,6 +933,10 @@ public: static bool isBodyAnmPart_0_2_4(s32 part); + static u32 getCurrentShieldPouchSlot(); + static s32 getShieldType(s32 item); + static s32 getCurrentlyEquippedShieldId(); + void updateEarringsColor(); void loadBodyModels(); void loadBody(); @@ -1009,7 +1004,7 @@ public: /* vt 0x114 */ virtual void somethingWithCarriedActorFlags() override; /* vt 0x118 */ virtual dAcObjBase_c *getCurrentCarriedActor() override { - return mRef.get(); + return mCarriedActorRef.get(); } /* vt 0x18C */ virtual void getBodyMtx(mMtx_c *out_mtx, int boneIdx) override { @@ -1042,8 +1037,11 @@ public: bool canStart(bool force, u16 newIdx, u16 invalidValue, u16 *out1, u16 *out2) const; void setFaceTexPat(s32 faceIdx, bool force); + void checkFaceTexPat(); void setFaceTexSrt(s32 faceIdx, bool force); + void checkFaceTexSrt(); void setFaceAnmChr(s32 faceIdx, bool force); + void checkFaceAnmChr(); void setPosCopy3(); @@ -1184,7 +1182,7 @@ protected: /* 0x1300 */ mQuat_c field_0x1300[4]; /* 0x1340 */ mQuat_c mQuat1; /* 0x1350 */ mQuat_c mQuat2; - /* 0x1360 */ dAcRef_c mRef; // not sure about the class + /* 0x1360 */ dAcRef_c mCarriedActorRef; // not sure about the class /* 0x136C */ mAng *field_0x136C; /* 0x1370 */ mAng *field_0x1370; /* 0x1374 */ mAng *field_0x1374; // x3 @@ -1252,8 +1250,9 @@ public: static s32 getCurrentBeetleType(); static s32 getCurrentBugNetType(); - static bool isInBambooCuttingMinigame(); - + static bool isInBambooCuttingMinigame() { + return MinigameManager::isInMinigameState(MinigameManager::BAMBOO_CUTTING); + } static bool isItemRestrictedByBokoBase(ITEM_ID item); static u32 getCurrentHealthCapacity(); diff --git a/include/d/d_pouch.h b/include/d/d_pouch.h index b1d064c1..feacc53d 100644 --- a/include/d/d_pouch.h +++ b/include/d/d_pouch.h @@ -12,6 +12,7 @@ s32 getPouchSlotCount(bool unk); bool isItemExtraAmmo(s32 item); bool isItemMedal(s32 item); bool hasAnyShields(); +bool isItemShield(s32 item); #define POUCH_SLOT_NONE 8 diff --git a/include/m/m3d/m_anmchr.h b/include/m/m3d/m_anmchr.h index 2b564451..2ff01dd7 100644 --- a/include/m/m3d/m_anmchr.h +++ b/include/m/m3d/m_anmchr.h @@ -17,6 +17,11 @@ public: bool create(nw4r::g3d::ResMdl mdl, nw4r::g3d::ResAnmChr anm, mAllocator_c *alloc) { return create(mdl, anm, alloc, nullptr); } + // Not sure about this overload but it fixes stack alloc in some cases and other files + // definitely have similar overloads with seemingly identical argument types + bool create2(nw4r::g3d::ResMdl mdl, nw4r::g3d::ResAnmChr anm, mAllocator_c *alloc) { + return create(mdl, anm, alloc); + } bool create(nw4r::g3d::ResMdl, nw4r::g3d::ResAnmChr, mAllocator_c *, u32 *); void setAnm(bmdl_c &, nw4r::g3d::ResAnmChr, playMode_e); void setAnmAfter(bmdl_c &, nw4r::g3d::ResAnmChr, playMode_e); diff --git a/src/d/d_player_mdl.cpp b/src/d/d_player_mdl.cpp index 35aabf95..f28d6fab 100644 --- a/src/d/d_player_mdl.cpp +++ b/src/d/d_player_mdl.cpp @@ -1,5 +1,6 @@ #include "common.h" #include "d/a/d_a_base.h" +#include "d/a/d_a_itembase.h" #include "d/a/d_a_player.h" #include "d/col/cc/d_cc_s.h" #include "d/d_heap.h" @@ -817,8 +818,7 @@ void daPlayerModelBase_c::loadBody() { nw4r::g3d::ResAnmChr resAnmChr26 = getExternalAnmChr(sAnimations[26].animName, mpExternalAnmCharBuffer, 0x2400); nw4r::g3d::AnmObjChr *animObj; for (s32 i = 0; i < 6; i++) { - // TODO: stack swap, need to mess with inlines more - anms->create(bodyMdl, resAnmChr26, &heap_allocator); + anms->create2(bodyMdl, resAnmChr26, &heap_allocator); anms->setAnm(mMainMdl, resAnmChr26, m3d::PLAY_MODE_0); f32 f; switch (i) { @@ -929,10 +929,10 @@ static const f32 sSwordRelatedUnk[] = {73.0f, 80.0f, 100.0f, 100.0f, 120.0f, 120 static const f32 sSwordRelatedZ[] = {0.7f, 0.7f, 0.9f, 0.9f, 1.0f, 1.0f, 0.7f}; static const f32 sSwordRelatedY[] = {0.7f, 0.8f, 0.9f, 0.9f, 1.0f, 1.0f, 0.7f}; -static const char *sSwordPods[] = {"EquipPodA", "EquipPodB", "EquipPodC", "EquipPodD", - "EquipPodE", "EquipPodMaster", "EquipPodA"}; - void daPlayerModelBase_c::initSwordModel() { + static const char *sSwordPods[] = {"EquipPodA", "EquipPodB", "EquipPodC", "EquipPodD", + "EquipPodE", "EquipPodMaster", "EquipPodA"}; + updateCurrentSword(); freeFrmHeap(&mSwordAllocator); const char *swordName = getSwordName(sCurrentSword); @@ -941,10 +941,8 @@ void daPlayerModelBase_c::initSwordModel() { field_0x127C.x = sSwordRelatedX[sCurrentSword]; field_0x127C.y = sSwordRelatedY[sCurrentSword]; field_0x127C.z = sSwordRelatedZ[sCurrentSword]; - // TODO instruction order - const char *pod = sSwordPods[sCurrentSword]; - nw4r::g3d::ResMdl sheathMdl = mSwordRes.GetResMdl(pod); + nw4r::g3d::ResMdl sheathMdl = mSwordRes.GetResMdl(sSwordPods[sCurrentSword]); createGenericSmdl(sheathMdl, mSheathMdl, &mSwordAllocator, 0x800); mScnCallback4.attach(mSheathMdl); @@ -995,6 +993,35 @@ void daPlayerModelBase_c::updateSwordModel() { mModelUpdateFlags &= ~UPDATE_MODEL_SWORD; } +u32 daPlayerModelBase_c::getCurrentShieldPouchSlot() { + // Compiler quirk, inline function not inlined due to GetLink call + if (dScGame_c::currentSpawnInfo.getTrial() == SpawnInfo::TRIAL || dAcPy_c::GetLink()->isInBambooCuttingMinigame()) { + return POUCH_SLOT_NONE; + } + return FileManager::GetInstance()->getShieldPouchSlot(); +} + +s32 daPlayerModelBase_c::getCurrentlyEquippedShieldId() { + s32 id; + u32 slot = getCurrentShieldPouchSlot(); + if (slot < POUCH_SLOT_NONE) { + id = getShieldType(FileManager::GetInstance()->getPouchItem(slot)); + } else { + id = 10; + } + if (id >= 11) { + id = 10; + } + return id; +} + +s32 daPlayerModelBase_c::getShieldType(s32 item) { + if (!isItemShield(item)) { + item = ITEM_WOODEN_SHIELD; + } + return item - ITEM_WOODEN_SHIELD; +} + static const char *sShieldModelsBase[] = { "EquipShieldWood", "EquipShieldIron", "EquipShieldHoly", "EquipShieldHylia", "EquipShieldWood", }; @@ -1004,9 +1031,6 @@ static const char *sShieldModelsBroken[] = { "EquipShieldHylia", "EquipShieldWoodBroken", }; -extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_529_; -extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_535_; -extern "C" const u16 PARTICLE_RESOURCE_ID_MAPPING_537_; void daPlayerModelBase_c::initShieldModel() { static const u16 shieldEffects[] = { PARTICLE_RESOURCE_ID_MAPPING_537_, PARTICLE_RESOURCE_ID_MAPPING_535_, PARTICLE_RESOURCE_ID_MAPPING_529_, @@ -1423,13 +1447,52 @@ void daPlayerModelBase_c::fn_8005F890(nw4r::math::MTX34 *result) { } void daPlayerModelBase_c::fn_8005FB90(nw4r::math::MTX34 *result) { - // Will suffer from the same problem as above, so not too interested rn + // Suffer from the same problem as above static const u16 sNodeIdsLegs1[] = {PLAYER_MAIN_NODE_LEG_L1, PLAYER_MAIN_NODE_LEG_R1}; static const Vec sLegVecs[] = { { 30.0f, 0.0f, 0.0f}, {39.3635f, 0.0f, 0.0f}, { 14.18f, 0.0f, 0.0f} }; + + nw4r::g3d::ResMdl mdl = mMainMdl.getResMdl(); + + if (vt_0x2E8(result, sNodeIdsLegs1, true)) { + mVec3_c legOffset = vt_0x304() * 0.5f; + + mVec3_c dstVec; + // (1) For some reason the compiler sets up pointers to stack vars here... + for (s32 leg = 0; leg < 2; leg++) { + u16 legNode = sNodeIdsLegs1[leg]; + mVec3_c *dst = nullptr; + mAng *angs; + if (leg == 0) { + angs = field_0x136C; + } else { + angs = field_0x1370; + } + nw4r::math::MTX34 *targetMtx; + // Walk down the arm bones and transform the whole thing again? + for (s32 i = 0; i < 3; i++) { + u32 mtxId = mdl.GetResNode(legNode).GetMtxID(); + targetMtx = &result[mtxId]; + applyWorldRotationMaybe(targetMtx, angs[i], 0, 0, dst, false); + mVec3_c v; + v.x = sLegVecs[i].x; + v.y = sLegVecs[i].y; + v.z = sLegVecs[i].z; + MTXMultVec(*targetMtx, v, dstVec); + if (i != 2) { + dstVec -= legOffset; + } + dst = &dstVec; + legNode++; + } + // (2) ... here it stores the passed-by-value angles to the stack, + // then calls GetResNode and uses the previously set up pointers as arguments? + applyWorldRotationMaybe(&result[mdl.GetResNode(legNode).GetMtxID()], 0, 0, angs[2], &dstVec, false); + } + } } void daPlayerModelBase_c::mainModelTimingA(u32 nodeId, nw4r::g3d::ChrAnmResult *result) { @@ -1626,6 +1689,19 @@ void daPlayerModelBase_c::setFaceTexPat(s32 faceIdx, bool force) { } } +void daPlayerModelBase_c::checkFaceTexPat() { + if (mFaceAnmTexPatIdx2 == 0x39) { + return; + } + s32 prev = mFaceAnmTexPatIdx1; + mFaceAnmTexPatIdx2 = 0x39; + if (prev >= 0x1F) { + prev = 1; + } + mFaceAnmTexPatIdx1 = 0x39; + setFaceTexPat(prev, false); +} + void daPlayerModelBase_c::setFaceTexSrt(s32 faceIdx, bool force) { offFaceUpdateFlags(0x80000000); if (canStart(force, faceIdx, 0x39, &mFaceAnmTexSrtIdx1, &mFaceAnmTexSrtIdx2)) { @@ -1635,6 +1711,19 @@ void daPlayerModelBase_c::setFaceTexSrt(s32 faceIdx, bool force) { } } +void daPlayerModelBase_c::checkFaceTexSrt() { + if (mFaceAnmTexSrtIdx2 == 0x39) { + return; + } + s32 prev = mFaceAnmTexSrtIdx1; + mFaceAnmTexSrtIdx2 = 0x39; + if (prev >= 0x1F) { + prev = 0; + } + mFaceAnmTexSrtIdx1 = 0x39; + setFaceTexSrt(prev, false); +} + void daPlayerModelBase_c::setFaceAnmChr(s32 faceIdx, bool force) { // TODO branching if (faceIdx != 0x38 && (force || (!checkFaceUpdateFlags(0x20000000) || (faceIdx != 0 && faceIdx != 2)))) { @@ -1648,6 +1737,19 @@ void daPlayerModelBase_c::setFaceAnmChr(s32 faceIdx, bool force) { } } +void daPlayerModelBase_c::checkFaceAnmChr() { + if (mFaceAnmChrIdx2 == 0x39) { + return; + } + s32 prev = mFaceAnmChrIdx1; + mFaceAnmChrIdx2 = 0x39; + if (prev >= 0x1F) { + prev = 0; + } + mFaceAnmChrIdx1 = 0x39; + setFaceAnmChr(prev, false); +} + void daPlayerModelBase_c::loadAnmChr(s32 childIdx, s32 animIdx, void *dest, u32 maxSize) { nw4r::g3d::ResAnmChr anm = getExternalAnmChr(sAnimations[animIdx].animName, dest, maxSize); mAnmChrs[childIdx].setAnm(mMainMdl, anm, m3d::PLAY_MODE_4); @@ -1835,15 +1937,16 @@ void daPlayerModelBase_c::setPosCopy3() { } } -void daPlayerModelBase_c::fn_80061410() { - // Just getting weak functions to appear here - alwaysRet0(); +bool daPlayerModelBase_c::fn_80061410() { + return (field_0x120A || alwaysRet0()) && !(someFlags_0x354 & 0x800); } // I believe this is the only strong virtual function of daPlayerModelBase_c, // and this causes the vtable and all other weak functions to be here /* vt 0x114 */ void daPlayerModelBase_c::somethingWithCarriedActorFlags() { - // TODO + if (mCarriedActorRef.get() != nullptr) { + mCarriedActorRef.get()->mObjectActorFlags |= 0x200; + } } mColor daPlayerModelBase_c::sGuideColor1(0x00, 0x82, 0xDC, 0xFF); mColor daPlayerModelBase_c::sGuideColor2(0x64, 0xFF, 0xFF, 0xFF); diff --git a/src/d/lyt/d_lyt_do_button.cpp b/src/d/lyt/d_lyt_do_button.cpp index 9aec9bcf..9f4fc89e 100644 --- a/src/d/lyt/d_lyt_do_button.cpp +++ b/src/d/lyt/d_lyt_do_button.cpp @@ -294,7 +294,7 @@ bool dLytDobutton_c::remove() { bool dLytDobutton_c::execute() { bool isInEvent = EventManager::isInEvent(); bool b1 = true; - if (dAcPy_c::isInBambooCuttingMinigame()) { + if (dAcPy_c::GetLink()->isInBambooCuttingMinigame()) { setActionTextStuff(ICON_12, ACT_DO_70, false); } if (field_0x490 == 0) {