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

build 210324. event queue text filter enhancement, contextual uncoupling sounds, parameter support for python screens, radio and odometer state exposed to python scripts, configurable audio volume when paused, skydome color calculation tweak, fog color calculation tweak, doorstep cab control enhancement, tempomat cab control enhancement, pantograph selector preset list support, minor bug fixes

This commit is contained in:
tmj-fstate
2021-03-24 22:00:23 +01:00
parent c8169fa1ee
commit 195b7cb17b
17 changed files with 383 additions and 202 deletions

View File

@@ -964,7 +964,9 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
VelLimitLastDist.second = d + point.trTrack->Length() + fLength; VelLimitLastDist.second = d + point.trTrack->Length() + fLength;
} }
else if( VelLimitLastDist.second > 0 ) { // the speed limit can potentially start afterwards, so don't mark it as broken too soon else if( VelLimitLastDist.second > 0 ) { // the speed limit can potentially start afterwards, so don't mark it as broken too soon
speedlimitiscontinuous = false; if( ( point.iFlags & ( spSwitch | spPassengerStopPoint ) ) == 0 ) {
speedlimitiscontinuous = false;
}
} }
if( false == railwaytrackend ) { if( false == railwaytrackend ) {
continue; // i tyle wystarczy continue; // i tyle wystarczy
@@ -1213,7 +1215,7 @@ TController::TableUpdateStopPoint( TCommandType &Command, TSpeedPos &Point, doub
//jeśli nie widzi następnego sygnału ustawia dotychczasową //jeśli nie widzi następnego sygnału ustawia dotychczasową
eSignNext = Point.evEvent; eSignNext = Point.evEvent;
} }
if( mvOccupied->Vel > 0.3 ) { if( mvOccupied->Vel > EU07_AI_MOVEMENT ) {
// jeśli jedzie (nie trzeba czekać, aż się drgania wytłumią - drzwi zamykane od 1.0) to będzie zatrzymanie // jeśli jedzie (nie trzeba czekać, aż się drgania wytłumią - drzwi zamykane od 1.0) to będzie zatrzymanie
Point.fVelNext = 0; Point.fVelNext = 0;
// potentially announce pending stop // potentially announce pending stop
@@ -1540,7 +1542,7 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo
Velocity = 0.0; Velocity = 0.0;
} }
else { else {
VelSignalNext - Point.fVelNext; VelSignalNext = Point.fVelNext;
if( Velocity < 0 ) { if( Velocity < 0 ) {
Velocity = fVelMax; Velocity = fVelMax;
VelSignal = fVelMax; VelSignal = fVelMax;
@@ -2510,10 +2512,8 @@ bool TController::CheckVehicles(TOrders user)
*/ */
} }
// Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61 // detect push-pull train configurations and mark them accordingly
if( ( is_emu() ) if( pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::control ) ) {
|| ( is_dmu() )
|| ( iVehicles == 1 ) ) {
// zmiana czoła przez zmianę kabiny // zmiana czoła przez zmianę kabiny
iDrivigFlags |= movePushPull; iDrivigFlags |= movePushPull;
} }
@@ -2540,7 +2540,7 @@ void TController::Lights(int head, int rear)
void TController::DirectionInitial() void TController::DirectionInitial()
{ // ustawienie kierunku po wczytaniu trainset (może jechać na wstecznym { // ustawienie kierunku po wczytaniu trainset (może jechać na wstecznym
mvOccupied->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) mvOccupied->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
if (mvOccupied->Vel > 0.0) if (mvOccupied->Vel > EU07_AI_NOMOVEMENT)
{ // jeśli na starcie jedzie { // jeśli na starcie jedzie
iDirection = iDirectionOrder = iDirection = iDirectionOrder =
(mvOccupied->V > 0 ? 1 : -1); // początkowa prędkość wymusza kierunek jazdy (mvOccupied->V > 0 ? 1 : -1); // początkowa prędkość wymusza kierunek jazdy
@@ -2825,7 +2825,7 @@ bool TController::ReleaseEngine() {
} }
*/ */
// don't bother with the rest until we're standing still // don't bother with the rest until we're standing still
if( mvOccupied->Vel > 0.01 ) { return false; } if( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) { return false; }
LastReactionTime = 0.0; LastReactionTime = 0.0;
ReactionTime = PrepareTime; ReactionTime = PrepareTime;
@@ -3248,7 +3248,7 @@ bool TController::DecBrakeEIM()
{ {
case 0: { case 0: {
if( mvOccupied->MED_amax != 9.81 ) { if( mvOccupied->MED_amax != 9.81 ) {
auto const desiredacceleration { ( mvOccupied->Vel > 0.01 ? AccDesired : std::max( 0.0, AccDesired ) ) }; auto const desiredacceleration { ( mvOccupied->Vel > EU07_AI_NOMOVEMENT ? AccDesired : std::max( 0.0, AccDesired ) ) };
auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * desiredacceleration / mvOccupied->MED_amax, 0.0, 1.0 ) }; auto const brakeposition { clamp( -1.0 * mvOccupied->AIHintLocalBrakeAccFactor * desiredacceleration / mvOccupied->MED_amax, 0.0, 1.0 ) };
OK = ( brakeposition != mvOccupied->LocalBrakePosA ); OK = ( brakeposition != mvOccupied->LocalBrakePosA );
mvOccupied->LocalBrakePosA = brakeposition; mvOccupied->LocalBrakePosA = brakeposition;
@@ -3684,7 +3684,7 @@ void TController::SpeedSet() {
else { else {
// jak ma jechać // jak ma jechać
if( fActionTime < 0.0 ) { break; } if( fActionTime < 0.0 ) { break; }
if( fReady > ( mvOccupied->Vel > 5.0 ? 0.5 : 0.4 ) ) { break; } if( false == Ready ) { break; }
if( mvOccupied->DirActive > 0 ) { if( mvOccupied->DirActive > 0 ) {
mvOccupied->DirectionForward(); //żeby EN57 jechały na drugiej nastawie mvOccupied->DirectionForward(); //żeby EN57 jechały na drugiej nastawie
@@ -4210,7 +4210,7 @@ void TController::Doors( bool const Open, int const Side ) {
if( ( true == ismanualdoor ) if( ( true == ismanualdoor )
&& ( ( vehicle->LoadExchangeTime() == 0.f ) && ( ( vehicle->LoadExchangeTime() == 0.f )
|| ( vehicle->MoverParameters->Vel > 0.1 ) ) ) { || ( vehicle->MoverParameters->Vel > EU07_AI_MOVEMENT ) ) ) {
vehicle->MoverParameters->OperateDoors( side::right, false, range_t::local ); vehicle->MoverParameters->OperateDoors( side::right, false, range_t::local );
vehicle->MoverParameters->OperateDoors( side::left, false, range_t::local ); vehicle->MoverParameters->OperateDoors( side::left, false, range_t::local );
} }
@@ -4535,7 +4535,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
OrderNext(o); // to samo robić po zmianie OrderNext(o); // to samo robić po zmianie
else if (!o) // jeśli wcześniej było czekanie else if (!o) // jeśli wcześniej było czekanie
OrderNext(Shunt); // to dalej jazda manewrowa OrderNext(Shunt); // to dalej jazda manewrowa
if (mvOccupied->Vel >= 1.0) // jeśli jedzie if (mvOccupied->Vel >= EU07_AI_MOVEMENT) // jeśli jedzie
iDrivigFlags &= ~moveStartHorn; // to bez trąbienia po ruszeniu z zatrzymania iDrivigFlags &= ~moveStartHorn; // to bez trąbienia po ruszeniu z zatrzymania
// Change_direction wykona się samo i następnie przejdzie do kolejnej komendy // Change_direction wykona się samo i następnie przejdzie do kolejnej komendy
return true; return true;
@@ -4795,7 +4795,7 @@ TController::Update( double const Timedelta ) {
auto const awarenessrange { auto const awarenessrange {
std::max( std::max(
750.0, 750.0,
mvOccupied->Vel > 5.0 ? mvOccupied->Vel > EU07_AI_MOVEMENT ?
400 + fBrakeDist : 400 + fBrakeDist :
30.0 * fDriverDist ) }; // 1500m dla stojących pociągów; 30.0 * fDriverDist ) }; // 1500m dla stojących pociągów;
if( is_active() ) { if( is_active() ) {
@@ -4893,8 +4893,9 @@ TController::PrepareDirection() {
if( iDirection == 0 ) { if( iDirection == 0 ) {
// jeśli nie ma ustalonego kierunku // jeśli nie ma ustalonego kierunku
if( mvOccupied->Vel < 0.01 ) { // ustalenie kierunku, gdy stoi if( mvOccupied->Vel < EU07_AI_NOMOVEMENT ) { // ustalenie kierunku, gdy stoi
iDirection = mvOccupied->CabActive; // wg wybranej kabiny iDirection = mvOccupied->CabActive; // wg wybranej kabiny
/*
if( iDirection == 0 ) { if( iDirection == 0 ) {
// jeśli nie ma ustalonego kierunku // jeśli nie ma ustalonego kierunku
if( mvOccupied->Couplers[ end::rear ].Connected == nullptr ) { if( mvOccupied->Couplers[ end::rear ].Connected == nullptr ) {
@@ -4906,6 +4907,7 @@ TController::PrepareDirection() {
iDirection = 1; // jazda w kierunku sprzęgu 0 iDirection = 1; // jazda w kierunku sprzęgu 0
} }
} }
*/
} }
else { else {
// ustalenie kierunku, gdy jedzie // ustalenie kierunku, gdy jedzie
@@ -5354,7 +5356,7 @@ TCommandType TController::BackwardScan( double const Range )
} }
else { else {
if( ( scandist > fMinProximityDist ) if( ( scandist > fMinProximityDist )
&& ( ( mvOccupied->Vel > 0.0 ) && ( ( mvOccupied->Vel > EU07_AI_NOMOVEMENT )
&& ( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) == 0 ) ) ) { && ( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) == 0 ) ) ) {
// jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości
// jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył
@@ -5393,12 +5395,12 @@ TCommandType TController::BackwardScan( double const Range )
if (move ? true : e->input_command() == TCommandType::cm_ShuntVelocity) if (move ? true : e->input_command() == TCommandType::cm_ShuntVelocity)
{ // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1 { // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1
if ((scandist > fMinProximityDist) && if ((scandist > fMinProximityDist) &&
(mvOccupied->Vel > 0.0) || (vmechmax == 0.0) ) (mvOccupied->Vel > EU07_AI_NOMOVEMENT) || (vmechmax == 0.0) )
{ // jeśli tarcza jest daleko, to: { // jeśli tarcza jest daleko, to:
//- jesli pojazd jedzie, to informujemy o zmianie prędkości //- jesli pojazd jedzie, to informujemy o zmianie prędkości
//- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą //- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą
// tarczę // tarczę
if (mvOccupied->Vel > 0.0) // tylko jeśli jedzie if (mvOccupied->Vel > EU07_AI_NOMOVEMENT) // tylko jeśli jedzie
{ // Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl); { // Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl);
#if LOGBACKSCAN #if LOGBACKSCAN
// WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" // WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+"
@@ -5907,7 +5909,7 @@ TController::determine_consist_state() {
fAccGravity /= fMass; fAccGravity /= fMass;
{ {
auto absaccs { fAccGravity }; // Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji auto absaccs { fAccGravity }; // Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji
if( mvOccupied->Vel > 0.01 ) { if( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) {
absaccs = 0; absaccs = 0;
auto *d = pVehicles[ end::front ]; // pojazd na czele składu auto *d = pVehicles[ end::front ]; // pojazd na czele składu
while( d ) { while( d ) {
@@ -5939,7 +5941,7 @@ TController::determine_consist_state() {
if( has_diesel_engine() ) { if( has_diesel_engine() ) {
Ready = ( Ready = (
( vehicle->Vel > 0.5 ) // already moving ( vehicle->Vel > EU07_AI_MOVEMENT ) // already moving
|| ( false == vehicle->Mains ) // deadweight vehicle || ( false == vehicle->Mains ) // deadweight vehicle
|| ( vehicle->enrot > 0.8 * ( || ( vehicle->enrot > 0.8 * (
vehicle->EngineType == TEngineType::DieselEngine ? vehicle->EngineType == TEngineType::DieselEngine ?
@@ -6001,7 +6003,7 @@ TController::control_pantographs() {
|| ( is_emu() ) // special case || ( is_emu() ) // special case
|| ( mvControlling->TrainType == dt_ET41 ) }; // special case || ( mvControlling->TrainType == dt_ET41 ) }; // special case
if( mvOccupied->Vel > 0.05 ) { if( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) {
if( ( fOverhead2 >= 0.0 ) || iOverheadZero ) { if( ( fOverhead2 >= 0.0 ) || iOverheadZero ) {
// jeśli jazda bezprądowa albo z opuszczonym pantografem // jeśli jazda bezprądowa albo z opuszczonym pantografem
@@ -6116,7 +6118,7 @@ TController::control_horns( double const Timedelta ) {
cue_action( locale::string::driver_hint_hornoff ); // a tu się kończy cue_action( locale::string::driver_hint_hornoff ); // a tu się kończy
} }
} }
if( mvOccupied->Vel >= 5.0 ) { if( mvOccupied->Vel > EU07_AI_MOVEMENT ) {
// jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy // jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy
iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie
iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem
@@ -6292,7 +6294,7 @@ TController::control_doors() {
if( false == doors_open() ) { return; } if( false == doors_open() ) { return; }
// jeżeli jedzie // jeżeli jedzie
// nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości
if( mvOccupied->Vel > 1.0 ) { if( mvOccupied->Vel > EU07_AI_MOVEMENT ) {
Doors( false ); Doors( false );
return; return;
} }
@@ -6600,25 +6602,30 @@ TController::check_departure() {
void void
TController::UpdateChangeDirection() { TController::UpdateChangeDirection() {
// TODO: rework into driver mode independent routine // TODO: rework into driver mode independent routine
if( ( true == AIControllFlag) if( false == TestFlag( OrderCurrentGet(), Change_direction ) ) { return; }
&& ( true == TestFlag( OrderCurrentGet(), Change_direction ) ) ) {
if( true == AIControllFlag ) {
// sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą) // sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą)
if( mvOccupied->Vel < 0.1 ) { if( mvOccupied->Vel < EU07_AI_NOMOVEMENT ) {
// jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon // jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon
Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI
PrepareEngine(); } // Change_direction (tylko dla AI)
JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo Obey_train) }
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) { // shared part of the routine, implement if direction matches what was requested
// jeśli dalej mamy manewry if( ( mvOccupied->Vel < EU07_AI_NOMOVEMENT )
if( false == TestFlag( iDrivigFlags, moveStopHere ) ) { && ( iDirection == iDirectionOrder ) ) {
// o ile nie ma stać w miejscu, PrepareEngine();
// jechać od razu w przeciwną stronę i nie trąbić z tego tytułu: JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo Obey_train)
iDrivigFlags &= ~moveStartHorn; if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) {
SetVelocity( fShuntVelocity, fShuntVelocity ); // jeśli dalej mamy manewry
} if( false == TestFlag( iDrivigFlags, moveStopHere ) ) {
// o ile nie ma stać w miejscu,
// jechać od razu w przeciwną stronę i nie trąbić z tego tytułu:
iDrivigFlags &= ~moveStartHorn;
SetVelocity( fShuntVelocity, fShuntVelocity );
} }
} }
} // Change_direction (tylko dla AI) }
} }
void void
@@ -7116,7 +7123,7 @@ TController::adjust_desired_speed_for_obstacles() {
} }
} }
ReactionTime = ( ReactionTime = (
mvOccupied->Vel > 0.01 ? mvOccupied->Vel > EU07_AI_NOMOVEMENT ?
0.1 : // orientuj się, bo jest goraco 0.1 : // orientuj się, bo jest goraco
2.0 ); // we're already standing still, so take it easy 2.0 ); // we're already standing still, so take it easy
} }
@@ -7225,7 +7232,7 @@ TController::adjust_desired_speed_for_target_speed( double const Range ) {
&& ( ActualProximityDist <= Range ) && ( ActualProximityDist <= Range )
&& ( vel >= VelNext ) ) { && ( vel >= VelNext ) ) {
// gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu // gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu
if (vel > 0.0) { if (vel > EU07_AI_NOMOVEMENT) {
// jeśli jedzie // jeśli jedzie
if( ( vel < VelNext ) if( ( vel < VelNext )
&& ( ActualProximityDist > fMaxProximityDist * ( 1.0 + 0.1 * vel ) ) ) { && ( ActualProximityDist > fMaxProximityDist * ( 1.0 + 0.1 * vel ) ) ) {
@@ -7402,7 +7409,7 @@ TController::adjust_desired_speed_for_current_speed() {
clamp( VelDesired - speedestimate, 0.0, fVelMinus ) / fVelMinus ) ); clamp( VelDesired - speedestimate, 0.0, fVelMinus ) / fVelMinus ) );
} }
// final tweaks // final tweaks
if( vel > 0.1 ) { if( vel > EU07_AI_NOMOVEMENT ) {
// going downhill also take into account impact of gravity // going downhill also take into account impact of gravity
AccDesired -= fAccGravity; AccDesired -= fAccGravity;
// HACK: if the max allowed speed was exceeded something went wrong; brake harder // HACK: if the max allowed speed was exceeded something went wrong; brake harder
@@ -7450,7 +7457,7 @@ TController::adjust_desired_speed_for_current_speed() {
if( vel < VelDesired ) { if( vel < VelDesired ) {
// don't adjust acceleration when going above current target speed // don't adjust acceleration when going above current target speed
if( -AccDesired * BrakeAccFactor() < ( if( -AccDesired * BrakeAccFactor() < (
( ( fReady > ( IsHeavyCargoTrain ? 0.4 : ( mvOccupied->Vel > 5.0 ) ? 0.45 : 0.4 ) ) ( ( false == Ready )
|| ( VelNext > vel - 40.0 ) ) ? || ( VelNext > vel - 40.0 ) ) ?
fBrake_a0[ 0 ] * 0.8 : fBrake_a0[ 0 ] * 0.8 :
-fAccThreshold ) -fAccThreshold )
@@ -7483,7 +7490,7 @@ TController::control_tractive_and_braking_force() {
// if the radio-stop was issued don't waste effort trying to fight it // if the radio-stop was issued don't waste effort trying to fight it
if( ( true == mvOccupied->RadioStopFlag ) // radio-stop if( ( true == mvOccupied->RadioStopFlag ) // radio-stop
&& ( mvOccupied->Vel > 0.0 ) ) { // and still moving && ( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) ) { // and still moving
cue_action( locale::string::driver_hint_mastercontrollersetzerospeed ); // just throttle down... cue_action( locale::string::driver_hint_mastercontrollersetzerospeed ); // just throttle down...
return; // ...and don't touch any other controls return; // ...and don't touch any other controls
} }
@@ -7702,15 +7709,18 @@ void TController::control_braking_force() {
} }
// odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy
if( ( mvOccupied->Vel < 0.01 ) if( ( mvOccupied->Vel < EU07_AI_NOMOVEMENT )
&& ( ( VelDesired == 0.0 ) && ( ( VelDesired == 0.0 )
|| ( AccDesired <= EU07_AI_NOACCELERATION ) ) ) { || ( AccDesired <= EU07_AI_NOACCELERATION ) ) ) {
if( ( ( OrderCurrentGet() & ( Disconnect | Connect ) ) == 0 ) // przy (p)odłączaniu nie zwalniamy tu hamulca if( ( ( OrderCurrentGet() & ( Disconnect | Connect | Change_direction ) ) == 0 ) // przy (p)odłączaniu nie zwalniamy tu hamulca
&& ( std::abs( fAccGravity ) < 0.01 ) ) { // only do this on flats, on slopes keep applied the train brake && ( std::abs( fAccGravity ) < 0.01 ) ) { // only do this on flats, on slopes keep applied the train brake
// do it only if the vehicle actually has the independent brake
apply_independent_brake_only(); apply_independent_brake_only();
} }
// if told to change direction don't confuse human driver with request to leave applied brake in the cab they're about to leave
if( ( OrderCurrentGet() & ( Change_direction ) ) != 0 ) {
cue_action( locale::string::driver_hint_independentbrakerelease );
}
} }
} }
@@ -7924,7 +7934,7 @@ TController::check_route_behind( double const Range ) {
void void
TController::UpdateBrakingHelper() { TController::UpdateBrakingHelper() {
if (( HelperState > 0 ) && (-AccDesired < fBrake_a0[0] + 2 * fBrake_a1[0]) && (mvOccupied->Vel > 1)) { if (( HelperState > 0 ) && (-AccDesired < fBrake_a0[0] + 2 * fBrake_a1[0]) && (mvOccupied->Vel > EU07_AI_NOMOVEMENT)) {
HelperState = 0; HelperState = 0;
} }

View File

@@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/.
#include "translation.h" #include "translation.h"
auto const EU07_AI_NOACCELERATION = -0.05; auto const EU07_AI_NOACCELERATION = -0.05;
auto const EU07_AI_NOMOVEMENT = 0.05; // standstill velocity threshold
auto const EU07_AI_MOVEMENT = 1.0; // deliberate movement velocity threshold
auto const EU07_AI_SPEEDLIMITEXTENDSBEYONDSCANRANGE = 10000.0; auto const EU07_AI_SPEEDLIMITEXTENDSBEYONDSCANRANGE = 10000.0;
enum TOrders enum TOrders

View File

@@ -249,6 +249,9 @@ bool TDynamicObject::destination_data::deserialize_mapping( cParser &Input ) {
else if( key == "parameters:" ) { else if( key == "parameters:" ) {
parameters = Input.getToken<std::string>(); parameters = Input.getToken<std::string>();
} }
else if( key == "background:" ) {
background = Input.getToken<std::string>();
}
return true; return true;
} }
@@ -4648,31 +4651,47 @@ void TDynamicObject::RenderSounds() {
} }
} }
// attach/detach sounds // attach/detach sounds
if( ( coupler.sounds & sound::attachcoupler ) != 0 ) { if( ( coupler.sounds & sound::detach ) == 0 ) {
couplersounds.attach_coupler.play(); // potentially added some couplings
if( ( coupler.sounds & sound::attachcoupler ) != 0 ) {
couplersounds.attach_coupler.play();
}
if( ( coupler.sounds & sound::attachbrakehose ) != 0 ) {
couplersounds.attach_brakehose.play();
}
if( ( coupler.sounds & sound::attachmainhose ) != 0 ) {
couplersounds.attach_mainhose.play();
}
if( ( coupler.sounds & sound::attachcontrol ) != 0 ) {
couplersounds.attach_control.play();
}
if( ( coupler.sounds & sound::attachgangway ) != 0 ) {
couplersounds.attach_gangway.play();
}
if( ( coupler.sounds & sound::attachheating ) != 0 ) {
couplersounds.attach_heating.play();
}
} }
if( ( coupler.sounds & sound::attachbrakehose ) != 0 ) { else {
couplersounds.attach_brakehose.play(); // potentially removed some couplings
} if( ( coupler.sounds & sound::attachcoupler ) != 0 ) {
if( ( coupler.sounds & sound::attachmainhose ) != 0 ) { couplersounds.detach_coupler.play();
couplersounds.attach_mainhose.play(); }
} if( ( coupler.sounds & sound::attachbrakehose ) != 0 ) {
if( ( coupler.sounds & sound::attachcontrol ) != 0 ) { couplersounds.detach_brakehose.play();
couplersounds.attach_control.play(); }
} if( ( coupler.sounds & sound::attachmainhose ) != 0 ) {
if( ( coupler.sounds & sound::attachgangway ) != 0 ) { couplersounds.detach_mainhose.play();
couplersounds.attach_gangway.play(); }
} if( ( coupler.sounds & sound::attachcontrol ) != 0 ) {
if( ( coupler.sounds & sound::attachheating ) != 0 ) { couplersounds.detach_control.play();
couplersounds.attach_heating.play(); }
} if( ( coupler.sounds & sound::attachgangway ) != 0 ) {
if( true == TestFlag( coupler.sounds, sound::detachall ) ) { couplersounds.detach_gangway.play();
couplersounds.detach_coupler.play(); }
couplersounds.detach_brakehose.play(); if( ( coupler.sounds & sound::attachheating ) != 0 ) {
couplersounds.detach_mainhose.play(); couplersounds.detach_heating.play();
couplersounds.detach_control.play(); }
couplersounds.detach_gangway.play();
couplersounds.detach_heating.play();
} }
if( true == TestFlag( coupler.sounds, sound::attachadapter ) ) { if( true == TestFlag( coupler.sounds, sound::attachadapter ) ) {
couplersounds.dsbAdapterAttach.play(); couplersounds.dsbAdapterAttach.play();
@@ -5992,12 +6011,15 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
// vehicle faces +Z in 'its' space, for motor locations negative value means ahead of centre // vehicle faces +Z in 'its' space, for motor locations negative value means ahead of centre
auto const offset { std::atof( token.c_str() ) * -1.f }; auto const offset { std::atof( token.c_str() ) * -1.f };
// NOTE: we skip setting owner of the sounds, it'll be done during individual sound deserialization // NOTE: we skip setting owner of the sounds, it'll be done during individual sound deserialization
sound_source motor { sound_placement::external }; // generally traction motor sound_source motor { sound_placement::external }; // generic traction motor sounds
sound_source acmotor { sound_placement::external }; // inverter-specific traction motor sounds
sound_source motorblower { sound_placement::engine }; // associated motor blowers sound_source motorblower { sound_placement::engine }; // associated motor blowers
// add entry to the list // add entry to the list
auto const location { glm::vec3 { 0.f, 0.f, offset } }; auto const location { glm::vec3 { 0.f, 0.f, offset } };
motor.offset( location ); motor.offset( location );
m_powertrainsounds.motors.emplace_back( motor ); m_powertrainsounds.motors.emplace_back( motor );
acmotor.offset( location );
m_powertrainsounds.acmotors.emplace_back( acmotor );
motorblower.offset( location ); motorblower.offset( location );
m_powertrainsounds.motorblowers.emplace_back( motorblower ); m_powertrainsounds.motorblowers.emplace_back( motorblower );
} }
@@ -6344,6 +6366,7 @@ void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string co
DestinationSign.script = asBaseDir + DestinationSign.script; DestinationSign.script = asBaseDir + DestinationSign.script;
} }
} }
// NOTE: legacy key, now expected as optional "background:" parameter in pydestinationsign: { parameter block }
else if( token == "destinationsignbackground:" ) { else if( token == "destinationsignbackground:" ) {
parser.getTokens(); parser.getTokens();
parser >> DestinationSign.background; parser >> DestinationSign.background;

View File

@@ -58,6 +58,14 @@ public:
// returns offset of submodel associated with the button from the model centre // returns offset of submodel associated with the button from the model centre
glm::vec3 model_offset() const; glm::vec3 model_offset() const;
TGaugeType type() const; TGaugeType type() const;
inline
bool is_push() const {
return ( static_cast<int>( type() ) & static_cast<int>( TGaugeType::push ) ) != 0; }
inline
bool is_toggle() const {
return ( static_cast<int>( type() ) & static_cast<int>( TGaugeType::toggle ) ) != 0; }
bool is_delayed() const {
return ( static_cast<int>( type() ) & static_cast<int>( TGaugeType::delayed ) ) != 0; }
// members // members
TSubModel *SubModel { nullptr }, // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie TSubModel *SubModel { nullptr }, // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
*SubModelOn { nullptr }; // optional submodel visible when the state input is set *SubModelOn { nullptr }; // optional submodel visible when the state input is set

View File

@@ -174,6 +174,12 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> EnvironmentAmbientVolume; Parser >> EnvironmentAmbientVolume;
EnvironmentAmbientVolume = clamp(EnvironmentAmbientVolume, 0.f, 1.f); EnvironmentAmbientVolume = clamp(EnvironmentAmbientVolume, 0.f, 1.f);
} }
else if( token == "sound.volume.paused" ) {
// selected device for audio renderer
Parser.getTokens();
Parser >> PausedVolume;
EnvironmentAmbientVolume = clamp( EnvironmentAmbientVolume, 0.f, 1.f );
}
// else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie // else if (str==AnsiString("renderalpha")) //McZapkie-1312302 - dwuprzebiegowe renderowanie
// bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes")); // bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes"));
else if (token == "physicslog") else if (token == "physicslog")
@@ -1035,6 +1041,7 @@ global_settings::export_as_text( std::ostream &Output ) const {
export_as_text( Output, "sound.volume.vehicle", VehicleVolume ); export_as_text( Output, "sound.volume.vehicle", VehicleVolume );
export_as_text( Output, "sound.volume.positional", EnvironmentPositionalVolume ); export_as_text( Output, "sound.volume.positional", EnvironmentPositionalVolume );
export_as_text( Output, "sound.volume.ambient", EnvironmentAmbientVolume ); export_as_text( Output, "sound.volume.ambient", EnvironmentAmbientVolume );
export_as_text( Output, "sound.volume.paused", PausedVolume );
export_as_text( Output, "physicslog", WriteLogFlag ); export_as_text( Output, "physicslog", WriteLogFlag );
export_as_text( Output, "fullphysics", FullPhysics ); export_as_text( Output, "fullphysics", FullPhysics );
export_as_text( Output, "debuglog", iWriteLogEnabled ); export_as_text( Output, "debuglog", iWriteLogEnabled );

View File

@@ -159,6 +159,7 @@ struct global_settings {
float VehicleVolume{ 1.0f }; float VehicleVolume{ 1.0f };
float EnvironmentPositionalVolume{ 1.0f }; float EnvironmentPositionalVolume{ 1.0f };
float EnvironmentAmbientVolume{ 1.0f }; float EnvironmentAmbientVolume{ 1.0f };
float PausedVolume { 0.15f };
std::string AudioRenderer; std::string AudioRenderer;
// input // input
float fMouseXScale{ 1.5f }; float fMouseXScale{ 1.5f };

View File

@@ -243,7 +243,7 @@ enum sound {
parallel = 1 << 4, parallel = 1 << 4,
shuntfield = 1 << 5, shuntfield = 1 << 5,
pneumatic = 1 << 6, pneumatic = 1 << 6,
detachall = 1 << 7, detach = 1 << 7,
attachcoupler = 1 << 8, attachcoupler = 1 << 8,
attachbrakehose = 1 << 9, attachbrakehose = 1 << 9,
attachmainhose = 1 << 10, attachmainhose = 1 << 10,
@@ -1168,6 +1168,7 @@ public:
bool UniCtrlIntegratedBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie*/ bool UniCtrlIntegratedBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie*/
bool UniCtrlIntegratedLocalBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie hamulcem pomocniczym*/ bool UniCtrlIntegratedLocalBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie hamulcem pomocniczym*/
int UniCtrlNoPowerPos{ 0 }; // cached highesr position not generating traction force int UniCtrlNoPowerPos{ 0 }; // cached highesr position not generating traction force
std::pair<std::string, std::array<int, 2>> PantsPreset { "", { 0, 0 } }; // pantograph preset switches; .first holds possible setups as chars, .second holds currently selected preset in each cab
/*-sekcja parametrow dla lokomotywy elektrycznej*/ /*-sekcja parametrow dla lokomotywy elektrycznej*/
TSchemeTable RList; /*lista rezystorow rozruchowych i polaczen silnikow, dla dizla: napelnienia*/ TSchemeTable RList; /*lista rezystorow rozruchowych i polaczen silnikow, dla dizla: napelnienia*/

View File

@@ -511,23 +511,39 @@ bool TMoverParameters::Dettach(int ConnectNo)
if( othervehicle == nullptr ) { return true; } // nie ma nic, to odczepiono if( othervehicle == nullptr ) { return true; } // nie ma nic, to odczepiono
auto const i = DettachStatus(ConnectNo); // stan sprzęgu auto couplingchange { coupler.CouplingFlag }; // presume we'll uncouple all active flags
if (i < 0) { auto const couplingstate { DettachStatus( ConnectNo ) }; // stan sprzęgu
if (couplingstate < 0) {
// gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony) // gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony)
std::tie( coupler.Connected, coupler.ConnectedNr, coupler.CouplingFlag ) std::tie( coupler.Connected, coupler.ConnectedNr, coupler.CouplingFlag )
= std::tie( othercoupler.Connected, othercoupler.ConnectedNr, othercoupler.CouplingFlag ) = std::tie( othercoupler.Connected, othercoupler.ConnectedNr, othercoupler.CouplingFlag )
= std::make_tuple( nullptr, -1, coupling::faux ); = std::make_tuple( nullptr, -1, coupling::faux );
// set sound event flag
SetFlag( coupler.sounds, sound::detachall );
return true;
} }
else if (i > 0) else if (couplingstate > 0)
{ // odłączamy węże i resztę, pozostaje sprzęg fizyczny, który wymaga dociśnięcia (z wirtualnym nic) { // odłączamy węże i resztę, pozostaje sprzęg fizyczny, który wymaga dociśnięcia (z wirtualnym nic)
coupler.CouplingFlag &= coupling::coupler; coupler.CouplingFlag &= coupling::coupler;
othercoupler.CouplingFlag &= coupling::coupler; othercoupler.CouplingFlag &= coupling::coupler;
} }
return false; // jeszcze nie rozłączony // set sound event flag
couplingchange ^= coupler.CouplingFlag; // remaining bits were removed from coupling
if( couplingchange != 0 ) {
int soundflag { sound::detach }; // HACK: use detach flag to indicate removal of listed coupling
std::vector<std::pair<coupling, sound>> const soundmappings = {
{ coupling::coupler, sound::attachcoupler },
{ coupling::brakehose, sound::attachbrakehose },
{ coupling::mainhose, sound::attachmainhose },
{ coupling::control, sound::attachcontrol},
{ coupling::gangway, sound::attachgangway},
{ coupling::heating, sound::attachheating} };
for( auto const &soundmapping : soundmappings ) {
if( ( couplingchange & soundmapping.first ) != 0 ) {
soundflag |= soundmapping.second;
}
}
SetFlag( coupler.sounds, soundflag );
}
return ( couplingstate < 0 );
}; };
bool TMoverParameters::DirectionForward() bool TMoverParameters::DirectionForward()
@@ -10800,6 +10816,14 @@ void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) {
extract_value( UniversalResetButtonFlag[ 0 ], "RelayResetButton1", Input, "" ); extract_value( UniversalResetButtonFlag[ 0 ], "RelayResetButton1", Input, "" );
extract_value( UniversalResetButtonFlag[ 1 ], "RelayResetButton2", Input, "" ); extract_value( UniversalResetButtonFlag[ 1 ], "RelayResetButton2", Input, "" );
extract_value( UniversalResetButtonFlag[ 2 ], "RelayResetButton3", Input, "" ); extract_value( UniversalResetButtonFlag[ 2 ], "RelayResetButton3", Input, "" );
// pantograph presets
{
auto &presets { PantsPreset.first };
extract_value( presets, "PantographPresets", Input, "0|1|3|2" );
presets.erase(
std::remove( std::begin( presets ), std::end( presets ), '|' ),
std::end( presets ) );
}
} }
void TMoverParameters::LoadFIZ_MotorParamTable( std::string const &Input ) { void TMoverParameters::LoadFIZ_MotorParamTable( std::string const &Input ) {

287
Train.cpp
View File

@@ -31,7 +31,6 @@ http://mozilla.org/MPL/2.0/.
#include "Console.h" #include "Console.h"
#include "application.h" #include "application.h"
#include "renderer.h" #include "renderer.h"
#include "dictionary.h"
/* /*
namespace input { namespace input {
@@ -72,6 +71,38 @@ control_mapper::contains( std::string const Control ) const {
return ( m_names.find( Control ) != m_names.end() ); return ( m_names.find( Control ) != m_names.end() );
} }
void TTrain::screen_entry::deserialize( cParser &Input ) {
while( true == deserialize_mapping( Input ) ) {
; // all work done by while()
}
}
bool TTrain::screen_entry::deserialize_mapping( cParser &Input ) {
// token can be a key or block end
auto const key { Input.getToken<std::string>( true, "\n\r\t ,;[]" ) };
if( ( true == key.empty() ) || ( key == "}" ) ) { return false; }
if( key == "{" ) {
script = Input.getToken<std::string>();
}
else if( key == "target:" ) {
target = Input.getToken<std::string>();
}
else if( key == "parameters:" ) {
parameters = dictionary_source( Input.getToken<std::string>() );
}
else {
// HACK: we expect this to be true only if the screen entry doesn't start with a { which means legacy configuration format
target = key;
script = Input.getToken<std::string>();
return false;
}
return true;
}
void TCab::Load(cParser &Parser) void TCab::Load(cParser &Parser)
{ {
// NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change // NOTE: clearing control tables here is bit of a crutch, imposed by current scheme of loading compartments anew on each cab change
@@ -537,12 +568,12 @@ bool TTrain::Init(TDynamicObject *NewDynamicObject, bool e3d)
return true; return true;
} }
dictionary_source *TTrain::GetTrainState() { dictionary_source *TTrain::GetTrainState( dictionary_source const &Extraparameters ) {
if( ( mvOccupied == nullptr ) if( ( mvOccupied == nullptr )
|| ( mvControlled == nullptr ) ) { return nullptr; } || ( mvControlled == nullptr ) ) { return nullptr; }
auto *dict { new dictionary_source }; auto *dict { new dictionary_source( Extraparameters ) };
if( dict == nullptr ) { return nullptr; } if( dict == nullptr ) { return nullptr; }
dict->insert( "name", DynamicObject->asName ); dict->insert( "name", DynamicObject->asName );
@@ -612,6 +643,7 @@ dictionary_source *TTrain::GetTrainState() {
dict->insert( "distance_counter", m_distancecounter ); dict->insert( "distance_counter", m_distancecounter );
dict->insert( "pantpress", std::abs( mvPantographUnit->PantPress ) ); dict->insert( "pantpress", std::abs( mvPantographUnit->PantPress ) );
dict->insert( "universal3", InstrumentLightActive ); dict->insert( "universal3", InstrumentLightActive );
dict->insert( "radio", mvOccupied->Radio );
dict->insert( "radio_channel", RadioChannel() ); dict->insert( "radio_channel", RadioChannel() );
dict->insert( "radio_volume", Global.RadioVolume ); dict->insert( "radio_volume", Global.RadioVolume );
dict->insert( "door_lock", mvOccupied->Doors.lock_enabled ); dict->insert( "door_lock", mvOccupied->Doors.lock_enabled );
@@ -621,6 +653,7 @@ dictionary_source *TTrain::GetTrainState() {
dict->insert( "tractionforce", std::abs( mvOccupied->Ft ) ); dict->insert( "tractionforce", std::abs( mvOccupied->Ft ) );
dict->insert( "slipping_wheels", mvOccupied->SlippingWheels ); dict->insert( "slipping_wheels", mvOccupied->SlippingWheels );
dict->insert( "sanding", mvOccupied->SandDose ); dict->insert( "sanding", mvOccupied->SandDose );
dict->insert( "odometer", mvOccupied->DistCounter );
// electric current data // electric current data
dict->insert( "traction_voltage", std::abs( mvPantographUnit->PantographVoltage ) ); dict->insert( "traction_voltage", std::abs( mvPantographUnit->PantographVoltage ) );
dict->insert( "voltage", std::abs( mvControlled->EngineVoltage ) ); dict->insert( "voltage", std::abs( mvControlled->EngineVoltage ) );
@@ -1122,18 +1155,30 @@ void TTrain::OnCommand_tempomattoggle( TTrain *Train, command_data const &Comman
if( Train->ggScndCtrlButton.type() == TGaugeType::push ) { if( Train->ggScndCtrlButton.type() == TGaugeType::push ) {
// impulse switch // impulse switch
if( Command.action == GLFW_RELEASE ) { if( Command.action == GLFW_RELEASE ) {
// just move the button back to default position // just move the button(s) back to default position
// visual feedback // visual feedback
Train->ggScndCtrlButton.UpdateValue( 0.0, Train->dsbSwitch ); Train->ggScndCtrlButton.UpdateValue( 0.0, Train->dsbSwitch );
Train->ggScndCtrlOffButton.UpdateValue( 0.0, Train->dsbSwitch );
return; return;
} }
// glfw_press // glfw_press
if( Train->mvControlled->ScndCtrlPos == 0 ) { if( Train->mvControlled->ScndCtrlPos == 0 ) {
// turn on if needed // turn on if it's not active
Train->mvControlled->IncScndCtrl( 1 ); Train->mvControlled->IncScndCtrl( 1 );
// visual feedback
Train->ggScndCtrlButton.UpdateValue( 1.0, Train->dsbSwitch );
}
else {
// otherwise turn off
Train->mvControlled->DecScndCtrl( 2 );
// visual feedback
if( Train->m_controlmapper.contains( "tempomatoff_sw:" ) ) {
Train->ggScndCtrlOffButton.UpdateValue( 1.0, Train->dsbSwitch );
}
else {
Train->ggScndCtrlButton.UpdateValue( 1.0, Train->dsbSwitch );
}
} }
// visual feedback
Train->ggScndCtrlButton.UpdateValue( 1.0, Train->dsbSwitch );
} }
else { else {
// two-state switch // two-state switch
@@ -2194,7 +2239,7 @@ void TTrain::OnCommand_batterydisable( TTrain *Train, command_data const &Comman
void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const &Command ) {
// HACK: presence of pantograph selector prevents manual operation of the individual valves // HACK: presence of pantograph selector prevents manual operation of the individual valves
if( Train->ggPantSelectButton.SubModel ) { return; } if( Train->m_controlmapper.contains( "pantselect_sw:" ) ) { 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
@@ -2226,7 +2271,7 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const
void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const &Command ) {
// HACK: presence of pantograph selector prevents manual operation of the individual valves // HACK: presence of pantograph selector prevents manual operation of the individual valves
if( Train->ggPantSelectButton.SubModel ) { return; } if( Train->m_controlmapper.contains( "pantselect_sw:" ) ) { 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
@@ -2258,7 +2303,7 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const &
void TTrain::OnCommand_pantographraisefront( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_pantographraisefront( TTrain *Train, command_data const &Command ) {
// HACK: presence of pantograph selector prevents manual operation of the individual valves // HACK: presence of pantograph selector prevents manual operation of the individual valves
if( Train->ggPantSelectButton.SubModel ) { return; } if( Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; }
// prevent operation without submodel outside of engine compartment // prevent operation without submodel outside of engine compartment
if( ( Train->iCabn != 0 ) if( ( Train->iCabn != 0 )
&& ( false == Train->m_controlmapper.contains( "pantfront_sw:" ) ) ) { return; } && ( false == Train->m_controlmapper.contains( "pantfront_sw:" ) ) ) { return; }
@@ -2285,7 +2330,7 @@ void TTrain::OnCommand_pantographraisefront( TTrain *Train, command_data const &
void TTrain::OnCommand_pantographraiserear( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_pantographraiserear( TTrain *Train, command_data const &Command ) {
// HACK: presence of pantograph selector prevents manual operation of the individual valves // HACK: presence of pantograph selector prevents manual operation of the individual valves
if( Train->ggPantSelectButton.SubModel ) { return; } if( Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; }
// prevent operation without submodel outside of engine compartment // prevent operation without submodel outside of engine compartment
if( ( Train->iCabn != 0 ) if( ( Train->iCabn != 0 )
&& ( false == Train->m_controlmapper.contains( "pantrear_sw:" ) ) ) { return; } && ( false == Train->m_controlmapper.contains( "pantrear_sw:" ) ) ) { return; }
@@ -2312,7 +2357,7 @@ void TTrain::OnCommand_pantographraiserear( TTrain *Train, command_data const &C
void TTrain::OnCommand_pantographlowerfront( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_pantographlowerfront( TTrain *Train, command_data const &Command ) {
// HACK: presence of pantograph selector prevents manual operation of the individual valves // HACK: presence of pantograph selector prevents manual operation of the individual valves
if( Train->ggPantSelectButton.SubModel ) { return; } if( Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; }
// prevent operation without submodel outside of engine compartment // prevent operation without submodel outside of engine compartment
if( ( Train->iCabn != 0 ) if( ( Train->iCabn != 0 )
&& ( false == Train->m_controlmapper.contains( && ( false == Train->m_controlmapper.contains(
@@ -2344,7 +2389,8 @@ void TTrain::OnCommand_pantographlowerfront( TTrain *Train, command_data const &
void TTrain::OnCommand_pantographlowerrear( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_pantographlowerrear( TTrain *Train, command_data const &Command ) {
// HACK: presence of pantograph selector prevents manual operation of the individual valves // HACK: presence of pantograph selector prevents manual operation of the individual valves
if( Train->ggPantSelectButton.SubModel ) { return; } if( Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; }
if( ( Train->iCabn != 0 ) if( ( Train->iCabn != 0 )
&& ( false == Train->m_controlmapper.contains( && ( false == Train->m_controlmapper.contains(
Train->mvOccupied->PantSwitchType == "impulse" ? Train->mvOccupied->PantSwitchType == "impulse" ?
@@ -2404,7 +2450,7 @@ void TTrain::OnCommand_pantographselectnext( TTrain *Train, command_data const &
if( Command.action != GLFW_PRESS ) { return; } if( Command.action != GLFW_PRESS ) { return; }
if( Train->ggPantSelectButton.SubModel == nullptr ) { return; } if( false == Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; }
Train->change_pantograph_selection( 1 ); Train->change_pantograph_selection( 1 );
} }
@@ -2413,7 +2459,7 @@ void TTrain::OnCommand_pantographselectprevious( TTrain *Train, command_data con
if( Command.action != GLFW_PRESS ) { return; } if( Command.action != GLFW_PRESS ) { return; }
if( Train->ggPantSelectButton.SubModel == nullptr ) { return; } if( false == Train->m_controlmapper.contains( "pantselect_sw:" ) ) { return; }
Train->change_pantograph_selection( -1 ); Train->change_pantograph_selection( -1 );
} }
@@ -2508,19 +2554,19 @@ void TTrain::OnCommand_pantographlowerselected( TTrain *Train, command_data cons
void TTrain::change_pantograph_selection( int const Change ) { void TTrain::change_pantograph_selection( int const Change ) {
auto const initialstate { m_pantselection }; auto const &presets { mvOccupied->PantsPreset.first };
auto &selection { mvOccupied->PantsPreset.second[ cab_to_end() ] };
auto const initialstate { selection };
selection = clamp<int>( selection + Change, 0, std::max<int>( presets.size() - 1, 0 ) );
m_pantselection = clamp( m_pantselection + Change, 0, 3 ); if( selection == initialstate ) { return; } // no change, nothing to do
// visual feedback
ggPantSelectButton.UpdateValue( m_pantselection );
if( m_pantselection == initialstate ) { return; } // no change, nothing to do
// configure pantograph valves matching the new state // configure pantograph valves matching the new state
auto const preset { presets[ selection ] - '0' };
auto const swapends { cab_to_end() != end::front }; auto const swapends { cab_to_end() != end::front };
// check desired states for both pantographs; value: whether the pantograph should be raised // check desired states for both pantographs; value: whether the pantograph should be raised
auto const frontstate{ ( m_pantselection == 2 ) || ( m_pantselection == ( swapends ? 1 : 3 ) ) }; auto const frontstate { preset & ( swapends ? 1 : 2 ) };
auto const rearstate{ ( m_pantselection == 2 ) || ( m_pantselection == ( swapends ? 3 : 1 ) ) }; auto const rearstate { preset & ( swapends ? 2 : 1 ) };
// potentially adjust pantograph valves // potentially adjust pantograph valves
mvOccupied->OperatePantographValve( end::front, ( frontstate ? operation_t::enable : operation_t::disable ) ); mvOccupied->OperatePantographValve( end::front, ( frontstate ? operation_t::enable : operation_t::disable ) );
mvOccupied->OperatePantographValve( end::rear, ( rearstate ? operation_t::enable : operation_t::disable ) ); mvOccupied->OperatePantographValve( end::rear, ( rearstate ? operation_t::enable : operation_t::disable ) );
@@ -5503,9 +5549,27 @@ void TTrain::OnCommand_doorcloseall( TTrain *Train, command_data const &Command
} }
void TTrain::OnCommand_doorsteptoggle( TTrain *Train, command_data const &Command ) { void TTrain::OnCommand_doorsteptoggle( TTrain *Train, command_data const &Command ) {
// TODO: move logic/visualization code to the gauge, on_command() should return hint whether it should invoke a reaction
if( Command.action == GLFW_PRESS ) { if( Command.action == GLFW_PRESS ) {
Train->mvOccupied->PermitDoorStep( false == Train->mvOccupied->Doors.step_enabled ); // effect
if( false == Train->ggDoorStepButton.is_delayed() ) {
Train->mvOccupied->PermitDoorStep( false == Train->mvOccupied->Doors.step_enabled );
}
// visual feedback
auto const isactive { (
Train->ggDoorStepButton.is_push() // always press push button
|| Train->mvOccupied->Doors.step_enabled ) }; // for toggle buttons indicate item state
Train->ggDoorStepButton.UpdateValue( isactive ? 1 : 0 );
}
else if( Command.action == GLFW_RELEASE ) {
// effect
if( Train->ggDoorStepButton.is_delayed() ) {
Train->mvOccupied->PermitDoorStep( false == Train->mvOccupied->Doors.step_enabled );
}
// visual feedback
if( Train->ggDoorStepButton.is_push() ) {
Train->ggDoorStepButton.UpdateValue( 0 );
}
} }
} }
@@ -6964,6 +7028,7 @@ bool TTrain::Update( double const Deltatime )
ggScndCtrl.Update(); ggScndCtrl.Update();
} }
ggScndCtrlButton.Update( lowvoltagepower ); ggScndCtrlButton.Update( lowvoltagepower );
ggScndCtrlOffButton.Update( lowvoltagepower );
ggDistanceCounterButton.Update(); ggDistanceCounterButton.Update();
if (ggDirKey.SubModel) { if (ggDirKey.SubModel) {
if (mvControlled->TrainType != dt_EZT) if (mvControlled->TrainType != dt_EZT)
@@ -7047,16 +7112,17 @@ bool TTrain::Update( double const Deltatime )
// NBMX wrzesien 2003 - drzwi // NBMX wrzesien 2003 - drzwi
ggDoorLeftPermitButton.Update( lowvoltagepower ); ggDoorLeftPermitButton.Update( lowvoltagepower );
ggDoorRightPermitButton.Update( lowvoltagepower ); ggDoorRightPermitButton.Update( lowvoltagepower );
ggDoorPermitPresetButton.Update(); ggDoorPermitPresetButton.Update( lowvoltagepower );
ggDoorLeftButton.Update(); ggDoorLeftButton.Update( lowvoltagepower );
ggDoorRightButton.Update(); ggDoorRightButton.Update( lowvoltagepower );
ggDoorLeftOnButton.Update(); ggDoorLeftOnButton.Update( lowvoltagepower );
ggDoorRightOnButton.Update(); ggDoorRightOnButton.Update( lowvoltagepower );
ggDoorLeftOffButton.Update(); ggDoorLeftOffButton.Update( lowvoltagepower );
ggDoorRightOffButton.Update(); ggDoorRightOffButton.Update( lowvoltagepower );
ggDoorAllOnButton.Update(); ggDoorAllOnButton.Update( lowvoltagepower );
ggDoorAllOffButton.Update( lowvoltagepower ); ggDoorAllOffButton.Update( lowvoltagepower );
ggDoorSignallingButton.Update(); ggDoorSignallingButton.Update( lowvoltagepower );
ggDoorStepButton.Update( lowvoltagepower );
// NBMX dzwignia sprezarki // NBMX dzwignia sprezarki
ggCompressorButton.Update(); ggCompressorButton.Update();
ggCompressorLocalButton.Update(); ggCompressorLocalButton.Update();
@@ -7125,7 +7191,6 @@ bool TTrain::Update( double const Deltatime )
ggPantAllDownButton.Update(); ggPantAllDownButton.Update();
ggPantSelectedDownButton.Update(); ggPantSelectedDownButton.Update();
ggPantSelectedButton.Update(); ggPantSelectedButton.Update();
ggPantSelectButton.Update();
ggPantCompressorButton.Update(); ggPantCompressorButton.Update();
ggPantCompressorValve.Update(); ggPantCompressorValve.Update();
@@ -7237,13 +7302,13 @@ bool TTrain::Update( double const Deltatime )
&& ( fScreenTimer > std::max( fScreenUpdateRate, Global.PythonScreenUpdateRate ) * 0.001f ) && ( fScreenTimer > std::max( fScreenUpdateRate, Global.PythonScreenUpdateRate ) * 0.001f )
&& ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside && ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside
fScreenTimer = 0.f; fScreenTimer = 0.f;
for( auto const &screen : m_screens ) { for( auto &screen : m_screens ) {
auto state_dict = GetTrainState(); auto *state_dict = GetTrainState( screen.parameters );
/* /*
state_dict->insert("touches", *screen.touch_list); state_dict->insert("touches", *screen.touch_list);
screen.touch_list->clear(); screen.touch_list->clear();
*/ */
Application.request({ screen.rendererpath, state_dict, screen.rt } ); Application.request( { screen.script, state_dict, screen.rt } );
} }
} }
// sounds // sounds
@@ -8038,60 +8103,62 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
// TODO: add "pydestination:" // TODO: add "pydestination:"
else if (token == "pyscreen:") else if (token == "pyscreen:")
{ {
std::string submodelname, renderername; screen_entry screen;
parser.getTokens( 2 ); screen.deserialize(parser);
parser if ((false == screen.script.empty()) && (substr_path(screen.script).empty()))
>> submodelname {
>> renderername; screen.script = DynamicObject->asBaseDir + screen.script;
}
const std::string rendererpath { opengl_texture *tex = nullptr;
substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided
DynamicObject->asBaseDir + renderername :
renderername };
opengl_texture *tex = nullptr;
TSubModel *submodel = nullptr; TSubModel *submodel = nullptr;
if (submodelname != "none") { if (screen.target != "none")
submodel = ( {
DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName( submodelname ) : submodel = (DynamicObject->mdKabina ?
DynamicObject->mdLowPolyInt ? DynamicObject->mdLowPolyInt->GetFromName( submodelname ) : DynamicObject->mdKabina->GetFromName(screen.target) :
nullptr ); DynamicObject->mdLowPolyInt ?
if( submodel == nullptr ) { DynamicObject->mdLowPolyInt->GetFromName(screen.target) :
WriteLog( "Python Screen: submodel " + submodelname + " not found - Ignoring screen" ); nullptr);
continue; if (submodel == nullptr)
} {
auto const material { submodel->GetMaterial() }; WriteLog("Python Screen: submodel " + screen.target +
if( material <= 0 ) { " not found - Ignoring screen");
// sub model nie posiada tekstury lub tekstura wymienna - nie obslugiwana continue;
WriteLog( "Python Screen: invalid texture id " + std::to_string( material ) + " - Ignoring screen" ); }
continue; auto const material{submodel->GetMaterial()};
} if (material <= 0)
{
// sub model nie posiada tekstury lub tekstura wymienna - nie obslugiwana
WriteLog("Python Screen: invalid texture id " + std::to_string(material) +
" - Ignoring screen");
continue;
}
tex = &GfxRenderer->Texture(GfxRenderer->Material(material).textures[0]); tex = &GfxRenderer->Texture(GfxRenderer->Material(material).textures[0]);
} }
else { else
// TODO: fix leak {
tex = new opengl_texture(); // TODO: fix leak
tex->make_stub(); tex = new opengl_texture();
} tex->make_stub();
}
tex->create( true ); // make the surface static so it doesn't get destroyed by garbage collector if the user spends long time outside cab tex->create(true); // make the surface static so it doesn't get destroyed by garbage
// TBD, TODO: keep texture handles around, so we can undo the static switch when the user changes cabs? // collector if the user spends long time outside cab
// TBD, TODO: keep texture handles around, so we can undo the static switch when the
// user changes cabs?
auto rt = std::make_shared<python_rt>();
rt->shared_tex = tex->id;
auto touch_list = std::make_shared<std::vector<glm::vec2>>();
auto rt = std::make_shared<python_rt>();
rt->shared_tex = tex->id;
/*
if (submodel)
submodel->screen_touch_list = touch_list;
*/
// record renderer and material binding for future update requests // record renderer and material binding for future update requests
m_screens.emplace_back(); m_screens.emplace_back(screen);
m_screens.back().rendererpath = rendererpath;
m_screens.back().rt = rt; m_screens.back().rt = rt;
/* /*
m_screens.back().touch_list = touch_list; m_screens.back().touch_list = std::make_shared<std::vector<glm::vec2>>();
if (submodel) // guaranteed at this point
submodel->screen_touch_list = m_screens.back().touch_list;
*/
/*
if (Global.python_displaywindows) if (Global.python_displaywindows)
m_screens.back().viewer = std::make_unique<python_screen_viewer>(rt, touch_list, rendererpath); m_screens.back().viewer = std::make_unique<python_screen_viewer>(rt, touch_list, rendererpath);
*/ */
@@ -8280,8 +8347,14 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
target_train->Occupied()->LimPipePress = target_train->Occupied()->PipePress; target_train->Occupied()->LimPipePress = target_train->Occupied()->PipePress;
target_train->Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny) target_train->Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
target_train->Dynamic()->MechInside = true; target_train->Dynamic()->MechInside = true;
target_train->Dynamic()->Controller = ( target_train->Dynamic()->Mechanik ? !target_train->Dynamic()->Mechanik->AIControllFlag : Humandriver ); if( target_train->Dynamic()->Mechanik ) {
} else { target_train->Dynamic()->Controller = target_train->Dynamic()->Mechanik->AIControllFlag;
target_train->Dynamic()->Mechanik->DirectionChange();
}
else {
target_train->Dynamic()->Controller = Humandriver;
}
} else {
target_train->Dynamic()->bDisplayCab = false; target_train->Dynamic()->bDisplayCab = false;
target_train->Dynamic()->ABuSetModelShake( {} ); target_train->Dynamic()->ABuSetModelShake( {} );
} }
@@ -8327,7 +8400,13 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
Occupied()->LimPipePress = Occupied()->PipePress; Occupied()->LimPipePress = Occupied()->PipePress;
Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny) Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
Dynamic()->MechInside = true; Dynamic()->MechInside = true;
Dynamic()->Controller = ( Dynamic()->Mechanik ? Dynamic()->Mechanik->AIControllFlag : Humandriver ); if( Dynamic()->Mechanik ) {
Dynamic()->Controller = Dynamic()->Mechanik->AIControllFlag;
Dynamic()->Mechanik->DirectionChange();
}
else {
Dynamic()->Controller = Humandriver;
}
} else { } else {
Dynamic()->bDisplayCab = false; Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} ); Dynamic()->ABuSetModelShake( {} );
@@ -8429,6 +8508,7 @@ void TTrain::clear_cab_controls()
ggMainCtrlAct.Clear(); ggMainCtrlAct.Clear();
ggScndCtrl.Clear(); ggScndCtrl.Clear();
ggScndCtrlButton.Clear(); ggScndCtrlButton.Clear();
ggScndCtrlOffButton.Clear();
ggDistanceCounterButton.Clear(); ggDistanceCounterButton.Clear();
ggDirKey.Clear(); ggDirKey.Clear();
ggDirForwardButton.Clear(); ggDirForwardButton.Clear();
@@ -8512,6 +8592,7 @@ void TTrain::clear_cab_controls()
ggTrainHeatingButton.Clear(); ggTrainHeatingButton.Clear();
ggSignallingButton.Clear(); ggSignallingButton.Clear();
ggDoorSignallingButton.Clear(); ggDoorSignallingButton.Clear();
ggDoorStepButton.Clear();
ggDepartureSignalButton.Clear(); ggDepartureSignalButton.Clear();
ggCompressorButton.Clear(); ggCompressorButton.Clear();
ggCompressorLocalButton.Clear(); ggCompressorLocalButton.Clear();
@@ -8528,7 +8609,6 @@ void TTrain::clear_cab_controls()
ggPantAllDownButton.Clear(); ggPantAllDownButton.Clear();
ggPantSelectedButton.Clear(); ggPantSelectedButton.Clear();
ggPantSelectedDownButton.Clear(); ggPantSelectedDownButton.Clear();
ggPantSelectButton.Clear();
ggPantCompressorButton.Clear(); ggPantCompressorButton.Clear();
ggPantCompressorValve.Clear(); ggPantCompressorValve.Clear();
ggI1B.Clear(); ggI1B.Clear();
@@ -8705,13 +8785,6 @@ void TTrain::set_cab_controls( int const Cab ) {
} }
*/ */
// front/end pantograph selection is relative to occupied cab // front/end pantograph selection is relative to occupied cab
m_pantselection = (
m_pantselection == 1 ? ( cab_to_end( Cab ) == cab_to_end() ? 1 : 3 ) :
m_pantselection == 3 ? ( cab_to_end( Cab ) == cab_to_end() ? 3 : 1 ) :
m_pantselection ); // other settings affect both pantographs
if( ggPantSelectButton.SubModel ) {
ggPantSelectButton.PutValue( m_pantselection );
}
if( ggPantSelectedButton.type() == TGaugeType::toggle ) { if( ggPantSelectedButton.type() == TGaugeType::toggle ) {
ggPantSelectedButton.PutValue( ggPantSelectedButton.PutValue(
( mvPantographUnit->PantsValve.is_enabled ? ( mvPantographUnit->PantsValve.is_enabled ?
@@ -8825,10 +8898,10 @@ void TTrain::set_cab_controls( int const Cab ) {
1.f : 1.f :
0.f ) ); 0.f ) );
// doors permits // doors permits
if( ggDoorLeftPermitButton.type() != TGaugeType::push ) { if( false == ggDoorLeftPermitButton.is_push() ) {
ggDoorLeftPermitButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit ? 1.f : 0.f ); ggDoorLeftPermitButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit ? 1.f : 0.f );
} }
if( ggDoorRightPermitButton.type() != TGaugeType::push ) { if( false == ggDoorRightPermitButton.is_push() ) {
ggDoorRightPermitButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit ? 1.f : 0.f ); ggDoorRightPermitButton.PutValue( mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit ? 1.f : 0.f );
} }
ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset ); ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset );
@@ -8840,8 +8913,15 @@ void TTrain::set_cab_controls( int const Cab ) {
mvOccupied->Doors.lock_enabled ? mvOccupied->Doors.lock_enabled ?
1.f : 1.f :
0.f ); 0.f );
// door step
if( false == ggDoorStepButton.is_push() ) {
ggDoorStepButton.PutValue(
mvOccupied->Doors.step_enabled ?
1.f :
0.f );
}
// heating // heating
if( ggTrainHeatingButton.type() != TGaugeType::push ) { if( false == ggTrainHeatingButton.is_push() ) {
ggTrainHeatingButton.PutValue( ggTrainHeatingButton.PutValue(
mvControlled->Heating ? mvControlled->Heating ?
1.f : 1.f :
@@ -8946,7 +9026,7 @@ void TTrain::set_cab_controls( int const Cab ) {
0.f ); 0.f );
} }
// tempomat // tempomat
if( ggScndCtrlButton.type() != TGaugeType::push ) { if( false == ggScndCtrlButton.is_push() ) {
ggScndCtrlButton.PutValue( ggScndCtrlButton.PutValue(
( mvControlled->ScndCtrlPos > 0 ) ? ( mvControlled->ScndCtrlPos > 0 ) ?
1.f : 1.f :
@@ -9225,7 +9305,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "pantalloff_sw:", ggPantAllDownButton }, { "pantalloff_sw:", ggPantAllDownButton },
{ "pantselected_sw:", ggPantSelectedButton }, { "pantselected_sw:", ggPantSelectedButton },
{ "pantselectedoff_sw:", ggPantSelectedDownButton }, { "pantselectedoff_sw:", ggPantSelectedDownButton },
{ "pantselect_sw:", ggPantSelectButton },
{ "pantcompressor_sw:", ggPantCompressorButton }, { "pantcompressor_sw:", ggPantCompressorButton },
{ "pantcompressorvalve_sw:", ggPantCompressorValve }, { "pantcompressorvalve_sw:", ggPantCompressorValve },
{ "trainheating_sw:", ggTrainHeatingButton }, { "trainheating_sw:", ggTrainHeatingButton },
@@ -9265,9 +9344,12 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
return true; return true;
} }
} }
// TODO: move viable gauges to the state driven array // dedicated gauges with state-driven optional submodel
// TODO: move viable gauges here
// TODO: convert dedicated gauges to auto-allocated ones, replace dedicated references in command handlers to mapper lookups
std::unordered_map<std::string, std::tuple<TGauge &, bool const *> > const stategauges = { std::unordered_map<std::string, std::tuple<TGauge &, bool const *> > const stategauges = {
{ "tempomat_sw:", { ggScndCtrlButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, { "tempomat_sw:", { ggScndCtrlButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "tempomatoff_sw:", { ggScndCtrlOffButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "speedinc_bt:", { ggSpeedControlIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, { "speedinc_bt:", { ggSpeedControlIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "speeddec_bt:", { ggSpeedControlDecreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, { "speeddec_bt:", { ggSpeedControlDecreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "speedctrlpowerinc_bt:", { ggSpeedControlPowerIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } }, { "speedctrlpowerinc_bt:", { ggSpeedControlPowerIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
@@ -9285,7 +9367,8 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "doorleftpermit_sw:", { ggDoorLeftPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit } }, { "doorleftpermit_sw:", { ggDoorLeftPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::left : side::right ) ].open_permit } },
{ "doorrightpermit_sw:", { ggDoorRightPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit } }, { "doorrightpermit_sw:", { ggDoorRightPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit } },
{ "dooralloff_sw:", { ggDoorAllOffButton, &m_doors } }, { "dooralloff_sw:", { ggDoorAllOffButton, &m_doors } },
{ "dirforward_bt:", { ggDirForwardButton, &m_dirforward } }, { "doorstep_sw:", { ggDoorStepButton, &mvOccupied->Doors.step_enabled } },
{ "dirforward_bt:", { ggDirForwardButton, &m_dirforward } },
{ "dirneutral_bt:", { ggDirNeutralButton, &m_dirneutral } }, { "dirneutral_bt:", { ggDirNeutralButton, &m_dirneutral } },
{ "dirbackward_bt:", { ggDirBackwardButton, &m_dirbackward } }, { "dirbackward_bt:", { ggDirBackwardButton, &m_dirbackward } },
}; };
@@ -9302,7 +9385,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
// TODO: move viable dedicated gauges to the automatic array // TODO: move viable dedicated gauges to the automatic array
std::unordered_map<std::string, bool *> const autoboolgauges = { std::unordered_map<std::string, bool *> const autoboolgauges = {
{ "doormode_sw:", &mvOccupied->Doors.remote_only }, { "doormode_sw:", &mvOccupied->Doors.remote_only },
{ "doorstep_sw:", &mvOccupied->Doors.step_enabled },
{ "coolingfans_sw:", &mvControlled->RVentForceOn }, { "coolingfans_sw:", &mvControlled->RVentForceOn },
{ "pantfront_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_enabled }, { "pantfront_sw:", &mvPantographUnit->Pantographs[end::front].valve.is_enabled },
{ "pantrear_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_enabled }, { "pantrear_sw:", &mvPantographUnit->Pantographs[end::rear].valve.is_enabled },
@@ -9326,6 +9408,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
// TODO: move viable dedicated gauges to the automatic array // TODO: move viable dedicated gauges to the automatic array
std::unordered_map<std::string, int *> const autointgauges = { std::unordered_map<std::string, int *> const autointgauges = {
{ "manualbrake:", &mvOccupied->ManualBrakePos }, { "manualbrake:", &mvOccupied->ManualBrakePos },
{ "pantselect_sw:", &mvOccupied->PantsPreset.second[cab_to_end()] },
}; };
{ {
auto lookup = autointgauges.find( Label ); auto lookup = autointgauges.find( Label );

32
Train.h
View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "sound.h" #include "sound.h"
#include "PyInt.h" #include "PyInt.h"
#include "command.h" #include "command.h"
#include "dictionary.h"
#undef snprintf // pyint.h->python #undef snprintf // pyint.h->python
@@ -113,15 +114,21 @@ class TTrain {
}; };
struct screen_entry { struct screen_entry {
std::string rendererpath;
std::string script;
std::string target;
std::shared_ptr<python_rt> rt; std::shared_ptr<python_rt> rt;
/* /*
std::unique_ptr<python_screen_viewer> viewer; std::unique_ptr<python_screen_viewer> viewer;
std::shared_ptr<std::vector<glm::vec2>> touch_list; std::shared_ptr<std::vector<glm::vec2>> touch_list;
*/ */
dictionary_source parameters; // cached pre-processed optional per-screen parameters
void deserialize( cParser &Input );
bool deserialize_mapping( cParser &Input );
}; };
typedef std::vector<screen_entry> screen_map; typedef std::vector<screen_entry> screenentry_sequence;
// constructors // constructors
TTrain(); TTrain();
@@ -132,16 +139,23 @@ class TTrain {
// McZapkie-010302 // McZapkie-010302
bool Init(TDynamicObject *NewDynamicObject, bool e3d = false); bool Init(TDynamicObject *NewDynamicObject, bool e3d = false);
inline Math3D::vector3 GetDirection() { return DynamicObject->VectorFront(); }; inline
inline Math3D::vector3 GetUp() { return DynamicObject->VectorUp(); }; Math3D::vector3 GetDirection() const {
inline std::string GetLabel( TSubModel const *Control ) const { return m_controlmapper.find( Control ); } return DynamicObject->VectorFront(); };
inline
Math3D::vector3 GetUp() const {
return DynamicObject->VectorUp(); };
inline
std::string GetLabel( TSubModel const *Control ) const {
return m_controlmapper.find( Control ); }
void UpdateCab(); void UpdateCab();
bool Update( double const Deltatime ); bool Update( double const Deltatime );
void add_distance( double const Distance ); void add_distance( double const Distance );
// McZapkie-310302: ladowanie parametrow z pliku // McZapkie-310302: ladowanie parametrow z pliku
bool LoadMMediaFile(std::string const &asFileName); bool LoadMMediaFile(std::string const &asFileName);
dictionary_source *GetTrainState(); dictionary_source *GetTrainState( dictionary_source const &Extraparameters );
state_t get_state() const; state_t get_state() const;
// basic_table interface
inline inline
std::string name() const { std::string name() const {
return Dynamic()->name(); } return Dynamic()->name(); }
@@ -464,6 +478,7 @@ public: // reszta może by?publiczna
TGauge ggMainCtrlAct; TGauge ggMainCtrlAct;
TGauge ggScndCtrl; TGauge ggScndCtrl;
TGauge ggScndCtrlButton; TGauge ggScndCtrlButton;
TGauge ggScndCtrlOffButton;
TGauge ggDirKey; TGauge ggDirKey;
TGauge ggDirForwardButton; TGauge ggDirForwardButton;
TGauge ggDirNeutralButton; TGauge ggDirNeutralButton;
@@ -572,6 +587,7 @@ public: // reszta może by?publiczna
TGauge ggDoorAllOnButton; TGauge ggDoorAllOnButton;
TGauge ggDoorAllOffButton; TGauge ggDoorAllOffButton;
TGauge ggDepartureSignalButton; TGauge ggDepartureSignalButton;
TGauge ggDoorStepButton;
// Winger 160204 - obsluga pantografow - ZROBIC // Winger 160204 - obsluga pantografow - ZROBIC
/* /*
@@ -583,7 +599,6 @@ public: // reszta może by?publiczna
TGauge ggPantAllDownButton; TGauge ggPantAllDownButton;
TGauge ggPantSelectedButton; TGauge ggPantSelectedButton;
TGauge ggPantSelectedDownButton; TGauge ggPantSelectedDownButton;
TGauge ggPantSelectButton;
TGauge ggPantCompressorButton; TGauge ggPantCompressorButton;
TGauge ggPantCompressorValve; TGauge ggPantCompressorValve;
// Winger 020304 - wlacznik ogrzewania // Winger 020304 - wlacznik ogrzewania
@@ -790,11 +805,10 @@ private:
float fPPress, fNPress; float fPPress, fNPress;
bool m_mastercontrollerinuse { false }; bool m_mastercontrollerinuse { false };
float m_mastercontrollerreturndelay { 0.f }; float m_mastercontrollerreturndelay { 0.f };
screen_map m_screens; screenentry_sequence m_screens;
uint16_t vid { 0 }; // train network recipient id uint16_t vid { 0 }; // train network recipient id
float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive float m_distancecounter { -1.f }; // distance traveled since meter was activated or -1 if inactive
double m_brakehandlecp{ 0.0 }; double m_brakehandlecp{ 0.0 };
int m_pantselection{ 0 };
bool m_doors{ false }; // helper, true if any door is open bool m_doors{ false }; // helper, true if any door is open
bool m_dirforward{ false }; // helper, true if direction set to forward bool m_dirforward{ false }; // helper, true if direction set to forward
bool m_dirneutral{ false }; // helper, true if direction set to neutral bool m_dirneutral{ false }; // helper, true if direction set to neutral

View File

@@ -335,7 +335,7 @@ void
openal_renderer::update( double const Deltatime ) { openal_renderer::update( double const Deltatime ) {
// update listener // update listener
// gain // gain
::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 0.f, 2.f ) * ( Global.iPause == 0 ? 1.f : 0.15f ) ); ::alListenerf( AL_GAIN, clamp( Global.AudioVolume, 0.f, 2.f ) * ( Global.iPause == 0 ? 1.f : Global.PausedVolume ) );
// orientation // orientation
glm::dmat4 cameramatrix; glm::dmat4 cameramatrix;
Global.pCamera.SetMatrix( cameramatrix ); Global.pCamera.SetMatrix( cameramatrix );

View File

@@ -279,7 +279,7 @@ scenario_panel::render() {
// hints // hints
if( owner != nullptr ) { if( owner != nullptr ) {
auto const hintheader{ locale::strings[ locale::string::driver_hint_header ] }; auto const hintheader{ locale::strings[ locale::string::driver_hint_header ] };
if( true == ImGui::CollapsingHeader( hintheader.c_str() ) ) { if( true == ImGui::CollapsingHeader( hintheader.c_str(), ImGuiTreeNodeFlags_DefaultOpen ) ) {
for( auto const &hint : owner->m_hints ) { for( auto const &hint : owner->m_hints ) {
auto const isdone { std::get<TController::hintpredicate>( hint )( std::get<float>( hint ) ) }; auto const isdone { std::get<TController::hintpredicate>( hint )( std::get<float>( hint ) ) };
auto const hintcolor{ ( auto const hintcolor{ (
@@ -1254,14 +1254,15 @@ debug_panel::update_section_eventqueue( std::vector<text_line> &Output ) {
&& ( ( false == m_eventqueueactivevehicleonly ) && ( ( false == m_eventqueueactivevehicleonly )
|| ( event->m_activator == m_input.vehicle ) ) ) { || ( event->m_activator == m_input.vehicle ) ) ) {
auto const label { event->m_name + ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" ) };
if( ( false == searchfilter.empty() ) if( ( false == searchfilter.empty() )
&& ( event->m_name.find( searchfilter ) == std::string::npos ) ) { && ( label.find( searchfilter ) == std::string::npos ) ) {
event = event->m_next; event = event->m_next;
continue; continue;
} }
auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) }; auto const delay { " " + to_string( std::max( 0.0, event->m_launchtime - time ), 1 ) };
auto const label { event->m_name + ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" ) };
textline = textline =
delay.substr( delay.length() - 6 ) delay.substr( delay.length() - 6 )
+ " " + " "

View File

@@ -64,7 +64,8 @@ class debug_panel : public ui_panel {
public: public:
debug_panel( std::string const &Name, bool const Isopen ) debug_panel( std::string const &Name, bool const Isopen )
: ui_panel( Name, Isopen ) {} : ui_panel( Name, Isopen ) {
m_eventsearch.fill( 0 ); }
void update() override; void update() override;
void render() override; void render() override;

View File

@@ -112,7 +112,7 @@ world_environment::update() {
// twilight factor can be reset later down, so we do it here while it's still reflecting state of the sun // twilight factor can be reset later down, so we do it here while it's still reflecting state of the sun
// turbidity varies from 2-3 during the day based on overcast, 3-4 after sunset to deal with sunlight bleeding too much into the sky from below horizon // turbidity varies from 2-3 during the day based on overcast, 3-4 after sunset to deal with sunlight bleeding too much into the sky from below horizon
m_skydome.SetTurbidity( m_skydome.SetTurbidity(
2.f 2.25f
+ clamp( Global.Overcast, 0.f, 1.f ) + clamp( Global.Overcast, 0.f, 1.f )
+ interpolate( 0.f, 1.f, clamp( twilightfactor * 1.5f, 0.f, 1.f ) ) ); + interpolate( 0.f, 1.f, clamp( twilightfactor * 1.5f, 0.f, 1.f ) ) );
m_skydome.SetOvercastFactor( Global.Overcast ); m_skydome.SetOvercastFactor( Global.Overcast );
@@ -173,8 +173,9 @@ world_environment::update() {
// update the fog. setting it to match the average colour of the sky dome is cheap // update the fog. setting it to match the average colour of the sky dome is cheap
// but quite effective way to make the distant items blend with background better // but quite effective way to make the distant items blend with background better
// NOTE: base brightness calculation provides scaled up value, so we bring it back to 'real' one here Global.FogColor =
Global.FogColor = m_skydome.GetAverageHorizonColor(); interpolate( m_skydome.GetAverageColor(), m_skydome.GetAverageHorizonColor(), 0.33f )
* clamp<float>( Global.fLuminance, 0.25f, 1.f );
// weather-related simulation factors // weather-related simulation factors
Global.FrictionWeatherFactor = ( Global.FrictionWeatherFactor = (

View File

@@ -264,6 +264,10 @@ void CSkyDome::RebuildColors() {
colorconverter.z = 1.0f - std::exp( -m_expfactor * colorconverter.z ); colorconverter.z = 1.0f - std::exp( -m_expfactor * colorconverter.z );
} }
if( colorconverter.z > 0.85f ) {
colorconverter.z = 0.85f + ( colorconverter.z - 0.85f ) * 0.35f;
}
colorconverter.y = clamp( colorconverter.y * 1.15f, 0.0f, 1.0f ); colorconverter.y = clamp( colorconverter.y * 1.15f, 0.0f, 1.0f );
// desaturate sky colour, based on overcast level // desaturate sky colour, based on overcast level
if( colorconverter.y > 0.0f ) { if( colorconverter.y > 0.0f ) {
@@ -310,14 +314,14 @@ void CSkyDome::RebuildColors() {
// save // save
m_colours[ i ] = color; m_colours[ i ] = color;
averagecolor += color; averagecolor += color;
if( ( m_vertices.size() - i ) <= ( m_tesselation * 2 ) ) { if( ( m_vertices.size() - i ) <= ( m_tesselation * 3 + 3 ) ) {
// calculate horizon colour from the bottom band of tris // calculate horizon colour from the bottom band of tris
averagehorizoncolor += color; averagehorizoncolor += color;
} }
} }
m_averagecolour = glm::max( glm::vec3(), averagecolor / static_cast<float>( m_vertices.size() ) ); m_averagecolour = glm::max( glm::vec3(), averagecolor / static_cast<float>( m_vertices.size() ) );
m_averagehorizoncolour = glm::max( glm::vec3(), averagehorizoncolor / static_cast<float>( m_tesselation * 2 ) ); m_averagehorizoncolour = glm::max( glm::vec3(), averagehorizoncolor / static_cast<float>( m_tesselation * 3 + 3 ) );
m_dirty = true; m_dirty = true;
} }

View File

@@ -77,6 +77,7 @@ ui_layer::init( GLFWwindow *Window ) {
static ImWchar const glyphranges[] = { static ImWchar const glyphranges[] = {
0x0020, 0x00FF, // ascii + extension 0x0020, 0x00FF, // ascii + extension
0x0100, 0x017F, // latin extended-a
0x2070, 0x2079, // superscript 0x2070, 0x2079, // superscript
0x2500, 0x256C, // box drawings 0x2500, 0x256C, // box drawings
0, 0,

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#define VERSION_MAJOR 21 #define VERSION_MAJOR 21
#define VERSION_MINOR 305 #define VERSION_MINOR 324
#define VERSION_REVISION 0 #define VERSION_REVISION 0