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;
}
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 ) {
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ą
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
Point.fVelNext = 0;
// potentially announce pending stop
@@ -1540,7 +1542,7 @@ TController::TableUpdateEvent( double &Velocity, TCommandType &Command, TSpeedPo
Velocity = 0.0;
}
else {
VelSignalNext - Point.fVelNext;
VelSignalNext = Point.fVelNext;
if( Velocity < 0 ) {
Velocity = fVelMax;
VelSignal = fVelMax;
@@ -2510,10 +2512,8 @@ bool TController::CheckVehicles(TOrders user)
*/
}
// Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61
if( ( is_emu() )
|| ( is_dmu() )
|| ( iVehicles == 1 ) ) {
// detect push-pull train configurations and mark them accordingly
if( pVehicles[ end::front ]->is_connected( pVehicles[ end::rear ], coupling::control ) ) {
// zmiana czoła przez zmianę kabiny
iDrivigFlags |= movePushPull;
}
@@ -2540,7 +2540,7 @@ void TController::Lights(int head, int rear)
void TController::DirectionInitial()
{ // ustawienie kierunku po wczytaniu trainset (może jechać na wstecznym
mvOccupied->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
if (mvOccupied->Vel > 0.0)
if (mvOccupied->Vel > EU07_AI_NOMOVEMENT)
{ // jeśli na starcie jedzie
iDirection = iDirectionOrder =
(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
if( mvOccupied->Vel > 0.01 ) { return false; }
if( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) { return false; }
LastReactionTime = 0.0;
ReactionTime = PrepareTime;
@@ -3248,7 +3248,7 @@ bool TController::DecBrakeEIM()
{
case 0: {
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 ) };
OK = ( brakeposition != mvOccupied->LocalBrakePosA );
mvOccupied->LocalBrakePosA = brakeposition;
@@ -3684,7 +3684,7 @@ void TController::SpeedSet() {
else {
// jak ma jechać
if( fActionTime < 0.0 ) { break; }
if( fReady > ( mvOccupied->Vel > 5.0 ? 0.5 : 0.4 ) ) { break; }
if( false == Ready ) { break; }
if( mvOccupied->DirActive > 0 ) {
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 )
&& ( ( 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::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
else if (!o) // jeśli wcześniej było czekanie
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
// Change_direction wykona się samo i następnie przejdzie do kolejnej komendy
return true;
@@ -4795,7 +4795,7 @@ TController::Update( double const Timedelta ) {
auto const awarenessrange {
std::max(
750.0,
mvOccupied->Vel > 5.0 ?
mvOccupied->Vel > EU07_AI_MOVEMENT ?
400 + fBrakeDist :
30.0 * fDriverDist ) }; // 1500m dla stojących pociągów;
if( is_active() ) {
@@ -4893,8 +4893,9 @@ TController::PrepareDirection() {
if( iDirection == 0 ) {
// 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
/*
if( iDirection == 0 ) {
// jeśli nie ma ustalonego kierunku
if( mvOccupied->Couplers[ end::rear ].Connected == nullptr ) {
@@ -4906,6 +4907,7 @@ TController::PrepareDirection() {
iDirection = 1; // jazda w kierunku sprzęgu 0
}
}
*/
}
else {
// ustalenie kierunku, gdy jedzie
@@ -5354,7 +5356,7 @@ TCommandType TController::BackwardScan( double const Range )
}
else {
if( ( scandist > fMinProximityDist )
&& ( ( mvOccupied->Vel > 0.0 )
&& ( ( mvOccupied->Vel > EU07_AI_NOMOVEMENT )
&& ( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) == 0 ) ) ) {
// 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ł
@@ -5393,12 +5395,12 @@ TCommandType TController::BackwardScan( double const Range )
if (move ? true : e->input_command() == TCommandType::cm_ShuntVelocity)
{ // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1
if ((scandist > fMinProximityDist) &&
(mvOccupied->Vel > 0.0) || (vmechmax == 0.0) )
(mvOccupied->Vel > EU07_AI_NOMOVEMENT) || (vmechmax == 0.0) )
{ // jeśli tarcza jest daleko, to:
//- jesli pojazd jedzie, to informujemy o zmianie prędkości
//- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą
// 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);
#if LOGBACKSCAN
// WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+"
@@ -5907,7 +5909,7 @@ TController::determine_consist_state() {
fAccGravity /= fMass;
{
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;
auto *d = pVehicles[ end::front ]; // pojazd na czele składu
while( d ) {
@@ -5939,7 +5941,7 @@ TController::determine_consist_state() {
if( has_diesel_engine() ) {
Ready = (
( vehicle->Vel > 0.5 ) // already moving
( vehicle->Vel > EU07_AI_MOVEMENT ) // already moving
|| ( false == vehicle->Mains ) // deadweight vehicle
|| ( vehicle->enrot > 0.8 * (
vehicle->EngineType == TEngineType::DieselEngine ?
@@ -6001,7 +6003,7 @@ TController::control_pantographs() {
|| ( is_emu() ) // special case
|| ( mvControlling->TrainType == dt_ET41 ) }; // special case
if( mvOccupied->Vel > 0.05 ) {
if( mvOccupied->Vel > EU07_AI_NOMOVEMENT ) {
if( ( fOverhead2 >= 0.0 ) || iOverheadZero ) {
// 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
}
}
if( mvOccupied->Vel >= 5.0 ) {
if( mvOccupied->Vel > EU07_AI_MOVEMENT ) {
// jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy
iDrivigFlags &= ~moveStartHornDone; // zatrąbi dopiero jak następnym razem stanie
iDrivigFlags |= moveStartHorn; // i trąbić przed następnym ruszeniem
@@ -6292,7 +6294,7 @@ TController::control_doors() {
if( false == doors_open() ) { return; }
// jeżeli jedzie
// 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 );
return;
}
@@ -6600,25 +6602,30 @@ TController::check_departure() {
void
TController::UpdateChangeDirection() {
// TODO: rework into driver mode independent routine
if( ( true == AIControllFlag)
&& ( true == TestFlag( OrderCurrentGet(), Change_direction ) ) ) {
if( false == TestFlag( OrderCurrentGet(), Change_direction ) ) { return; }
if( true == AIControllFlag ) {
// 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
Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI
PrepareEngine();
JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo Obey_train)
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) {
// 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)
}
// shared part of the routine, implement if direction matches what was requested
if( ( mvOccupied->Vel < EU07_AI_NOMOVEMENT )
&& ( iDirection == iDirectionOrder ) ) {
PrepareEngine();
JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo Obey_train)
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) {
// 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
@@ -7116,7 +7123,7 @@ TController::adjust_desired_speed_for_obstacles() {
}
}
ReactionTime = (
mvOccupied->Vel > 0.01 ?
mvOccupied->Vel > EU07_AI_NOMOVEMENT ?
0.1 : // orientuj się, bo jest goraco
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 )
&& ( vel >= VelNext ) ) {
// 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
if( ( vel < VelNext )
&& ( 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 ) );
}
// final tweaks
if( vel > 0.1 ) {
if( vel > EU07_AI_NOMOVEMENT ) {
// going downhill also take into account impact of gravity
AccDesired -= fAccGravity;
// 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 ) {
// don't adjust acceleration when going above current target speed
if( -AccDesired * BrakeAccFactor() < (
( ( fReady > ( IsHeavyCargoTrain ? 0.4 : ( mvOccupied->Vel > 5.0 ) ? 0.45 : 0.4 ) )
( ( false == Ready )
|| ( VelNext > vel - 40.0 ) ) ?
fBrake_a0[ 0 ] * 0.8 :
-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( ( 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...
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
if( ( mvOccupied->Vel < 0.01 )
if( ( mvOccupied->Vel < EU07_AI_NOMOVEMENT )
&& ( ( VelDesired == 0.0 )
|| ( 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
// do it only if the vehicle actually has the independent brake
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
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;
}

View File

@@ -18,6 +18,8 @@ http://mozilla.org/MPL/2.0/.
#include "translation.h"
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;
enum TOrders

View File

@@ -249,6 +249,9 @@ bool TDynamicObject::destination_data::deserialize_mapping( cParser &Input ) {
else if( key == "parameters:" ) {
parameters = Input.getToken<std::string>();
}
else if( key == "background:" ) {
background = Input.getToken<std::string>();
}
return true;
}
@@ -4648,31 +4651,47 @@ void TDynamicObject::RenderSounds() {
}
}
// attach/detach sounds
if( ( coupler.sounds & sound::attachcoupler ) != 0 ) {
couplersounds.attach_coupler.play();
if( ( coupler.sounds & sound::detach ) == 0 ) {
// 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 ) {
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( true == TestFlag( coupler.sounds, sound::detachall ) ) {
couplersounds.detach_coupler.play();
couplersounds.detach_brakehose.play();
couplersounds.detach_mainhose.play();
couplersounds.detach_control.play();
couplersounds.detach_gangway.play();
couplersounds.detach_heating.play();
else {
// potentially removed some couplings
if( ( coupler.sounds & sound::attachcoupler ) != 0 ) {
couplersounds.detach_coupler.play();
}
if( ( coupler.sounds & sound::attachbrakehose ) != 0 ) {
couplersounds.detach_brakehose.play();
}
if( ( coupler.sounds & sound::attachmainhose ) != 0 ) {
couplersounds.detach_mainhose.play();
}
if( ( coupler.sounds & sound::attachcontrol ) != 0 ) {
couplersounds.detach_control.play();
}
if( ( coupler.sounds & sound::attachgangway ) != 0 ) {
couplersounds.detach_gangway.play();
}
if( ( coupler.sounds & sound::attachheating ) != 0 ) {
couplersounds.detach_heating.play();
}
}
if( true == TestFlag( coupler.sounds, sound::attachadapter ) ) {
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
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
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
// add entry to the list
auto const location { glm::vec3 { 0.f, 0.f, offset } };
motor.offset( location );
m_powertrainsounds.motors.emplace_back( motor );
acmotor.offset( location );
m_powertrainsounds.acmotors.emplace_back( acmotor );
motorblower.offset( location );
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;
}
}
// NOTE: legacy key, now expected as optional "background:" parameter in pydestinationsign: { parameter block }
else if( token == "destinationsignbackground:" ) {
parser.getTokens();
parser >> DestinationSign.background;

View File

@@ -58,6 +58,14 @@ public:
// returns offset of submodel associated with the button from the model centre
glm::vec3 model_offset() 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
TSubModel *SubModel { nullptr }, // McZapkie-310302: zeby mozna bylo sprawdzac czy zainicjowany poprawnie
*SubModelOn { nullptr }; // optional submodel visible when the state input is set

View File

@@ -174,6 +174,12 @@ global_settings::ConfigParse(cParser &Parser) {
Parser >> EnvironmentAmbientVolume;
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
// bRenderAlpha=(GetNextSymbol().LowerCase()==AnsiString("yes"));
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.positional", EnvironmentPositionalVolume );
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, "fullphysics", FullPhysics );
export_as_text( Output, "debuglog", iWriteLogEnabled );

View File

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

View File

@@ -243,7 +243,7 @@ enum sound {
parallel = 1 << 4,
shuntfield = 1 << 5,
pneumatic = 1 << 6,
detachall = 1 << 7,
detach = 1 << 7,
attachcoupler = 1 << 8,
attachbrakehose = 1 << 9,
attachmainhose = 1 << 10,
@@ -1168,6 +1168,7 @@ public:
bool UniCtrlIntegratedBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie*/
bool UniCtrlIntegratedLocalBrakeCtrl = false; /*zintegrowany nastawnik JH obsluguje hamowanie hamulcem pomocniczym*/
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*/
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
auto const i = DettachStatus(ConnectNo); // stan sprzęgu
if (i < 0) {
auto couplingchange { coupler.CouplingFlag }; // presume we'll uncouple all active flags
auto const couplingstate { DettachStatus( ConnectNo ) }; // stan sprzęgu
if (couplingstate < 0) {
// gdy scisniete zderzaki, chyba ze zerwany sprzeg (wirtualnego nie odpinamy z drugiej strony)
std::tie( coupler.Connected, coupler.ConnectedNr, coupler.CouplingFlag )
= std::tie( othercoupler.Connected, othercoupler.ConnectedNr, othercoupler.CouplingFlag )
= 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)
coupler.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()
@@ -10800,6 +10816,14 @@ void TMoverParameters::LoadFIZ_Switches( std::string const &Input ) {
extract_value( UniversalResetButtonFlag[ 0 ], "RelayResetButton1", Input, "" );
extract_value( UniversalResetButtonFlag[ 1 ], "RelayResetButton2", 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 ) {

287
Train.cpp
View File

@@ -31,7 +31,6 @@ http://mozilla.org/MPL/2.0/.
#include "Console.h"
#include "application.h"
#include "renderer.h"
#include "dictionary.h"
/*
namespace input {
@@ -72,6 +71,38 @@ control_mapper::contains( std::string const Control ) const {
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)
{
// 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;
}
dictionary_source *TTrain::GetTrainState() {
dictionary_source *TTrain::GetTrainState( dictionary_source const &Extraparameters ) {
if( ( mvOccupied == nullptr )
|| ( mvControlled == nullptr ) ) { return nullptr; }
auto *dict { new dictionary_source };
auto *dict { new dictionary_source( Extraparameters ) };
if( dict == nullptr ) { return nullptr; }
dict->insert( "name", DynamicObject->asName );
@@ -612,6 +643,7 @@ dictionary_source *TTrain::GetTrainState() {
dict->insert( "distance_counter", m_distancecounter );
dict->insert( "pantpress", std::abs( mvPantographUnit->PantPress ) );
dict->insert( "universal3", InstrumentLightActive );
dict->insert( "radio", mvOccupied->Radio );
dict->insert( "radio_channel", RadioChannel() );
dict->insert( "radio_volume", Global.RadioVolume );
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( "slipping_wheels", mvOccupied->SlippingWheels );
dict->insert( "sanding", mvOccupied->SandDose );
dict->insert( "odometer", mvOccupied->DistCounter );
// electric current data
dict->insert( "traction_voltage", std::abs( mvPantographUnit->PantographVoltage ) );
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 ) {
// impulse switch
if( Command.action == GLFW_RELEASE ) {
// just move the button back to default position
// just move the button(s) back to default position
// visual feedback
Train->ggScndCtrlButton.UpdateValue( 0.0, Train->dsbSwitch );
Train->ggScndCtrlOffButton.UpdateValue( 0.0, Train->dsbSwitch );
return;
}
// glfw_press
if( Train->mvControlled->ScndCtrlPos == 0 ) {
// turn on if needed
// turn on if it's not active
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 {
// 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 ) {
// 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 ) {
// 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 ) {
// 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 ) {
// 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 ) {
// 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
if( ( Train->iCabn != 0 )
&& ( 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 ) {
// 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
if( ( Train->iCabn != 0 )
&& ( 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 ) {
// 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
if( ( Train->iCabn != 0 )
&& ( 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 ) {
// 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 )
&& ( false == Train->m_controlmapper.contains(
Train->mvOccupied->PantSwitchType == "impulse" ?
@@ -2404,7 +2450,7 @@ void TTrain::OnCommand_pantographselectnext( TTrain *Train, command_data const &
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 );
}
@@ -2413,7 +2459,7 @@ void TTrain::OnCommand_pantographselectprevious( TTrain *Train, command_data con
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 );
}
@@ -2508,19 +2554,19 @@ void TTrain::OnCommand_pantographlowerselected( TTrain *Train, command_data cons
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 );
// visual feedback
ggPantSelectButton.UpdateValue( m_pantselection );
if( m_pantselection == initialstate ) { return; } // no change, nothing to do
if( selection == initialstate ) { return; } // no change, nothing to do
// configure pantograph valves matching the new state
auto const preset { presets[ selection ] - '0' };
auto const swapends { cab_to_end() != end::front };
// 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 rearstate{ ( m_pantselection == 2 ) || ( m_pantselection == ( swapends ? 3 : 1 ) ) };
auto const frontstate { preset & ( swapends ? 1 : 2 ) };
auto const rearstate { preset & ( swapends ? 2 : 1 ) };
// potentially adjust pantograph valves
mvOccupied->OperatePantographValve( end::front, ( frontstate ? 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 ) {
// TODO: move logic/visualization code to the gauge, on_command() should return hint whether it should invoke a reaction
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();
}
ggScndCtrlButton.Update( lowvoltagepower );
ggScndCtrlOffButton.Update( lowvoltagepower );
ggDistanceCounterButton.Update();
if (ggDirKey.SubModel) {
if (mvControlled->TrainType != dt_EZT)
@@ -7047,16 +7112,17 @@ bool TTrain::Update( double const Deltatime )
// NBMX wrzesien 2003 - drzwi
ggDoorLeftPermitButton.Update( lowvoltagepower );
ggDoorRightPermitButton.Update( lowvoltagepower );
ggDoorPermitPresetButton.Update();
ggDoorLeftButton.Update();
ggDoorRightButton.Update();
ggDoorLeftOnButton.Update();
ggDoorRightOnButton.Update();
ggDoorLeftOffButton.Update();
ggDoorRightOffButton.Update();
ggDoorAllOnButton.Update();
ggDoorPermitPresetButton.Update( lowvoltagepower );
ggDoorLeftButton.Update( lowvoltagepower );
ggDoorRightButton.Update( lowvoltagepower );
ggDoorLeftOnButton.Update( lowvoltagepower );
ggDoorRightOnButton.Update( lowvoltagepower );
ggDoorLeftOffButton.Update( lowvoltagepower );
ggDoorRightOffButton.Update( lowvoltagepower );
ggDoorAllOnButton.Update( lowvoltagepower );
ggDoorAllOffButton.Update( lowvoltagepower );
ggDoorSignallingButton.Update();
ggDoorSignallingButton.Update( lowvoltagepower );
ggDoorStepButton.Update( lowvoltagepower );
// NBMX dzwignia sprezarki
ggCompressorButton.Update();
ggCompressorLocalButton.Update();
@@ -7125,7 +7191,6 @@ bool TTrain::Update( double const Deltatime )
ggPantAllDownButton.Update();
ggPantSelectedDownButton.Update();
ggPantSelectedButton.Update();
ggPantSelectButton.Update();
ggPantCompressorButton.Update();
ggPantCompressorValve.Update();
@@ -7237,13 +7302,13 @@ bool TTrain::Update( double const Deltatime )
&& ( fScreenTimer > std::max( fScreenUpdateRate, Global.PythonScreenUpdateRate ) * 0.001f )
&& ( false == FreeFlyModeFlag ) ) { // don't bother if we're outside
fScreenTimer = 0.f;
for( auto const &screen : m_screens ) {
auto state_dict = GetTrainState();
for( auto &screen : m_screens ) {
auto *state_dict = GetTrainState( screen.parameters );
/*
state_dict->insert("touches", *screen.touch_list);
screen.touch_list->clear();
*/
Application.request({ screen.rendererpath, state_dict, screen.rt } );
Application.request( { screen.script, state_dict, screen.rt } );
}
}
// sounds
@@ -8038,60 +8103,62 @@ bool TTrain::InitializeCab(int NewCabNo, std::string const &asFileName)
// TODO: add "pydestination:"
else if (token == "pyscreen:")
{
std::string submodelname, renderername;
parser.getTokens( 2 );
parser
>> submodelname
>> renderername;
screen_entry screen;
screen.deserialize(parser);
if ((false == screen.script.empty()) && (substr_path(screen.script).empty()))
{
screen.script = DynamicObject->asBaseDir + screen.script;
}
const std::string rendererpath {
substr_path(renderername).empty() ? // supply vehicle folder as path if none is provided
DynamicObject->asBaseDir + renderername :
renderername };
opengl_texture *tex = nullptr;
opengl_texture *tex = nullptr;
TSubModel *submodel = nullptr;
if (submodelname != "none") {
submodel = (
DynamicObject->mdKabina ? DynamicObject->mdKabina->GetFromName( submodelname ) :
DynamicObject->mdLowPolyInt ? DynamicObject->mdLowPolyInt->GetFromName( submodelname ) :
nullptr );
if( submodel == nullptr ) {
WriteLog( "Python Screen: submodel " + submodelname + " not found - 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;
}
if (screen.target != "none")
{
submodel = (DynamicObject->mdKabina ?
DynamicObject->mdKabina->GetFromName(screen.target) :
DynamicObject->mdLowPolyInt ?
DynamicObject->mdLowPolyInt->GetFromName(screen.target) :
nullptr);
if (submodel == nullptr)
{
WriteLog("Python Screen: submodel " + screen.target +
" not found - 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]);
}
else {
// TODO: fix leak
tex = new opengl_texture();
tex->make_stub();
}
}
else
{
// TODO: fix leak
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
// TBD, TODO: keep texture handles around, so we can undo the static switch when the user changes cabs?
tex->create(true); // make the surface static so it doesn't get destroyed by garbage
// 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
m_screens.emplace_back();
m_screens.back().rendererpath = rendererpath;
m_screens.emplace_back(screen);
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)
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()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
target_train->Dynamic()->MechInside = true;
target_train->Dynamic()->Controller = ( target_train->Dynamic()->Mechanik ? !target_train->Dynamic()->Mechanik->AIControllFlag : Humandriver );
} else {
if( target_train->Dynamic()->Mechanik ) {
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()->ABuSetModelShake( {} );
}
@@ -8327,7 +8400,13 @@ TTrain::MoveToVehicle(TDynamicObject *target) {
Occupied()->LimPipePress = Occupied()->PipePress;
Occupied()->CabActivisation( true ); // załączenie rozrządu (wirtualne kabiny)
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 {
Dynamic()->bDisplayCab = false;
Dynamic()->ABuSetModelShake( {} );
@@ -8429,6 +8508,7 @@ void TTrain::clear_cab_controls()
ggMainCtrlAct.Clear();
ggScndCtrl.Clear();
ggScndCtrlButton.Clear();
ggScndCtrlOffButton.Clear();
ggDistanceCounterButton.Clear();
ggDirKey.Clear();
ggDirForwardButton.Clear();
@@ -8512,6 +8592,7 @@ void TTrain::clear_cab_controls()
ggTrainHeatingButton.Clear();
ggSignallingButton.Clear();
ggDoorSignallingButton.Clear();
ggDoorStepButton.Clear();
ggDepartureSignalButton.Clear();
ggCompressorButton.Clear();
ggCompressorLocalButton.Clear();
@@ -8528,7 +8609,6 @@ void TTrain::clear_cab_controls()
ggPantAllDownButton.Clear();
ggPantSelectedButton.Clear();
ggPantSelectedDownButton.Clear();
ggPantSelectButton.Clear();
ggPantCompressorButton.Clear();
ggPantCompressorValve.Clear();
ggI1B.Clear();
@@ -8705,13 +8785,6 @@ void TTrain::set_cab_controls( int const 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 ) {
ggPantSelectedButton.PutValue(
( mvPantographUnit->PantsValve.is_enabled ?
@@ -8825,10 +8898,10 @@ void TTrain::set_cab_controls( int const Cab ) {
1.f :
0.f ) );
// 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 );
}
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 );
}
ggDoorPermitPresetButton.PutValue( mvOccupied->Doors.permit_preset );
@@ -8840,8 +8913,15 @@ void TTrain::set_cab_controls( int const Cab ) {
mvOccupied->Doors.lock_enabled ?
1.f :
0.f );
// door step
if( false == ggDoorStepButton.is_push() ) {
ggDoorStepButton.PutValue(
mvOccupied->Doors.step_enabled ?
1.f :
0.f );
}
// heating
if( ggTrainHeatingButton.type() != TGaugeType::push ) {
if( false == ggTrainHeatingButton.is_push() ) {
ggTrainHeatingButton.PutValue(
mvControlled->Heating ?
1.f :
@@ -8946,7 +9026,7 @@ void TTrain::set_cab_controls( int const Cab ) {
0.f );
}
// tempomat
if( ggScndCtrlButton.type() != TGaugeType::push ) {
if( false == ggScndCtrlButton.is_push() ) {
ggScndCtrlButton.PutValue(
( mvControlled->ScndCtrlPos > 0 ) ?
1.f :
@@ -9225,7 +9305,6 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
{ "pantalloff_sw:", ggPantAllDownButton },
{ "pantselected_sw:", ggPantSelectedButton },
{ "pantselectedoff_sw:", ggPantSelectedDownButton },
{ "pantselect_sw:", ggPantSelectButton },
{ "pantcompressor_sw:", ggPantCompressorButton },
{ "pantcompressorvalve_sw:", ggPantCompressorValve },
{ "trainheating_sw:", ggTrainHeatingButton },
@@ -9265,9 +9344,12 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con
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 = {
{ "tempomat_sw:", { ggScndCtrlButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "tempomatoff_sw:", { ggScndCtrlOffButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "speedinc_bt:", { ggSpeedControlIncreaseButton, &mvOccupied->SpeedCtrlUnit.IsActive } },
{ "speeddec_bt:", { ggSpeedControlDecreaseButton, &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 } },
{ "doorrightpermit_sw:", { ggDoorRightPermitButton, &mvOccupied->Doors.instances[ ( cab_to_end() == end::front ? side::right : side::left ) ].open_permit } },
{ "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 } },
{ "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
std::unordered_map<std::string, bool *> const autoboolgauges = {
{ "doormode_sw:", &mvOccupied->Doors.remote_only },
{ "doorstep_sw:", &mvOccupied->Doors.step_enabled },
{ "coolingfans_sw:", &mvControlled->RVentForceOn },
{ "pantfront_sw:", &mvPantographUnit->Pantographs[end::front].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
std::unordered_map<std::string, int *> const autointgauges = {
{ "manualbrake:", &mvOccupied->ManualBrakePos },
{ "pantselect_sw:", &mvOccupied->PantsPreset.second[cab_to_end()] },
};
{
auto lookup = autointgauges.find( Label );

32
Train.h
View File

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

View File

@@ -335,7 +335,7 @@ void
openal_renderer::update( double const Deltatime ) {
// update listener
// 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
glm::dmat4 cameramatrix;
Global.pCamera.SetMatrix( cameramatrix );

View File

@@ -279,7 +279,7 @@ scenario_panel::render() {
// hints
if( owner != nullptr ) {
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 ) {
auto const isdone { std::get<TController::hintpredicate>( hint )( std::get<float>( hint ) ) };
auto const hintcolor{ (
@@ -1254,14 +1254,15 @@ debug_panel::update_section_eventqueue( std::vector<text_line> &Output ) {
&& ( ( false == m_eventqueueactivevehicleonly )
|| ( event->m_activator == m_input.vehicle ) ) ) {
auto const label { event->m_name + ( event->m_activator ? " (by: " + event->m_activator->asName + ")" : "" ) };
if( ( false == searchfilter.empty() )
&& ( event->m_name.find( searchfilter ) == std::string::npos ) ) {
&& ( label.find( searchfilter ) == std::string::npos ) ) {
event = event->m_next;
continue;
}
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 =
delay.substr( delay.length() - 6 )
+ " "

View File

@@ -64,7 +64,8 @@ class debug_panel : public ui_panel {
public:
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 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
// 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(
2.f
2.25f
+ clamp( Global.Overcast, 0.f, 1.f )
+ interpolate( 0.f, 1.f, clamp( twilightfactor * 1.5f, 0.f, 1.f ) ) );
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
// 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 = m_skydome.GetAverageHorizonColor();
Global.FogColor =
interpolate( m_skydome.GetAverageColor(), m_skydome.GetAverageHorizonColor(), 0.33f )
* clamp<float>( Global.fLuminance, 0.25f, 1.f );
// weather-related simulation factors
Global.FrictionWeatherFactor = (

View File

@@ -264,6 +264,10 @@ void CSkyDome::RebuildColors() {
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 );
// desaturate sky colour, based on overcast level
if( colorconverter.y > 0.0f ) {
@@ -310,14 +314,14 @@ void CSkyDome::RebuildColors() {
// save
m_colours[ i ] = 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
averagehorizoncolor += color;
}
}
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;
}

View File

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

View File

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