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:
@@ -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"
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
24
Driver.cpp
24
Driver.cpp
@@ -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;
|
||||
}
|
||||
|
||||
61
DynObj.cpp
61
DynObj.cpp
@@ -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
|
||||
|
||||
10
DynObj.h
10
DynObj.h
@@ -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;
|
||||
|
||||
|
||||
31
Event.cpp
31
Event.cpp
@@ -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 };
|
||||
|
||||
1
Event.h
1
Event.h
@@ -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
|
||||
|
||||
43
Train.cpp
43
Train.cpp
@@ -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 };
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
17
mtable.cpp
17
mtable.cpp
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
4
mtable.h
4
mtable.h
@@ -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
105
sound.cpp
@@ -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: {
|
||||
|
||||
4
sound.h
4
sound.h
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user