16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-22 23:19:19 +02:00

model lights state transition toggle, ambient sounds support, departure time based event delay, minor bug fixes

This commit is contained in:
tmj-fstate
2020-08-18 22:19:58 +02:00
parent 82ebe1ab4a
commit 8cc11bcd8d
14 changed files with 226 additions and 122 deletions

View File

@@ -438,7 +438,8 @@ TAnimModel::is_keyword( std::string const &Token ) const {
return ( Token == "endmodel" )
|| ( Token == "lights" )
|| ( Token == "lightcolors" )
|| ( Token == "angles" );
|| ( Token == "angles" )
|| ( Token == "notransition" );
}
bool TAnimModel::Load(cParser *parser, bool ter)
@@ -529,6 +530,10 @@ bool TAnimModel::Load(cParser *parser, bool ter)
>> vAngle[ 2 ];
}
if( token == "notransition" ) {
m_transition = false;
}
} while( ( false == token.empty() )
&& ( token != "endmodel" ) );
@@ -589,6 +594,13 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
auto &timer { m_lighttimers[ idx ] };
if( ( modeintegral < ls_Blink ) && ( modefractional < 0.01f ) ) {
// simple flip modes
auto const transitiontime { (
m_transition ?
std::min(
1.f,
std::min( fOnTime, fOffTime ) * 0.9f ) :
0.01f ) };
switch( mode ) {
case ls_Off: {
// reduce to zero
@@ -597,14 +609,14 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
}
case ls_On: {
// increase to max value
timer = std::min<float>( fTransitionTime, timer + timedelta );
timer = std::min<float>( transitiontime, timer + timedelta );
break;
}
default: {
break;
}
}
opacity = timer / fTransitionTime;
opacity = timer / transitiontime;
}
else {
// blink modes
@@ -618,10 +630,12 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) {
( mode == ls_Off ) ? ontime :
( mode == ls_On ) ? ( fOnTime + fOffTime ) - ontime :
fOffTime ) }; // fallback
auto const transitiontime {
std::min(
1.f,
std::min( ontime, offtime ) * 0.9f ) };
auto const transitiontime { (
m_transition ?
std::min(
1.f,
std::min( ontime, offtime ) * 0.9f ) :
0.01f ) };
timer = clamp_circular<float>( timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime );
// set opacity depending on blink stage
@@ -958,6 +972,10 @@ TAnimModel::export_as_text_( std::ostream &Output ) const {
Output << lsLights[ lightidx ] << ' ';
}
}
// potential light transition switch
if( false == m_transition ) {
Output << "notransition" << ' ';
}
// footer
Output
<< "endmodel"

View File

@@ -198,7 +198,8 @@ private:
std::array<float, iMaxNumLights> m_lightopacities; // {1} in constructor
float fOnTime { 1.f / 2 };// { 60.f / 45.f / 2 };
float fOffTime { 1.f / 2 };// { 60.f / 45.f / 2 }; // były stałymi, teraz mogą być zmienne dla każdego egzemplarza
float fTransitionTime { fOnTime * 0.9f }; // time
// float fTransitionTime { fOnTime * 0.9f }; // time
bool m_transition { true }; // smooth transition between light states
unsigned int m_framestamp { 0 }; // id of last rendered gfx frame
};

View File

@@ -190,7 +190,7 @@ void TCamera::Update()
auto movement { Velocity * -2.0 };
movement.y = -movement.y;
if( ( m_owner->ctOwner )
&& ( m_owner->ctOwner->Vehicle()->MoverParameters->CabOccupied < 0 ) ) {
&& ( m_owner->ctOwner->Vehicle()->DirectionGet() != m_owner->DirectionGet() ) ) {
movement *= -1.f;
movement.y = -movement.y;
}

View File

