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

Merge with TMJ

This commit is contained in:
Królik Uszasty
2019-05-22 21:31:56 +02:00
22 changed files with 370 additions and 214 deletions

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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;
};
//---------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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 );

112
Train.cpp
View File

@@ -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<std::string, bool *> const autoboolgauges = {
{ "doormode_sw:", &mvOccupied->Doors.remote_only },
{ "doorstep_sw:", &mvOccupied->Doors.step_enabled },
{ "coolingfans_sw:", &mvControlled->RVentForceOn }
};

View File

@@ -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 );

View File

@@ -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 },

View File

@@ -147,6 +147,7 @@ enum class user_command {
doorcloseright,
doorcloseall,
doorsteptoggle,
doormodetoggle,
departureannounce,
doorlocktoggle,
pantographcompressorvalvetoggle,

View File

@@ -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 },

View File

@@ -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 } },

View File

@@ -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<int>( 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() {

View File

@@ -50,12 +50,14 @@ public:
: ui_panel( Name, Isopen ) {}
void update() override;
void render() override;
bool is_expanded{ false };
private:
// members
// members
std::array<char, 256> m_buffer;
std::vector<text_line> m_tablelines;
};
class debug_panel : public ui_panel {

View File

@@ -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<float>( 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<float>( 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;
}
}

View File

@@ -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;

View File

@@ -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<std::string>() };

View File

@@ -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:",

View File

@@ -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,

View File

@@ -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

View File

@@ -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<int>( std::floor( minutesfractional * 10 + 0.1 ) ) ] );
}
int stol_def(const std::string &str, const int &DefaultValue) {
int result { DefaultValue };

View File

@@ -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) {

View File

@@ -1,5 +1,5 @@
#pragma once
#define VERSION_MAJOR 19
#define VERSION_MINOR 430
#define VERSION_MINOR 522
#define VERSION_REVISION 0