Skip to content

Commit 8037a54

Browse files
committed
C4SoundSystem: Fix 'global' script sounds not being constrained to a section and differentiate between section-local and global sounds
1 parent 63a6c66 commit 8037a54

9 files changed

+85
-63
lines changed

src/C4Control.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,9 +1246,9 @@ void C4ControlMessage::Execute(const std::shared_ptr<spdlog::logger> &) const
12461246
if (auto *client = Game.Clients.getClientByID(iByClient); client && client->TryAllowSound())
12471247
{
12481248
if (client->isMuted()
1249-
|| StartSoundEffect(szMessage, false, 100, nullptr)
1250-
|| StartSoundEffect((szMessage + std::string{".ogg"}).c_str(), false, 100, nullptr)
1251-
|| StartSoundEffect((szMessage + std::string{".mp3"}).c_str(), false, 100, nullptr))
1249+
|| StartSoundEffect(szMessage, false, 100, C4SoundSystem::GlobalSound)
1250+
|| StartSoundEffect((szMessage + std::string{".ogg"}).c_str(), false, 100, C4SoundSystem::GlobalSound)
1251+
|| StartSoundEffect((szMessage + std::string{".mp3"}).c_str(), false, 100, C4SoundSystem::GlobalSound))
12521252
{
12531253
if (pLobby) pLobby->OnClientSound(Game.Clients.getClientByID(iByClient));
12541254
}

src/C4GameLobby.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ void MainDlg::SetCountdownState(CountdownState eToState, int32_t iTimer)
350350
// changing away from countdown?
351351
if (eCountdownState == CDS_Countdown)
352352
{
353-
StopSoundEffect("Elevator", nullptr);
353+
StopSoundEffect("Elevator", C4SoundSystem::GlobalSound);
354354
if (eToState != CDS_Start) StartSoundEffect("Pshshsh");
355355
}
356356
// change to game start?

src/C4GraphicsSystem.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,11 @@ int32_t C4GraphicsSystem::GetAudibility(C4Section &section, int32_t iX, int32_t
776776
return iAudible;
777777
}
778778

779+
bool C4GraphicsSystem::IsSectionAudible(C4Section &section) const
780+
{
781+
return std::ranges::any_of(Viewports, [&section](const auto &cvp) { return &cvp->GetViewSection() == &section; });
782+
}
783+
779784
void C4GraphicsSystem::SetGamma(uint32_t dwClr1, uint32_t dwClr2, uint32_t dwClr3, int32_t iRampIndex)
780785
{
781786
// No gamma effects

src/C4GraphicsSystem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class C4GraphicsSystem
7575
bool CreateViewport(int32_t iPlayer, bool fSilent);
7676
bool CloseViewport(int32_t iPlayer, bool fSilent);
7777
int32_t GetAudibility(C4Section &section, int32_t iX, int32_t iY, int32_t *iPan, int32_t iAudibilityRadius = 0);
78+
bool IsSectionAudible(C4Section &section) const;
7879
int32_t GetViewportCount();
7980
C4Viewport *GetViewport(int32_t iPlayer);
8081
const std::vector<std::unique_ptr<C4Viewport>> &GetViewports() { return Viewports; }

src/C4Script.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,10 +2456,19 @@ static bool FnSound(C4AulContext *cthr, C4String *szSound, bool fGlobal, C4Objec
24562456
if (iLoop >= 0 && !fMultiple && IsSoundPlaying(FnStringPar(szSound), pObj))
24572457
return true;
24582458
// try to play effect
2459+
C4SoundSystem::TargetVariant target;
2460+
if (fGlobal)
2461+
{
2462+
target.emplace<C4Section *>(&cthr->GetSection());
2463+
}
2464+
else
2465+
{
2466+
target.emplace<C4Object *>(pObj);
2467+
}
24592468
if (iLoop >= 0)
2460-
StartSoundEffect(FnStringPar(szSound), !!iLoop, iLevel, pObj, iCustomFalloffDistance);
2469+
StartSoundEffect(FnStringPar(szSound), !!iLoop, iLevel, target, iCustomFalloffDistance);
24612470
else
2462-
StopSoundEffect(FnStringPar(szSound), pObj);
2471+
StopSoundEffect(FnStringPar(szSound), target);
24632472
// always return true (network safety!)
24642473
return true;
24652474
}

src/C4SoundSystem.cpp

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,43 +30,43 @@
3030
#include <utility>
3131
#include <vector>
3232

33-
bool IsSoundPlaying(const char *const name, const C4Object *const obj)
33+
bool IsSoundPlaying(const char *const name, const C4SoundSystem::TargetVariant target)
3434
{
35-
return Application.SoundSystem->FindInst(name, obj).has_value();
35+
return Application.SoundSystem->FindInst(name, target).has_value();
3636
}
3737

38-
void SoundLevel(const char *const name, C4Object *const obj, const std::int32_t level)
38+
void SoundLevel(const char *const name, const C4SoundSystem::TargetVariant target, const std::int32_t level)
3939
{
4040
// Sound level zero? Stop
41-
if (level <= 0) { StopSoundEffect(name, obj); return; }
41+
if (level <= 0) { StopSoundEffect(name, target); return; }
4242
// Set volume of existing instance or create new instance
43-
const auto it = Application.SoundSystem->FindInst(name, obj);
43+
const auto it = Application.SoundSystem->FindInst(name, target);
4444
if (it)
4545
{
4646
(**it).volume = level;
4747
}
4848
else
4949
{
50-
StartSoundEffect(name, true, level, obj);
50+
StartSoundEffect(name, true, level, target);
5151
}
5252
}
5353

5454
bool StartSoundEffect(const char *const name, const bool loop, const std::int32_t volume,
55-
C4Object *const obj, const std::int32_t falloffDistance)
55+
const C4SoundSystem::TargetVariant target, const std::int32_t falloffDistance)
5656
{
57-
return Application.SoundSystem->NewInstance(name, loop, volume, 0, obj, falloffDistance) != nullptr;
57+
return Application.SoundSystem->NewInstance(name, loop, volume, 0, target, falloffDistance) != nullptr;
5858
}
5959

