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

generic cab control state indicators, ai master controller logic enhancements, battery charging for diesel powered vehicles workaround, water heater damage fix, ai route scanning fixes, material loading fix

This commit is contained in:
tmj-fstate
2019-01-12 16:50:20 +01:00
parent b53ac3bf10
commit 84830882c5
8 changed files with 179 additions and 103 deletions

View File

@@ -182,9 +182,9 @@ TSpeedPos::TSpeedPos(TTrack *track, double dist, int flag)
Set(track, dist, flag); Set(track, dist, flag);
}; };
TSpeedPos::TSpeedPos(basic_event *event, double dist, TOrders order) TSpeedPos::TSpeedPos(basic_event *event, double dist, double length, TOrders order)
{ {
Set(event, dist, order); Set(event, dist, length, order);
}; };
void TSpeedPos::Clear() void TSpeedPos::Clear()
@@ -366,13 +366,20 @@ bool TSpeedPos::IsProperSemaphor(TOrders order)
return false; // true gdy zatrzymanie, wtedy nie ma po co skanować dalej return false; // true gdy zatrzymanie, wtedy nie ma po co skanować dalej
} }
bool TSpeedPos::Set(basic_event *event, double dist, TOrders order) bool TSpeedPos::Set(basic_event *event, double dist, double length, TOrders order)
{ // zapamiętanie zdarzenia { // zapamiętanie zdarzenia
fDist = dist; fDist = dist;
iFlags = spEnabled | spEvent; // event+istotny iFlags = spEvent;
evEvent = event; evEvent = event;
vPos = event->input_location(); // współrzędne eventu albo komórki pamięci (zrzutować na tor?) vPos = event->input_location(); // współrzędne eventu albo komórki pamięci (zrzutować na tor?)
CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości if( dist + length >= 0 ) {
iFlags |= spEnabled;
CommandCheck(); // sprawdzenie typu komendy w evencie i określenie prędkości
}
else {
// located behind the tracking consist, don't bother with it
return false;
}
// zależnie od trybu sprawdzenie czy jest tutaj gdzieś semafor lub tarcza manewrowa // zależnie od trybu sprawdzenie czy jest tutaj gdzieś semafor lub tarcza manewrowa
// jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania // jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania
// WriteLog("EventSet: Vel=" + AnsiString(fVelNext) + " iFlags=" + AnsiString(iFlags) + " order="+AnsiString(order)); // WriteLog("EventSet: Vel=" + AnsiString(fVelNext) + " iFlags=" + AnsiString(iFlags) + " order="+AnsiString(order));
@@ -582,6 +589,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
if( newspeedpoint.Set( if( newspeedpoint.Set(
pEvent, pEvent,
GetDistanceToEvent( pTrack, pEvent, fLastDir, fCurrentDistance ), GetDistanceToEvent( pTrack, pEvent, fLastDir, fCurrentDistance ),
fLength,
OrderCurrentGet() ) ) { OrderCurrentGet() ) ) {
fDistance = newspeedpoint.fDist; // jeśli sygnał stop, to nie ma potrzeby dalej skanować fDistance = newspeedpoint.fDist; // jeśli sygnał stop, to nie ma potrzeby dalej skanować
@@ -1911,72 +1919,83 @@ void TController::AutoRewident()
mvOccupied->BrakeOpModeFlag = i; mvOccupied->BrakeOpModeFlag = i;
} }
} }
// teraz zerujemy tabelkę opóźnienia hamowania // teraz zerujemy tabelkę opóźnienia hamowania
for (int i = 0; i < BrakeAccTableSize; ++i) for (int i = 0; i < BrakeAccTableSize; ++i)
{ {
fBrake_a0[i+1] = 0; fBrake_a0[i+1] = 0;
fBrake_a1[i+1] = 0; fBrake_a1[i+1] = 0;
} }
// 4. Przeliczanie siły hamowania
double const velstep = ( mvOccupied->Vmax*0.5 ) / BrakeAccTableSize;
d = pVehicles[0]; // pojazd na czele składu
while (d) {
for( int i = 0; i < BrakeAccTableSize; ++i ) {
fBrake_a0[ i + 1 ] += d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) );
fBrake_a1[ i + 1 ] += d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) );
}
d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła)
}
for (int i = 0; i < BrakeAccTableSize; ++i)
{
fBrake_a1[i+1] -= fBrake_a0[i+1];
fBrake_a0[i+1] /= fMass;
fBrake_a0[i + 1] += 0.001*velstep*(1 + 2 * i);
fBrake_a1[i+1] /= (12*fMass);
}
IsCargoTrain = ( mvOccupied->CategoryFlag == 1 ) && ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 ); if( OrderCurrentGet() & Shunt ) {
IsHeavyCargoTrain = ( true == IsCargoTrain ) && ( fBrake_a0[ 1 ] > 0.4 ); // for uniform behaviour and compatibility with older scenarios set default acceleration table values for shunting
fAccThreshold = (
BrakingInitialLevel = ( mvOccupied->TrainType == dt_EZT ? -0.55 :
IsHeavyCargoTrain ? 1.25 : mvOccupied->TrainType == dt_DMU ? -0.45 :
IsCargoTrain ? 1.25 : -0.2 );
1.00 ); // HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors
if( ( mvOccupied->TrainType == dt_EZT )
BrakingLevelIncrease = ( && ( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) ) {
IsHeavyCargoTrain ? 0.25 : fAccThreshold += 0.10;
IsCargoTrain ? 0.25 :
0.25 );
if( mvOccupied->TrainType == dt_EZT ) {
if( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) {
// HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors
fNominalAccThreshold = std::max( -0.60, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
} }
else {
fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
}
fBrakeReaction = 0.25;
}
else if( mvOccupied->TrainType == dt_DMU ) {
fNominalAccThreshold = std::max( -0.45, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
fBrakeReaction = 0.25;
} }
else if (ustaw > 16) {
fNominalAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 4 * fBrake_a1[ BrakeAccTableSize ]; if( OrderCurrentGet() & Obey_train ) {
fBrakeReaction = 1.00 + fLength*0.004; // 4. Przeliczanie siły hamowania
} double const velstep = ( mvOccupied->Vmax*0.5 ) / BrakeAccTableSize;
else { d = pVehicles[0]; // pojazd na czele składu
fNominalAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 1 * fBrake_a1[ BrakeAccTableSize ]; while (d) {
fBrakeReaction = 1.00 + fLength*0.005; for( int i = 0; i < BrakeAccTableSize; ++i ) {
} fBrake_a0[ i + 1 ] += d->MoverParameters->BrakeForceR( 0.25, velstep*( 1 + 2 * i ) );
fAccThreshold = fNominalAccThreshold; fBrake_a1[ i + 1 ] += d->MoverParameters->BrakeForceR( 1.00, velstep*( 1 + 2 * i ) );
/* }
if( IsHeavyCargoTrain ) { d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła)
// HACK: heavy cargo trains don't activate brakes early enough }
fAccThreshold = std::max( -0.2, fAccThreshold ); for (int i = 0; i < BrakeAccTableSize; ++i)
{
fBrake_a1[i+1] -= fBrake_a0[i+1];
fBrake_a0[i+1] /= fMass;
fBrake_a0[i + 1] += 0.001*velstep*(1 + 2 * i);
fBrake_a1[i+1] /= (12*fMass);
}
IsCargoTrain = ( mvOccupied->CategoryFlag == 1 ) && ( ( mvOccupied->BrakeDelayFlag & bdelay_G ) != 0 );
IsHeavyCargoTrain = ( true == IsCargoTrain ) && ( fBrake_a0[ 1 ] > 0.4 );
BrakingInitialLevel = (
IsHeavyCargoTrain ? 1.25 :
IsCargoTrain ? 1.25 :
1.00 );
BrakingLevelIncrease = (
IsHeavyCargoTrain ? 0.25 :
IsCargoTrain ? 0.25 :
0.25 );
if( mvOccupied->TrainType == dt_EZT ) {
if( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) {
// HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors
fNominalAccThreshold = std::max( -0.60, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
}
else {
fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
}
fBrakeReaction = 0.25;
}
else if( mvOccupied->TrainType == dt_DMU ) {
fNominalAccThreshold = std::max( -0.45, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
fBrakeReaction = 0.25;
}
else if (ustaw > 16) {
fNominalAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 4 * fBrake_a1[ BrakeAccTableSize ];
fBrakeReaction = 1.00 + fLength*0.004;
}
else {
fNominalAccThreshold = -fBrake_a0[ BrakeAccTableSize ] - 1 * fBrake_a1[ BrakeAccTableSize ];
fBrakeReaction = 1.00 + fLength*0.005;
}
fAccThreshold = fNominalAccThreshold;
} }
*/
} }
double TController::ESMVelocity(bool Main) double TController::ESMVelocity(bool Main)
@@ -2854,7 +2873,11 @@ bool TController::IncSpeed()
auto const sufficienttractionforce { std::abs( mvControlling->Ft ) > ( IsHeavyCargoTrain ? 125 : 100 ) * 1000.0 }; auto const sufficienttractionforce { std::abs( mvControlling->Ft ) > ( IsHeavyCargoTrain ? 125 : 100 ) * 1000.0 };
auto const seriesmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 ) }; auto const seriesmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn == 1 ) };
auto const parallelmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) }; auto const parallelmodefieldshunting { ( mvControlling->ScndCtrlPos > 0 ) && ( mvControlling->RList[ mvControlling->MainCtrlPos ].Bn > 1 ) };
auto const useseriesmodevoltage { mvControlling->EnginePowerSource.CollectorParameters.MaxV * ( IsHeavyCargoTrain ? 0.70 : 0.80 ) }; auto const useseriesmodevoltage {
interpolate(
mvControlling->EnginePowerSource.CollectorParameters.MinV,
mvControlling->EnginePowerSource.CollectorParameters.MaxV,
( IsHeavyCargoTrain ? 0.35 : 0.40 ) ) };
auto const useseriesmode = ( auto const useseriesmode = (
( mvControlling->Imax > mvControlling->ImaxLo ) ( mvControlling->Imax > mvControlling->ImaxLo )
|| ( fVoltage < useseriesmodevoltage ) || ( fVoltage < useseriesmodevoltage )
@@ -2885,7 +2908,7 @@ bool TController::IncSpeed()
if( usefieldshunting ) { if( usefieldshunting ) {
// to dać bocznik // to dać bocznik
// engage the shuntfield only if there's sufficient power margin to draw from // engage the shuntfield only if there's sufficient power margin to draw from
auto const sufficientpowermargin { fVoltage - useseriesmodevoltage > ( IsHeavyCargoTrain ? 100.0 : 50.0 ) }; auto const sufficientpowermargin { fVoltage - useseriesmodevoltage > ( IsHeavyCargoTrain ? 100.0 : 75.0 ) };
OK = ( OK = (
sufficientpowermargin ? sufficientpowermargin ?
@@ -2898,7 +2921,14 @@ bool TController::IncSpeed()
mvControlling->DecScndCtrl( 2 ); mvControlling->DecScndCtrl( 2 );
} }
// kręcimy nastawnik jazdy // kręcimy nastawnik jazdy
auto const sufficientpowermargin { fVoltage - useseriesmodevoltage > ( IsHeavyCargoTrain ? 80.0 : 40.0 ) }; // don't draw too much power;
// keep from dropping into series mode when entering/using parallel mode, and from shutting down in the series mode
auto const sufficientpowermargin {
fVoltage - (
mvControlling->RList[ std::min( mvControlling->MainCtrlPos + 1, mvControlling->MainCtrlPosNo ) ].Bn == 1 ?
mvControlling->EnginePowerSource.CollectorParameters.MinV :
useseriesmodevoltage )
> ( IsHeavyCargoTrain ? 80.0 : 60.0 ) };
OK = ( OK = (
( sufficientpowermargin && ( false == mvControlling->DelayCtrlFlag ) ) ? ( sufficientpowermargin && ( false == mvControlling->DelayCtrlFlag ) ) ?
@@ -3909,12 +3939,13 @@ TController::UpdateSituation(double dt) {
p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła)
} }
// crude way to deal with automatic door opening on W4 preventing further ride // HACK: crude way to deal with automatic door opening on W4 preventing further ride
// for human-controlled vehicles with no door control and dynamic brake auto-activating with door open // for human-controlled vehicles with no door control and dynamic brake auto-activating with door open
// TODO: check if this situation still happens and the hack is still needed
if( ( false == AIControllFlag ) if( ( false == AIControllFlag )
&& ( iDrivigFlags & moveDoorOpened ) && ( iDrivigFlags & moveDoorOpened )
&& ( mvOccupied->DoorCloseCtrl != control_t::driver ) && ( mvOccupied->DoorCloseCtrl != control_t::driver )
&& ( mvControlling->MainCtrlPos > 0 ) ) { && ( mvControlling->MainCtrlPos > ( mvControlling->EngineType != TEngineType::DieselEngine ? 0 : 1 ) ) ) { // for diesel 1st position is effectively 0
Doors( false ); Doors( false );
} }
@@ -4013,7 +4044,12 @@ TController::UpdateSituation(double dt) {
} }
} }
auto const useseriesmodevoltage { mvControlling->EnginePowerSource.CollectorParameters.MaxV * ( IsHeavyCargoTrain ? 0.70 : 0.80 ) }; // TODO: refactor this calculation into a subroutine
auto const useseriesmodevoltage {
interpolate(
mvControlling->EnginePowerSource.CollectorParameters.MinV,
mvControlling->EnginePowerSource.CollectorParameters.MaxV,
( IsHeavyCargoTrain ? 0.35 : 0.40 ) ) };
if( fVoltage <= useseriesmodevoltage ) { if( fVoltage <= useseriesmodevoltage ) {
// if the power station is heavily burdened try to reduce the load // if the power station is heavily burdened try to reduce the load
@@ -5865,12 +5901,20 @@ basic_event * TController::CheckTrackEventBackward(double fDirection, TTrack *Tr
{ // sprawdzanie eventu w torze, czy jest sygnałowym - skanowanie do tyłu { // sprawdzanie eventu w torze, czy jest sygnałowym - skanowanie do tyłu
// NOTE: this method returns only one event which meets the conditions, due to limitations in the caller // NOTE: this method returns only one event which meets the conditions, due to limitations in the caller
// TBD, TODO: clean up the caller and return all suitable events, as in theory things will go awry if the track has more than one signal // TBD, TODO: clean up the caller and return all suitable events, as in theory things will go awry if the track has more than one signal
auto const dir{ pVehicles[ 0 ]->VectorFront() * pVehicles[ 0 ]->DirectionGet() };
auto const pos{ pVehicles[ 0 ]->HeadPosition() };
auto const &eventsequence { ( fDirection > 0 ? Track->m_events2 : Track->m_events1 ) }; auto const &eventsequence { ( fDirection > 0 ? Track->m_events2 : Track->m_events1 ) };
for( auto const &event : eventsequence ) { for( auto const &event : eventsequence ) {
if( ( event.second != nullptr ) if( ( event.second != nullptr )
&& ( event.second->m_passive ) && ( event.second->m_passive )
&& ( typeid(*(event.second)) == typeid( getvalues_event ) ) ) { && ( typeid(*(event.second)) == typeid( getvalues_event ) ) ) {
return event.second; // since we're checking for events behind us discard the sources in front of the scanning vehicle
auto const sl{ event.second->input_location() }; // położenie komórki pamięci
auto const sem{ sl - pos }; // wektor do komórki pamięci od końca składu
if( dir.x * sem.x + dir.z * sem.z < 0 ) {
// iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu
return event.second;
}
} }
} }
return nullptr; return nullptr;

View File

@@ -141,7 +141,7 @@ class TSpeedPos
public: public:
TSpeedPos(TTrack *track, double dist, int flag); TSpeedPos(TTrack *track, double dist, int flag);
TSpeedPos(basic_event *event, double dist, TOrders order); TSpeedPos(basic_event *event, double dist, double length, TOrders order);
TSpeedPos() = default; TSpeedPos() = default;
void Clear(); void Clear();
bool Update(); bool Update();
@@ -150,7 +150,7 @@ class TSpeedPos
void void
UpdateDistance( double dist ) { UpdateDistance( double dist ) {
fDist -= dist; } fDist -= dist; }
bool Set(basic_event *e, double d, TOrders order = Wait_for_orders); bool Set(basic_event *e, double d, double length, TOrders order = Wait_for_orders);
void Set(TTrack *t, double d, int f); void Set(TTrack *t, double d, int f);
std::string TableText() const; std::string TableText() const;
std::string GetName() const; std::string GetName() const;

View File

@@ -2782,7 +2782,7 @@ TDynamicObject::update_load_visibility() {
} }
*/ */
auto loadpercentage { ( auto loadpercentage { (
MoverParameters->MaxLoad == 0.0 ? MoverParameters->MaxLoad == 0.f ?
0.0 : 0.0 :
100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) }; 100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) };
auto const sectionloadpercentage { ( auto const sectionloadpercentage { (
@@ -2816,7 +2816,7 @@ TDynamicObject::update_load_offset() {
if( MoverParameters->LoadType.offset_min == 0.f ) { return; } if( MoverParameters->LoadType.offset_min == 0.f ) { return; }
auto const loadpercentage { ( auto const loadpercentage { (
MoverParameters->MaxLoad == 0.0 ? MoverParameters->MaxLoad == 0.f ?
0.0 : 0.0 :
100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) }; 100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) };

View File

@@ -812,10 +812,13 @@ void TMoverParameters::UpdateBatteryVoltage(double dt)
// HACK: allow to draw power also from adjacent converter, applicable for EMUs // HACK: allow to draw power also from adjacent converter, applicable for EMUs
// TODO: expand power cables system to include low voltage power transfers // TODO: expand power cables system to include low voltage power transfers
// HACK: emulate low voltage generator powered directly by the diesel engine
auto const converteractive{ ( auto const converteractive{ (
( ConverterFlag ) ( ConverterFlag )
|| ( ( ( Couplers[ side::front ].CouplingFlag & coupling::permanent ) != 0 ) && Couplers[ side::front ].Connected->ConverterFlag ) || ( ( ( Couplers[ side::front ].CouplingFlag & coupling::permanent ) != 0 ) && Couplers[ side::front ].Connected->ConverterFlag )
|| ( ( ( Couplers[ side::rear ].CouplingFlag & coupling::permanent ) != 0 ) && Couplers[ side::rear ].Connected->ConverterFlag ) ) }; || ( ( ( Couplers[ side::rear ].CouplingFlag & coupling::permanent ) != 0 ) && Couplers[ side::rear ].Connected->ConverterFlag ) )
|| ( ( EngineType == TEngineType::DieselElectric ) && ( true == Mains ) )
|| ( ( EngineType == TEngineType::DieselEngine ) && ( true == Mains ) ) };
if ((NominalBatteryVoltage / BatteryVoltage < 1.22) && Battery) if ((NominalBatteryVoltage / BatteryVoltage < 1.22) && Battery)
{ // 110V { // 110V
@@ -1529,18 +1532,18 @@ void TMoverParameters::WaterPumpCheck( double const Timestep ) {
// water heater status check // water heater status check
void TMoverParameters::WaterHeaterCheck( double const Timestep ) { void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
WaterHeater.is_active = ( WaterHeater.is_active = (
( false == WaterHeater.is_damaged ) ( false == WaterHeater.is_damaged )
&& ( true == Battery ) && ( true == Battery )
&& ( true == WaterHeater.is_enabled ) && ( true == WaterHeater.is_enabled )
&& ( true == WaterHeater.breaker ) && ( true == WaterHeater.breaker )
&& ( ( WaterHeater.is_active ) || ( WaterHeater.config.temp_min < 0 ) || ( dizel_heat.temperatura1 < WaterHeater.config.temp_min ) ) ); && ( ( WaterHeater.is_active ) || ( WaterHeater.config.temp_min < 0 ) || ( dizel_heat.temperatura1 < WaterHeater.config.temp_min ) ) );
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
if( ( WaterHeater.config.temp_max > 0 ) if( ( WaterHeater.config.temp_max > 0 )
&& ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) { && ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) {
WaterHeater.is_active = false; WaterHeater.is_active = false;
@@ -6664,7 +6667,7 @@ TMoverParameters::AssignLoad( std::string const &Name, float const Amount ) {
for( auto const &loadattributes : LoadAttributes ) { for( auto const &loadattributes : LoadAttributes ) {
if( Name == loadattributes.name ) { if( Name == loadattributes.name ) {
LoadType = loadattributes; LoadType = loadattributes;
LoadAmount = Amount; LoadAmount = clamp( Amount, 0.f, MaxLoad ) ;
return true; return true;
} }
} }
@@ -6702,7 +6705,7 @@ bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadn
if( ( LoadAmount <= 0 ) || ( CommandIn.Value1 <= 0 ) ) { if( ( LoadAmount <= 0 ) || ( CommandIn.Value1 <= 0 ) ) {
// pusto lub rozładowano żądaną ilość // pusto lub rozładowano żądaną ilość
LoadStatus = 4; // skończony rozładunek LoadStatus = 4; // skończony rozładunek
LoadAmount = std::max( 0.f, LoadAmount ); //ładunek nie może być ujemny LoadAmount = clamp( LoadAmount, 0.f, MaxLoad); //ładunek nie może być ujemny
} }
if( LoadAmount == 0.f ) { if( LoadAmount == 0.f ) {
AssignLoad(""); // jak nic nie ma, to nie ma też nazwy AssignLoad(""); // jak nic nie ma, to nie ma też nazwy

View File

@@ -448,9 +448,9 @@ PyObject *TTrain::GetTrainState() {
// basic systems state data // basic systems state data
PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) ); PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) );
PyDict_SetItemString( dict, "linebreaker", PyGetBool( mvControlled->Mains ) ); PyDict_SetItemString( dict, "linebreaker", PyGetBool( mvControlled->Mains ) );
PyDict_SetItemString( dict, "converter", PyGetBool( mover->ConverterFlag ) ); PyDict_SetItemString( dict, "converter", PyGetBool( mvControlled->ConverterFlag ) );
PyDict_SetItemString( dict, "converter_overload", PyGetBool( mover->ConvOvldFlag ) ); PyDict_SetItemString( dict, "converter_overload", PyGetBool( mvControlled->ConvOvldFlag ) );
PyDict_SetItemString( dict, "compress", PyGetBool( mover->CompressorFlag ) ); PyDict_SetItemString( dict, "compress", PyGetBool( mvControlled->CompressorFlag ) );
// reverser // reverser
PyDict_SetItemString( dict, "direction", PyGetInt( mover->ActiveDir ) ); PyDict_SetItemString( dict, "direction", PyGetInt( mover->ActiveDir ) );
// throttle // throttle
@@ -463,34 +463,35 @@ PyObject *TTrain::GetTrainState() {
bool const bEP = ( mvControlled->LocHandle->GetCP() > 0.2 ) || ( fEIMParams[ 0 ][ 2 ] > 0.01 ); bool const bEP = ( mvControlled->LocHandle->GetCP() > 0.2 ) || ( fEIMParams[ 0 ][ 2 ] > 0.01 );
PyDict_SetItemString( dict, "dir_brake", PyGetBool( bEP ) ); PyDict_SetItemString( dict, "dir_brake", PyGetBool( bEP ) );
bool bPN; bool bPN;
if( ( typeid( *mvControlled->Hamulec ) == typeid( TLSt ) ) if( ( typeid( *mvOccupied->Hamulec ) == typeid( TLSt ) )
|| ( typeid( *mvControlled->Hamulec ) == typeid( TEStED ) ) ) { || ( typeid( *mvOccupied->Hamulec ) == typeid( TEStED ) ) ) {
TBrake* temp_ham = mvControlled->Hamulec.get(); TBrake* temp_ham = mvOccupied->Hamulec.get();
bPN = ( static_cast<TLSt*>( temp_ham )->GetEDBCP() > 0.2 ); bPN = ( static_cast<TLSt*>( temp_ham )->GetEDBCP() > 0.2 );
} }
else else
bPN = false; bPN = false;
PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) ); PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) );
PyDict_SetItemString( dict, "brake_delay_flag", PyGetInt( mvControlled->BrakeDelayFlag )); PyDict_SetItemString( dict, "brake_delay_flag", PyGetInt( mvOccupied->BrakeDelayFlag ));
PyDict_SetItemString( dict, "brake_op_mode_flag", PyGetInt( mvControlled->BrakeOpModeFlag )); PyDict_SetItemString( dict, "brake_op_mode_flag", PyGetInt( mvOccupied->BrakeOpModeFlag ));
// other controls // other controls
PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) ); PyDict_SetItemString( dict, "ca", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_aware ) ) );
PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) ); PyDict_SetItemString( dict, "shp", PyGetBool( TestFlag( mvOccupied->SecuritySystem.Status, s_active ) ) );
PyDict_SetItemString( dict, "pantpress", PyGetFloat( mvControlled->PantPress ) ); PyDict_SetItemString( dict, "pantpress", PyGetFloat( mvControlled->PantPress ) );
PyDict_SetItemString( dict, "universal3", PyGetBool( InstrumentLightActive ) ); PyDict_SetItemString( dict, "universal3", PyGetBool( InstrumentLightActive ) );
PyDict_SetItemString( dict, "radio_channel", PyGetInt( iRadioChannel ) ); PyDict_SetItemString( dict, "radio_channel", PyGetInt( iRadioChannel ) );
PyDict_SetItemString( dict, "door_lock", PyGetInt( mvOccupied->DoorLockEnabled ) );
// movement data // movement data
PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) ); PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) );
PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) ); PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) );
PyDict_SetItemString( dict, "slipping_wheels", PyGetBool( mover->SlippingWheels ) ); PyDict_SetItemString( dict, "slipping_wheels", PyGetBool( mover->SlippingWheels ) );
PyDict_SetItemString( dict, "sanding", PyGetBool( mover->SandDose ) ); PyDict_SetItemString( dict, "sanding", PyGetBool( mover->SandDose ) );
// electric current data // electric current data
PyDict_SetItemString( dict, "traction_voltage", PyGetFloat( mover->RunningTraction.TractionVoltage ) ); PyDict_SetItemString( dict, "traction_voltage", PyGetFloat( mvControlled->RunningTraction.TractionVoltage ) );
PyDict_SetItemString( dict, "voltage", PyGetFloat( mover->Voltage ) ); PyDict_SetItemString( dict, "voltage", PyGetFloat( mvControlled->Voltage ) );
PyDict_SetItemString( dict, "im", PyGetFloat( mover->Im ) ); PyDict_SetItemString( dict, "im", PyGetFloat( mvControlled->Im ) );
PyDict_SetItemString( dict, "fuse", PyGetBool( mover->FuseFlag ) ); PyDict_SetItemString( dict, "fuse", PyGetBool( mvControlled->FuseFlag ) );
PyDict_SetItemString( dict, "epfuse", PyGetBool( mover->EpFuse ) ); PyDict_SetItemString( dict, "epfuse", PyGetBool( mvOccupied->EpFuse ) );
// induction motor state data // induction motor state data
char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" }; char const *TXTT[ 10 ] = { "fd", "fdt", "fdb", "pd", "pdt", "pdb", "itothv", "1", "2", "3" };
char const *TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" }; char const *TXTC[ 10 ] = { "fr", "frt", "frb", "pr", "prt", "prb", "im", "vm", "ihv", "uhv" };
@@ -575,6 +576,7 @@ PyObject *TTrain::GetTrainState() {
PyDict_SetItemString( dict, "minutes", PyGetInt( simulation::Time.data().wMinute ) ); PyDict_SetItemString( dict, "minutes", PyGetInt( simulation::Time.data().wMinute ) );
PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) ); PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) );
PyDict_SetItemString( dict, "air_temperature", PyGetInt( Global.AirTemperature ) ); PyDict_SetItemString( dict, "air_temperature", PyGetInt( Global.AirTemperature ) );
PyDict_SetItemString( dict, "light_level", PyGetFloat( Global.fLuminance - std::max( 0.f, Global.Overcast - 1.f ) ) );
Application.release_python_lock(); Application.release_python_lock();
return dict; return dict;
@@ -1041,7 +1043,7 @@ void TTrain::OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Co
if( Command.action != GLFW_RELEASE ) { if( Command.action != GLFW_RELEASE ) {
if( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) { if( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) {
Train->mvOccupied->BrakeLevelAdd( 0.1 /*15.0 * Command.time_delta*/ ); Train->mvOccupied->BrakeLevelAdd( 0.1 * Global.fBrakeStep );
} }
else { else {
Train->set_train_brake( Train->mvOccupied->BrakeCtrlPos + Global.fBrakeStep ); Train->set_train_brake( Train->mvOccupied->BrakeCtrlPos + Global.fBrakeStep );
@@ -1054,7 +1056,7 @@ void TTrain::OnCommand_trainbrakedecrease( TTrain *Train, command_data const &Co
if( Command.action != GLFW_RELEASE ) { if( Command.action != GLFW_RELEASE ) {
// press or hold // press or hold
if( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) { if( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) {
Train->mvOccupied->BrakeLevelAdd( -0.1 /*-15.0 * Command.time_delta*/ ); Train->mvOccupied->BrakeLevelAdd( -0.1 * Global.fBrakeStep );
} }
else { else {
Train->set_train_brake( Train->mvOccupied->BrakeCtrlPos - Global.fBrakeStep ); Train->set_train_brake( Train->mvOccupied->BrakeCtrlPos - Global.fBrakeStep );
@@ -4085,14 +4087,14 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command
auto const itemindex = static_cast<int>( Command.command ) - static_cast<int>( user_command::generictoggle0 ); auto const itemindex = static_cast<int>( Command.command ) - static_cast<int>( user_command::generictoggle0 );
auto &item = Train->ggUniversals[ itemindex ]; auto &item = Train->ggUniversals[ itemindex ];
/*
if( item.SubModel == nullptr ) { if( item.SubModel == nullptr ) {
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" ); WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" );
} }
return; return;
} }
*/
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down // only reacting to press, so the switch doesn't flip back and forth if key is held down
if( item.GetDesiredValue() < 0.5 ) { if( item.GetDesiredValue() < 0.5 ) {
@@ -5475,6 +5477,10 @@ bool TTrain::Update( double const Deltatime )
// others // others
btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA ); btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA );
btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ side::front ].is_active ) && ( mvControlled->MotorBlowers[ side::rear ].is_active ) ); btLampkaMotorBlowers.Turn( ( mvControlled->MotorBlowers[ side::front ].is_active ) && ( mvControlled->MotorBlowers[ side::rear ].is_active ) );
// universal devices state indicators
for( auto idx = 0; idx < btUniversals.size(); ++idx ) {
btUniversals[ idx ].Turn( ggUniversals[ idx ].GetValue() > 0.5 );
}
} }
else { else {
// wylaczone // wylaczone
@@ -5530,6 +5536,10 @@ bool TTrain::Update( double const Deltatime )
// others // others
btLampkaMalfunction.Turn( false ); btLampkaMalfunction.Turn( false );
btLampkaMotorBlowers.Turn( false ); btLampkaMotorBlowers.Turn( false );
// universal devices state indicators
for( auto &universal : btUniversals ) {
universal.Turn( false );
}
} }
{ // yB - wskazniki drugiego czlonu { // yB - wskazniki drugiego czlonu
@@ -6184,7 +6194,9 @@ void TTrain::update_sounds_runningnoise( sound_source &Sound ) {
// volume calculation // volume calculation
auto volume = auto volume =
Sound.m_amplitudeoffset Sound.m_amplitudeoffset
+ Sound.m_amplitudefactor * mvOccupied->Vel; + Sound.m_amplitudefactor * interpolate(
mvOccupied->Vel / ( 1 + mvOccupied->Vmax ), 1.0,
0.5 ); // scale base volume between 0.5-1.0
if( std::abs( mvOccupied->nrot ) > 0.01 ) { if( std::abs( mvOccupied->nrot ) > 0.01 ) {
// hamulce wzmagaja halas // hamulce wzmagaja halas
auto const brakeforceratio { ( auto const brakeforceratio { (
@@ -6208,7 +6220,7 @@ void TTrain::update_sounds_runningnoise( sound_source &Sound ) {
interpolate( interpolate(
0.0, 1.0, 0.0, 1.0,
clamp( clamp(
mvOccupied->Vel / 40.0, mvOccupied->Vel / 25.0,
0.0, 1.0 ) ); 0.0, 1.0 ) );
} }
@@ -7075,6 +7087,9 @@ void TTrain::clear_cab_controls()
btLampkaHamulecReczny.Clear(); btLampkaHamulecReczny.Clear();
btLampkaBlokadaDrzwi.Clear(); btLampkaBlokadaDrzwi.Clear();
btLampkaDoorLockOff.Clear(); btLampkaDoorLockOff.Clear();
for( auto &universal : btUniversals ) {
universal.Clear();
}
btInstrumentLight.Clear(); btInstrumentLight.Clear();
btDashboardLight.Clear(); btDashboardLight.Clear();
btTimetableLight.Clear(); btTimetableLight.Clear();
@@ -7507,7 +7522,17 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
{ "i-rearrightend:", btLampkaRearRightEndLight }, { "i-rearrightend:", btLampkaRearRightEndLight },
{ "i-dashboardlight:", btDashboardLight }, { "i-dashboardlight:", btDashboardLight },
{ "i-timetablelight:", btTimetableLight }, { "i-timetablelight:", btTimetableLight },
{ "i-cablight:", btCabLight } { "i-cablight:", btCabLight },
{ "i-universal0:", btUniversals[ 0 ] },
{ "i-universal1:", btUniversals[ 1 ] },
{ "i-universal2:", btUniversals[ 2 ] },
{ "i-universal3:", btUniversals[ 3 ] },
{ "i-universal4:", btUniversals[ 4 ] },
{ "i-universal5:", btUniversals[ 5 ] },
{ "i-universal6:", btUniversals[ 6 ] },
{ "i-universal7:", btUniversals[ 7 ] },
{ "i-universal8:", btUniversals[ 8 ] },
{ "i-universal9:", btUniversals[ 9 ] }
}; };
auto lookup = lights.find( Label ); auto lookup = lights.find( Label );
if( lookup != lights.end() ) { if( lookup != lights.end() ) {

View File

@@ -505,6 +505,7 @@ public: // reszta może by?publiczna
TButton btLampkaHamowanie2zes; TButton btLampkaHamowanie2zes;
TButton btLampkaOpory; TButton btLampkaOpory;
TButton btLampkaWysRozr; TButton btLampkaWysRozr;
std::array<TButton, 10> btUniversals; // NOTE: temporary arrangement until we have dynamically built control table
TButton btInstrumentLight; TButton btInstrumentLight;
TButton btDashboardLight; TButton btDashboardLight;
TButton btTimetableLight; TButton btTimetableLight;

View File

@@ -1133,6 +1133,7 @@ driver_mode::InOutKey()
if( train == nullptr ) { if( train == nullptr ) {
FreeFlyModeFlag = true; // nadal poza kabiną FreeFlyModeFlag = true; // nadal poza kabiną
Camera.m_owner = nullptr; // detach camera from the vehicle
return; return;
} }

View File

@@ -60,17 +60,19 @@ opengl_material::deserialize_mapping( cParser &Input, int const Priority, bool c
} }
else if( ( key == "texture1:" ) else if( ( key == "texture1:" )
|| ( key == "texture_diffuse:" ) ) { || ( key == "texture_diffuse:" ) ) {
auto const value { deserialize_random_set( Input ) };
if( ( texture1 == null_handle ) if( ( texture1 == null_handle )
|| ( Priority > priority1 ) ) { || ( Priority > priority1 ) ) {
texture1 = GfxRenderer.Fetch_Texture( deserialize_random_set( Input ), Loadnow ); texture1 = GfxRenderer.Fetch_Texture( value, Loadnow );
priority1 = Priority; priority1 = Priority;
} }
} }
else if( ( key == "texture2:" ) else if( ( key == "texture2:" )
|| ( key == "texture_normalmap:" ) ) { || ( key == "texture_normalmap:" ) ) {
auto const value { deserialize_random_set( Input ) };
if( ( texture2 == null_handle ) if( ( texture2 == null_handle )
|| ( Priority > priority2 ) ) { || ( Priority > priority2 ) ) {
texture2 = GfxRenderer.Fetch_Texture( deserialize_random_set( Input ), Loadnow ); texture2 = GfxRenderer.Fetch_Texture( value, Loadnow );
priority2 = Priority; priority2 = Priority;
} }
} }