diff --git a/Driver.cpp b/Driver.cpp index 6add5b5f..46369124 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2127,11 +2127,12 @@ bool TController::CheckVehicles(TOrders user) while (p) { // HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi... - if( ( p != pVehicle ) - && ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 ) - && ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) { - // NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly - p->MoverParameters->BatterySwitch( true ); + if( p != pVehicle ) { + if( ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 ) + && ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) { + // NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly + p->MoverParameters->BatterySwitch( true ); + } // enable heating and converter in carriages with can be heated if( p->MoverParameters->HeatingPower > 0 ) { p->MoverParameters->HeatingAllow = true; @@ -2730,8 +2731,12 @@ bool TController::IncBrake() // NOTE: we could simplify this by doing only check of the rear coupler, but this can be quite tricky in itself // TODO: add easier ways to access front/rear coupler taking into account vehicle's direction standalone = - ( ( ( vehicle->MoverParameters->Couplers[ end::front ].Connected == nullptr ) || ( vehicle->MoverParameters->Couplers[ end::front ].CouplingFlag & coupling::control ) ) - && ( ( vehicle->MoverParameters->Couplers[ end::rear ].Connected == nullptr ) || ( vehicle->MoverParameters->Couplers[ end::rear ].CouplingFlag & coupling::control ) ) ); + ( ( ( vehicle->MoverParameters->Couplers[ end::front ].Connected == nullptr ) + || ( ( vehicle->MoverParameters->Couplers[ end::front ].CouplingFlag & coupling::control ) + && ( vehicle->MoverParameters->Couplers[ end::front ].Connected->Power > 1 ) ) ) + && ( ( vehicle->MoverParameters->Couplers[ end::rear ].Connected == nullptr ) + || ( ( vehicle->MoverParameters->Couplers[ end::rear ].CouplingFlag & coupling::control ) + && ( vehicle->MoverParameters->Couplers[ end::rear ].Connected->Power > 1 ) ) ) ); vehicle = vehicle->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } } @@ -4196,6 +4201,7 @@ TController::UpdateSituation(double dt) { // HACK: activate route scanning if an idling vehicle is activated by a human user if( ( OrderCurrentGet() == Wait_for_orders ) && ( false == AIControllFlag ) + && ( false == iEngineActive ) && ( true == mvControlling->Battery ) ) { OrderNext( Prepare_engine ); } @@ -5024,54 +5030,50 @@ TController::UpdateSituation(double dt) { // jeśli dociskanie w celu odczepienia // 3. faza odczepiania. SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2 - if( ( mvControlling->MainCtrlPowerPos() > 0 ) - || ( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) ) { - // jeśli jazda - WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute)); - TDynamicObject *p = pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI - int d; // numer sprzęgu, który sprawdzamy albo odczepiamy - int n = iVehicleCount; // ile wagonów ma zostać - do - { // szukanie pojazdu do odczepienia - d = p->DirectionGet() > 0 ? - end::front : - end::rear; // numer sprzęgu od strony czoła składu - // if (p->MoverParameters->Couplers[d].CouplerType==Articulated) - // //jeśli sprzęg typu wózek (za mało) - if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany - // if (p->GetTrack()->) //a nie stoi na torze warsztatowym - // (ustalić po czym poznać taki tor) - ++n; // to liczymy człony jako jeden - p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać - // GBH p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował - BrakeLevelSet(gbh_RP); - if (n) - { // jeśli jeszcze nie koniec - p = p->Prev(); // kolejny w stronę czoła składu (licząc od tyłu), bo dociskamy - if (!p) - iVehicleCount = -2, - n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone - } - } while (n--); - if( ( p == nullptr ) - || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { - // no target, or already just virtual coupling - WriteLog( mvOccupied->Name + " didn't find anything to disconnect." ); - iVehicleCount = -2; // odczepiono, co było do odczepienia - } else if ( p->Dettach(d) == coupling::faux ) { - // tylko jeśli odepnie - WriteLog( mvOccupied->Name + " odczepiony." ); - iVehicleCount = -2; - } // a jak nie, to dociskać dalej - } - if (iVehicleCount >= 0) // zmieni się po odczepieniu - if (!mvOccupied->DecLocalBrakeLevel(1)) - { // dociśnij sklad - WriteLog( mvOccupied->Name + " dociskanie..." ); - // mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę - // Ready=true; //zamiast sprawdzenia odhamowania całego składu - IncSpeed(); // dla (Ready)==false nie ruszy + if( iVehicleCount >= 0 ) { + // zmieni się po odczepieniu + WriteLog( mvOccupied->Name + " dociskanie..." ); + while( mvOccupied->DecLocalBrakeLevel( 1 ) ) { // dociśnij sklad + ; } + IncSpeed(); + } + WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute)); + TDynamicObject *p = pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI + int d; // numer sprzęgu, który sprawdzamy albo odczepiamy + int n = iVehicleCount; // ile wagonów ma zostać + do + { // szukanie pojazdu do odczepienia + d = p->DirectionGet() > 0 ? + end::front : + end::rear; // numer sprzęgu od strony czoła składu + // if (p->MoverParameters->Couplers[d].CouplerType==Articulated) + // //jeśli sprzęg typu wózek (za mało) + if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany + // if (p->GetTrack()->) //a nie stoi na torze warsztatowym + // (ustalić po czym poznać taki tor) + ++n; // to liczymy człony jako jeden + p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać + // GBH p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował + BrakeLevelSet(gbh_RP); + if (n) + { // jeśli jeszcze nie koniec + p = p->Prev(); // kolejny w stronę czoła składu (licząc od tyłu), bo dociskamy + if (!p) + iVehicleCount = -2, + n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone + } + } while (n--); + if( ( p == nullptr ) + || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { + // no target, or already just virtual coupling + WriteLog( mvOccupied->Name + " didn't find anything to disconnect." ); + iVehicleCount = -2; // odczepiono, co było do odczepienia + } else if ( p->Dettach(d) == coupling::faux ) { + // tylko jeśli odepnie + WriteLog( mvOccupied->Name + " odczepiony." ); + iVehicleCount = -2; + } // a jak nie, to dociskać dalej } if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress)) { // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij @@ -6598,17 +6600,18 @@ std::string TController::NextStop() const // dodać godzinę odjazdu if (!TrainParams) return ""; // tu nie powinno nigdy wejść - std::string nextstop = asNextStop; + std::string nextstop = Bezogonkow( asNextStop, true ); TMTableLine *t = TrainParams->TimeTable + TrainParams->StationIndex; if( t->Ah >= 0 ) { // przyjazd - nextstop += " przyj." + std::to_string( t->Ah ) + ":" - + ( t->Am < 10 ? "0" : "" ) + std::to_string( int(t->Am) ) + "." + std::to_string(int(t->Am * 10) % 10); + nextstop += " przyj." + std::to_string( t->Ah ) + ":" + + to_minutes_str( t->Am, true, 3 ); + } if( t->Dh >= 0 ) { // jeśli jest godzina odjazdu nextstop += " odj." + std::to_string( t->Dh ) + ":" - + ( t->Dm < 10 ? "0" : "" ) + std::to_string( int( t->Dm )) + "." + std::to_string(int(t->Dm * 10) % 10); + + to_minutes_str( t->Dm, true, 3 ); } return nextstop; }; diff --git a/Driver.h b/Driver.h index 2b0a8053..96067b79 100644 --- a/Driver.h +++ b/Driver.h @@ -201,6 +201,10 @@ public: inline TMoverParameters const *Controlling() const { return mvControlling; } + inline + TMoverParameters const *Occupied() const { + return mvOccupied; + } void DirectionInitial(); void DirectionChange(); inline @@ -251,6 +255,7 @@ public: bool AIControllFlag = false; // rzeczywisty/wirtualny maszynista int iOverheadZero = 0; // suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami int iOverheadDown = 0; // suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami + double BrakeCtrlPosition = 0.0; // intermediate position of main brake controller private: bool Psyche = false; int HelperState = 0; //stan pomocnika maszynisty @@ -318,7 +323,6 @@ private: double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca double BrakeChargingCooldown {}; // prevents the ai from trying to charge the train brake too frequently - double BrakeCtrlPosition = 0.0; // intermediate position of main brake controller double LastReactionTime = 0.0; double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations diff --git a/DynObj.cpp b/DynObj.cpp index e8ad81bd..6f2f3eaf 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -6120,30 +6120,32 @@ TDynamicObject * TDynamicObject::ControlledFind() // problematyczna może być kwestia wybranej kabiny (w silnikowym...) // jeśli silnikowy będzie zapięty odwrotnie (tzn. -1), to i tak powinno jeździć dobrze // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... - TDynamicObject *d = this; // zaczynamy od aktualnego - if( ( d->MoverParameters->TrainType == dt_EZT ) - || ( d->MoverParameters->TrainType == dt_DMU ) ) { - // na razie dotyczy to EZT - if( ( d->NextConnected() != nullptr ) - && ( true == TestFlag( d->MoverParameters->Couplers[ end::rear ].AllowedFlag, coupling::permanent ) ) ) { - // gdy jest człon od sprzęgu 1, a sprzęg łączony warsztatowo (powiedzmy) - if( ( d->MoverParameters->Power < 1.0 ) - && ( d->NextConnected()->MoverParameters->Power > 1.0 ) ) { - // my nie mamy mocy, ale ten drugi ma - d = d->NextConnected(); // będziemy sterować tym z mocą - } - } - else if( ( d->PrevConnected() != nullptr ) - && ( true == TestFlag( d->MoverParameters->Couplers[ end::front ].AllowedFlag, coupling::permanent ) ) ) { - // gdy jest człon od sprzęgu 0, a sprzęg łączony warsztatowo (powiedzmy) - if( ( d->MoverParameters->Power < 1.0 ) - && ( d->PrevConnected()->MoverParameters->Power > 1.0 ) ) { - // my nie mamy mocy, ale ten drugi ma - d = d->PrevConnected(); // będziemy sterować tym z mocą - } + if( MoverParameters->Power > 1.0 ) { return this; } + + auto const couplingtype { ( + ( MoverParameters->TrainType == dt_EZT ) + || ( MoverParameters->TrainType == dt_DMU ) ) ? + coupling::permanent : + coupling::control + }; + // try first to look towards the rear + auto *d = this; // zaczynamy od aktualnego + + while( ( d = d->NextC( couplingtype ) ) != nullptr ) { + if( d->MoverParameters->Power > 1.0 ) { + return d; } } - return d; + // if we didn't yet find a suitable vehicle try in the other direction + d = this; // zaczynamy od aktualnego + + while( ( d = d->PrevC( couplingtype ) ) != nullptr ) { + if( d->MoverParameters->Power > 1.0 ) { + return d; + } + } + // if we still don't have a match give up + return this; }; //--------------------------------------------------------------------------- diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index bd9308f6..a286f238 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -766,6 +766,7 @@ private: // ld inputs bool lock_enabled { true }; bool step_enabled { true }; + bool remote_only { false }; // door ignores local control signals // internal data int permit_preset { -1 }; // curent position of preset selection switch // vehicle parts @@ -1162,6 +1163,7 @@ public: bool CompressorAllowLocal{ true }; // local device state override (most units don't have this fitted so it's set to true not to intefere) bool CompressorGovernorLock{ false }; // indicates whether compressor pressure switch was activated due to reaching cut-out pressure start_t CompressorStart{ start_t::manual }; // whether the compressor is started manually, or another way + start_t PantographCompressorStart{ start_t::manual }; // TODO converter parameters, for when we start cleaning up mover parameters start_t ConverterStart{ start_t::manual }; // whether converter is started manually, or by other means float ConverterStartDelay{ 0.0f }; // delay (in seconds) before the converter is started, once its activation conditions are met @@ -1346,8 +1348,6 @@ public: bool PantRearUp = false; bool PantFrontSP = true; //dzwiek patykow 'Winger 010304 bool PantRearSP = true; - int PantFrontStart = 0; //stan patykow 'Winger 160204 - int PantRearStart = 0; double PantFrontVolt = 0.0; //pantograf pod napieciem? 'Winger 160404 double PantRearVolt = 0.0; // TODO: move these switch types where they belong, cabin definition @@ -1555,6 +1555,7 @@ public: bool PermitDoors( side const Door, bool const State = true, range_t const Notify = range_t::consist ); bool ChangeDoorPermitPreset( int const Change, range_t const Notify = range_t::consist ); bool PermitDoorStep( bool const State, range_t const Notify = range_t::consist ); + bool ChangeDoorControlMode( bool const State, range_t const Notify = range_t::consist ); bool OperateDoors( side const Door, bool const State, range_t const Notify = range_t::consist ); bool LockDoors( bool const State, range_t const Notify = range_t::consist ); bool signal_departure( bool const State, range_t const Notify = range_t::consist ); // toggles departure warning diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index af0368c1..fb83ef35 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -653,11 +653,18 @@ void TMoverParameters::UpdatePantVolume(double dt) { // KURS90 - sprężarka pantografów; Ra 2014-07: teraz jest to zbiornik rozrządu, chociaż to jeszcze nie tak // check the pantograph compressor while at it - if( PantCompFlag ) { - if( ( false == Battery ) - && ( false == ConverterFlag ) ) { - PantCompFlag = false; - } + if( ( PantPress < 4.2 ) + && ( ( PantographCompressorStart == start_t::automatic ) + || ( PantographCompressorStart == start_t::manualwithautofallback ) ) + && ( ( true == PantRearUp ) + || ( true == PantFrontUp ) ) ) { + // automatic start if the pressure is too low + PantCompFlag = true; + } + if( ( true == PantCompFlag ) + && ( false == Battery ) + && ( false == ConverterFlag ) ) { + PantCompFlag = false; } if (EnginePowerSource.SourceType == TPowerSource::CurrentCollector) // tylko jeśli pantografujący @@ -5924,7 +5931,6 @@ bool TMoverParameters::PantFront( bool const State, range_t const Notify ) if( PantFrontUp != State ) { PantFrontUp = State; if( State == true ) { - PantFrontStart = 0; if( Notify != range_t::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( @@ -5935,7 +5941,6 @@ bool TMoverParameters::PantFront( bool const State, range_t const Notify ) } } else { - PantFrontStart = 1; if( Notify != range_t::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( @@ -5977,7 +5982,6 @@ bool TMoverParameters::PantRear( bool const State, range_t const Notify ) if( PantRearUp != State ) { PantRearUp = State; if( State == true ) { - PantRearStart = 0; if( Notify != range_t::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( @@ -5988,7 +5992,6 @@ bool TMoverParameters::PantRear( bool const State, range_t const Notify ) } } else { - PantRearStart = 1; if( Notify != range_t::local ) { // wysłanie wyłączenia do pozostałych? SendCtrlToNext( @@ -6939,12 +6942,7 @@ bool TMoverParameters::PermitDoors( side const Door, bool const State, range_t c bool const initialstate { Doors.instances[Door].open_permit }; - if( ( false == Doors.permit_presets.empty() ) // HACK: for cases where preset switch is used before battery - || ( ( true == Battery ) - && ( false == Doors.is_locked ) ) ) { - - Doors.instances[ Door ].open_permit = State; - } + Doors.instances[ Door ].open_permit = State; if( Notify != range_t::local ) { @@ -6963,6 +6961,34 @@ bool TMoverParameters::PermitDoors( side const Door, bool const State, range_t c return ( Doors.instances[ Door ].open_permit != initialstate ); } +bool TMoverParameters::ChangeDoorControlMode( bool const State, range_t const Notify ) { + + auto const initialstate { Doors.remote_only }; + + Doors.remote_only = State; + if( Notify != range_t::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "DoorMode", + ( State == true ? + 1 : + 0 ), + CabNo, + ( Notify == range_t::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + if( true == State ) { + // when door are put in remote control mode they're automatically open + // TBD, TODO: make it dependant on config switch? + OperateDoors( side::left, true ); + OperateDoors( side::right, true ); + } + + return ( Doors.step_enabled != initialstate ); +} + bool TMoverParameters::OperateDoors( side const Door, bool const State, range_t const Notify ) { auto &door { Doors.instances[ Door ] }; @@ -7070,15 +7096,17 @@ TMoverParameters::update_doors( double const Deltatime ) { // NBMX Obsluga drzwi, MC: zuniwersalnione auto const localopencontrol { - ( Doors.open_control == control_t::passenger ) - || ( Doors.open_control == control_t::mixed ) }; + ( false == Doors.remote_only ) + && ( ( Doors.open_control == control_t::passenger ) + || ( Doors.open_control == control_t::mixed ) ) }; auto const remoteopencontrol { ( Doors.open_control == control_t::driver ) || ( Doors.open_control == control_t::conductor ) || ( Doors.open_control == control_t::mixed ) }; auto const localclosecontrol { - ( Doors.close_control == control_t::passenger ) - || ( Doors.close_control == control_t::mixed ) }; + ( false == Doors.remote_only ) + && ( ( Doors.close_control == control_t::passenger ) + || ( Doors.close_control == control_t::mixed ) ) }; auto const remoteclosecontrol { ( Doors.close_control == control_t::driver ) || ( Doors.close_control == control_t::conductor ) @@ -7106,7 +7134,7 @@ TMoverParameters::update_doors( double const Deltatime ) { && ( door.step_position <= 0.f ); door.local_open = door.local_open && ( false == door.is_open ) && ( ( false == Doors.permit_needed ) || door.open_permit ); - door.remote_open = door.remote_open && ( false == door.is_open ) && ( ( false == Doors.permit_needed ) || door.open_permit ); + door.remote_open = ( door.remote_open || Doors.remote_only ) && ( false == door.is_open ) && ( ( false == Doors.permit_needed ) || door.open_permit ); door.local_close = door.local_close && ( false == door.is_closed ); door.remote_close = door.remote_close && ( false == door.is_closed ); @@ -8760,6 +8788,14 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { lookup->second : start_t::manual; } + // pantograph compressor + { + auto lookup = starts.find( extract_value( "PantCompressorStart", line ) ); + PantographCompressorStart = + lookup != starts.end() ? + lookup->second : + start_t::manual; + } // fuel pump { auto lookup = starts.find( extract_value( "FuelStart", line ) ); @@ -10074,6 +10110,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C false ); OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } + else if( Command == "DoorMode" ) { + Doors.remote_only = ( + CValue1 == 1 ? + true : + false ); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } else if( Command == "DepartureSignal" ) { DepartureSignal = ( CValue1 == 1 ? @@ -10090,12 +10133,10 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C if ((CValue1 == 1)) { PantFrontUp = true; - PantFrontStart = 0; } else if ((CValue1 == 0)) { PantFrontUp = false; - PantFrontStart = 1; } } else @@ -10105,24 +10146,20 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C (TestFlag(Couplers[0].CouplingFlag, ctrain_controll) && (CValue2 == -1))) { PantFrontUp = true; - PantFrontStart = 0; } else { PantRearUp = true; - PantRearStart = 0; } else if ((CValue1 == 0)) if ((TestFlag(Couplers[1].CouplingFlag, ctrain_controll) && (CValue2 == 1)) || (TestFlag(Couplers[0].CouplingFlag, ctrain_controll) && (CValue2 == -1))) { PantFrontUp = false; - PantFrontStart = 1; } else { PantRearUp = false; - PantRearStart = 1; } } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); @@ -10135,12 +10172,10 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C if ((CValue1 == 1)) { PantRearUp = true; - PantRearStart = 0; } else if ((CValue1 == 0)) { PantRearUp = false; - PantRearStart = 1; } } else @@ -10151,24 +10186,20 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C (TestFlag(Couplers[0].CouplingFlag, ctrain_controll) && (CValue2 == -1))) { PantRearUp = true; - PantRearStart = 0; } else { PantFrontUp = true; - PantFrontStart = 0; } else if ((CValue1 == 0)) if ((TestFlag(Couplers[1].CouplingFlag, ctrain_controll) && (CValue2 == 1)) || (TestFlag(Couplers[0].CouplingFlag, ctrain_controll) && (CValue2 == -1))) { PantRearUp = false; - PantRearStart = 1; } else { PantFrontUp = false; - PantFrontStart = 1; } } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); diff --git a/Train.cpp b/Train.cpp index 9d6bf1cd..1870279e 100644 --- a/Train.cpp +++ b/Train.cpp @@ -327,6 +327,7 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::dooropenall, &TTrain::OnCommand_dooropenall }, { user_command::doorcloseall, &TTrain::OnCommand_doorcloseall }, { user_command::doorsteptoggle, &TTrain::OnCommand_doorsteptoggle }, + { user_command::doormodetoggle, &TTrain::OnCommand_doormodetoggle }, { user_command::carcouplingincrease, &TTrain::OnCommand_carcouplingincrease }, { user_command::carcouplingdisconnect, &TTrain::OnCommand_carcouplingdisconnect }, { user_command::departureannounce, &TTrain::OnCommand_departureannounce }, @@ -786,7 +787,7 @@ void TTrain::OnCommand_mastercontrollerincrease( TTrain *Train, command_data con if( Command.action != GLFW_RELEASE ) { // on press or hold if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvControlled->LocalBrakePosA > 0.0 ) ) { + && ( Train->mvOccupied->LocalBrakePosA > 0.0 ) ) { OnCommand_independentbrakedecrease( Train, Command ); } else { @@ -806,7 +807,7 @@ void TTrain::OnCommand_mastercontrollerincreasefast( TTrain *Train, command_data if( Command.action != GLFW_RELEASE ) { // on press or hold if( ( Train->ggJointCtrl.SubModel != nullptr ) - && ( Train->mvControlled->LocalBrakePosA > 0.0 ) ) { + && ( Train->mvOccupied->LocalBrakePosA > 0.0 ) ) { OnCommand_independentbrakedecreasefast( Train, Command ); } else { @@ -1730,10 +1731,11 @@ void TTrain::OnCommand_alerteracknowledge( TTrain *Train, command_data const &Co } } +// TODO: replace battery with a two-state device, update switch code accordingly void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command ) { - if( Command.action == GLFW_PRESS ) { - // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( Command.action != GLFW_REPEAT ) { + // keep the switch from flipping back and forth if key is held down if( false == Train->mvOccupied->Battery ) { // turn on OnCommand_batteryenable( Train, Command ); @@ -1747,16 +1749,13 @@ void TTrain::OnCommand_batterytoggle( TTrain *Train, command_data const &Command void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command ) { - if( true == Train->mvOccupied->Battery ) { return; } // already on - if( Command.action == GLFW_PRESS ) { - // ignore repeats - // wyłącznik jest też w SN61, ewentualnie załączać prąd na stałe z poziomu FIZ + // visual feedback + Train->ggBatteryButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvOccupied->Battery ) { return; } // already on + if( Train->mvOccupied->BatterySwitch( true ) ) { - // bateria potrzebna np. do zapalenia świateł - if( Train->ggBatteryButton.SubModel ) { - Train->ggBatteryButton.UpdateValue( 1.0, Train->dsbSwitch ); - } // side-effects if( Train->mvOccupied->LightsPosNo > 0 ) { Train->SetLights(); @@ -1768,19 +1767,23 @@ void TTrain::OnCommand_batteryenable( TTrain *Train, command_data const &Command } } } + else if( Command.action == GLFW_RELEASE ) { + if( Train->ggBatteryButton.type() == TGaugeType::push ) { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue( 0.5f ); + } + } } void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Command ) { - - if( false == Train->mvOccupied->Battery ) { return; } // already off - + // TBD, TODO: ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora if( Command.action == GLFW_PRESS ) { - // ignore repeats + // visual feedback + Train->ggBatteryButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvOccupied->Battery ) { return; } // already off + if( Train->mvOccupied->BatterySwitch( false ) ) { - // ewentualnie zablokować z FIZ, np. w samochodach się nie odłącza akumulatora - if( Train->ggBatteryButton.SubModel ) { - Train->ggBatteryButton.UpdateValue( 0.0, Train->dsbSwitch ); - } // side-effects if( false == Train->mvControlled->ConverterFlag ) { // if there's no (low voltage) power source left, drop pantographs @@ -1789,6 +1792,12 @@ void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Comman } } } + else if( Command.action == GLFW_RELEASE ) { + if( Train->ggBatteryButton.type() == TGaugeType::push ) { + // return the switch to neutral position + Train->ggBatteryButton.UpdateValue( 0.5f ); + } + } } void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const &Command ) { @@ -4138,7 +4147,7 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command } if( Command.action == GLFW_PRESS ) { - // only reacting to press, so the switch doesn't flip back and forth if key is held down + // ignore repeats so the switch doesn't flip back and forth if key is held down if( false == Train->mvControlled->HeatingAllow ) { // turn on OnCommand_heatingenable( Train, Command ); @@ -4148,6 +4157,14 @@ void TTrain::OnCommand_heatingtoggle( TTrain *Train, command_data const &Command OnCommand_heatingdisable( Train, Command ); } } + else if( Command.action == GLFW_RELEASE ) { + + if( Train->ggTrainHeatingButton.type() == TGaugeType::push ) { + // impulse switch + // visual feedback + Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + } } void TTrain::OnCommand_heatingenable( TTrain *Train, command_data const &Command ) { @@ -4166,7 +4183,11 @@ void TTrain::OnCommand_heatingdisable( TTrain *Train, command_data const &Comman Train->mvControlled->HeatingAllow = false; // visual feedback - Train->ggTrainHeatingButton.UpdateValue( 0.0, Train->dsbSwitch ); + Train->ggTrainHeatingButton.UpdateValue( + ( Train->ggTrainHeatingButton.type() == TGaugeType::push ? + 1.0 : + 0.0 ), + Train->dsbSwitch ); } } @@ -4733,6 +4754,13 @@ void TTrain::OnCommand_doorsteptoggle( TTrain *Train, command_data const &Comman } } +void TTrain::OnCommand_doormodetoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + Train->mvOccupied->ChangeDoorControlMode( false == Train->mvOccupied->Doors.remote_only ); + } +} + void TTrain::OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ) { if( ( true == FreeFlyModeFlag ) @@ -7135,28 +7163,11 @@ void TTrain::DynamicSet(TDynamicObject *d) // jeździć dobrze // również hamowanie wykonuje się zaworem w członie, a nie w silnikowym... DynamicObject = d; // jedyne miejsce zmiany - mvOccupied = mvControlled = d ? DynamicObject->MoverParameters : NULL; // albo silnikowy w EZT - if (!DynamicObject) - return; - // TODO: leverage code already present in TDynamicObject::ControlledFind() - if( ( d->MoverParameters->TrainType == dt_EZT ) - || ( d->MoverParameters->TrainType == dt_DMU ) ) { + mvOccupied = mvControlled = ( d ? DynamicObject->MoverParameters : nullptr ); // albo silnikowy w EZT - if( ( d->NextConnected() != nullptr ) - && ( true == TestFlag( d->MoverParameters->Couplers[ end::rear ].AllowedFlag, coupling::permanent ) ) ) { - if( ( mvControlled->Power < 1.0 ) && ( mvControlled->Couplers[ 1 ].Connected->Power > 1.0 ) ) { - // my nie mamy mocy, ale ten drugi ma - mvControlled = DynamicObject->NextConnected()->MoverParameters; // będziemy sterować tym z mocą - } - } - else if( ( d->PrevConnected() != nullptr ) - && ( true == TestFlag( d->MoverParameters->Couplers[ end::front ].AllowedFlag, coupling::permanent ) ) ) { - if( ( mvControlled->Power < 1.0 ) && ( mvControlled->Couplers[ 0 ].Connected->Power > 1.0 ) ) { - // my nie mamy mocy, ale ten drugi ma - mvControlled = DynamicObject->PrevConnected()->MoverParameters; // będziemy sterować tym z mocą - } - } - } + if( DynamicObject == nullptr ) { return; } + + mvControlled = DynamicObject->ControlledFind()->MoverParameters; mvSecond = NULL; // gdyby się nic nie znalazło if (mvOccupied->Power > 1.0) // dwuczłonowe lub ukrotnienia, żeby nie szukać każdorazowo if (mvOccupied->Couplers[1].Connected ? @@ -7480,9 +7491,10 @@ void TTrain::clear_cab_controls() void TTrain::set_cab_controls( int const Cab ) { // switches // battery - if( true == mvOccupied->Battery ) { - ggBatteryButton.PutValue( 1.f ); - } + ggBatteryButton.PutValue( + ( ggBatteryButton.type() == TGaugeType::push ? 0.5f : + mvOccupied->Battery ? 1.f : + 0.f ) ); // motor connectors ggStLinOffButton.PutValue( ( mvControlled->StLinSwitchOff ? @@ -7660,8 +7672,11 @@ void TTrain::set_cab_controls( int const Cab ) { 1.f : 0.f ); // heating - if( true == mvControlled->Heating ) { - ggTrainHeatingButton.PutValue( 1.f ); + if( ggTrainHeatingButton.type() != TGaugeType::push ) { + ggTrainHeatingButton.PutValue( + mvControlled->Heating ? + 1.f : + 0.f ); } // brake acting time if( ggBrakeProfileCtrl.SubModel != nullptr ) { @@ -8050,6 +8065,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con } // TODO: move viable dedicated gauges to the automatic array std::unordered_map const autoboolgauges = { + { "doormode_sw:", &mvOccupied->Doors.remote_only }, { "doorstep_sw:", &mvOccupied->Doors.step_enabled }, { "coolingfans_sw:", &mvControlled->RVentForceOn } }; diff --git a/Train.h b/Train.h index 5a7c3b69..27a8c43e 100644 --- a/Train.h +++ b/Train.h @@ -329,6 +329,7 @@ class TTrain static void OnCommand_dooropenall( TTrain *Train, command_data const &Command ); static void OnCommand_doorcloseall( TTrain *Train, command_data const &Command ); static void OnCommand_doorsteptoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_doormodetoggle( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingincrease( TTrain *Train, command_data const &Command ); static void OnCommand_carcouplingdisconnect( TTrain *Train, command_data const &Command ); static void OnCommand_departureannounce( TTrain *Train, command_data const &Command ); diff --git a/command.cpp b/command.cpp index 25eeac6c..ea77daed 100644 --- a/command.cpp +++ b/command.cpp @@ -154,6 +154,7 @@ commanddescription_sequence Commands_descriptions = { { "doorcloseright", command_target::vehicle }, { "doorcloseall", command_target::vehicle }, { "doorsteptoggle", command_target::vehicle }, + { "doormodetoggle", command_target::vehicle }, { "departureannounce", command_target::vehicle }, { "doorlocktoggle", command_target::vehicle }, { "pantographcompressorvalvetoggle", command_target::vehicle }, diff --git a/command.h b/command.h index 9e321ffe..76f87aea 100644 --- a/command.h +++ b/command.h @@ -147,6 +147,7 @@ enum class user_command { doorcloseright, doorcloseall, doorsteptoggle, + doormodetoggle, departureannounce, doorlocktoggle, pantographcompressorvalvetoggle, diff --git a/driverkeyboardinput.cpp b/driverkeyboardinput.cpp index 1b530384..3d8d3a08 100644 --- a/driverkeyboardinput.cpp +++ b/driverkeyboardinput.cpp @@ -156,6 +156,7 @@ driverkeyboard_input::default_bindings() { // doorcloseright, { user_command::doorcloseall, GLFW_KEY_SLASH | keymodifier::control }, // doorsteptoggle, + { user_command::doormodetoggle, GLFW_KEY_SLASH | keymodifier::shift | keymodifier::control }, { user_command::departureannounce, GLFW_KEY_SLASH }, { user_command::doorlocktoggle, GLFW_KEY_S | keymodifier::control }, { user_command::pantographcompressorvalvetoggle, GLFW_KEY_V | keymodifier::control }, diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index e74cc17c..4d5b3130 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -633,6 +633,9 @@ drivermouse_input::default_bindings() { { "doorstep_sw:", { user_command::doorsteptoggle, user_command::none } }, + { "doormode_sw:", { + user_command::doormodetoggle, + user_command::none } }, { "departure_signal_bt:", { user_command::departureannounce, user_command::none } }, diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 03d44f38..6a482e81 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -229,6 +229,7 @@ timetable_panel::update() { if( false == is_open ) { return; } text_lines.clear(); + m_tablelines.clear(); auto const *train { simulation::Train }; auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; @@ -239,7 +240,7 @@ timetable_panel::update() { std::snprintf( m_buffer.data(), m_buffer.size(), locale::strings[ locale::string::driver_timetable_header ].c_str(), - 40, 40, + 37, 37, locale::strings[ locale::string::driver_timetable_name ].c_str(), time.wHour, time.wMinute, @@ -274,7 +275,7 @@ timetable_panel::update() { } { // next station - auto const nextstation = Bezogonkow( owner->NextStop(), true ); + auto const nextstation = owner->NextStop(); if( false == nextstation.empty() ) { // jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania auto textline = " -> " + nextstation; @@ -317,67 +318,126 @@ timetable_panel::update() { } else { + auto const loadingcolor { glm::vec4( 164.0f / 255.0f, 84.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; + auto const waitcolor { glm::vec4( 164.0f / 255.0f, 132.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; // header - text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + m_tablelines.emplace_back( u8"┌─────┬────────────────────────────────────┬─────────┬─────┐", Global.UITextColor ); TMTableLine const *tableline; for( int i = owner->iStationStart; i <= table->StationCount; ++i ) { // wyświetlenie pozycji z rozkładu tableline = table->TimeTable + i; // linijka rozkładu - std::string vmax = - " " - + to_string( tableline->vmax, 0 ); - vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej - std::string const station = ( + bool vmaxchange { true }; + if( i > owner->iStationStart ) { + auto const *previoustableline { tableline - 1 }; + if( tableline->vmax == previoustableline->vmax ) { + vmaxchange = false; + } + } + std::string vmax { " " }; + if( true == vmaxchange ) { + vmax += to_string( tableline->vmax, 0 ); + vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej + } + auto const station { ( Bezogonkow( tableline->StationName, true ) + " " ) - .substr( 0, 34 ); - std::string const location = ( + .substr( 0, 34 ) }; + auto const location { ( ( tableline->km > 0.0 ? to_string( tableline->km, 2 ) : "" ) + " " ) - .substr( 0, 34 - tableline->StationWare.size() ); - std::string const arrival = ( + .substr( 0, 34 - tableline->StationWare.size() ) }; + auto const arrival { ( tableline->Ah >= 0 ? - to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : - " | " ); - std::string const departure = ( + to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_minutes_str( tableline->Am, true, 3 ) : + u8" │ " ) }; + auto const departure { ( tableline->Dh >= 0 ? - to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : - " | " ); - auto const candeparture = ( + to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_minutes_str( tableline->Dm, true, 3 ) : + u8" │ " ) }; + auto const candeparture { ( ( owner->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) && ( ( tableline->Ah < 0 ) // pass-through, always valid - || ( time.wHour * 60 + time.wMinute + time.wSecond * 0.0167 >= tableline->Dh * 60 + tableline->Dm ) ) ); - auto traveltime = - " " - + ( i < 2 ? "" : - tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : - to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); - traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej - - text_lines.emplace_back( - ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), - ( candeparture ? - readycolor :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global.UITextColor ) ); - text_lines.emplace_back( - ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), - ( candeparture ? - readycolor :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global.UITextColor ) ); + || ( time.wHour * 60 + time.wMinute + time.wSecond * 0.0167 >= tableline->Dh * 60 + tableline->Dm ) ) ) }; + auto const loadchangeinprogress { ( ( static_cast( std::ceil( -1.0 * owner->fStopTime ) ) ) > 0 ) }; + auto const isatpassengerstop { ( true == owner->IsAtPassengerStop ) && ( vehicle->MoverParameters->Vel < 1.0 ) }; + auto const traveltime { ( + i < 2 ? " " : + tableline->Ah >= 0 ? to_minutes_str( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), false, 3 ) : + to_minutes_str( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), false, 3 ) ) }; + auto const linecolor { ( + ( i != owner->iStationStart ) ? Global.UITextColor : + loadchangeinprogress ? loadingcolor : + candeparture ? readycolor : // czas minął i odjazd był, to nazwa stacji będzie na zielono + isatpassengerstop ? waitcolor : + Global.UITextColor ) }; + m_tablelines.emplace_back( + ( u8"│ " + vmax + u8" │ " + station + u8" │ " + arrival + u8" │ " + traveltime + u8" │" ), + linecolor ); + m_tablelines.emplace_back( + ( u8"│ │ " + location + tableline->StationWare + u8" │ " + departure + u8" │ │" ), + linecolor ); // divider/footer - text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + if( i < table->StationCount ) { + auto const *nexttableline { tableline + 1 }; + if( tableline->vmax == nexttableline->vmax ) { + m_tablelines.emplace_back( u8"│ ├────────────────────────────────────┼─────────┼─────┤", Global.UITextColor ); + } + else { + m_tablelines.emplace_back( u8"├─────┼────────────────────────────────────┼─────────┼─────┤", Global.UITextColor ); + } + } + else { + m_tablelines.emplace_back( u8"└─────┴────────────────────────────────────┴─────────┴─────┘", Global.UITextColor ); + } } } } // is_expanded } +void +timetable_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + auto const panelname { ( + title.empty() ? + name : + title ) + + "###" + name }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + if( is_expanded ) { + ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 1, 0 ) ); + for( auto const &line : m_tablelines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + ImGui::PopStyleVar(); + } + } + ImGui::End(); +} + void debug_panel::update() { diff --git a/driveruipanels.h b/driveruipanels.h index 28363796..7c075562 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -50,12 +50,14 @@ public: : ui_panel( Name, Isopen ) {} void update() override; + void render() override; bool is_expanded{ false }; private: - // members +// members std::array m_buffer; + std::vector m_tablelines; }; class debug_panel : public ui_panel { diff --git a/mtable.cpp b/mtable.cpp index 3d207cdb..957a4f8d 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -480,14 +480,14 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) { if ((TimeTable[i].Ah >= 0)) { - adjustedtime = clamp_circular( TimeTable[i].Ah * 60 + TimeTable[i].Am + timeoffset, 24.0 * 60.0 ); // nowe minuty - TimeTable[i].Am = (int(60 * adjustedtime) % 3600) / 60.0; + adjustedtime = clamp_circular( TimeTable[i].Ah * 60 + TimeTable[i].Am + timeoffset, 24 * 60 ); // nowe minuty + TimeTable[i].Am = (int(60 * adjustedtime) % 3600) / 60.f; TimeTable[i].Ah = int((adjustedtime) / 60) % 24; } if ((TimeTable[i].Dh >= 0)) { - adjustedtime = clamp_circular( TimeTable[i].Dh * 60 + TimeTable[i].Dm + timeoffset, 24.0 * 60.0 ); // nowe minuty - TimeTable[i].Dm = (int(60 * adjustedtime) % 3600) / 60.0; + adjustedtime = clamp_circular( TimeTable[i].Dh * 60 + TimeTable[i].Dm + timeoffset, 24 * 60 ); // nowe minuty + TimeTable[i].Dm = (int(60 * adjustedtime) % 3600) / 60.f; TimeTable[i].Dh = int((adjustedtime) / 60) % 24; } } diff --git a/mtable.h b/mtable.h index 17191ff1..b0bea8bd 100644 --- a/mtable.h +++ b/mtable.h @@ -24,18 +24,18 @@ static char const *hrsd = "."; struct TMTableLine { - double km; // kilometraz linii - double vmax; // predkosc rozkladowa przed przystankiem + float km; // kilometraz linii + float vmax; // predkosc rozkladowa przed przystankiem // StationName:string[32]; //nazwa stacji ('_' zamiast spacji) // StationWare:string[32]; //typ i wyposazenie stacji, oddz. przecinkami} std::string StationName; // nazwa stacji ('_' zamiast spacji) std::string StationWare; // typ i wyposazenie stacji, oddz. przecinkami} int TrackNo; // ilosc torow szlakowych int Ah; - double Am; // godz. i min. przyjazdu, -1 gdy bez postoju + float Am; // godz. i min. przyjazdu, -1 gdy bez postoju int Dh; - double Dm; // godz. i min. odjazdu - double tm; // czas jazdy do tej stacji w min. (z kolumny) + float Dm; // godz. i min. odjazdu + float tm; // czas jazdy do tej stacji w min. (z kolumny) TMTableLine() { km = 0; diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index e28992a0..10f20e2e 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -179,7 +179,7 @@ state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratch Global.fFogEnd = clamp( Random( std::min( fograngestart, fograngeend ), std::max( fograngestart, fograngeend ) ), - 100.0, 2000.0 ); + 10.0, 2000.0 ); } std::string token { Input.getToken() }; diff --git a/translation.cpp b/translation.cpp index cd7d56bc..fe0df205 100644 --- a/translation.cpp +++ b/translation.cpp @@ -131,6 +131,7 @@ init() { "all doors (open)", "all doors (close)", "doorstep", + "door control mode", "departure signal", "upper headlight", "left headlight", @@ -296,6 +297,7 @@ init() { "drzwi (otworz)", "drzwi (zamknij)", "stopien drzwi", + "tryb sterowania drzwiami", "sygnal odjazdu", "reflektor gorny", "reflektor lewy", @@ -414,6 +416,7 @@ init() { "doorallon_sw:", "dooralloff_sw:", "doorstep_sw:", + "doormode_sw:", "departure_signal_bt:", "upperlight_sw:", "leftlight_sw:", diff --git a/translation.h b/translation.h index 18edda94..71bec11c 100644 --- a/translation.h +++ b/translation.h @@ -120,6 +120,7 @@ enum string { cab_doorallon_sw, cab_dooralloff_sw, cab_doorstep_sw, + cab_doormode_sw, cab_departure_signal_bt, cab_upperlight_sw, cab_leftlight_sw, diff --git a/uilayer.cpp b/uilayer.cpp index 6ad6929f..c5aea330 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -74,8 +74,15 @@ ui_layer::init( GLFWwindow *Window ) { IMGUI_CHECKVERSION(); ImGui::CreateContext(); + + static ImWchar const glyphranges[] = { + 0x0020, 0x00FF, // ascii + extension + 0x2070, 0x2079, // superscript + 0x2500, 0x256C, // box drawings + 0, + }; m_imguiio = &ImGui::GetIO(); -// m_imguiio->Fonts->AddFontFromFileTTF( "c:/windows/fonts/lucon.ttf", 13.0f ); + m_imguiio->Fonts->AddFontFromFileTTF( "fonts/dejavusansmono.ttf", 13.0f, nullptr, &glyphranges[ 0 ] ); ImGui_ImplGlfw_InitForOpenGL( m_window, false ); #ifdef EU07_USEIMGUIIMPLOPENGL2 diff --git a/utilities.cpp b/utilities.cpp index 971b034d..4c9953b1 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -1,4 +1,4 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not @@ -246,6 +246,24 @@ std::string to_hex_str( int const Value, int const Width ) return converter.str(); }; +char * const fractionlabels[] = { " ", u8"¹", u8"²", u8"³", u8"⁴", u8"⁵", u8"⁶", u8"⁷", u8"⁸", u8"⁹" }; + +std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ) { + + float minutesintegral; + auto const minutesfractional { std::modf( Minutes, &minutesintegral ) }; + auto const width { Width - 1 }; + auto minutes = ( + std::string( width - 1, ' ' ) + + ( Leadingzero ? + to_string( 100 + minutesintegral ).substr( 1, 2 ) : + to_string( minutesintegral, 0 ) ) ); + return ( + minutes.substr( minutes.size() - width, width ) + + fractionlabels[ static_cast( std::floor( minutesfractional * 10 + 0.1 ) ) ] ); +} + + int stol_def(const std::string &str, const int &DefaultValue) { int result { DefaultValue }; diff --git a/utilities.h b/utilities.h index 400f12df..1c930f7a 100644 --- a/utilities.h +++ b/utilities.h @@ -107,6 +107,7 @@ std::string to_string(double Value); std::string to_string(double Value, int precision); std::string to_string(double Value, int precision, int width); std::string to_hex_str( int const Value, int const width = 4 ); +std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ); inline std::string to_string(bool Value) { diff --git a/version.h b/version.h index 7bcb12d5..5424911c 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 430 +#define VERSION_MINOR 522 #define VERSION_REVISION 0