6060
void StartSoundEffectAt(const char *const name, C4Section &section, const std::int32_t x, const std::int32_t y)
6161
{
6262
std::int32_t volume, pan;
6363
Application.SoundSystem->GetVolumeByPos(section, x, y, volume, pan);
64-
Application.SoundSystem->NewInstance(name, false, volume, pan, nullptr, 0);
64+
Application.SoundSystem->NewInstance(name, false, volume, pan, C4SoundSystem::Position{&section, x, y}, 0);
6565
}
6666

67-
void StopSoundEffect(const char *const name, const C4Object *const obj)
67+
void StopSoundEffect(const char *const name, const C4SoundSystem::TargetVariant target)
6868
{
69-
if (const auto it = Application.SoundSystem->FindInst(name, obj))
69+
if (const auto it = Application.SoundSystem->FindInst(name, target))
7070
{
7171
(**it).sample.instances.erase(*it);
7272
}
@@ -156,7 +156,7 @@ bool C4SoundSystem::Instance::DetachObj()
156156
if (loop) return false;
157157
// Otherwise: set volume by last position
158158
const auto detachedObj = GetObj();
159-
obj.emplace<const ObjPos>(*detachedObj);
159+
target.emplace<Position>(detachedObj->Section, detachedObj->x, detachedObj->y);
160160
GetVolumeByPos(*detachedObj->Section, detachedObj->x, detachedObj->y, volume, pan);
161161

162162
// Do not stop instance
@@ -200,6 +200,10 @@ bool C4SoundSystem::Instance::Execute(const bool justStarted)
200200
vol *= audibility / 100.0f;
201201
pan += obj->GetAudiblePan() / 100.0f;
202202
}
203+
else if (C4Section *const *const section{std::get_if<C4Section *>(&target)}; section && !Game.GraphicsSystem.IsSectionAudible(**section))
204+
{
205+
vol = 0.0f;
206+
}
203207

204208
// Sound off? Release channel to make it available for other instances.
205209
if (vol <= 0.0f)
@@ -237,7 +241,7 @@ bool C4SoundSystem::Instance::Execute(const bool justStarted)
237241

238242
C4Object *C4SoundSystem::Instance::GetObj() const
239243
{
240-
const auto ptr = std::get_if<C4Object *>(&obj);
244+
const auto ptr = std::get_if<C4Object *>(&target);
241245
return ptr ? *ptr : nullptr;
242246
}
243247

@@ -252,10 +256,10 @@ std::uint32_t C4SoundSystem::Instance::GetPlaybackPosition() const
252256
bool C4SoundSystem::Instance::IsNear(const C4Object &obj2) const
253257
{
254258
// Attached to object?
255-
if (const auto objAsObject = std::get_if<C4Object *>(&obj); objAsObject && *objAsObject)
259+
if (const auto targetAsObject = std::get_if<C4Object *>(&target); targetAsObject && *targetAsObject)
256260
{
257-
const auto x = (**objAsObject).x;
258-
const auto y = (**objAsObject).y;
261+
const auto x = (**targetAsObject).x;
262+
const auto y = (**targetAsObject).y;
259263
return (x - obj2.x) * (x - obj2.x) + (y - obj2.y) * (y - obj2.y) <=
260264
NearSoundRadius * NearSoundRadius;
261265
}
@@ -267,7 +271,7 @@ bool C4SoundSystem::Instance::IsNear(const C4Object &obj2) const
267271
return false;
268272
}
269273

