mirror of https://github.com/OpenRCT2/OpenRCT2.git
Move vehicle sounds update into Ui library (#21577)
* Move vehicle sounds update into Ui library * Add missing statics * Apply review comments * Sprinkle some const * Clang format accumulate
This commit is contained in:
parent
3f81a491b0
commit
5a70fd97fb
|
@ -10,6 +10,7 @@
|
|||
#include "WindowManager.h"
|
||||
|
||||
#include "interface/Theme.h"
|
||||
#include "ride/VehicleSounds.h"
|
||||
#include "windows/Window.h"
|
||||
|
||||
#include <openrct2-ui/input/InputManager.h>
|
||||
|
@ -510,6 +511,10 @@ public:
|
|||
WindowInvalidateByClass(WindowClass::Research);
|
||||
break;
|
||||
|
||||
case INTENT_ACTION_UPDATE_VEHICLE_SOUNDS:
|
||||
OpenRCT2::Audio::UpdateVehicleSounds();
|
||||
break;
|
||||
|
||||
case INTENT_ACTION_TRACK_DESIGN_REMOVE_PROVISIONAL:
|
||||
TrackPlaceClearProvisionalTemporarily();
|
||||
break;
|
||||
|
|
|
@ -832,3 +832,31 @@ ScreenCoordsXY WindowGetViewportSoundIconPos(WindowBase& w)
|
|||
const uint8_t buttonOffset = (gConfigInterface.WindowButtonsOnTheLeft) ? CloseButtonWidth + 2 : 0;
|
||||
return w.windowPos + ScreenCoordsXY{ 2 + buttonOffset, 2 };
|
||||
}
|
||||
|
||||
namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
WindowBase* WindowGetListening()
|
||||
{
|
||||
for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
|
||||
{
|
||||
auto& w = **it;
|
||||
if (w.flags & WF_DEAD)
|
||||
continue;
|
||||
|
||||
auto viewport = w.viewport;
|
||||
if (viewport != nullptr)
|
||||
{
|
||||
if (viewport->flags & VIEWPORT_FLAG_SOUND_ON)
|
||||
{
|
||||
return &w;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WindowClass WindowGetClassification(const WindowBase& window)
|
||||
{
|
||||
return window.classification;
|
||||
}
|
||||
} // namespace OpenRCT2::Ui::Windows
|
||||
|
|
|
@ -70,4 +70,7 @@ namespace OpenRCT2::Ui::Windows
|
|||
void WindowTileInspectorKeyboardShortcutToggleInvisibility();
|
||||
|
||||
extern const StringId ColourSchemeNames[4];
|
||||
|
||||
WindowBase* WindowGetListening();
|
||||
WindowClass WindowGetClassification(const WindowBase& window);
|
||||
} // namespace OpenRCT2::Ui::Windows
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
<ClInclude Include="interface\Widget.h" />
|
||||
<ClInclude Include="interface\Window.h" />
|
||||
<ClInclude Include="ride\Construction.h" />
|
||||
<ClInclude Include="ride\VehicleSounds.h" />
|
||||
<ClInclude Include="scripting\CustomImages.h" />
|
||||
<ClInclude Include="scripting\CustomListView.h" />
|
||||
<ClInclude Include="scripting\CustomMenu.h" />
|
||||
|
@ -133,6 +134,7 @@
|
|||
<ClCompile Include="interface\Widget.cpp" />
|
||||
<ClCompile Include="interface\Window.cpp" />
|
||||
<ClCompile Include="ride\Construction.cpp" />
|
||||
<ClCompile Include="ride\VehicleSounds.cpp" />
|
||||
<ClCompile Include="scripting\CustomImages.cpp" />
|
||||
<ClCompile Include="scripting\CustomListView.cpp" />
|
||||
<ClCompile Include="scripting\CustomMenu.cpp" />
|
||||
|
|
|
@ -0,0 +1,605 @@
|
|||
#include "VehicleSounds.h"
|
||||
|
||||
#include "../interface/Viewport.h"
|
||||
#include "../interface/Window.h"
|
||||
|
||||
#include <numeric>
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/GameState.h>
|
||||
#include <openrct2/OpenRCT2.h>
|
||||
#include <openrct2/audio/AudioChannel.h>
|
||||
#include <openrct2/audio/AudioMixer.h>
|
||||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/core/FixedVector.h>
|
||||
#include <openrct2/entity/EntityRegistry.h>
|
||||
#include <openrct2/profiling/Profiling.h>
|
||||
#include <openrct2/ride/TrainManager.h>
|
||||
#include <openrct2/ride/Vehicle.h>
|
||||
|
||||
namespace OpenRCT2::Audio
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template<typename T> class TrainIterator;
|
||||
template<typename T> class Train
|
||||
{
|
||||
public:
|
||||
explicit Train(T* vehicle)
|
||||
: FirstCar(vehicle)
|
||||
{
|
||||
assert(FirstCar->IsHead());
|
||||
}
|
||||
int32_t GetMass() const;
|
||||
|
||||
friend class TrainIterator<T>;
|
||||
using iterator = TrainIterator<T>;
|
||||
iterator begin() const
|
||||
{
|
||||
return iterator{ FirstCar };
|
||||
}
|
||||
iterator end() const
|
||||
{
|
||||
return iterator{};
|
||||
}
|
||||
|
||||
private:
|
||||
T* FirstCar;
|
||||
};
|
||||
template<typename T> class TrainIterator
|
||||
{
|
||||
public:
|
||||
using iterator = TrainIterator;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
|
||||
TrainIterator() = default;
|
||||
explicit TrainIterator(T* vehicle)
|
||||
: Current(vehicle)
|
||||
{
|
||||
}
|
||||
reference operator*() const
|
||||
{
|
||||
return *Current;
|
||||
}
|
||||
iterator& operator++()
|
||||
{
|
||||
Current = GetEntity<Vehicle>(NextVehicleId);
|
||||
if (Current != nullptr)
|
||||
{
|
||||
NextVehicleId = Current->next_vehicle_on_train;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
bool operator!=(const iterator& other) const
|
||||
{
|
||||
return Current != other.Current;
|
||||
}
|
||||
|
||||
private:
|
||||
T* Current = nullptr;
|
||||
EntityId NextVehicleId = EntityId::GetNull();
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template<typename T> int32_t Train<T>::GetMass() const
|
||||
{
|
||||
return std::accumulate(
|
||||
begin(), end(), 0, [](int32_t totalMass, const Vehicle& vehicle) { return totalMass + vehicle.mass; });
|
||||
}
|
||||
|
||||
static bool SoundCanPlay(const Vehicle& vehicle)
|
||||
{
|
||||
if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
|
||||
return false;
|
||||
|
||||
if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && GetGameState().EditorStep != EditorStep::RollercoasterDesigner)
|
||||
return false;
|
||||
|
||||
if (vehicle.sound1_id == SoundId::Null && vehicle.sound2_id == SoundId::Null)
|
||||
return false;
|
||||
|
||||
if (vehicle.x == LOCATION_NULL)
|
||||
return false;
|
||||
|
||||
if (g_music_tracking_viewport == nullptr)
|
||||
return false;
|
||||
|
||||
const auto quarter_w = g_music_tracking_viewport->view_width / 4;
|
||||
const auto quarter_h = g_music_tracking_viewport->view_height / 4;
|
||||
|
||||
auto left = g_music_tracking_viewport->viewPos.x;
|
||||
auto bottom = g_music_tracking_viewport->viewPos.y;
|
||||
|
||||
if (Ui::Windows::WindowGetClassification(*gWindowAudioExclusive) == WindowClass::MainWindow)
|
||||
{
|
||||
left -= quarter_w;
|
||||
bottom -= quarter_h;
|
||||
}
|
||||
|
||||
if (left >= vehicle.SpriteData.SpriteRect.GetRight() || bottom >= vehicle.SpriteData.SpriteRect.GetBottom())
|
||||
return false;
|
||||
|
||||
auto right = g_music_tracking_viewport->view_width + left;
|
||||
auto top = g_music_tracking_viewport->view_height + bottom;
|
||||
|
||||
if (Ui::Windows::WindowGetClassification(*gWindowAudioExclusive) == WindowClass::MainWindow)
|
||||
{
|
||||
right += quarter_w + quarter_w;
|
||||
top += quarter_h + quarter_h;
|
||||
}
|
||||
|
||||
if (right < vehicle.SpriteData.SpriteRect.GetRight() || top < vehicle.SpriteData.SpriteRect.GetTop())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006BC2F3
|
||||
*/
|
||||
static uint16_t GetSoundPriority(const Vehicle& vehicle)
|
||||
{
|
||||
int32_t result = Train(&vehicle).GetMass() + (std::abs(vehicle.velocity) >> 13);
|
||||
|
||||
for (const auto& vehicleSound : gVehicleSoundList)
|
||||
{
|
||||
if (vehicleSound.id == vehicle.Id.ToUnderlying())
|
||||
{
|
||||
// Vehicle sounds will get higher priority if they are already playing
|
||||
return result + 300;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static VehicleSoundParams CreateSoundParam(const Vehicle& vehicle, uint16_t priority)
|
||||
{
|
||||
VehicleSoundParams param;
|
||||
param.priority = priority;
|
||||
int32_t panX = (vehicle.SpriteData.SpriteRect.GetLeft() / 2) + (vehicle.SpriteData.SpriteRect.GetRight() / 2)
|
||||
- g_music_tracking_viewport->viewPos.x;
|
||||
panX = g_music_tracking_viewport->zoom.ApplyInversedTo(panX);
|
||||
panX += g_music_tracking_viewport->pos.x;
|
||||
|
||||
uint16_t screenWidth = ContextGetWidth();
|
||||
if (screenWidth < 64)
|
||||
{
|
||||
screenWidth = 64;
|
||||
}
|
||||
param.pan_x = ((((panX * 65536) / screenWidth) - 0x8000) >> 4);
|
||||
|
||||
int32_t panY = (vehicle.SpriteData.SpriteRect.GetTop() / 2) + (vehicle.SpriteData.SpriteRect.GetBottom() / 2)
|
||||
- g_music_tracking_viewport->viewPos.y;
|
||||
panY = g_music_tracking_viewport->zoom.ApplyInversedTo(panY);
|
||||
panY += g_music_tracking_viewport->pos.y;
|
||||
|
||||
uint16_t screenHeight = ContextGetHeight();
|
||||
if (screenHeight < 64)
|
||||
{
|
||||
screenHeight = 64;
|
||||
}
|
||||
param.pan_y = ((((panY * 65536) / screenHeight) - 0x8000) >> 4);
|
||||
|
||||
int32_t frequency = std::abs(vehicle.velocity);
|
||||
|
||||
const auto* rideType = vehicle.GetRideEntry();
|
||||
if (rideType != nullptr)
|
||||
{
|
||||
if (rideType->Cars[vehicle.vehicle_type].double_sound_frequency & 1)
|
||||
{
|
||||
frequency *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// * 0.0105133...
|
||||
frequency >>= 5; // /32
|
||||
frequency *= 5512;
|
||||
frequency >>= 14; // /16384
|
||||
|
||||
frequency += 11025;
|
||||
frequency += 16 * vehicle.sound_vector_factor;
|
||||
param.frequency = static_cast<uint16_t>(frequency);
|
||||
param.id = vehicle.Id.ToUnderlying();
|
||||
param.volume = 0;
|
||||
|
||||
if (vehicle.x != LOCATION_NULL)
|
||||
{
|
||||
auto surfaceElement = MapGetSurfaceElementAt(CoordsXY{ vehicle.x, vehicle.y });
|
||||
|
||||
// vehicle underground
|
||||
if (surfaceElement != nullptr && surfaceElement->GetBaseZ() > vehicle.z)
|
||||
{
|
||||
param.volume = 0x30;
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006BB9FF
|
||||
*/
|
||||
static void UpdateSoundParams(
|
||||
const Vehicle& vehicle, FixedVector<VehicleSoundParams, MaxVehicleSounds>& vehicleSoundParamsList)
|
||||
{
|
||||
if (!SoundCanPlay(vehicle))
|
||||
return;
|
||||
|
||||
uint16_t soundPriority = GetSoundPriority(vehicle);
|
||||
// Find a sound param of lower priority to use
|
||||
auto soundParamIter = std::find_if(
|
||||
vehicleSoundParamsList.begin(), vehicleSoundParamsList.end(),
|
||||
[soundPriority](const auto& param) { return soundPriority > param.priority; });
|
||||
|
||||
if (soundParamIter == std::end(vehicleSoundParamsList))
|
||||
{
|
||||
if (vehicleSoundParamsList.size() < MaxVehicleSounds)
|
||||
{
|
||||
vehicleSoundParamsList.push_back(CreateSoundParam(vehicle, soundPriority));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vehicleSoundParamsList.size() < MaxVehicleSounds)
|
||||
{
|
||||
// Shift all sound params down one if using a free space
|
||||
vehicleSoundParamsList.insert(soundParamIter, CreateSoundParam(vehicle, soundPriority));
|
||||
}
|
||||
else
|
||||
{
|
||||
*soundParamIter = CreateSoundParam(vehicle, soundPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void VehicleSoundsUpdateWindowSetup()
|
||||
{
|
||||
g_music_tracking_viewport = nullptr;
|
||||
|
||||
WindowBase* window = Ui::Windows::WindowGetListening();
|
||||
if (window == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Viewport* viewport = WindowGetViewport(window);
|
||||
if (viewport == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_music_tracking_viewport = viewport;
|
||||
gWindowAudioExclusive = window;
|
||||
if (viewport->zoom <= ZoomLevel{ 0 })
|
||||
gVolumeAdjustZoom = 0;
|
||||
else if (viewport->zoom == ZoomLevel{ 1 })
|
||||
gVolumeAdjustZoom = 35;
|
||||
else
|
||||
gVolumeAdjustZoom = 70;
|
||||
}
|
||||
|
||||
static uint8_t VehicleSoundsUpdateGetPanVolume(VehicleSoundParams* sound_params)
|
||||
{
|
||||
uint8_t vol1 = 0xFF;
|
||||
uint8_t vol2 = 0xFF;
|
||||
|
||||
int16_t pan_y = std::abs(sound_params->pan_y);
|
||||
pan_y = std::min(static_cast<int16_t>(0xFFF), pan_y);
|
||||
pan_y -= 0x800;
|
||||
if (pan_y > 0)
|
||||
{
|
||||
pan_y = (0x400 - pan_y) / 4;
|
||||
vol1 = LoByte(pan_y);
|
||||
if (static_cast<int8_t>(HiByte(pan_y)) != 0)
|
||||
{
|
||||
vol1 = 0xFF;
|
||||
if (static_cast<int8_t>(HiByte(pan_y)) < 0)
|
||||
{
|
||||
vol1 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t pan_x = std::abs(sound_params->pan_x);
|
||||
pan_x = std::min(static_cast<int16_t>(0xFFF), pan_x);
|
||||
pan_x -= 0x800;
|
||||
|
||||
if (pan_x > 0)
|
||||
{
|
||||
pan_x = (0x400 - pan_x) / 4;
|
||||
vol2 = LoByte(pan_x);
|
||||
if (static_cast<int8_t>(HiByte(pan_x)) != 0)
|
||||
{
|
||||
vol2 = 0xFF;
|
||||
if (static_cast<int8_t>(HiByte(pan_x)) < 0)
|
||||
{
|
||||
vol2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vol1 = std::min(vol1, vol2);
|
||||
return std::max(0, vol1 - gVolumeAdjustZoom);
|
||||
}
|
||||
|
||||
/* Returns the vehicle sound for a sound_param.
|
||||
*
|
||||
* If already playing returns sound.
|
||||
* If not playing allocates a sound slot to sound_param->id.
|
||||
* If no free slots returns nullptr.
|
||||
*/
|
||||
static VehicleSound* VehicleSoundsUpdateGetVehicleSound(VehicleSoundParams* sound_params)
|
||||
{
|
||||
// Search for already playing vehicle sound
|
||||
for (auto& vehicleSound : gVehicleSoundList)
|
||||
{
|
||||
if (vehicleSound.id == sound_params->id)
|
||||
return &vehicleSound;
|
||||
}
|
||||
|
||||
// No sound already playing
|
||||
for (auto& vehicleSound : gVehicleSoundList)
|
||||
{
|
||||
// Use free slot
|
||||
if (vehicleSound.id == SoundIdNull)
|
||||
{
|
||||
vehicleSound.id = sound_params->id;
|
||||
vehicleSound.TrackSound.Id = SoundId::Null;
|
||||
vehicleSound.OtherSound.Id = SoundId::Null;
|
||||
vehicleSound.volume = 0x30;
|
||||
return &vehicleSound;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool IsLoopingSound(SoundId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SoundId::LiftClassic:
|
||||
case SoundId::TrackFrictionClassicWood:
|
||||
case SoundId::FrictionClassic:
|
||||
case SoundId::LiftFrictionWheels:
|
||||
case SoundId::GoKartEngine:
|
||||
case SoundId::TrackFrictionTrain:
|
||||
case SoundId::TrackFrictionWater:
|
||||
case SoundId::LiftArrow:
|
||||
case SoundId::LiftWood:
|
||||
case SoundId::TrackFrictionWood:
|
||||
case SoundId::LiftWildMouse:
|
||||
case SoundId::LiftBM:
|
||||
case SoundId::TrackFrictionBM:
|
||||
case SoundId::LiftRMC:
|
||||
case SoundId::TrackFrictionRMC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsFixedFrequencySound(SoundId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SoundId::Scream1:
|
||||
case SoundId::Scream2:
|
||||
case SoundId::Scream3:
|
||||
case SoundId::Scream4:
|
||||
case SoundId::Scream5:
|
||||
case SoundId::Scream6:
|
||||
case SoundId::Scream7:
|
||||
case SoundId::Scream8:
|
||||
case SoundId::TrainWhistle:
|
||||
case SoundId::TrainDeparting:
|
||||
case SoundId::Tram:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSpecialFrequencySound(SoundId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SoundId::TrackFrictionBM:
|
||||
case SoundId::TrackFrictionRMC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum class SoundType
|
||||
{
|
||||
TrackNoises,
|
||||
OtherNoises, // e.g. Screams
|
||||
};
|
||||
|
||||
template<SoundType type> static uint16_t SoundFrequency(const SoundId id, uint16_t baseFrequency)
|
||||
{
|
||||
if constexpr (type == SoundType::TrackNoises)
|
||||
{
|
||||
if (IsSpecialFrequencySound(id))
|
||||
{
|
||||
return (baseFrequency / 2) + 4000;
|
||||
}
|
||||
return baseFrequency;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsFixedFrequencySound(id))
|
||||
{
|
||||
return 22050;
|
||||
}
|
||||
return std::min((baseFrequency * 2) - 3248, 25700);
|
||||
}
|
||||
}
|
||||
|
||||
template<SoundType type> static bool ShouldUpdateChannelRate(const SoundId id)
|
||||
{
|
||||
return type == SoundType::TrackNoises || !IsFixedFrequencySound(id);
|
||||
}
|
||||
|
||||
template<SoundType type>
|
||||
static void UpdateSound(const SoundId id, int32_t volume, VehicleSoundParams* sound_params, Sound& sound, uint8_t panVol)
|
||||
{
|
||||
volume *= panVol;
|
||||
volume = volume / 8;
|
||||
volume = std::max(volume - 0x1FFF, -10000);
|
||||
|
||||
if (sound.Channel != nullptr && sound.Channel->IsDone())
|
||||
{
|
||||
sound.Id = SoundId::Null;
|
||||
sound.Channel = nullptr;
|
||||
}
|
||||
if (id != sound.Id && sound.Id != SoundId::Null)
|
||||
{
|
||||
sound.Id = SoundId::Null;
|
||||
sound.Channel->Stop();
|
||||
}
|
||||
if (id == SoundId::Null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sound.Id == SoundId::Null)
|
||||
{
|
||||
auto frequency = SoundFrequency<type>(id, sound_params->frequency);
|
||||
auto looping = IsLoopingSound(id);
|
||||
auto pan = sound_params->pan_x;
|
||||
auto channel = CreateAudioChannel(
|
||||
id, looping, DStoMixerVolume(volume), DStoMixerPan(pan), DStoMixerRate(frequency), false);
|
||||
if (channel != nullptr)
|
||||
{
|
||||
sound.Id = id;
|
||||
sound.Pan = sound_params->pan_x;
|
||||
sound.Volume = volume;
|
||||
sound.Frequency = sound_params->frequency;
|
||||
sound.Channel = channel;
|
||||
}
|
||||
else
|
||||
{
|
||||
sound.Id = SoundId::Null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (volume != sound.Volume)
|
||||
{
|
||||
sound.Volume = volume;
|
||||
sound.Channel->SetVolume(DStoMixerVolume(volume));
|
||||
}
|
||||
if (sound_params->pan_x != sound.Pan)
|
||||
{
|
||||
sound.Pan = sound_params->pan_x;
|
||||
sound.Channel->SetPan(DStoMixerPan(sound_params->pan_x));
|
||||
}
|
||||
if (!(GetGameState().CurrentTicks & 3) && sound_params->frequency != sound.Frequency)
|
||||
{
|
||||
sound.Frequency = sound_params->frequency;
|
||||
if (ShouldUpdateChannelRate<type>(id))
|
||||
{
|
||||
uint16_t frequency = SoundFrequency<type>(id, sound_params->frequency);
|
||||
sound.Channel->SetRate(DStoMixerRate(frequency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006BBC6B
|
||||
*/
|
||||
void UpdateVehicleSounds()
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
|
||||
if (!IsAvailable())
|
||||
return;
|
||||
|
||||
FixedVector<VehicleSoundParams, MaxVehicleSounds> vehicleSoundParamsList;
|
||||
|
||||
VehicleSoundsUpdateWindowSetup();
|
||||
|
||||
for (auto vehicle : TrainManager::View())
|
||||
{
|
||||
UpdateSoundParams(*vehicle, vehicleSoundParamsList);
|
||||
}
|
||||
|
||||
// Stop all playing sounds that no longer have priority to play after vehicle_update_sound_params
|
||||
for (auto& vehicleSound : gVehicleSoundList)
|
||||
{
|
||||
if (vehicleSound.id != SoundIdNull)
|
||||
{
|
||||
bool keepPlaying = false;
|
||||
for (auto vehicleSoundParams : vehicleSoundParamsList)
|
||||
{
|
||||
if (vehicleSound.id == vehicleSoundParams.id)
|
||||
{
|
||||
keepPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keepPlaying)
|
||||
continue;
|
||||
|
||||
if (vehicleSound.TrackSound.Id != SoundId::Null)
|
||||
{
|
||||
vehicleSound.TrackSound.Channel->Stop();
|
||||
}
|
||||
if (vehicleSound.OtherSound.Id != SoundId::Null)
|
||||
{
|
||||
vehicleSound.OtherSound.Channel->Stop();
|
||||
}
|
||||
vehicleSound.id = SoundIdNull;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& vehicleSoundParams : vehicleSoundParamsList)
|
||||
{
|
||||
uint8_t panVol = VehicleSoundsUpdateGetPanVolume(&vehicleSoundParams);
|
||||
|
||||
auto* vehicleSound = VehicleSoundsUpdateGetVehicleSound(&vehicleSoundParams);
|
||||
// No free vehicle sound slots (RCT2 corrupts the pointer here)
|
||||
if (vehicleSound == nullptr)
|
||||
continue;
|
||||
|
||||
// Move the Sound Volume towards the SoundsParam Volume
|
||||
int32_t tempvolume = vehicleSound->volume;
|
||||
if (tempvolume != vehicleSoundParams.volume)
|
||||
{
|
||||
if (tempvolume < vehicleSoundParams.volume)
|
||||
{
|
||||
tempvolume += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempvolume -= 4;
|
||||
}
|
||||
}
|
||||
vehicleSound->volume = tempvolume;
|
||||
panVol = std::max(0, panVol - tempvolume);
|
||||
|
||||
Vehicle* vehicle = GetEntity<Vehicle>(EntityId::FromUnderlying(vehicleSoundParams.id));
|
||||
if (vehicle != nullptr)
|
||||
{
|
||||
UpdateSound<SoundType::TrackNoises>(
|
||||
vehicle->sound1_id, vehicle->sound1_volume, &vehicleSoundParams, vehicleSound->TrackSound, panVol);
|
||||
UpdateSound<SoundType::OtherNoises>(
|
||||
vehicle->sound2_id, vehicle->sound2_volume, &vehicleSoundParams, vehicleSound->OtherSound, panVol);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace OpenRCT2::Audio
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
namespace OpenRCT2::Audio
|
||||
{
|
||||
void UpdateVehicleSounds();
|
||||
}
|
|
@ -1841,31 +1841,6 @@ Viewport* WindowGetViewport(WindowBase* w)
|
|||
return w->viewport;
|
||||
}
|
||||
|
||||
WindowBase* WindowGetListening()
|
||||
{
|
||||
for (auto it = g_window_list.rbegin(); it != g_window_list.rend(); it++)
|
||||
{
|
||||
auto& w = **it;
|
||||
if (w.flags & WF_DEAD)
|
||||
continue;
|
||||
|
||||
auto viewport = w.viewport;
|
||||
if (viewport != nullptr)
|
||||
{
|
||||
if (viewport->flags & VIEWPORT_FLAG_SOUND_ON)
|
||||
{
|
||||
return &w;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WindowClass WindowGetClassification(const WindowBase& window)
|
||||
{
|
||||
return window.classification;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006EAF26
|
||||
|
|
|
@ -643,6 +643,3 @@ money64 PlaceProvisionalTrackPiece(
|
|||
const CoordsXYZ& trackPos);
|
||||
|
||||
extern RideConstructionState _rideConstructionState2;
|
||||
|
||||
WindowBase* WindowGetListening();
|
||||
WindowClass WindowGetClassification(const WindowBase& window);
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "../scenario/Scenario.h"
|
||||
#include "../scripting/HookEngine.h"
|
||||
#include "../scripting/ScriptEngine.h"
|
||||
#include "../ui/UiContext.h"
|
||||
#include "../ui/WindowManager.h"
|
||||
#include "../util/Util.h"
|
||||
#include "../windows/Intent.h"
|
||||
#include "../world/Map.h"
|
||||
|
@ -577,596 +579,10 @@ Vehicle* TryGetVehicle(EntityId spriteIndex)
|
|||
return TryGetEntity<Vehicle>(spriteIndex);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename T> class TrainIterator;
|
||||
template<typename T> class Train
|
||||
{
|
||||
public:
|
||||
explicit Train(T* vehicle)
|
||||
: FirstCar(vehicle)
|
||||
{
|
||||
assert(FirstCar->IsHead());
|
||||
}
|
||||
int32_t Mass();
|
||||
|
||||
friend class TrainIterator<T>;
|
||||
using iterator = TrainIterator<T>;
|
||||
iterator begin()
|
||||
{
|
||||
return iterator{ FirstCar };
|
||||
}
|
||||
iterator end()
|
||||
{
|
||||
return iterator{};
|
||||
}
|
||||
|
||||
private:
|
||||
T* FirstCar;
|
||||
};
|
||||
template<typename T> class TrainIterator
|
||||
{
|
||||
public:
|
||||
using iterator = TrainIterator;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = T;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
|
||||
TrainIterator() = default;
|
||||
explicit TrainIterator(T* vehicle)
|
||||
: Current(vehicle)
|
||||
{
|
||||
}
|
||||
reference operator*()
|
||||
{
|
||||
return *Current;
|
||||
}
|
||||
iterator& operator++()
|
||||
{
|
||||
Current = GetEntity<Vehicle>(NextVehicleId);
|
||||
if (Current != nullptr)
|
||||
{
|
||||
NextVehicleId = Current->next_vehicle_on_train;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
bool operator!=(const iterator& other)
|
||||
{
|
||||
return Current != other.Current;
|
||||
}
|
||||
|
||||
private:
|
||||
T* Current = nullptr;
|
||||
EntityId NextVehicleId = EntityId::GetNull();
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template<typename T> int32_t Train<T>::Mass()
|
||||
{
|
||||
int32_t totalMass = 0;
|
||||
for (const auto& vehicle : *this)
|
||||
{
|
||||
totalMass += vehicle.mass;
|
||||
}
|
||||
|
||||
return totalMass;
|
||||
}
|
||||
|
||||
bool Vehicle::SoundCanPlay() const
|
||||
{
|
||||
if (gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
|
||||
return false;
|
||||
|
||||
if ((gScreenFlags & SCREEN_FLAGS_TRACK_DESIGNER) && GetGameState().EditorStep != EditorStep::RollercoasterDesigner)
|
||||
return false;
|
||||
|
||||
if (sound1_id == OpenRCT2::Audio::SoundId::Null && sound2_id == OpenRCT2::Audio::SoundId::Null)
|
||||
return false;
|
||||
|
||||
if (x == LOCATION_NULL)
|
||||
return false;
|
||||
|
||||
if (g_music_tracking_viewport == nullptr)
|
||||
return false;
|
||||
|
||||
const auto quarter_w = g_music_tracking_viewport->view_width / 4;
|
||||
const auto quarter_h = g_music_tracking_viewport->view_height / 4;
|
||||
|
||||
auto left = g_music_tracking_viewport->viewPos.x;
|
||||
auto bottom = g_music_tracking_viewport->viewPos.y;
|
||||
|
||||
if (WindowGetClassification(*gWindowAudioExclusive) == WindowClass::MainWindow)
|
||||
{
|
||||
left -= quarter_w;
|
||||
bottom -= quarter_h;
|
||||
}
|
||||
|
||||
if (left >= SpriteData.SpriteRect.GetRight() || bottom >= SpriteData.SpriteRect.GetBottom())
|
||||
return false;
|
||||
|
||||
auto right = g_music_tracking_viewport->view_width + left;
|
||||
auto top = g_music_tracking_viewport->view_height + bottom;
|
||||
|
||||
if (WindowGetClassification(*gWindowAudioExclusive) == WindowClass::MainWindow)
|
||||
{
|
||||
right += quarter_w + quarter_w;
|
||||
top += quarter_h + quarter_h;
|
||||
}
|
||||
|
||||
if (right < SpriteData.SpriteRect.GetRight() || top < SpriteData.SpriteRect.GetTop())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006BC2F3
|
||||
*/
|
||||
uint16_t Vehicle::GetSoundPriority() const
|
||||
{
|
||||
int32_t result = Train(this).Mass() + (std::abs(velocity) >> 13);
|
||||
|
||||
for (const auto& vehicleSound : OpenRCT2::Audio::gVehicleSoundList)
|
||||
{
|
||||
if (vehicleSound.id == Id.ToUnderlying())
|
||||
{
|
||||
// Vehicle sounds will get higher priority if they are already playing
|
||||
return result + 300;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
OpenRCT2::Audio::VehicleSoundParams Vehicle::CreateSoundParam(uint16_t priority) const
|
||||
{
|
||||
OpenRCT2::Audio::VehicleSoundParams param;
|
||||
param.priority = priority;
|
||||
int32_t panX = (SpriteData.SpriteRect.GetLeft() / 2) + (SpriteData.SpriteRect.GetRight() / 2)
|
||||
- g_music_tracking_viewport->viewPos.x;
|
||||
panX = g_music_tracking_viewport->zoom.ApplyInversedTo(panX);
|
||||
panX += g_music_tracking_viewport->pos.x;
|
||||
|
||||
uint16_t screenWidth = ContextGetWidth();
|
||||
if (screenWidth < 64)
|
||||
{
|
||||
screenWidth = 64;
|
||||
}
|
||||
param.pan_x = ((((panX * 65536) / screenWidth) - 0x8000) >> 4);
|
||||
|
||||
int32_t panY = (SpriteData.SpriteRect.GetTop() / 2) + (SpriteData.SpriteRect.GetBottom() / 2)
|
||||
- g_music_tracking_viewport->viewPos.y;
|
||||
panY = g_music_tracking_viewport->zoom.ApplyInversedTo(panY);
|
||||
panY += g_music_tracking_viewport->pos.y;
|
||||
|
||||
uint16_t screenHeight = ContextGetHeight();
|
||||
if (screenHeight < 64)
|
||||
{
|
||||
screenHeight = 64;
|
||||
}
|
||||
param.pan_y = ((((panY * 65536) / screenHeight) - 0x8000) >> 4);
|
||||
|
||||
int32_t frequency = std::abs(velocity);
|
||||
|
||||
const auto* rideType = GetRideEntry();
|
||||
if (rideType != nullptr)
|
||||
{
|
||||
if (rideType->Cars[vehicle_type].double_sound_frequency & 1)
|
||||
{
|
||||
frequency *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// * 0.0105133...
|
||||
frequency >>= 5; // /32
|
||||
frequency *= 5512;
|
||||
frequency >>= 14; // /16384
|
||||
|
||||
frequency += 11025;
|
||||
frequency += 16 * sound_vector_factor;
|
||||
param.frequency = static_cast<uint16_t>(frequency);
|
||||
param.id = Id.ToUnderlying();
|
||||
param.volume = 0;
|
||||
|
||||
if (x != LOCATION_NULL)
|
||||
{
|
||||
auto surfaceElement = MapGetSurfaceElementAt(CoordsXY{ x, y });
|
||||
|
||||
// vehicle underground
|
||||
if (surfaceElement != nullptr && surfaceElement->GetBaseZ() > z)
|
||||
{
|
||||
param.volume = 0x30;
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006BB9FF
|
||||
*/
|
||||
void Vehicle::UpdateSoundParams(std::vector<OpenRCT2::Audio::VehicleSoundParams>& vehicleSoundParamsList) const
|
||||
{
|
||||
if (!SoundCanPlay())
|
||||
return;
|
||||
|
||||
uint16_t soundPriority = GetSoundPriority();
|
||||
// Find a sound param of lower priority to use
|
||||
auto soundParamIter = std::find_if(
|
||||
vehicleSoundParamsList.begin(), vehicleSoundParamsList.end(),
|
||||
[soundPriority](const auto& param) { return soundPriority > param.priority; });
|
||||
|
||||
if (soundParamIter == std::end(vehicleSoundParamsList))
|
||||
{
|
||||
if (vehicleSoundParamsList.size() < OpenRCT2::Audio::MaxVehicleSounds)
|
||||
{
|
||||
vehicleSoundParamsList.push_back(CreateSoundParam(soundPriority));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vehicleSoundParamsList.size() < OpenRCT2::Audio::MaxVehicleSounds)
|
||||
{
|
||||
// Shift all sound params down one if using a free space
|
||||
vehicleSoundParamsList.insert(soundParamIter, CreateSoundParam(soundPriority));
|
||||
}
|
||||
else
|
||||
{
|
||||
*soundParamIter = CreateSoundParam(soundPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vehicle_sounds_update_window_setup()
|
||||
{
|
||||
g_music_tracking_viewport = nullptr;
|
||||
|
||||
WindowBase* window = WindowGetListening();
|
||||
if (window == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Viewport* viewport = WindowGetViewport(window);
|
||||
if (viewport == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
g_music_tracking_viewport = viewport;
|
||||
gWindowAudioExclusive = window;
|
||||
if (viewport->zoom <= ZoomLevel{ 0 })
|
||||
OpenRCT2::Audio::gVolumeAdjustZoom = 0;
|
||||
else if (viewport->zoom == ZoomLevel{ 1 })
|
||||
OpenRCT2::Audio::gVolumeAdjustZoom = 35;
|
||||
else
|
||||
OpenRCT2::Audio::gVolumeAdjustZoom = 70;
|
||||
}
|
||||
|
||||
static uint8_t vehicle_sounds_update_get_pan_volume(OpenRCT2::Audio::VehicleSoundParams* sound_params)
|
||||
{
|
||||
uint8_t vol1 = 0xFF;
|
||||
uint8_t vol2 = 0xFF;
|
||||
|
||||
int16_t pan_y = std::abs(sound_params->pan_y);
|
||||
pan_y = std::min(static_cast<int16_t>(0xFFF), pan_y);
|
||||
pan_y -= 0x800;
|
||||
if (pan_y > 0)
|
||||
{
|
||||
pan_y = (0x400 - pan_y) / 4;
|
||||
vol1 = LoByte(pan_y);
|
||||
if (static_cast<int8_t>(HiByte(pan_y)) != 0)
|
||||
{
|
||||
vol1 = 0xFF;
|
||||
if (static_cast<int8_t>(HiByte(pan_y)) < 0)
|
||||
{
|
||||
vol1 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t pan_x = std::abs(sound_params->pan_x);
|
||||
pan_x = std::min(static_cast<int16_t>(0xFFF), pan_x);
|
||||
pan_x -= 0x800;
|
||||
|
||||
if (pan_x > 0)
|
||||
{
|
||||
pan_x = (0x400 - pan_x) / 4;
|
||||
vol2 = LoByte(pan_x);
|
||||
if (static_cast<int8_t>(HiByte(pan_x)) != 0)
|
||||
{
|
||||
vol2 = 0xFF;
|
||||
if (static_cast<int8_t>(HiByte(pan_x)) < 0)
|
||||
{
|
||||
vol2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vol1 = std::min(vol1, vol2);
|
||||
return std::max(0, vol1 - OpenRCT2::Audio::gVolumeAdjustZoom);
|
||||
}
|
||||
|
||||
/* Returns the vehicle sound for a sound_param.
|
||||
*
|
||||
* If already playing returns sound.
|
||||
* If not playing allocates a sound slot to sound_param->id.
|
||||
* If no free slots returns nullptr.
|
||||
*/
|
||||
static OpenRCT2::Audio::VehicleSound* vehicle_sounds_update_get_vehicle_sound(OpenRCT2::Audio::VehicleSoundParams* sound_params)
|
||||
{
|
||||
// Search for already playing vehicle sound
|
||||
for (auto& vehicleSound : OpenRCT2::Audio::gVehicleSoundList)
|
||||
{
|
||||
if (vehicleSound.id == sound_params->id)
|
||||
return &vehicleSound;
|
||||
}
|
||||
|
||||
// No sound already playing
|
||||
for (auto& vehicleSound : OpenRCT2::Audio::gVehicleSoundList)
|
||||
{
|
||||
// Use free slot
|
||||
if (vehicleSound.id == OpenRCT2::Audio::SoundIdNull)
|
||||
{
|
||||
vehicleSound.id = sound_params->id;
|
||||
vehicleSound.TrackSound.Id = OpenRCT2::Audio::SoundId::Null;
|
||||
vehicleSound.OtherSound.Id = OpenRCT2::Audio::SoundId::Null;
|
||||
vehicleSound.volume = 0x30;
|
||||
return &vehicleSound;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool IsLoopingSound(SoundId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SoundId::LiftClassic:
|
||||
case SoundId::TrackFrictionClassicWood:
|
||||
case SoundId::FrictionClassic:
|
||||
case SoundId::LiftFrictionWheels:
|
||||
case SoundId::GoKartEngine:
|
||||
case SoundId::TrackFrictionTrain:
|
||||
case SoundId::TrackFrictionWater:
|
||||
case SoundId::LiftArrow:
|
||||
case SoundId::LiftWood:
|
||||
case SoundId::TrackFrictionWood:
|
||||
case SoundId::LiftWildMouse:
|
||||
case SoundId::LiftBM:
|
||||
case SoundId::TrackFrictionBM:
|
||||
case SoundId::LiftRMC:
|
||||
case SoundId::TrackFrictionRMC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsFixedFrequencySound(SoundId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SoundId::Scream1:
|
||||
case SoundId::Scream2:
|
||||
case SoundId::Scream3:
|
||||
case SoundId::Scream4:
|
||||
case SoundId::Scream5:
|
||||
case SoundId::Scream6:
|
||||
case SoundId::Scream7:
|
||||
case SoundId::Scream8:
|
||||
case SoundId::TrainWhistle:
|
||||
case SoundId::TrainDeparting:
|
||||
case SoundId::Tram:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSpecialFrequencySound(SoundId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case SoundId::TrackFrictionBM:
|
||||
case SoundId::TrackFrictionRMC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enum class SoundType
|
||||
{
|
||||
TrackNoises,
|
||||
OtherNoises, // e.g. Screams
|
||||
};
|
||||
|
||||
template<SoundType type> static uint16_t SoundFrequency(const OpenRCT2::Audio::SoundId id, uint16_t baseFrequency)
|
||||
{
|
||||
if constexpr (type == SoundType::TrackNoises)
|
||||
{
|
||||
if (IsSpecialFrequencySound(id))
|
||||
{
|
||||
return (baseFrequency / 2) + 4000;
|
||||
}
|
||||
return baseFrequency;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsFixedFrequencySound(id))
|
||||
{
|
||||
return 22050;
|
||||
}
|
||||
return std::min((baseFrequency * 2) - 3248, 25700);
|
||||
}
|
||||
}
|
||||
|
||||
template<SoundType type> static bool ShouldUpdateChannelRate(const OpenRCT2::Audio::SoundId id)
|
||||
{
|
||||
return type == SoundType::TrackNoises || !IsFixedFrequencySound(id);
|
||||
}
|
||||
|
||||
template<SoundType type>
|
||||
static void UpdateSound(
|
||||
const OpenRCT2::Audio::SoundId id, int32_t volume, OpenRCT2::Audio::VehicleSoundParams* sound_params,
|
||||
OpenRCT2::Audio::Sound& sound, uint8_t panVol)
|
||||
{
|
||||
volume *= panVol;
|
||||
volume = volume / 8;
|
||||
volume = std::max(volume - 0x1FFF, -10000);
|
||||
|
||||
if (sound.Channel != nullptr && sound.Channel->IsDone())
|
||||
{
|
||||
sound.Id = OpenRCT2::Audio::SoundId::Null;
|
||||
sound.Channel = nullptr;
|
||||
}
|
||||
if (id != sound.Id && sound.Id != OpenRCT2::Audio::SoundId::Null)
|
||||
{
|
||||
sound.Id = OpenRCT2::Audio::SoundId::Null;
|
||||
sound.Channel->Stop();
|
||||
}
|
||||
if (id == OpenRCT2::Audio::SoundId::Null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sound.Id == OpenRCT2::Audio::SoundId::Null)
|
||||
{
|
||||
auto frequency = SoundFrequency<type>(id, sound_params->frequency);
|
||||
auto looping = IsLoopingSound(id);
|
||||
auto pan = sound_params->pan_x;
|
||||
auto channel = CreateAudioChannel(
|
||||
id, looping, DStoMixerVolume(volume), DStoMixerPan(pan), DStoMixerRate(frequency), false);
|
||||
if (channel != nullptr)
|
||||
{
|
||||
sound.Id = id;
|
||||
sound.Pan = sound_params->pan_x;
|
||||
sound.Volume = volume;
|
||||
sound.Frequency = sound_params->frequency;
|
||||
sound.Channel = channel;
|
||||
}
|
||||
else
|
||||
{
|
||||
sound.Id = OpenRCT2::Audio::SoundId::Null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (volume != sound.Volume)
|
||||
{
|
||||
sound.Volume = volume;
|
||||
sound.Channel->SetVolume(DStoMixerVolume(volume));
|
||||
}
|
||||
if (sound_params->pan_x != sound.Pan)
|
||||
{
|
||||
sound.Pan = sound_params->pan_x;
|
||||
sound.Channel->SetPan(DStoMixerPan(sound_params->pan_x));
|
||||
}
|
||||
if (!(GetGameState().CurrentTicks & 3) && sound_params->frequency != sound.Frequency)
|
||||
{
|
||||
sound.Frequency = sound_params->frequency;
|
||||
if (ShouldUpdateChannelRate<type>(id))
|
||||
{
|
||||
uint16_t frequency = SoundFrequency<type>(id, sound_params->frequency);
|
||||
sound.Channel->SetRate(DStoMixerRate(frequency));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006BBC6B
|
||||
*/
|
||||
void VehicleSoundsUpdate()
|
||||
{
|
||||
PROFILED_FUNCTION();
|
||||
|
||||
if (!OpenRCT2::Audio::IsAvailable())
|
||||
return;
|
||||
|
||||
std::vector<OpenRCT2::Audio::VehicleSoundParams> vehicleSoundParamsList;
|
||||
vehicleSoundParamsList.reserve(OpenRCT2::Audio::MaxVehicleSounds);
|
||||
|
||||
vehicle_sounds_update_window_setup();
|
||||
|
||||
for (auto vehicle : TrainManager::View())
|
||||
{
|
||||
vehicle->UpdateSoundParams(vehicleSoundParamsList);
|
||||
}
|
||||
|
||||
// Stop all playing sounds that no longer have priority to play after vehicle_update_sound_params
|
||||
for (auto& vehicle_sound : OpenRCT2::Audio::gVehicleSoundList)
|
||||
{
|
||||
if (vehicle_sound.id != OpenRCT2::Audio::SoundIdNull)
|
||||
{
|
||||
bool keepPlaying = false;
|
||||
for (auto vehicleSoundParams : vehicleSoundParamsList)
|
||||
{
|
||||
if (vehicle_sound.id == vehicleSoundParams.id)
|
||||
{
|
||||
keepPlaying = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keepPlaying)
|
||||
continue;
|
||||
|
||||
if (vehicle_sound.TrackSound.Id != OpenRCT2::Audio::SoundId::Null)
|
||||
{
|
||||
vehicle_sound.TrackSound.Channel->Stop();
|
||||
}
|
||||
if (vehicle_sound.OtherSound.Id != OpenRCT2::Audio::SoundId::Null)
|
||||
{
|
||||
vehicle_sound.OtherSound.Channel->Stop();
|
||||
}
|
||||
vehicle_sound.id = OpenRCT2::Audio::SoundIdNull;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& vehicleSoundParams : vehicleSoundParamsList)
|
||||
{
|
||||
uint8_t panVol = vehicle_sounds_update_get_pan_volume(&vehicleSoundParams);
|
||||
|
||||
auto* vehicleSound = vehicle_sounds_update_get_vehicle_sound(&vehicleSoundParams);
|
||||
// No free vehicle sound slots (RCT2 corrupts the pointer here)
|
||||
if (vehicleSound == nullptr)
|
||||
continue;
|
||||
|
||||
// Move the Sound Volume towards the SoundsParam Volume
|
||||
int32_t tempvolume = vehicleSound->volume;
|
||||
if (tempvolume != vehicleSoundParams.volume)
|
||||
{
|
||||
if (tempvolume < vehicleSoundParams.volume)
|
||||
{
|
||||
tempvolume += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempvolume -= 4;
|
||||
}
|
||||
}
|
||||
vehicleSound->volume = tempvolume;
|
||||
panVol = std::max(0, panVol - tempvolume);
|
||||
|
||||
Vehicle* vehicle = GetEntity<Vehicle>(EntityId::FromUnderlying(vehicleSoundParams.id));
|
||||
if (vehicle != nullptr)
|
||||
{
|
||||
UpdateSound<SoundType::TrackNoises>(
|
||||
vehicle->sound1_id, vehicle->sound1_volume, &vehicleSoundParams, vehicleSound->TrackSound, panVol);
|
||||
UpdateSound<SoundType::OtherNoises>(
|
||||
vehicle->sound2_id, vehicle->sound2_volume, &vehicleSoundParams, vehicleSound->OtherSound, panVol);
|
||||
}
|
||||
}
|
||||
auto windowManager = OpenRCT2::GetContext()->GetUiContext()->GetWindowManager();
|
||||
windowManager->BroadcastIntent(Intent(INTENT_ACTION_UPDATE_VEHICLE_SOUNDS));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -222,7 +222,6 @@ struct Vehicle : EntityBase
|
|||
Vehicle* GetCar(size_t carIndex) const;
|
||||
void SetState(Vehicle::Status vehicleStatus, uint8_t subState = 0);
|
||||
bool IsGhost() const;
|
||||
void UpdateSoundParams(std::vector<OpenRCT2::Audio::VehicleSoundParams>& vehicleSoundParamsList) const;
|
||||
std::optional<EntityId> DodgemsCarWouldCollideAt(const CoordsXY& coords) const;
|
||||
int32_t UpdateTrackMotion(int32_t* outStation);
|
||||
int32_t CableLiftUpdateTrackMotion();
|
||||
|
@ -281,11 +280,8 @@ struct Vehicle : EntityBase
|
|||
friend void UpdateRotatingEnterprise(Vehicle& vehicle);
|
||||
|
||||
private:
|
||||
bool SoundCanPlay() const;
|
||||
uint16_t GetSoundPriority() const;
|
||||
const VehicleInfo* GetMoveInfo() const;
|
||||
uint16_t GetTrackProgress() const;
|
||||
OpenRCT2::Audio::VehicleSoundParams CreateSoundParam(uint16_t priority) const;
|
||||
void CableLiftUpdate();
|
||||
bool CableLiftUpdateTrackMotionForwards();
|
||||
bool CableLiftUpdateTrackMotionBackwards();
|
||||
|
|
|
@ -43,6 +43,7 @@ enum IntentAction
|
|||
INTENT_ACTION_UPDATE_CASH,
|
||||
INTENT_ACTION_UPDATE_BANNER,
|
||||
INTENT_ACTION_UPDATE_RESEARCH,
|
||||
INTENT_ACTION_UPDATE_VEHICLE_SOUNDS,
|
||||
INTENT_ACTION_TRACK_DESIGN_REMOVE_PROVISIONAL,
|
||||
INTENT_ACTION_TRACK_DESIGN_RESTORE_PROVISIONAL,
|
||||
INTENT_ACTION_SET_MAP_TOOLTIP,
|
||||
|
|
Loading…
Reference in New Issue