@@ -1909,24 +1909,24 @@ void TController::Activation()
mvOccupied->CabOccupied = mvOccupied->CabActive; // użytkownik moze zmienić CabOccupied wychodząc
mvOccupied->CabDeactivisation(); // tak jest w Train.cpp
// przejście AI na drugą stronę EN57, ET41 itp.
while (TestFlag(d->MoverParameters->Couplers[iDirection < 0 ? end::rear : end::front].CouplingFlag, coupling::control))
{ // jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego
d = iDirection * d->DirectionGet() < 0 ? d->Next() :
d->Prev(); // przechodzimy do następnego członu
if (d)
{
{
int movedirection { ( iDirection < 0 ? end::rear : end::front ) };
d = pVehicle->FirstFind( movedirection, coupling::control );
if( pVehicle != d ) {
drugi = d->Mechanik; // zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie dwóch zamienić miejscami
d->Mechanik = this; // na razie bilokacja
d->MoverParameters->SetInternalCommand("", 0, 0); // usunięcie ewentualnie zalegającej komendy (Change_direction?)
if (d->DirectionGet() != pVehicle->DirectionGet()) // jeśli są przeciwne do siebie
iDirection = -iDirection; // to będziemy jechać w drugą stronę względem zasiedzianego pojazdu
if( d->DirectionGet() != pVehicle->DirectionGet() ) {
// jeśli są przeciwne do siebie to będziemy jechać w drugą stronę względem zasiedzianego pojazdu
iDirection = -iDirection;
}
pVehicle->Mechanik = drugi; // wsadzamy tego, co ewentualnie był (podwójna trakcja)
/*
pVehicle->MoverParameters->CabActive = 0; // wyłączanie kabin po drodze
pVehicle->MoverParameters->CabOccupied = 0; // i zaznaczenie, że nie ma tam nikogo
*/
pVehicle = d; // a mechu ma nowy pojazd (no, człon)
}
else
break; // jak koniec składu, to mechanik dalej nie idzie
}
if (pVehicle != old)
{ // jeśli zmieniony został pojazd prowadzony
@@ -2371,7 +2371,7 @@ bool TController::CheckVehicles(TOrders user)
( ( mvControlling->EngineType == TEngineType::DieselElectric )
|| ( mvControlling->EngineType == TEngineType::DieselEngine ) ) ? ( Global.AirTemperature < 10 ) :
true );
}
}
}
else { // gdy człowiek i gdy nastąpiło połącznie albo rozłączenie
// Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja o składzie
@@ -3197,7 +3197,7 @@ bool TController::DecBrakeEIM()
{
case 0: {
if( mvOccupied->MED_amax != 9.81 ) {
auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * AccDesired / mvOccupied->MED_amax, 0.0, 1.0 ) };
auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * std::max( 0.0, AccDesired ) / mvOccupied->MED_amax, 0.0, 1.0 ) };
OK = ( brakeposition != mvOccupied->LocalBrakePosA );
mvOccupied->LocalBrakePosA = brakeposition;
}

View File

