Files
ss/src/d/snd/d_snd_state_mgr.cpp
T
2025-09-13 11:48:25 +02:00

1248 lines
40 KiB
C++

#include "d/snd/d_snd_state_mgr.h"
#include "common.h"
#include "d/a/d_a_player.h"
#include "d/d_camera.h"
#include "d/d_sc_game.h"
#include "d/snd/d_snd_area_sound_effect_mgr.h"
#include "d/snd/d_snd_bgm_mgr.h"
#include "d/snd/d_snd_checkers.h"
#include "d/snd/d_snd_control_player_mgr.h"
#include "d/snd/d_snd_event.h"
#include "d/snd/d_snd_harp_song_mgr.h"
#include "d/snd/d_snd_mgr.h"
#include "d/snd/d_snd_player_mgr.h"
#include "d/snd/d_snd_small_effect_mgr.h"
#include "d/snd/d_snd_source_mgr.h"
#include "d/snd/d_snd_stage_data.h"
#include "d/snd/d_snd_util.h"
#include "d/snd/d_snd_wzsound.h"
#include "d/t/d_t_sound_area_mgr.h"
#include "egg/core/eggHeap.h"
#include "nw4r/snd/snd_FxReverbStdDpl2.h"
#include "nw4r/snd/snd_SeqSoundHandle.h"
#include "nw4r/snd/snd_SoundPlayer.h"
#include "nw4r/snd/snd_global.h"
#include "sized_string.h"
#include "toBeSorted/event_manager.h"
#include <cstring>
SndEventCallback dSndStateMgr_c::sEventExecuteCallback;
SND_DISPOSER_DEFINE(dSndStateMgr_c);
dSndStateMgr_c::dSndStateMgr_c()
: field_0x010(0),
field_0x014(0),
field_0x018(0),
field_0x03C(0),
mStageId(0xAC),
mPreviousStageId(0xAC),
mStageTypeFlags(0),
mLayer(0),
mRoomId(-1),
mCheckRoomIdCooldown(0),
field_0x064(false),
field_0x065(false),
mHasChangedTgSndAreaFlags(false),
mHasChangedTgSndAreaMgFlags(false),
mSavedTgSndAreaFlags(-1),
mSavedTgSndAreaMgFlags(-1),
mpUnkCallback(nullptr),
field_0x074(0),
mpOnEventStartCallback(nullptr),
field_0x07C(0),
mpTgSndAreaFlagsChangeCallback(nullptr),
mpTgSndAreaMgFlagsChangeCallback(nullptr),
field_0x088(0),
mSoundEventId(SND_EVENT_0x89),
mCameraCutCounter(0),
mEventFlags(0),
mpStbEventName(nullptr),
mFrameCounter(0),
mCameraCutFrameCounter(0),
mMsgFrameCounter(0),
mSeLvSoundId(-1),
field_0x22C(0),
mpSoundEventDef(nullptr),
field_0x238(-1),
field_0x23C(0),
field_0x23D(0),
field_0x240(0),
field_0x244(0),
field_0x248(0),
mMsgCounter(-1),
mMsgWaitSelectCounter(0),
field_0x254(0),
field_0x258(0),
field_0x48C(0),
mFxSend3DDefault(0.02f),
mFxSend3DOverride(-1.0f),
mFxSend3DNext(-1.0f),
mFxSend3D(0.02f),
mFxSend3DTarget(0.02f),
mPrevStageGroup(-1),
field_0x4A8(0),
mNeedsGroupsReload(false) {}
extern "C" void fn_803665B0(nw4r::snd::detail::FxReverbStdParam &, int);
void dSndStateMgr_c::setup(EGG::Heap *pHeap) {
u32 max = 0;
for (int i = 0; i < 5; i++) {
nw4r::snd::detail::FxReverbStdParam param;
fn_803665B0(param, i);
mFx.SetParam(param);
u32 thisSize = mFx.GetRequiredMemSize();
if (max < thisSize) {
max = thisSize;
}
}
void *mem = pHeap->alloc(max, 4);
mFx.AssignWorkBuffer(mem, max);
resetEventName();
}
void dSndStateMgr_c::onStageOrLayerUpdate() {
if (dSndPlayerMgr_c::GetInstance()->checkFlag(dSndPlayerMgr_c::MGR_CAUTION)) {
dSndPlayerMgr_c::GetInstance()->leaveCaution();
}
bool unk_0x065 = field_0x065;
onFlag0x10(FLAG0x10_0x02);
field_0x064 = false;
if (!streq(mStageName, dScGame_c::currentSpawnInfo.getStageName())) {
mNeedsGroupsReload = true;
mStageName = dScGame_c::currentSpawnInfo.getStageName();
}
if (!mNeedsGroupsReload && dScGame_c::currentSpawnInfo.layer != mLayer) {
mNeedsGroupsReload = true;
}
mLayer = dScGame_c::currentSpawnInfo.layer;
u32 newStageId = getStageId(dScGame_c::currentSpawnInfo.getStageName(), dScGame_c::currentSpawnInfo.layer);
mPreviousStageId = mStageId;
field_0x044 = getStageUnk2(newStageId);
mStageId = newStageId;
if (unk_0x065) {
setCallbacksForStage();
}
}
inline bool checkStagePrefix(const char *stageName, const char *prefix) {
return !std::strncmp(prefix, stageName, 2);
}
u32 dSndStateMgr_c::getStageTypeFlags(const char *stageName) const {
u32 flags = 0;
if (checkStagePrefix(stageName, "F0")) {
flags |= STAGE_SKY | STAGE_FIELD;
} else if (checkStagePrefix(stageName, "D0")) {
flags |= STAGE_SKY | STAGE_DUNGEON;
} else if (checkStagePrefix(stageName, "B0")) {
flags |= STAGE_SKY | STAGE_BOSS;
} else if (checkStagePrefix(stageName, "S0")) {
flags |= STAGE_SKY | STAGE_SILENT_REALM;
} else if (checkStagePrefix(stageName, "F1")) {
flags |= STAGE_FOREST | STAGE_FIELD;
} else if (checkStagePrefix(stageName, "D1")) {
flags |= STAGE_FOREST | STAGE_DUNGEON;
} else if (checkStagePrefix(stageName, "B1")) {
flags |= STAGE_FOREST | STAGE_BOSS;
} else if (checkStagePrefix(stageName, "S1")) {
flags |= STAGE_FOREST | STAGE_SILENT_REALM;
} else if (checkStagePrefix(stageName, "F2")) {
flags |= STAGE_MOUNTAIN | STAGE_FIELD;
} else if (checkStagePrefix(stageName, "D2")) {
flags |= STAGE_MOUNTAIN | STAGE_DUNGEON;
} else if (checkStagePrefix(stageName, "B2")) {
flags |= STAGE_MOUNTAIN | STAGE_BOSS;
} else if (checkStagePrefix(stageName, "S2")) {
flags |= STAGE_MOUNTAIN | STAGE_SILENT_REALM;
} else if (checkStagePrefix(stageName, "F3")) {
flags |= STAGE_DESERT | STAGE_FIELD;
} else if (checkStagePrefix(stageName, "D3")) {
flags |= STAGE_DESERT | STAGE_DUNGEON;
} else if (checkStagePrefix(stageName, "B3")) {
flags |= STAGE_DESERT | STAGE_BOSS;
} else if (checkStagePrefix(stageName, "S3")) {
flags |= STAGE_DESERT | STAGE_SILENT_REALM;
} else if (checkStagePrefix(stageName, "F4")) {
flags |= STAGE_SILENT_GROUNDS | STAGE_FIELD;
} else if (checkStagePrefix(stageName, "D4")) {
flags |= STAGE_SILENT_GROUNDS | STAGE_DUNGEON;
} else if (checkStagePrefix(stageName, "B4")) {
flags |= STAGE_SILENT_GROUNDS | STAGE_BOSS;
}
if ((flags & STAGE_SKY) != 0 && std::strstr(stageName, "r") != nullptr) {
flags |= STAGE_ROOM;
}
return flags;
}
bool dSndStateMgr_c::isVolcanicDungeon(u32 stageId) {
u32 base = getStageUnk2(stageId);
switch (base) {
case SND_STAGE_D200:
case SND_STAGE_D201:
case SND_STAGE_D201_1:
case SND_STAGE_D003_0:
case SND_STAGE_D003_1: return true;
default: return false;
}
}
bool dSndStateMgr_c::isSeekerStoneStage(const char *stageName, s32 layer) {
if (streq(stageName, "F000") && layer == 22) {
// Skyloft hint stone
return true;
}
if (streq(stageName, "F202") && layer == 10) {
// Boko base hint stone
return true;
}
return false;
}
bool dSndStateMgr_c::isSomeSkyloftRoom() const {
switch (field_0x044) {
case SND_STAGE_F001r:
case SND_STAGE_F002r:
case SND_STAGE_F011r:
case SND_STAGE_F005r:
case SND_STAGE_F006r:
case SND_STAGE_F007r:
case SND_STAGE_F013r:
case SND_STAGE_F014r:
case SND_STAGE_F015r:
case SND_STAGE_F016r:
case SND_STAGE_F017r:
case SND_STAGE_F018r: return true;
default: return false;
}
}
void dSndStateMgr_c::onRestartScene(s32 fadeFrames) {
if (field_0x064) {
return;
}
s32 nextLayer = dScGame_c::nextSpawnInfo.layer;
// This combines next stage with current layer, so this effectively checks if you're leaving the Hint Movie scene
if (isSeekerStoneStage(mStageName, dScGame_c::currentSpawnInfo.layer)) {
dSndBgmMgr_c::GetInstance()->stopAllBgm(fadeFrames);
} else if (mLayer != nextLayer) {
if (isSeekerStoneStage(mStageName, nextLayer)) {
dSndBgmMgr_c::GetInstance()->stopAllBgm(fadeFrames);
dSndBgmMgr_c::GetInstance()->prepareBgm(BGM_HINT_SELECT, 0);
dSndBgmMgr_c::GetInstance()->setOverrideBgmId(BGM_HINT_SELECT);
dSndBgmMgr_c::GetInstance()->activateOverrideBgmId();
dSndAreaSoundEffectMgr_c::GetInstance()->stopSounds(fadeFrames);
} else {
onGotoStage(fadeFrames);
onFlag0x10(FLAG0x10_0x01);
return;
}
}
dSndSmallEffectMgr_c::GetInstance()->stopAllSoundExceptEvent(fadeFrames);
dSndBgmMgr_c::GetInstance()->prepareBgm();
dSndHarpSongMgr_c::GetInstance()->deactivate();
onFlag0x10(FLAG0x10_0x01);
dSndBgmMgr_c::GetInstance()->setField_0x306(1);
offFlag0x10(FLAG0x10_0x04);
offFlag0x10(FLAG0x10_0x10);
}
void dSndStateMgr_c::loadStageSound() {
loadStageSound(false);
}
void dSndStateMgr_c::loadStageSound(bool force) {
if (!force && !mNeedsGroupsReload) {
return;
}
bool demo = isInDemo();
if (!checkFlag0x18(0x40)) {
for (int i = 0; i < dSndControlPlayerMgr_c::sNumPlayers; i++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(i, 0.0f, 0);
dSndControlPlayerMgr_c::GetInstance()->setFxSend(i, 0.0f, 0);
}
}
if (checkEventFlag(EVENT_0x800)) {
if (!dSndBgmMgr_c::GetInstance()->isPlayingBgmSound()) {
dSndControlPlayerMgr_c::GetInstance()->setupPlayerControlsStage();
offEventFlag(EVENT_0x800);
} else {
dSndControlPlayerMgr_c::GetInstance()->setupPlayerControlsStageBgm();
}
} else {
if (dSndBgmMgr_c::GetInstance()->isPlayingBgmSound()) {
dSndControlPlayerMgr_c::GetInstance()->setupPlayerControlsStageBgm();
onEventFlag(EVENT_0x800);
} else {
dSndControlPlayerMgr_c::GetInstance()->setupPlayerControlsStage();
}
}
dSndControlPlayerMgr_c::GetInstance()->muteScenePlayers(0);
dSndPlayerMgr_c::GetInstance()->shutdownDemo();
field_0x4A8 = 1;
bool bHasState1 = false;
if (isSomeSkyloftRoom()) {
u32 id = dSndMgr_c::GetInstance()->getArchive()->ConvertLabelStringToGroupId("GRP_FAN_TIMECHANGE");
if (dSndMgr_c::GetInstance()->getPlayer().IsLoadedGroup(id)) {
bHasState1 = true;
} else {
dSndPlayerMgr_c::GetInstance()->popToState0();
if (dSndMgr_c::GetInstance()->loadGroup(id, nullptr, 0)) {
dSndPlayerMgr_c::GetInstance()->saveState1();
bHasState1 = true;
}
}
}
const dSndStageInfo *info = &dSndStageInfo::sInfos[mStageId];
u32 id = -1;
int round = 1;
bool canReuseStageState = false;
SizedString<64> label;
if (info->unk4 == mStageId) {
const char *stageName = getStageName(info->unk4);
label.sprintf("GRP_A_%s_L%d", stageName, mLayer);
round = 2;
} else {
const char *stageName = getCurrentStageName4();
label.sprintf("GRP_A_%s", stageName);
}
for (; round > 0; round--) {
id = dSndMgr_c::GetInstance()->getArchive()->ConvertLabelStringToGroupId(label);
if (mPrevStageGroup == id && mPrevStageGroup != -1) {
canReuseStageState = true;
break;
}
if (id != -1) {
if (bHasState1) {
dSndPlayerMgr_c::GetInstance()->popToState1();
} else {
dSndPlayerMgr_c::GetInstance()->popToState0();
}
if (dSndMgr_c::GetInstance()->loadGroup(id, nullptr, 0)) {
mPrevStageGroup = id;
dSndPlayerMgr_c::GetInstance()->saveState2();
break;
}
}
if (round == 2) {
// we tried layer variant, now try variant without layer
const char *stageName = getCurrentStageName4();
label.sprintf("GRP_A_%s", stageName);
}
}
if (canReuseStageState) {
dSndPlayerMgr_c::GetInstance()->popToState2();
} else if (id == -1) {
if (bHasState1) {
dSndPlayerMgr_c::GetInstance()->popToState1();
} else {
dSndPlayerMgr_c::GetInstance()->popToState0();
}
dSndPlayerMgr_c::GetInstance()->saveState2();
mPrevStageGroup = -1;
}
if (!demo && (field_0x03C != 2 || field_0x065)) {
if (field_0x065) {
id = GRP_SIREN;
} else if (checkStageTypeFlag(STAGE_ROOM)) {
id = GRP_INDOOR;
} else if (checkStageTypeFlag(STAGE_FIELD)) {
id = GRP_FIELD;
} else if (checkStageTypeFlag(STAGE_DUNGEON)) {
if (isVolcanicDungeon(mStageId)) {
id = GRP_DUNGEON_BATTLE_ROOM;
} else {
id = GRP_DUNGEON;
}
} else if (checkStageTypeFlag(STAGE_BOSS)) {
id = GRP_BOSS;
} else {
id = GRP_DEFAULT;
}
if (id != -1) {
dSndMgr_c::GetInstance()->loadGroup(id, nullptr, 0);
}
}
if (!field_0x065) {
id = -1;
if (!demo) {
if (field_0x03C == 2) {
id = GRP_SKY;
} else if (checkStageTypeFlag(STAGE_FOREST)) {
id = GRP_FOREST;
} else if (checkStageTypeFlag(STAGE_MOUNTAIN)) {
id = GRP_MOUNTAIN;
} else if (checkStageTypeFlag(STAGE_DESERT)) {
id = GRP_DESERT;
}
if (id != -1) {
dSndMgr_c::GetInstance()->loadGroup(id, nullptr, 0);
}
}
SizedString<64> label;
label.sprintf("GRP_%s_L%d", &mStageName, mLayer);
id = dSndMgr_c::GetInstance()->getArchive()->ConvertLabelStringToGroupId(label);
if (id == -1) {
label.sprintf("GRP_%s", &mStageName);
id = dSndMgr_c::GetInstance()->getArchive()->ConvertLabelStringToGroupId(label);
}
if (id != -1) {
dSndMgr_c::GetInstance()->loadGroup(id, nullptr, 0);
}
if (demo) {
// REGSWAP
if (dSndPlayerMgr_c::GetInstance()->loadDemoArchive(getCurrentStageMusicDemoName())) {
for (u32 i = dSndPlayerMgr_c::PLAYER_LINK_BODY; i <= dSndPlayerMgr_c::PLAYER_EVENT; i++) {
dSndControlPlayerMgr_c::GetInstance()->getPlayer1(i)->StopAllSound(0);
}
dSndControlPlayerMgr_c::GetInstance()->setupPlayerControlsDemo();
}
}
}
field_0x4A8 = 0;
dSndBgmMgr_c::GetInstance()->loadStageSound();
f32 volume = -1.0f;
dSndAreaSoundEffectMgr_c::GetInstance()->loadStageSound(&volume);
if (volume > 0.0f) {
mFxSend3DDefault = volume;
}
}
void dSndStateMgr_c::calcEvent() {
if (!isInEvent()) {
return;
}
bool b = false;
if (dSndPlayerMgr_c::GetInstance()->checkFlag(dSndPlayerMgr_c::MGR_CAUTION) ||
dSndPlayerMgr_c::GetInstance()->checkFlag(dSndPlayerMgr_c::MGR_MAP) ||
dSndPlayerMgr_c::GetInstance()->checkFlag(dSndPlayerMgr_c::MGR_MSG_WAIT)) {
b = true;
}
if (mpSoundEventDef != nullptr && sEventExecuteCallback != nullptr) {
(sEventExecuteCallback)();
}
if (!b) {
if (EventManager::getCurrentEventName() == nullptr) {
if (!checkEventFlag(EVENT_0x800)) {
endEvent(false);
}
} else {
if (mSeLvSoundId != -1) {
dSndMgr_c::GetInstance()->holdSound(&mSeLvSoundHandle, mSeLvSoundId);
}
calcBgm();
calcSe();
calcCmd();
mFrameCounter++;
mCameraCutFrameCounter++;
mMsgFrameCounter++;
nw4r::snd::SeqSoundHandle::WriteGlobalVariable(2, mCameraCutFrameCounter);
}
}
}
void dSndStateMgr_c::setEvent(const char *eventName) {
if (eventName == nullptr) {
return;
}
if (dSndPlayerMgr_c::GetInstance()->checkFlag(dSndPlayerMgr_c::MGR_CAUTION)) {
dSndPlayerMgr_c::GetInstance()->leaveCaution();
}
if (!field_0x064) {
if (streq(mEventName, "DefaultSkip")) {
onSkipEvent();
mPrevEventName = mEventName;
return;
}
if (!checkFlag0x18(0x20) || !checkFlag0x10(FLAG0x10_0x04)) {
SizedString<64> prevEvent = mEventName;
if (isInEvent()) {
field_0x23C = 1;
finalizeEvent(false);
} else {
field_0x23C = 0;
}
// TODO - constness or direct access
if (checkEventFlag(EVENT_0x04)) {
offEventFlag(EVENT_0x04);
}
mEventName = eventName;
mPrevEventName = prevEvent;
resetEventVars();
field_0x23D = 0;
field_0x238 = -1;
if (streq(mEventName, "STB")) {
if (mpStbEventName != nullptr) {
mEventName = mpStbEventName;
}
onEventFlag(EVENT_DEMO);
} else {
mpStbEventName = nullptr;
}
if (!checkFlag0x10(FLAG0x10_0x04)) {
if (mpUnkCallback != nullptr) {
mpUnkCallback();
}
field_0x23D = 1;
dSndBgmMgr_c::GetInstance()->setField_0x306(1);
dSndBgmMgr_c::GetInstance()->prepareBgm();
onEventFlag(EVENT_0x04);
onFlag0x10(FLAG0x10_0x04);
dSndControlPlayerMgr_c::GetInstance()->unmuteScenePlayers(30);
}
bool b2 = checkEventFlag(EVENT_0x800) && dSndBgmMgr_c::GetInstance()->isPlayingBgmSound();
if (checkEventFlag(EVENT_0x800) && !field_0x064) {
// TODO - constness or direct access
offEventFlag(0x800);
}
mSoundEventId = SND_EVENT_0x89;
initializeEventCallbacks(mEventName);
s32 i3 = 0;
SizedString<64> eventLabel;
if (mSoundEventId == SND_EVENT_JMAP) {
s32 eventRoomId = EventManager::getCurrentEventRoomId();
// UB: Cannot pass object of non-POD type 'SizedString<32>' through variadic method
eventLabel.sprintf("%s_R%d_JMAP_%d", mStageName, mRoomId, eventRoomId);
} else if (mSoundEventId == SND_EVENT_JMAPAllMove) {
s32 eventRoomId = EventManager::getCurrentEventRoomId();
// UB: Cannot pass object of non-POD type 'SizedString<32>' through variadic method
eventLabel.sprintf("%s_R%d_JMAPAllMove_%d", mStageName, mRoomId, eventRoomId);
} else {
eventLabel.sprintf("%s", &mEventName);
}
if (checkEventFlag(EVENT_DEMO)) {
mBgmName.sprintf("BGM_%s", &eventLabel);
mFanName.sprintf("FAN_%s", &eventLabel);
mSeName.sprintf("SE_%s", &eventLabel);
mCmdName.sprintf("CMD_%s", &eventLabel);
} else {
mBgmName.sprintf("BGM_EVENT_%s", &eventLabel);
mFanName.sprintf("FAN_EVENT_%s", &eventLabel);
mSeName.sprintf("SE_EVENT_%s", &eventLabel);
mCmdName.sprintf("CMD_EVENT_%s", &eventLabel);
}
if (checkEventFlag(EVENT_0x04)) {
field_0x238 = getBgmLabelSoundId();
if (b2 && field_0x238 == -1) {
field_0x23D = 0;
}
} else {
i3 = playFanOrBgm(getBgmLabelSoundId());
if (i3) {
field_0x23D = 0;
}
}
handleFan();
handleSe();
handleSeLv();
handleCmd();
if (mSoundEventId != SND_EVENT_0x89) {
onEventFlag(EVENT_IN_EVENT);
mFrameCounter = 0;
mCameraCutFrameCounter = 0;
mMsgFrameCounter = 0;
if (mpOnEventStartCallback != nullptr) {
(mpOnEventStartCallback)(mSoundEventId, mEventFlags);
}
if (field_0x238 == -1) {
dSndBgmMgr_c::GetInstance()->onEventStart(mEventName, mSoundEventId, i3);
}
dSndAreaSoundEffectMgr_c::GetInstance()->onEventStart();
dSndSourceMgr_c::GetInstance()->onEventStart();
}
}
}
}
bool dSndStateMgr_c::isInStage(const char *stageName) {
return !std::strcmp(dScGame_c::currentSpawnInfo.getStageName(), stageName);
}
void dSndStateMgr_c::initializeEventCallbacks(const char *name) {
if (name == nullptr) {
return;
}
mpSoundEventDef = nullptr;
sEventExecuteCallback = nullptr;
resetOverrides();
if (checkEventFlag(EVENT_DEMO)) {
handleDemoEvent(name);
return;
}
if (mSoundEventId == SND_EVENT_0x87) {
return;
}
if (!handleStageEvent(name)) {
handleGlobalEvent(name);
}
if (mSoundEventId == SND_EVENT_0x89) {
if (strstr(name, "Intro")) {
mSoundEventId = SND_EVENT_0x88;
} else {
mSoundEventId = SND_EVENT_0x86;
cbUnkNoop();
}
}
}
void dSndStateMgr_c::doLabelSuffix(const char *suffix) {
SizedString<64> label;
label.sprintf("%s%s", &mBgmName, suffix);
doBgm(label);
label.sprintf("%s%s", &mSeName, suffix);
doSe(label);
label.sprintf("%s%s", &mCmdName, suffix);
doCmd(label);
}
u32 dSndStateMgr_c::getSeCameraId() {
SizedString<64> label;
label.sprintf(getCameraFmt(), &mSeName, mCameraCutCounter, mCameraCutFrameCounter);
return convertSeLabelToSoundId(label);
}
u32 dSndStateMgr_c::getSeMsgWaitId() {
SizedString<64> label;
label.sprintf(getMsgWaitFmt(), &mSeName, mMsgCounter, mMsgWaitSelectCounter, mMsgFrameCounter);
return convertSeLabelToSoundId(label);
}
u32 dSndStateMgr_c::getSeFrameCountId() {
SizedString<64> label;
label.sprintf(getFrameFmt(), &mSeName, mFrameCounter);
return convertSeLabelToSoundId(label);
}
u32 dSndStateMgr_c::getBgmCameraId() {
SizedString<64> label;
label.sprintf(getCameraFmt(), &mBgmName, mCameraCutCounter, mCameraCutFrameCounter);
return convertBgmLabelToSoundId(label);
}
u32 dSndStateMgr_c::getBgmMsgWaitId() {
SizedString<64> label;
label.sprintf(getMsgWaitFmt(), &mBgmName, mMsgCounter, mMsgWaitSelectCounter, mMsgFrameCounter);
return convertBgmLabelToSoundId(label);
}
u32 dSndStateMgr_c::getBgmFrameCountId() {
SizedString<64> label;
label.sprintf(getFrameFmt(), &mBgmName, mFrameCounter);
return convertBgmLabelToSoundId(label);
}
u32 dSndStateMgr_c::getCmdCameraId() {
SizedString<64> label;
label.sprintf(getCameraFmt(), &mCmdName, mCameraCutCounter, mCameraCutFrameCounter);
return convertCmdLabelToSoundId(label);
}
u32 dSndStateMgr_c::getCmdMsgWaitId() {
SizedString<64> label;
label.sprintf(getMsgWaitFmt(), &mCmdName, mMsgCounter, mMsgWaitSelectCounter, mMsgFrameCounter);
return convertCmdLabelToSoundId(label);
}
u32 dSndStateMgr_c::getCmdFrameCountId() {
SizedString<64> label;
label.sprintf(getFrameFmt(), &mCmdName, mFrameCounter);
return convertCmdLabelToSoundId(label);
}
void dSndStateMgr_c::clearEventExecuteCallback() {
sEventExecuteCallback = nullptr;
}
bool dSndStateMgr_c::calcBgm() {
bool ok = playFanOrBgm(getBgmCameraId());
if (!ok) {
ok = playFanOrBgm(getBgmMsgWaitId());
}
if (!ok) {
// @bug (?) shouldn't this assign to ok? Maybe a shadowing redeclaration...
(void)playFanOrBgm(getBgmFrameCountId());
}
return ok;
}
void dSndStateMgr_c::calcSe() {
playSe(getSeCameraId());
playSe(getSeMsgWaitId());
playSe(getSeFrameCountId());
}
void dSndStateMgr_c::handleSeLv() {
SizedString<0x40> name = mSeName;
name += "_LV";
u32 soundId = convertSeLabelToSoundId(name);
if (soundId != -1) {
mSeLvSoundId = soundId;
if (dSndMgr_c::GetInstance()->holdSound(&mSeLvSoundHandle, soundId)) {
u32 id = dSndPlayerMgr_c::GetInstance()->getDemoArchive()->GetSoundUserParam(soundId);
if ((dSndPlayerMgr_c::sEventMuteFlagsMask & id & 0x2000000) == 0) {
mSeLvSoundHandle.SetFxSend(nw4r::snd::AUX_A, mFxSend3D);
}
}
} else {
mSeLvSoundId = -1;
}
}
void dSndStateMgr_c::calcCmd() {
playCmd(getCmdCameraId());
playCmd(getCmdMsgWaitId());
playCmd(getCmdFrameCountId());
}
bool dSndStateMgr_c::finalizeEvent(bool skipped) {
dSndPlayerMgr_c *mgr = dSndPlayerMgr_c::GetInstance();
if (mgr->checkFlag(dSndPlayerMgr_c::MGR_CAUTION)) {
mgr->leaveCaution();
}
if (!isInEvent()) {
return false;
}
if (mpSoundEventDef != nullptr && mpSoundEventDef->finalizeCb) {
mpSoundEventDef->finalizeCb(skipped);
}
if (!isInDemo()) {
nw4r::snd::SoundPlayer *p = dSndControlPlayerMgr_c::GetInstance()->getPlayer1(dSndPlayerMgr_c::PLAYER_EVENT);
SoundStopperIfParamFlag20 stopper;
p->ForEachSound(stopper, false);
}
SizedString<64> label;
label.sprintf("%s_FIN", &mSeName);
playSe(dSndPlayerMgr_c::GetInstance()->convertLabelStringToSoundId(label));
label.sprintf("%s_FIN", &mBgmName);
doBgm(label);
label.sprintf("%s_FIN", &mCmdName);
doCmd(label);
return dSndBgmMgr_c::GetInstance()->onEventFinalize(mEventName, mSoundEventId, skipped);
}
// TODO - the whole "camera cut" thing seems plausible but I haven't confirmed it yet
void dSndStateMgr_c::onCameraCut(s32 cutIdx) {
if (cutIdx <= 0) {
mCameraCutCounter++;
} else {
mCameraCutCounter = cutIdx;
}
mCameraCutFrameCounter = 0;
nw4r::snd::SeqSoundHandle::WriteGlobalVariable(1, mCameraCutCounter);
nw4r::snd::SeqSoundHandle::WriteGlobalVariable(2, 0);
SizedString<64> suffix;
suffix.sprintf("_C%d", mCameraCutCounter);
doLabelSuffix(suffix);
}
bool dSndStateMgr_c::isInEvent() {
return checkEventFlag(EVENT_IN_EVENT);
}
bool dSndStateMgr_c::isInEvent(const char *eventName) {
return streq(mEventName, eventName);
}
void dSndStateMgr_c::onMsgStart(s32 idx) {
if (idx >= 0) {
mMsgCounter = idx;
} else {
mMsgCounter++;
}
field_0x254 = 1;
mMsgWaitSelectCounter = 0;
mMsgFrameCounter = 0;
SizedString<64> label;
label.sprintf("_MS%d", mMsgCounter);
doLabelSuffix(label);
}
void dSndStateMgr_c::onMsgEnd() {
field_0x254 = 0;
SizedString<64> label;
label.sprintf("_ME%d", mMsgCounter);
doLabelSuffix(label);
}
void dSndStateMgr_c::onMsgWaitStart() {
mMsgFrameCounter = 0;
mMsgWaitSelectCounter++;
if (mpSoundEventDef != nullptr && mpSoundEventDef->msgWaitStartCb != nullptr) {
mpSoundEventDef->msgWaitStartCb(mMsgWaitSelectCounter);
}
SizedString<64> label;
label.sprintf("_M%d_WS%d", mMsgCounter, mMsgWaitSelectCounter);
doLabelSuffix(label);
}
void dSndStateMgr_c::onMsgWaitEnd() {
if (mpSoundEventDef != nullptr && mpSoundEventDef->msgWaitEndCb != nullptr) {
mpSoundEventDef->msgWaitEndCb(mMsgWaitSelectCounter);
}
SizedString<64> label;
label.sprintf("_M%d_WE%d", mMsgCounter, mMsgWaitSelectCounter);
doLabelSuffix(label);
}
void dSndStateMgr_c::onLinkDie() {
if (!checkFlag0x10(FLAG0x10_0x08)) {
onFlag0x10(FLAG0x10_0x08);
dSndBgmMgr_c::GetInstance()->stopAllBgm(15);
dSndSmallEffectMgr_c::GetInstance()->stopAllSoundExceptEffectOrLink(15);
if (field_0x065 == 0) {
dSndBgmMgr_c::GetInstance()->prepareFanSound(FAN_GAMEOVER);
}
}
}
void dSndStateMgr_c::setStbEventName(const char *eventName) {
mpStbEventName = eventName;
}
void dSndStateMgr_c::calcRoomId() {
if (checkFlag0x10(FLAG0x10_0x04)) {
if (mCheckRoomIdCooldown > 0) {
mCheckRoomIdCooldown--;
} else {
if (mRoomId == -1) {
mCheckRoomIdCooldown = 30;
}
s32 newRoom = dSndSourceMgr_c::GetInstance()->getPlayerSourceRoomId();
if (mRoomId != newRoom) {
setRoomId(newRoom);
} else if (newRoom != -1 && !checkFlag0x10(FLAG0x10_0x10)) {
setRoomId(newRoom);
}
}
}
}
void dSndStateMgr_c::setRoomId(s32 roomId) {
// ...
}
void dSndStateMgr_c::calcTgSnd() {
mHasChangedTgSndAreaFlags = false;
mHasChangedTgSndAreaMgFlags = false;
dAcPy_c *link = dAcPy_c::GetLinkM();
if (link != nullptr && dTgSndMg_c::GetInstance() != nullptr) {
u32 flags = dTgSndMg_c::GetInstance()->getSndFlags();
if (flags != mSavedTgSndAreaMgFlags) {
mHasChangedTgSndAreaMgFlags = true;
if (mpTgSndAreaMgFlagsChangeCallback != nullptr) {
(mpTgSndAreaMgFlagsChangeCallback)(flags, mSavedTgSndAreaMgFlags);
}
dSndBgmMgr_c::GetInstance()->onTgSndAreaMgFlagsChange(flags, mSavedTgSndAreaMgFlags);
mSavedTgSndAreaMgFlags = flags;
}
if (dSndSourceMgr_c::getBoomerangSource() != nullptr) {
flags = mSavedTgSndAreaMgFlags;
} else {
flags = link->mTgSndAreaFlags;
}
if (flags != mSavedTgSndAreaFlags) {
mHasChangedTgSndAreaFlags = true;
if (mpTgSndAreaFlagsChangeCallback != nullptr) {
(mpTgSndAreaFlagsChangeCallback)(flags, mSavedTgSndAreaFlags);
}
mFxSend3DNext = getUserParamVolume(flags);
dSndBgmMgr_c::GetInstance()->onTgSndAreaFlagsChange(flags, mSavedTgSndAreaFlags);
mSavedTgSndAreaFlags = flags;
}
}
}
void dSndStateMgr_c::calcFilters() {
dCamera_c *cam = dScGame_c::getCamera(0);
if (cam != nullptr && !checkFlag0x258(0x2)) {
if (cam->isUnderwater()) {
if (!checkFlag0x258(0x1)) {
resetFlag0x258();
onFlag0x258(1);
setFiltersIfUnderwater();
}
f32 depth = cam->getUnderwaterDepth();
dSndAreaSoundEffectMgr_c::GetInstance()->holdInWaterLvSound(depth);
f32 maxDepth = isInStage("F103") ? 5000.0f : 1000.0f;
f32 unk = isInStage("F103") ? 0.5f : 0.3f;
if (depth < maxDepth) {
f32 tmp = (1.0f - unk);
f32 tmp2 = (depth / maxDepth);
unk = 1.0f - tmp2 * tmp;
}
dSndBgmMgr_c::GetInstance()->updateField_0x2F4(unk);
} else {
if (checkFlag0x258(0x1)) {
offFlag0x258(1);
resetLpfAndFxSend();
}
if (dAcPy_c::GetLink()->checkActionFlagsCont(0x400000)) {
if (!checkFlag0x258(0x4)) {
resetFlag0x258();
onFlag0x258(0x4);
setBgmAndStageEffectLpf();
dSndBgmMgr_c::GetInstance()->setField_0x307(0);
}
} else {
if (checkFlag0x258(0x4)) {
offFlag0x258(0x4);
resetBgmAndStageEffectLpf();
if (dSndBgmMgr_c::GetInstance()->getField_0x308() != 0) {
dSndBgmMgr_c::GetInstance()->setField_0x307(1);
}
}
}
}
}
}
void dSndStateMgr_c::setFiltersIfUnderwater() {
dCamera_c *cam = dScGame_c::getCamera(0);
if (cam == nullptr || cam->isUnderwater()) {
setBgmLpfAndFxSendIfUnderwater();
for (u32 id = dSndPlayerMgr_c::PLAYER_LINK_BODY; id < dSndPlayerMgr_c::PLAYER_LINK_EQUIPMENT + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, -0.45f, 15);
}
for (u32 id = dSndPlayerMgr_c::PLAYER_ENEMY; id < dSndPlayerMgr_c::PLAYER_AREA + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, -0.41f, 15);
}
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(dSndPlayerMgr_c::PLAYER_AREA_IN_WATER_LV, -0.3f, 15);
for (u32 id = dSndPlayerMgr_c::PLAYER_ENEMY; id <= dSndPlayerMgr_c::PLAYER_AREA_IN_WATER_LV; id++) {
dSndControlPlayerMgr_c::GetInstance()->setFxSend(id, 0.14f, 15);
}
}
}
void dSndStateMgr_c::setBgmLpfAndFxSendIfUnderwater() {
dCamera_c *cam = dScGame_c::getCamera(0);
if (cam == nullptr || cam->isUnderwater()) {
for (u32 id = dSndPlayerMgr_c::PLAYER_BGM; id < dSndPlayerMgr_c::PLAYER_BGM_BATTLE + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, -0.55f, 15);
dSndControlPlayerMgr_c::GetInstance()->setFxSend(id, 0.2f, 15);
}
}
}
void dSndStateMgr_c::resetLpfAndFxSend() {
resetBgmLpfAndFxSend();
for (u32 id = dSndPlayerMgr_c::PLAYER_LINK_BODY; id <= dSndPlayerMgr_c::PLAYER_AREA_IN_WATER_LV; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, 0.0f, 15);
}
for (u32 id = dSndPlayerMgr_c::PLAYER_LINK_BODY; id <= dSndPlayerMgr_c::PLAYER_AREA_IN_WATER_LV; id++) {
dSndControlPlayerMgr_c::GetInstance()->setFxSend(id, 0.0f, 15);
}
}
void dSndStateMgr_c::resetBgmLpfAndFxSend() {
for (u32 id = dSndPlayerMgr_c::PLAYER_BGM; id < dSndPlayerMgr_c::PLAYER_BGM_BATTLE + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, 0.0f, 15);
dSndControlPlayerMgr_c::GetInstance()->setFxSend(id, 0.0f, 15);
}
}
void dSndStateMgr_c::setBgmAndStageEffectLpf() {
setBgmLpf();
for (u32 id = dSndPlayerMgr_c::PLAYER_TG_SOUND; id < dSndPlayerMgr_c::PLAYER_AREA + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, -0.55f, 15);
}
}
void dSndStateMgr_c::setBgmLpf() {
setBgmLpf(15);
}
void dSndStateMgr_c::setBgmLpf(s32 fadeFrames) {
for (u32 id = dSndPlayerMgr_c::PLAYER_BGM; id < dSndPlayerMgr_c::PLAYER_BGM_BATTLE + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, -0.55f, fadeFrames);
}
}
void dSndStateMgr_c::resetBgmAndStageEffectLpf() {
resetBgmLpf();
for (u32 id = dSndPlayerMgr_c::PLAYER_TG_SOUND; id < dSndPlayerMgr_c::PLAYER_AREA + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, 0.0f, 15);
}
}
void dSndStateMgr_c::resetBgmLpf() {
for (u32 id = dSndPlayerMgr_c::PLAYER_BGM; id < dSndPlayerMgr_c::PLAYER_BGM_BATTLE + 1; id++) {
dSndControlPlayerMgr_c::GetInstance()->setLpfFreq(id, 0.0f, 15);
}
}
void dSndStateMgr_c::calcFxSend3D() {
if (mFxSend3D > mFxSend3DTarget) {
mFxSend3D -= 0.02f;
if (mFxSend3D < mFxSend3DTarget) {
mFxSend3D = mFxSend3DTarget;
}
} else if (mFxSend3D < mFxSend3DTarget) {
mFxSend3D += 0.02f;
if (mFxSend3D > mFxSend3DTarget) {
mFxSend3D = mFxSend3DTarget;
}
}
}
void dSndStateMgr_c::setFxSend3DTarget() {
// TODO - weird control flow
f32 target = mFxSend3DDefault;
if (mFxSend3DNext > 0.0f) {
target = mFxSend3DNext;
} else if (mFxSend3DOverride > 0.0f) {
target = mFxSend3DOverride;
}
if (target < 0.02f) {
target = 0.02f;
} else if (target > 0.3f) {
target = 0.3f;
}
mFxSend3DTarget = target;
}
f32 dSndStateMgr_c::getUserParamVolume(u32 userParam) {
s32 bit = 31;
for (int i = 0; i < 4; i++) {
if (((1 << bit) & userParam) != 0) {
switch (bit) {
case 31: return 0.3f;
case 30: return 0.2f;
case 29: return 0.1f;
case 28: return 0.02f;
}
}
bit--;
}
return 0.0f;
}
const char *dSndStateMgr_c::getStageName(s32 id) {
if (id >= SND_STAGE_MAX) {
return "NULL";
}
return dSndStageInfo::sInfos[id].stageName;
}
const char *dSndStateMgr_c::getStageName4(s32 id) {
if (id >= SND_STAGE_MAX) {
return "NULL";
}
return dSndStageInfo::sInfos[getSndStageId4(id)].stageName;
}
const char *dSndStateMgr_c::getCurrentStageName4() {
return getStageName(dSndStageInfo::sInfos[mStageId].unk4);
}
s32 dSndStateMgr_c::getSndStageId(const char *stageName, s32 layer) {
if (stageName != nullptr) {
for (s32 idx = 0; idx < dSndStageInfo::sNumStageInfos; idx++) {
if (streq(stageName, dSndStageInfo::sInfos[idx].stageName)) {
if (dSndStageInfo::sInfos[idx].layer == -1) {
return dSndStageInfo::sInfos[idx].unk1;
}
if (dSndStageInfo::sInfos[idx].layer == layer) {
return dSndStageInfo::sInfos[idx].unk1;
}
}
}
}
return SND_STAGE_MAX;
}
s32 dSndStateMgr_c::getSndStageId3(const char *stageName, s32 layer) {
if (stageName != nullptr) {
for (s32 idx = 0; idx < dSndStageInfo::sNumStageInfos; idx++) {
if (streq(stageName, dSndStageInfo::sInfos[idx].stageName)) {
if (dSndStageInfo::sInfos[idx].layer == -1 || dSndStageInfo::sInfos[idx].layer == layer) {
return dSndStageInfo::sInfos[idx].unk3;
}
}
}
}
return SND_STAGE_MAX;
}
s32 dSndStateMgr_c::getSndStageId4(const char *stageName, s32 layer) {
if (stageName != nullptr) {
for (s32 idx = 0; idx < dSndStageInfo::sNumStageInfos; idx++) {
if (streq(stageName, dSndStageInfo::sInfos[idx].stageName)) {
if (dSndStageInfo::sInfos[idx].layer == -1 || dSndStageInfo::sInfos[idx].layer == layer) {
return dSndStageInfo::sInfos[idx].unk4;
}
}
}
}
return SND_STAGE_MAX;
}
s32 dSndStateMgr_c::getSndStageId2(s32 id) {
if (id >= SND_STAGE_MAX) {
return SND_STAGE_MAX;
}
return dSndStageInfo::sInfos[id].unk2;
}
s32 dSndStateMgr_c::getSndStageId4(s32 id) {
if (id >= SND_STAGE_MAX) {
return SND_STAGE_MAX;
}
return dSndStageInfo::sInfos[id].unk4;
}
s32 dSndStateMgr_c::getNextSndStageId(s32 id) {
return getSndStageId(dScGame_c::nextSpawnInfo.getStageName(), dScGame_c::nextSpawnInfo.layer);
}
bool dSndStateMgr_c::specialLayerVersionExists(const char *stageName, s32 layer) {
if (stageName != nullptr && layer > 0) {
return getSndStageId(stageName, layer) != getSndStageId(stageName, 0);
}
return false;
}
u32 dSndStateMgr_c::getSoundIdForStageAndLayer(SoundIdLookup_e lookup, const char *stageName, s32 layer, s32 stageId) {
// Ternary causes regswaps...
const char *prefix = "BGM_";
if (lookup == LOOKUP_SE_A) {
prefix = "SE_A_";
}
SizedString<64> label;
u32 soundId = -1;
s32 round = 3;
bool hasSpecialLayerVersion = false;
if (layer > 0) {
hasSpecialLayerVersion = specialLayerVersionExists(stageName, layer);
}
if (hasSpecialLayerVersion) {
label.sprintf("%s%s_L%d", prefix, stageName, layer);
} else if (layer > 0) {
label.sprintf("%s%s_L%d", prefix, stageName, layer);
} else {
label.sprintf("%s%s", prefix, stageName);
// We didn't bother with a _L layer variant, so we're going
// in with the base variant
round = 2;
}
while (round > 0) {
if (lookup == LOOKUP_BGM_MAIN) {
label += "_MAIN";
}
soundId = dSndPlayerMgr_c::GetInstance()->convertLabelStringToSoundId(label);
if (soundId != -1) {
break;
}
if (round == 3) {
// If _L layer variant didn't exist, try the one without a layer...
label.sprintf("%s%s", prefix, stageName);
} else if (round == 2) {
if (lookup == LOOKUP_BGM) {
// If the one without a layer doesn't exist, continue with the one referenced
// in field 3, unless it's the same as the original one
s32 otherStageId = getSndStageId3(stageName, layer);
if (stageId != otherStageId) {
label.sprintf("%s%s", prefix, getStageName(otherStageId));
} else {
// break to prevent infinite loop
round = 0;
}
} else if (lookup == LOOKUP_SE_A) {
// If the one without a layer doesn't exist, continue with the one referenced
// in field 4, unless it's the same as the original one
s32 otherStageId = getSndStageId4(stageName, layer);
if (stageId != otherStageId) {
label.sprintf("%s%s", prefix, getStageName(otherStageId));
} else {
// break to prevent infinite loop
break;
}
} else {
break;
}
}
round--;
}
return soundId;
}