summaryrefslogtreecommitdiff
path: root/src/d/snd/d_snd_sound_equipment_callbacks.cpp
blob: 75d9e10f2e616aab33c0df92daa8afa8e5f1264b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156

#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<u32>(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;
    }
}