270-
auto C4SoundSystem::FindInst(const char *wildcard, const C4Object *const obj) ->
274+
auto C4SoundSystem::FindInst(const char *wildcard, const TargetVariant target) ->
271275
std::optional<decltype(Sample::instances)::iterator>
272276
{
273277
const auto wildcardStr = PrepareFilename(wildcard);
@@ -279,7 +283,7 @@ auto C4SoundSystem::FindInst(const char *wildcard, const C4Object *const obj) ->
279283
if (!WildcardMatch(wildcard, sample.name.c_str())) continue;
280284
// Try to find an instance that is bound to obj
281285
auto it = std::find_if(sample.instances.begin(), sample.instances.end(),
282-
[&](const auto &inst) { return inst.GetObj() == obj; });
286+
[&](const auto &inst) { return inst.target == target; });
283287
if (it != sample.instances.end()) return it;
284288
}
285289

@@ -299,7 +303,7 @@ void C4SoundSystem::GetVolumeByPos(C4Section &section, std::int32_t x, std::int3
299303
}
300304

301305
auto C4SoundSystem::NewInstance(const char *filename, const bool loop,
302-
const std::int32_t volume, const std::int32_t pan, C4Object *const obj,
306+
const std::int32_t volume, const std::int32_t pan, const TargetVariant target,
303307
const std::int32_t falloffDistance) -> Instance *
304308
{
305309
if (!Application.AudioSystem) return nullptr;
@@ -340,15 +344,13 @@ auto C4SoundSystem::NewInstance(const char *filename, const bool loop,
340344
if (!loop && sample->instances.size() >= MaxSoundInstances) return nullptr;
341345

342346
// Already playing near?
343-
const auto nearIt = obj ?
344-
std::find_if(sample->instances.cbegin(), sample->instances.cend(),
345-
[&](const auto &inst) { return inst.IsNear(*obj); }) :
346-
std::find_if(sample->instances.cbegin(), sample->instances.cend(),
347-
[](const auto &inst) { return !inst.GetObj(); });
347+
const auto nearIt = std::holds_alternative<C4Object *>(target)
348+
? std::find_if(sample->instances.cbegin(), sample->instances.cend(), [&](const auto &inst) { return inst.IsNear(*std::get<C4Object *>(target)); })
349+
: std::find_if(sample->instances.cbegin(), sample->instances.cend(), [&](const auto &inst) { return inst.target == target; });
348350
if (nearIt != sample->instances.cend()) return nullptr;
349351

350352
// Create instance
351-
auto &inst = sample->instances.emplace_back(*sample, loop, volume, obj, falloffDistance);
353+
auto &inst = sample->instances.emplace_back(*sample, loop, volume, target, falloffDistance);
352354
if (!inst.Execute(true))
353355
{
354356
sample->instances.pop_back();

src/C4SoundSystem.h

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,27 @@
3131

3232
class C4Section;
3333

34-
bool IsSoundPlaying(const char *name, const C4Object *obj);
35-
void SoundLevel(const char *name, C4Object *obj, std::int32_t iLevel);
36-
bool StartSoundEffect(const char *name, bool loop = false, std::int32_t volume = 100,
37-
C4Object *obj = nullptr, std::int32_t falloffDistance = 0);
38-
void StartSoundEffectAt(const char *name, C4Section &section, std::int32_t x, std::int32_t y);
39-
void StopSoundEffect(const char *name, const C4Object *obj);
40-
4134
class C4SoundSystem
4235
{
36+
public:
37+
struct Position
38+
{
39+
C4Section *const Section;
40+
const int32_t X;
41+
const int32_t Y;
42+
43+
constexpr bool operator==(const Position &other) const = default;
44+
};
45+
46+
struct GlobalSoundMarker
47+
{
48+
constexpr bool operator==(GlobalSoundMarker) const noexcept { return true; }
49+
};
50+
51+
static inline constexpr GlobalSoundMarker GlobalSound{};
52+
53+
using TargetVariant = std::variant<C4Object *, Position, C4Section *, GlobalSoundMarker>;
54+
4355
public:
4456
static constexpr std::int32_t AudibilityRadius = 700;
4557
static constexpr std::int32_t NearSoundRadius = 50;
@@ -81,24 +93,10 @@ class C4SoundSystem
8193

8294
struct Instance
8395
{
84-
struct ObjPos
85-
{
86-
const int32_t x;
87-
const int32_t y;
88-
89-
ObjPos() = delete;
90-
ObjPos(const C4Object &obj) : x{obj.x}, y{obj.y} {}
91-
ObjPos(const ObjPos &) = delete;
92-
ObjPos(ObjPos &&) = delete;
93-
~ObjPos() = default;
94-
ObjPos &operator=(const ObjPos &) = delete;
95-
ObjPos &operator=(ObjPos &&) = delete;
96-
};
97-
9896
Instance(Sample &sample, bool loop, std::int32_t volume,
99-
C4Object *obj, std::int32_t falloffDistance)
97+
TargetVariant target, std::int32_t falloffDistance)
10098
: sample{sample}, loop{loop}, volume{volume},
101-
obj{obj}, falloffDistance{falloffDistance},
99+
target{target}, falloffDistance{falloffDistance},
102100
startTime{std::chrono::steady_clock::now()} {}
103101
Instance(const Instance &) = delete;
104102
Instance(Instance &&) = delete;
@@ -110,7 +108,7 @@ class C4SoundSystem
110108
std::unique_ptr<C4AudioSystem::SoundChannel> channel;
111109
const bool loop;
112110
std::int32_t volume, pan{0};
113-
std::variant<C4Object *, const ObjPos> obj;
111+
TargetVariant target;
114112
const std::int32_t falloffDistance;
115113
const std::chrono::time_point<std::chrono::steady_clock> startTime;
116114

@@ -129,19 +127,26 @@ class C4SoundSystem
129127

130128
// Returns a sound instance that matches the specified name and object.
131129
std::optional<decltype(Sample::instances)::iterator> FindInst(
132-
const char *wildcard, const C4Object *obj);
130+
const char *wildcard, TargetVariant target);
133131
// Returns a reference to the "sound enabled" config entry of the current game mode
134132
static bool &GetCfgSoundEnabled();
135133
static void GetVolumeByPos(C4Section &section, std::int32_t x, std::int32_t y,
136134
std::int32_t &volume, std::int32_t &pan);
137135
Instance *NewInstance(const char *filename, bool loop,
138-
std::int32_t volume, std::int32_t pan, C4Object *obj, std::int32_t falloffDistance);
136+
std::int32_t volume, std::int32_t pan, TargetVariant target, std::int32_t falloffDistance);
139137
// Adds default file extension if missing and replaces "*" with "?"
140138
static std::string PrepareFilename(const char *filename);
141139

142-
friend bool IsSoundPlaying(const char *, const C4Object *);
143-
friend void SoundLevel(const char *, C4Object *, std::int32_t);
144-
friend bool StartSoundEffect(const char *, bool, std::int32_t, C4Object *, std::int32_t);
140+
friend bool IsSoundPlaying(const char *, TargetVariant);
141+
friend void SoundLevel(const char *, TargetVariant, std::int32_t);
142+
friend bool StartSoundEffect(const char *, bool, std::int32_t, C4SoundSystem::TargetVariant, std::int32_t);
145143
friend void StartSoundEffectAt(const char *, C4Section &, std::int32_t, std::int32_t);
146-
friend void StopSoundEffect(const char *, const C4Object *);
144+
friend void StopSoundEffect(const char *, TargetVariant);
147145
};
146+
147+
bool IsSoundPlaying(const char *name, C4SoundSystem::TargetVariant target);
148+
void SoundLevel(const char *name, C4SoundSystem::TargetVariant target, std::int32_t iLevel);
149+
bool StartSoundEffect(const char *name, bool loop = false, std::int32_t volume = 100,
150+
C4SoundSystem::TargetVariant target = C4SoundSystem::GlobalSound, std::int32_t falloffDistance = 0);
151+
void StartSoundEffectAt(const char *name, C4Section &section, std::int32_t x, std::int32_t y);
152+
void StopSoundEffect(const char *name, C4SoundSystem::TargetVariant target);

src/C4StartupOptionsDlg.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ void C4StartupOptionsDlg::OnSoundVolumeSliderChange(int32_t iNewVal)
13651365
// sound system reads this value directly
13661366
Config.Sound.SoundVolume = iNewVal;
13671367
// test sound
1368-
StartSoundEffect("ArrowHit", false, 100, nullptr);
1368+
StartSoundEffect("ArrowHit", false, 100, C4SoundSystem::GlobalSound);
13691369
}
13701370

13711371
bool C4StartupOptionsDlg::KeyMusicToggle()

src/C4Weather.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void C4Weather::Execute()
102102
section.C4S.Weather.Wind.Min,
103103
section.C4S.Weather.Wind.Max);
104104
if (!Tick10)
105-
SoundLevel("Wind", nullptr, (std::max)(Abs(Wind) - 30, 0) * 2);
105+
SoundLevel("Wind", &section, (std::max)(Abs(Wind) - 30, 0) * 2);
106106
// Disaster launch
107107
if (!Tick10)
108108
{

0 commit comments

Comments
 (0)