mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-19 13:29:18 +02:00
Merge with TMJ
This commit is contained in:
547
Driver.cpp
547
Driver.cpp
@@ -15,8 +15,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "Driver.h"
|
||||
|
||||
#include <direct.h>
|
||||
//#include <direct.h>
|
||||
#include "Globals.h"
|
||||
#include "translation.h"
|
||||
#include "Logs.h"
|
||||
#include "Train.h"
|
||||
#include "mtable.h"
|
||||
@@ -351,7 +352,7 @@ std::string TSpeedPos::TableText() const
|
||||
|
||||
bool TSpeedPos::IsProperSemaphor(TOrders order)
|
||||
{ // sprawdzenie czy semafor jest zgodny z trybem jazdy
|
||||
if (order < 0x40) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt
|
||||
if (order < Obey_train) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt
|
||||
{
|
||||
if (iFlags & (spSemaphor | spShuntSemaphor))
|
||||
return true;
|
||||
@@ -382,7 +383,7 @@ bool TSpeedPos::Set(basic_event *event, double dist, double length, TOrders orde
|
||||
// zależnie od trybu sprawdzenie czy jest tutaj gdzieś semafor lub tarcza manewrowa
|
||||
// jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania
|
||||
// WriteLog("EventSet: Vel=" + AnsiString(fVelNext) + " iFlags=" + AnsiString(iFlags) + " order="+AnsiString(order));
|
||||
if (order < 0x40) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt
|
||||
if (order < Obey_train) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt
|
||||
{
|
||||
if (iFlags & (spSemaphor | spShuntSemaphor) && fVelNext == 0.0)
|
||||
return true;
|
||||
@@ -541,7 +542,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if( ( OrderCurrentGet() < 0x40 )
|
||||
if( ( OrderCurrentGet() < Obey_train )
|
||||
&& ( sSpeedTable[SemNextStopIndex].iFlags & ( spSemaphor | spShuntSemaphor | spOutsideStation ) ) ) {
|
||||
return;
|
||||
}
|
||||
@@ -860,7 +861,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
// jeśli przystanek, trzeba obsłużyć wg rozkładu
|
||||
iDrivigFlags |= moveStopPointFound;
|
||||
// stop points are irrelevant when not in one of the basic modes
|
||||
if( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) == 0 ) { continue; }
|
||||
if( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) { continue; }
|
||||
// first 19 chars of the command is expected to be "PassengerStopPoint:" so we skip them
|
||||
if ( ToLower(sSpeedTable[i].evEvent->input_text()).compare( 19, sizeof(asNextStop), ToLower(asNextStop)) != 0 )
|
||||
{ // jeśli nazwa nie jest zgodna
|
||||
@@ -1012,7 +1013,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN
|
||||
}
|
||||
}
|
||||
|
||||
if (OrderCurrentGet() & Shunt) {
|
||||
if (OrderCurrentGet() & ( Shunt | Loose_shunt )) {
|
||||
OrderNext(Obey_train); // uruchomić jazdę pociągową
|
||||
CheckVehicles(); // zmienić światła
|
||||
}
|
||||
@@ -1688,15 +1689,62 @@ std::string TController::Order2Str(TOrders Order) const {
|
||||
case Connect: return "Connect";
|
||||
case Disconnect: return "Disconnect";
|
||||
case Shunt: return "Shunt";
|
||||
case Loose_shunt: return "Loose_shunt";
|
||||
case Obey_train: return "Obey_train";
|
||||
case Bank: return "Bank";
|
||||
case Jump_to_first_order: return "Jump_to_first_order";
|
||||
default: return "Undefined";
|
||||
}
|
||||
}
|
||||
|
||||
std::array<char, 64> orderbuffer;
|
||||
|
||||
std::string TController::OrderCurrent() const
|
||||
{ // pobranie aktualnego rozkazu celem wyświetlenia
|
||||
return "[" + std::to_string(OrderPos) + "] " + Order2Str(OrderList[OrderPos]);
|
||||
auto const order { OrderCurrentGet() };
|
||||
if( order & Change_direction ) {
|
||||
return locale::strings[ locale::string::driver_scenario_changedirection ];
|
||||
}
|
||||
|
||||
switch( OrderList[ OrderPos ] ) {
|
||||
case Wait_for_orders: { return locale::strings[ locale::string::driver_scenario_waitfororders ]; }
|
||||
case Prepare_engine: { return locale::strings[ locale::string::driver_scenario_prepareengine ]; }
|
||||
case Release_engine: { return locale::strings[ locale::string::driver_scenario_releaseengine ]; }
|
||||
case Change_direction: { return locale::strings[ locale::string::driver_scenario_changedirection ]; }
|
||||
case Connect: { return locale::strings[ locale::string::driver_scenario_connect ]; }
|
||||
case Disconnect: {
|
||||
if( iVehicleCount < 0 ) {
|
||||
// done with uncoupling, order should update shortly
|
||||
return locale::strings[ locale::string::driver_scenario_waitfororders ];
|
||||
}
|
||||
// try to provide some task details
|
||||
auto const count { iVehicleCount };
|
||||
|
||||
if( iVehicleCount > 1 ) {
|
||||
std::snprintf(
|
||||
orderbuffer.data(), orderbuffer.size(),
|
||||
( iVehicleCount < 5 ?
|
||||
locale::strings[ locale::string::driver_scenario_fewvehicles ].c_str() : // 2-4
|
||||
locale::strings[ locale::string::driver_scenario_somevehicles ].c_str() ), // 5+
|
||||
count );
|
||||
}
|
||||
auto const countstring { (
|
||||
count == 0 ? locale::strings[ locale::string::driver_scenario_allvehicles ] :
|
||||
count == 1 ? locale::strings[ locale::string::driver_scenario_onevehicle ] :
|
||||
orderbuffer.data() ) };
|
||||
|
||||
std::snprintf(
|
||||
orderbuffer.data(), orderbuffer.size(),
|
||||
locale::strings[ locale::string::driver_scenario_disconnect ].c_str(),
|
||||
countstring.c_str() );
|
||||
return orderbuffer.data();
|
||||
}
|
||||
case Shunt: { return locale::strings[ locale::string::driver_scenario_shunt ]; }
|
||||
case Loose_shunt: { return locale::strings[ locale::string::driver_scenario_looseshunt ]; }
|
||||
case Obey_train: { return locale::strings[ locale::string::driver_scenario_obeytrain ]; }
|
||||
case Bank: { return locale::strings[ locale::string::driver_scenario_bank ]; }
|
||||
default: { return{}; }
|
||||
}
|
||||
};
|
||||
|
||||
void TController::OrdersClear()
|
||||
@@ -1766,14 +1814,13 @@ void TController::Activation()
|
||||
// ewentualna zmiana kabiny użytkownikowi
|
||||
Global.changeDynObj = pVehicle; // uruchomienie protezy
|
||||
}
|
||||
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) -
|
||||
// silnikowy dla EZT
|
||||
ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT
|
||||
}
|
||||
if( mvControlling->EngineType == TEngineType::DieselEngine ) {
|
||||
// dla 2Ls150 - przed ustawieniem kierunku - można zmienić tryb pracy
|
||||
if( mvControlling->ShuntModeAllow ) {
|
||||
mvControlling->CurrentSwitch(
|
||||
( ( OrderList[ OrderPos ] & Shunt ) == Shunt )
|
||||
( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) != 0 )
|
||||
|| ( fMass > 224000.0 ) ); // do tego na wzniesieniu może nie dać rady na liniowym
|
||||
}
|
||||
}
|
||||
@@ -1908,7 +1955,7 @@ void TController::AutoRewident()
|
||||
fBrake_a1[i+1] = 0;
|
||||
}
|
||||
|
||||
if( OrderCurrentGet() & Shunt ) {
|
||||
if( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) {
|
||||
// for uniform behaviour and compatibility with older scenarios set default acceleration table values for shunting
|
||||
fAccThreshold = (
|
||||
mvOccupied->TrainType == dt_EZT ? -0.55 :
|
||||
@@ -1921,7 +1968,7 @@ void TController::AutoRewident()
|
||||
}
|
||||
}
|
||||
|
||||
if( OrderCurrentGet() & Obey_train ) {
|
||||
if( OrderCurrentGet() & ( Obey_train | Bank ) ) {
|
||||
// 4. Przeliczanie siły hamowania
|
||||
double const velstep = ( mvOccupied->Vmax*0.5 ) / BrakeAccTableSize;
|
||||
d = pVehicles[0]; // pojazd na czele składu
|
||||
@@ -2022,9 +2069,10 @@ double TController::ESMVelocity(bool Main)
|
||||
int TController::CheckDirection() {
|
||||
|
||||
int d = mvOccupied->DirAbsolute; // który sprzęg jest z przodu
|
||||
if( !d ) // jeśli nie ma ustalonego kierunku
|
||||
d = mvOccupied->CabNo; // to jedziemy wg aktualnej kabiny
|
||||
iDirection = d; // ustalenie kierunku jazdy (powinno zrobić PrepareEngine?)
|
||||
if( !d ) {
|
||||
// jeśli nie ma ustalonego kierunku to jedziemy wg aktualnej kabiny
|
||||
d = mvOccupied->CabNo;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -2076,8 +2124,8 @@ bool TController::CheckVehicles(TOrders user)
|
||||
{
|
||||
// HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi...
|
||||
if( ( p != pVehicle )
|
||||
&& ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 )
|
||||
&& ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 ) ) {
|
||||
&& ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 )
|
||||
&& ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) {
|
||||
// NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly
|
||||
p->MoverParameters->BatterySwitch( true );
|
||||
}
|
||||
@@ -2112,7 +2160,7 @@ bool TController::CheckVehicles(TOrders user)
|
||||
frontlights,
|
||||
rearlights );
|
||||
}
|
||||
else if (OrderCurrentGet() & (Shunt | Connect))
|
||||
else if (OrderCurrentGet() & (Shunt | Loose_shunt | Connect))
|
||||
{
|
||||
// HACK: the 'front' and 'rear' of the consist is determined by current consist direction
|
||||
// since direction shouldn't affect Tb1 light configuration, we 'counter' this behaviour by virtually swapping end vehicles
|
||||
@@ -2144,7 +2192,7 @@ bool TController::CheckVehicles(TOrders user)
|
||||
}
|
||||
}
|
||||
|
||||
if( OrderCurrentGet() & ( Obey_train | Shunt ) ) {
|
||||
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) {
|
||||
// nastawianie hamulca do jazdy pociągowej
|
||||
AutoRewident();
|
||||
// enable door locks
|
||||
@@ -2232,6 +2280,15 @@ void TController::DirectionInitial()
|
||||
CheckVehicles(); // sprawdzenie świateł oraz skrajnych pojazdów do skanowania
|
||||
};
|
||||
|
||||
void TController::DirectionChange() {
|
||||
|
||||
auto const initialstate { iDirection };
|
||||
iDirection = CheckDirection();
|
||||
if( iDirection != initialstate ) {
|
||||
CheckVehicles( Change_direction );
|
||||
}
|
||||
}
|
||||
|
||||
int TController::OrderDirectionChange(int newdir, TMoverParameters *Vehicle)
|
||||
{ // zmiana kierunku jazdy, niezależnie od kabiny
|
||||
int testd = newdir;
|
||||
@@ -2280,9 +2337,7 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r)
|
||||
{
|
||||
eStopReason = stopNone; // podana prędkość, to nie ma powodów do stania
|
||||
// to całe poniżej to warunki zatrąbienia przed ruszeniem
|
||||
if (OrderList[OrderPos] ?
|
||||
OrderList[OrderPos] & (Obey_train | Shunt | Connect | Prepare_engine) :
|
||||
true) // jeśli jedzie w dowolnym trybie
|
||||
if( (OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank | Connect | Prepare_engine ) ) != 0 ) // jeśli jedzie w dowolnym trybie
|
||||
if ((mvOccupied->Vel < 1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem)
|
||||
if (iDrivigFlags & moveStartHorn) // jezeli trąbienie włączone
|
||||
if (!(iDrivigFlags & (moveStartHornDone | moveConnect)))
|
||||
@@ -2311,7 +2366,7 @@ double TController::BrakeAccFactor() const
|
||||
|
||||
void TController::SetDriverPsyche()
|
||||
{
|
||||
if ((Psyche == Aggressive) && (OrderList[OrderPos] == Obey_train))
|
||||
if ((Psyche == Aggressive) && (OrderCurrentGet() == Obey_train))
|
||||
{
|
||||
ReactionTime = HardReactionTime; // w zaleznosci od charakteru maszynisty
|
||||
if (mvOccupied->CategoryFlag & 2)
|
||||
@@ -2634,6 +2689,11 @@ bool TController::IncBrake()
|
||||
// enforce use of train brake for DMUs
|
||||
standalone = false;
|
||||
}
|
||||
else if( ( ( OrderCurrentGet() & ( Loose_shunt ) ) != 0 )
|
||||
&& ( mvOccupied->Vel - VelDesired < fVelPlus + fVelMinus ) ) {
|
||||
// try to reduce train brake use in loose shunting mode
|
||||
standalone = true;
|
||||
}
|
||||
else {
|
||||
/*
|
||||
standalone =
|
||||
@@ -3486,7 +3546,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
{
|
||||
if (NewLocation)
|
||||
vCommandLocation = *NewLocation;
|
||||
if ((NewValue1 != 0.0) && (OrderList[OrderPos] != Obey_train))
|
||||
if ((NewValue1 != 0.0) && (OrderCurrentGet() != Obey_train))
|
||||
{ // o ile jazda
|
||||
if( iEngineActive == 0 ) {
|
||||
// trzeba odpalić silnik najpierw, światła ustawi
|
||||
@@ -3565,7 +3625,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
|
||||
if (NewCommand == "Change_direction")
|
||||
{
|
||||
TOrders o = OrderList[OrderPos]; // co robił przed zmianą kierunku
|
||||
TOrders o = OrderCurrentGet(); // co robił przed zmianą kierunku
|
||||
if (!iEngineActive)
|
||||
OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw
|
||||
if (NewValue1 == 0.0)
|
||||
@@ -3592,18 +3652,29 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NewCommand == "Obey_train")
|
||||
{
|
||||
if (!iEngineActive)
|
||||
OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw
|
||||
OrderNext(Obey_train);
|
||||
if (NewCommand == "Obey_train") {
|
||||
if( false == iEngineActive ) {
|
||||
OrderNext( Prepare_engine ); // trzeba odpalić silnik najpierw
|
||||
}
|
||||
OrderNext( Obey_train );
|
||||
// if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ???
|
||||
OrderCheck(); // jeśli jazda pociągowa teraz, to wykonać niezbędne operacje
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NewCommand == "Shunt")
|
||||
if (NewCommand == "Bank") {
|
||||
if( false == iEngineActive ) {
|
||||
OrderNext( Prepare_engine ); // trzeba odpalić silnik najpierw
|
||||
}
|
||||
OrderNext( Bank );
|
||||
// if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ???
|
||||
OrderCheck(); // jeśli jazda pociągowa teraz, to wykonać niezbędne operacje
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if( ( NewCommand == "Shunt" ) || ( NewCommand == "Loose_shunt" ) )
|
||||
{ // NewValue1 - ilość wagonów (-1=wszystkie); NewValue2: 0=odczep, 1..63=dołącz, -1=bez zmian
|
||||
//-3,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać w
|
||||
// trybie pociągowym
|
||||
@@ -3613,8 +3684,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
//-1, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać dalej
|
||||
//-1, 0 - tryb manewrowy bez zmian (odczepianie z pozostawieniem wagonów nie ma sensu)
|
||||
// 0, 0 - odczepienie lokomotywy
|
||||
// 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x)
|
||||
// wagonów
|
||||
// 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x) wagonów
|
||||
// 1, 0 - odczepienie lokomotywy z jednym wagonem
|
||||
iDrivigFlags &= ~moveStopHere; // podjeżanie do semaforów zezwolone
|
||||
if (!iEngineActive)
|
||||
@@ -3628,9 +3698,15 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
iDirectionOrder = -iDirection; // zmiana na ciągnięcie
|
||||
OrderPush(Change_direction); // najpierw zmień kierunek, bo odczepiamy z tyłu
|
||||
OrderPush(Disconnect); // a odczep już po zmianie kierunku
|
||||
if( ( NewValue2 > 0.0 )
|
||||
&& ( NewCommand == "Loose_shunt" ) ) {
|
||||
// after decoupling continue pushing in the original direction
|
||||
// NOTE: for backward compatibility this option isn't supported for basic shunting mode
|
||||
iDirectionOrder = iDirection; // back to pushing
|
||||
OrderPush( Change_direction );
|
||||
}
|
||||
}
|
||||
else if (NewValue2 < 0.0) // jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku
|
||||
// po podczepieniu
|
||||
else if (NewValue2 < 0.0) // jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku po podczepieniu
|
||||
{ // np. Shunt -1 -3
|
||||
iDirectionOrder = -iDirection; // jak się podczepi, to jazda w przeciwną stronę
|
||||
OrderNext(Change_direction);
|
||||
@@ -3662,9 +3738,9 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N
|
||||
iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora, jeśli droga nie jest wolna
|
||||
// (nie dotyczy Connect)
|
||||
if (NewValue1 < -2.5) // jeśli
|
||||
OrderNext(Obey_train); // to potem jazda pociągowa
|
||||
OrderNext(( NewCommand == "Shunt" ? Obey_train : Bank )); // to potem jazda pociągowa
|
||||
else
|
||||
OrderNext(Shunt); // to potem manewruj dalej
|
||||
OrderNext(( NewCommand == "Shunt" ? Shunt : Loose_shunt )); // to potem manewruj dalej
|
||||
CheckVehicles(); // sprawdzić światła
|
||||
// if ((iVehicleCount>=0)&&(NewValue1<0)) WriteLog("Skasowano ilosć wagonów w Shunt!");
|
||||
if (NewValue1 != iVehicleCount)
|
||||
@@ -3815,12 +3891,18 @@ TController::UpdateSituation(double dt) {
|
||||
LastReactionTime += dt;
|
||||
LastUpdatedTime += dt;
|
||||
if( ( mvOccupied->Vel < 0.05 )
|
||||
&& ( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) != 0 ) ) {
|
||||
&& ( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) != 0 ) ) {
|
||||
IdleTime += dt;
|
||||
}
|
||||
else {
|
||||
IdleTime = 0.0;
|
||||
}
|
||||
// HACK: activate route scanning if an idling vehicle is activated by a human user
|
||||
if( ( OrderCurrentGet() == Wait_for_orders )
|
||||
&& ( false == AIControllFlag )
|
||||
&& ( true == mvControlling->Battery ) ) {
|
||||
OrderNext( Prepare_engine );
|
||||
}
|
||||
|
||||
// log vehicle data
|
||||
if( ( WriteLogFlag )
|
||||
@@ -4037,7 +4119,7 @@ TController::UpdateSituation(double dt) {
|
||||
mvControlling->PantFront( true );
|
||||
}
|
||||
}
|
||||
if( mvOccupied->Vel > 10 ) {
|
||||
if( mvOccupied->Vel > 5 ) {
|
||||
// opuszczenie przedniego po rozpędzeniu się o ile jest więcej niż jeden
|
||||
if( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) {
|
||||
if( iDirection >= 0 ) // jak jedzie w kierunku sprzęgu 0
|
||||
@@ -4145,20 +4227,22 @@ TController::UpdateSituation(double dt) {
|
||||
// następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane zalecane ciśnienie
|
||||
|
||||
// przybliżona droga hamowania
|
||||
fBrakeDist = fDriverBraking * mvOccupied->Vel * ( 40.0 + mvOccupied->Vel );
|
||||
// NOTE: we're ensuring some minimal braking distance to reduce ai flipping states between starting and braking
|
||||
auto const velceil { std::max( 2.0, std::ceil( mvOccupied->Vel ) ) };
|
||||
fBrakeDist = fDriverBraking * velceil * ( 40.0 + velceil );
|
||||
if( fMass > 1000000.0 ) {
|
||||
// korekta dla ciężkich, bo przeżynają - da to coś?
|
||||
fBrakeDist *= 2.0;
|
||||
}
|
||||
if( ( -fAccThreshold > 0.05 )
|
||||
&& ( mvOccupied->CategoryFlag == 1 ) ) {
|
||||
fBrakeDist = mvOccupied->Vel * mvOccupied->Vel / 25.92 / -fAccThreshold;
|
||||
fBrakeDist = velceil * velceil / 25.92 / -fAccThreshold;
|
||||
}
|
||||
if( mvOccupied->BrakeDelayFlag == bdelay_G ) {
|
||||
// dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji
|
||||
fBrakeDist += 2 * mvOccupied->Vel;
|
||||
fBrakeDist += 2 * velceil;
|
||||
}
|
||||
if( ( mvOccupied->Vel > 0.05 )
|
||||
if( ( mvOccupied->Vel > 15.0 )
|
||||
&& ( mvControlling->EngineType == TEngineType::ElectricInductionMotor )
|
||||
&& ( ( mvControlling->TrainType & dt_EZT ) != 0 ) ) {
|
||||
// HACK: make the induction motor powered EMUs start braking slightly earlier
|
||||
@@ -4213,7 +4297,12 @@ TController::UpdateSituation(double dt) {
|
||||
// towards coupler 1
|
||||
routescandirection = end::rear;
|
||||
}
|
||||
|
||||
/*
|
||||
if( pVehicle->MoverParameters->ActiveCab < 0 ) {
|
||||
// flip the scan direction in the rear cab
|
||||
routescandirection ^= routescandirection;
|
||||
}
|
||||
*/
|
||||
Obstacle = neighbour_data();
|
||||
auto const lookup { frontvehicle->find_vehicle( routescandirection, routescanrange ) };
|
||||
|
||||
@@ -4223,14 +4312,11 @@ TController::UpdateSituation(double dt) {
|
||||
Obstacle.vehicle_end = std::get<int>( lookup );
|
||||
Obstacle.distance = std::get<double>( lookup );
|
||||
|
||||
if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 25 : 100 ) ) {
|
||||
if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 50 : 100 ) ) {
|
||||
// at short distances (re)calculate range between couplers directly
|
||||
Obstacle.distance = TMoverParameters::CouplerDist( frontvehicle->MoverParameters, Obstacle.vehicle->MoverParameters );
|
||||
}
|
||||
}
|
||||
else {
|
||||
Obstacle.distance = 10000; // legacy value. TBD, TODO: use standard -1 instead?
|
||||
}
|
||||
}
|
||||
// tu bedzie logika sterowania
|
||||
if (AIControllFlag) {
|
||||
@@ -4280,7 +4366,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
}
|
||||
|
||||
switch (OrderList[OrderPos])
|
||||
switch (OrderCurrentGet())
|
||||
{ // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach
|
||||
case Connect: {
|
||||
// podłączanie do składu
|
||||
@@ -4351,6 +4437,13 @@ TController::UpdateSituation(double dt) {
|
||||
fVelMinus = std::min( 0.1 * fShuntVelocity, 3.0 );
|
||||
break;
|
||||
}
|
||||
case Loose_shunt: {
|
||||
fMinProximityDist = -1.0;
|
||||
fMaxProximityDist = 0.0; //[m] dojechać maksymalnie
|
||||
fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||||
fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu
|
||||
break;
|
||||
}
|
||||
case Obey_train: {
|
||||
// na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody
|
||||
if( mvOccupied->CategoryFlag & 1 ) {
|
||||
@@ -4400,6 +4493,10 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Bank: {
|
||||
// TODO: implement
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
fMinProximityDist = 5.0;
|
||||
fMaxProximityDist = 10.0; //[m]
|
||||
@@ -4408,7 +4505,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
} // switch OrderList[OrderPos]
|
||||
|
||||
switch (OrderList[OrderPos])
|
||||
switch (OrderCurrentGet())
|
||||
{ // co robi maszynista
|
||||
case Prepare_engine: // odpala silnik
|
||||
// if (AIControllFlag)
|
||||
@@ -4442,13 +4539,16 @@ TController::UpdateSituation(double dt) {
|
||||
break;
|
||||
case Wait_for_orders: // jeśli czeka, też ma skanować, żeby odpalić się od semafora
|
||||
case Shunt:
|
||||
case Loose_shunt:
|
||||
case Obey_train:
|
||||
case Bank:
|
||||
case Connect:
|
||||
case Disconnect:
|
||||
case Change_direction: // tryby wymagające jazdy
|
||||
case Change_direction | Shunt: // zmiana kierunku podczas manewrów
|
||||
case Change_direction | Loose_shunt:
|
||||
case Change_direction | Connect: // zmiana kierunku podczas podłączania
|
||||
if (OrderList[OrderPos] != Obey_train) // spokojne manewry
|
||||
if ((OrderCurrentGet() & ( Obey_train | Bank )) == 0) // spokojne manewry
|
||||
{
|
||||
VelSignal = min_speed( VelSignal, 40.0 ); // jeśli manewry, to ograniczamy prędkość
|
||||
|
||||
@@ -4470,14 +4570,14 @@ TController::UpdateSituation(double dt) {
|
||||
else
|
||||
SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu?
|
||||
|
||||
if (OrderList[OrderPos] & (Shunt | Obey_train | Connect)) {
|
||||
if (OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank | Connect )) {
|
||||
// odjechać sam może tylko jeśli jest w trybie jazdy
|
||||
// automatyczne ruszanie po odstaniu albo spod SBL
|
||||
if( ( VelSignal == 0.0 )
|
||||
&& ( WaitingTime > 0.0 )
|
||||
&& ( mvOccupied->RunningTrack.Velmax != 0.0 ) ) {
|
||||
// jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość
|
||||
if( ( OrderList[ OrderPos ] & ( Obey_train | Shunt ) )
|
||||
if( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) )
|
||||
&& ( iDrivigFlags & moveStopHere ) ) {
|
||||
// zakaz ruszania z miejsca bez otrzymania wolnej drogi
|
||||
WaitingTime = -WaitingExpireTime;
|
||||
@@ -4520,14 +4620,14 @@ TController::UpdateSituation(double dt) {
|
||||
} // koniec samoistnego odjeżdżania
|
||||
|
||||
if( ( true == AIControllFlag)
|
||||
&& ( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) ) {
|
||||
&& ( true == TestFlag( OrderCurrentGet(), Change_direction ) ) ) {
|
||||
// sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą)
|
||||
if( mvOccupied->Vel < 0.1 ) {
|
||||
// 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( OrderList[ OrderPos ] & ( Shunt | Connect ) ) {
|
||||
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) {
|
||||
// jeśli dalej mamy manewry
|
||||
if( false == TestFlag( iDrivigFlags, moveStopHere ) ) {
|
||||
// o ile nie ma stać w miejscu,
|
||||
@@ -4541,7 +4641,7 @@ TController::UpdateSituation(double dt) {
|
||||
|
||||
if( ( true == AIControllFlag )
|
||||
&& ( iEngineActive == 0 )
|
||||
&& ( OrderList[ OrderPos ] & ( Change_direction | Connect | Disconnect | Shunt | Obey_train ) ) ) {
|
||||
&& ( OrderCurrentGet() & ( Change_direction | Connect | Disconnect | Shunt | Loose_shunt | Obey_train | Bank ) ) ) {
|
||||
// jeśli coś ma robić to niech odpala do skutku
|
||||
PrepareEngine();
|
||||
}
|
||||
@@ -4580,21 +4680,18 @@ TController::UpdateSituation(double dt) {
|
||||
if (iDrivigFlags & moveStopCloser)
|
||||
VelSignal = -1.0; // ma czekać na sygnał z sygnalizatora!
|
||||
case TCommandType::cm_SetVelocity: // od wersji 357 semafor nie budzi wyłączonej lokomotywy
|
||||
if (!(OrderList[OrderPos] &
|
||||
~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders
|
||||
if (fabs(VelSignal) >=
|
||||
1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą
|
||||
if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) // jedzie w dowolnym trybie albo Wait_for_orders
|
||||
if (fabs(VelSignal) >= 1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą
|
||||
PutCommand("SetVelocity", VelSignal, VelNext, nullptr); // komenda robi dodatkowe operacje
|
||||
break;
|
||||
case TCommandType::cm_ShuntVelocity: // od wersji 357 Tm nie budzi wyłączonej lokomotywy
|
||||
if (!(OrderList[OrderPos] &
|
||||
~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders
|
||||
if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) // jedzie w dowolnym trybie albo Wait_for_orders
|
||||
PutCommand("ShuntVelocity", VelSignal, VelNext, nullptr);
|
||||
else if (iCoupler) // jeśli jedzie w celu połączenia
|
||||
SetVelocity(VelSignal, VelNext);
|
||||
break;
|
||||
case TCommandType::cm_Command: // komenda z komórki
|
||||
if( !( OrderList[ OrderPos ] & ~( Obey_train | Shunt ) ) ) {
|
||||
if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) {
|
||||
// jedzie w dowolnym trybie albo Wait_for_orders
|
||||
if( mvOccupied->Vel < 0.1 ) {
|
||||
// dopiero jak stanie
|
||||
@@ -4611,138 +4708,151 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
// disconnect mode potentially overrides scan results
|
||||
// TBD: when in this mode skip scanning altogether?
|
||||
if( ( OrderCurrentGet() & Disconnect ) != 0 ) {
|
||||
if( ( true == AIControllFlag )
|
||||
&& ( ( OrderCurrentGet() & Disconnect ) != 0 ) ) {
|
||||
|
||||
if (AIControllFlag) {
|
||||
if (iVehicleCount >= 0) {
|
||||
// jeśli była podana ilość wagonów
|
||||
if (iDrivigFlags & movePress) {
|
||||
// jeśli dociskanie w celu odczepienia
|
||||
// 3. faza odczepiania.
|
||||
SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2
|
||||
if ((mvControlling->MainCtrlPos > 0) ||
|
||||
(mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)) // jeśli jazda
|
||||
{
|
||||
WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute));
|
||||
TDynamicObject *p =
|
||||
pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI
|
||||
int d; // numer sprzęgu, który sprawdzamy albo odczepiamy
|
||||
int n = iVehicleCount; // ile wagonów ma zostać
|
||||
do
|
||||
{ // szukanie pojazdu do odczepienia
|
||||
d = p->DirectionGet() > 0 ?
|
||||
0 :
|
||||
1; // numer sprzęgu od strony czoła składu
|
||||
// if (p->MoverParameters->Couplers[d].CouplerType==Articulated)
|
||||
// //jeśli sprzęg typu wózek (za mało)
|
||||
if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany
|
||||
// if (p->GetTrack()->) //a nie stoi na torze warsztatowym
|
||||
// (ustalić po czym poznać taki tor)
|
||||
++n; // to liczymy człony jako jeden
|
||||
p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać
|
||||
p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował
|
||||
if (n)
|
||||
{ // jeśli jeszcze nie koniec
|
||||
p = p->Prev(); // kolejny w stronę czoła składu (licząc od
|
||||
// tyłu), bo dociskamy
|
||||
if (!p)
|
||||
iVehicleCount = -2,
|
||||
n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone
|
||||
}
|
||||
} while (n--);
|
||||
if( ( p == nullptr )
|
||||
|| ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) {
|
||||
// no target, or already just virtual coupling
|
||||
WriteLog( mvOccupied->Name + " didn't find anything to disconnect." );
|
||||
iVehicleCount = -2; // odczepiono, co było do odczepienia
|
||||
} else if ( p->Dettach(d) == coupling::faux ) {
|
||||
// tylko jeśli odepnie
|
||||
WriteLog( mvOccupied->Name + " odczepiony." );
|
||||
iVehicleCount = -2;
|
||||
} // a jak nie, to dociskać dalej
|
||||
}
|
||||
if (iVehicleCount >= 0) // zmieni się po odczepieniu
|
||||
if (!mvOccupied->DecLocalBrakeLevel(1))
|
||||
{ // dociśnij sklad
|
||||
WriteLog( mvOccupied->Name + " dociskanie..." );
|
||||
// mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę
|
||||
// Ready=true; //zamiast sprawdzenia odhamowania całego składu
|
||||
IncSpeed(); // dla (Ready)==false nie ruszy
|
||||
if (iVehicleCount >= 0) {
|
||||
// jeśli była podana ilość wagonów
|
||||
if (iDrivigFlags & movePress) {
|
||||
// jeśli dociskanie w celu odczepienia
|
||||
// 3. faza odczepiania.
|
||||
SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2
|
||||
if( ( mvControlling->MainCtrlPos > 0 )
|
||||
|| ( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) ) {
|
||||
// jeśli jazda
|
||||
WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute));
|
||||
TDynamicObject *p = pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI
|
||||
int d; // numer sprzęgu, który sprawdzamy albo odczepiamy
|
||||
int n = iVehicleCount; // ile wagonów ma zostać
|
||||
do
|
||||
{ // szukanie pojazdu do odczepienia
|
||||
d = p->DirectionGet() > 0 ?
|
||||
end::front :
|
||||
end::rear; // numer sprzęgu od strony czoła składu
|
||||
// if (p->MoverParameters->Couplers[d].CouplerType==Articulated)
|
||||
// //jeśli sprzęg typu wózek (za mało)
|
||||
if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany
|
||||
// if (p->GetTrack()->) //a nie stoi na torze warsztatowym
|
||||
// (ustalić po czym poznać taki tor)
|
||||
++n; // to liczymy człony jako jeden
|
||||
p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać
|
||||
p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował
|
||||
if (n)
|
||||
{ // jeśli jeszcze nie koniec
|
||||
p = p->Prev(); // kolejny w stronę czoła składu (licząc od tyłu), bo dociskamy
|
||||
if (!p)
|
||||
iVehicleCount = -2,
|
||||
n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone
|
||||
}
|
||||
} while (n--);
|
||||
if( ( p == nullptr )
|
||||
|| ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) {
|
||||
// no target, or already just virtual coupling
|
||||
WriteLog( mvOccupied->Name + " didn't find anything to disconnect." );
|
||||
iVehicleCount = -2; // odczepiono, co było do odczepienia
|
||||
} else if ( p->Dettach(d) == coupling::faux ) {
|
||||
// tylko jeśli odepnie
|
||||
WriteLog( mvOccupied->Name + " odczepiony." );
|
||||
iVehicleCount = -2;
|
||||
} // a jak nie, to dociskać dalej
|
||||
}
|
||||
if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress))
|
||||
{ // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij
|
||||
// za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach
|
||||
// powino zostać wyłączone)
|
||||
// WriteLog("Zahamowanie składu");
|
||||
mvOccupied->BrakeLevelSet(
|
||||
mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
|
||||
1 :
|
||||
3 );
|
||||
double p = mvOccupied->BrakePressureActual.PipePressureVal;
|
||||
if( p < 3.9 ) {
|
||||
// tu może być 0 albo -1 nawet
|
||||
// TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu
|
||||
p = 3.9;
|
||||
if (iVehicleCount >= 0) // zmieni się po odczepieniu
|
||||
if (!mvOccupied->DecLocalBrakeLevel(1))
|
||||
{ // dociśnij sklad
|
||||
WriteLog( mvOccupied->Name + " dociskanie..." );
|
||||
// mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę
|
||||
// Ready=true; //zamiast sprawdzenia odhamowania całego składu
|
||||
IncSpeed(); // dla (Ready)==false nie ruszy
|
||||
}
|
||||
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
|
||||
mvOccupied->BrakePress > 2 :
|
||||
mvOccupied->PipePress < p + 0.1)
|
||||
{ // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na
|
||||
// pozycji 3, zwyle 0.37)
|
||||
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)
|
||||
mvOccupied->BrakeLevelSet(0); // wyłączenie EP, gdy wystarczy (może
|
||||
// nie być potrzebne, bo na początku jest)
|
||||
WriteLog("Luzowanie lokomotywy i zmiana kierunku");
|
||||
mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45?
|
||||
mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca
|
||||
iDrivigFlags |= movePress; // następnie będzie dociskanie
|
||||
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie)
|
||||
CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi
|
||||
/*
|
||||
// NOTE: disabled to prevent closing the door before passengers can disembark
|
||||
fStopTime = 0.0; // nie ma na co czekać z odczepianiem
|
||||
*/
|
||||
}
|
||||
if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress))
|
||||
{ // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij
|
||||
// za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach
|
||||
// powino zostać wyłączone)
|
||||
// WriteLog("Zahamowanie składu");
|
||||
mvOccupied->BrakeLevelSet(
|
||||
mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
|
||||
1 :
|
||||
3 );
|
||||
double p = mvOccupied->BrakePressureActual.PipePressureVal;
|
||||
if( p < 3.9 ) {
|
||||
// tu może być 0 albo -1 nawet
|
||||
// TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu
|
||||
p = 3.9;
|
||||
}
|
||||
if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ?
|
||||
mvOccupied->BrakePress > 2 :
|
||||
mvOccupied->PipePress < p + 0.1)
|
||||
{ // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na pozycji 3, zwyle 0.37)
|
||||
if( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) {
|
||||
// wyłączenie EP, gdy wystarczy (może nie być potrzebne, bo na początku jest)
|
||||
mvOccupied->BrakeLevelSet( 0 );
|
||||
}
|
||||
WriteLog("Luzowanie lokomotywy i zmiana kierunku");
|
||||
mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45?
|
||||
mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca
|
||||
iDrivigFlags |= movePress; // następnie będzie dociskanie
|
||||
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie)
|
||||
CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi
|
||||
}
|
||||
else {
|
||||
if( mvOccupied->Vel > 0.01 ) {
|
||||
// 1st phase(?)
|
||||
// bring it to stop if it's not already stopped
|
||||
SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie
|
||||
}
|
||||
}
|
||||
} // odczepiania
|
||||
else // to poniżej jeśli ilość wagonów ujemna
|
||||
if (iDrivigFlags & movePress)
|
||||
{ // 4. faza odczepiania: zwolnij i zmień kierunek
|
||||
SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie
|
||||
if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da
|
||||
{ // ponowna zmiana kierunku
|
||||
WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" );
|
||||
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy
|
||||
iDrivigFlags &= ~movePress; // koniec dociskania
|
||||
JumpToNextOrder(); // zmieni światła
|
||||
TableClear(); // skanowanie od nowa
|
||||
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem
|
||||
SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy
|
||||
}
|
||||
else {
|
||||
if( mvOccupied->Vel > 0.01 ) {
|
||||
// 1st phase(?)
|
||||
// bring it to stop if it's not already stopped
|
||||
SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie
|
||||
}
|
||||
}
|
||||
} // odczepiania
|
||||
else // to poniżej jeśli ilość wagonów ujemna
|
||||
if (iDrivigFlags & movePress)
|
||||
{ // 4. faza odczepiania: zwolnij i zmień kierunek
|
||||
SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie
|
||||
if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da
|
||||
{ // ponowna zmiana kierunku
|
||||
WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" );
|
||||
DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy
|
||||
iDrivigFlags &= ~movePress; // koniec dociskania
|
||||
JumpToNextOrder(); // zmieni światła
|
||||
TableClear(); // skanowanie od nowa
|
||||
iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem
|
||||
SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) {
|
||||
// when loose shunting try to detect situations where engaged brakes in a consist to be pushed prevent movement
|
||||
if( ( true == AIControllFlag )
|
||||
&& ( ( OrderCurrentGet() & Loose_shunt ) != 0 )
|
||||
&& ( Obstacle.distance < 1.0 )
|
||||
&& ( AccDesired > 0.1 )
|
||||
&& ( mvOccupied->Vel < 1.0 ) ){
|
||||
|
||||
auto *vehicle { Obstacle.vehicle };
|
||||
auto const direction { ( vehicle->Prev() != nullptr ? end::front : end::rear ) };
|
||||
while( vehicle != nullptr ) {
|
||||
if( vehicle->MoverParameters->BrakePress > 0.2 ) {
|
||||
vehicle->MoverParameters->BrakeLevelSet( 0 ); // hamulec na zero, aby nie hamował
|
||||
vehicle->MoverParameters->BrakeReleaser( 1 ); // wyluzuj pojazd, aby dało się dopychać
|
||||
}
|
||||
// NOTE: we trust the consist to be arranged in a valid chain
|
||||
// TBD, TODO: traversal direction validation?
|
||||
vehicle = ( direction == end::front ? vehicle->Prev() : vehicle->Next() );
|
||||
}
|
||||
}
|
||||
|
||||
if( true == TestFlag( OrderCurrentGet(), Change_direction ) ) {
|
||||
// if ordered to change direction, try to stop
|
||||
SetVelocity( 0, 0, stopDir );
|
||||
}
|
||||
|
||||
if( VelNext == 0.0 ) {
|
||||
if( !( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) {
|
||||
if( !( OrderCurrentGet() & ~( Shunt | Loose_shunt | Connect ) ) ) {
|
||||
// jedzie w Shunt albo Connect, albo Wait_for_orders
|
||||
// w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie ma taboru do podłączenia
|
||||
// Ra 2F1H: z tym (fTrackBlock) to nie jest najlepszy pomysł, bo lepiej by
|
||||
// było porównać z odległością od sygnalizatora z przodu
|
||||
if( ( ( OrderList[ OrderPos ] & Connect ) == 0 )
|
||||
if( ( ( OrderCurrentGet() & Connect ) == 0 )
|
||||
|| ( Obstacle.distance > std::min( 2000.0, FirstSemaphorDist ) ) ) {
|
||||
|
||||
if( ( comm = BackwardScan() ) != TCommandType::cm_Unknown ) {
|
||||
@@ -4756,7 +4866,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
iDirectionOrder = -iDirection; // zmiana kierunku jazdy
|
||||
// zmiana kierunku bez psucia kolejnych komend
|
||||
OrderList[ OrderPos ] = TOrders( OrderList[ OrderPos ] | Change_direction );
|
||||
OrderList[ OrderPos ] = TOrders( OrderCurrentGet() | Change_direction );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4768,6 +4878,7 @@ TController::UpdateSituation(double dt) {
|
||||
if (VelDesired < 0.0)
|
||||
VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną
|
||||
|
||||
// Ra: jazda na widoczność
|
||||
// Ra: jazda na widoczność
|
||||
if( Obstacle.distance < 5000 ) {
|
||||
// mamy coś z przodu
|
||||
@@ -4805,16 +4916,16 @@ TController::UpdateSituation(double dt) {
|
||||
// jeśli odległość jest zbyt mała
|
||||
if( k < 10.0 ) // k - prędkość tego z przodu
|
||||
{ // jeśli tamten porusza się z niewielką prędkością albo stoi
|
||||
if( OrderCurrentGet() & Connect ) {
|
||||
if( ( OrderCurrentGet() & ( Connect | Loose_shunt ) ) != 0 ) {
|
||||
// jeśli spinanie, to jechać dalej
|
||||
AccPreferred = std::min( 0.35, AccPreferred ); // nie hamuj
|
||||
VelDesired =
|
||||
VelDesired = std::floor(
|
||||
min_speed(
|
||||
VelDesired,
|
||||
( Obstacle.distance > 150 ?
|
||||
20.0:
|
||||
4.0 ) );
|
||||
VelNext = 2.0; // i pakuj się na tamtego
|
||||
k + 20.0:
|
||||
std::min( 8.0, k + 4.0 ) ) ) );
|
||||
VelNext = std::floor( std::min( 8.0, k + 2.0 ) ); // i pakuj się na tamtego
|
||||
}
|
||||
else {
|
||||
// a normalnie to hamować
|
||||
@@ -4917,7 +5028,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
}
|
||||
|
||||
if( ( OrderCurrentGet() & ( Shunt | Obey_train ) ) != 0 ) {
|
||||
if( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) != 0 ) {
|
||||
// w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu
|
||||
if( ( ( iDrivigFlags & moveStopHere ) != 0 )
|
||||
&& ( vel < 0.01 )
|
||||
@@ -5387,7 +5498,7 @@ TController::UpdateSituation(double dt) {
|
||||
// wyluzuj lokomotywę - może być więcej!
|
||||
mvOccupied->BrakeReleaser( 1 );
|
||||
}
|
||||
else if( OrderList[ OrderPos ] != Disconnect ) {
|
||||
else if( OrderCurrentGet() != Disconnect ) {
|
||||
// przy odłączaniu nie zwalniamy tu hamulca
|
||||
if( ( fAccGravity * fAccGravity < 0.001 ?
|
||||
true :
|
||||
@@ -5460,7 +5571,7 @@ TController::UpdateSituation(double dt) {
|
||||
// hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired)
|
||||
IncBrake();
|
||||
}
|
||||
else if( OrderList[ OrderPos ] != Disconnect ) {
|
||||
else if( OrderCurrentGet() != Disconnect ) {
|
||||
// przy odłączaniu nie zwalniamy tu hamulca
|
||||
if( AbsAccS < AccDesired - 0.05 ) {
|
||||
// jeśli opóźnienie większe od wymaganego (z histerezą) luzowanie, gdy za dużo
|
||||
@@ -5505,7 +5616,7 @@ TController::UpdateSituation(double dt) {
|
||||
if ((AccDesired < fAccGravity - 0.05) && (AbsAccS < AccDesired - fBrake_a1[0]*0.51)) {
|
||||
// jak hamuje, to nie tykaj kranu za często
|
||||
// yB: luzuje hamulec dopiero przy różnicy opóźnień rzędu 0.2
|
||||
if( OrderList[ OrderPos ] != Disconnect ) {
|
||||
if( OrderCurrentGet() != Disconnect ) {
|
||||
// przy odłączaniu nie zwalniamy tu hamulca
|
||||
DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu
|
||||
}
|
||||
@@ -5548,7 +5659,7 @@ TController::UpdateSituation(double dt) {
|
||||
}
|
||||
if (AIControllFlag)
|
||||
{ // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy
|
||||
if( ( ( OrderList[ OrderPos ] & ( Disconnect | Connect ) ) == 0 )
|
||||
if( ( ( OrderCurrentGet() & ( Disconnect | Connect ) ) == 0 )
|
||||
&& ( std::abs( fAccGravity ) < 0.01 ) ) {
|
||||
// przy (p)odłączaniu nie zwalniamy tu hamulca
|
||||
// only do this on flats, on slopes keep applied the train brake
|
||||
@@ -5629,9 +5740,7 @@ void TController::JumpToNextOrder()
|
||||
if (OrderList[OrderPos] & Change_direction) // jeśli zmiana kierunku
|
||||
if (OrderList[OrderPos] != Change_direction) // ale nałożona na coś
|
||||
{
|
||||
OrderList[OrderPos] =
|
||||
TOrders(OrderList[OrderPos] &
|
||||
~Change_direction); // usunięcie zmiany kierunku z innej komendy
|
||||
OrderList[OrderPos] = TOrders(OrderList[OrderPos] & ~Change_direction); // usunięcie zmiany kierunku z innej komendy
|
||||
OrderCheck();
|
||||
return;
|
||||
}
|
||||
@@ -5662,14 +5771,14 @@ void TController::JumpToFirstOrder()
|
||||
void TController::OrderCheck()
|
||||
{ // reakcja na zmianę rozkazu
|
||||
|
||||
if( OrderList[ OrderPos ] != Obey_train ) {
|
||||
if( OrderCurrentGet() != Obey_train ) {
|
||||
// reset light hints
|
||||
m_lighthints[ end::front ] = m_lighthints[ end::rear ] = -1;
|
||||
}
|
||||
if( OrderList[ OrderPos ] & ( Shunt | Connect | Obey_train ) ) {
|
||||
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect | Obey_train | Bank ) ) {
|
||||
CheckVehicles(); // sprawdzić światła
|
||||
}
|
||||
if( OrderList[ OrderPos ] & ( Shunt | Connect ) ) {
|
||||
if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) {
|
||||
// HACK: ensure consist doors will be closed on departure
|
||||
iDrivigFlags |= moveDoorOpened;
|
||||
}
|
||||
@@ -5694,7 +5803,7 @@ void TController::OrderNext(TOrders NewOrder)
|
||||
OrderTop = OrderPos; // ale może jest czymś zajęty na razie
|
||||
if (NewOrder >= Shunt) // jeśli ma jechać
|
||||
{ // ale może być zajęty chwilowymi operacjami
|
||||
while (OrderList[OrderTop] ? OrderList[OrderTop] < Shunt : false) // jeśli coś robi
|
||||
while ((OrderList[OrderTop] != Wait_for_orders) && (OrderList[OrderTop] < Shunt)) // jeśli coś robi
|
||||
++OrderTop; // pomijamy wszystkie tymczasowe prace
|
||||
}
|
||||
else
|
||||
@@ -5739,16 +5848,6 @@ void TController::OrdersDump()
|
||||
}
|
||||
};
|
||||
|
||||
inline TOrders TController::OrderCurrentGet()
|
||||
{
|
||||
return OrderList[OrderPos];
|
||||
}
|
||||
|
||||
inline TOrders TController::OrderNextGet()
|
||||
{
|
||||
return OrderList[OrderPos + 1];
|
||||
}
|
||||
|
||||
void TController::OrdersInit(double fVel)
|
||||
{ // wypełnianie tabelki rozkazów na podstawie rozkładu
|
||||
// ustawienie kolejności komend, niezależnie kto prowadzi
|
||||
@@ -5989,7 +6088,7 @@ TCommandType TController::BackwardScan()
|
||||
// dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda na kozioł
|
||||
// ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie przydatny
|
||||
// zwraca true, jeśli należy odwrócić kierunek jazdy pojazdu
|
||||
if( ( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) {
|
||||
if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Connect ) ) ) {
|
||||
// skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na rozkazy
|
||||
return TCommandType::cm_Unknown;
|
||||
}
|
||||
@@ -6054,14 +6153,14 @@ TCommandType TController::BackwardScan()
|
||||
bool move = false; // czy AI w trybie manewerowym ma dociągnąć pod S1
|
||||
if( e->input_command() == TCommandType::cm_SetVelocity ) {
|
||||
if( ( vmechmax == 0.0 ) ?
|
||||
( OrderCurrentGet() & ( Shunt | Connect ) ) :
|
||||
( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) :
|
||||
( OrderCurrentGet() & Connect ) ) { // przy podczepianiu ignorować wyjazd?
|
||||
move = true; // AI w trybie manewerowym ma dociągnąć pod S1
|
||||
}
|
||||
else {
|
||||
if( ( scandist > fMinProximityDist )
|
||||
&& ( ( mvOccupied->Vel > 0.0 )
|
||||
&& ( OrderCurrentGet() != Shunt ) ) ) {
|
||||
&& ( ( 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ł
|
||||
#if LOGBACKSCAN
|
||||
@@ -6093,14 +6192,13 @@ TCommandType TController::BackwardScan()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Connect) :
|
||||
if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Loose_shunt | Connect) :
|
||||
true) // w Wait_for_orders też widzi tarcze
|
||||
{ // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe
|
||||
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) :
|
||||
false)
|
||||
if ((scandist > fMinProximityDist) &&
|
||||
(mvOccupied->Vel > 0.0) || (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ą
|
||||
@@ -6211,11 +6309,13 @@ void TController::TakeControl(bool yes)
|
||||
if (OrderCurrentGet()) // jeśli coś robi
|
||||
PrepareEngine(); // niech sprawdzi stan silnika
|
||||
else // jeśli nic nie robi
|
||||
if (pVehicle->iLights[mvOccupied->CabNo < 0 ? 1 : 0] &
|
||||
21) // któreś ze świateł zapalone?
|
||||
if (pVehicle->iLights[ ( mvOccupied->CabNo < 0 ?
|
||||
end::rear :
|
||||
end::front ) ]
|
||||
& (light::headlight_left | light::headlight_right | light::headlight_upper)) // któreś ze świateł zapalone?
|
||||
{ // od wersji 357 oczekujemy podania komend dla AI przez scenerię
|
||||
OrderNext(Prepare_engine);
|
||||
if (pVehicle->iLights[mvOccupied->CabNo < 0 ? 1 : 0] & 4) // górne światło zapalone
|
||||
if (pVehicle->iLights[mvOccupied->CabNo < 0 ? end::rear : end::front] & light::headlight_upper) // górne światło zapalone
|
||||
OrderNext(Obey_train); // jazda pociągowa
|
||||
else
|
||||
OrderNext(Shunt); // jazda manewrowa
|
||||
@@ -6224,27 +6324,8 @@ void TController::TakeControl(bool yes)
|
||||
else
|
||||
iDrivigFlags |= moveStopHere; // a jak stoi, to niech czeka
|
||||
}
|
||||
/* od wersji 357 oczekujemy podania komend dla AI przez scenerię
|
||||
if (OrderCurrentGet())
|
||||
{if (OrderCurrentGet()<Shunt)
|
||||
{OrderNext(Prepare_engine);
|
||||
if (pVehicle->iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło
|
||||
OrderNext(Obey_train); //jazda pociągowa
|
||||
else
|
||||
OrderNext(Shunt); //jazda manewrowa
|
||||
}
|
||||
}
|
||||
else //jeśli jest w stanie Wait_for_orders
|
||||
JumpToFirstOrder(); //uruchomienie?
|
||||
// czy dac ponizsze? to problematyczne
|
||||
//SetVelocity(pVehicle->GetVelocity(),-1); //utrzymanie dotychczasowej?
|
||||
if (pVehicle->GetVelocity()>0.0)
|
||||
SetVelocity(-1,-1); //AI ustali sobie odpowiednią prędkość
|
||||
*/
|
||||
// Activation(); //przeniesie użytkownika w ostatnio wybranym kierunku
|
||||
CheckVehicles(); // ustawienie świateł
|
||||
TableClear(); // ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z
|
||||
// sygnałami
|
||||
TableClear(); // ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z sygnałami
|
||||
}
|
||||
else
|
||||
{ // a teraz użytkownik
|
||||
|
||||
38
Driver.h
38
Driver.h
@@ -19,15 +19,18 @@ enum TOrders
|
||||
{ // rozkazy dla AI
|
||||
Wait_for_orders = 0, // czekanie na dostarczenie następnych rozkazów
|
||||
// operacje tymczasowe
|
||||
Prepare_engine = 1, // włączenie silnika
|
||||
Release_engine = 2, // wyłączenie silnika
|
||||
Change_direction = 4, // zmiana kierunku (bez skanowania sygnalizacji)
|
||||
Connect = 8, // podłączanie wagonów (z częściowym skanowaniem sygnalizacji)
|
||||
Disconnect = 0x10, // odłączanie wagonów (bez skanowania sygnalizacji)
|
||||
Prepare_engine = 1 << 0, // włączenie silnika
|
||||
Release_engine = 1 << 1, // wyłączenie silnika
|
||||
Change_direction = 1 << 2, // zmiana kierunku (bez skanowania sygnalizacji)
|
||||
Connect = 1 << 3, // podłączanie wagonów (z częściowym skanowaniem sygnalizacji)
|
||||
Disconnect = 1 << 4, // odłączanie wagonów (bez skanowania sygnalizacji)
|
||||
// jazda
|
||||
Shunt = 0x20, // tryb manewrowy
|
||||
Obey_train = 0x40, // tryb pociągowy
|
||||
Jump_to_first_order = 0x60 // zapęlenie do pierwszej pozycji (po co?)
|
||||
Shunt = 1 << 5, // tryb manewrowy
|
||||
Loose_shunt = 1 << 6, // coupling-free shunting mode
|
||||
Obey_train = 1 << 7, // tryb pociągowy
|
||||
Bank = 1 << 8, // assist mode
|
||||
// others
|
||||
Jump_to_first_order = 1 << 9 // zapęlenie do pierwszej pozycji (po co?)
|
||||
};
|
||||
|
||||
enum TMovementStatus
|
||||
@@ -193,6 +196,7 @@ public:
|
||||
TMoverParameters const *Controlling() const {
|
||||
return mvControlling; }
|
||||
void DirectionInitial();
|
||||
void DirectionChange();
|
||||
inline
|
||||
int Direction() const {
|
||||
return iDirection; }
|
||||
@@ -308,21 +312,25 @@ private:
|
||||
public:
|
||||
void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm);
|
||||
bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm );
|
||||
// defines assignment data
|
||||
inline auto assignment() -> std::string & { return m_assignment; }
|
||||
inline auto assignment() const -> std::string const & { return m_assignment; }
|
||||
std::string OrderCurrent() const;
|
||||
private:
|
||||
void RecognizeCommand(); // odczytuje komende przekazana lokomotywie
|
||||
void JumpToNextOrder();
|
||||
void JumpToFirstOrder();
|
||||
void OrderPush(TOrders NewOrder);
|
||||
void OrderNext(TOrders NewOrder);
|
||||
inline TOrders OrderCurrentGet();
|
||||
inline TOrders OrderNextGet();
|
||||
inline TOrders OrderCurrentGet() const;
|
||||
inline TOrders OrderNextGet() const;
|
||||
void OrderCheck();
|
||||
void OrdersInit(double fVel);
|
||||
void OrdersClear();
|
||||
void OrdersDump();
|
||||
std::string OrderCurrent() const;
|
||||
std::string Order2Str(TOrders Order) const;
|
||||
// members
|
||||
std::string m_assignment;
|
||||
Math3D::vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego odnosi sie komenda // NOTE: not used
|
||||
TOrders OrderList[ maxorders ]; // lista rozkazów
|
||||
int OrderPos = 0,
|
||||
@@ -449,3 +457,11 @@ private:
|
||||
*/
|
||||
|
||||
};
|
||||
|
||||
inline TOrders TController::OrderCurrentGet() const {
|
||||
return OrderList[ OrderPos ];
|
||||
}
|
||||
|
||||
inline TOrders TController::OrderNextGet() const {
|
||||
return OrderList[ OrderPos + 1 ];
|
||||
}
|
||||
|
||||
@@ -5879,7 +5879,7 @@ TDynamicObject::update_neighbours() {
|
||||
neighbour.vehicle_end = std::get<int>( lookup );
|
||||
neighbour.distance = std::get<double>( lookup );
|
||||
|
||||
if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 25 : 50 ) ) {
|
||||
if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 50 : 100 ) ) {
|
||||
// at short distances (re)calculate range between couplers directly
|
||||
neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, neighbour.vehicle->MoverParameters );
|
||||
}
|
||||
|
||||
@@ -635,7 +635,7 @@ struct TCoupling {
|
||||
struct neighbour_data {
|
||||
TDynamicObject *vehicle { nullptr }; // detected obstacle
|
||||
int vehicle_end { -1 }; // facing end of the obstacle
|
||||
float distance { -1.f }; // distance to the obstacle
|
||||
float distance { 10000.f }; // distance to the obstacle // NOTE: legacy value. TBD, TODO: use standard -1 instead?
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1415,8 +1415,8 @@ void TMoverParameters::compute_movement_( double const Deltatime ) {
|
||||
UpdateBatteryVoltage(Deltatime);
|
||||
UpdateScndPipePressure(Deltatime); // druga rurka, youBy
|
||||
|
||||
if ((DCEMUED_CC & 1) && (Couplers[0].CouplingFlag & 4)) DynamicBrakeEMUStatus &= Couplers[0].Connected->DynamicBrakeEMUStatus;
|
||||
if ((DCEMUED_CC & 2) && (Couplers[1].CouplingFlag & 4)) DynamicBrakeEMUStatus &= Couplers[1].Connected->DynamicBrakeEMUStatus;
|
||||
if( ( ( DCEMUED_CC & 1 ) != 0 ) && ( ( Couplers[ end::front ].CouplingFlag & coupling::control ) != 0 ) ) { DynamicBrakeEMUStatus &= Couplers[ end::front ].Connected->DynamicBrakeEMUStatus; }
|
||||
if( ( ( DCEMUED_CC & 2 ) != 0 ) && ( ( Couplers[ end::rear ].CouplingFlag & coupling::control ) != 0 ) ) { DynamicBrakeEMUStatus &= Couplers[ end::rear ].Connected->DynamicBrakeEMUStatus; }
|
||||
|
||||
if( ( BrakeSlippingTimer > 0.8 ) && ( ASBType != 128 ) ) { // ASBSpeed=0.8
|
||||
// hamulec antypoślizgowy - wyłączanie
|
||||
|
||||
53
Train.cpp
53
Train.cpp
@@ -518,13 +518,16 @@ dictionary_source *TTrain::GetTrainState() {
|
||||
dict->insert( "unit_no", iUnitNo );
|
||||
|
||||
for( int i = 0; i < 20; i++ ) {
|
||||
dict->insert( ( "doors_" + std::to_string( i + 1 ) ), bDoors[ i ][ 0 ] );
|
||||
dict->insert( ( "doors_r_" + std::to_string( i + 1 ) ), bDoors[ i ][ 1 ] );
|
||||
dict->insert( ( "doors_l_" + std::to_string( i + 1 ) ), bDoors[ i ][ 2 ] );
|
||||
dict->insert( ( "doors_no_" + std::to_string( i + 1 ) ), iDoorNo[ i ] );
|
||||
dict->insert( ( "code_" + std::to_string( i + 1 ) ), ( std::to_string( iUnits[ i ] ) + cCode[ i ] ) );
|
||||
dict->insert( ( "car_name" + std::to_string( i + 1 ) ), asCarName[ i ] );
|
||||
dict->insert( ( "slip_" + std::to_string( i + 1 ) ), bSlip[ i ] );
|
||||
auto const caridx { std::to_string( i + 1 ) };
|
||||
dict->insert( ( "doors_" + caridx ), bDoors[ i ][ 0 ] );
|
||||
dict->insert( ( "doors_l_" + caridx ), bDoors[ i ][ 1 ] );
|
||||
dict->insert( ( "doors_r_" + caridx ), bDoors[ i ][ 2 ] );
|
||||
dict->insert( ( "doorstep_l_" + caridx ), bDoors[ i ][ 3 ] );
|
||||
dict->insert( ( "doorstep_r_" + caridx ), bDoors[ i ][ 4 ] );
|
||||
dict->insert( ( "doors_no_" + caridx ), iDoorNo[ i ] );
|
||||
dict->insert( ( "code_" + caridx ), ( std::to_string( iUnits[ i ] ) + cCode[ i ] ) );
|
||||
dict->insert( ( "car_name" + caridx ), asCarName[ i ] );
|
||||
dict->insert( ( "slip_" + caridx ), bSlip[ i ] );
|
||||
}
|
||||
// ai state data
|
||||
auto const *driver = DynamicObject->Mechanik;
|
||||
@@ -1588,7 +1591,7 @@ void TTrain::OnCommand_reverserincrease( TTrain *Train, command_data const &Comm
|
||||
if( ( Train->mvOccupied->ActiveDir )
|
||||
&& ( Train->DynamicObject->Mechanik ) ) {
|
||||
|
||||
Train->DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
Train->DynamicObject->Mechanik->DirectionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1603,7 +1606,7 @@ void TTrain::OnCommand_reverserdecrease( TTrain *Train, command_data const &Comm
|
||||
if( ( Train->mvOccupied->ActiveDir )
|
||||
&& ( Train->DynamicObject->Mechanik ) ) {
|
||||
|
||||
Train->DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
Train->DynamicObject->Mechanik->DirectionChange();;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1634,7 +1637,7 @@ void TTrain::OnCommand_reverserforward( TTrain *Train, command_data const &Comma
|
||||
if( ( Train->mvOccupied->ActiveDir == 1 )
|
||||
&& ( Train->DynamicObject->Mechanik ) ) {
|
||||
|
||||
Train->DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
Train->DynamicObject->Mechanik->DirectionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1669,7 +1672,7 @@ void TTrain::OnCommand_reverserbackward( TTrain *Train, command_data const &Comm
|
||||
if( ( Train->mvOccupied->ActiveDir == -1 )
|
||||
&& ( Train->DynamicObject->Mechanik ) ) {
|
||||
|
||||
Train->DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
Train->DynamicObject->Mechanik->DirectionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4153,12 +4156,12 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command
|
||||
if( item.GetDesiredValue() < 0.5 ) {
|
||||
// turn on
|
||||
// visual feedback
|
||||
item.UpdateValue( 1.0, Train->dsbSwitch );
|
||||
item.UpdateValue( 1.0 );
|
||||
}
|
||||
else {
|
||||
// turn off
|
||||
// visual feedback
|
||||
item.UpdateValue( 0.0, Train->dsbSwitch );
|
||||
item.UpdateValue( 0.0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5186,8 +5189,10 @@ bool TTrain::Update( double const Deltatime )
|
||||
fPress[i][0] = p->MoverParameters->BrakePress;
|
||||
fPress[i][1] = p->MoverParameters->PipePress;
|
||||
fPress[i][2] = p->MoverParameters->ScndPipePress;
|
||||
bDoors[i][1] = ( false == p->MoverParameters->Doors.instances[ side::right ].is_closed );
|
||||
bDoors[i][2] = ( false == p->MoverParameters->Doors.instances[ side::left ].is_closed );
|
||||
bDoors[i][1] = ( false == p->MoverParameters->Doors.instances[ side::left ].is_closed );
|
||||
bDoors[i][2] = ( false == p->MoverParameters->Doors.instances[ side::right ].is_closed );
|
||||
bDoors[i][3] = ( p->MoverParameters->Doors.instances[ side::left ].step_position > 0.0 );
|
||||
bDoors[i][4] = ( p->MoverParameters->Doors.instances[ side::right ].step_position > 0.0 );
|
||||
bDoors[i][0] = ( bDoors[i][1] || bDoors[i][2] );
|
||||
iDoorNo[i] = p->iAnimType[ANIM_DOORS];
|
||||
iUnits[i] = iUnitNo;
|
||||
@@ -5234,12 +5239,16 @@ bool TTrain::Update( double const Deltatime )
|
||||
}
|
||||
else
|
||||
{
|
||||
fPress[i][0] = 0;
|
||||
fPress[i][1] = 0;
|
||||
fPress[i][2] = 0;
|
||||
bDoors[i][0] = false;
|
||||
bDoors[i][1] = false;
|
||||
bDoors[i][2] = false;
|
||||
fPress[i][0]
|
||||
= fPress[i][1]
|
||||
= fPress[i][2]
|
||||
= 0;
|
||||
bDoors[i][0]
|
||||
= bDoors[i][1]
|
||||
= bDoors[i][2]
|
||||
= bDoors[i][3]
|
||||
= bDoors[i][4]
|
||||
= false;
|
||||
bSlip[i] = false;
|
||||
iUnits[i] = 0;
|
||||
cCode[i] = 0; //'0';
|
||||
@@ -6493,7 +6502,7 @@ bool TTrain::CabChange(int iDirection)
|
||||
DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + ".mmd" ) ) {
|
||||
// zmiana kabiny w ramach tego samego pojazdu
|
||||
DynamicObject->MoverParameters->CabActivisation(); // załączenie rozrządu (wirtualne kabiny)
|
||||
DynamicObject->Mechanik->CheckVehicles( Change_direction );
|
||||
DynamicObject->Mechanik->DirectionChange();
|
||||
return true; // udało się zmienić kabinę
|
||||
}
|
||||
}
|
||||
|
||||
4
Train.h
4
Train.h
@@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "PyInt.h"
|
||||
#include "command.h"
|
||||
|
||||
#undef snprintf // pyint.h->python
|
||||
|
||||
// typedef enum {st_Off, st_Starting, st_On, st_ShuttingDown} T4State;
|
||||
|
||||
const int maxcab = 2;
|
||||
@@ -643,7 +645,7 @@ private:
|
||||
float fHCurrent[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; // pr?dy: suma i amperomierze 1,2,3
|
||||
float fEngine[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; // obroty te? trzeba pobra?
|
||||
int iCarNo, iPowerNo, iUnitNo; // liczba pojazdow, czlonow napednych i jednostek spiętych ze sobą
|
||||
bool bDoors[20][3]; // drzwi dla wszystkich czlonow
|
||||
bool bDoors[20][5]; // drzwi dla wszystkich czlonow; left+right, left, right, step_left, step_right
|
||||
int iUnits[20]; // numer jednostki
|
||||
int iDoorNo[20]; // liczba drzwi
|
||||
char cCode[20]; // kod pojazdu
|
||||
|
||||
@@ -23,12 +23,17 @@ driver_ui::driver_ui() {
|
||||
clear_panels();
|
||||
// bind the panels with ui object. maybe not the best place for this but, eh
|
||||
push_back( &m_aidpanel );
|
||||
push_back( &m_scenariopanel );
|
||||
push_back( &m_timetablepanel );
|
||||
push_back( &m_debugpanel );
|
||||
push_back( &m_transcriptspanel );
|
||||
|
||||
m_aidpanel.title = locale::strings[ locale::string::driver_aid_header ];
|
||||
|
||||
m_scenariopanel.title = locale::strings[ locale::string::driver_scenario_header ];
|
||||
m_scenariopanel.size_min = { 435, 85 };
|
||||
m_scenariopanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 };
|
||||
|
||||
m_timetablepanel.title = locale::strings[ locale::string::driver_timetable_header ];
|
||||
m_timetablepanel.size_min = { 435, 110 };
|
||||
m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 };
|
||||
@@ -65,6 +70,7 @@ driver_ui::on_key_( int const Key, int const Scancode, int const Action, int con
|
||||
|
||||
case GLFW_KEY_F1:
|
||||
case GLFW_KEY_F2:
|
||||
case GLFW_KEY_F3:
|
||||
case GLFW_KEY_F10:
|
||||
case GLFW_KEY_F12: { // ui mode selectors
|
||||
|
||||
@@ -112,6 +118,12 @@ driver_ui::on_key_( int const Key, int const Scancode, int const Action, int con
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F3: {
|
||||
// debug panel
|
||||
m_scenariopanel.is_open = !m_scenariopanel.is_open;
|
||||
return true;
|
||||
}
|
||||
|
||||
case GLFW_KEY_F12: {
|
||||
// debug panel
|
||||
m_debugpanel.is_open = !m_debugpanel.is_open;
|
||||
|
||||
@@ -41,6 +41,7 @@ private:
|
||||
on_mouse_button_( int const Button, int const Action, int const Mods ) override;
|
||||
// members
|
||||
drivingaid_panel m_aidpanel { "Driving Aid", true };
|
||||
scenario_panel m_scenariopanel { "Scenario", true };
|
||||
timetable_panel m_timetablepanel { "Timetable", false };
|
||||
debug_panel m_debugpanel { "Debug Data", false };
|
||||
transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts
|
||||
|
||||
@@ -27,8 +27,6 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities.h"
|
||||
#include "Logs.h"
|
||||
|
||||
#undef snprintf // defined by train.h->pyint.h->python
|
||||
|
||||
void
|
||||
drivingaid_panel::update() {
|
||||
|
||||
@@ -152,6 +150,79 @@ drivingaid_panel::update() {
|
||||
size = { sizex, 85 };
|
||||
}
|
||||
|
||||
void
|
||||
scenario_panel::update() {
|
||||
|
||||
if( false == is_open ) { return; }
|
||||
|
||||
text_lines.clear();
|
||||
|
||||
auto const *train { simulation::Train };
|
||||
auto const *controlled { ( train ? train->Dynamic() : nullptr ) };
|
||||
auto const &camera { Global.pCamera };
|
||||
m_nearest = (
|
||||
false == FreeFlyModeFlag ? controlled :
|
||||
camera.m_owner != nullptr ? camera.m_owner :
|
||||
std::get<TDynamicObject *>( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) ); // w trybie latania lokalizujemy wg mapy
|
||||
if( m_nearest == nullptr ) { return; }
|
||||
auto const *owner { (
|
||||
( ( m_nearest->Mechanik != nullptr ) && ( m_nearest->Mechanik->Primary() ) ) ?
|
||||
m_nearest->Mechanik :
|
||||
m_nearest->ctOwner ) };
|
||||
if( owner == nullptr ) { return; }
|
||||
|
||||
std::string textline =
|
||||
locale::strings[ locale::string::driver_scenario_currenttask ] + "\n "
|
||||
+ owner->OrderCurrent();
|
||||
|
||||
text_lines.emplace_back( textline, Global.UITextColor );
|
||||
}
|
||||
|
||||
void
|
||||
scenario_panel::render() {
|
||||
|
||||
if( false == is_open ) { return; }
|
||||
if( true == text_lines.empty() ) { return; }
|
||||
if( m_nearest == nullptr ) { return; } // possibly superfluous given the above but, eh
|
||||
|
||||
auto flags =
|
||||
ImGuiWindowFlags_NoFocusOnAppearing
|
||||
| ImGuiWindowFlags_NoCollapse
|
||||
| ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 );
|
||||
|
||||
if( size.x > 0 ) {
|
||||
ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) );
|
||||
}
|
||||
if( size_min.x > 0 ) {
|
||||
ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) );
|
||||
}
|
||||
auto const panelname { (
|
||||
title.empty() ?
|
||||
name :
|
||||
title )
|
||||
+ "###" + name };
|
||||
if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) {
|
||||
// potential assignment section
|
||||
auto const *owner { (
|
||||
( ( m_nearest->Mechanik != nullptr ) && ( m_nearest->Mechanik->Primary() ) ) ?
|
||||
m_nearest->Mechanik :
|
||||
m_nearest->ctOwner ) };
|
||||
if( owner != nullptr ) {
|
||||
auto const assignmentheader { locale::strings[ locale::string::driver_scenario_assignment ] };
|
||||
if( ( false == owner->assignment().empty() )
|
||||
&& ( true == ImGui::CollapsingHeader( assignmentheader.c_str() ) ) ) {
|
||||
ImGui::TextWrapped( owner->assignment().c_str() );
|
||||
ImGui::Separator();
|
||||
}
|
||||
}
|
||||
// current task
|
||||
for( auto const &line : text_lines ) {
|
||||
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void
|
||||
timetable_panel::update() {
|
||||
|
||||
@@ -370,7 +441,12 @@ debug_panel::render() {
|
||||
if( size_min.x > 0 ) {
|
||||
ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) );
|
||||
}
|
||||
if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) {
|
||||
auto const panelname { (
|
||||
title.empty() ?
|
||||
name :
|
||||
title )
|
||||
+ "###" + name };
|
||||
if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) {
|
||||
// header section
|
||||
for( auto const &line : text_lines ) {
|
||||
ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() );
|
||||
@@ -676,7 +752,9 @@ debug_panel::update_section_ai( std::vector<text_line> &Output ) {
|
||||
auto const &mechanik{ *m_input.mechanik };
|
||||
|
||||
// biezaca komenda dla AI
|
||||
auto textline = "Current order: " + mechanik.OrderCurrent();
|
||||
auto textline =
|
||||
"Current order: [" + std::to_string( mechanik.OrderPos ) + "] "
|
||||
+ mechanik.OrderCurrent();
|
||||
|
||||
if( mechanik.fStopTime < 0.0 ) {
|
||||
textline += "\n stop time: " + to_string( std::abs( mechanik.fStopTime ), 1 );
|
||||
|
||||
@@ -28,6 +28,21 @@ private:
|
||||
std::array<char, 256> m_buffer;
|
||||
};
|
||||
|
||||
class scenario_panel : public ui_panel {
|
||||
|
||||
public:
|
||||
scenario_panel( std::string const &Name, bool const Isopen )
|
||||
: ui_panel( Name, Isopen ) {}
|
||||
|
||||
void update() override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
// members
|
||||
// std::array<char, 256> m_buffer;
|
||||
TDynamicObject const *m_nearest { nullptr };
|
||||
};
|
||||
|
||||
class timetable_panel : public ui_panel {
|
||||
|
||||
public:
|
||||
|
||||
1
scene.h
1
scene.h
@@ -51,6 +51,7 @@ struct scratch_data {
|
||||
std::vector<int> couplings;
|
||||
TDynamicObject * driver { nullptr };
|
||||
bool is_open { false };
|
||||
std::unordered_map<std::string, std::string> assignment;
|
||||
} trainset;
|
||||
|
||||
std::string name;
|
||||
|
||||
@@ -70,6 +70,7 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad )
|
||||
std::string,
|
||||
deserializefunction> > functionlist = {
|
||||
{ "area", &state_serializer::deserialize_area },
|
||||
{ "assignment", &state_serializer::deserialize_assignment },
|
||||
{ "atmo", &state_serializer::deserialize_atmo },
|
||||
{ "camera", &state_serializer::deserialize_camera },
|
||||
{ "config", &state_serializer::deserialize_config },
|
||||
@@ -142,6 +143,20 @@ state_serializer::deserialize_area( cParser &Input, scene::scratch_data &Scratch
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
std::string token { Input.getToken<std::string>() };
|
||||
while( ( false == token.empty() )
|
||||
&& ( token != "endassignment" ) ) {
|
||||
// assignment is expected to come as string pairs: language id and the actual assignment enclosed in quotes to form a single token
|
||||
auto assignment{ Input.getToken<std::string>() };
|
||||
win1250_to_ascii( assignment );
|
||||
Scratchpad.trainset.assignment.emplace( token, assignment );
|
||||
token = Input.getToken<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) {
|
||||
|
||||
@@ -628,6 +643,11 @@ state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data &
|
||||
&& ( vehicle->Mechanik->Primary() ) ) {
|
||||
// primary driver will receive the timetable for this trainset
|
||||
Scratchpad.trainset.driver = vehicle;
|
||||
// they'll also receive assignment data if there's any
|
||||
auto const lookup { Scratchpad.trainset.assignment.find( Global.asLang ) };
|
||||
if( lookup != Scratchpad.trainset.assignment.end() ) {
|
||||
vehicle->Mechanik->assignment() = lookup->second;
|
||||
}
|
||||
}
|
||||
if( vehicleindex > 0 ) {
|
||||
// from second vehicle on couple it with the previous one
|
||||
|
||||
@@ -30,6 +30,7 @@ private:
|
||||
// restores class data from provided stream
|
||||
void deserialize( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad );
|
||||
|
||||
@@ -38,6 +38,24 @@ init() {
|
||||
" Loading/unloading in progress (%d s left)",
|
||||
" Another vehicle ahead (distance: %.1f m)",
|
||||
|
||||
"Scenario",
|
||||
"Assignment",
|
||||
"Current task:",
|
||||
"Wait for orders",
|
||||
"Start the engine",
|
||||
"Shut down the engine",
|
||||
"Change direction",
|
||||
"Couple to consist ahead",
|
||||
"Uncouple %s",
|
||||
"the engine",
|
||||
"the engine plus the next vehicle",
|
||||
"the engine plus %d next vehicles",
|
||||
"the engine plus %d next vehicles",
|
||||
"Shunt according to signals",
|
||||
"Loose shunt according to signals",
|
||||
"Drive according to signals and timetable",
|
||||
"Bank consist ahead",
|
||||
|
||||
"Timetable",
|
||||
"Time: %d:%02d:%02d",
|
||||
"(no timetable)",
|
||||
@@ -183,6 +201,24 @@ init() {
|
||||
" Wsiadanie/wysiadanie pasazerow (do zakonczenia %d s)",
|
||||
" Inny pojazd na drodze (odleglosc: %.1f m)",
|
||||
|
||||
"Scenariusz",
|
||||
"Zlecenie",
|
||||
"Biezace zadanie:",
|
||||
"Oczekiwac dalszych polecen",
|
||||
"Przygotowac pojazd do jazdy",
|
||||
"Wylaczyc pojazd",
|
||||
"Zmienic kierunek jazdy",
|
||||
"Sprzac sie ze skladem z przodu",
|
||||
"Odpiac %s",
|
||||
"pojazd prowadzacy",
|
||||
"pojazd prowadzacy plus kolejny",
|
||||
"pojazd prowadzacy plus %d kolejne",
|
||||
"pojazd prowadzacy plus %d kolejnych",
|
||||
"Prowadzic manewry wedlug sygnalow",
|
||||
"Prowadzic manewry przetaczania odrzutem",
|
||||
"Prowadzic sklad wedlug sygnalow i rozkladu",
|
||||
"Popychac sklad z przodu",
|
||||
|
||||
"Rozklad jazdy",
|
||||
"Godzina: %d:%02d:%02d",
|
||||
"(brak rozkladu)",
|
||||
|
||||
@@ -27,6 +27,24 @@ enum string {
|
||||
driver_aid_loadinginprogress,
|
||||
driver_aid_vehicleahead,
|
||||
|
||||
driver_scenario_header,
|
||||
driver_scenario_assignment,
|
||||
driver_scenario_currenttask,
|
||||
driver_scenario_waitfororders,
|
||||
driver_scenario_prepareengine,
|
||||
driver_scenario_releaseengine,
|
||||
driver_scenario_changedirection,
|
||||
driver_scenario_connect,
|
||||
driver_scenario_disconnect,
|
||||
driver_scenario_allvehicles,
|
||||
driver_scenario_onevehicle,
|
||||
driver_scenario_fewvehicles,
|
||||
driver_scenario_somevehicles,
|
||||
driver_scenario_shunt,
|
||||
driver_scenario_looseshunt,
|
||||
driver_scenario_obeytrain,
|
||||
driver_scenario_bank,
|
||||
|
||||
driver_timetable_header,
|
||||
driver_timetable_time,
|
||||
driver_timetable_notimetable,
|
||||
|
||||
Reference in New Issue
Block a user