diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index 5a4ac7c9..3a5b3926 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -20878,7 +20878,7 @@ setButtonPressSound__20dSndSmallEffectMgr_cFP14dSoundSource_c = .text:0x8037F0F0 playBattleHitSound__20dSndSmallEffectMgr_cFQ220dSndSmallEffectMgr_c16BattleHitSound_eP14dSoundSource_c = .text:0x8037F150; // type:function size:0x6D0 getName__14dSoundSource_cCFv = .text:0x8037F820; // type:function size:0x8 getSourceType__14dSoundSource_cCFv = .text:0x8037F830; // type:function size:0x8 -fn_8037F840 = .text:0x8037F840; // type:function size:0x74 +setBitsIfAdjacent__20dSndSmallEffectMgr_cFP27dSndBgmDataHarpVarSetBase_cllPUl = .text:0x8037F840; // type:function size:0x74 __dt__35SndMgrDisposer<17dSndHarpSongMgr_c>Fv = .text:0x8037F8C0; // type:function size:0x78 create__35SndMgrDisposer<17dSndHarpSongMgr_c>Fv = .text:0x8037F940; // type:function size:0x48 remove__35SndMgrDisposer<17dSndHarpSongMgr_c>Fv = .text:0x8037F990; // type:function size:0x10 diff --git a/include/d/snd/d_snd_bgm_harp_data.h b/include/d/snd/d_snd_bgm_harp_data.h index fc62f9ab..3c4cee7f 100644 --- a/include/d/snd/d_snd_bgm_harp_data.h +++ b/include/d/snd/d_snd_bgm_harp_data.h @@ -2,6 +2,7 @@ #define D_SND_BGM_HARP_DATA_H #include "common.h" +#include "d/snd/d_snd_rng_mgr.h" /** * This file deals with the pitch of the Goddess' Harp when Link @@ -37,6 +38,10 @@ struct dSndBgmDataHarpVar_c { field_0x00 |= 1; } + bool checkFlag() const { + return field_0x00 & 1; + } + /* 0x00 */ u8 field_0x00; // flags /* 0x01 */ s8 field_0x01; // var }; @@ -61,7 +66,7 @@ public: mPosition = position; } - s32 getCount() const { + s32 getCount() { return mCount; } @@ -69,6 +74,16 @@ public: return mMax; } + s32 getNumBitsSet() { + s32 numBits = 0; + for (int i = 0; i < getCount(); i++) { + if (mpVars[i].checkFlag()) { + numBits++; + } + } + return numBits; + } + dSndBgmDataHarpVar_c *getVar(s32 idx) { if (idx >= getCount()) { return nullptr; @@ -76,6 +91,33 @@ public: return &mpVars[idx]; } + s32 getRandomIdx() { + return dSndRngMgr_c::GetInstance()->rndIntRange(0, getCount()); + } + + s32 getRandomIdxWithBitSet() { + s32 numBitsSet = getNumBitsSet(); + s32 idx; + if (numBitsSet <= 0) { + return 0; + } else { + idx = dSndRngMgr_c::GetInstance()->rndIntRange(0, getCount()); + while (true) { + if (mpVars[idx].checkFlag()) { + return idx; + } + idx = dSndRngMgr_c::GetInstance()->rndIntRange(0, getCount()); + } + } + } + + s32 getVal(s32 idx) { + if (idx >= getCount()) { + return 0; + } + return mpVars[idx].field_0x01; + } + dSndBgmDataHarpVar_c *getUnusedVar() { if (mCount >= mMax) { return nullptr; diff --git a/include/d/snd/d_snd_bgm_sound.h b/include/d/snd/d_snd_bgm_sound.h index 09403fb7..3d4ccd7b 100644 --- a/include/d/snd/d_snd_bgm_sound.h +++ b/include/d/snd/d_snd_bgm_sound.h @@ -55,7 +55,7 @@ public: void onBecomeActive(); bool isBgmBattle() const; - const dSndBgmDataHarpVarSetBase_c *getCurrentHarpVarSet(); + dSndBgmDataHarpVarSetBase_c *getCurrentHarpVarSet(); u32 getStrmPlaySamplePosition(); u32 getWavePlaySamplePosition(); diff --git a/include/d/snd/d_snd_bgm_sound_harp_mgr.h b/include/d/snd/d_snd_bgm_sound_harp_mgr.h index 16bcdc40..34ed6df2 100644 --- a/include/d/snd/d_snd_bgm_sound_harp_mgr.h +++ b/include/d/snd/d_snd_bgm_sound_harp_mgr.h @@ -15,7 +15,7 @@ public: void setPlaySamplePosition(s32 position); - const dSndBgmDataHarpVarSetBase_c *getCurrentVarSet(); + dSndBgmDataHarpVarSetBase_c *getCurrentVarSet(); bool isLoaded() const { return mIsLoaded; diff --git a/include/d/snd/d_snd_rng_mgr.h b/include/d/snd/d_snd_rng_mgr.h index 9ef8adab..64596883 100644 --- a/include/d/snd/d_snd_rng_mgr.h +++ b/include/d/snd/d_snd_rng_mgr.h @@ -10,10 +10,9 @@ class dSndRngMgr_c : public dSndRng_c { public: SND_DISPOSER_MEMBERS(dSndRngMgr_c) - u32 rndIntRange(s32 min, s32 max); - public: dSndRngMgr_c() {} + u32 rndIntRange(s32 min, s32 max); }; #endif diff --git a/include/d/snd/d_snd_small_effect_mgr.h b/include/d/snd/d_snd_small_effect_mgr.h index 7c6ad9d0..3e55b06a 100644 --- a/include/d/snd/d_snd_small_effect_mgr.h +++ b/include/d/snd/d_snd_small_effect_mgr.h @@ -82,6 +82,8 @@ private: bool isPlayingSound(u32 playerIdx, u32 soundId); bool isPlayingSound(u32 soundId); + void setBitsIfAdjacent(dSndBgmDataHarpVarSetBase_c *set, s32 count, s32 target, u32 *pMask); + /** * Finds a sound handle currently playing the given sound, * or an idle sound handle, @@ -100,9 +102,9 @@ private: /* 0x30 */ s32 mDelayedSoundTimers[NUM_DELAYED_SOUNDS]; /* 0x38 */ u32 mTextboxAdvanceSound; /* 0x3C */ nw4r::snd::SoundHandle mBattleTuttiHandle; - /* 0x40 */ u16 field_0x40; - /* 0x42 */ u16 field_0x42; - /* 0x44 */ s32 field_0x44; + /* 0x40 */ s16 field_0x40; + /* 0x42 */ s16 field_0x42; + /* 0x44 */ u32 field_0x44; }; #endif diff --git a/include/d/snd/d_snd_types.h b/include/d/snd/d_snd_types.h index c156c7c1..4c835232 100644 --- a/include/d/snd/d_snd_types.h +++ b/include/d/snd/d_snd_types.h @@ -28,6 +28,8 @@ class dSndBgmSoundHarpMgr_c; class dSndBgmSeqConfig; class dSndBgmBattleConfig; +class dSndBgmDataHarpVarSetBase_c; + class dSndHarpSongData_c; class dSndTagData; diff --git a/src/d/snd/d_snd_bgm_sound.cpp b/src/d/snd/d_snd_bgm_sound.cpp index cfd488a7..2d01949f 100644 --- a/src/d/snd/d_snd_bgm_sound.cpp +++ b/src/d/snd/d_snd_bgm_sound.cpp @@ -456,7 +456,7 @@ void dSndBgmSound_c::onBecomeActive() { spGlobalHarpMgr->resetPrevIdx(); } -const dSndBgmDataHarpVarSetBase_c *dSndBgmSound_c::getCurrentHarpVarSet() { +dSndBgmDataHarpVarSetBase_c *dSndBgmSound_c::getCurrentHarpVarSet() { if (isRunning()) { return mpHarpMgr->getCurrentVarSet(); } diff --git a/src/d/snd/d_snd_bgm_sound_harp_mgr.cpp b/src/d/snd/d_snd_bgm_sound_harp_mgr.cpp index e54a999c..ee376ac9 100644 --- a/src/d/snd/d_snd_bgm_sound_harp_mgr.cpp +++ b/src/d/snd/d_snd_bgm_sound_harp_mgr.cpp @@ -36,6 +36,6 @@ void dSndBgmSoundHarpMgr_c::setPlaySamplePosition(s32 position) { } } -const dSndBgmDataHarpVarSetBase_c *dSndBgmSoundHarpMgr_c::getCurrentVarSet() { +dSndBgmDataHarpVarSetBase_c *dSndBgmSoundHarpMgr_c::getCurrentVarSet() { return mpCurrVarSet; } diff --git a/src/d/snd/d_snd_small_effect_mgr.cpp b/src/d/snd/d_snd_small_effect_mgr.cpp index 41c89b8e..46a9ffc5 100644 --- a/src/d/snd/d_snd_small_effect_mgr.cpp +++ b/src/d/snd/d_snd_small_effect_mgr.cpp @@ -1,7 +1,9 @@ #include "d/snd/d_snd_small_effect_mgr.h" #include "common.h" +#include "d/snd/d_snd_bgm_harp_data.h" #include "d/snd/d_snd_bgm_mgr.h" +#include "d/snd/d_snd_bgm_sound.h" #include "d/snd/d_snd_calc_pitch.h" #include "d/snd/d_snd_checkers.h" #include "d/snd/d_snd_control_player_mgr.h" @@ -603,7 +605,141 @@ bool dSndSmallEffectMgr_c::playBattleHitSound(BattleHitSound_e type, dSoundSourc mBattleTuttiHandle.Stop(5); } - // TODO ... + dSndBgmSound_c *bgmSound = dSndBgmMgr_c::GetInstance()->getActiveBgmSound(); + if (bgmSound == nullptr) { + return false; + } - return true; + dSndBgmDataHarpVarSetBase_c *set = bgmSound->getCurrentHarpVarSet(); + if (set == nullptr) { + return false; + } + + bool ok = playSoundInternal(soundId, &mBattleTuttiHandle); + if (ok) { + nw4r::snd::SeqSoundHandle seqHandle(&mBattleTuttiHandle); + if (set->getCount() <= 0) { + return true; + } + + s32 count = set->getCount(); + if (count == 1) { + field_0x40 = set->getVal(0); + field_0x42 = field_0x40; + for (int i = 1; i < 4; i++) { + seqHandle.WriteVariable(i, field_0x40); + } + return true; + } else { + s32 i2 = 0; + field_0x44 = 0; + s32 varIdx = 0; + u32 mask = 0; + + // Pick a var 0 + if (type == BATTLE_TUTTI_FINISH) { + field_0x40 = set->getVal(0); + varIdx = 0; + } else { + s32 numHarpBits = set->getNumBitsSet(); + + if (numHarpBits <= 0) { + // No bits set, just try and pick a random variable + // that's not equal to the one we picked before + s32 pick = field_0x40; + int i = 0; + while (pick == field_0x40) { + i++; + if (i > 0x14) { + break; + } + varIdx = set->getRandomIdx(); + pick = set->getVal(varIdx); + } + field_0x40 = pick; + } else if (numHarpBits == 1) { + // One bit set, get the value (using a slightly convoluted method + // due to inline complexity) without rejecting it when it equals + // the previously picked value + // TODO - unnecessary reload of count here. + varIdx = set->getRandomIdxWithBitSet(); + field_0x40 = set->getVal(varIdx); + } else { + // Multiple bits set, just pick a random variable with the bit set + // that's not equal to the one we picked before + s32 pick = field_0x40; + int i = 0; + while (pick == field_0x40) { + i++; + if (i > 0x14) { + break; + } + varIdx = set->getRandomIdxWithBitSet(); + pick = set->getVal(varIdx); + } + field_0x40 = pick; + } + } + field_0x44 |= 1 << varIdx; + setBitsIfAdjacent(set, count, field_0x40, &mask); + seqHandle.WriteVariable(0, field_0x40); + + // Pick a new field_0x42 -> var 1 + u32 mask5 = 0; + s32 value = 0; + int i = 0; + do { + i++; + if (i > 0x14) { + break; + } + u32 rndValue = set->getRandomIdx(); + mask5 = 1 << rndValue; + value = set->getVal(rndValue); + + } while ((mask & mask5) || value == field_0x42); + field_0x42 = value; + field_0x44 |= mask5; + + setBitsIfAdjacent(set, count, field_0x42, &mask); + seqHandle.WriteVariable(1, field_0x42); + + // Pick new vars 2 and 3 + bool b = field_0x40 != field_0x42; + s32 seqVarIdx = 2; + for (; seqVarIdx < 4; seqVarIdx++) { + u32 rndValue = 0; + u32 mask5 = 0; + int i = 0; + do { + i++; + if (i > 0x14) { + break; + } + rndValue = set->getRandomIdx(); + mask5 = 1 << rndValue; + } while ((mask & mask5) || (seqVarIdx >= 3 && !b && (field_0x44 & mask5))); + if (!(field_0x44 & mask5)) { + b = true; + } + s32 nextVal = value = set->getVal(rndValue); + setBitsIfAdjacent(set, count, nextVal, &mask); + field_0x44 |= mask5; + seqHandle.WriteVariable(seqVarIdx, nextVal); + } + } + } + + return ok; +} + +void dSndSmallEffectMgr_c::setBitsIfAdjacent( + dSndBgmDataHarpVarSetBase_c *set, s32 count, s32 target, u32 *pMask +) { + for (int i = 0; i < count; i++) { + s32 val = set->getVal(i); + if (val == target + 1 || val == target - 1) { + *pMask |= 1 << i; + } + } }