16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-24 09:49: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);
};
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()
@@ -366,13 +366,20 @@ bool TSpeedPos::IsProperSemaphor(TOrders order)
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
fDist = dist;
iFlags = spEnabled | spEvent; // event+istotny
iFlags = spEvent;
evEvent = event;
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
// jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania
// 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(
pEvent,
GetDistanceToEvent( pTrack, pEvent, fLastDir, fCurrentDistance ),
fLength,
OrderCurrentGet() ) ) {
fDistance = newspeedpoint.fDist; // jeśli sygnał stop, to nie ma potrzeby dalej skanować
@@ -1911,72 +1919,83 @@ void TController::AutoRewident()
mvOccupied->BrakeOpModeFlag = i;
}
}
// teraz zerujemy tabelkę opóźnienia hamowania
for (int i = 0; i < BrakeAccTableSize; ++i)
{
fBrake_a0[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 );
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 ] );
if( OrderCurrentGet() & Shunt ) {
// for uniform behaviour and compatibility with older scenarios set default acceleration table values for shunting
fAccThreshold = (
mvOccupied->TrainType == dt_EZT ? -0.55 :
mvOccupied->TrainType == dt_DMU ? -0.45 :
-0.2 );
// HACK: emu with induction motors need to start their braking a bit sooner than the ones with series motors
if( ( mvOccupied->TrainType == dt_EZT )
&& ( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) ) {
fAccThreshold += 0.10;
}
else {
fNominalAccThreshold = std::max( -0.75, -fBrake_a0[ BrakeAccTableSize ] - 8 * fBrake_a1[ BrakeAccTableSize ] );
}
if( OrderCurrentGet() & Obey_train ) {
// 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 );
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;
}
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;
}
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;
/*
if( IsHeavyCargoTrain ) {
// HACK: heavy cargo trains don't activate brakes early enough
fAccThreshold = std::max( -0.2, fAccThreshold );
}
*/
}
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 seriesmodefieldshunting { ( 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 = (
( mvControlling->Imax > mvControlling->ImaxLo )
|| ( fVoltage < useseriesmodevoltage )
@@ -2885,7 +2908,7 @@ bool TController::IncSpeed()
if( usefieldshunting ) {
// to dać bocznik
// 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 = (
sufficientpowermargin ?
@@ -2898,7 +2921,14 @@ bool TController::IncSpeed()
mvControlling->DecScndCtrl( 2 );
}
// 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 = (
( 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)
}
// 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
// TODO: check if this situation still happens and the hack is still needed
if( ( false == AIControllFlag )
&& ( iDrivigFlags & moveDoorOpened )
&& ( 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 );
}
@@ -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 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
// 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
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 ) };
for( auto const &event : eventsequence ) {
if( ( event.second != nullptr )
&& ( event.second->m_passive )
&& ( 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;

View File

@@ -141,7 +141,7 @@ class TSpeedPos
public:
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;
void Clear();
bool Update();
@@ -150,7 +150,7 @@ class TSpeedPos
void
UpdateDistance( double 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);
std::string TableText() const;
std::string GetName() const;

View File

@@ -2782,7 +2782,7 @@ TDynamicObject::update_load_visibility() {
}
*/
auto loadpercentage { (
MoverParameters->MaxLoad == 0.0 ?
MoverParameters->MaxLoad == 0.f ?
0.0 :
100.0 * MoverParameters->LoadAmount / MoverParameters->MaxLoad ) };
auto const sectionloadpercentage { (
@@ -2816,7 +2816,7 @@ TDynamicObject::update_load_offset() {
if( MoverParameters->LoadType.offset_min == 0.f ) { return; }
auto const loadpercentage { (
MoverParameters->MaxLoad == 0.0 ?
MoverParameters->MaxLoad == 0.f ?
0.0 :
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
// 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{ (
( 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)
{ // 110V
@@ -1529,11 +1532,6 @@ void TMoverParameters::WaterPumpCheck( double const Timestep ) {
// water heater status check
void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
WaterHeater.is_damaged = (
( true == WaterHeater.is_damaged )
|| ( ( true == WaterHeater.is_active )
&& ( false == WaterPump.is_active ) ) );
WaterHeater.is_active = (
( false == WaterHeater.is_damaged )
&& ( true == Battery )
@@ -1541,6 +1539,11 @@ void TMoverParameters::WaterHeaterCheck( double const Timestep ) {
&& ( true == WaterHeater.breaker )
&& ( ( 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 )
&& ( dizel_heat.temperatura1 > WaterHeater.config.temp_max ) ) {
WaterHeater.is_active = false;
@@ -6664,7 +6667,7 @@ TMoverParameters::AssignLoad( std::string const &Name, float const Amount ) {
for( auto const &loadattributes : LoadAttributes ) {
if( Name == loadattributes.name ) {
LoadType = loadattributes;
LoadAmount = Amount;
LoadAmount = clamp( Amount, 0.f, MaxLoad ) ;
return true;
}
}
@@ -6702,7 +6705,7 @@ bool TMoverParameters::LoadingDone(double const LSpeed, std::string const &Loadn
if( ( LoadAmount <= 0 ) || ( CommandIn.Value1 <= 0 ) ) {
// pusto lub rozładowano żądaną ilość
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 ) {
AssignLoad(""); // jak nic nie ma, to nie ma też nazwy

View File

@@ -448,9 +448,9 @@ PyObject *TTrain::GetTrainState() {
// basic systems state data
PyDict_SetItemString( dict, "battery", PyGetBool( mvControlled->Battery ) );
PyDict_SetItemString( dict, "linebreaker", PyGetBool( mvControlled->Mains ) );
PyDict_SetItemString( dict, "converter", PyGetBool( mover->ConverterFlag ) );
PyDict_SetItemString( dict, "converter_overload", PyGetBool( mover->ConvOvldFlag ) );
PyDict_SetItemString( dict, "compress", PyGetBool( mover->CompressorFlag ) );
PyDict_SetItemString( dict, "converter", PyGetBool( mvControlled->ConverterFlag ) );
PyDict_SetItemString( dict, "converter_overload", PyGetBool( mvControlled->ConvOvldFlag ) );
PyDict_SetItemString( dict, "compress", PyGetBool( mvControlled->CompressorFlag ) );
// reverser
PyDict_SetItemString( dict, "direction", PyGetInt( mover->ActiveDir ) );
// throttle
@@ -463,34 +463,35 @@ PyObject *TTrain::GetTrainState() {
bool const bEP = ( mvControlled->LocHandle->GetCP() > 0.2 ) || ( fEIMParams[ 0 ][ 2 ] > 0.01 );
PyDict_SetItemString( dict, "dir_brake", PyGetBool( bEP ) );
bool bPN;
if( ( typeid( *mvControlled->Hamulec ) == typeid( TLSt ) )
|| ( typeid( *mvControlled->Hamulec ) == typeid( TEStED ) ) ) {
if( ( typeid( *mvOccupied->Hamulec ) == typeid( TLSt ) )
|| ( 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 );
}
else
bPN = false;
PyDict_SetItemString( dict, "indir_brake", PyGetBool( bPN ) );
PyDict_SetItemString( dict, "brake_delay_flag", PyGetInt( mvControlled->BrakeDelayFlag ));
PyDict_SetItemString( dict, "brake_op_mode_flag", PyGetInt( mvControlled->BrakeOpModeFlag ));
PyDict_SetItemString( dict, "brake_delay_flag", PyGetInt( mvOccupied->BrakeDelayFlag ));
PyDict_SetItemString( dict, "brake_op_mode_flag", PyGetInt( mvOccupied->BrakeOpModeFlag ));
// other controls
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, "pantpress", PyGetFloat( mvControlled->PantPress ) );
PyDict_SetItemString( dict, "universal3", PyGetBool( InstrumentLightActive ) );
PyDict_SetItemString( dict, "radio_channel", PyGetInt( iRadioChannel ) );
PyDict_SetItemString( dict, "door_lock", PyGetInt( mvOccupied->DoorLockEnabled ) );
// movement data
PyDict_SetItemString( dict, "velocity", PyGetFloat( mover->Vel ) );
PyDict_SetItemString( dict, "tractionforce", PyGetFloat( mover->Ft ) );
PyDict_SetItemString( dict, "slipping_wheels", PyGetBool( mover->SlippingWheels ) );
PyDict_SetItemString( dict, "sanding", PyGetBool( mover->SandDose ) );
// electric current data
PyDict_SetItemString( dict, "traction_voltage", PyGetFloat( mover->RunningTraction.TractionVoltage ) );
PyDict_SetItemString( dict, "voltage", PyGetFloat( mover->Voltage ) );
PyDict_SetItemString( dict, "im", PyGetFloat( mover->Im ) );
PyDict_SetItemString( dict, "fuse", PyGetBool( mover->FuseFlag ) );
PyDict_SetItemString( dict, "epfuse", PyGetBool( mover->EpFuse ) );
PyDict_SetItemString( dict, "traction_voltage", PyGetFloat( mvControlled->RunningTraction.TractionVoltage ) );
PyDict_SetItemString( dict, "voltage", PyGetFloat( mvControlled->Voltage ) );
PyDict_SetItemString( dict, "im", PyGetFloat( mvControlled->Im ) );
PyDict_SetItemString( dict, "fuse", PyGetBool( mvControlled->FuseFlag ) );
PyDict_SetItemString( dict, "epfuse", PyGetBool( mvOccupied->EpFuse ) );
// induction motor state data
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" };
@@ -575,6 +576,7 @@ PyObject *TTrain::GetTrainState() {
PyDict_SetItemString( dict, "minutes", PyGetInt( simulation::Time.data().wMinute ) );
PyDict_SetItemString( dict, "seconds", PyGetInt( simulation::Time.second() ) );
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();
return dict;
@@ -1041,7 +1043,7 @@ void TTrain::OnCommand_trainbrakeincrease( TTrain *Train, command_data const &Co
if( Command.action != GLFW_RELEASE ) {
if( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) {
Train->mvOccupied->BrakeLevelAdd( 0.1 /*15.0 * Command.time_delta*/ );
Train->mvOccupied->BrakeLevelAdd( 0.1 * Global.fBrakeStep );
}
else {
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 ) {
// press or hold
if( Train->mvOccupied->BrakeHandle == TBrakeHandle::FV4a ) {
Train->mvOccupied->BrakeLevelAdd( -0.1 /*-15.0 * Command.time_delta*/ );
Train->mvOccupied->BrakeLevelAdd( -0.1 * Global.fBrakeStep );
}
else {
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 &item = Train->ggUniversals[ itemindex ];
/*
if( item.SubModel == nullptr ) {
if( Command.action == GLFW_PRESS ) {
WriteLog( "Train generic item " + std::to_string( itemindex ) + " is missing, or wasn't defined" );
}
return;
}
*/
if( Command.action == GLFW_PRESS ) {
// only reacting to press, so the switch doesn't flip back and forth if key is held down
if( item.GetDesiredValue() < 0.5 ) {
@@ -5475,6 +5477,10 @@ bool TTrain::Update( double const Deltatime )
// others
btLampkaMalfunction.Turn( mvControlled->dizel_heat.PA );
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 {
// wylaczone
@@ -5530,6 +5536,10 @@ bool TTrain::Update( double const Deltatime )
// others
btLampkaMalfunction.Turn( false );
btLampkaMotorBlowers.Turn( false );
// universal devices state indicators
for( auto &universal : btUniversals ) {
universal.Turn( false );
}
}
{ // yB - wskazniki drugiego czlonu
@@ -6184,7 +6194,9 @@ void TTrain::update_sounds_runningnoise( sound_source &Sound ) {
// volume calculation
auto volume =
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 ) {
// hamulce wzmagaja halas
auto const brakeforceratio { (
@@ -6208,7 +6220,7 @@ void TTrain::update_sounds_runningnoise( sound_source &Sound ) {
interpolate(
0.0, 1.0,
clamp(
mvOccupied->Vel / 40.0,
mvOccupied->Vel / 25.0,
0.0, 1.0 ) );
}
@@ -7075,6 +7087,9 @@ void TTrain::clear_cab_controls()
btLampkaHamulecReczny.Clear();
btLampkaBlokadaDrzwi.Clear();
btLampkaDoorLockOff.Clear();
for( auto &universal : btUniversals ) {
universal.Clear();
}
btInstrumentLight.Clear();
btDashboardLight.Clear();
btTimetableLight.Clear();
@@ -7507,7 +7522,17 @@ bool TTrain::initialize_button(cParser &Parser, std::string const &Label, int co
{ "i-rearrightend:", btLampkaRearRightEndLight },
{ "i-dashboardlight:", btDashboardLight },
{ "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 );
if( lookup != lights.end() ) {

View File

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

View File

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

View File

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