diff --git a/Driver.cpp b/Driver.cpp index 84b661f3..ed05f08e 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2017,9 +2017,7 @@ void TController::Activation() if (initiallocalbrakelevel > 0.0) // hamowanie tylko jeśli był wcześniej zahamowany (bo możliwe, że jedzie!) mvOccupied->LocalBrakePosA = initiallocalbrakelevel; // zahamuj jak wcześniej */ - if( initialspringbrakestate ) { - mvOccupied->SpringBrakeActivate( initialspringbrakestate ); - } + mvOccupied->SpringBrakeActivate( initialspringbrakestate ); CheckVehicles(); // sprawdzenie składu, AI zapali światła TableClear(); // resetowanie tabelki skanowania torów } @@ -2288,11 +2286,15 @@ bool TController::CheckVehicles(TOrders user) if (p->Mechanik != this) // ale chodzi o inny pojazd, niż aktualnie sprawdzający if( p->Mechanik->iDrivigFlags & movePrimary ) { // a tamten ma priorytet + // TODO: take into account drivers' operating modes, one or more of them might be on banking duty if( ( iDrivigFlags & movePrimary ) && ( mvOccupied->DirAbsolute ) && ( mvOccupied->BrakeCtrlPos >= -1 ) ) { // jeśli rządzi i ma kierunek p->Mechanik->primary( false ); // dezaktywuje tamtego + p->Mechanik->ZeroLocalBrake(); + p->MoverParameters->BrakeLevelSet( p->MoverParameters->Handle->GetPos( bh_NP ) ); // odcięcie na zaworze maszynisty + p->Mechanik->BrakeLevelSet( p->MoverParameters->BrakeCtrlPos ); //ustawienie zmiennej GBH } else { main = false; // nici z rządzenia @@ -2441,6 +2443,14 @@ bool TController::CheckVehicles(TOrders user) || ( mvControlling->EngineType == TEngineType::DieselEngine ) ) ? ( Global.AirTemperature < 10 ) : true ); } + + if( ( true == TestFlag( iDrivigFlags, moveConnect ) ) + && ( true == TestFlag( OrderCurrentGet(), Connect ) ) ) { + iCoupler = 0; // dalsza jazda manewrowa już bez łączenia + iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania + SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie + JumpToNextOrder(); // wykonanie następnej komendy + } } 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 @@ -2804,6 +2814,9 @@ bool TController::PrepareEngine() if( lookup != brakepositions.end() ) { BrakeLevelSet( lookup->second ); // GBH } + // sync spring brake state across consist + mvOccupied->SpringBrakeActivate( mvOccupied->SpringBrake.Activate ); + OK = ( false == IsAnyConverterOverloadRelayOpen ) && ( VelforDriver == -1 ); } @@ -3475,17 +3488,28 @@ bool TController::IncSpeed() } break; case TEngineType::ElectricInductionMotor: - if (!IsAnyMotorOverloadRelayOpen) - if (Ready || (iDrivigFlags & movePress) || (mvOccupied->ShuntMode)) //{(BrakePress<=0.01*MaxBrakePress)} + if( !IsAnyMotorOverloadRelayOpen ) { + if( Ready || ( iDrivigFlags & movePress ) || ( mvOccupied->ShuntMode ) ) //{(BrakePress<=0.01*MaxBrakePress)} { OK = IncSpeedEIM(); - // cruise control - auto const SpeedCntrlVel { ( - ( ActualProximityDist > std::max( 50.0, fMaxProximityDist ) ) ? - VelDesired : - min_speed( VelDesired, VelNext ) ) }; - SpeedCntrl(SpeedCntrlVel); + if( ( mvControlling->SpeedCtrl ) && ( mvControlling->Mains ) ) { + // cruise control + auto const couplinginprogress{ ( true == TestFlag( iDrivigFlags, moveConnect ) ) && ( true == TestFlag( OrderCurrentGet(), Connect ) ) }; + auto const SpeedCntrlVel{ ( + ( ActualProximityDist > std::max( 50.0, fMaxProximityDist ) ) || ( couplinginprogress ) ? + VelDesired : + min_speed( VelDesired, VelNext ) ) }; + if( ( SpeedCntrlVel >= mvControlling->SpeedCtrlUnit.MinVelocity ) + && ( SpeedCntrlVel - mvControlling->SpeedCtrlUnit.MinVelocity == quantize( SpeedCntrlVel - mvControlling->SpeedCtrlUnit.MinVelocity, mvControlling->SpeedCtrlUnit.VelocityStep ) ) ) { + SpeedCntrl( SpeedCntrlVel ); + } + else if( SpeedCntrlVel > 0.1 ) { + SpeedCntrl( 0.0 ); + mvControlling->DecScndCtrl( 2 ); + } + } } + } break; case TEngineType::WheelsDriven: if (!mvControlling->CabActive) @@ -3501,16 +3525,19 @@ bool TController::IncSpeed() // mvControlling->ShuntMode=(OrderList[OrderPos]&Shunt)||(fMass>224000.0); } if ((mvControlling->SpeedCtrl)&&(mvControlling->Mains)) {// cruise control - auto const SpeedCntrlVel{ ( - (ActualProximityDist > std::max(50.0, fMaxProximityDist)) ? - VelDesired : - min_speed(VelDesired, VelNext)) }; - if (SpeedCntrlVel >= mvControlling->SpeedCtrlUnit.MinVelocity) { - SpeedCntrl(SpeedCntrlVel); - } - else if (SpeedCntrlVel > 0.1) { - SpeedCntrl(0.0); - } + auto const couplinginprogress { ( true == TestFlag( iDrivigFlags, moveConnect ) ) && ( true == TestFlag( OrderCurrentGet(), Connect ) ) }; + auto const SpeedCntrlVel { ( + ( ActualProximityDist > std::max( 50.0, fMaxProximityDist ) ) || ( couplinginprogress ) ? + VelDesired : + min_speed( VelDesired, VelNext ) ) }; + if( ( SpeedCntrlVel >= mvControlling->SpeedCtrlUnit.MinVelocity ) + && ( SpeedCntrlVel - mvControlling->SpeedCtrlUnit.MinVelocity == quantize( SpeedCntrlVel - mvControlling->SpeedCtrlUnit.MinVelocity, mvControlling->SpeedCtrlUnit.VelocityStep ) ) ) { + SpeedCntrl(SpeedCntrlVel); + } + else if (SpeedCntrlVel > 0.1) { + SpeedCntrl(0.0); + mvControlling->DecScndCtrl( 2 ); + } } if (mvControlling->EIMCtrlType > 0) { if (true == Ready) @@ -3534,6 +3561,7 @@ bool TController::IncSpeed() } if( false == mvControlling->Mains ) { SpeedCntrl(0.0); + mvControlling->DecScndCtrl( 2 ); mvOccupied->MainSwitch( true ); mvOccupied->ConverterSwitch( true ); mvOccupied->CompressorSwitch( true ); @@ -5472,11 +5500,7 @@ TController::UpdateSituation(double dt) { iCoupler ); if( vehicleparameters->Couplers[ end ].CouplingFlag == iCoupler ) { // jeżeli został podłączony - iCoupler = 0; // dalsza jazda manewrowa już bez łączenia - iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania - SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie CheckVehicles( Connect ); // sprawdzić światła nowego składu - JumpToNextOrder(); // wykonanie następnej komendy } } } diff --git a/DynObj.cpp b/DynObj.cpp index 68fba56c..57aaa0a7 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -6316,6 +6316,17 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co >> HuntingShake.fadein_end; } + else if( token == "soundproofing:" ) { + for( auto &soundproofingtable : m_soundproofing ) { + for( auto &soundproofingelement : soundproofingtable ) { + auto const value { parser.getToken( false ) }; + if( value != -1.f ) { + soundproofingelement = std::sqrt( clamp( value, 0.f, 1.f ) ); + } + } + } + } + else if( token == "jointcabs:" ) { parser.getTokens(); parser >> JointCabs; @@ -6809,7 +6820,8 @@ TDynamicObject::update_neighbours() { neighbour.vehicle_end = std::get( lookup ); neighbour.distance = std::get( lookup ); - if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 50 : 100 ) ) { + if( ( neighbour.vehicle ) + && ( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 50 : 100 ) ) ) { // at short distances (re)calculate range between couplers directly neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, neighbour.vehicle->MoverParameters ); // take into account potential adapters attached to the couplers @@ -6858,7 +6870,9 @@ TDynamicObject::find_vehicle( int const Direction, double const Distance ) const // jeśli następny tor jest podpięty od Point2 direction = -direction; // to zmieniamy kierunek szukania na tym torze } - track = track->CurrentNext(); // potem dopiero zmieniamy wskaźnik + if( track ) { + track = track->CurrentNext(); // potem dopiero zmieniamy wskaźnik + } } else { // w kierunku Point1 @@ -6868,7 +6882,9 @@ TDynamicObject::find_vehicle( int const Direction, double const Distance ) const // jeśli poprzedni tor nie jest podpięty od Point2 direction = -direction; // to zmieniamy kierunek szukania na tym torze } - track = track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik + if( track ) { + track = track->CurrentPrev(); // potem dopiero zmieniamy wskaźnik + } } if (track) { // jesli jest kolejny odcinek toru diff --git a/DynObj.h b/DynObj.h index aad7f64b..83c14e4a 100644 --- a/DynObj.h +++ b/DynObj.h @@ -519,6 +519,16 @@ private: std::vector m_doorspeakers; pasystem_sounds m_pasystem; + std::array< + std::array // listener: rear cab, engine, front cab, window, attached camera, free camera + , 5> m_soundproofing = {{ + {{ EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_SOME, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_STRONG }}, // internal sounds + {{ EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_SOME, EU07_SOUNDPROOFING_SOME, EU07_SOUNDPROOFING_SOME }}, // engine sounds + {{ EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_SOME, EU07_SOUNDPROOFING_SOME, EU07_SOUNDPROOFING_NONE }}, // external sound + {{ EU07_SOUNDPROOFING_VERYSTRONG, EU07_SOUNDPROOFING_VERYSTRONG, EU07_SOUNDPROOFING_VERYSTRONG, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_STRONG, EU07_SOUNDPROOFING_NONE }}, // external ambient sound + {{ EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_NONE, EU07_SOUNDPROOFING_NONE }}, // custom sounds + }}; + coupleradapter_data m_coupleradapter; bool renderme; // yB - czy renderowac @@ -730,6 +740,9 @@ private: void move_set(double distance); // playes specified announcement, potentially preceding it with a chime void announce( announcement_t const Announcement, bool const Chime = true ); + // returns soundproofing for specified sound type and listener location + float soundproofing( int const Placement, int const Listener ) const { + return m_soundproofing[ Placement - 1 ][ Listener + 1 ]; } double MED[9][8]; // lista zmiennych do debugowania hamulca ED static std::string const MED_labels[ 8 ]; diff --git a/Event.cpp b/Event.cpp index 8c0d8e34..30acbe10 100644 --- a/Event.cpp +++ b/Event.cpp @@ -524,7 +524,6 @@ updatevalues_event::run_() { + ( ( m_input.flags & flags::text ) ? m_input.data_text : "X" ) + "] [" + ( ( m_input.flags & flags::value1 ) ? to_string( m_input.data_value_1, 2 ) : "X" ) + "] [" + ( ( m_input.flags & flags::value2 ) ? to_string( m_input.data_value_2, 2 ) : "X" ) + "]" ); - // TODO: dump status of target cells after the operation for( auto &target : m_targets ) { auto *targetcell { static_cast( std::get( target ) ) }; if( targetcell == nullptr ) { continue; } @@ -533,13 +532,18 @@ updatevalues_event::run_() { m_input.data_value_1, m_input.data_value_2, m_input.flags ); + WriteLog( " Memcell: " + targetcell->name() + " - " + targetcell->Values() ); +// targetcell->LogValues(); if( targetcell->Track == nullptr ) { continue; } // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla wszystkich 'dynamic' na danym torze auto const location { targetcell->location() }; - for( auto dynamic : targetcell->Track->Dynamics ) { - targetcell->PutCommand( - dynamic->Mechanik, - &location ); + for( auto vehicle : targetcell->Track->Dynamics ) { + if( vehicle->Mechanik ) { + targetcell->PutCommand( + vehicle->Mechanik, + &location ); + WriteLog( " Vehicle: [" + vehicle->name() + "]" ); + } } } @@ -774,8 +778,10 @@ putvalues_event::run_() { m_input.location.z, m_input.location.y }; + std::string vehiclename; if( m_activator->Mechanik ) { // przekazanie rozkazu do AI + vehiclename = m_activator->Mechanik->Vehicle()->name(); m_activator->Mechanik->PutCommand( m_input.data_text, m_input.data_value_1, @@ -787,6 +793,7 @@ putvalues_event::run_() { // send the command to consist owner, // we're acting on presumption there's hardly ever need to issue command to unmanned vehicle // and the intended recipient moved between vehicles after the event was queued + vehiclename = m_activator->ctOwner->Vehicle()->name(); m_activator->ctOwner->PutCommand( m_input.data_text, m_input.data_value_1, @@ -795,12 +802,15 @@ putvalues_event::run_() { } else { // przekazanie do pojazdu + vehiclename = m_activator->name(); m_activator->MoverParameters->PutCommand( m_input.data_text, m_input.data_value_1, m_input.data_value_2, loc ); } + + WriteLog( " Vehicle: [" + vehiclename + "]" ); } // export_as_text() subclass details @@ -930,13 +940,18 @@ copyvalues_event::run_() { m_input.data_value_1, m_input.data_value_2, m_input.flags ); + WriteLog( " Memcell: " + targetcell->name() + " - " + targetcell->Values() ); +// targetcell->LogValues(); if( targetcell->Track == nullptr ) { continue; } // McZapkie-100302 - updatevalues oprocz zmiany wartosci robi putcommand dla wszystkich 'dynamic' na danym torze auto const location { targetcell->location() }; - for( auto dynamic : targetcell->Track->Dynamics ) { - targetcell->PutCommand( - dynamic->Mechanik, - &location ); + for( auto vehicle : targetcell->Track->Dynamics ) { + if( vehicle->Mechanik ) { + targetcell->PutCommand( + vehicle->Mechanik, + &location ); + WriteLog( " Vehicle: [" + vehicle->name() + "]" ); + } } } } @@ -1145,11 +1160,7 @@ logvalues_event::run_() { for( auto &target : m_targets ) { auto *targetcell { static_cast( std::get( target ) ) }; if( targetcell == nullptr ) { continue; } - WriteLog( - "Memcell \"" + targetcell->name() + "\": [" - + targetcell->Text() + "] [" - + to_string( targetcell->Value1(), 2 ) + "] [" - + to_string( targetcell->Value2(), 2 ) + "]" ); + targetcell->LogValues(); } } } diff --git a/Globals.cpp b/Globals.cpp index 2a0d1067..05489d8c 100644 --- a/Globals.cpp +++ b/Globals.cpp @@ -105,6 +105,10 @@ global_settings::ConfigParse(cParser &Parser) { Parser.getTokens(1, false); Parser >> fullscreen_monitor; } + else if( token == "fullscreenwindowed" ) { + Parser.getTokens(); + Parser >> fullscreen_windowed; + } else if( token == "vsync" ) { Parser.getTokens(); @@ -1201,6 +1205,7 @@ global_settings::export_as_text( std::ostream &Output ) const { export_as_text( Output, "basedrawrange", BaseDrawRange ); export_as_text( Output, "fullscreen", bFullScreen ); export_as_text( Output, "fullscreenmonitor", fullscreen_monitor ); + export_as_text( Output, "fullscreenwindowed", fullscreen_windowed ); export_as_text( Output, "vsync", VSync ); // NOTE: values are changed dynamically during simulation. cache initial settings and export instead if( FreeFlyModeFlag ) { diff --git a/Globals.h b/Globals.h index 7a1d3b19..b11d0b85 100644 --- a/Globals.h +++ b/Globals.h @@ -223,8 +223,8 @@ struct global_settings { #endif std::chrono::duration minframetime {0.0f}; - - std::string fullscreen_monitor; + std::string fullscreen_monitor; + bool fullscreen_windowed{ false }; bool python_enabled = true; bool python_mipmaps = true; diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 787c7c0a..6395685b 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1834,13 +1834,17 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime, coupling cons for( auto side = 0; side < 2; ++side ) { auto &coupler { Couplers[ side ] }; - auto const &connectedothercoupler { coupler.Connected->Couplers[ ( coupler.ConnectedNr == end::front ? end::rear : end::front ) ] }; - auto *coupling = ( Coupling == coupling::highvoltage ? &coupler.power_high : Coupling == coupling::power110v ? &coupler.power_110v : Coupling == coupling::power24v ? &coupler.power_24v : nullptr ); + + coupling->current = 0.0; + + if( coupler.Connected == nullptr ) { continue; } + + auto const &connectedothercoupler { coupler.Connected->Couplers[ ( coupler.ConnectedNr == end::front ? end::rear : end::front ) ] }; auto const *connectedothercoupling = ( Coupling == coupling::highvoltage ? &connectedothercoupler.power_high : Coupling == coupling::power110v ? &connectedothercoupler.power_110v : @@ -1850,7 +1854,6 @@ void TMoverParameters::PowerCouplersCheck( double const Deltatime, coupling cons Coupling == coupling::highvoltage ? std::abs( Itot ) * IsVehicleEIMBrakingFactor() : 0.0 ); - coupling->current = 0.0; if( false == localpowersource ) { // bez napiecia... if( couplervoltage != 0.0 ) { @@ -3486,7 +3489,7 @@ bool TMoverParameters::MainSwitchCheck() const { } case TEngineType::ElectricSeriesMotor: case TEngineType::ElectricInductionMotor: { - powerisavailable == ( std::max( GetTrainsetHighVoltage(), PantographVoltage ) > 0.5 * EnginePowerSource.MaxVoltage ); + powerisavailable = ( std::max( GetTrainsetHighVoltage(), PantographVoltage ) > 0.5 * EnginePowerSource.MaxVoltage ); break; } default: { diff --git a/MemCell.cpp b/MemCell.cpp index d8690a84..950f5dee 100644 --- a/MemCell.cpp +++ b/MemCell.cpp @@ -205,6 +205,16 @@ void TMemCell::AssignEvents(basic_event *e) OnSent = e; }; +std::string TMemCell::Values() const { + + return { "[" + Text() + "] [" + to_string( Value1(), 2 ) + "] [" + to_string( Value2(), 2 ) + "]" }; +} + +void TMemCell::LogValues() const { + + WriteLog( "Memcell " + name() + ": " + Values() ); +} + // serialize() subclass details, sends content of the subclass to provided stream void TMemCell::serialize_( std::ostream &Output ) const { @@ -264,10 +274,6 @@ void memory_table::log_all() { for( auto *cell : m_items ) { - - WriteLog( "Memcell \"" + cell->name() + "\": [" - + cell->Text() + "] [" - + to_string( cell->Value1(), 2 ) + "] [" - + to_string( cell->Value2(), 2 ) + "]" ); + cell->LogValues(); } } diff --git a/MemCell.h b/MemCell.h index 3cde311a..e3671bbf 100644 --- a/MemCell.h +++ b/MemCell.h @@ -51,6 +51,8 @@ public: TCommandType CommandCheck(); bool IsVelocity() const; void AssignEvents(basic_event *e); + std::string Values() const; + void LogValues() const; // members std::string asTrackName; // McZapkie-100302 - zeby nazwe toru na ktory jest Putcommand wysylane pamietac TTrack *Track { nullptr }; // resolved binding with the specified track diff --git a/Traction.cpp b/Traction.cpp index 7b54c362..b400f2c8 100644 --- a/Traction.cpp +++ b/Traction.cpp @@ -373,6 +373,8 @@ TTraction::Connect(int my, TTraction *with, int to) { iLast = 0; } + if( with == nullptr ) { return; } + with->hvNext[ to ] = this; with->iNext[ to ] = my; diff --git a/TractionPower.cpp b/TractionPower.cpp index 9e473731..0f76b8b0 100644 --- a/TractionPower.cpp +++ b/TractionPower.cpp @@ -74,7 +74,7 @@ bool TTractionPowerSource::Load(cParser *parser) { bool TTractionPowerSource::Update(double dt) { // powinno być wykonane raz na krok fizyki // iloczyn napięcia i admitancji daje prąd - if (NominalVoltage * TotalPreviousAdmitance > MaxOutputCurrent) { + if (TotalCurrent > MaxOutputCurrent) { FastFuse = true; FuseCounter += 1; diff --git a/Train.cpp b/Train.cpp index a64cdd29..da4d21f4 100644 --- a/Train.cpp +++ b/Train.cpp @@ -5564,10 +5564,10 @@ void TTrain::OnCommand_occupiedcarcouplingdisconnect( TTrain *Train, command_dat if( Train->DynamicObject ) { Train->DynamicObject->uncouple( Train->cab_to_end() ); - } - if( Train->DynamicObject->Mechanik ) { - // aktualizacja flag kierunku w składzie - Train->DynamicObject->Mechanik->CheckVehicles( Disconnect ); + if( Train->DynamicObject->Mechanik ) { + // aktualizacja flag kierunku w składzie + Train->DynamicObject->Mechanik->CheckVehicles( Disconnect ); + } } } else if( Command.action == GLFW_RELEASE ) { @@ -5928,15 +5928,17 @@ void TTrain::OnCommand_vehicleboost(TTrain *Train, const command_data &Command) double boost = Command.param1 != 0.0 ? Command.param1 : 2.78; - TDynamicObject *d = Train->DynamicObject; - while( d ) { - d->MoverParameters->V += d->DirectionGet() * boost; - d = d->Next(); // pozostałe też + if( Train->DynamicObject == nullptr ) { return; } + + auto *vehicle { Train->DynamicObject }; + while( vehicle ) { + vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; + vehicle = vehicle->Next(); // pozostałe też } - d = Train->DynamicObject->Prev(); - while( d ) { - d->MoverParameters->V += d->DirectionGet() * boost; - d = d->Prev(); // w drugą stronę też + vehicle = Train->DynamicObject->Prev(); + while( vehicle ) { + vehicle->MoverParameters->V += vehicle->DirectionGet() * boost; + vehicle = vehicle->Prev(); // w drugą stronę też } } @@ -6480,16 +6482,7 @@ bool TTrain::Update( double const Deltatime ) btLampkaPoslizg.Turn( false ); } - if ((mvControlled->Mains) || (mvControlled->TrainType == dt_EZT)) - { - btLampkaNadmSil.Turn(mvControlled->FuseFlagCheck()); - } - else - { - btLampkaNadmSil.Turn( false ); - } - - if (mvControlled->Battery || mvControlled->ConverterFlag) { + if( true == lowvoltagepower ) { // McZapkie-141102: SHP i czuwak, TODO: sygnalizacja kabinowa if( mvOccupied->SecuritySystem.is_vigilance_blinking() ) { if( fBlinkTimer > fCzuwakBlink ) @@ -6554,6 +6547,11 @@ bool TTrain::Update( double const Deltatime ) false : ( mvControlled->BrakePress < 1.0 ) ); // relay is off and needs a reset + btLampkaNadmSil.Turn( + ( ( false == mvControlled->FuseFlagCheck() ) || ( mvControlled->ControlPressureSwitch ) ) ? + false : + ( mvControlled->BrakePress < 1.0 ) ); // relay is off and needs a reset + if( ( ( mvControlled->CabOccupied == 1 ) && ( TestFlag( mvControlled->Couplers[ end::rear ].CouplingFlag, coupling::control ) ) ) || ( ( mvControlled->CabOccupied == -1 ) && ( TestFlag( mvControlled->Couplers[ end::front ].CouplingFlag, coupling::control ) ) ) ) { btLampkaUkrotnienie.Turn( true ); @@ -7363,10 +7361,15 @@ TTrain::update_sounds( double const Deltatime ) { if( ( false == FreeFlyModeFlag ) && ( false == Global.CabWindowOpen ) && ( Global.Weather == "rain:" ) ) { - m_precipitationsound.play( sound_flags::exclusive | sound_flags::looping ); + if( m_rainsound.is_combined() ) { + m_rainsound.pitch( Global.Overcast - 1.0 ); + } + m_rainsound + .gain( m_rainsound.m_amplitudeoffset + m_rainsound.m_amplitudefactor * 1.f ) + .play( sound_flags::exclusive | sound_flags::looping ); } else { - m_precipitationsound.stop(); + m_rainsound.stop(); } if( fTachoCount >= 3.f ) { @@ -7733,8 +7736,8 @@ bool TTrain::LoadMMediaFile(std::string const &asFileName) } else if( token == "rainsound:" ) { // precipitation sound: - m_precipitationsound.deserialize( parser, sound_type::single ); - m_precipitationsound.owner( DynamicObject ); + m_rainsound.deserialize( parser, sound_type::single ); + m_rainsound.owner( DynamicObject ); } } while (token != ""); @@ -8046,9 +8049,9 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName) { */ // assign default samples to sound emitters which weren't included in the config file - if( m_precipitationsound.empty() ) { - m_precipitationsound.deserialize( "rainsound_default", sound_type::single ); - m_precipitationsound.owner( DynamicObject ); + if( m_rainsound.empty() ) { + m_rainsound.deserialize( "rainsound_default", sound_type::single ); + m_rainsound.owner( DynamicObject ); } // configure placement of sound emitters which aren't bound with any device model, and weren't placed manually // try first to bind sounds to location of possible devices diff --git a/Train.h b/Train.h index 233e6f5a..70b96924 100644 --- a/Train.h +++ b/Train.h @@ -726,7 +726,7 @@ public: // reszta może by?publiczna sound_source rsFadeSound { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; sound_source rsRunningNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE }; sound_source rsHuntingNoise{ sound_placement::internal, EU07_SOUND_GLOBALRANGE }; - sound_source m_precipitationsound { sound_placement::internal, -1 }; + sound_source m_rainsound { sound_placement::internal, -1 }; sound_source dsbHasler { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; sound_source dsbBuzzer { sound_placement::internal, EU07_SOUND_CABCONTROLSCUTOFFRANGE }; diff --git a/application.cpp b/application.cpp index 47415d9c..947f66aa 100644 --- a/application.cpp +++ b/application.cpp @@ -755,8 +755,15 @@ eu07_application::init_glfw() { glfwWindowHint(GLFW_SRGB_CAPABLE, !Global.gfx_shadergamma); + if( Global.fullscreen_windowed ) { + auto const mode = glfwGetVideoMode( monitor ); + Global.iWindowWidth = mode->width; + Global.iWindowHeight = mode->height; + Global.bFullScreen = true; + } + auto *mainwindow = window( - -1, true, Global.iWindowWidth, Global.iWindowHeight, Global.bFullScreen ? monitor : nullptr, true, false ); + -1, true, Global.iWindowWidth, Global.iWindowHeight, ( Global.bFullScreen ? monitor : nullptr ), true, false ); if( mainwindow == nullptr ) { ErrorLog( "Bad init: failed to create glfw window" ); diff --git a/drivermode.cpp b/drivermode.cpp index 67e490fd..5c1699d9 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -562,7 +562,8 @@ driver_mode::update_camera( double const Deltatime ) { // uwzględnienie ruchu wywołanego klawiszami if( false == DebugCameraFlag ) { // regular camera - if( ( false == FreeFlyModeFlag ) + if( ( simulation::Train != nullptr ) + && ( false == FreeFlyModeFlag ) && ( false == Global.CabWindowOpen ) ) { // if in cab potentially alter camera placement based on changes in train object Camera.m_owneroffset = simulation::Train->pMechOffset; @@ -572,12 +573,14 @@ driver_mode::update_camera( double const Deltatime ) { Camera.Update(); - if( false == FreeFlyModeFlag ) { + if( ( simulation::Train != nullptr ) + && ( false == FreeFlyModeFlag ) ) { // keep the camera within cab boundaries Camera.m_owneroffset = simulation::Train->clamp_inside( Camera.m_owneroffset ); } - if( ( false == FreeFlyModeFlag ) + if( ( simulation::Train != nullptr ) + && ( false == FreeFlyModeFlag ) && ( false == Global.CabWindowOpen ) ) { // cache cab camera in case of view type switch simulation::Train->pMechViewAngle = { Camera.Angle.x, Camera.Angle.y }; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index bf10837c..1ccab536 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -1171,7 +1171,7 @@ debug_panel::update_section_powergrid( std::vector &Output ) { auto const lowpowercolor { glm::vec4( 164.0f / 255.0f, 132.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; auto const nopowercolor { glm::vec4( 164.0f / 255.0f, 84.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; - Output.emplace_back( "Name: Output: Timeout:", Global.UITextColor ); + Output.emplace_back( "Name: Output: Current: Timeout:", Global.UITextColor ); std::string textline; @@ -1185,13 +1185,14 @@ debug_panel::update_section_powergrid( std::vector &Output ) { powerstation->m_name ) + " " }; - textline = - name.substr( 0, 20 ) - + " " + to_string( powerstation->OutputVoltage, 0, 5 ) - + " " + to_string( powerstation->FuseTimer, 1, 12 ) - + ( powerstation->FuseCounter == 0 ? - "" : - " (x" + to_string( powerstation->FuseCounter ) + ")" ); + textline = + name.substr( 0, 20 ) + + " " + to_string( powerstation->OutputVoltage, 0, 5 ) + + " " + to_string( powerstation->TotalCurrent, 1, 8 ) + + " " + to_string( powerstation->FuseTimer, 1, 8 ) + + ( powerstation->FuseCounter == 0 ? + "" : + " (x" + to_string( powerstation->FuseCounter ) + ")" ); Output.emplace_back( textline, @@ -1240,7 +1241,8 @@ debug_panel::update_section_renderer( std::vector &Output ) { + ", Draw range: " + to_string( Global.BaseDrawRange * Global.fDistanceFactor, 0 ) + "m" // + "; sectors: " + std::to_string( GfxRenderer->m_drawcount ) // + ", FPS: " + to_string( Timer::GetFPS(), 2 ); - + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer->Framerate())) ); + + ", FPS: " + std::to_string( static_cast(std::round(GfxRenderer->Framerate())) ) + + ( Global.VSync ? " (vsync on)" : "" ); if( Global.iSlowMotion ) { textline += " (slowmotion " + to_string( Global.iSlowMotion ) + ")"; } diff --git a/simulationenvironment.cpp b/simulationenvironment.cpp index 2d19797f..fc691f7d 100644 --- a/simulationenvironment.cpp +++ b/simulationenvironment.cpp @@ -192,7 +192,9 @@ world_environment::update() { if( m_rainsound.is_combined() ) { m_rainsound.pitch( Global.Overcast - 1.0 ); } - m_rainsound.play( sound_flags::exclusive | sound_flags::looping ); + m_rainsound + .gain( m_rainsound.m_amplitudeoffset + m_rainsound.m_amplitudefactor * 1.f ) + .play( sound_flags::exclusive | sound_flags::looping ); } else { m_rainsound.stop(); diff --git a/sound.cpp b/sound.cpp index 27d94453..e1c2cd62 100644 --- a/sound.cpp +++ b/sound.cpp @@ -230,6 +230,7 @@ sound_source::deserialize_mapping( cParser &Input ) { { "internal", sound_placement::internal }, { "engine", sound_placement::engine }, { "external", sound_placement::external }, + { "custom", sound_placement::custom }, { "general", sound_placement::general } }; auto lookup{ placements.find( value ) }; if( lookup != placements.end() ) { @@ -935,115 +936,53 @@ sound_source::update_location() { m_properties.location = location(); } -float const EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG { 0.01f }; -float const EU07_SOUNDPROOFING_GLOBAL_STRONG { std::sqrt( 0.025f ) }; -float const EU07_SOUNDPROOFING_GLOBAL_SOME { std::sqrt( 0.15f ) }; -float const EU07_SOUNDPROOFING_GLOBAL_NONE { std::sqrt( 0.40f ) }; -float const EU07_SOUNDPROOFING_STRONG { std::sqrt( 0.20f ) }; -float const EU07_SOUNDPROOFING_SOME { std::sqrt( 0.65f ) }; -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 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 : + auto const *listenervehicle { Global.pCamera.m_owner }; // nullptr in free roam mode + auto const occupiedcab { ( + Global.CabWindowOpen ? 2 : // window view FreeFlyModeFlag ? ( - Global.pCamera.m_owner ? - 3 : - 0 ) : - ( simulation::Train ? - simulation::Train->Occupied()->CabOccupied : - 0 ) ); + listenervehicle ? + 3 : // external view + 4 ) : // free roam view + listenervehicle->MoverParameters->CabOccupied ) }; // some internal view so we can be sure listener isn't a nullptr // location-based gain factor: - std::uintptr_t soundproofingstamp = reinterpret_cast( ( - FreeFlyModeFlag ? - Global.pCamera.m_owner : - ( simulation::Train ? - simulation::Train->Dynamic() : - nullptr ) ) ) - + occupiedcab; + std::uintptr_t soundproofingstamp = + reinterpret_cast( listenervehicle ) + + ( listenervehicle ? + occupiedcab : + 0 ); if( soundproofingstamp == m_properties.soundproofing_stamp ) { return false; } // listener location has changed, calculate new location-based gain factor - auto const externalcamera { ( Global.CabWindowOpen ) || ( Global.pCamera.m_owner && FreeFlyModeFlag ) }; - switch( m_placement ) { - case sound_placement::general: { - m_properties.soundproofing = ( - m_range >= -1 ? - EU07_SOUNDPROOFING_NONE : - EU07_SOUNDPROOFING_GLOBAL_NONE ); - break; + // TBD, TODO: clean up parameters for soundproofing() call -- make ambient separate, explicit placement + m_properties.soundproofing = EU07_SOUNDPROOFING_NONE; // default proofing for environment sounds and free listener + if( m_placement != sound_placement::general ) { + auto const isambient { ( ( m_placement == sound_placement::external ) && ( m_owner == nullptr ) && ( m_range < -1 ) ? 1 : 0 ) }; + auto const placement { ( isambient ? sound_placement::external_ambient : m_placement ) }; + if( m_owner != nullptr ) { + m_properties.soundproofing = + m_owner->soundproofing( + static_cast( placement ), + ( m_owner != listenervehicle ? + 4 : // part of two-stage calculation owner->outside->listener, or single stage owner->outside one + occupiedcab ) ); } - case sound_placement::external: { - if( m_range >= -1 ) { // limited range sound... - m_properties.soundproofing = ( - soundproofingstamp == 0 ? EU07_SOUNDPROOFING_NONE : // ...with listener outside - externalcamera ? EU07_SOUNDPROOFING_SOME : // ...with listener inside and window open - EU07_SOUNDPROOFING_STRONG ); // ...with listener inside and window closed - } - else { // global sound... - m_properties.soundproofing = ( - soundproofingstamp == 0 ? EU07_SOUNDPROOFING_GLOBAL_NONE : // ...with listener outside - externalcamera ? EU07_SOUNDPROOFING_GLOBAL_STRONG : // ...with listener inside and window open - EU07_SOUNDPROOFING_GLOBAL_VERYSTRONG ); // ...with listener inside and window closed - } - break; - } - case sound_placement::internal: { - if( m_range >= -1 ) { // limited range sound - m_properties.soundproofing = ( - ( FreeFlyModeFlag || externalcamera ) ? - 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 { // global sound - m_properties.soundproofing = ( - ( FreeFlyModeFlag || externalcamera ) ? - 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: { - if( m_range >= -1 ) { // limited range sound - m_properties.soundproofing = ( - ( FreeFlyModeFlag || externalcamera ) ? - 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 { // global sound - m_properties.soundproofing = ( - ( FreeFlyModeFlag || externalcamera ) ? - 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: { - // shouldn't ever land here, but, eh - m_properties.soundproofing = EU07_SOUNDPROOFING_NONE; - break; + if( ( listenervehicle ) && ( listenervehicle != m_owner ) ) { + // if the listener is located in another vehicle, calculate additional proofing of the sound coming from outside + m_properties.soundproofing *= + listenervehicle->soundproofing( + static_cast( sound_placement::external ) + isambient, + occupiedcab ); } } + // for ambient sounds reduce their volume to account for their placement right on top of the listener + if( m_range < -1 ) { + m_properties.soundproofing *= 0.4f; + } m_properties.soundproofing_stamp = soundproofingstamp; return true; diff --git a/sound.h b/sound.h index 067ec1cc..ed4febcc 100644 --- a/sound.h +++ b/sound.h @@ -41,9 +41,16 @@ enum class sound_placement { general, // source is equally audible in potential carrier and outside of it internal, // source is located inside of the carrier, and less audible when the listener is outside engine, // source is located in the engine compartment, less audible when the listener is outside and even less in the cabs - external // source is located on the outside of the carrier, and less audible when the listener is inside + external, // source is located on the outside of the carrier, and less audible when the listener is inside + external_ambient, // source is located on the outside of the carrier, with fixed volume + custom, // source doesn't fit in any standard location or requires custom soundproofing }; +auto const EU07_SOUNDPROOFING_NONE{ 1.f }; +auto const EU07_SOUNDPROOFING_SOME{ std::sqrt( 0.65f ) }; +auto const EU07_SOUNDPROOFING_STRONG{ std::sqrt( 0.20f ) }; +auto const EU07_SOUNDPROOFING_VERYSTRONG{ std::sqrt( 0.01f ) }; + // mini controller and audio dispatcher; issues play commands for the audio renderer, // updates parameters of created audio emitters for the playback duration // TODO: move to simulation namespace after clean up of owner classes diff --git a/uart.cpp b/uart.cpp index dd976e74..40bfa533 100644 --- a/uart.cpp +++ b/uart.cpp @@ -416,6 +416,7 @@ void uart_input::poll() if (conf.debug) { char buf[buffer.size() * 3 + 1]; + buf[ buffer.size() * 3 ] = 0; size_t pos = 0; for (uint8_t b : buffer) pos += sprintf(&buf[pos], "%02X ", b);