From e5980f946ce980a269f1037a3fe419fdca099230 Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 30 Aug 2017 19:54:43 +0200 Subject: [PATCH] minor refactoring and diagnostics enhancements, fixed some memory leaks, radiostop test command --- AirCoupler.cpp | 6 +- AnimModel.cpp | 12 +- AnimModel.h | 4 +- Button.cpp | 4 +- Driver.cpp | 2483 ++++++++++++++++++++++---------------------- Driver.h | 3 +- DynObj.cpp | 22 +- DynObj.h | 3 +- Event.cpp | 16 +- Event.h | 5 +- Gauge.cpp | 4 +- Ground.cpp | 151 ++- McZapkie/MOVER.h | 5 +- McZapkie/Mover.cpp | 16 +- Model3d.cpp | 84 +- Model3d.h | 7 +- PyInt.cpp | 2 +- Track.cpp | 186 ++-- Track.h | 1 - Train.cpp | 70 +- Train.h | 1 + command.cpp | 5 +- command.h | 1 + keyboardinput.cpp | 2 + parser.cpp | 93 +- parser.h | 11 +- version.h | 4 +- 27 files changed, 1584 insertions(+), 1617 deletions(-) diff --git a/AirCoupler.cpp b/AirCoupler.cpp index 62b72624..5c6c0b09 100644 --- a/AirCoupler.cpp +++ b/AirCoupler.cpp @@ -42,9 +42,9 @@ void TAirCoupler::Init(std::string const &asName, TModel3d *pModel) { // wyszukanie submodeli if (!pModel) return; // nie ma w czym szukać - pModelOn = pModel->GetFromName( (asName + "_on").c_str() ); // połączony na wprost - pModelOff = pModel->GetFromName( (asName + "_off").c_str() ); // odwieszony - pModelxOn = pModel->GetFromName( (asName + "_xon").c_str() ); // połączony na skos + pModelOn = pModel->GetFromName( asName + "_on" ); // połączony na wprost + pModelOff = pModel->GetFromName( asName + "_off" ); // odwieszony + pModelxOn = pModel->GetFromName( asName + "_xon" ); // połączony na skos } void TAirCoupler::Load(cParser *Parser, TModel3d *pModel) diff --git a/AnimModel.cpp b/AnimModel.cpp index c0ff498b..b956331a 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -523,11 +523,11 @@ bool TAnimModel::Load(cParser *parser, bool ter) return true; } -TAnimContainer * TAnimModel::AddContainer(char *pName) +TAnimContainer * TAnimModel::AddContainer(std::string const &Name) { // dodanie sterowania submodelem dla egzemplarza if (!pModel) return NULL; - TSubModel *tsb = pModel->GetFromName(pName); + TSubModel *tsb = pModel->GetFromName(Name); if (tsb) { TAnimContainer *tmp = new TAnimContainer(); @@ -539,16 +539,16 @@ TAnimContainer * TAnimModel::AddContainer(char *pName) return NULL; } -TAnimContainer * TAnimModel::GetContainer(char *pName) +TAnimContainer * TAnimModel::GetContainer(std::string const &Name) { // szukanie/dodanie sterowania submodelem dla egzemplarza - if (!pName) + if (true == Name.empty()) return pRoot; // pobranie pierwszego (dla obrotnicy) TAnimContainer *pCurrent; for (pCurrent = pRoot; pCurrent != NULL; pCurrent = pCurrent->pNext) // if (pCurrent->GetName()==pName) - if (std::string(pName) == pCurrent->NameGet()) + if (Name == pCurrent->NameGet()) return pCurrent; - return AddContainer(pName); + return AddContainer(Name); } // przeliczenie animacji - jednorazowo na klatkę diff --git a/AnimModel.h b/AnimModel.h index 1aa11735..e24ab335 100644 --- a/AnimModel.h +++ b/AnimModel.h @@ -163,8 +163,8 @@ private: bool Init(TModel3d *pNewModel); bool Init(std::string const &asName, std::string const &asReplacableTexture); bool Load(cParser *parser, bool ter = false); - TAnimContainer * AddContainer(char *pName); - TAnimContainer * GetContainer(char *pName); + TAnimContainer * AddContainer(std::string const &Name); + TAnimContainer * GetContainer(std::string const &Name = ""); int Flags(); void RaAnglesSet(double a, double b, double c) { diff --git a/Button.cpp b/Button.cpp index a673bbfd..8629da2b 100644 --- a/Button.cpp +++ b/Button.cpp @@ -28,8 +28,8 @@ void TButton::Init(std::string const &asName, TModel3d *pModel, bool bNewOn) { if( pModel == nullptr ) { return; } - pModelOn = pModel->GetFromName( (asName + "_on").c_str() ); - pModelOff = pModel->GetFromName( (asName + "_off").c_str() ); + pModelOn = pModel->GetFromName( asName + "_on" ); + pModelOff = pModel->GetFromName( asName + "_off" ); m_state = bNewOn; Update(); }; diff --git a/Driver.cpp b/Driver.cpp index 6c7f97a5..d6ace476 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -1446,7 +1446,7 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, if( WriteLogFlag ) { _mkdir( "physicslog\\" ); - LogFile.open( std::string( "physicslog\\" + VehicleName + ".dat" ).c_str(), + LogFile.open( std::string( "physicslog\\" + VehicleName + ".dat" ), std::ios::in | std::ios::out | std::ios::trunc ); #if LOGPRESS == 0 LogFile << std::string( " Time [s] Velocity [m/s] Acceleration [m/ss] Coupler.Dist[m] " @@ -3337,34 +3337,37 @@ void TController::PhysicsLog() } }; -bool TController::UpdateSituation(double dt) -{ // uruchamiać przynajmniej raz na sekundę - if ((iDrivigFlags & movePrimary) == 0) - return true; // pasywny nic nie robi +void +TController::UpdateSituation(double dt) { + // uruchamiać przynajmniej raz na sekundę + if( ( iDrivigFlags & movePrimary ) == 0 ) { return; } // pasywny nic nie robi - double AbsAccS = 0; - // double VelReduced; //o ile km/h może przekroczyć dozwoloną prędkość bez hamowania - bool UpdateOK = false; - if (AIControllFlag) - { // yb: zeby EP nie musial sie bawic z ciesnieniem w PG - // if (mvOccupied->BrakeSystem==ElectroPneumatic) - // mvOccupied->PipePress=0.5; //yB: w SPKS są poprawnie zrobione pozycje - if (mvControlling->SlippingWheels) - { - mvControlling->Sandbox(true); // piasku! - // Controlling->SlippingWheels=false; //a to tu nie ma sensu, flaga używana w dalszej - // części - } - else { - // deactivate sandbox if we aren't slipping - if( mvControlling->SandDose ) { - mvControlling->Sandbox( false ); - } - } + // update timers + ElapsedTime += dt; + WaitingTime += dt; + fBrakeTime -= dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca + fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne + fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi + LastReactionTime += dt; + LastUpdatedTime += dt; + + // log vehicle data + if( ( WriteLogFlag ) + && ( LastUpdatedTime > deltalog ) ) { + // zapis do pliku DAT + PhysicsLog(); + LastUpdatedTime -= deltalog; } + + if( ( fLastStopExpDist > 0.0 ) + && ( mvOccupied->DistCounter > fLastStopExpDist ) ) { + // zaktualizować wyświetlanie rozkładu + iStationStart = TrainParams->StationIndex; + fLastStopExpDist = -1.0; // usunąć licznik + } + // ABu-160305 testowanie gotowości do jazdy - // Ra: przeniesione z DynObj, skład użytkownika też jest testowany, żeby mu przekazać, że ma - // odhamować + // Ra: przeniesione z DynObj, skład użytkownika też jest testowany, żeby mu przekazać, że ma odhamować int index = double(BrakeAccTableSize) * (mvOccupied->Vel / mvOccupied->Vmax); index = std::min(BrakeAccTableSize, std::max(1, index)); fBrake_a0[0] = fBrake_a0[index]; @@ -3373,6 +3376,7 @@ bool TController::UpdateSituation(double dt) fReady = 0.0; // założenie, że odhamowany fAccGravity = 0.0; // przyspieszenie wynikające z pochylenia double dy; // składowa styczna grawitacji, w przedziale <0,1> + double AbsAccS = 0; TDynamicObject *p = pVehicles[0]; // pojazd na czole składu while (p) { // sprawdzenie odhamowania wszystkich połączonych pojazdów @@ -3397,22 +3401,22 @@ bool TController::UpdateSituation(double dt) } if (fReady < p->MoverParameters->BrakePress) fReady = p->MoverParameters->BrakePress; // szukanie najbardziej zahamowanego - if ((dy = p->VectorFront().y) != 0.0) // istotne tylko dla pojazdów na pochyleniu - fAccGravity -= p->DirectionGet() * p->MoverParameters->TotalMassxg * - dy; // ciężar razy składowa styczna grawitacji + if( ( dy = p->VectorFront().y ) != 0.0 ) { + // istotne tylko dla pojazdów na pochyleniu + // ciężar razy składowa styczna grawitacji + fAccGravity -= p->DirectionGet() * p->MoverParameters->TotalMassxg * dy; + } p = p->Next(); // pojazd podłączony z tyłu (patrząc od czoła) } - if (iDirection) - fAccGravity /= - iDirection * - fMass; // siłę generują pojazdy na pochyleniu ale działa ona całość składu, więc a=F/m + if( iDirection ) { + // siłę generują pojazdy na pochyleniu ale działa ona całość składu, więc a=F/m + fAccGravity /= iDirection * fMass; + } if (!Ready) // v367: jeśli wg powyższych warunków skład nie jest odhamowany if (fAccGravity < -0.05) // jeśli ma pod górę na tyle, by się stoczyć - // if (mvOccupied->BrakePress<0.08) //to wystarczy, że zadziałają liniowe (nie ma ich - // jeszcze!!!) + // if (mvOccupied->BrakePress<0.08) //to wystarczy, że zadziałają liniowe (nie ma ich jeszcze!!!) if (fReady < 0.8) // delikatniejszy warunek, obejmuje wszystkie wagony Ready = true; //żeby uznać za odhamowany - HelpMeFlag = false; // crude way to deal with automatic door opening on W4 preventing further ride // for human-controlled vehicles with no door control and dynamic brake auto-activating with door open @@ -3423,29 +3427,48 @@ bool TController::UpdateSituation(double dt) Doors( false ); } - // Winger 020304 - if (true == AIControllFlag) - { - if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) - { - if (mvOccupied->ScndPipePress > 4.3) // gdy główna sprężarka bezpiecznie nabije ciśnienie - mvControlling->bPantKurek3 = true; // to można przestawić kurek na zasilanie pantografów z głównej pneumatyki - fVoltage = - 0.5 * (fVoltage + - fabs(mvControlling->RunningTraction.TractionVoltage)); // uśrednione napięcie - // sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas - if (fVoltage < mvControlling->EnginePowerSource.CollectorParameters - .MinV) // gdy rozłączenie WS z powodu niskiego napięcia - if (fActionTime >= 0) // jeśli czas oczekiwania nie został ustawiony - fActionTime = - -2 - Random(10); // losowy czas oczekiwania przed ponownym załączeniem jazdy + // basic situational ai operations + // TBD, TODO: move these to main routine, if it's not neccessary for them to fire every time? + if( AIControllFlag ) { + + // wheel slip + if( mvControlling->SlippingWheels ) { + mvControlling->Sandbox( true ); // piasku! } - if (mvOccupied->Vel > 0.0) - { // jeżeli jedzie - if (iDrivigFlags & moveDoorOpened) // jeśli drzwi otwarte - if (mvOccupied->Vel > 1.0) // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 - // akceptuje niewielkie prędkości - Doors(false); + else { + // deactivate sandbox if we aren't slipping + if( mvControlling->SandDose ) { + mvControlling->Sandbox( false ); + } + } + + if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { + + if( mvOccupied->ScndPipePress > 4.3 ) { + // gdy główna sprężarka bezpiecznie nabije ciśnienie to można przestawić kurek na zasilanie pantografów z głównej pneumatyki + mvControlling->bPantKurek3 = true; + } + + // uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas + fVoltage = 0.5 * (fVoltage + std::abs(mvControlling->RunningTraction.TractionVoltage)); + if( fVoltage < mvControlling->EnginePowerSource.CollectorParameters.MinV ) { + // gdy rozłączenie WS z powodu niskiego napięcia + if( fActionTime >= 0 ) { + // jeśli czas oczekiwania nie został ustawiony, losowy czas oczekiwania przed ponownym załączeniem jazdy + fActionTime = -2.0 - Random( 10 ); + } + } + } + + if (mvOccupied->Vel > 0.0) { + // jeżeli jedzie + if( iDrivigFlags & moveDoorOpened ) { + // jeśli drzwi otwarte + if( mvOccupied->Vel > 1.0 ) { + // nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości + Doors( false ); + } + } /* // NOTE: this section moved all cars to the edge of their respective roads // it may have some use eventually for collision avoidance, @@ -3463,8 +3486,7 @@ bool TController::UpdateSituation(double dt) { if ((fOverhead2 >= 0.0) || iOverheadZero) { // jeśli jazda bezprądowa albo z opuszczonym pantografem - while (DecSpeed(true)) - ; // zerowanie napędu + while( DecSpeed( true ) ) { ; } // zerowanie napędu } if ((fOverhead2 > 0.0) || iOverheadDown) { // jazda z opuszczonymi pantografami @@ -3497,6 +3519,20 @@ bool TController::UpdateSituation(double dt) } } } + + // horn control + if( fWarningDuration > 0.0 ) { + // jeśli pozostało coś do wytrąbienia trąbienie trwa nadal + fWarningDuration -= dt; + if( fWarningDuration < 0.05 ) + mvOccupied->WarningSignal = 0; // a tu się kończy + } + if( mvOccupied->Vel >= 3.0 ) { + // 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 + } + if( ( true == TestFlag( iDrivigFlags, moveStartHornNow ) ) && ( true == Ready ) && ( iEngineActive != 0 ) @@ -3508,1304 +3544,1249 @@ bool TController::UpdateSituation(double dt) iDrivigFlags &= ~moveStartHornNow; // trąbienie zostało zorganizowane } } - ElapsedTime += dt; - WaitingTime += dt; - fBrakeTime -= dt; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca - fStopTime += dt; // zliczanie czasu postoju, nie ruszy dopóki ujemne - fActionTime += dt; // czas używany przy regulacji prędkości i zamykaniu drzwi - if (WriteLogFlag) - { - if (LastUpdatedTime > deltalog) - { // zapis do pliku DAT - PhysicsLog(); - if (fabs(mvOccupied->V) > 0.1) // Ra: [m/s] - deltalog = 0.05; // 0.2; - else - deltalog = 0.05; // 1.0; - LastUpdatedTime = 0.0; - } - else - LastUpdatedTime = LastUpdatedTime + dt; - } - // Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość - if ((LastReactionTime > std::min(ReactionTime, 2.0))) - { - // Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna STÓJ - // yB: otóż jest to jedna trzecia czasu napełniania na towarowym; może się przydać przy - // wdrażaniu hamowania, żeby nie ruszało kranem jak głupie - // Ra: ale nie może się budzić co pół minuty, bo przeżyna semafory - // Ra: trzeba by tak: - // 1. Ustalić istotną odległość zainteresowania (np. 3×droga hamowania z V.max). - // dla hamowania -0.2 [m/ss] droga wynosi 0.389*Vel*Vel [km/h], czyli 600m dla 40km/h, 3.8km - // dla 100km/h i 9.8km dla 160km/h - // dla hamowania -0.4 [m/ss] droga wynosi 0.096*Vel*Vel [km/h], czyli 150m dla 40km/h, 1.0km - // dla 100km/h i 2.5km dla 160km/h - // ogólnie droga hamowania przy stałym opóźnieniu to Vel*Vel/(3.6*3.6*a) [m] - // fBrakeDist powinno być wyznaczane dla danego składu za pomocą sieci neuronowych, w - // zależności od prędkości i siły (ciśnienia) hamowania - // 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 ); - 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; - } - if( mvOccupied->BrakeDelayFlag == bdelay_G ) { - // dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji - fBrakeDist += 2 * mvOccupied->Vel; - } - // double scanmax=(mvOccupied->Vel>0.0)?3*fDriverDist+fBrakeDist:10.0*fDriverDist; - double scanmax = ( - mvOccupied->Vel > 5.0 ? - 400 + fBrakeDist : - 30.0 * fDriverDist ); // 1500m dla stojących pociągów; - // Ra 2015-01: przy dłuższej drodze skanowania AI jeździ spokojniej - // 2. Sprawdzić, czy tabelka pokrywa założony odcinek (nie musi, jeśli jest STOP). - // 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeśli tak, to sprawdzić, - // czy stan się nie zmienił. - // 4. Ewentualnie uzupełnić tabelkę informacjami o sygnałach i ograniczeniach, jeśli się - // "zużyła". - TableCheck(scanmax); // wypełnianie tabelki i aktualizacja odległości - // 5. Sprawdzić stany sygnalizacji zapisanej w tabelce, wyznaczyć prędkości. - // 6. Z tabelki wyznaczyć krytyczną odległość i prędkość (najmniejsze przyspieszenie). - // 7. Jeśli jest inny pojazd z przodu, ewentualnie skorygować odległość i prędkość. - // 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji - // - rzadziej). - // check for potential colliders - { - auto const scandistance = 300.0 + fBrakeDist; - auto rearvehicle = ( - pVehicles[ 0 ] == pVehicles[ 1 ] ? - pVehicles[ 0 ] : - pVehicles[ 1 ] ); - if( mvOccupied->V >= 0.0 ) { - // towards coupler 0 - if( ( mvOccupied->V * iDirection < 0.0 ) - || ( ( rearvehicle->NextConnected != nullptr ) - && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 1 : 0 ) ].CouplingFlag == ctrain_virtual ) ) ) { - // scan behind if we're moving backward, or if we had something connected there and are moving away - rearvehicle->ABuScanObjects( ( - pVehicle->DirectionGet() == rearvehicle->DirectionGet() ? - -1 : - 1 ), - fMaxProximityDist ); - } - pVehicles[ 0 ]->ABuScanObjects( ( - pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? - 1 : - -1 ), - scandistance ); - } - else { - // towards coupler 1 - if( ( mvOccupied->V * iDirection < 0.0 ) - || ( ( rearvehicle->PrevConnected != nullptr ) - && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 0 : 1 ) ].CouplingFlag == ctrain_virtual ) ) ) { - // scan behind if we're moving backward, or if we had something connected there and are moving away - rearvehicle->ABuScanObjects( ( - pVehicle->DirectionGet() == rearvehicle->DirectionGet() ? - 1 : - -1 ), - fMaxProximityDist ); - } - pVehicles[ 0 ]->ABuScanObjects( ( - pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? + // main ai update routine + auto const reactiontime = std::min( ReactionTime, 2.0 ); + if( LastReactionTime < reactiontime ) { return; } + + LastReactionTime -= reactiontime; + // Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna STÓJ + // yB: otóż jest to jedna trzecia czasu napełniania na towarowym; może się przydać przy + // wdrażaniu hamowania, żeby nie ruszało kranem jak głupie + // Ra: ale nie może się budzić co pół minuty, bo przeżyna semafory + // Ra: trzeba by tak: + // 1. Ustalić istotną odległość zainteresowania (np. 3×droga hamowania z V.max). + // dla hamowania -0.2 [m/ss] droga wynosi 0.389*Vel*Vel [km/h], czyli 600m dla 40km/h, 3.8km + // dla 100km/h i 9.8km dla 160km/h + // dla hamowania -0.4 [m/ss] droga wynosi 0.096*Vel*Vel [km/h], czyli 150m dla 40km/h, 1.0km + // dla 100km/h i 2.5km dla 160km/h + // ogólnie droga hamowania przy stałym opóźnieniu to Vel*Vel/(3.6*3.6*a) [m] + // fBrakeDist powinno być wyznaczane dla danego składu za pomocą sieci neuronowych, w + // zależności od prędkości i siły (ciśnienia) hamowania + // 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 ); + 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; + } + if( mvOccupied->BrakeDelayFlag == bdelay_G ) { + // dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji + fBrakeDist += 2 * mvOccupied->Vel; + } + // route scan + double routescanrange = ( + mvOccupied->Vel > 5.0 ? + 400 + fBrakeDist : + 30.0 * fDriverDist ); // 1500m dla stojących pociągów; + // Ra 2015-01: przy dłuższej drodze skanowania AI jeździ spokojniej + // 2. Sprawdzić, czy tabelka pokrywa założony odcinek (nie musi, jeśli jest STOP). + // 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeśli tak, to sprawdzić, + // czy stan się nie zmienił. + // 4. Ewentualnie uzupełnić tabelkę informacjami o sygnałach i ograniczeniach, jeśli się + // "zużyła". + TableCheck(routescanrange); // wypełnianie tabelki i aktualizacja odległości + // 5. Sprawdzić stany sygnalizacji zapisanej w tabelce, wyznaczyć prędkości. + // 6. Z tabelki wyznaczyć krytyczną odległość i prędkość (najmniejsze przyspieszenie). + // 7. Jeśli jest inny pojazd z przodu, ewentualnie skorygować odległość i prędkość. + // 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji + // - rzadziej). + + // check for potential colliders + { + auto const collisionscanrange = 300.0 + fBrakeDist; + auto rearvehicle = ( + pVehicles[ 0 ] == pVehicles[ 1 ] ? + pVehicles[ 0 ] : + pVehicles[ 1 ] ); + // for moving vehicle determine heading from velocity; for standing fall back on the set direction + if( ( mvOccupied->V != 0.0 ? + mvOccupied->V > 0.0 : + iDirection > 0 ) ) { + // towards coupler 0 + if( ( mvOccupied->V * iDirection < 0.0 ) + || ( ( rearvehicle->NextConnected != nullptr ) + && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 1 : 0 ) ].CouplingFlag == ctrain_virtual ) ) ) { + // scan behind if we're moving backward, or if we had something connected there and are moving away + rearvehicle->ABuScanObjects( ( + pVehicle->DirectionGet() == rearvehicle->DirectionGet() ? -1 : 1 ), - scandistance ); + fMaxProximityDist ); } + pVehicles[ 0 ]->ABuScanObjects( ( + pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? + 1 : + -1 ), + collisionscanrange ); } - - - - if (AIControllFlag) - { // tu bedzie logika sterowania - if (mvOccupied->CommandIn.Command != "") - if( !mvOccupied->RunInternalCommand() ) { - // rozpoznaj komende bo lokomotywa jej nie rozpoznaje - RecognizeCommand(); // samo czyta komendę wstawioną do pojazdu? - } - if( mvOccupied->SecuritySystem.Status > 1 ) { - // jak zadziałało CA/SHP - if( !mvOccupied->SecuritySystemReset() ) { // to skasuj - if( ( mvOccupied->BrakeCtrlPos == 0 ) - && ( AccDesired > 0.0 ) - && ( ( TestFlag( mvOccupied->SecuritySystem.Status, s_SHPebrake ) ) - || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAebrake ) ) ) ) { - //!!! hm, może po prostu normalnie sterować hamulcem? - mvOccupied->BrakeLevelSet( 0 ); - } - } + else { + // towards coupler 1 + if( ( mvOccupied->V * iDirection < 0.0 ) + || ( ( rearvehicle->PrevConnected != nullptr ) + && ( rearvehicle->MoverParameters->Couplers[ ( rearvehicle->DirectionGet() > 0 ? 0 : 1 ) ].CouplingFlag == ctrain_virtual ) ) ) { + // scan behind if we're moving backward, or if we had something connected there and are moving away + rearvehicle->ABuScanObjects( ( + pVehicle->DirectionGet() == rearvehicle->DirectionGet() ? + 1 : + -1 ), + fMaxProximityDist ); } - // basic emergency stop handling, while at it - if( ( true == mvOccupied->EmergencyBrakeFlag ) // radio-stop - && ( mvOccupied->Vel == 0.0 ) // and actual stop - && ( true == mvOccupied->Radio ) ) { // and we didn't touch the radio yet - // turning off the radio should reset the flag, during security system check - if( m_radiocontroltime > 5.0 ) { - // arbitrary delay between stop and disabling the radio - mvOccupied->Radio = false; - m_radiocontroltime = 0.0; - } - else { - m_radiocontroltime += LastReactionTime; - } + pVehicles[ 0 ]->ABuScanObjects( ( + pVehicle->DirectionGet() == pVehicles[ 0 ]->DirectionGet() ? + -1 : + 1 ), + collisionscanrange ); + } + } + + // tu bedzie logika sterowania + if (AIControllFlag) { + + if (mvOccupied->CommandIn.Command != "") + if( !mvOccupied->RunInternalCommand() ) { + // rozpoznaj komende bo lokomotywa jej nie rozpoznaje + RecognizeCommand(); // samo czyta komendę wstawioną do pojazdu? } - if( ( false == mvOccupied->Radio ) - && ( false == mvOccupied->EmergencyBrakeFlag ) ) { - // otherwise if it's safe to do so, turn the radio back on - if( m_radiocontroltime > 10.0 ) { - // arbitrary 5 sec delay before switching radio back on - mvOccupied->Radio = true; - m_radiocontroltime = 0.0; - } - else { - m_radiocontroltime += LastReactionTime; + if( mvOccupied->SecuritySystem.Status > 1 ) { + // jak zadziałało CA/SHP + if( !mvOccupied->SecuritySystemReset() ) { // to skasuj + if( ( mvOccupied->BrakeCtrlPos == 0 ) + && ( AccDesired > 0.0 ) + && ( ( TestFlag( mvOccupied->SecuritySystem.Status, s_SHPebrake ) ) + || ( TestFlag( mvOccupied->SecuritySystem.Status, s_CAebrake ) ) ) ) { + //!!! hm, może po prostu normalnie sterować hamulcem? + mvOccupied->BrakeLevelSet( 0 ); } } } - - switch (OrderList[OrderPos]) - { // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach - case Connect: { - // podłączanie do składu - if (iDrivigFlags & moveConnect) { - // jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć - fMinProximityDist = -0.5; - fMaxProximityDist = 0.0; //[m] dojechać maksymalnie - fVelPlus = 0.5; // dopuszczalne przekroczenie prędkości na ograniczeniu bez - // hamowania - fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu - if (AIControllFlag) - { // to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić - // sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec - bool ok; // true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) - if (pVehicles[0]->DirectionGet() > 0) // jeśli sprzęg 0 - { // sprzęg 0 - próba podczepienia - if (pVehicles[0]->MoverParameters->Couplers[0].Connected) // jeśli jest coś - // wykryte (a - // chyba jest, - // nie?) - if (pVehicles[0]->MoverParameters->Attach( - 0, 2, pVehicles[0]->MoverParameters->Couplers[0].Connected, - iCoupler)) - { - // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); - } - // WriteLog("CoupleDist[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CoupleDist)+", - // Connected[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag)); - ok = (pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag == - iCoupler); // udało się? (mogło częściowo) - } - else // if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 - { // sprzęg 1 - próba podczepienia - if (pVehicles[0]->MoverParameters->Couplers[1].Connected) // jeśli jest coś - // wykryte (a - // chyba jest, - // nie?) - if (pVehicles[0]->MoverParameters->Attach( - 1, 2, pVehicles[0]->MoverParameters->Couplers[1].Connected, - iCoupler)) - { - // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); - // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); - } - // WriteLog("CoupleDist[1]="+AnsiString(Controlling->Couplers[1].CoupleDist)+", - // Connected[0]="+AnsiString(Controlling->Couplers[1].CouplingFlag)); - ok = (pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag == - iCoupler); // udało się? (mogło częściowo) - } - if (ok) - { // jeżeli został podłączony - iCoupler = 0; // dalsza jazda manewrowa już bez łączenia - iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania - SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie - CheckVehicles(); // sprawdzić światła nowego składu - JumpToNextOrder(); // wykonanie następnej komendy - } - else - SetVelocity(2.0, 0.0); // jazda w ustawionym kierunku z prędkością 2 (18s) - } // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna + // basic emergency stop handling, while at it + if( ( true == mvOccupied->RadioStopFlag ) // radio-stop + && ( mvOccupied->Vel == 0.0 ) // and actual stop + && ( true == mvOccupied->Radio ) ) { // and we didn't touch the radio yet + // turning off the radio should reset the flag, during security system check + if( m_radiocontroltime > 5.0 ) { + // arbitrary delay between stop and disabling the radio + mvOccupied->Radio = false; + m_radiocontroltime = 0.0; } else { - // jak daleko, to jazda jak dla Shunt na kolizję - fMinProximityDist = 2.0; - fMaxProximityDist = 5.0; //[m] w takim przedziale odległości powinien stanąć - fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus = 1.0; // margines prędkości powodujący załączenie napędu - if( pVehicles[ 0 ]->fTrackBlock <= 20.0 ) { - // przy zderzeniu fTrackBlock nie jest miarodajne - // początek podczepiania, z wyłączeniem sprawdzania fTrackBlock - iDrivigFlags |= moveConnect; - } + m_radiocontroltime += reactiontime; } - break; } - case Disconnect: { - // 20.07.03 - manewrowanie wagonami - fMinProximityDist = 1.0; - fMaxProximityDist = 10.0; //[m] - fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + if( ( false == mvOccupied->Radio ) + && ( false == mvOccupied->RadioStopFlag ) ) { + // otherwise if it's safe to do so, turn the radio back on + if( m_radiocontroltime > 10.0 ) { + // arbitrary 5 sec delay before switching radio back on + mvOccupied->Radio = true; + m_radiocontroltime = 0.0; + } + else { + m_radiocontroltime += reactiontime; + } + } + } + + switch (OrderList[OrderPos]) + { // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach + case Connect: { + // podłączanie do składu + if (iDrivigFlags & moveConnect) { + // jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć + fMinProximityDist = -0.5; + fMaxProximityDist = 0.0; //[m] dojechać maksymalnie + fVelPlus = 0.5; // dopuszczalne przekroczenie prędkości na ograniczeniu bez + // hamowania fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu - 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 == ElectroPneumatic)) // jeśli jazda + if (AIControllFlag) + { // to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić + // sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec + bool ok; // true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym) + if (pVehicles[0]->DirectionGet() > 0) // jeśli sprzęg 0 + { // sprzęg 0 - próba podczepienia + if (pVehicles[0]->MoverParameters->Couplers[0].Connected) // jeśli jest coś + // wykryte (a + // chyba jest, + // nie?) + if (pVehicles[0]->MoverParameters->Attach( + 0, 2, pVehicles[0]->MoverParameters->Couplers[0].Connected, + iCoupler)) { - 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 ? p->MoverParameters->Couplers[ d ].CouplingFlag == coupling::faux : true ) { - // 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 + // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); } - 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->Vel == 0.0) && !(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 == 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 == 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 == 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(10); // 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 - fStopTime = 0.0; // nie ma na co czekać z odczepianiem + // WriteLog("CoupleDist[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CoupleDist)+", + // Connected[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag)); + ok = (pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag == + iCoupler); // udało się? (mogło częściowo) + } + else // if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1 + { // sprzęg 1 - próba podczepienia + if( pVehicles[ 0 ]->MoverParameters->Couplers[ 1 ].Connected ) { + // jeśli jest coś wykryte (a chyba jest, nie?) + if( pVehicles[ 0 ]->MoverParameters->Attach( + 1, 2, pVehicles[ 0 ]->MoverParameters->Couplers[ 1 ].Connected, + iCoupler ) ) { + // pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX); + // pVehicles[0]->dsbCouplerAttach->Play(0,0,0); } } - } // odczepiania - else // to poniżej jeśli ilość wagonów ujemna - if (iDrivigFlags & movePress) - { // 4. faza odczepiania: zwolnij i zmień kierunek + // WriteLog("CoupleDist[1]="+AnsiString(Controlling->Couplers[1].CoupleDist)+", + // Connected[0]="+AnsiString(Controlling->Couplers[1].CouplingFlag)); + ok = (pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag == + iCoupler); // udało się? (mogło częściowo) + } + if (ok) + { // jeżeli został podłączony + iCoupler = 0; // dalsza jazda manewrowa już bez łączenia + iDrivigFlags &= ~moveConnect; // zdjęcie flagi doczepiania 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 + CheckVehicles(); // sprawdzić światła nowego składu + JumpToNextOrder(); // wykonanie następnej komendy + } + else + SetVelocity(2.0, 0.0); // jazda w ustawionym kierunku z prędkością 2 (18s) + } // if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna + } + else { + // jak daleko, to jazda jak dla Shunt na kolizję + fMinProximityDist = 2.0; + fMaxProximityDist = 5.0; //[m] w takim przedziale odległości powinien stanąć + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 1.0; // margines prędkości powodujący załączenie napędu + if( pVehicles[ 0 ]->fTrackBlock <= 20.0 ) { + // przy zderzeniu fTrackBlock nie jest miarodajne + // początek podczepiania, z wyłączeniem sprawdzania fTrackBlock + iDrivigFlags |= moveConnect; + } + } + break; + } + case Disconnect: { + // 20.07.03 - manewrowanie wagonami + fMinProximityDist = 1.0; + fMaxProximityDist = 10.0; //[m] + fVelPlus = 1.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu + 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 == 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 ? p->MoverParameters->Couplers[ d ].CouplingFlag == coupling::faux : true ) { + // 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 ((mvOccupied->Vel == 0.0) && !(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 == 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 == 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 == 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(10); // 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 + fStopTime = 0.0; // nie ma na co czekać z odczepianiem } } - } - break; - } - case Shunt: { - // na jaką odleglość i z jaką predkością ma podjechać - fMinProximityDist = 5.0; - fMaxProximityDist = 10.0; //[m] - if( pVehicles[ 0 ] != pVehicles[ 1 ] ) { - // for larger consists increase margins to account for slower braking etc - // NOTE: this will affect also multi-unit vehicles TBD: is this what we want? - fMinProximityDist *= 2.0; - fMaxProximityDist *= 2.0; - } - fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - // margines prędkości powodujący załączenie napędu - // były problemy z jazdą np. 3km/h podczas ładowania wagonów - fVelMinus = std::min( 0.1 * fShuntVelocity, 3.0 ); - break; - } - case Obey_train: { - // na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody - if( mvOccupied->CategoryFlag & 1 ) { - // jeśli pociąg - fMinProximityDist = 15.0; - fMaxProximityDist = - ( mvOccupied->Vel > 0.0 ) ? - 25.0 : - 50.0; //[m] jak stanie za daleko, to niech nie dociąga paru metrów - if( iDrivigFlags & moveLate ) { - // jeśli spóźniony, to gna - fVelMinus = 1.0; - // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelPlus = 5.0; - } - else { - // gdy nie musi się sprężać - // margines prędkości powodujący załączenie napędu; min 1.0 żeby nie ruszał przy 0.1 - fVelMinus = clamp( std::round( 0.05 * VelDesired ), 1.0, 5.0 ); - // normalnie dopuszczalne przekroczenie to 5% prędkości ale nie więcej niż 5km/h - // bottom margin raised to 2 km/h to give the AI more leeway at low speed limits - fVelPlus = clamp( std::ceil( 0.05 * VelDesired ), 2.0, 5.0 ); + } // 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 } } + } + break; + } + case Shunt: { + // na jaką odleglość i z jaką predkością ma podjechać + fMinProximityDist = 5.0; + fMaxProximityDist = 10.0; //[m] + if( pVehicles[ 0 ] != pVehicles[ 1 ] ) { + // for larger consists increase margins to account for slower braking etc + // NOTE: this will affect also multi-unit vehicles TBD: is this what we want? + fMinProximityDist *= 2.0; + fMaxProximityDist *= 2.0; + } + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + // margines prędkości powodujący załączenie napędu + // były problemy z jazdą np. 3km/h podczas ładowania wagonów + fVelMinus = std::min( 0.1 * fShuntVelocity, 3.0 ); + break; + } + case Obey_train: { + // na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody + if( mvOccupied->CategoryFlag & 1 ) { + // jeśli pociąg + fMinProximityDist = 15.0; + fMaxProximityDist = + ( mvOccupied->Vel > 0.0 ) ? + 25.0 : + 50.0; //[m] jak stanie za daleko, to niech nie dociąga paru metrów + if( iDrivigFlags & moveLate ) { + // jeśli spóźniony, to gna + fVelMinus = 1.0; + // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelPlus = 5.0; + } else { - // samochod (sokista też) - fMinProximityDist = std::max( 4.0, mvOccupied->Vel * 0.2 ); - fMaxProximityDist = std::max( 8.0, mvOccupied->Vel * 0.375 ); //[m] - // margines prędkości powodujący załączenie napędu - fVelMinus = 2.0; - // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelPlus = std::min( 10.0, mvOccupied->Vel * 0.1 ); + // gdy nie musi się sprężać + // margines prędkości powodujący załączenie napędu; min 1.0 żeby nie ruszał przy 0.1 + fVelMinus = clamp( std::round( 0.05 * VelDesired ), 1.0, 5.0 ); + // normalnie dopuszczalne przekroczenie to 5% prędkości ale nie więcej niż 5km/h + // bottom margin raised to 2 km/h to give the AI more leeway at low speed limits + fVelPlus = clamp( std::ceil( 0.05 * VelDesired ), 2.0, 5.0 ); } - break; } - default: { - fMinProximityDist = 0.01; - fMaxProximityDist = 2.0; //[m] - fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania - fVelMinus = 5.0; // margines prędkości powodujący załączenie napędu + else { + // samochod (sokista też) + fMinProximityDist = std::max( 4.0, mvOccupied->Vel * 0.2 ); + fMaxProximityDist = std::max( 8.0, mvOccupied->Vel * 0.375 ); //[m] + // margines prędkości powodujący załączenie napędu + fVelMinus = 2.0; + // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelPlus = std::min( 10.0, mvOccupied->Vel * 0.1 ); } - } // switch OrderList[OrderPos] + break; + } + default: { + fMinProximityDist = 0.01; + fMaxProximityDist = 2.0; //[m] + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 5.0; // margines prędkości powodujący załączenie napędu + } + } // switch OrderList[OrderPos] - switch (OrderList[OrderPos]) - { // co robi maszynista - case Prepare_engine: // odpala silnik - // if (AIControllFlag) - if (PrepareEngine()) // dla użytkownika tylko sprawdza, czy uruchomił - { // gotowy do drogi? - SetDriverPsyche(); - // OrderList[OrderPos]:=Shunt; //Ra: to nie może tak być, bo scenerie robią - // Jump_to_first_order i przechodzi w manewrowy - JumpToNextOrder(); // w następnym jest Shunt albo Obey_train, moze też być - // Change_direction, Connect albo Disconnect - // if OrderList[OrderPos]<>Wait_for_Orders) - // if BrakeSystem=Pneumatic) //napelnianie uderzeniowe na wstepie - // if BrakeSubsystem=Oerlikon) - // if (BrakeCtrlPos=0)) - // DecBrakeLevel; - } - break; - case Release_engine: - if( ReleaseEngine() ) // zdana maszyna? - JumpToNextOrder(); - break; - case Jump_to_first_order: - if (OrderPos > 1) - OrderPos = 1; // w zerowym zawsze jest czekanie - else - ++OrderPos; + switch (OrderList[OrderPos]) + { // co robi maszynista + case Prepare_engine: // odpala silnik + // if (AIControllFlag) + if (PrepareEngine()) // dla użytkownika tylko sprawdza, czy uruchomił + { // gotowy do drogi? + SetDriverPsyche(); + // OrderList[OrderPos]:=Shunt; //Ra: to nie może tak być, bo scenerie robią + // Jump_to_first_order i przechodzi w manewrowy + JumpToNextOrder(); // w następnym jest Shunt albo Obey_train, moze też być + // Change_direction, Connect albo Disconnect + // if OrderList[OrderPos]<>Wait_for_Orders) + // if BrakeSystem=Pneumatic) //napelnianie uderzeniowe na wstepie + // if BrakeSubsystem=Oerlikon) + // if (BrakeCtrlPos=0)) + // DecBrakeLevel; + } + break; + case Release_engine: + if( ReleaseEngine() ) // zdana maszyna? + JumpToNextOrder(); + break; + case Jump_to_first_order: + if (OrderPos > 1) + OrderPos = 1; // w zerowym zawsze jest czekanie + else + ++OrderPos; #if LOGORDERS - WriteLog("--> Jump_to_first_order"); - OrdersDump(); + WriteLog("--> Jump_to_first_order"); + OrdersDump(); #endif - break; - case Wait_for_orders: // jeśli czeka, też ma skanować, żeby odpalić się od semafora - case Shunt: - case Obey_train: - case Connect: - case Disconnect: - case Change_direction: // tryby wymagające jazdy - case Change_direction | Shunt: // zmiana kierunku podczas manewrów - case Change_direction | Connect: // zmiana kierunku podczas podłączania - if (OrderList[OrderPos] != Obey_train) // spokojne manewry - { - VelSignal = Global::Min0RSpeed(VelSignal, 40); // jeśli manewry, to ograniczamy prędkość - - // NOTE: this section should be moved to disconnect or plain removed, but it seems to be (mis)used by some scenarios - // to keep vehicle idling without moving :| - if( ( true == AIControllFlag ) - && ( iVehicleCount >= 0 ) - && ( false == TestFlag( iDrivigFlags, movePress ) ) - && ( iCoupler == 0 ) -// && ( mvOccupied->Vel > 0.0 ) - && ( pVehicle->PrevConnected == nullptr ) - && ( pVehicle->NextConnected == nullptr ) ) { - SetVelocity(0, 0, stopJoin); // 1. faza odczepiania: zatrzymanie - // WriteLog("Zatrzymanie w celu odczepienia"); - AccPreferred = std::min( 0.0, AccPreferred ); - } + break; + case Wait_for_orders: // jeśli czeka, też ma skanować, żeby odpalić się od semafora + case Shunt: + case Obey_train: + case Connect: + case Disconnect: + case Change_direction: // tryby wymagające jazdy + case Change_direction | Shunt: // zmiana kierunku podczas manewrów + case Change_direction | Connect: // zmiana kierunku podczas podłączania + if (OrderList[OrderPos] != Obey_train) // spokojne manewry + { + VelSignal = Global::Min0RSpeed(VelSignal, 40); // jeśli manewry, to ograniczamy prędkość + // NOTE: this section should be moved to disconnect or plain removed, but it seems to be (mis)used by some scenarios + // to keep vehicle idling without moving :| + if( ( true == AIControllFlag ) + && ( iVehicleCount >= 0 ) + && ( false == TestFlag( iDrivigFlags, movePress ) ) + && ( iCoupler == 0 ) +// && ( mvOccupied->Vel > 0.0 ) + && ( pVehicle->PrevConnected == nullptr ) + && ( pVehicle->NextConnected == nullptr ) ) { + SetVelocity(0, 0, stopJoin); // 1. faza odczepiania: zatrzymanie + // WriteLog("Zatrzymanie w celu odczepienia"); + AccPreferred = std::min( 0.0, AccPreferred ); } - else - SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu? - // no albo przypisujemy -WaitingExpireTime, albo porównujemy z WaitingExpireTime - // if - // ((VelSignal==0.0)&&(WaitingTime>WaitingExpireTime)&&(mvOccupied->RunningTrack.Velmax!=0.0)) - if (OrderList[OrderPos] & - (Shunt | Obey_train | 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 (WriteLogFlag) - { - append(AIlogFile); - writeln(AILogFile,ElapsedTime:5:2,": ",Name," V=0 waiting time expired! - (",WaitingTime:4:1,")"); - close(AILogFile); - } - */ - if ((OrderList[OrderPos] & (Obey_train | Shunt)) ? - (iDrivigFlags & moveStopHere) : - false) - WaitingTime = -WaitingExpireTime; // zakaz ruszania z miejsca bez otrzymania - // wolnej drogi - else if (mvOccupied->CategoryFlag & 1) - { // jeśli pociąg - if (AIControllFlag) + + } + else + SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu? + // no albo przypisujemy -WaitingExpireTime, albo porównujemy z WaitingExpireTime + // if + // ((VelSignal==0.0)&&(WaitingTime>WaitingExpireTime)&&(mvOccupied->RunningTrack.Velmax!=0.0)) + if (OrderList[OrderPos] & + (Shunt | Obey_train | 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 (WriteLogFlag) { - PrepareEngine(); // zmieni ustawiony kierunek - SetVelocity(20, 20); // jak się nastał, to niech jedzie 20km/h - WaitingTime = 0.0; - fWarningDuration = 1.5; // a zatrąbić trochę - mvOccupied->WarningSignal = 1; + append(AIlogFile); + writeln(AILogFile,ElapsedTime:5:2,": ",Name," V=0 waiting time expired! + (",WaitingTime:4:1,")"); + close(AILogFile); } - else - SetVelocity(20, 20); // użytkownikowi zezwalamy jechać + */ + if ((OrderList[OrderPos] & (Obey_train | Shunt)) ? + (iDrivigFlags & moveStopHere) : + false) + WaitingTime = -WaitingExpireTime; // zakaz ruszania z miejsca bez otrzymania + // wolnej drogi + else if (mvOccupied->CategoryFlag & 1) + { // jeśli pociąg + if (AIControllFlag) + { + PrepareEngine(); // zmieni ustawiony kierunek + SetVelocity(20, 20); // jak się nastał, to niech jedzie 20km/h + WaitingTime = 0.0; + fWarningDuration = 1.5; // a zatrąbić trochę + mvOccupied->WarningSignal = 1; } else - { // samochód ma stać, aż dostanie odjazd, chyba że stoi przez kolizję - if (eStopReason == stopBlock) - if (pVehicles[0]->fTrackBlock > fDriverDist) - if (AIControllFlag) - { - PrepareEngine(); // zmieni ustawiony kierunek - SetVelocity(-1, -1); // jak się nastał, to niech jedzie - WaitingTime = 0.0; - } - else { - // użytkownikowi pozwalamy jechać (samochodem?) - SetVelocity( -1, -1 ); - } - } + SetVelocity(20, 20); // użytkownikowi zezwalamy jechać + } + else + { // samochód ma stać, aż dostanie odjazd, chyba że stoi przez kolizję + if (eStopReason == stopBlock) + if (pVehicles[0]->fTrackBlock > fDriverDist) + if (AIControllFlag) + { + PrepareEngine(); // zmieni ustawiony kierunek + SetVelocity(-1, -1); // jak się nastał, to niech jedzie + WaitingTime = 0.0; + } + else { + // użytkownikowi pozwalamy jechać (samochodem?) + SetVelocity( -1, -1 ); + } } - else if ((VelSignal == 0.0) && (VelNext > 0.0) && (mvOccupied->Vel < 1.0)) - if (iCoupler ? true : (iDrivigFlags & moveStopHere) == 0) // Ra: tu jest coś nie - // tak, bo bez tego - // warunku ruszało w - // manewrowym !!!! - SetVelocity(VelNext, VelNext, stopSem); // omijanie SBL - } // koniec samoistnego odjeżdżania - - if( ( true == AIControllFlag ) - && ( ( true == HelpMeFlag ) - || ( mvControlling->DamageFlag > 0 ) ) ) { - HelpMeFlag = false; } - - if( ( true == AIControllFlag) - && ( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) ) { - // sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą) - SetVelocity( 0, 0, stopDir ); // najpierw trzeba się zatrzymać - 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 ) ) { - // 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 ); - } - } + else if( ( VelSignal == 0.0 ) && ( VelNext > 0.0 ) && ( mvOccupied->Vel < 1.0 ) ) { + if( iCoupler ? true : ( iDrivigFlags & moveStopHere ) == 0 ) { + // Ra: tu jest coś nie tak, bo bez tego warunku ruszało w manewrowym !!!! + SetVelocity( VelNext, VelNext, stopSem ); // omijanie SBL } - } // Change_direction (tylko dla AI) + } + } // koniec samoistnego odjeżdżania - if( ( true == AIControllFlag ) - && ( iEngineActive == 0 ) - && ( OrderList[ OrderPos ] & ( Change_direction | Connect | Disconnect | Shunt | Obey_train ) ) ) { - // jeśli coś ma robić to niech odpala do skutku + if( ( true == AIControllFlag) + && ( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) ) { + // sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą) + SetVelocity( 0, 0, stopDir ); // najpierw trzeba się zatrzymać + 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 ) ) { + // 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) + + if( ( true == AIControllFlag ) + && ( iEngineActive == 0 ) + && ( OrderList[ OrderPos ] & ( Change_direction | Connect | Disconnect | Shunt | Obey_train ) ) ) { + // jeśli coś ma robić to niech odpala do skutku + PrepareEngine(); + } + + // ustalanie zadanej predkosci + if (iDrivigFlags & moveActive) // jeśli może skanować sygnały i reagować na komendy + { // jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy + // Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od + // przeszkody + // no chyba żeby to uwzgldnić już w (ActualProximityDist) + VelDesired = fVelMax; // wstępnie prędkość maksymalna dla pojazdu(-ów), będzie + // następnie ograniczana + if( ( TrainParams ) + && ( TrainParams->TTVmax > 0.0 ) ) { + // jeśli ma rozkład i ograniczenie w rozkładzie to nie przekraczać rozkladowej + VelDesired = Global::Min0RSpeed( VelDesired, TrainParams->TTVmax ); } - // ustalanie zadanej predkosci - if (iDrivigFlags & moveActive) // jeśli może skanować sygnały i reagować na komendy - { // jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy - // Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od - // przeszkody - // no chyba żeby to uwzgldnić już w (ActualProximityDist) - VelDesired = fVelMax; // wstępnie prędkość maksymalna dla pojazdu(-ów), będzie - // następnie ograniczana - if( ( TrainParams ) - && ( TrainParams->TTVmax > 0.0 ) ) { - // jeśli ma rozkład i ograniczenie w rozkładzie to nie przekraczać rozkladowej - VelDesired = Global::Min0RSpeed( VelDesired, TrainParams->TTVmax ); - } - SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?) - // Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci - AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika - VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu - ActualProximityDist = scanmax; // funkcja Update() może pozostawić wartości bez zmian - // szukanie optymalnych wartości - TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); - switch (comm) - { // ustawienie VelSignal - trochę proteza = do przemyślenia - case cm_Ready: // W4 zezwolił na jazdę - // ewentualne doskanowanie trasy za W4, który zezwolił na jazdę - TableCheck( scanmax); - TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); // aktualizacja po skanowaniu - if (VelNext == 0.0) - break; // ale jak coś z przodu zamyka, to ma stać - if (iDrivigFlags & moveStopCloser) - VelSignal = -1.0; // ma czekać na sygnał z sygnalizatora! - case 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ą - PutCommand("SetVelocity", VelSignal, VelNext, - NULL); // komenda robi dodatkowe operacje - break; - case 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 - PutCommand("ShuntVelocity", VelSignal, VelNext, NULL); - else if (iCoupler) // jeśli jedzie w celu połączenia - SetVelocity(VelSignal, VelNext); - break; - case cm_Command: // komenda z komórki - if (!(OrderList[OrderPos] & - ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders - if (mvOccupied->Vel < 0.1) // dopiero jak stanie - // iDrivigFlags|=moveStopHere moveStopCloser) //chyba że stanął za daleko - // (SU46 w WK staje za daleko) - { - PutCommand(eSignNext->CommandGet(), eSignNext->ValueGet(1), - eSignNext->ValueGet(2), NULL); - eSignNext->StopCommandSent(); // się wykonało już - } - break; - } - if (VelNext == 0.0) - if (!(OrderList[OrderPos] & - ~(Shunt | Connect))) // jedzie w Shunt albo Connect, albo Wait_for_orders - { // jeżeli wolnej drogi nie ma, a jest w trybie manewrowym albo oczekiwania - // if - // ((OrderList[OrderPos]&Connect)?pVehicles[0]->fTrackBlock>ActualProximityDist:true) - // //pomiar odległości nie działa dobrze? - // 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) ? (pVehicles[0]->fTrackBlock > 2000 || pVehicles[0]->fTrackBlock > FirstSemaphorDist) : - true) - if ((comm = BackwardScan()) != cm_Unknown) // jeśli w drugą można jechać - { // należy sprawdzać odległość od znalezionego sygnalizatora, - // aby w przypadku prędkości 0.1 wyciągnąć najpierw skład za - // sygnalizator - // i dopiero wtedy zmienić kierunek jazdy, oczekując podania - // prędkości >0.5 - if (comm == cm_Command) // jeśli komenda Shunt - iDrivigFlags |= moveStopHere; // to ją odbierz bez przemieszczania się (np. - // odczep wagony po dopchnięciu do końca toru) - iDirectionOrder = -iDirection; // zmiana kierunku jazdy - // zmiana kierunku bez psucia kolejnych komend - OrderList[OrderPos] = TOrders(OrderList[OrderPos] | Change_direction); - } - } - double vel = mvOccupied->Vel; // prędkość w kierunku jazdy - if (iDirection * mvOccupied->V < 0) - vel = -vel; // ujemna, gdy jedzie w przeciwną stronę, niż powinien - if (VelDesired < 0.0) - VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną + SetDriverPsyche(); // ustawia AccPreferred (potrzebne tu?) - // Ra: jazda na widoczność + // szukanie optymalnych wartości + AccDesired = AccPreferred; // AccPreferred wynika z osobowości mechanika + VelNext = VelDesired; // maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu + ActualProximityDist = routescanrange; // funkcja Update() może pozostawić wartości bez zmian + // Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci + TCommandType comm = TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); + + switch (comm) + { // ustawienie VelSignal - trochę proteza = do przemyślenia + case cm_Ready: // W4 zezwolił na jazdę + // ewentualne doskanowanie trasy za W4, który zezwolił na jazdę + TableCheck( routescanrange); + TableUpdate(VelDesired, ActualProximityDist, VelNext, AccDesired); // aktualizacja po skanowaniu + if (VelNext == 0.0) + break; // ale jak coś z przodu zamyka, to ma stać + if (iDrivigFlags & moveStopCloser) + VelSignal = -1.0; // ma czekać na sygnał z sygnalizatora! + case 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ą + PutCommand("SetVelocity", VelSignal, VelNext, + NULL); // komenda robi dodatkowe operacje + break; + case 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 + PutCommand("ShuntVelocity", VelSignal, VelNext, NULL); + else if (iCoupler) // jeśli jedzie w celu połączenia + SetVelocity(VelSignal, VelNext); + break; + case cm_Command: // komenda z komórki + if( !( OrderList[ OrderPos ] & ~( Obey_train | Shunt ) ) ) { + // jedzie w dowolnym trybie albo Wait_for_orders + if( mvOccupied->Vel < 0.1 ) { + // dopiero jak stanie + PutCommand( eSignNext->CommandGet(), eSignNext->ValueGet( 1 ), eSignNext->ValueGet( 2 ), nullptr ); + eSignNext->StopCommandSent(); // się wykonało już + } + } + break; + } + + if( VelNext == 0.0 ) { + if( !( OrderList[ OrderPos ] & ~( 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 ) ? + ( pVehicles[ 0 ]->fTrackBlock > 2000 || pVehicles[ 0 ]->fTrackBlock > FirstSemaphorDist ) : + true ) { + if( ( comm = BackwardScan() ) != cm_Unknown ) { + // jeśli w drugą można jechać + // należy sprawdzać odległość od znalezionego sygnalizatora, + // aby w przypadku prędkości 0.1 wyciągnąć najpierw skład za sygnalizator + // i dopiero wtedy zmienić kierunek jazdy, oczekując podania prędkości >0.5 + if( comm == cm_Command ) { + // jeśli komenda Shunt to ją odbierz bez przemieszczania się (np. odczep wagony po dopchnięciu do końca toru) + iDrivigFlags |= moveStopHere; + } + iDirectionOrder = -iDirection; // zmiana kierunku jazdy + // zmiana kierunku bez psucia kolejnych komend + OrderList[ OrderPos ] = TOrders( OrderList[ OrderPos ] | Change_direction ); + } + } + } + } + + double vel = mvOccupied->Vel; // prędkość w kierunku jazdy + if (iDirection * mvOccupied->V < 0) + vel = -vel; // ujemna, gdy jedzie w przeciwną stronę, niż powinien + if (VelDesired < 0.0) + VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną + + // Ra: jazda na widoczność /* - // condition disabled, it'd prevent setting reduced acceleration in the last connect stage - if ((iDrivigFlags & moveConnect) == 0) // przy końcówce podłączania nie hamować + // condition disabled, it'd prevent setting reduced acceleration in the last connect stage + if ((iDrivigFlags & moveConnect) == 0) // przy końcówce podłączania nie hamować */ - { // sprawdzenie jazdy na widoczność - auto const vehicle = pVehicles[ 0 ]; // base calculactions off relevant end of the consist - auto const coupler = - vehicle->MoverParameters->Couplers + ( - vehicle->DirectionGet() > 0 ? - 0 : - 1 ); // sprzęg z przodu składu - if( ( coupler->Connected ) - && ( coupler->CouplingFlag == 0 ) ) { - // mamy coś z przodu podłączone sprzęgiem wirtualnym - // wyliczanie optymalnego przyspieszenia do jazdy na widoczność - ActualProximityDist = std::min( - ActualProximityDist, - vehicle->fTrackBlock - ( - mvOccupied->CategoryFlag & 2 ? - fMinProximityDist : // cars can bunch up tighter - fMaxProximityDist ) ); // other vehicle types less so - double k = coupler->Connected->Vel; // prędkość pojazdu z przodu (zakładając, - // że jedzie w tę samą stronę!!!) - if( k < vel + 10 ) { - // porównanie modułów prędkości [km/h] - // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej - double const distance = vehicle->fTrackBlock - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odległość bezpieczna zależy od prędkości - if( distance < 0 ) { - // 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 ) { - // jeśli spinanie, to jechać dalej - AccPreferred = std::min( 0.25, AccPreferred ); // nie hamuj - VelDesired = Global::Min0RSpeed( 20.0, VelDesired ); - VelNext = 2.0; // i pakuj się na tamtego - } - else { - // a normalnie to hamować - VelNext = 0.0; - if( vehicle->fTrackBlock <= fMinProximityDist ) { - VelDesired = 0.0; - } - } + { // sprawdzenie jazdy na widoczność + auto const vehicle = pVehicles[ 0 ]; // base calculactions off relevant end of the consist + auto const coupler = + vehicle->MoverParameters->Couplers + ( + vehicle->DirectionGet() > 0 ? + 0 : + 1 ); // sprzęg z przodu składu + if( ( coupler->Connected ) + && ( coupler->CouplingFlag == 0 ) ) { + // mamy coś z przodu podłączone sprzęgiem wirtualnym + // wyliczanie optymalnego przyspieszenia do jazdy na widoczność + ActualProximityDist = std::min( + ActualProximityDist, + vehicle->fTrackBlock - ( + mvOccupied->CategoryFlag & 2 ? + fMinProximityDist : // cars can bunch up tighter + fMaxProximityDist ) ); // other vehicle types less so + double k = coupler->Connected->Vel; // prędkość pojazdu z przodu (zakładając, + // że jedzie w tę samą stronę!!!) + if( k < vel + 10 ) { + // porównanie modułów prędkości [km/h] + // zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej + double const distance = vehicle->fTrackBlock - fMaxProximityDist - ( fBrakeDist * 1.15 ); // odległość bezpieczna zależy od prędkości + if( distance < 0 ) { + // 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 ) { + // jeśli spinanie, to jechać dalej + AccPreferred = std::min( 0.25, AccPreferred ); // nie hamuj + VelDesired = Global::Min0RSpeed( 20.0, VelDesired ); + VelNext = 2.0; // i pakuj się na tamtego } else { - // jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość - if( vehicle->fTrackBlock < ( - mvOccupied->CategoryFlag & 2 ? - fMaxProximityDist + 0.5 * vel : // cars - 2.0 * fMaxProximityDist + 2.0 * vel ) ) { //others - // jak tamten jedzie wolniej a jest w drodze hamowania - AccPreferred = std::min( -0.9, AccPreferred ); - VelNext = Global::Min0RSpeed( std::round( k ) - 5.0, VelDesired ); - if( vehicle->fTrackBlock <= ( - mvOccupied->CategoryFlag & 2 ? - fMaxProximityDist : // cars - 2.0 * fMaxProximityDist ) ) { //others - // try to force speed change if obstacle is really close - VelDesired = VelNext; - } + // a normalnie to hamować + VelNext = 0.0; + if( vehicle->fTrackBlock <= fMinProximityDist ) { + VelDesired = 0.0; } } - ReactionTime = ( - vel != 0.0 ? - 0.1 : // orientuj się, bo jest goraco - 2.0 ); // we're already standing still, so take it easy } else { - if( OrderCurrentGet() & Connect ) { - // if there's something nearby in the connect mode don't speed up too much - VelDesired = Global::Min0RSpeed( 20.0, VelDesired ); + // jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość + if( vehicle->fTrackBlock < ( + mvOccupied->CategoryFlag & 2 ? + fMaxProximityDist + 0.5 * vel : // cars + 2.0 * fMaxProximityDist + 2.0 * vel ) ) { //others + // jak tamten jedzie wolniej a jest w drodze hamowania + AccPreferred = std::min( -0.9, AccPreferred ); + VelNext = Global::Min0RSpeed( std::round( k ) - 5.0, VelDesired ); + if( vehicle->fTrackBlock <= ( + mvOccupied->CategoryFlag & 2 ? + fMaxProximityDist : // cars + 2.0 * fMaxProximityDist ) ) { //others + // try to force speed change if obstacle is really close + VelDesired = VelNext; + } } } + ReactionTime = ( + vel != 0.0 ? + 0.1 : // orientuj się, bo jest goraco + 2.0 ); // we're already standing still, so take it easy + } + else { + if( OrderCurrentGet() & Connect ) { + // if there's something nearby in the connect mode don't speed up too much + VelDesired = Global::Min0RSpeed( 20.0, VelDesired ); + } } } } + } - // sprawdzamy możliwe ograniczenia prędkości - if (OrderCurrentGet() & (Shunt | Obey_train)) // w Connect nie, bo moveStopHere - // odnosi się do stanu po połączeniu - if (iDrivigFlags & moveStopHere) // jeśli ma czekać na wolną drogę - if (vel == 0.0) // a stoi - if (VelNext == 0.0) // a wyjazdu nie ma - VelDesired = 0.0; // to ma stać - if (fStopTime < 0) // czas postoju przed dalszą jazdą (np. na przystanku) - VelDesired = 0.0; // jak ma czekać, to nie ma jazdy - // else if (VelSignal<0) - // VelDesired=fVelMax; //ile fabryka dala (Ra: uwzględione wagony) - else if (VelSignal >= 0) // jeśli skład był zatrzymany na początku i teraz już może jechać - VelDesired = Global::Min0RSpeed(VelDesired, VelSignal); + // sprawdzamy możliwe ograniczenia prędkości + if (OrderCurrentGet() & (Shunt | Obey_train)) // w Connect nie, bo moveStopHere + // odnosi się do stanu po połączeniu + if (iDrivigFlags & moveStopHere) // jeśli ma czekać na wolną drogę + if (vel == 0.0) // a stoi + if (VelNext == 0.0) // a wyjazdu nie ma + VelDesired = 0.0; // to ma stać + if (fStopTime < 0) // czas postoju przed dalszą jazdą (np. na przystanku) + VelDesired = 0.0; // jak ma czekać, to nie ma jazdy + // else if (VelSignal<0) + // VelDesired=fVelMax; //ile fabryka dala (Ra: uwzględione wagony) + else if (VelSignal >= 0) // jeśli skład był zatrzymany na początku i teraz już może jechać + VelDesired = Global::Min0RSpeed(VelDesired, VelSignal); - if (mvOccupied->RunningTrack.Velmax >= - 0) // ograniczenie prędkości z trajektorii ruchu - VelDesired = - Global::Min0RSpeed(VelDesired, - mvOccupied->RunningTrack.Velmax); // uwaga na ograniczenia szlakowej! - if (VelforDriver >= 0) // tu jest zero przy zmianie kierunku jazdy - VelDesired = Global::Min0RSpeed(VelDesired, VelforDriver); // Ra: tu może być 40, jeśli - // mechanik nie ma znajomości - // szlaaku, albo kierowca jeździ - // 70 - if (TrainParams) - if (TrainParams->CheckTrainLatency() < 5.0) - if (TrainParams->TTVmax > 0.0) - VelDesired = Global::Min0RSpeed( - VelDesired, - TrainParams - ->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej - if (VelDesired > 0.0) - if( ( ( iDrivigFlags & moveStopHere ) == 0 ) - || ( ( SemNextIndex != -1 ) - && ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s) - && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) { - // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w - // składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić - if (iDrivigFlags & moveGuardSignal) - { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas - // stania - iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać + if (mvOccupied->RunningTrack.Velmax >= + 0) // ograniczenie prędkości z trajektorii ruchu + VelDesired = + Global::Min0RSpeed(VelDesired, + mvOccupied->RunningTrack.Velmax); // uwaga na ograniczenia szlakowej! + if (VelforDriver >= 0) // tu jest zero przy zmianie kierunku jazdy + VelDesired = Global::Min0RSpeed(VelDesired, VelforDriver); // Ra: tu może być 40, jeśli + // mechanik nie ma znajomości + // szlaaku, albo kierowca jeździ + // 70 + if (TrainParams) + if (TrainParams->CheckTrainLatency() < 5.0) + if (TrainParams->TTVmax > 0.0) + VelDesired = Global::Min0RSpeed( + VelDesired, + TrainParams + ->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej + if (VelDesired > 0.0) + if( ( ( iDrivigFlags & moveStopHere ) == 0 ) + || ( ( SemNextIndex != -1 ) + && ( SemNextIndex < sSpeedTable.size() ) // BUG: index can point at non-existing slot. investigate reason(s) + && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) ) { + // jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w + // składzie, jeśli nie mamy czekać na sygnał też trzeba odpalić + if (iDrivigFlags & moveGuardSignal) + { // komunikat od kierownika tu, bo musi być wolna droga i odczekany czas + // stania + iDrivigFlags &= ~moveGuardSignal; // tylko raz nadać - if( iDrivigFlags & moveDoorOpened ) // jeśli drzwi otwarte - if( !mvOccupied - ->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę - Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika + if( iDrivigFlags & moveDoorOpened ) // jeśli drzwi otwarte + if( !mvOccupied + ->DoorOpenCtrl ) // jeśli drzwi niesterowane przez maszynistę + Doors( false ); // a EZT zamknie dopiero po odegraniu komunikatu kierownika - tsGuardSignal->Stop(); - // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy - // bezpośrednim - // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w - // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach - // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić - // obsługę kanałów radiowych itd. - if( !iGuardRadio ) { - // jeśli nie przez radio - tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej - } - else { - // if (iGuardRadio==iRadioChannel) //zgodność kanału - // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu - // (albo może mieć radio przenośne) - kierownik mógłby powtarzać - // przy braku reakcji - if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { - // w odległości mniejszej niż 2km - tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio - } + tsGuardSignal->Stop(); + // w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy + // bezpośrednim + // albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w + // pobliżu, a drugi radiowy, słyszalny w innych lokomotywach + // na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić + // obsługę kanałów radiowych itd. + if( !iGuardRadio ) { + // jeśli nie przez radio + tsGuardSignal->Play( 1.0, 0, !FreeFlyModeFlag, pVehicle->GetPosition() ); // dla true jest głośniej + } + else { + // if (iGuardRadio==iRadioChannel) //zgodność kanału + // if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu + // (albo może mieć radio przenośne) - kierownik mógłby powtarzać + // przy braku reakcji + if( SquareMagnitude( pVehicle->GetPosition() - Global::pCameraPosition ) < 2000 * 2000 ) { + // w odległości mniejszej niż 2km + tsGuardSignal->Play( 1.0, 0, true, pVehicle->GetPosition() ); // dźwięk niby przez radio } } } - if( mvOccupied->V == 0.0 ) { - // Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji - AbsAccS = fAccGravity; } - else { - AbsAccS = 0; - TDynamicObject *d = pVehicles[0]; // pojazd na czele składu - while (d) - { - AbsAccS += d->MoverParameters->TotalMass * d->MoverParameters->AccS * iDirection; - d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) - } - AbsAccS /= fMass; + if( mvOccupied->V == 0.0 ) { + // Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji + AbsAccS = fAccGravity; + } + else { + AbsAccS = 0; + TDynamicObject *d = pVehicles[0]; // pojazd na czele składu + while (d) + { + AbsAccS += d->MoverParameters->TotalMass * d->MoverParameters->AccS * iDirection; + d = d->Next(); // kolejny pojazd, podłączony od tyłu (licząc od czoła) } - AbsAccS_pub = AbsAccS; + AbsAccS /= fMass; + } + AbsAccS_pub = AbsAccS; #if LOGVELOCITY - // WriteLog("VelDesired="+AnsiString(VelDesired)+", - // VelSignal="+AnsiString(VelSignal)); - WriteLog("Vel=" + AnsiString(vel) + ", AbsAccS=" + AnsiString(AbsAccS) + - ", AccGrav=" + AnsiString(fAccGravity)); + // WriteLog("VelDesired="+AnsiString(VelDesired)+", + // VelSignal="+AnsiString(VelSignal)); + WriteLog("Vel=" + AnsiString(vel) + ", AbsAccS=" + AnsiString(AbsAccS) + + ", AccGrav=" + AnsiString(fAccGravity)); #endif - // ustalanie zadanego przyspieszenia - //(ActualProximityDist) - odległość do miejsca zmniejszenia prędkości - //(AccPreferred) - wynika z psychyki oraz uwzglęnia już ewentualne zderzenie z - // pojazdem z przodu, ujemne gdy należy hamować - //(AccDesired) - uwzględnia sygnały na drodze ruchu, ujemne gdy należy hamować - //(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne działa przeciwnie do - // zadanego kierunku jazdy - //(AbsAccS) - chwilowe przyspieszenie pojazu (uwzględnia grawitację), ujemne działa - // przeciwnie do zadanego kierunku jazdy - //(AccDesired) porównujemy z (fAccGravity) albo (AbsAccS) - if( ( VelNext >= 0.0 ) - && ( ActualProximityDist <= scanmax ) - && ( vel >= VelNext ) ) { - // gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu - if (vel > 0.0) { - // jeśli jedzie - if( ( vel < VelNext ) - && ( ActualProximityDist > fMaxProximityDist * ( 1.0 + 0.1 * vel ) ) ) { - // jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można przyspieszyć - if( AccPreferred > 0.0 ) { - // jeśli nie ma zawalidrogi dojedz do semafora/przeszkody - AccDesired = AccPreferred; - } - } - else if (ActualProximityDist > fMinProximityDist) { - // jedzie szybciej, niż trzeba na końcu ActualProximityDist, ale jeszcze jest daleko - if (ActualProximityDist < fMaxProximityDist) { - // jak minął już maksymalny dystans po prostu hamuj (niski stopień) - // ma stanąć, a jest w drodze hamowania albo ma jechać - VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); - if( VelDesired == 0.0 ) { - // hamowanie tak, aby stanąć - AccDesired = ( VelNext * VelNext - vel * vel ) / ( 25.92 * ( ActualProximityDist + 0.1 - 0.5*fMinProximityDist ) ); - AccDesired = std::min( AccDesired, fAccThreshold ); - } - } - else { - // przy dużej różnicy wysoki stopień (1,00 potrzebnego opoznienia) - // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever - auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); - AccDesired = std::min( - AccDesired, - ( VelNext * VelNext - vel * vel ) - / ( 25.92 - * std::max( - ActualProximityDist - brakingpointoffset, - std::min( - ActualProximityDist, - brakingpointoffset ) ) - + 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje - } - AccDesired = std::min( AccDesired, AccPreferred ); - } - else { - // jest bliżej niż fMinProximityDist - // utrzymuj predkosc bo juz blisko - VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); - if( vel <= VelNext + fVelPlus ) { - // jeśli niewielkie przekroczenie, ale ma jechać - AccDesired = std::max( 0.0, AccPreferred ); // to olej (zacznij luzować) - } - ReactionTime = 0.1; // i orientuj się szybciej - } - } - else { - // zatrzymany (vel==0.0) - if( VelNext > 0.0 ) { - // można jechać + // ustalanie zadanego przyspieszenia + //(ActualProximityDist) - odległość do miejsca zmniejszenia prędkości + //(AccPreferred) - wynika z psychyki oraz uwzglęnia już ewentualne zderzenie z + // pojazdem z przodu, ujemne gdy należy hamować + //(AccDesired) - uwzględnia sygnały na drodze ruchu, ujemne gdy należy hamować + //(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne działa przeciwnie do + // zadanego kierunku jazdy + //(AbsAccS) - chwilowe przyspieszenie pojazu (uwzględnia grawitację), ujemne działa + // przeciwnie do zadanego kierunku jazdy + //(AccDesired) porównujemy z (fAccGravity) albo (AbsAccS) + if( ( VelNext >= 0.0 ) + && ( ActualProximityDist <= routescanrange ) + && ( vel >= VelNext ) ) { + // gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu + if (vel > 0.0) { + // jeśli jedzie + if( ( vel < VelNext ) + && ( ActualProximityDist > fMaxProximityDist * ( 1.0 + 0.1 * vel ) ) ) { + // jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można przyspieszyć + if( AccPreferred > 0.0 ) { + // jeśli nie ma zawalidrogi dojedz do semafora/przeszkody AccDesired = AccPreferred; } - else { - // jeśli daleko jechać nie można - if( ActualProximityDist > ( - mvOccupied->CategoryFlag & 2 ? - fMinProximityDist : // cars - fMaxProximityDist ) ) { // trains and others - // ale ma kawałek do sygnalizatora - if( AccPreferred > 0.0 ) { - // dociagnij do semafora; - AccDesired = AccPreferred; - } - else { - //stoj - VelDesired = 0.0; - } + } + else if (ActualProximityDist > fMinProximityDist) { + // jedzie szybciej, niż trzeba na końcu ActualProximityDist, ale jeszcze jest daleko + if (ActualProximityDist < fMaxProximityDist) { + // jak minął już maksymalny dystans po prostu hamuj (niski stopień) + // ma stanąć, a jest w drodze hamowania albo ma jechać + VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); + if( VelDesired == 0.0 ) { + // hamowanie tak, aby stanąć + AccDesired = ( VelNext * VelNext - vel * vel ) / ( 25.92 * ( ActualProximityDist + 0.1 - 0.5*fMinProximityDist ) ); + AccDesired = std::min( AccDesired, fAccThreshold ); + } + } + else { + // przy dużej różnicy wysoki stopień (1,00 potrzebnego opoznienia) + // ensure some minimal coasting speed, otherwise a vehicle entering this zone at very low speed will be crawling forever + auto const brakingpointoffset = VelNext * braking_distance_multiplier( VelNext ); + AccDesired = std::min( + AccDesired, + ( VelNext * VelNext - vel * vel ) + / ( 25.92 + * std::max( + ActualProximityDist - brakingpointoffset, + std::min( + ActualProximityDist, + brakingpointoffset ) ) + + 0.1 ) ); // najpierw hamuje mocniej, potem zluzuje + } + AccDesired = std::min( AccDesired, AccPreferred ); + } + else { + // jest bliżej niż fMinProximityDist + // utrzymuj predkosc bo juz blisko + VelDesired = Global::Min0RSpeed( VelDesired, VelNext ); + if( vel <= VelNext + fVelPlus ) { + // jeśli niewielkie przekroczenie, ale ma jechać + AccDesired = std::max( 0.0, AccPreferred ); // to olej (zacznij luzować) + } + ReactionTime = 0.1; // i orientuj się szybciej + } + } + else { + // zatrzymany (vel==0.0) + if( VelNext > 0.0 ) { + // można jechać + AccDesired = AccPreferred; + } + else { + // jeśli daleko jechać nie można + if( ActualProximityDist > ( + mvOccupied->CategoryFlag & 2 ? + fMinProximityDist : // cars + fMaxProximityDist ) ) { // trains and others + // ale ma kawałek do sygnalizatora + if( AccPreferred > 0.0 ) { + // dociagnij do semafora; + AccDesired = AccPreferred; } else { - // VelNext=0 i stoi bliżej niż fMaxProximityDist + //stoj VelDesired = 0.0; } } + else { + // VelNext=0 i stoi bliżej niż fMaxProximityDist + VelDesired = 0.0; + } } } + } + else { + // gdy jedzie wolniej niż potrzeba, albo nie ma przeszkód na drodze + // normalna jazda + AccDesired = ( + VelDesired != 0.0 ? + AccPreferred : + -0.01 ); + } + // koniec predkosci nastepnej + + if( vel > VelDesired ) { + // jesli jedzie za szybko do AKTUALNEGO + if( VelDesired == 0.0 ) { + // jesli stoj, to hamuj, ale i tak juz za pozno :) + AccDesired = std::min( AccDesired, -0.9 ); // hamuj solidnie + } else { - // gdy jedzie wolniej niż potrzeba, albo nie ma przeszkód na drodze - // normalna jazda - AccDesired = ( - VelDesired != 0.0 ? - AccPreferred : - -0.01 ); - } - // koniec predkosci nastepnej - - if( vel > VelDesired ) { - // jesli jedzie za szybko do AKTUALNEGO - if( VelDesired == 0.0 ) { - // jesli stoj, to hamuj, ale i tak juz za pozno :) - AccDesired = std::min( AccDesired, -0.9 ); // hamuj solidnie + // slow down, not full stop + if( vel > ( VelDesired + fVelPlus ) ) { + // hamuj tak średnio + AccDesired = std::min( AccDesired, -fBrake_a0[ 0 ] * 0.5 ); } else { - // slow down, not full stop - if( vel > ( VelDesired + fVelPlus ) ) { - // hamuj tak średnio - AccDesired = std::min( AccDesired, -fBrake_a0[ 0 ] * 0.5 ); - } - else { - // o 5 km/h to olej (zacznij luzować) - AccDesired = std::min( - AccDesired, // but don't override decceleration for VelNext - std::max( 0.0, AccPreferred ) ); - } + // o 5 km/h to olej (zacznij luzować) + AccDesired = std::min( + AccDesired, // but don't override decceleration for VelNext + std::max( 0.0, AccPreferred ) ); } } - // koniec predkosci aktualnej + } + // koniec predkosci aktualnej - // last step sanity check, until the whole calculation is straightened out - AccDesired = std::min( AccDesired, AccPreferred ); + // last step sanity check, until the whole calculation is straightened out + AccDesired = std::min( AccDesired, AccPreferred ); - if (AIControllFlag) { - // część wykonawcza tylko dla AI, dla człowieka jedynie napisy + if (AIControllFlag) { + // część wykonawcza tylko dla AI, dla człowieka jedynie napisy - // zapobieganie poslizgowi u nas - if (mvControlling->SlippingWheels) { + // zapobieganie poslizgowi u nas + if (mvControlling->SlippingWheels) { - if (!mvControlling->DecScndCtrl(2)) // bocznik na zero - mvControlling->DecMainCtrl(1); + if (!mvControlling->DecScndCtrl(2)) // bocznik na zero + mvControlling->DecMainCtrl(1); /* - if (mvOccupied->BrakeCtrlPos == - mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania - //yB: ten warunek wyżej nie ma sensu - mvOccupied->DecBrakeLevel(); // to cofnij hamulec - DecBrake(); // to cofnij hamulec - else - mvControlling->AntiSlippingButton(); -*/ + if (mvOccupied->BrakeCtrlPos == + mvOccupied->BrakeCtrlPosNo) // jeśli ostatnia pozycja hamowania + //yB: ten warunek wyżej nie ma sensu + mvOccupied->DecBrakeLevel(); // to cofnij hamulec DecBrake(); // to cofnij hamulec + else mvControlling->AntiSlippingButton(); - ++iDriverFailCount; - mvControlling->SlippingWheels = false; // flaga już wykorzystana - } - if (iDriverFailCount > maxdriverfails) +*/ + DecBrake(); // to cofnij hamulec + mvControlling->AntiSlippingButton(); + ++iDriverFailCount; + mvControlling->SlippingWheels = false; // flaga już wykorzystana + } + if (iDriverFailCount > maxdriverfails) + { + Psyche = Easyman; + if (iDriverFailCount > maxdriverfails * 2) + SetDriverPsyche(); + } + + if( ( true == mvOccupied->RadioStopFlag ) // radio-stop + && ( mvOccupied->Vel > 0.0 ) ) { // and still moving + // if the radio-stop was issued don't waste effort trying to fight it + while( true == DecSpeed() ) { ; } // just throttle down... + return; // ...and don't touch any other controls + } + + if (mvControlling->ConvOvldFlag || + !mvControlling->Mains) // WS może wywalić z powodu błędu w drutach + { // wywalił bezpiecznik nadmiarowy przetwornicy + PrepareEngine(); // próba ponownego załączenia + } + // włączanie bezpiecznika + if ((mvControlling->EngineType == ElectricSeriesMotor) || + (mvControlling->TrainType & dt_EZT) || + (mvControlling->EngineType == DieselElectric)) + if (mvControlling->FuseFlag || Need_TryAgain) { - Psyche = Easyman; - if (iDriverFailCount > maxdriverfails * 2) - SetDriverPsyche(); - } - - if( ( true == mvOccupied->EmergencyBrakeFlag ) // radio-stop - && ( mvOccupied->Vel > 0.0 ) ) { // and still moving - // if the radio-stop was issued don't waste effort trying to fight it - while( true == DecSpeed() ) { ; } // just throttle down... - goto maintenance; // ...and don't touch any other controls - } - - if (mvControlling->ConvOvldFlag || - !mvControlling->Mains) // WS może wywalić z powodu błędu w drutach - { // wywalił bezpiecznik nadmiarowy przetwornicy - PrepareEngine(); // próba ponownego załączenia - } - // włączanie bezpiecznika - if ((mvControlling->EngineType == ElectricSeriesMotor) || - (mvControlling->TrainType & dt_EZT) || - (mvControlling->EngineType == DieselElectric)) - if (mvControlling->FuseFlag || Need_TryAgain) - { - Need_TryAgain = false; // true, jeśli druga pozycja w elektryku nie załapała - mvControlling->DecScndCtrl(2); // nastawnik bocznikowania na 0 - mvControlling->DecMainCtrl(2); // nastawnik jazdy na 0 - mvControlling->MainSwitch(true); // Ra: dodałem, bo EN57 stawały po wywaleniu - if (!mvControlling->FuseOn()) - HelpMeFlag = true; - else - { - ++iDriverFailCount; - if (iDriverFailCount > maxdriverfails) - Psyche = Easyman; - if (iDriverFailCount > maxdriverfails * 2) - SetDriverPsyche(); - } - } - // NOTE: as a stop-gap measure the routine is limited to trains only while car calculations seem off - if( mvControlling->CategoryFlag == 1 ) { - if( -AccDesired * BrakeAccFactor() < ( - ( ( fReady > 0.4 ) || ( VelNext > vel - 40.0 ) ) ? - fBrake_a0[ 0 ] * 0.8 : - -fAccThreshold ) - / braking_distance_multiplier( VelNext ) ) { - AccDesired = std::max( -0.06, AccDesired ); - } - else { - ReactionTime = 0.25; // i orientuj się szybciej, jeśli hamujesz + Need_TryAgain = false; // true, jeśli druga pozycja w elektryku nie załapała + mvControlling->DecScndCtrl(2); // nastawnik bocznikowania na 0 + mvControlling->DecMainCtrl(2); // nastawnik jazdy na 0 + mvControlling->MainSwitch(true); // Ra: dodałem, bo EN57 stawały po wywaleniu + if (mvControlling->FuseOn()) { + ++iDriverFailCount; + if (iDriverFailCount > maxdriverfails) + Psyche = Easyman; + if (iDriverFailCount > maxdriverfails * 2) + SetDriverPsyche(); } } - if (mvOccupied->BrakeSystem == Pneumatic) // napełnianie uderzeniowe - if (mvOccupied->BrakeHandle == FV4a) - { - if( mvOccupied->BrakeCtrlPos == -2 ) { - mvOccupied->BrakeLevelSet( 0 ); - } - if( ( mvOccupied->PipePress < 3.0 ) - && ( AccDesired > -0.03 ) ) { - mvOccupied->BrakeReleaser( 1 ); - } - if( ( mvOccupied->BrakeCtrlPos == 0 ) - && ( AbsAccS < 0.0 ) - && ( AccDesired > -0.03 ) ) { - - if( ( mvOccupied->EqvtPipePress < 4.95 ) - && ( fReady > 0.35 ) ) { // a reszta składu jest na to gotowa - - if( iDrivigFlags & moveOerlikons ) { - // napełnianie w Oerlikonie - mvOccupied->BrakeLevelSet( -1 ); - } - } - else if( Need_BrakeRelease ) { - Need_BrakeRelease = false; - mvOccupied->BrakeReleaser( 1 ); - } - } - - if( ( mvOccupied->BrakeCtrlPos < 0 ) - && ( mvOccupied->EqvtPipePress > ( - fReady < 0.25 ? - 5.1 : - 5.2 ) ) ) { - mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) ); - } - } -#if LOGVELOCITY - WriteLog("Dist=" + FloatToStrF(ActualProximityDist, ffFixed, 7, 1) + - ", VelDesired=" + FloatToStrF(VelDesired, ffFixed, 7, 1) + - ", AccDesired=" + FloatToStrF(AccDesired, ffFixed, 7, 3) + - ", VelSignal=" + AnsiString(VelSignal) + ", VelNext=" + - AnsiString(VelNext)); -#endif - if( ( vel < 10.0 ) - && ( AccDesired > 0.1 ) ) { - // Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, - // to nie ograniczać przyspieszenia do 0.5m/ss - // przy małych prędkościach może być trudno utrzymać - AccDesired = std::max( 0.9, AccDesired ); + // NOTE: as a stop-gap measure the routine is limited to trains only while car calculations seem off + if( mvControlling->CategoryFlag == 1 ) { + if( -AccDesired * BrakeAccFactor() < ( + ( ( fReady > 0.4 ) || ( VelNext > vel - 40.0 ) ) ? + fBrake_a0[ 0 ] * 0.8 : + -fAccThreshold ) + / braking_distance_multiplier( VelNext ) ) { + AccDesired = std::max( -0.06, AccDesired ); } - // małe przyspieszenie - // Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu migocze - if (AccDesired > -0.15) // hamowania lepeiej nie uśredniać - AccDesired = fAccDesiredAv = - 0.2 * AccDesired + - 0.8 * fAccDesiredAv; // uśrednione, żeby ograniczyć migotanie - if( VelDesired == 0.0 ) { - // Ra 2F1J: jeszcze jedna prowizoryczna łatka - if( AccDesired >= -0.01 ) { - AccDesired = -0.01; - } + else { + ReactionTime = 0.25; // i orientuj się szybciej, jeśli hamujesz } - if( AccDesired >= 0.0 ) { - if( true == TestFlag( iDrivigFlags, movePress ) ) { - // wyluzuj lokomotywę - może być więcej! + } + if (mvOccupied->BrakeSystem == Pneumatic) // napełnianie uderzeniowe + if (mvOccupied->BrakeHandle == FV4a) + { + if( mvOccupied->BrakeCtrlPos == -2 ) { + mvOccupied->BrakeLevelSet( 0 ); + } + if( ( mvOccupied->PipePress < 3.0 ) + && ( AccDesired > -0.03 ) ) { mvOccupied->BrakeReleaser( 1 ); } - else if( OrderList[ OrderPos ] != Disconnect ) { - // przy odłączaniu nie zwalniamy tu hamulca - if( ( fAccGravity * fAccGravity < 0.001 ? - true : - AccDesired > 0.0 ) ) { - // on slopes disengage the brakes only if you actually intend to accelerate - while( true == DecBrake() ) { ; } // jeśli przyspieszamy, to nie hamujemy - if( ( mvOccupied->BrakePress > 0.4 ) - && ( mvOccupied->Hamulec->GetCRP() > 4.9 ) ) { - // wyluzuj lokomotywę, to szybciej ruszymy - mvOccupied->BrakeReleaser( 1 ); + if( ( mvOccupied->BrakeCtrlPos == 0 ) + && ( AbsAccS < 0.0 ) + && ( AccDesired > -0.03 ) ) { + + if( ( mvOccupied->EqvtPipePress < 4.95 ) + && ( fReady > 0.35 ) ) { // a reszta składu jest na to gotowa + + if( iDrivigFlags & moveOerlikons ) { + // napełnianie w Oerlikonie + mvOccupied->BrakeLevelSet( -1 ); } - else { - if( mvOccupied->PipePress >= 3.0 ) { - // TODO: combine all releaser handling in single decision tree instead of having bits all over the place - mvOccupied->BrakeReleaser( 0 ); - } + } + else if( Need_BrakeRelease ) { + Need_BrakeRelease = false; + mvOccupied->BrakeReleaser( 1 ); + } + } + + if( ( mvOccupied->BrakeCtrlPos < 0 ) + && ( mvOccupied->EqvtPipePress > ( + fReady < 0.25 ? + 5.1 : + 5.2 ) ) ) { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_RP ) ); + } + } +#if LOGVELOCITY + WriteLog("Dist=" + FloatToStrF(ActualProximityDist, ffFixed, 7, 1) + + ", VelDesired=" + FloatToStrF(VelDesired, ffFixed, 7, 1) + + ", AccDesired=" + FloatToStrF(AccDesired, ffFixed, 7, 3) + + ", VelSignal=" + AnsiString(VelSignal) + ", VelNext=" + + AnsiString(VelNext)); +#endif + if( ( vel < 10.0 ) + && ( AccDesired > 0.1 ) ) { + // Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, + // to nie ograniczać przyspieszenia do 0.5m/ss + // przy małych prędkościach może być trudno utrzymać + AccDesired = std::max( 0.9, AccDesired ); + } + // małe przyspieszenie + // Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu migocze + if (AccDesired > -0.15) // hamowania lepeiej nie uśredniać + AccDesired = fAccDesiredAv = + 0.2 * AccDesired + + 0.8 * fAccDesiredAv; // uśrednione, żeby ograniczyć migotanie + if( VelDesired == 0.0 ) { + // Ra 2F1J: jeszcze jedna prowizoryczna łatka + if( AccDesired >= -0.01 ) { + AccDesired = -0.01; + } + } + if( AccDesired >= 0.0 ) { + if( true == TestFlag( iDrivigFlags, movePress ) ) { + // wyluzuj lokomotywę - może być więcej! + mvOccupied->BrakeReleaser( 1 ); + } + else if( OrderList[ OrderPos ] != Disconnect ) { + // przy odłączaniu nie zwalniamy tu hamulca + if( ( fAccGravity * fAccGravity < 0.001 ? + true : + AccDesired > 0.0 ) ) { + // on slopes disengage the brakes only if you actually intend to accelerate + while( true == DecBrake() ) { ; } // jeśli przyspieszamy, to nie hamujemy + if( ( mvOccupied->BrakePress > 0.4 ) + && ( mvOccupied->Hamulec->GetCRP() > 4.9 ) ) { + // wyluzuj lokomotywę, to szybciej ruszymy + mvOccupied->BrakeReleaser( 1 ); + } + else { + if( mvOccupied->PipePress >= 3.0 ) { + // TODO: combine all releaser handling in single decision tree instead of having bits all over the place + mvOccupied->BrakeReleaser( 0 ); } } } } - // margines dla prędkości jest doliczany tylko jeśli oczekiwana prędkość jest większa od 5km/h - if( false == TestFlag( iDrivigFlags, movePress ) ) { - // jeśli nie dociskanie - if( AccDesired < -0.1 ) { - while( true == DecSpeed() ) { ; } // jeśli hamujemy, to nie przyspieszamy - } - else if( ( vel > VelDesired ) - || ( fAccGravity < -0.01 ? - AccDesired < 0.0 : - AbsAccS > AccDesired ) ) { - // jak za bardzo przyspiesza albo prędkość przekroczona - DecSpeed(); // pojedyncze cofnięcie pozycji, bo na zero to przesada + } + // margines dla prędkości jest doliczany tylko jeśli oczekiwana prędkość jest większa od 5km/h + if( false == TestFlag( iDrivigFlags, movePress ) ) { + // jeśli nie dociskanie + if( AccDesired < -0.1 ) { + while( true == DecSpeed() ) { ; } // jeśli hamujemy, to nie przyspieszamy + } + else if( ( vel > VelDesired ) + || ( fAccGravity < -0.01 ? + AccDesired < 0.0 : + AbsAccS > AccDesired ) ) { + // jak za bardzo przyspiesza albo prędkość przekroczona + DecSpeed(); // pojedyncze cofnięcie pozycji, bo na zero to przesada + } + } + // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej + // zwiekszanie predkosci + // Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym + // przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia + if( AbsAccS < AccDesired ) { + // jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz + if( vel < VelDesired - fVelMinus ) { + // jeśli prędkość w kierunku czoła jest mniejsza od dozwolonej o margines + if( ( ActualProximityDist > ( + mvOccupied->CategoryFlag & 2 ? + fMinProximityDist : // cars are allowed to move within min proximity distance + fMaxProximityDist ) ? // other vehicle types keep wider margin + true : + vel < VelNext ) ) { + // to można przyspieszyć + IncSpeed(); } } - // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej - // zwiekszanie predkosci - // Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym - // przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia - if( AbsAccS < AccDesired ) { - // jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz - if( vel < VelDesired - fVelMinus ) { - // jeśli prędkość w kierunku czoła jest mniejsza od dozwolonej o margines - if( ( ActualProximityDist > ( - mvOccupied->CategoryFlag & 2 ? - fMinProximityDist : // cars are allowed to move within min proximity distance - fMaxProximityDist ) ? // other vehicle types keep wider margin - true : - vel < VelNext ) ) { - // to można przyspieszyć - IncSpeed(); - } - } + } + // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej + // zmniejszanie predkosci + if( mvOccupied->TrainType & dt_EZT ) { + // właściwie, to warunek powinien być na działający EP + // Ra: to dobrze hamuje EP w EZT + if( ( AccDesired <= fAccThreshold ) // jeśli hamować - u góry ustawia się hamowanie na fAccThreshold + && ( ( AbsAccS > AccDesired ) + || ( mvOccupied->BrakeCtrlPos < 0 ) ) ) { + // hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired) + IncBrake(); } - // yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej - // zmniejszanie predkosci - if( mvOccupied->TrainType & dt_EZT ) { - // właściwie, to warunek powinien być na działający EP - // Ra: to dobrze hamuje EP w EZT - if( ( AccDesired <= fAccThreshold ) // jeśli hamować - u góry ustawia się hamowanie na fAccThreshold - && ( ( AbsAccS > AccDesired ) - || ( mvOccupied->BrakeCtrlPos < 0 ) ) ) { - // hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired) - IncBrake(); - } - else if( OrderList[ OrderPos ] != 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 - if( mvOccupied->BrakeCtrlPos >= 0 ) { - DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu - } - } - else if( mvOccupied->Handle->TimeEP ) { - if( mvOccupied->Handle->GetPos( bh_EPR ) - - mvOccupied->Handle->GetPos( bh_EPN ) < - 0.1 ) { - mvOccupied->SwitchEPBrake( 0 ); - } - else { - mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPN ) ); - } - } - } // order != disconnect - } // type & dt_ezt - else { - // a stara wersja w miarę dobrze działa na składy wagonowe - if( ( ( fAccGravity < -0.05 ) && ( vel < 0.0 ) ) - || ( ( AccDesired < fAccGravity - 0.1 ) && ( AbsAccS > AccDesired + fBrake_a1[ 0 ] ) ) ) { - // u góry ustawia się hamowanie na fAccThreshold - if( ( fBrakeTime < 0.0 ) - || ( AccDesired < fAccGravity - 0.5 ) - || ( mvOccupied->BrakeCtrlPos <= 0 ) ) { - // jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował - if( true == IncBrake() ) { - fBrakeTime = - 3.0 - + 0.5 * ( ( - mvOccupied->BrakeDelayFlag > bdelay_G ? - mvOccupied->BrakeDelay[ 1 ] : - mvOccupied->BrakeDelay[ 3 ] ) - - 3.0 ); - // Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy - fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 - } - } - } - 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 ) { - // przy odłączaniu nie zwalniamy tu hamulca + else if( OrderList[ OrderPos ] != 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 + if( mvOccupied->BrakeCtrlPos >= 0 ) { DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu } - fBrakeTime = ( - mvOccupied->BrakeDelayFlag > bdelay_G ? - mvOccupied->BrakeDelay[ 0 ] : - mvOccupied->BrakeDelay[ 2 ] ) - / 3.0; - fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 } - // stop-gap measure to ensure cars actually brake to stop even when above calculactions go awry - // instead of releasing the brakes and creeping into obstacle at 1-2 km/h - if( mvControlling->CategoryFlag == 2 ) { - if( ( VelDesired == 0.0 ) - && ( vel > VelDesired ) - && ( ActualProximityDist <= fMinProximityDist ) - && ( mvOccupied->LocalBrakePos == 0 ) ) { - IncBrake(); + else if( mvOccupied->Handle->TimeEP ) { + if( mvOccupied->Handle->GetPos( bh_EPR ) - + mvOccupied->Handle->GetPos( bh_EPN ) < + 0.1 ) { + mvOccupied->SwitchEPBrake( 0 ); + } + else { + mvOccupied->BrakeLevelSet( mvOccupied->Handle->GetPos( bh_EPN ) ); + } + } + } // order != disconnect + } // type & dt_ezt + else { + // a stara wersja w miarę dobrze działa na składy wagonowe + if( ( ( fAccGravity < -0.05 ) && ( vel < 0.0 ) ) + || ( ( AccDesired < fAccGravity - 0.1 ) && ( AbsAccS > AccDesired + fBrake_a1[ 0 ] ) ) ) { + // u góry ustawia się hamowanie na fAccThreshold + if( ( fBrakeTime < 0.0 ) + || ( AccDesired < fAccGravity - 0.5 ) + || ( mvOccupied->BrakeCtrlPos <= 0 ) ) { + // jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował + if( true == IncBrake() ) { + fBrakeTime = + 3.0 + + 0.5 * ( ( + mvOccupied->BrakeDelayFlag > bdelay_G ? + mvOccupied->BrakeDelay[ 1 ] : + mvOccupied->BrakeDelay[ 3 ] ) + - 3.0 ); + // Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy + fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 } } } - // Mietek-end1 - SpeedSet(); // ciągla regulacja prędkości -#if LOGVELOCITY - WriteLog("BrakePos=" + AnsiString(mvOccupied->BrakeCtrlPos) + ", MainCtrl=" + - AnsiString(mvControlling->MainCtrlPos)); -#endif - } // if (AIControllFlag) - } // kierunek różny od zera - else - { // tutaj, gdy pojazd jest wyłączony - if (!AIControllFlag) // jeśli sterowanie jest w gestii użytkownika - if (mvOccupied->Battery) // czy użytkownik załączył baterię? - if (mvOccupied->ActiveDir) // czy ustawił kierunek - { // jeśli tak, to uruchomienie skanowania - CheckVehicles(); // sprawdzić skład - TableClear(); // resetowanie tabelki skanowania - PrepareEngine(); // uruchomienie + 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 ) { + // przy odłączaniu nie zwalniamy tu hamulca + DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu } - } - if (AIControllFlag) - { // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy - if ((OrderList[OrderPos] & (Disconnect | Connect)) == - 0) // przy (p)odłączaniu nie zwalniamy tu hamulca - if ((mvOccupied->V == 0.0) && ((VelDesired == 0.0) || (AccDesired == 0.0))) - if (mvOccupied->BrakeCtrlPos == mvOccupied->Handle->GetPos(bh_RP)) - mvOccupied->IncLocalBrakeLevel(1); // dodatkowy na pozycję 1 - else - mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP)); - } - break; // rzeczy robione przy jezdzie - } // switch (OrderList[OrderPos]) - // kasowanie licznika czasu - LastReactionTime = 0.0; - UpdateOK = true; - } // if ((LastReactionTime>Min0R(ReactionTime,2.0))) - else - LastReactionTime += dt; - -maintenance: - - if ((fLastStopExpDist > 0.0) && (mvOccupied->DistCounter > fLastStopExpDist)) - { - iStationStart = TrainParams->StationIndex; // zaktualizować wyświetlanie rozkładu - fLastStopExpDist = -1.0f; // usunąć licznik - } - if (AIControllFlag) - { - if (fWarningDuration > 0.0) // jeśli pozostało coś do wytrąbienia - { // trąbienie trwa nadal - fWarningDuration = fWarningDuration - dt; - if (fWarningDuration < 0.05) - mvOccupied->WarningSignal = 0; // a tu się kończy - if (ReactionTime > fWarningDuration) - ReactionTime = - fWarningDuration; // wcześniejszy przebłysk świadomości, by zakończyć trąbienie + fBrakeTime = ( + mvOccupied->BrakeDelayFlag > bdelay_G ? + mvOccupied->BrakeDelay[ 0 ] : + mvOccupied->BrakeDelay[ 2 ] ) + / 3.0; + fBrakeTime *= 0.5; // Ra: tymczasowo, bo przeżyna S1 + } + // stop-gap measure to ensure cars actually brake to stop even when above calculactions go awry + // instead of releasing the brakes and creeping into obstacle at 1-2 km/h + if( mvControlling->CategoryFlag == 2 ) { + if( ( VelDesired == 0.0 ) + && ( vel > VelDesired ) + && ( ActualProximityDist <= fMinProximityDist ) + && ( mvOccupied->LocalBrakePos == 0 ) ) { + IncBrake(); + } + } + } + // Mietek-end1 + SpeedSet(); // ciągla regulacja prędkości +#if LOGVELOCITY + WriteLog("BrakePos=" + AnsiString(mvOccupied->BrakeCtrlPos) + ", MainCtrl=" + + AnsiString(mvControlling->MainCtrlPos)); +#endif + } // if (AIControllFlag) + } // kierunek różny od zera + else + { // tutaj, gdy pojazd jest wyłączony + if (!AIControllFlag) // jeśli sterowanie jest w gestii użytkownika + if (mvOccupied->Battery) // czy użytkownik załączył baterię? + if (mvOccupied->ActiveDir) // czy ustawił kierunek + { // jeśli tak, to uruchomienie skanowania + CheckVehicles(); // sprawdzić skład + TableClear(); // resetowanie tabelki skanowania + PrepareEngine(); // uruchomienie + } } - if (mvOccupied->Vel >= 3.0) { - // 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 + if (AIControllFlag) + { // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy + if ((OrderList[OrderPos] & (Disconnect | Connect)) == + 0) // przy (p)odłączaniu nie zwalniamy tu hamulca + if ((mvOccupied->V == 0.0) && ((VelDesired == 0.0) || (AccDesired == 0.0))) + if (mvOccupied->BrakeCtrlPos == mvOccupied->Handle->GetPos(bh_RP)) + mvOccupied->IncLocalBrakeLevel(1); // dodatkowy na pozycję 1 + else + mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_RP)); } - return UpdateOK; - } - else // if (AIControllFlag) - return false; // AI nie obsługuje + break; // rzeczy robione przy jezdzie + } // switch (OrderList[OrderPos]) } void TController::JumpToNextOrder() @@ -5031,14 +5012,6 @@ std::string TController::StopReasonText() //- rozpoznają tylko zerową prędkość (jako koniec toru i brak podstaw do dalszego skanowania) //---------------------------------------------------------------------------------------------------------------------- -/* //nie używane -double TController::Distance(vector3 &p1,vector3 &n,vector3 &p2) -{//Ra:obliczenie odległości punktu (p1) od płaszczyzny o wektorze normalnym (n) przechodzącej przez -(p2) - return n.x*(p1.x-p2.x)+n.y*(p1.y-p2.y)+n.z*(p1.z-p2.z); //ax1+by1+cz1+d, gdzie d=-(ax2+by2+cz2) -}; -*/ - bool TController::BackwardTrackBusy(TTrack *Track) { // najpierw sprawdzamy, czy na danym torze są pojazdy z innego składu if( false == Track->Dynamics.empty() ) { @@ -5062,8 +5035,7 @@ TEvent * TController::CheckTrackEventBackward(double fDirection, TTrack *Track) return NULL; }; -TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection, - TTrack *Track, TEvent *&Event) +TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection, TTrack *Track, TEvent *&Event) { // szukanie sygnalizatora w kierunku przeciwnym jazdy (eventu odczytu komórki pamięci) TTrack *pTrackChVel = Track; // tor ze zmianą prędkości TTrack *pTrackFrom; // odcinek poprzedni, do znajdywania końca dróg @@ -5106,10 +5078,11 @@ TTrack * TController::BackwardTraceRoute(double &fDistance, double &fDirection, } if (Track == pTrackFrom) Track = NULL; // koniec, tak jak dla torów - if (Track ? - (Track->VelocityGet() == 0.0) || (Track->iDamageFlag & 128) || - BackwardTrackBusy(Track) : - true) + if( ( Track ? + ( ( Track->VelocityGet() == 0.0 ) + || ( Track->iDamageFlag & 128 ) + || ( true == BackwardTrackBusy( Track ) ) ) : + true ) ) { // gdy dalej toru nie ma albo zerowa prędkość, albo uszkadza pojazd fDistance = s; return NULL; // zwraca NULL, że skanowanie nie dało sensownych rezultatów diff --git a/Driver.h b/Driver.h index 69f636b0..ea68da69 100644 --- a/Driver.h +++ b/Driver.h @@ -217,7 +217,6 @@ class TController double fActionTime = 0.0; // czas używany przy regulacji prędkości i zamykaniu drzwi double m_radiocontroltime{ 0.0 }; // timer used to control speed of radio operations TAction eAction = actSleep; // aktualny stan - bool HelpMeFlag = false; // wystawiane True jesli cos niedobrego sie dzieje public: inline TAction GetAction() { @@ -320,7 +319,7 @@ class TController const TLocation &NewLocation, TStopReason reason = stopComm); bool PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const vector3 *NewLocation, TStopReason reason = stopComm); - bool UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę + void UpdateSituation(double dt); // uruchamiac przynajmniej raz na sekundę // procedury dotyczace rozkazow dla maszynisty void SetVelocity(double NewVel, double NewVelNext, TStopReason r = stopNone); // uaktualnia informacje o prędkości diff --git a/DynObj.cpp b/DynObj.cpp index 67ce1097..3c570da5 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -1945,14 +1945,14 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" compartmentindex < 10 ? "0" + std::to_string( compartmentindex ) : std::to_string( compartmentindex ) ); - submodel = mdLowPolyInt->GetFromName( compartmentname.c_str() ); + submodel = mdLowPolyInt->GetFromName( compartmentname ); if( submodel != nullptr ) { // if specified compartment was found we check also for potential matching section in the currently assigned load // NOTE: if the load gets changed this will invalidate stored pointers. TODO: rebuild the table on load change SectionLightLevels.emplace_back( submodel, ( mdLoad != nullptr ? - mdLoad->GetFromName( compartmentname.c_str() ): + mdLoad->GetFromName( compartmentname ): nullptr ), 0.0f ); } @@ -1965,11 +1965,11 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" for (int i = 0; i < 2; i++) { asAnimName = std::string("buffer_left0") + to_string(i + 1); - smBuforLewy[i] = mdModel->GetFromName(asAnimName.c_str()); + smBuforLewy[i] = mdModel->GetFromName(asAnimName); if (smBuforLewy[i]) smBuforLewy[i]->WillBeAnimated(); // ustawienie flagi animacji asAnimName = std::string("buffer_right0") + to_string(i + 1); - smBuforPrawy[i] = mdModel->GetFromName(asAnimName.c_str()); + smBuforPrawy[i] = mdModel->GetFromName(asAnimName); if (smBuforPrawy[i]) smBuforPrawy[i]->WillBeAnimated(); } @@ -4212,7 +4212,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, for (int i = 0; i < iAnimType[ANIM_PANTS]; i++) { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* asAnimName = token + std::to_string(i + 1); - sm = mdModel->GetFromName(asAnimName.c_str()); + sm = mdModel->GetFromName(asAnimName); pants[i].smElement[0] = sm; // jak NULL, to nie będzie animowany if (sm) { // w EP09 wywalało się tu z powodu NULL @@ -4304,7 +4304,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, for( int i = 0; i < iAnimType[ ANIM_PANTS ]; i++ ) { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* asAnimName = token + std::to_string( i + 1 ); - sm = mdModel->GetFromName( asAnimName.c_str() ); + sm = mdModel->GetFromName( asAnimName ); pants[ i ].smElement[ 1 ] = sm; // jak NULL, to nie będzie animowany if( sm ) { // w EP09 wywalało się tu z powodu NULL sm->WillBeAnimated(); @@ -4338,7 +4338,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, for( int i = 0; i < iAnimType[ ANIM_PANTS ]; i++ ) { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* asAnimName = token + std::to_string( i + 1 ); - pants[ i ].smElement[ 2 ] = mdModel->GetFromName( asAnimName.c_str() ); + pants[ i ].smElement[ 2 ] = mdModel->GetFromName( asAnimName ); pants[ i ].smElement[ 2 ]->WillBeAnimated(); } } @@ -4351,7 +4351,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, for( int i = 0; i < iAnimType[ ANIM_PANTS ]; i++ ) { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* asAnimName = token + std::to_string( i + 1 ); - pants[ i ].smElement[ 3 ] = mdModel->GetFromName( asAnimName.c_str() ); + pants[ i ].smElement[ 3 ] = mdModel->GetFromName( asAnimName ); pants[ i ].smElement[ 3 ]->WillBeAnimated(); } } @@ -4364,7 +4364,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, for( int i = 0; i < iAnimType[ ANIM_PANTS ]; i++ ) { // Winger 160204: wyszukiwanie max 2 patykow o nazwie str* asAnimName = token + std::to_string( i + 1 ); - pants[ i ].smElement[ 4 ] = mdModel->GetFromName( asAnimName.c_str() ); + pants[ i ].smElement[ 4 ] = mdModel->GetFromName( asAnimName ); pants[ i ].smElement[ 4 ]->WillBeAnimated(); /* pants[ i ].yUpdate = UpdatePant; */ pants[ i ].yUpdate = std::bind( &TDynamicObject::UpdatePant, this, std::placeholders::_1 ); @@ -4498,7 +4498,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, for (int i = 1; i <= 4; i++) { // McZapkie-050402: wyszukiwanie max 4 wahaczy o nazwie str* asAnimName = token + std::to_string(i); - smWahacze[i - 1] = mdModel->GetFromName(asAnimName.c_str()); + smWahacze[i - 1] = mdModel->GetFromName(asAnimName); smWahacze[i - 1]->WillBeAnimated(); } parser.getTokens(); parser >> token; @@ -4535,7 +4535,7 @@ void TDynamicObject::LoadMMediaFile(std::string BaseDir, std::string TypeName, { // NBMX wrzesien 2003: wyszukiwanie drzwi o nazwie str* asAnimName = token + std::to_string(i + 1); pAnimations[i + j].smAnimated = - mdModel->GetFromName(asAnimName.c_str()); // ustalenie submodelu + mdModel->GetFromName(asAnimName); // ustalenie submodelu if (pAnimations[i + j].smAnimated) { //++iAnimatedDoors; pAnimations[i + j].smAnimated->WillBeAnimated(); // wyłączenie optymalizacji transformu diff --git a/DynObj.h b/DynObj.h index 59efe6e2..88c9e0ea 100644 --- a/DynObj.h +++ b/DynObj.h @@ -178,6 +178,7 @@ public: // parametry położenia pojazdu dostępne publicznie int NextConnectedNo; // numer sprzęgu podłączonego z tyłu int PrevConnectedNo; // numer sprzęgu podłączonego z przodu double fScanDist; // odległość skanowania torów na obecność innych pojazdów + double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym pojazdem) TPowerSource ConnectedEnginePowerSource( TDynamicObject const *Caller ) const; @@ -366,8 +367,6 @@ public: // modele składowe pojazdu public: int *iLights; // wskaźnik na bity zapalonych świateł (własne albo innego członu) bool DimHeadlights{ false }; // status of the headlight dimming toggle. NOTE: single toggle for all lights is a simplification. TODO: separate per-light switches - double fTrackBlock; // odległość do przeszkody do dalszego ruchu (wykrywanie kolizji z innym - // pojazdem) TDynamicObject * PrevAny(); TDynamicObject * Prev(); TDynamicObject * Next(); diff --git a/Event.cpp b/Event.cpp index ae9836c3..1038d1be 100644 --- a/Event.cpp +++ b/Event.cpp @@ -78,7 +78,7 @@ void TEvent::Conditions(cParser *parser, std::string s) if (!asNodeName.empty()) { // podczepienie łańcucha, jeśli nie jest pusty // BUG: source of a memory leak -- the array never gets deleted. fix the destructor - Params[9].asText = new char[asNodeName.length() + 1]; // usuwane i zamieniane na + Params[9].asText = new char[asNodeName.size() + 1]; // usuwane i zamieniane na // wskaźnik strcpy(Params[9].asText, asNodeName.c_str()); } @@ -103,7 +103,7 @@ void TEvent::Conditions(cParser *parser, std::string s) str = token; if (str != "*") //"*" - nie brac command pod uwage { // zapamiętanie łańcucha do porównania - Params[10].asText = new char[255]; + Params[10].asText = new char[str.size() + 1]; strcpy(Params[10].asText, str.c_str()); iFlags |= conditional_memstring; } @@ -144,7 +144,6 @@ void TEvent::Load(cParser *parser, vector3 *org) int ti; std::string token; //string str; - char *ptr; bEnabled = true; // zmieniane na false dla eventów używanych do skanowania sygnałów @@ -222,14 +221,12 @@ void TEvent::Load(cParser *parser, vector3 *org) // if (Type==tp_UpdateValues) iFlags=0; //co modyfikować parser->getTokens(1, false); // case sensitive *parser >> token; - // str = AnsiString(token.c_str()); - Params[0].asText = new char[token.length() + 1]; // BUG: source of memory leak + Params[0].asText = new char[token.size() + 1]; // BUG: source of memory leak strcpy(Params[0].asText, token.c_str()); if (token != "*") // czy ma zostać bez zmian? iFlags |= update_memstring; parser->getTokens(); *parser >> token; - // str = AnsiString(token.c_str()); if (token != "*") // czy ma zostać bez zmian? { Params[1].asdouble = atof(token.c_str()); @@ -239,7 +236,6 @@ void TEvent::Load(cParser *parser, vector3 *org) Params[1].asdouble = 0; parser->getTokens(); *parser >> token; - // str = AnsiString(token.c_str()); if (token != "*") // czy ma zostać bez zmian? { Params[2].asdouble = atof(token.c_str()); @@ -262,7 +258,7 @@ void TEvent::Load(cParser *parser, vector3 *org) switch (++i) { // znaczenie kolejnych parametrów case 1: // nazwa drugiej komórki (źródłowej) - Params[9].asText = new char[token.length() + 1]; // usuwane i zamieniane na wskaźnik + Params[9].asText = new char[token.size() + 1]; // usuwane i zamieniane na wskaźnik strcpy(Params[9].asText, token.c_str()); break; case 2: // maska wartości @@ -353,7 +349,7 @@ void TEvent::Load(cParser *parser, vector3 *org) } else Params[6].asCommand = cm_Unknown; - Params[0].asText = new char[token.length() + 1]; + Params[0].asText = new char[token.size() + 1]; strcpy(Params[0].asText, token.c_str()); parser->getTokens(); *parser >> token; @@ -561,7 +557,7 @@ void TEvent::Load(cParser *parser, vector3 *org) { // eventy rozpoczynające się od "none_" są ignorowane if (token != "else") { - Params[i].asText = new char[255]; + Params[i].asText = new char[token.size() + 1]; strcpy(Params[i].asText, token.c_str()); if (ti) iFlags |= conditional_else << i; // oflagowanie dla eventów "else" diff --git a/Event.h b/Event.h index 7d020046..4eaebfe1 100644 --- a/Event.h +++ b/Event.h @@ -15,8 +15,7 @@ http://mozilla.org/MPL/2.0/. using namespace Math3D; -typedef enum -{ +enum TEventType { tp_Unknown, tp_Sound, tp_SoundPos, @@ -41,7 +40,7 @@ typedef enum tp_Voltage, tp_Message, tp_Friction -} TEventType; +}; const int update_memstring = 0x0000001; // zmodyfikować tekst (UpdateValues) const int update_memval1 = 0x0000002; // zmodyfikować pierwszą wartosć diff --git a/Gauge.cpp b/Gauge.cpp index 2c262268..4def85c2 100644 --- a/Gauge.cpp +++ b/Gauge.cpp @@ -85,7 +85,7 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) { } scale *= mul; - TSubModel *submodel = md1->GetFromName( submodelname.c_str() ); + TSubModel *submodel = md1->GetFromName( submodelname ); if( scale == 0.0 ) { ErrorLog( "Scale of 0.0 defined for sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\". Forcing scale of 1.0 to prevent division by 0" ); scale = 1.0; @@ -93,7 +93,7 @@ bool TGauge::Load(cParser &Parser, TModel3d *md1, TModel3d *md2, double mul) { if (submodel) // jeśli nie znaleziony md2 = nullptr; // informacja, że znaleziony else if (md2) // a jest podany drugi model (np. zewnętrzny) - submodel = md2->GetFromName(submodelname.c_str()); // to może tam będzie, co za różnica gdzie + submodel = md2->GetFromName(submodelname); // to może tam będzie, co za różnica gdzie if( submodel == nullptr ) { ErrorLog( "Failed to locate sub-model \"" + submodelname + "\" in 3d model \"" + md1->NameGet() + "\"" ); } diff --git a/Ground.cpp b/Ground.cpp index 6c5b29e1..8c2a349d 100644 --- a/Ground.cpp +++ b/Ground.cpp @@ -1599,7 +1599,7 @@ TGroundNode * TGround::AddGroundNode(cParser *parser) importedvertices.emplace_back( vertex0 ); } if( importedvertices.size() % 2 != 0 ) { - ErrorLog( "Lines node specified odd number of vertices, encountered in file \"" + parser->Name() + "\"" ); + ErrorLog( "Lines node specified odd number of vertices, encountered in file \"" + parser->Name() + "\" (line " + std::to_string( parser->Line() - 1 ) + ")" ); importedvertices.pop_back(); } tmp->iType = GL_LINES; @@ -1654,6 +1654,8 @@ TSubRect * TGround::GetSubRect(int iCol, int iRow) TEvent * TGround::FindEvent(const std::string &asEventName) { + if( asEventName.empty() ) { return nullptr; } + auto const lookup = m_eventmap.find( asEventName ); return ( lookup != m_eventmap.end() ? @@ -1868,7 +1870,7 @@ bool TGround::Init(std::string File) } else { - ErrorLog("Scene parsing error in file \"" + parser.Name() + "\", unexpected token \"" + token + "\""); + ErrorLog("Scene parsing error in file \"" + parser.Name() + "\" (line " + std::to_string( parser.Line() ) + "), unexpected token \"" + token + "\""); // break; } } @@ -2208,7 +2210,7 @@ bool TGround::Init(std::string File) bool TGround::InitEvents() { //łączenie eventów z pozostałymi obiektami TGroundNode *tmp, *trk; - char buff[ 255 ]; std::string cellastext; + std::string cellastext; int i; for (TEvent *Current = RootEvent; Current; Current = Current->evNext2) { @@ -2216,19 +2218,16 @@ bool TGround::InitEvents() { case tp_AddValues: // sumowanie wartości case tp_UpdateValues: // zmiana wartości - tmp = FindGroundNode(Current->asNodeName, - TP_MEMCELL); // nazwa komórki powiązanej z eventem + tmp = FindGroundNode(Current->asNodeName, TP_MEMCELL); // nazwa komórki powiązanej z eventem if (tmp) { // McZapkie-100302 if (Current->iFlags & (conditional_trackoccupied | conditional_trackfree)) { // jeśli chodzi o zajetosc toru (tor może być inny, niż wpisany w komórce) - trk = FindGroundNode(Current->asNodeName, - TP_TRACK); // nazwa toru ta sama, co nazwa komórki + trk = FindGroundNode(Current->asNodeName, TP_TRACK); // nazwa toru ta sama, co nazwa komórki if (trk) Current->Params[9].asTrack = trk->pTrack; if (!Current->Params[9].asTrack) - ErrorLog("Bad event: track \"" + Current->asNodeName + - "\" does not exists in \"" + Current->asName + "\""); + ErrorLog("Bad event: track \"" + Current->asNodeName + "\" referenced in event \"" + Current->asName + "\" doesn't exist"); } Current->Params[4].nGroundNode = tmp; Current->Params[5].asMemCell = tmp->MemCell; // komórka do aktualizacji @@ -2241,8 +2240,7 @@ bool TGround::InitEvents() if (trk) Current->Params[6].asTrack = trk->pTrack; else - ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName + - "\" not exists in memcell \"" + tmp->asName + "\""); + ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName + "\" referenced in memcell \"" + tmp->asName + "\" doesn't exist"); } else Current->Params[6].asTrack = NULL; @@ -2250,8 +2248,7 @@ bool TGround::InitEvents() else { // nie ma komórki, to nie będzie działał poprawnie Current->Type = tp_Ignored; // deaktywacja - ErrorLog("Bad event: \"" + Current->asName + "\" cannot find memcell \"" + - Current->asNodeName + "\""); + ErrorLog("Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\""); } break; case tp_LogValues: // skojarzenie z memcell @@ -2275,8 +2272,7 @@ bool TGround::InitEvents() else { // nie ma komórki, to nie będzie działał poprawnie Current->Type = tp_Ignored; // deaktywacja - ErrorLog("Bad event: \"" + Current->asName + "\" cannot find memcell \"" + - Current->asNodeName + "\""); + ErrorLog("Bad event: event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\""); } break; case tp_CopyValues: // skopiowanie komórki do innej @@ -2292,15 +2288,13 @@ bool TGround::InitEvents() if (trk) Current->Params[6].asTrack = trk->pTrack; else - ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName + - "\" not exists in memcell \"" + tmp->asName + "\""); + ErrorLog("Bad memcell: track \"" + tmp->MemCell->asTrackName + "\" referenced in memcell \"" + tmp->asName + "\" doesn't exists"); } else Current->Params[6].asTrack = NULL; } else - ErrorLog("Bad copyvalues: event \"" + Current->asName + - "\" cannot find memcell \"" + Current->asNodeName + "\""); + ErrorLog("Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + Current->asNodeName + "\""); cellastext = Current->Params[ 9 ].asText; SafeDeleteArray(Current->Params[9].asText); // usunięcie nazwy komórki tmp = FindGroundNode( cellastext, TP_MEMCELL); // komórka źódłowa @@ -2309,22 +2303,19 @@ bool TGround::InitEvents() Current->Params[9].asMemCell = tmp->MemCell; // komórka źródłowa } else - ErrorLog("Bad copyvalues: event \"" + Current->asName + - "\" cannot find memcell \"" + cellastext + "\""); + ErrorLog("Bad event: copyvalues event \"" + Current->asName + "\" cannot find memcell \"" + cellastext + "\""); break; case tp_Animation: // animacja modelu tmp = FindGroundNode(Current->asNodeName, TP_MODEL); // egzemplarza modelu do animowania if (tmp) { - strcpy( - buff, - Current->Params[9].asText); // skopiowanie nazwy submodelu do bufora roboczego + cellastext = Current->Params[9].asText; // skopiowanie nazwy submodelu do bufora roboczego SafeDeleteArray(Current->Params[9].asText); // usunięcie nazwy submodelu if (Current->Params[0].asInt == 4) Current->Params[9].asModel = tmp->Model; // model dla całomodelowych animacji else { // standardowo przypisanie submodelu - Current->Params[9].asAnimContainer = tmp->Model->GetContainer(buff); // submodel + Current->Params[9].asAnimContainer = tmp->Model->GetContainer(cellastext); // submodel if (Current->Params[9].asAnimContainer) { Current->Params[9].asAnimContainer->WillBeAnimated(); // oflagowanie @@ -2332,13 +2323,12 @@ bool TGround::InitEvents() if (!Current->Params[9] .asAnimContainer->Event()) // nie szukać, gdy znaleziony Current->Params[9].asAnimContainer->EventAssign( - FindEvent(Current->asNodeName + "." + buff + ":done")); + FindEvent(Current->asNodeName + "." + cellastext + ":done")); } } } else - ErrorLog("Bad animation: event \"" + Current->asName + "\" cannot find model \"" + - Current->asNodeName + "\""); + ErrorLog("Bad event: animation event \"" + Current->asName + "\" cannot find model \"" + Current->asNodeName + "\""); Current->asNodeName = ""; break; case tp_Lights: // zmiana świeteł modelu @@ -2346,8 +2336,7 @@ bool TGround::InitEvents() if (tmp) Current->Params[9].asModel = tmp->Model; else - ErrorLog("Bad lights: event \"" + Current->asName + "\" cannot find model \"" + - Current->asNodeName + "\""); + ErrorLog("Bad event: lights event \"" + Current->asName + "\" cannot find model \"" + Current->asNodeName + "\""); Current->asNodeName = ""; break; case tp_Visible: // ukrycie albo przywrócenie obiektu @@ -2359,8 +2348,7 @@ bool TGround::InitEvents() if (tmp) Current->Params[9].nGroundNode = tmp; else - ErrorLog("Bad visibility: event \"" + Current->asName + "\" cannot find model \"" + - Current->asNodeName + "\""); + ErrorLog("Bad event: visibility event \"" + Current->asName + "\" cannot find model \"" + Current->asNodeName + "\""); Current->asNodeName = ""; break; case tp_Switch: // przełożenie zwrotnicy albo zmiana stanu obrotnicy @@ -2378,8 +2366,7 @@ bool TGround::InitEvents() Current->Params[2].asdouble); // przesłanie parametrów } else - ErrorLog("Bad switch: event \"" + Current->asName + "\" cannot find track \"" + - Current->asNodeName + "\""); + ErrorLog("Bad event: switch event \"" + Current->asName + "\" cannot find track \"" + Current->asNodeName + "\""); Current->asNodeName = ""; break; case tp_Sound: // odtworzenie dźwięku @@ -2387,8 +2374,7 @@ bool TGround::InitEvents() if (tmp) Current->Params[9].tsTextSound = tmp->tsStaticSound; else - ErrorLog("Bad sound: event \"" + Current->asName + - "\" cannot find static sound \"" + Current->asNodeName + "\""); + ErrorLog("Bad event: sound event \"" + Current->asName + "\" cannot find static sound \"" + Current->asNodeName + "\""); Current->asNodeName = ""; break; case tp_TrackVel: // ustawienie prędkości na torze @@ -2402,8 +2388,7 @@ bool TGround::InitEvents() Current->Params[9].asTrack = tmp->pTrack; } else - ErrorLog("Bad velocity: event \"" + Current->asName + - "\" cannot find track \"" + Current->asNodeName + "\""); + ErrorLog("Bad event: track velocity event \"" + Current->asName + "\" cannot find track \"" + Current->asNodeName + "\""); } Current->asNodeName = ""; break; @@ -2416,54 +2401,53 @@ bool TGround::InitEvents() if (tmp) Current->Params[9].asDynamic = tmp->DynamicObject; else - Error("Event \"" + Current->asName + "\" cannot find dynamic \"" + - Current->asNodeName + "\""); + Error("Bad event: vehicle velocity event \"" + Current->asName + "\" cannot find vehicle \"" + Current->asNodeName + "\""); } Current->asNodeName = ""; break; case tp_Multiple: if (Current->Params[9].asText != NULL) { // przepisanie nazwy do bufora - strcpy(buff, Current->Params[9].asText); + cellastext = Current->Params[ 9 ].asText; SafeDeleteArray(Current->Params[9].asText); Current->Params[9].asPointer = NULL; // zerowanie wskaźnika, aby wykryć brak obeiktu } else - buff[0] = '\0'; + cellastext = ""; if (Current->iFlags & (conditional_trackoccupied | conditional_trackfree)) { // jeśli chodzi o zajetosc toru - tmp = FindGroundNode(buff, TP_TRACK); + tmp = FindGroundNode(cellastext, TP_TRACK); if (tmp) Current->Params[9].asTrack = tmp->pTrack; if (!Current->Params[9].asTrack) { - ErrorLog("Bad event: Track \"" + std::string(buff) + "\" does not exist in \"" + Current->asName + "\""); + ErrorLog("Bad event: Track \"" + cellastext + "\" does not exist in \"" + Current->asName + "\""); Current->iFlags &= ~(conditional_trackoccupied | conditional_trackfree); // zerowanie flag } } else if (Current->iFlags & (conditional_memstring | conditional_memval1 | conditional_memval2)) { // jeśli chodzi o komorke pamieciową - tmp = FindGroundNode(buff, TP_MEMCELL); + tmp = FindGroundNode(cellastext, TP_MEMCELL); if (tmp) Current->Params[9].asMemCell = tmp->MemCell; if (!Current->Params[9].asMemCell) { - ErrorLog("Bad event: MemCell \"" + std::string(buff) + "\" does not exist in \"" + Current->asName + "\""); + ErrorLog("Bad event: MemCell \"" + cellastext + "\" does not exist in \"" + Current->asName + "\""); Current->iFlags &= ~(conditional_memstring | conditional_memval1 | conditional_memval2); } } - for (i = 0; i < 8; i++) + for (i = 0; i < 8; ++i) { if (Current->Params[i].asText != NULL) { - strcpy(buff, Current->Params[i].asText); + cellastext = Current->Params[ i ].asText; SafeDeleteArray(Current->Params[i].asText); - Current->Params[i].asEvent = FindEvent(buff); + Current->Params[i].asEvent = FindEvent(cellastext); if( !Current->Params[ i ].asEvent ) { // Ra: tylko w logu informacja o braku if( ( Current->Params[ i ].asText == NULL ) || ( std::string( Current->Params[ i ].asText ).substr( 0, 5 ) != "none_" ) ) { - WriteLog( "Event \"" + std::string( buff ) + "\" does not exist" ); - ErrorLog( "Missed event: " + std::string( buff ) + " in multiple " + Current->asName ); + WriteLog( "Event \"" + cellastext + "\" does not exist" ); + ErrorLog( "Missed event: " + cellastext + " in multiple " + Current->asName ); } } } @@ -2472,13 +2456,11 @@ bool TGround::InitEvents() case tp_Voltage: // zmiana napięcia w zasilaczu (TractionPowerSource) if (!Current->asNodeName.empty()) { - tmp = FindGroundNode(Current->asNodeName, - TP_TRACTIONPOWERSOURCE); // podłączenie zasilacza + tmp = FindGroundNode(Current->asNodeName, TP_TRACTIONPOWERSOURCE); // podłączenie zasilacza if (tmp) Current->Params[9].psPower = tmp->psTractionPowerSource; else - ErrorLog("Bad voltage: event \"" + Current->asName + - "\" cannot find power source \"" + Current->asNodeName + "\""); + ErrorLog("Bad event: voltage event \"" + Current->asName + "\" cannot find power source \"" + Current->asNodeName + "\""); } Current->asNodeName = ""; break; @@ -2501,43 +2483,32 @@ void TGround::InitTracks() TTrack *tmp; // znaleziony tor TTrack *Track; int iConnection; - std::string name; - // tracks=tracksfar=0; - for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext) - { - Track = Current->pTrack; - if (Global::iHiddenEvents & 1) - if (!Current->asName.empty()) - { // jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę - if (Track->asEvent0Name.empty()) - if (FindEvent(Current->asName + ":event0")) - Track->asEvent0Name = Current->asName + ":event0"; - if (Track->asEvent1Name.empty()) - if (FindEvent(Current->asName + ":event1")) - Track->asEvent1Name = Current->asName + ":event1"; - if (Track->asEvent2Name.empty()) - if (FindEvent(Current->asName + ":event2")) - Track->asEvent2Name = Current->asName + ":event2"; - if (Track->asEventall0Name.empty()) - if (FindEvent(Current->asName + ":eventall0")) - Track->asEventall0Name = Current->asName + ":eventall0"; - if (Track->asEventall1Name.empty()) - if (FindEvent(Current->asName + ":eventall1")) - Track->asEventall1Name = Current->asName + ":eventall1"; - if (Track->asEventall2Name.empty()) - if (FindEvent(Current->asName + ":eventall2")) - Track->asEventall2Name = Current->asName + ":eventall2"; - } + for (Current = nRootOfType[TP_TRACK]; Current; Current = Current->nNext) { + + Track = Current->pTrack; + // assign track events Track->AssignEvents( - Track->asEvent0Name.empty() ? NULL : FindEvent(Track->asEvent0Name), - Track->asEvent1Name.empty() ? NULL : FindEventScan(Track->asEvent1Name), - Track->asEvent2Name.empty() ? NULL : FindEventScan(Track->asEvent2Name)); + FindEvent( Track->asEvent0Name ), + FindEvent( Track->asEvent1Name ), + FindEvent( Track->asEvent2Name ) ); Track->AssignallEvents( - Track->asEventall0Name.empty() ? NULL : FindEvent(Track->asEventall0Name), - Track->asEventall1Name.empty() ? NULL : FindEvent(Track->asEventall1Name), - Track->asEventall2Name.empty() ? NULL : - FindEvent(Track->asEventall2Name)); // MC-280503 + FindEvent( Track->asEventall0Name ), + FindEvent( Track->asEventall1Name ), + FindEvent( Track->asEventall2Name ) ); + if( ( Global::iHiddenEvents & 1 ) + && ( false == Current->asName.empty() ) ) { + // jeśli podana jest nazwa torów, można szukać eventów skojarzonych przez nazwę + Track->AssignEvents( + FindEvent( Current->asName + ":event0" ), + FindEvent( Current->asName + ":event1" ), + FindEvent( Current->asName + ":event2" ) ); + Track->AssignallEvents( + FindEvent( Current->asName + ":eventall0" ), + FindEvent( Current->asName + ":eventall1" ), + FindEvent( Current->asName + ":eventall2" ) ); + } + switch (Track->eType) { case tt_Table: // obrotnicę też łączymy na starcie z innymi torami @@ -2635,7 +2606,7 @@ void TGround::InitTracks() FindEvent(Current->asName + ":forced-")); break; } - name = Track->IsolatedName(); // pobranie nazwy odcinka izolowanego + std::string const name = Track->IsolatedName(); // pobranie nazwy odcinka izolowanego if (!name.empty()) // jeśli została zwrócona nazwa Track->IsolatedEventsAssign(FindEvent(name + ":busy"), FindEvent(name + ":free")); if (Current->asName.substr(0, 1) == diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index ff855c95..68a331cb 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -867,7 +867,8 @@ public: /* int BrakeStatus = b_off; //0 - odham, 1 - ham., 2 - uszk., 4 - odluzniacz, 8 - antyposlizg, 16 - uzyte EP, 32 - pozycja R, 64 - powrot z R */ - bool EmergencyBrakeFlag = false; /*hamowanie nagle*/ + bool EmergencyBrakeFlag = false; // manual emergency brake + bool RadioStopFlag = false; /*hamowanie nagle*/ int BrakeDelayFlag = 0; /*nastawa opoznienia ham. osob/towar/posp/exp 0/1/2/4*/ int BrakeDelays = 0; /*nastawy mozliwe do uzyskania*/ int BrakeOpModeFlag = 0; /*nastawa trybu pracy PS/PN/EP/MED 1/2/4/8*/ @@ -1082,7 +1083,7 @@ public: bool IncManualBrakeLevel(int CtrlSpeed); bool DecManualBrakeLevel(int CtrlSpeed); bool DynamicBrakeSwitch(bool Switch); - bool EmergencyBrakeSwitch(bool Switch); + bool RadiostopSwitch(bool Switch); bool AntiSlippingBrake(void); bool BrakeReleaser(int state); bool SwitchEPBrake(int state); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 1a1a0cfa..e338b93d 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -2188,7 +2188,7 @@ void TMoverParameters::SecuritySystemCheck(double dt) // obsady // poza tym jest zdefiniowany we wszystkich 3 członach EN57 if ((!Radio)) - EmergencyBrakeSwitch(false); + RadiostopSwitch(false); if ((SecuritySystem.SystemType > 0) && (SecuritySystem.Status > 0) && (Battery)) // Ra: EZT ma teraz czuwak w rozrządczym @@ -2259,7 +2259,7 @@ void TMoverParameters::SecuritySystemCheck(double dt) } else if (!Battery) { // wyłączenie baterii deaktywuje sprzęt - EmergencyBrakeSwitch(false); + RadiostopSwitch(false); // SecuritySystem.Status = 0; //deaktywacja czuwaka } } @@ -2777,14 +2777,14 @@ bool TMoverParameters::DynamicBrakeSwitch(bool Switch) // Q: 20160711 // włączenie / wyłączenie hamowania awaryjnego // ************************************************************************************************* -bool TMoverParameters::EmergencyBrakeSwitch(bool Switch) +bool TMoverParameters::RadiostopSwitch(bool Switch) { bool EBS; if ((BrakeSystem != Individual) && (BrakeCtrlPosNo > 0)) { - if ((!EmergencyBrakeFlag) && Switch) + if ((!RadioStopFlag) && Switch) { - EmergencyBrakeFlag = Switch; + RadioStopFlag = Switch; EBS = true; } else @@ -2792,7 +2792,7 @@ bool TMoverParameters::EmergencyBrakeSwitch(bool Switch) if ((abs(V) < 0.1) && (Switch == false)) // odblokowanie hamulca bezpieczenistwa tylko po zatrzymaniu { - EmergencyBrakeFlag = Switch; + RadioStopFlag = Switch; EBS = true; } else @@ -3283,7 +3283,7 @@ void TMoverParameters::UpdatePipePressure(double dt) } // if(EmergencyBrakeFlag)and(BrakeCtrlPosNo=0)then //ulepszony hamulec bezp. - if ((EmergencyBrakeFlag) || (TestFlag(SecuritySystem.Status, s_SHPebrake)) || + if ((RadioStopFlag) || (TestFlag(SecuritySystem.Status, s_SHPebrake)) || (TestFlag(SecuritySystem.Status, s_CAebrake)) || (s_CAtestebrake == true) || (TestFlag(EngDmgFlag, 32)) /* or (not Battery)*/) // ulepszony hamulec bezp. @@ -8266,7 +8266,7 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } else if (Command == "Emergency_brake") { - if (EmergencyBrakeSwitch(floor(CValue1) == 1)) // YB: czy to jest potrzebne? + if (RadiostopSwitch(floor(CValue1) == 1)) // YB: czy to jest potrzebne? OK = true; else OK = false; diff --git a/Model3d.cpp b/Model3d.cpp index 802e918e..41834753 100644 --- a/Model3d.cpp +++ b/Model3d.cpp @@ -842,23 +842,18 @@ struct ToLower }; TSubModel *TSubModel::GetFromName(std::string const &search, bool i) -{ - return GetFromName(search.c_str(), i); -}; - -TSubModel *TSubModel::GetFromName(char const *search, bool i) { TSubModel *result; // std::transform(search.begin(),search.end(),search.begin(),ToLower()); // search=search.LowerCase(); // AnsiString name=AnsiString(); - std::string search_lc = std::string(search); + std::string search_lc = search; if (i) std::transform(search_lc.begin(), search_lc.end(), search_lc.begin(), ::tolower); std::string pName_lc = pName; if (i) std::transform(pName_lc.begin(), pName_lc.end(), pName_lc.begin(), ::tolower); - if (pName.size() && search) + if (pName.size() && search.size()) if (pName_lc == search_lc) return this; if (Next) @@ -1147,23 +1142,19 @@ TModel3d::TModel3d() Root = NULL; iFlags = 0; iSubModelsCount = 0; - iModel = NULL; // tylko jak wczytany model binarny iNumVerts = 0; // nie ma jeszcze wierzchołków }; -TModel3d::~TModel3d() -{ - // SafeDeleteArray(Materials); - if (iFlags & 0x0200) - { // wczytany z pliku tekstowego, submodele sprzątają same - SafeDelete(Root); // submodele się usuną rekurencyjnie +TModel3d::~TModel3d() { + + if (iFlags & 0x0200) { + // wczytany z pliku tekstowego, submodele sprzątają same + Root = nullptr; } - else - { // wczytano z pliku binarnego (jest właścicielem tablic) - Root = nullptr; - delete[] iModel; // usuwamy cały wczytany plik i to wystarczy - } - // później się jeszcze usuwa obiekt z którego dziedziczymy tabelę VBO + else { + // wczytano z pliku binarnego (jest właścicielem tablic) + SafeDeleteArray( Root ); // submodele się usuną rekurencyjnie + } }; TSubModel *TModel3d::AddToNamed(const char *Name, TSubModel *SubModel) @@ -1190,16 +1181,16 @@ void TModel3d::AddTo(TSubModel *tmp, TSubModel *SubModel) iFlags |= 0x0200; // submodele są oddzielne }; -TSubModel *TModel3d::GetFromName(const char *sName) +TSubModel *TModel3d::GetFromName(std::string const &Name) { // wyszukanie submodelu po nazwie - if (!sName) + if (Name.empty()) return Root; // potrzebne do terenu z E3D if (iFlags & 0x0200) // wczytany z pliku tekstowego, wyszukiwanie rekurencyjne - return Root ? Root->GetFromName(sName) : nullptr; + return Root ? Root->GetFromName(Name) : nullptr; else // wczytano z pliku binarnego, można wyszukać iteracyjnie { // for (int i=0;iGetFromName(sName) : nullptr; + return Root ? Root->GetFromName(Name) : nullptr; } }; @@ -1455,7 +1446,6 @@ void TSubModel::deserialize(std::istream &s) void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) { Root = nullptr; - float4x4 *tm = nullptr; if( m_geometrybank == null_handle ) { m_geometrybank = GfxRenderer.Create_Bank(); } @@ -1478,7 +1468,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) iSubModelsCount = (int)sm_cnt; Root = new TSubModel[sm_cnt]; size_t pos = s.tellg(); - for (size_t i = 0; i < sm_cnt; i++) + for (size_t i = 0; i < sm_cnt; ++i) { s.seekg(pos + sm_size * i); Root[i].deserialize(s); @@ -1493,18 +1483,13 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) size_t vt_cnt = size / 32; iNumVerts = (int)vt_cnt; m_nVertexCount = (int)vt_cnt; -#ifdef EU07_USE_OLD_VERTEXBUFFER - assert( m_pVNT == nullptr ); - m_pVNT = new basic_vertex[vt_cnt]; -#else m_pVNT.resize( vt_cnt ); -#endif for (size_t i = 0; i < vt_cnt; i++) m_pVNT[i].deserialize(s); */ - // we rely on the SUB chunk coming before the vertex data, and on the overall vertex count matching the size of data in the chunk + // we rely on the SUB chunk coming before the vertex data, and on the overall vertex count matching the size of data in the chunk. // geometry associated with chunks isn't stored in the same order as the chunks themselves, so we need to sort that out first - std::vector< std::pair > submodeloffsets; + std::vector< std::pair > submodeloffsets; // vertex data offset, submodel index submodeloffsets.reserve( iSubModelsCount ); for( int submodelindex = 0; submodelindex < iSubModelsCount; ++submodelindex ) { auto const &submodel = Root[ submodelindex ]; @@ -1551,23 +1536,23 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) } else if (type == MAKE_ID4('T', 'R', 'A', '0')) { - if (tm != nullptr) - throw std::runtime_error("e3d: duplicated TRA chunk"); + if( false == Matrices.empty() ) + throw std::runtime_error("e3d: duplicated TRA chunk"); size_t t_cnt = size / 64; - tm = new float4x4[t_cnt]; - for (size_t i = 0; i < t_cnt; i++) - tm[i].deserialize_float32(s); + Matrices.resize(t_cnt); + for (size_t i = 0; i < t_cnt; ++i) + Matrices[i].deserialize_float32(s); } else if (type == MAKE_ID4('T', 'R', 'A', '1')) { - if (tm != nullptr) - throw std::runtime_error("e3d: duplicated TRA chunk"); + if( false == Matrices.empty() ) + throw std::runtime_error("e3d: duplicated TRA chunk"); size_t t_cnt = size / 128; - tm = new float4x4[t_cnt]; - for (size_t i = 0; i < t_cnt; i++) - tm[i].deserialize_float64(s); + Matrices.resize( t_cnt ); + for (size_t i = 0; i < t_cnt; ++i) + Matrices[i].deserialize_float64(s); } else if (type == MAKE_ID4('T', 'E', 'X', '0')) { @@ -1589,17 +1574,10 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic) if (!Root) throw std::runtime_error("e3d: no submodels"); -/* -#ifdef EU07_USE_OLD_VERTEXBUFFER - if (!m_pVNT) -#else - if(m_pVNT.empty() ) -#endif - throw std::runtime_error("e3d: no vertices"); -*/ - for (size_t i = 0; (int)i < iSubModelsCount; ++i) + + for (size_t i = 0; (int)i < iSubModelsCount; ++i) { - Root[i].BinInit( Root, tm, &Textures, &Names, dynamic ); + Root[i].BinInit( Root, Matrices.data(), &Textures, &Names, dynamic ); if (Root[i].ChildGet()) Root[i].ChildGet()->Parent = &Root[i]; diff --git a/Model3d.h b/Model3d.h index 395bf40a..181bd93a 100644 --- a/Model3d.h +++ b/Model3d.h @@ -172,8 +172,7 @@ public: void SetTranslate(vector3 vNewTransVector); void SetTranslate(float3 vNewTransVector); void SetRotateIK1(float3 vNewAngles); - TSubModel * GetFromName(std::string const &search, bool i = true); - TSubModel * GetFromName(char const *search, bool i = true); + TSubModel * GetFromName( std::string const &search, bool i = true ); inline float4x4 * GetMatrix() { return fMatrix; }; inline void Hide() { iVisible = 0; }; @@ -232,7 +231,7 @@ public: // Ra: tymczasowo private: std::vector Textures; // nazwy tekstur std::vector Names; // nazwy submodeli - int *iModel; // zawartość pliku binarnego + std::vector Matrices; // submodel matrices int iSubModelsCount; // Ra: używane do tworzenia binarnych std::string asBinary; // nazwa pod którą zapisać model binarny std::string m_filename; @@ -240,7 +239,7 @@ public: inline TSubModel * GetSMRoot() { return (Root); }; TModel3d(); ~TModel3d(); - TSubModel * GetFromName(const char *sName); + TSubModel * GetFromName(std::string const &Name); TSubModel * AddToNamed(const char *Name, TSubModel *SubModel); void AddTo(TSubModel *tmp, TSubModel *SubModel); void LoadFromTextFile(std::string const &FileName, bool dynamic); diff --git a/PyInt.cpp b/PyInt.cpp index 5203afbb..6d91a24b 100644 --- a/PyInt.cpp +++ b/PyInt.cpp @@ -446,7 +446,7 @@ void TPythonScreens::init(cParser &parser, TModel3d *model, std::string const &n >> asPyClassName; std::string subModelName = ToLower( asSubModelName ); std::string pyClassName = ToLower( asPyClassName ); - TSubModel *subModel = model->GetFromName(subModelName.c_str()); + TSubModel *subModel = model->GetFromName(subModelName); if (subModel == NULL) { WriteLog( "Python Screen: submodel " + subModelName + " not found - Ignoring screen" ); diff --git a/Track.cpp b/Track.cpp index dddd9e59..bee712aa 100644 --- a/Track.cpp +++ b/Track.cpp @@ -778,145 +778,127 @@ void TTrack::Load(cParser *parser, vector3 pOrigin, std::string name) } } +// TODO: refactor this mess bool TTrack::AssignEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2) { bool bError = false; - if (!evEvent0) - { - if (NewEvent0) - { + + if( NewEvent0 == nullptr ) { + if( false == asEvent0Name.empty() ) { + ErrorLog( "Bad event: event \"" + asEvent0Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" ); + bError = true; + } + } + else { + if( evEvent0 == nullptr ) { evEvent0 = NewEvent0; asEvent0Name = ""; iEvents |= 1; // sumaryczna informacja o eventach } - else - { - if (!asEvent0Name.empty()) - { - ErrorLog("Bad track: Event0 \"" + asEvent0Name + - "\" does not exist"); - bError = true; - } + else { + ErrorLog( "Bad track: event \"" + NewEvent0->asName + "\" cannot be assigned to track, track already has one" ); + bError = true; } } - else - { - ErrorLog( "Bad track: Event0 cannot be assigned to track, track already has one"); - bError = true; + + if( NewEvent1 == nullptr ) { + if( false == asEvent1Name.empty() ) { + ErrorLog( "Bad event: event \"" + asEvent1Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" ); + bError = true; + } } - if (!evEvent1) - { - if (NewEvent1) - { + else { + if( evEvent1 == nullptr ) { evEvent1 = NewEvent1; asEvent1Name = ""; iEvents |= 2; // sumaryczna informacja o eventach } - else if (!asEvent1Name.empty()) - { // Ra: tylko w logu informacja - ErrorLog("Bad track: Event1 \"" + asEvent1Name + "\" does not exist"); + else { + ErrorLog( "Bad track: event \"" + NewEvent1->asName + "\" cannot be assigned to track, track already has one" ); bError = true; } } - else - { - ErrorLog("Bad track: Event1 cannot be assigned to track, track already has one"); - bError = true; + + if( NewEvent2 == nullptr ) { + if( false == asEvent2Name.empty() ) { + ErrorLog( "Bad event: event \"" + asEvent2Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" ); + bError = true; + } } - if (!evEvent2) - { - if (NewEvent2) - { + else { + if( evEvent2 == nullptr ) { evEvent2 = NewEvent2; asEvent2Name = ""; iEvents |= 4; // sumaryczna informacja o eventach } - else if (!asEvent2Name.empty()) - { // Ra: tylko w logu informacja - ErrorLog("Bad track: Event2 \"" + asEvent2Name + "\" does not exist"); + else { + ErrorLog( "Bad track: event \"" + NewEvent2->asName + "\" cannot be assigned to track, track already has one" ); bError = true; } } - else - { - ErrorLog("Bad track: Event2 cannot be assigned to track, track already has one"); - bError = true; - } - return !bError; + + return ( bError == false ); } bool TTrack::AssignallEvents(TEvent *NewEvent0, TEvent *NewEvent1, TEvent *NewEvent2) { bool bError = false; - if (!evEventall0) - { - if (NewEvent0) - { + + if( NewEvent0 == nullptr ) { + if( false == asEventall0Name.empty() ) { + ErrorLog( "Bad event: event \"" + asEventall0Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" ); + bError = true; + } + } + else { + if( evEventall0 == nullptr ) { evEventall0 = NewEvent0; asEventall0Name = ""; iEvents |= 8; // sumaryczna informacja o eventach } - else - { - if (!asEvent0Name.empty()) - { - Error("Eventall0 \"" + asEventall0Name + - "\" does not exist"); - bError = true; - } + else { + ErrorLog( "Bad track: event \"" + NewEvent0->asName + "\" cannot be assigned to track, track already has one" ); + bError = true; } } - else - { - Error("Eventall0 cannot be assigned to track, track already has one"); - bError = true; + + if( NewEvent1 == nullptr ) { + if( false == asEventall1Name.empty() ) { + ErrorLog( "Bad event: event \"" + asEventall1Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" ); + bError = true; + } } - if (!evEventall1) - { - if (NewEvent1) - { - evEventall1 = NewEvent1; + else { + if( evEventall1 == nullptr ) { + evEventall1 = NewEvent0; asEventall1Name = ""; iEvents |= 16; // sumaryczna informacja o eventach } - else - { - if (!asEvent0Name.empty()) - { // Ra: tylko w logu informacja - WriteLog("Eventall1 \"" + asEventall1Name + "\" does not exist"); - bError = true; - } + else { + ErrorLog( "Bad track: event \"" + NewEvent1->asName + "\" cannot be assigned to track, track already has one" ); + bError = true; } } - else - { - Error("Eventall1 cannot be assigned to track, track already has one"); - bError = true; + + if( NewEvent2 == nullptr ) { + if( false == asEventall2Name.empty() ) { + ErrorLog( "Bad event: event \"" + asEventall2Name + "\" assigned to track \"" + pMyNode->asName + "\" does not exist" ); + bError = true; + } } - if (!evEventall2) - { - if (NewEvent2) - { - evEventall2 = NewEvent2; + else { + if( evEventall2 == nullptr ) { + evEventall2 = NewEvent0; asEventall2Name = ""; iEvents |= 32; // sumaryczna informacja o eventach } - else - { - if (!asEvent0Name.empty()) - { // Ra: tylko w logu informacja - WriteLog("Eventall2 \"" + asEventall2Name + - "\" does not exist"); - bError = true; - } + else { + ErrorLog( "Bad track: event \"" + NewEvent2->asName + "\" cannot be assigned to track, track already has one" ); + bError = true; } } - else - { - Error("Eventall2 cannot be assigned to track, track already has one"); - bError = true; - } - return !bError; + + return ( bError == false ); } bool TTrack::AssignForcedEvents(TEvent *NewEventPlus, TEvent *NewEventMinus) @@ -1079,8 +1061,10 @@ bool TTrack::InMovement() if (!SwitchExtension->CurrentIndex) return false; // 0=zablokowana się nie animuje // trzeba każdorazowo porównywać z kątem modelu - TAnimContainer *ac = - SwitchExtension->pModel ? SwitchExtension->pModel->GetContainer(NULL) : NULL; + TAnimContainer *ac = ( + SwitchExtension->pModel ? + SwitchExtension->pModel->GetContainer() : + nullptr ); return ac ? (ac->AngleGet() != SwitchExtension->fOffset) || !(ac->TransGet() == SwitchExtension->vTrans) : @@ -1090,10 +1074,7 @@ bool TTrack::InMovement() } return false; }; -void TTrack::RaAssign(TGroundNode *gn, TAnimContainer *ac){ - // Ra: wiązanie toru z modelem obrotnicy - // if (eType==tt_Table) SwitchExtension->pAnim=p; -}; + void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined) { // Ra: wiązanie toru z modelem obrotnicy if (eType == tt_Table) @@ -1104,8 +1085,8 @@ void TTrack::RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joi SwitchExtension->evPlus = joined; // event potwierdzenia połączenia (gdy nie znajdzie, to się nie połączy) if (am) - if (am->GetContainer(NULL)) // może nie być? - am->GetContainer(NULL)->EventAssign(done); // zdarzenie zakończenia animacji + if (am->GetContainer()) // może nie być? + am->GetContainer()->EventAssign(done); // zdarzenie zakończenia animacji } }; @@ -2172,9 +2153,10 @@ TTrack * TTrack::RaAnimate() SwitchExtension->CurrentIndex) // 0=zablokowana się nie animuje { // trzeba każdorazowo porównywać z kątem modelu // //pobranie kąta z modelu - TAnimContainer *ac = SwitchExtension->pModel ? - SwitchExtension->pModel->GetContainer(NULL) : - NULL; // pobranie głównego submodelu + TAnimContainer *ac = ( + SwitchExtension->pModel ? + SwitchExtension->pModel->GetContainer() : // pobranie głównego submodelu + nullptr ); if (ac) if ((ac->AngleGet() != SwitchExtension->fOffset) || !(ac->TransGet() == diff --git a/Track.h b/Track.h index 7b791a05..af635859 100644 --- a/Track.h +++ b/Track.h @@ -230,7 +230,6 @@ public: if (SwitchExtension) SwitchExtension->pOwner = o; }; bool InMovement(); // czy w trakcie animacji? - void RaAssign(TGroundNode *gn, TAnimContainer *ac); void RaAssign(TGroundNode *gn, TAnimModel *am, TEvent *done, TEvent *joined); void RaAnimListAdd(TTrack *t); TTrack * RaAnimate(); diff --git a/Train.cpp b/Train.cpp index 5a1e2671..61ca575a 100644 --- a/Train.cpp +++ b/Train.cpp @@ -264,6 +264,7 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::hornlowactivate, &TTrain::OnCommand_hornlowactivate }, { user_command::hornhighactivate, &TTrain::OnCommand_hornhighactivate }, { user_command::radiotoggle, &TTrain::OnCommand_radiotoggle }, + { user_command::radiostoptest, &TTrain::OnCommand_radiostoptest }, { user_command::generictoggle0, &TTrain::OnCommand_generictoggle }, { user_command::generictoggle1, &TTrain::OnCommand_generictoggle }, { user_command::generictoggle2, &TTrain::OnCommand_generictoggle }, @@ -905,7 +906,7 @@ void TTrain::OnCommand_trainbrakeemergency( TTrain *Train, command_data const &C Train->mvOccupied->BrakeLevelSet( Train->mvOccupied->Handle->GetPos( bh_EB ) ); if( Train->mvOccupied->BrakeCtrlPosNo <= 0.1 ) { // hamulec bezpieczeństwa dla wagonów - Train->mvOccupied->EmergencyBrakeFlag = true; + Train->mvOccupied->RadioStopFlag = true; } } } @@ -2036,6 +2037,10 @@ void TTrain::OnCommand_headlighttoggleleft( TTrain *Train, command_data const &C Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_left; // visual feedback Train->ggLeftLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable marker light + if( Train->ggLeftEndLightButton.SubModel == nullptr ) { + Train->DynamicObject->iLights[ lightsindex ] &= ~TMoverParameters::light::redmarker_left; + } } else { //turn off @@ -2065,6 +2070,10 @@ void TTrain::OnCommand_headlighttoggleright( TTrain *Train, command_data const & Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::headlight_right; // visual feedback Train->ggRightLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable marker light + if( Train->ggRightEndLightButton.SubModel == nullptr ) { + Train->DynamicObject->iLights[ lightsindex ] &= ~TMoverParameters::light::redmarker_right; + } } else { //turn off @@ -2122,13 +2131,29 @@ void TTrain::OnCommand_redmarkertoggleleft( TTrain *Train, command_data const &C // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback - Train->ggLeftEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( Train->ggLeftEndLightButton.SubModel != nullptr ) { + Train->ggLeftEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggLeftLightButton.UpdateValue( -1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable the headlight + Train->DynamicObject->iLights[ lightsindex ] &= ~TMoverParameters::light::headlight_left; + } } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_left; // visual feedback - Train->ggLeftEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + if( Train->ggLeftEndLightButton.SubModel != nullptr ) { + Train->ggLeftEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggLeftLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } } } } @@ -2151,13 +2176,29 @@ void TTrain::OnCommand_redmarkertoggleright( TTrain *Train, command_data const & // turn on Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback - Train->ggRightEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + if( Train->ggRightEndLightButton.SubModel != nullptr ) { + Train->ggRightEndLightButton.UpdateValue( 1.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggRightLightButton.UpdateValue( -1.0, Train->dsbSwitch ); + // if the light is controlled by 3-way switch, disable the headlight + Train->DynamicObject->iLights[ lightsindex ] &= ~TMoverParameters::light::headlight_right; + } } else { //turn off Train->DynamicObject->iLights[ lightsindex ] ^= TMoverParameters::light::redmarker_right; // visual feedback - Train->ggRightEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + if( Train->ggRightEndLightButton.SubModel != nullptr ) { + Train->ggRightEndLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } + else { + // we interpret lack of dedicated switch as a sign the light is controlled with 3-way switch + // this is crude, but for now will do + Train->ggRightLightButton.UpdateValue( 0.0, Train->dsbSwitch ); + } } } } @@ -2731,14 +2772,21 @@ void TTrain::OnCommand_radiotoggle( TTrain *Train, command_data const &Command ) } } +void TTrain::OnCommand_radiostoptest( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + Train->Dynamic()->RadioStop(); + } +} + void TTrain::OnKeyDown(int cKey) { // naciśnięcie klawisza - bool isEztOer; - isEztOer = ((mvControlled->TrainType == dt_EZT) && (mvControlled->Battery == true) && - (mvControlled->EpFuse == true) && (mvOccupied->BrakeSubsystem == ss_ESt) && - (mvControlled->ActiveDir != 0)); // od yB - // isEztOer=(mvControlled->TrainType==dt_EZT)&&(mvControlled->Mains)&&(mvOccupied->BrakeSubsystem==ss_ESt)&&(mvControlled->ActiveDir!=0); - // isEztOer=((mvControlled->TrainType==dt_EZT)&&(mvControlled->Battery==true)&&(mvControlled->EpFuse==true)&&(mvOccupied->BrakeSubsystem==Oerlikon)&&(mvControlled->ActiveDir!=0)); + bool const isEztOer = + ( ( mvControlled->TrainType == dt_EZT ) + && ( mvControlled->Battery == true ) + && ( mvControlled->EpFuse == true ) + && ( mvOccupied->BrakeSubsystem == ss_ESt ) + && ( mvControlled->ActiveDir != 0 ) ); // od yB if (Global::shiftState) { // wciśnięty [Shift] diff --git a/Train.h b/Train.h index 2b4b4595..e795650e 100644 --- a/Train.h +++ b/Train.h @@ -188,6 +188,7 @@ class TTrain static void OnCommand_hornlowactivate( TTrain *Train, command_data const &Command ); static void OnCommand_hornhighactivate( TTrain *Train, command_data const &Command ); static void OnCommand_radiotoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_radiostoptest( TTrain *Train, command_data const &Command ); static void OnCommand_generictoggle( TTrain *Train, command_data const &Command ); // members diff --git a/command.cpp b/command.cpp index f297c6be..d2bd0fca 100644 --- a/command.cpp +++ b/command.cpp @@ -62,6 +62,7 @@ commanddescription_sequence Commands_descriptions = { { "hornlowactivate", command_target::vehicle }, { "hornhighactivate", command_target::vehicle }, { "radiotoggle", command_target::vehicle }, + { "radiostoptest", command_target::vehicle }, /* const int k_FailedEngineCutOff = 35; */ @@ -118,10 +119,6 @@ const int k_ProgramHelp = 48; { "interiorlightdimtoggle", command_target::vehicle }, { "instrumentlighttoggle", command_target::vehicle }, /* -const int k_Univ1 = 66; -const int k_Univ2 = 67; -const int k_Univ3 = 68; -const int k_Univ4 = 69; const int k_EndSign = 70; const int k_Active = 71; */ diff --git a/command.h b/command.h index 239b145e..0b2c4ba4 100644 --- a/command.h +++ b/command.h @@ -57,6 +57,7 @@ enum class user_command { hornlowactivate, hornhighactivate, radiotoggle, + radiostoptest, /* const int k_FailedEngineCutOff = 35; */ diff --git a/keyboardinput.cpp b/keyboardinput.cpp index 959d3648..7db76e4e 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -250,6 +250,8 @@ keyboard_input::default_bindings() { { GLFW_KEY_A | keymodifier::shift }, // radiotoggle { GLFW_KEY_R | keymodifier::control }, + // radiostoptest + { GLFW_KEY_R | keymodifier::shift | keymodifier::control }, // viewturn { -1 }, // movevector diff --git a/parser.cpp b/parser.cpp index c7bbebd5..465b1d7b 100644 --- a/parser.cpp +++ b/parser.cpp @@ -21,32 +21,32 @@ http://mozilla.org/MPL/2.0/. // cParser -- generic class for parsing text data. // constructors -cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction ) -{ - LoadTraction = Loadtraction; +cParser::cParser( std::string const &Stream, buffertype const Type, std::string Path, bool const Loadtraction ) : + mPath(Path), + LoadTraction( Loadtraction ) { // build comments map mComments.insert(commentmap::value_type("/*", "*/")); mComments.insert(commentmap::value_type("//", "\n")); // mComments.insert(commentmap::value_type("--","\n")); //Ra: to chyba nie używane // store to calculate sub-sequent includes from relative path - mPath = Path; if( Type == buffertype::buffer_FILE ) { mFile = Stream; } // reset pointers and attach proper type of buffer - switch (Type) - { - case buffer_FILE: - Path.append(Stream); - mStream = new std::ifstream(Path.c_str()); - break; - case buffer_TEXT: - mStream = new std::istringstream(Stream); - break; - default: - mStream = NULL; + switch (Type) { + case buffer_FILE: { + Path.append( Stream ); + mStream = std::make_shared( Path ); + break; + } + case buffer_TEXT: { + mStream = std::make_shared( Stream ); + break; + } + default: { + break; + } } - mIncludeParser = NULL; // calculate stream size if (mStream) { @@ -56,19 +56,14 @@ cParser::cParser( std::string const &Stream, buffertype const Type, std::string else { mSize = mStream->rdbuf()->pubseekoff( 0, std::ios_base::end ); mStream->rdbuf()->pubseekoff( 0, std::ios_base::beg ); + mLine = 1; } } - else - mSize = 0; } // destructor -cParser::~cParser() -{ - if (mIncludeParser) - delete mIncludeParser; - if (mStream) - delete mStream; +cParser::~cParser() { + mComments.clear(); } @@ -157,7 +152,7 @@ std::string cParser::readToken(bool ToLower, const char *Break) // see if there's include parsing going on. clean up when it's done. if (mIncludeParser) { - token = (*mIncludeParser).readToken(ToLower, Break); + token = mIncludeParser->readToken(ToLower, Break); if (!token.empty()) { pos = token.find("(p"); @@ -182,13 +177,12 @@ std::string cParser::readToken(bool ToLower, const char *Break) } else { - delete mIncludeParser; mIncludeParser = NULL; parameters.clear(); } } // get the token yourself if there's no child to delegate it to. - char c; + char c { 0 }; do { while (mStream->peek() != EOF && strchr(Break, c = mStream->get()) == NULL) @@ -201,6 +195,10 @@ std::string cParser::readToken(bool ToLower, const char *Break) if (trimComments(token)) // don't glue together words separated with comment break; } + if( c == '\n' ) { + // update line counter + ++mLine; + } } while (token == "" && mStream->peek() != EOF); // double check to deal with trailing spaces // launch child parser if include directive found. // NOTE: parameter collecting uses default set of token separators. @@ -218,16 +216,18 @@ std::string cParser::readToken(bool ToLower, const char *Break) && (parameter.compare("end") != 0) ) { parameters.push_back(parameter); - parameter = readToken(ToLower); + parameter = readToken(false); } // if (trtest2.find("tr/")!=0) - mIncludeParser = new cParser(includefile, buffer_FILE, mPath, LoadTraction); + mIncludeParser = std::make_shared(includefile, buffer_FILE, mPath, LoadTraction); if (mIncludeParser->mSize <= 0) ErrorLog("Missed include: " + includefile); } - else - while (token.compare("end") != 0) - token = readToken(ToLower); + else { + while( token.compare( "end" ) != 0 ) { + token = readToken( true ); // minimize risk of case mismatch on comparison + } + } token = readToken(ToLower, Break); } return token; @@ -235,8 +235,12 @@ std::string cParser::readToken(bool ToLower, const char *Break) std::string cParser::readQuotes(char const Quote) { // read the stream until specified char or stream end std::string token = ""; - char c; + char c { 0 }; while( mStream->peek() != EOF && Quote != (c = mStream->get()) ) { // get all chars until the quote mark + if( c == '\n' ) { + // update line counter + ++mLine; + } token += c; } return token; @@ -244,9 +248,16 @@ std::string cParser::readQuotes(char const Quote) { // read the stream until spe void cParser::skipComment( std::string const &Endmark ) { // pobieranie znaków aż do znalezienia znacznika końca std::string input = ""; + char c { 0 }; auto const endmarksize = Endmark.size(); - while( mStream->peek() != EOF ) { // o ile nie koniec pliku - input += mStream->get(); // pobranie znaku + while( mStream->peek() != EOF ) { + // o ile nie koniec pliku + c = mStream->get(); // pobranie znaku + if( c == '\n' ) { + // update line counter + ++mLine; + } + input += c; if( input.find( Endmark ) != std::string::npos ) // szukanie znacznika końca break; if( input.size() >= endmarksize ) { @@ -302,7 +313,7 @@ std::size_t cParser::countTokens( std::string const &Stream, std::string Path ) std::size_t cParser::count() { std::string token; - size_t count{ 0 }; + size_t count { 0 }; do { token = ""; token = readToken( false ); @@ -319,8 +330,16 @@ void cParser::addCommentStyle( std::string const &Commentstart, std::string cons // returns name of currently open file, or empty string for text type stream std::string -cParser::Name() { +cParser::Name() const { if( mIncludeParser ) { return mIncludeParser->Name(); } else { return mPath + mFile; } } + +// returns number of currently processed line +std::size_t +cParser::Line() const { + + if( mIncludeParser ) { return mIncludeParser->Line(); } + else { return mLine; } +} diff --git a/parser.h b/parser.h index 982959ef..5709d16c 100644 --- a/parser.h +++ b/parser.h @@ -78,7 +78,9 @@ class cParser //: public std::stringstream // add custom definition of text which should be ignored when retrieving tokens void addCommentStyle( std::string const &Commentstart, std::string const &Commentend ); // returns name of currently open file, or empty string for text type stream - std::string Name(); + std::string Name() const; + // returns number of currently processed line + std::size_t Line() const; private: // methods: @@ -90,13 +92,14 @@ class cParser //: public std::stringstream std::size_t count(); // members: bool LoadTraction; // load traction? - std::istream *mStream; // relevant kind of buffer is attached on creation. + std::shared_ptr mStream; // relevant kind of buffer is attached on creation. std::string mFile; // name of the open file, if any std::string mPath; // path to open stream, for relative path lookups. - std::streamoff mSize; // size of open stream, for progress report. + std::streamoff mSize { 0 }; // size of open stream, for progress report. + std::size_t mLine { 0 }; // currently processed line typedef std::map commentmap; commentmap mComments; - cParser *mIncludeParser; // child class to handle include directives. + std::shared_ptr mIncludeParser; // child class to handle include directives. std::vector parameters; // parameter list for included file. std::deque tokens; }; diff --git a/version.h b/version.h index 7525fac4..1334935a 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 17 -#define VERSION_MINOR 828 -#define VERSION_REVISION 0 +#define VERSION_MINOR 829 +#define VERSION_REVISION 1