#include "common.h" #include "d/a/d_a_player.h" #include "d/snd/d_snd_checkers.h" #include "d/snd/d_snd_control_player_mgr.h" #include "d/snd/d_snd_player_mgr.h" #include "d/snd/d_snd_se_sound.h" #include "d/snd/d_snd_se_sound_2.h" #include "d/snd/d_snd_source_equipment.h" #include "d/snd/d_snd_wzsound.h" #include "nw4r/snd/snd_SeqSoundHandle.h" #include "nw4r/snd/snd_SoundPlayer.h" void dSndSourceEquipment_c::cbBeFlyLv(dSndSeSound_c *sound, dSoundSource_c *source, nw4r::snd::SoundHandle &handle) { if (sound->getCtxParams()[0].floatParam > 0.0f) { nw4r::snd::SeqSoundHandle seqHandle(&handle); f32 volume = 0.6f; f32 pitch = 1.0f; if (sound->getCtxParams()[0].floatParam == 1.0f) { volume = 1.0f; pitch = 1.3f; } handle.SetVolume(volume, 0); handle.SetPitch(pitch); seqHandle.SetTempoRatio(pitch); } } void dSndSourceEquipment_c::cbBeThrowRc(dSndSeSound_c *sound, dSoundSource_c *source, nw4r::snd::SoundHandle &handle) { if (dAcPy_c::GetLink() != nullptr && !dAcPy_c::GetLink()->isBeetleInFlight()) { handle.Stop(10); return; } dSndSeSound2_c *flyHoldHandle = source->getHandleType2ForSoundId(SE_BE_FLY_LV); if (flyHoldHandle == nullptr) { if (sound->getField0x114() != 0) { handle.Stop(3); sound->setCallback2(nullptr); } return; } nw4r::snd::SeqSoundHandle seqHandle(sound->getHandle()); if (flyHoldHandle->getCtxParams()[0].floatParam > 0.0f) { f32 volume = 0.6f; f32 pitch = 1.0f; if (flyHoldHandle->getCtxParams()[0].floatParam == 1.0f) { volume = 1.0f; pitch = 1.3f; } handle.SetVolume(volume, 0); handle.SetPitch(pitch); seqHandle.SetTempoRatio(pitch); } } void dSndSourceEquipment_c::cbBmIgnitionLv( dSndSeSound_c *sound, dSoundSource_c *source, nw4r::snd::SoundHandle &handle ) { // TODO how are these flags set if (source->checkFlag(0x1)) { handle.SetLpfFreq(-0.4f); } else { handle.SetLpfFreq(0.0f); } } void dSndSourceEquipment_c::cbBmBound(dSndSeSound_c *sound, dSoundSource_c *source, nw4r::snd::SoundHandle &handle) { f32 param = sound->getCtxParams()[0].floatParam; if (param <= 2.0f) { handle.Stop(0); return; } // TODO what does this do? f32 volume = param / 70.0f + 0.3f; if (volume > 1.0f) { volume = 1.0f; } handle.SetVolume(volume, 0); } static const f32 beMinSpeed = 2.0f; static const f32 beMaxSpeed = 40.0f; void dSndSourceEquipment_c::cbWiFxLv(dSndSeSound_c *sound, dSoundSource_c *source, nw4r::snd::SoundHandle &handle) { if (dAcPy_c::GetLink() == nullptr) { return; } f32 volume = 1.0f; f32 pitch = 1.0f; if (dAcPy_c::GetLink()->checkCurrentAction(/* WHIP_LOCKED */ 0x8E)) { volume = 0.9f; } else { if (dAcPy_c::GetLink()->checkCurrentAction(/* USE_WHIP */ 0x8D)) { pitch = 1.2f; } else if (dAcPy_c::GetLink()->isUsingWhip()) { f32 speed = source->getSpeed(); if (speed <= beMinSpeed) { volume = 0.2; } else if (speed >= beMaxSpeed) { volume = 0.8f; } else { volume = speed * 0.6f / 38.0f; volume += 0.8f; volume -= (beMaxSpeed * 0.6f / 38.0f); // @bug not actually clamped (void)nw4r::ut::Clamp(volume, 0.2f, 0.8f); } pitch = 0.9f; } } // Save the current speed value... sound->shiftFloatParam(pitch); // And read the speed value from 4 frames earlier (~133ms) f32 actualPitch = sound->getCtxParams()[5].floatParam; handle.SetVolume(volume, 0); handle.SetPitch(actualPitch); } void dSndSourceEquipment_c::cbPcHit(dSndSeSound_c *sound, dSoundSource_c *source, nw4r::snd::SoundHandle &handle) { nw4r::snd::SoundPlayer *equipmentPlayer = dSndControlPlayerMgr_c::GetInstance()->getPlayer2(dSndPlayerMgr_c::PLAYER_LINK_EQUIPMENT); s32 result = 0; SoundPropertiesChecker checker(handle.GetId()); // due to a @bug in SoundPropertiesChecker's ctor, mCounter4 is uninitialized, // so when MWCC creates a copy of `checker` for ForEachSound, // it uses r3 to store the ininitialized field, which currently holds // `equipmentPlayer`. So this behaves as if someone wrote: // checker.mCounter4 = reinterpret_cast(equipmentPlayer); // This is harmless here, since we never use the result. checker.mpPlayCounter = &result; // The more equipment sounds are playing, the more // the volume on SE_PC_HIT is reduced equipmentPlayer->ForEachSound(checker, false); if (result == 2) { handle.SetVolume(0.7f, 0); } else if (result == 3) { handle.SetVolume(0.5f, 0); } else if (result >= 4) { handle.SetVolume(0.3f, 0); } } void dSndSourceEquipment_c::postSetupSound(u32 playingId, u32 requestedId, dSndSeSound_c *seSound) { switch (requestedId) { case SE_BE_FLY_LV: seSound->setCallback2(&cbBeFlyLv); break; case SE_BE_THROW_RC: seSound->setCallback2(&cbBeThrowRc); break; case SE_BM_IGNITION_LV: seSound->setCallback2(&cbBmIgnitionLv); break; case SE_BM_BOUND: seSound->setCallback1(&cbBmBound); break; case SE_WI_FX_LV: seSound->setCallback2(&cbWiFxLv); break; case SE_PC_HIT: seSound->setCallback1(&cbPcHit); break; } }