@@ -4298,7 +4298,7 @@ void TDynamicObject::RenderSounds() {
// NBMX sygnal odjazdu
if( MoverParameters->Doors.has_warning ) {
auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable };
for( auto &speaker : m_speakers ) {
for( auto &doorspeaker : m_doorspeakers ) {
// TBD, TODO: per-location door state triggers?
if( ( MoverParameters->DepartureSignal )
&& ( lowvoltagepower )
@@ -4310,30 +4310,31 @@ void TDynamicObject::RenderSounds() {
) {
// for the autonomous doors play the warning automatically whenever a door is closing
// MC: pod warunkiem ze jest zdefiniowane w chk
speaker.departure_signal.play( sound_flags::exclusive | sound_flags::looping );
doorspeaker.departure_signal.play( sound_flags::exclusive | sound_flags::looping );
}
else {
speaker.departure_signal.stop();
doorspeaker.departure_signal.stop();
}
}
}
// announcements
for( auto &speaker : m_speakers ) {
{
auto const lowvoltagepower { MoverParameters->Power24vIsAvailable || MoverParameters->Power110vIsAvailable };
if( lowvoltagepower ) {
// speaker is powered up, can play queued announcements
if( speaker.announcement.is_playing() ) { continue; }
if( speaker.announcement_queue.empty() ) { continue; }
// pull first sound from the queue
speaker.announcement = speaker.announcement_queue.front();
speaker.announcement.owner( this );
speaker.announcement.offset( speaker.offset );
speaker.announcement.play();
speaker.announcement_queue.pop_front();
// system is powered up, can play queued announcements
if( ( false == m_pasystem.announcement_queue.empty() )
&& ( false == m_pasystem.announcement.is_playing() ) ) {
// pull first sound from the queue
m_pasystem.announcement = m_pasystem.announcement_queue.front();
m_pasystem.announcement.owner( this );
m_pasystem.announcement.range( 0.5 * MoverParameters->Dim.L * -1 );
m_pasystem.announcement.play();
m_pasystem.announcement_queue.pop_front();
}
}
else {
speaker.announcement.stop();
speaker.announcement_queue.clear();
m_pasystem.announcement.stop();
m_pasystem.announcement_queue.clear();
}
}
// NBMX Obsluga drzwi, MC: zuniwersalnione
@@ -5708,7 +5709,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
sound_source soundtemplate { sound_placement::general, 25.f };
soundtemplate.deserialize( parser, sound_type::multipart, sound_parameters::range );
soundtemplate.owner( this );
for( auto &speaker : m_speakers ) {
for( auto &speaker : m_doorspeakers ) {
speaker.departure_signal = soundtemplate;
speaker.departure_signal.offset( speaker.offset );
}
@@ -5787,11 +5788,13 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
}
else if( token == "unloading:" ) {
m_exchangesounds.unloading.range( MoverParameters->Dim.L * 0.5f * -1 );
m_exchangesounds.unloading.deserialize( parser, sound_type::single );
m_exchangesounds.unloading.owner( this );
}
else if( token == "loading:" ) {
m_exchangesounds.loading.range( MoverParameters->Dim.L * 0.5f * -1 );
m_exchangesounds.loading.deserialize( parser, sound_type::single );
m_exchangesounds.loading.owner( this );
}
@@ -5878,10 +5881,10 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
if( announcementtype == announcement_t::idle ) {
continue;
}
sound_source soundtemplate { sound_placement::general, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE };
sound_source soundtemplate { sound_placement::engine }; // NOTE: sound range gets filled by pa system
soundtemplate.deserialize( announcementsound, sound_type::single );
soundtemplate.owner( this );
m_announcements[ static_cast<int>( announcementtype ) ] = soundtemplate;
m_pasystem.announcements[ static_cast<int>( announcementtype ) ] = soundtemplate;
}
}
}
@@ -5933,10 +5936,9 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
door.step_open.offset( location );
m_doorsounds.emplace_back( door );
}
m_speakers.emplace_back(
speaker_sounds {
m_doorspeakers.emplace_back(
doorspeaker_sounds {
{ 0.f, 3.f, offset },
{},
{} } );
}
}
@@ -7053,7 +7055,7 @@ material_handle TDynamicObject::DestinationFind( std::string Destination ) {
void TDynamicObject::announce( announcement_t const Announcement, bool const Chime ) {
if( m_speakers.empty() ) { return; }
if( m_doorspeakers.empty() ) { return; }
auto const *driver { (
ctOwner != nullptr ?
@@ -7062,9 +7064,10 @@ void TDynamicObject::announce( announcement_t const Announcement, bool const Chi
if( driver == nullptr ) { return; }
auto const &timetable { driver->TrainTimetable() };
auto const &announcements { m_pasystem.announcements };
auto playchime { Chime };
if( m_announcements[ static_cast<int>( Announcement ) ].empty() ) {
if( announcements[ static_cast<int>( Announcement ) ].empty() ) {
goto followup;
}
// if the announcement sound was defined queue playback
@@ -7093,17 +7096,13 @@ void TDynamicObject::announce( announcement_t const Announcement, bool const Chi
}
// potentially precede the announcement with a chime...
if( ( true == playchime )
&& ( false == m_announcements[ static_cast<int>( announcement_t::chime ) ].empty() ) ) {
for( auto &speaker : m_speakers ) {
speaker.announcement_queue.emplace_back( m_announcements[ static_cast<int>( announcement_t::chime ) ] );
}
&& ( false == announcements[ static_cast<int>( announcement_t::chime ) ].empty() ) ) {
m_pasystem.announcement_queue.emplace_back( announcements[ static_cast<int>( announcement_t::chime ) ] );
playchime = false;
}
// ...then play the announcement itself
for( auto &speaker : m_speakers ) {
speaker.announcement_queue.emplace_back( m_announcements[ static_cast<int>( Announcement ) ] );
speaker.announcement_queue.emplace_back( stopnamesound );
}
m_pasystem.announcement_queue.emplace_back( announcements[ static_cast<int>( Announcement ) ] );
m_pasystem.announcement_queue.emplace_back( stopnamesound );
}
followup:
// potentially follow up with another announcement

View File

@@ -406,9 +406,13 @@ private:
void render( TMoverParameters const &Vehicle, double const Deltatime );
};
// single source per door (pair) on the centreline
struct speaker_sounds {
struct doorspeaker_sounds {
glm::vec3 offset;
sound_source departure_signal;
};
// single source per vehicle
struct pasystem_sounds {
std::array<sound_source, static_cast<int>( announcement_t::end )> announcements;
sound_source announcement;
std::deque<sound_source> announcement_queue; // fifo queue
};
@@ -509,8 +513,8 @@ private:
exchange_data m_exchange; // state of active load exchange procedure, if any
exchange_sounds m_exchangesounds; // sounds associated with the load exchange
std::vector<speaker_sounds> m_speakers;
std::array<sound_source, static_cast<int>( announcement_t::end )> m_announcements;
std::vector<doorspeaker_sounds> m_doorspeakers;
pasystem_sounds m_pasystem;
coupleradapter_data m_coupleradapter;

View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "Event.h"
#include "simulation.h"
#include "simulationtime.h"
#include "messaging.h"
#include "Globals.h"
#include "MemCell.h"
@@ -307,6 +308,10 @@ basic_event::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) {
Input.getTokens();
Input >> m_delayrandom; // Ra 2014-03-11
}
if( token == "departuredelay" ) { // timetable-based delay
Input.getTokens();
Input >> m_delaydeparture;
}
Input.getTokens();
}
}
@@ -363,6 +368,11 @@ basic_event::export_as_text( std::ostream &Output ) const {
<< "randomdelay "
<< m_delayrandom << ' ';
}
if( false == std::isnan( m_delayrandom ) ) {
Output
<< "departuredelay "
<< m_delaydeparture << ' ';
}
// footer
Output
<< "endevent"
@@ -428,9 +438,10 @@ basic_event::input_location() const {
bool
basic_event::is_keyword( std::string const &Token ) {
// TODO: convert to array lookup if keyword list gets longer
return ( Token == "endevent" )
|| ( Token == "randomdelay" );
|| ( Token == "randomdelay" )
|| ( Token == "departuredelay" );
}
@@ -2289,11 +2300,25 @@ event_manager::AddToQuery( basic_event *Event, TDynamicObject const *Owner ) {
// standardowe dodanie do kolejki
++(Event->m_inqueue); // zabezpieczenie przed podwójnym dodaniem do kolejki
WriteLog( "EVENT ADDED TO QUEUE" + ( Owner ? ( " by " + Owner->asName ) : "" ) + ": " + Event->m_name );
Event->m_launchtime = std::abs( Event->m_delay ) + Timer::GetTime(); // czas od uruchomienia scenerii
Event->m_launchtime = Timer::GetTime() + std::abs( Event->m_delay ); // czas od uruchomienia scenerii
if( Event->m_delayrandom > 0.0 ) {
// doliczenie losowego czasu opóźnienia
Event->m_launchtime += Event->m_delayrandom * Random();
}
if( ( Owner != nullptr )
&& ( false == std::isnan( Event->m_delaydeparture ) ) ) {
auto const *timetableowner { (
( ( Owner->Mechanik != nullptr ) && ( Owner->Mechanik->primary() ) ) ?
Owner->Mechanik :
Owner->ctOwner ) };
if( timetableowner != nullptr ) {
auto const &timetable { timetableowner->TrainTimetable() };
auto const &time { simulation::Time.data() };
Event->m_launchtime +=
timetable.seconds_until_departure( time.wHour, time.wMinute + time.wSecond * 0.0167 )
+ Event->m_delaydeparture;
}
}
if( QueryRootEvent != nullptr ) {
basic_event *target { QueryRootEvent };
basic_event *previous { nullptr };

View File

@@ -91,6 +91,7 @@ public:
double m_launchtime { 0.0 };
double m_delay { 0.0 };
double m_delayrandom { 0.0 }; // zakres dodatkowego opóźnienia // standardowo nie będzie dodatkowego losowego opóźnienia
double m_delaydeparture { std::numeric_limits<double>::quiet_NaN() }; // departure-based event delay
protected:
// types

View File

@@ -6025,7 +6025,9 @@ bool TTrain::Update( double const Deltatime )
}
}
// helper variables
m_doors = ( DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] );
if( DynamicObject->Mechanik != nullptr ) {
m_doors = ( DynamicObject->Mechanik->IsAnyDoorOpen[ side::right ] || DynamicObject->Mechanik->IsAnyDoorOpen[ side::left ] );
}
m_dirforward = ( mvControlled->DirActive > 0 );
m_dirneutral = ( mvControlled->DirActive == 0 );
m_dirbackward = ( mvControlled->DirActive <0 );
@@ -6991,9 +6993,9 @@ bool TTrain::Update( double const Deltatime )
}
ggLocalBrake.Update();
}
ggDirForwardButton.Update();
ggDirNeutralButton.Update();
ggDirBackwardButton.Update();
ggDirForwardButton.Update( lowvoltagepower );
ggDirNeutralButton.Update( lowvoltagepower );
ggDirBackwardButton.Update( lowvoltagepower );
ggAlarmChain.Update();
ggBrakeProfileCtrl.Update();
ggBrakeProfileG.Update();
@@ -7001,8 +7003,8 @@ bool TTrain::Update( double const Deltatime )
ggBrakeOperationModeCtrl.Update();
ggMaxCurrentCtrl.Update();
// NBMX wrzesien 2003 - drzwi
ggDoorLeftPermitButton.Update();
ggDoorRightPermitButton.Update();
ggDoorLeftPermitButton.Update( lowvoltagepower );
ggDoorRightPermitButton.Update( lowvoltagepower );
ggDoorPermitPresetButton.Update();
ggDoorLeftButton.Update();
ggDoorRightButton.Update();
@@ -7011,7 +7013,7 @@ bool TTrain::Update( double const Deltatime )
ggDoorLeftOffButton.Update();
ggDoorRightOffButton.Update();
ggDoorAllOnButton.Update();
ggDoorAllOffButton.Update();
ggDoorAllOffButton.Update( lowvoltagepower );
ggDoorSignallingButton.Update();
// NBMX dzwignia sprezarki
ggCompressorButton.Update();
@@ -7534,6 +7536,7 @@ void TTrain::update_sounds_radio() {
for( auto &message : m_radiomessages ) {
auto const volume {
( true == radioenabled )
&& ( Dynamic()->Mechanik != nullptr )
&& ( message.first == RadioChannel() ) ?
Global.RadioVolume :
0.0 };
@@ -8125,24 +8128,13 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
Math3D::vector3 TTrain::MirrorPosition(bool lewe)
{ // zwraca współrzędne widoku kamery z lusterka
switch (iCabn)
{
case 2: // tylna (-1)
return DynamicObject->mMatrix *
Math3D::vector3(
mvOccupied->Dim.W * ( lewe ? -0.5 : 0.5 ) + 0.2 * ( lewe ? -1 : 1 ),
1.5 + Cabine[iCabn].CabPos1.y,
Cabine[iCabn].CabPos1.z);
case 1: // przednia (1)
[[fallthrough]];
default:
return DynamicObject->mMatrix *
Math3D::vector3(
mvOccupied->Dim.W * ( lewe ? 0.5 : -0.5 ) + 0.2 * ( lewe ? 1 : -1 ),
1.5 + Cabine[iCabn].CabPos1.y,
Cabine[iCabn].CabPos2.z);
}
// return DynamicObject->GetPosition(); // współrzędne środka pojazdu
auto const shiftdirection { ( lewe ? -1 : 1 ) * ( iCabn == 2 ? 1 : -1 ) };
return DynamicObject->mMatrix
* Math3D::vector3(
mvOccupied->Dim.W * ( 0.5 * shiftdirection ) + ( 0.2 * shiftdirection ),
1.5 + Cabine[iCabn].CabPos1.y,
interpolate( Cabine[ iCabn ].CabPos1.z , Cabine[ iCabn ].CabPos2.z, 0.5 ) );
};
void TTrain::DynamicSet(TDynamicObject *d)
@@ -8337,6 +8329,7 @@ TTrain::radio_message( sound_source *Message, int const Channel ) {
auto const radioenabled { ( true == mvOccupied->Radio ) && ( mvOccupied->Power24vIsAvailable || mvOccupied->Power110vIsAvailable ) };
auto const volume {
( true == radioenabled )
&& ( Dynamic()->Mechanik != nullptr )
&& ( Channel == RadioChannel() ) ?
1.0 :
0.0 };

View File

@@ -135,8 +135,9 @@ openal_source::sync_with( sound_properties const &State ) {
// location
properties.location = State.location;
sound_distance = properties.location - glm::dvec3 { Global.pCamera.Pos };
if( sound_range > 0 ) {
// range cutoff check
if( sound_range != -1 ) {
// range cutoff check for songs other than 'unlimited'
// NOTE: since we're comparing squared distances we can ignore that sound range can be negative
auto const cutoffrange = (
is_multipart ?
EU07_SOUND_CUTOFFRANGE : // we keep multi-part sounds around longer, to minimize restarts as the sounds get out and back in range
@@ -151,7 +152,7 @@ openal_source::sync_with( sound_properties const &State ) {
::alSourcefv( id, AL_POSITION, glm::value_ptr( sound_distance ) );
}
else {
// sounds with 'unlimited' range are positioned on top of the listener
// sounds with 'unlimited' or negative range are positioned on top of the listener
::alSourcefv( id, AL_POSITION, glm::value_ptr( glm::vec3() ) );
}
// gain
@@ -168,7 +169,7 @@ openal_source::sync_with( sound_properties const &State ) {
5 ) }; // range of -1 means sound of unlimited range, positioned at the listener
::alSourcef( id, AL_REFERENCE_DISTANCE, range * ( 1.f / 16.f ) * properties.soundproofing );
}
if( sound_range > 0 ) {
if( sound_range != -1 ) {
auto const rangesquared { sound_range * sound_range };
auto const distancesquared { glm::length2( sound_distance ) };
if( ( distancesquared > rangesquared )
@@ -428,7 +429,7 @@ openal_renderer::fetch_source() {
continue;
}
auto const sourceweight { (
source->sound_range > 0 ?
source->sound_range != -1 ?
( source->sound_range * source->sound_range ) / ( glm::length2( source->sound_distance ) + 1 ) :
std::numeric_limits<float>::max() ) };
if( sourceweight < leastimportantweight ) {

View File

@@ -45,7 +45,7 @@ std::string TTrainParameters::NextStop() const
sound_source
TTrainParameters::next_stop_sound() const {
if( StationIndex > StationCount ) {
return { sound_placement::general };
return { sound_placement::engine };
}
for( auto stationidx { StationIndex }; stationidx < StationCount + 1; ++stationidx ) {
auto &station{ TimeTable[ stationidx ] };
@@ -56,7 +56,7 @@ TTrainParameters::next_stop_sound() const {
return station.name_sound;
}
// shouldn't normally get here, unless the timetable is malformed
return { sound_placement::general };
return { sound_placement::engine };
}
sound_source
@@ -98,7 +98,7 @@ sound_source TTrainParameters::current_stop_sound() const {
if( ( StationIndex <= StationCount ) )
return TimeTable[ StationIndex ].name_sound;
else
return { sound_placement::general };
return { sound_placement::engine };
}
bool TTrainParameters::UpdateMTable( scenario_time const &Time, std::string const &NewName ) {
@@ -181,6 +181,15 @@ bool TTrainParameters::IsTimeToGo(double hh, double mm)
return false; // dalej nie jechać
}
// returns: difference between specified time and scheduled departure from current stop, in seconds
double TTrainParameters::seconds_until_departure( double const Hour, double const Minute ) const {
if( ( TimeTable[ StationIndex ].Ah < 0 ) ) { // passthrough
return 0;
}
return ( 60.0 * CompareTime( Hour, Minute, TimeTable[ StationIndex ].Dh, TimeTable[ StationIndex ].Dm ) );
}
std::string TTrainParameters::ShowRelation() const
/*zwraca informację o relacji*/
{
@@ -595,7 +604,7 @@ TTrainParameters::load_sounds() {
}
// wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
station.name_sound =
sound_source{ sound_placement::general, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE }
sound_source{ sound_placement::engine, EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE }
.deserialize( lookup.first + lookup.second, sound_type::single );
}
}

View File

@@ -39,7 +39,7 @@ struct TMTableLine
float tm{ 0.f }; // czas jazdy do tej stacji w min. (z kolumny)
bool is_maintenance{ false };
int radio_channel{ -1 };
sound_source name_sound{ sound_placement::internal };
sound_source name_sound{ sound_placement::engine };
};
typedef TMTableLine TMTable[MaxTTableSize + 1];
@@ -73,6 +73,8 @@ class TTrainParameters
bool IsLastStop() const;
bool IsMaintenance() const;
bool IsTimeToGo(double hh, double mm);
// returns: difference between specified time and scheduled departure from current stop, in seconds
double seconds_until_departure( double const Hour, double const Minute ) const;
bool UpdateMTable(double hh, double mm, std::string const &NewName);
bool UpdateMTable( scenario_time const &Time, std::string const &NewName );
bool RewindTimeTable( std::string actualStationName );

105
sound.cpp
View File

@@ -341,8 +341,8 @@ sound_source::play( int const Flags ) {
// NOTE: we cache the flags early, even if the sound is out of range, to mark activated event sounds
m_flags = Flags;
if( m_range > 0 ) {
auto const cutoffrange { m_range * 5 };
if( m_range != -1 ) {
auto const cutoffrange { std::abs( m_range * 5 ) };
if( glm::length2( location() - glm::dvec3 { Global.pCamera.Pos } ) > std::min( 2750.f * 2750.f, cutoffrange * cutoffrange ) ) {
// while we drop sounds from beyond sensible and/or audible range
// we act as if it was activated normally, meaning no need to include the opening bookend in subsequent calls
@@ -887,6 +887,12 @@ sound_source::location() const {
+ m_owner->VectorFront() * m_offset.z };
}
void
sound_source::range( float const Range ) {
m_range = Range;
}
// returns defined range of the sound
float const
sound_source::range() const {
@@ -920,24 +926,31 @@ sound_source::update_location() {
m_properties.location = location();
}
float const EU07_SOUNDPROOFING_STRONG { 0.5f }; // 0.25 after squaring
float const EU07_SOUNDPROOFING_SOME { 0.8f }; // ~0.65 after squaring
float const EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG { 0.01f };
float const EU07_SOUNDPROOFING_GLOBAL_STRONG { std::sqrtf( 0.025 ) };
float const EU07_SOUNDPROOFING_GLOBAL_SOME { std::sqrtf( 0.15 ) };
float const EU07_SOUNDPROOFING_GLOBAL_NONE { std::sqrtf( 0.40 ) };
float const EU07_SOUNDPROOFING_STRONG { std::sqrtf( 0.20 ) };
float const EU07_SOUNDPROOFING_SOME { std::sqrtf( 0.65 ) };
float const EU07_SOUNDPROOFING_NONE { 1.f };
bool
sound_source::update_soundproofing() {
// NOTE, HACK: current cab id can vary from -1 to +1, and we use another higher priority value for open cab window
// NOTE, HACK: current cab id can vary from -1 to +1, and we use higher priority values for open cab window and external views
// we use this as modifier to force re-calculations when moving between compartments or changing window state
int const occupiedcab = (
Global.CabWindowOpen ? 2 :
FreeFlyModeFlag ? 0 :
FreeFlyModeFlag ? (
Global.pCamera.m_owner ?
3 :
0 ) :
( simulation::Train ?
simulation::Train->Occupied()->CabOccupied :
0 ) );
// location-based gain factor:
std::uintptr_t soundproofingstamp = reinterpret_cast<std::uintptr_t>( (
FreeFlyModeFlag ?
nullptr :
Global.pCamera.m_owner :
( simulation::Train ?
simulation::Train->Dynamic() :
nullptr ) ) )
@@ -948,36 +961,72 @@ sound_source::update_soundproofing() {
// listener location has changed, calculate new location-based gain factor
switch( m_placement ) {
case sound_placement::general: {
m_properties.soundproofing = EU07_SOUNDPROOFING_NONE;
m_properties.soundproofing = (
m_range >= -1 ?
EU07_SOUNDPROOFING_NONE :
EU07_SOUNDPROOFING_GLOBAL_NONE );
break;
}
case sound_placement::external: {
m_properties.soundproofing = (
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
EU07_SOUNDPROOFING_NONE : // listener outside or has a window open
EU07_SOUNDPROOFING_STRONG ); // listener in a vehicle with windows shut
if( m_range >= -1 ) { // limited range sound...
m_properties.soundproofing = (
( soundproofingstamp == 0 ? EU07_SOUNDPROOFING_NONE : // ...and listener outside
true == Global.CabWindowOpen ? EU07_SOUNDPROOFING_SOME : // ...and window open
EU07_SOUNDPROOFING_STRONG ) ); // ...and window closed
}
else { // global sound...
auto const externalcamera { ( Global.CabWindowOpen ) || ( Global.pCamera.m_owner && FreeFlyModeFlag ) };
m_properties.soundproofing = (
( soundproofingstamp == 0 ? EU07_SOUNDPROOFING_GLOBAL_NONE : // ...and listener outside
externalcamera ? EU07_SOUNDPROOFING_GLOBAL_STRONG : // ...and window open
EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG ) ); // ...and window closed
}
break;
}
case sound_placement::internal: {
m_properties.soundproofing = (
soundproofingstamp == 0 ?
EU07_SOUNDPROOFING_STRONG : // listener outside HACK: won't be true if active vehicle has open window
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_STRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment
EU07_SOUNDPROOFING_NONE ) ) ); // listener in the cab of the same vehicle
if( m_range >= -1 ) {
m_properties.soundproofing = (
soundproofingstamp == 0 ?
EU07_SOUNDPROOFING_STRONG : // listener outside HACK: won't be true if active vehicle has open window
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_STRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_STRONG : // listener in the engine compartment
EU07_SOUNDPROOFING_NONE ) ) ); // listener in the cab of the same vehicle
}
else {
m_properties.soundproofing = (
soundproofingstamp == 0 ?
EU07_SOUNDPROOFING_GLOBAL_STRONG : // listener outside HACK: won't be true if active vehicle has open window
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_GLOBAL_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_GLOBAL_STRONG ) ) ); // listener in the cab of the same vehicle
}
break;
}
case sound_placement::engine: {
m_properties.soundproofing = (
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
EU07_SOUNDPROOFING_SOME : // listener outside or has a window open
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_STRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_STRONG ) ) ); // listener in another compartment of the same vehicle
if( m_range >= -1 ) {
m_properties.soundproofing = (
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
EU07_SOUNDPROOFING_SOME : // listener outside or has a window open
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_STRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_STRONG ) ) ); // listener in another compartment of the same vehicle
}
else {
m_properties.soundproofing = (
( ( soundproofingstamp == 0 ) || ( true == Global.CabWindowOpen ) ) ?
EU07_SOUNDPROOFING_GLOBAL_STRONG : // listener outside or has a window open
( simulation::Train->Dynamic() != m_owner ?
EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG : // in another vehicle
( occupiedcab == 0 ?
EU07_SOUNDPROOFING_NONE : // listener in the engine compartment
EU07_SOUNDPROOFING_GLOBAL_STRONG ) ) ); // listener in another compartment of the same vehicle
}
break;
}
default: {

View File

@@ -15,7 +15,7 @@ http://mozilla.org/MPL/2.0/.
float const EU07_SOUND_GLOBALRANGE { -1.f };
float const EU07_SOUND_CABCONTROLSCUTOFFRANGE { 7.5f };
float const EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE{ 30.f };
float const EU07_SOUND_CABANNOUNCEMENTCUTOFFRANGE{ -10.f };
float const EU07_SOUND_BRAKINGCUTOFFRANGE { 100.f };
float const EU07_SOUND_RUNNINGNOISECUTOFFRANGE { 200.f };
float const EU07_SOUND_HANDHELDRADIORANGE { 3500.f };
@@ -122,6 +122,8 @@ public:
glm::dvec3 const
location() const;
// returns defined range of the sound
void
range( float const Range );
float const
range() const;