diff --git a/Driver.cpp b/Driver.cpp index 5b88f354..c5d51c01 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -189,36 +189,45 @@ bool TSpeedPos::Update(vector3 *p, vector3 *dir, double &len) { // przeliczenie odległości od punktu (*p), w kierunku (*dir), zaczynając od pojazdu // dla kolejnych pozycji podawane są współrzędne poprzedniego obiektu w (*p) vector3 v = vPos - *p; // wektor od poprzedniego obiektu (albo pojazdu) do punktu zmiany - fDist = - v.Length(); // długość wektora to odległość pomiędzy czołem a sygnałem albo początkiem toru - // v.SafeNormalize(); //normalizacja w celu określenia znaku (nie potrzebna?) + fDist = v.Length(); // długość wektora to odległość pomiędzy czołem a sygnałem albo początkiem toru if (len == 0.0) { // jeżeli liczymy względem pojazdu - double iska = dir ? dir->x * v.x + dir->z * v.z : - fDist; // iloczyn skalarny to rzut na chwilową prostą ruchu - if (iska < 0.0) // iloczyn skalarny jest ujemny, gdy punkt jest z tyłu + double angle; + if( dir ) { + angle = + glm::dot( + glm::normalize( glm::make_vec3( &v.x ) ), // towards target + glm::normalize( glm::make_vec3( &dir->x ) ) ); // orientation at scan point + } + else { + angle = fDist; + } + if (angle < 0.0) // iloczyn skalarny jest ujemny, gdy punkt jest z tyłu { // jeśli coś jest z tyłu, to dokładna odległość nie ma już większego znaczenia fDist = -fDist; // potrzebne do badania wyjechania składem poza ograniczenie - if (iFlags & spElapsed) // 32 ustawione, gdy obiekt już został minięty - { // jeśli minięty (musi być minięty również przez końcówkę składu) + if (iFlags & spElapsed) { + // jeśli minięty (musi być minięty również przez końcówkę składu) + // NOTE: empty branch, why? } else { - iFlags ^= spElapsed; // 32-minięty - będziemy liczyć odległość względem przeciwnego końca + // minięty - będziemy liczyć odległość względem przeciwnego końca // toru (nadal może być z przodu i ograniczać) - if ((iFlags & 0x43) == 3) // tylko jeśli (istotny) tor, bo eventy są punktowe - if (trTrack) // może być NULL, jeśli koniec toru (????) + iFlags ^= spElapsed; + if ((iFlags & (spEnd | spTrack | spEnabled)) == (spTrack | spEnabled)) { + // tylko jeśli (istotny) tor, bo eventy są punktowe + if (trTrack) { + // może być NULL, jeśli koniec toru (????) vPos = (iFlags & spReverse) ? trTrack->CurrentSegment()->FastGetPoint_0() : trTrack->CurrentSegment()->FastGetPoint_1(); // drugi koniec istotny + } + } } } - else if (fDist < 50.0) // przy dużym kącie łuku iloczyn skalarny bardziej zaniży odległość - // niż cięciwa - fDist = iska; // ale przy małych odległościach rzut na chwilową prostą ruchu da - // dokładniejsze wartości } + if (fDist > 0.0) // nie może być 0.0, a przypadkiem mogło by się trafić i było by źle if ((iFlags & spElapsed) == 0) // 32 ustawione, gdy obiekt już został minięty { // jeśli obiekt nie został minięty, można od niego zliczać narastająco (inaczej może być @@ -297,7 +306,7 @@ std::string TSpeedPos::TableText() if (iFlags & spEnabled) { // o ile pozycja istotna return "Flags:" + to_hex_str(iFlags, 6) + ", Dist:" + to_string(fDist, 1, 6) + - ", Vel:" + (fVelNext == -1.0 ? " * " : to_string(static_cast(fVelNext), 0, 3)) + ", Name:" + GetName(); + ", Vel:" + (fVelNext == -1.0 ? " - " : to_string(static_cast(fVelNext), 0, 3)) + ", Name:" + GetName(); //if (iFlags & spTrack) // jeśli tor // return "Flags=#" + IntToHex(iFlags, 8) + ", Dist=" + FloatToStrF(fDist, ffFixed, 7, 1) + // ", Vel=" + AnsiString(fVelNext) + ", Track=" + trTrack->NameGet(); @@ -373,19 +382,22 @@ void TSpeedPos::Set(TTrack *track, double dist, int flag) } }; -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- //--------------------------------------------------------------------------- void TController::TableClear() { // wyczyszczenie tablicy +#ifdef EU07_USE_OLD_SPEEDTABLE iFirst = iLast = 0; - iTableDirection = 0; // nieznany for (int i = 0; i < iSpeedTableSize; ++i) // czyszczenie tabeli prędkości sSpeedTable[i].Clear(); - tLast = NULL; - fLastVel = -1; - eSignSkip = NULL; // nic nie pomijamy +#else + sSpeedTable.clear(); +#endif + iLast = -1; + iTableDirection = 0; // nieznany + tLast = nullptr; + fLastVel = -1.0; + eSignSkip = nullptr; // nic nie pomijamy }; TEvent * TController::CheckTrackEvent(double fDirection, TTrack *Track) @@ -401,17 +413,23 @@ TEvent * TController::CheckTrackEvent(double fDirection, TTrack *Track) bool TController::TableAddNew() { // zwiększenie użytej tabelki o jeden rekord - iLast = (iLast + 1) % iSpeedTableSize; +#ifdef EU07_USE_OLD_SPEEDTABLE + iLast = ( iLast + 1 ) % iSpeedTableSize; // TODO: jeszcze sprawdzić, czy się na iFirst nie nałoży // TODO: wstawić tu wywołanie odtykacza - teraz jest to w TableTraceRoute() // TODO: jeśli ostatnia pozycja zajęta, ustawiać dodatkowe flagi - teraz jest to w // TableTraceRoute() // TODO: przydało by się też posortować tabelkę wg odległości (ale nie w tym miejscu) +#else + sSpeedTable.emplace_back(); // add a new slot + iLast = sSpeedTable.size() - 1; +#endif return true; // false gdy się nałoży }; -bool TController::TableNotFound(TEvent *e) +bool TController::TableNotFound(TEvent const *Event) const { // sprawdzenie, czy nie został już dodany do tabelki (np. podwójne W4 robi problemy) +#ifdef EU07_USE_OLD_SPEEDTABLE int j = (iLast + 1) % iSpeedTableSize; // j, aby sprawdzić też ostatnią pozycję for (int i = iFirst; i != j; i = (i + 1) % iSpeedTableSize) if ((sSpeedTable[i].iFlags & (spEnabled | spEvent)) == (spEnabled | @@ -423,42 +441,59 @@ bool TController::TableNotFound(TEvent *e) return false; // już jest, drugi raz dodawać nie ma po co } return true; // nie ma, czyli można dodać +#else + auto lookup = std::find_if( + sSpeedTable.begin(), + sSpeedTable.end(), + [Event]( TSpeedPos const &speedpoint ){ + return ( ( true == TestFlag( speedpoint.iFlags, spEnabled | spEvent ) ) + && ( speedpoint.evEvent == Event ) ); } ); + + if( ( Global::iWriteLogEnabled & 8 ) + && ( lookup != sSpeedTable.end() ) ) { + WriteLog( "Speed table for " + OwnerName() + " already contains event " + lookup->evEvent->asName ); + } + + return lookup == sSpeedTable.end(); +#endif }; void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) { // skanowanie trajektorii na odległość (fDistance) od (pVehicle) w kierunku przodu składu i // uzupełnianie tabelki // WriteLog("Starting TableTraceRoute"); - if (!iDirection) // kierunek pojazdu z napędem - { // jeśli kierunek jazdy nie jest okreslony - iTableDirection = 0; // czekamy na ustawienie kierunku - } - TTrack *pTrack; // zaczynamy od ostatniego analizowanego toru - // double fDistChVel=-1; //odległość do toru ze zmianą prędkości - double fTrackLength; // długość aktualnego toru (krótsza dla pierwszego) - double fCurrentDistance; // aktualna przeskanowana długość - TEvent *pEvent; - double fLastDir; // kierunek na ostatnim torze - if (iTableDirection != iDirection) - { // jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem + + TTrack *pTrack{ nullptr }; // zaczynamy od ostatniego analizowanego toru + double fTrackLength{ 0.0 }; // długość aktualnego toru (krótsza dla pierwszego) + double fCurrentDistance{ 0.0 }; // aktualna przeskanowana długość + TEvent *pEvent{ nullptr }; + double fLastDir{ 0.0 }; + + if (iTableDirection != iDirection) { + // jeśli zmiana kierunku, zaczynamy od toru ze wskazanym pojazdem + iTableDirection = iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu pTrack = pVehicle->RaTrackGet(); // odcinek, na którym stoi - fLastDir = pVehicle->DirectionGet() * - pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze - fCurrentDistance = 0; // na razie nic nie przeskanowano fTrackLength = pVehicle->RaTranslationGet(); // pozycja na tym torze (odległość od Point1) - if (fLastDir > 0) // jeśli w kierunku Point2 toru - fTrackLength = - pTrack->Length() - fTrackLength; // przeskanowana zostanie odległość do Point2 + fLastDir = pVehicle->DirectionGet() * pVehicle->RaDirectionGet(); // ustalenie kierunku skanowania na torze + if( fLastDir > 0.0 ) { + // jeśli w kierunku Point2 toru + fTrackLength = pTrack->Length() - fTrackLength; // przeskanowana zostanie odległość do Point2 + } fLastVel = pTrack->VelocityGet(); // aktualna prędkość - iTableDirection = - iDirection; // ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu +#ifdef EU07_USE_OLD_SPEEDTABLE iFirst = iLast = 0; - tLast = NULL; //żaden nie sprawdzony +#endif + sSpeedTable.clear(); + iLast = -1; + tLast = nullptr; //żaden nie sprawdzony + SemNextIndex = -1; + SemNextStopIndex = -1; } - else - { // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) + else { + // kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor) // WriteLog("TableTraceRoute: check last track"); - if (sSpeedTable[iLast].iFlags & spEndOfTable) // zatkanie +#ifdef EU07_USE_OLD_SPEEDTABLE + if( sSpeedTable[ iLast ].iFlags & spEndOfTable ) // zatkanie { // jeśli zapełniła się tabelka if ((iLast + 1) % iSpeedTableSize == iFirst) // jeśli nadal jest zapełniona { @@ -474,22 +509,38 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) } sSpeedTable[iLast].iFlags &= 0xBE; // kontynuować próby doskanowania } - // znaleziono semafor lub tarczę lub tor z prędkością zero - // trzeba sprawdzić czy to nadał semafor - // WriteLog("TableTraceRoute: "+OwnerName()+" check semaphor... "); - // if (sSemNext) - // WriteLog(sSemNext->TableText()); - if (sSemNextStop && - sSemNextStop->fVelNext == - 0.0) // jeśli jest następny semafor to sprawdzamy czy to on nadał zero - { - // WriteLog("TableTraceRoute: "+sSemNext->TableText()); - if ((OrderCurrentGet() & Obey_train) && (sSemNextStop->iFlags & spSemaphor)) - return; - else if ((OrderCurrentGet() < 0x40) && - (sSemNextStop->iFlags & (spSemaphor | spShuntSemaphor | spOutsideStation))) +#endif + // znaleziono semafor lub tarczę lub tor z prędkością zero, trzeba sprawdzić czy to nadał semafor +#ifdef EU07_USE_OLD_SPEEDTABLE + if( ( sSemNextStop != nullptr ) + && ( sSemNextStop->fVelNext < 1.0 ) ) { +#else + if( ( SemNextStopIndex != -1 ) + && ( sSpeedTable[SemNextStopIndex].fVelNext < 1.0 ) ) { +#endif + // jeśli jest następny semafor to sprawdzamy czy to on nadał zero +#ifdef EU07_USE_OLD_SPEEDTABLE + if( ( OrderCurrentGet() & Obey_train ) + && ( sSemNextStop->iFlags & spSemaphor ) ) { +#else + if( ( OrderCurrentGet() & Obey_train ) + && ( sSpeedTable[SemNextStopIndex].iFlags & spSemaphor ) ) { +#endif return; + } + else { +#ifdef EU07_USE_OLD_SPEEDTABLE + if( ( OrderCurrentGet() < 0x40 ) + && ( sSemNextStop->iFlags & ( spSemaphor | spShuntSemaphor | spOutsideStation ) ) ) { +#else + if( ( OrderCurrentGet() < 0x40 ) + && ( sSpeedTable[SemNextStopIndex].iFlags & ( spSemaphor | spShuntSemaphor | spOutsideStation ) ) ) { +#endif + return; + } + } } +#ifdef EU07_USE_OLD_SPEEDTABLE pTrack = sSpeedTable[iLast].trTrack; // ostatnio sprawdzony tor if (!pTrack) return; // koniec toru, to nie ma co sprawdzać (nie ma prawa tak być) @@ -498,289 +549,339 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) fTrackLength = (sSpeedTable[iLast].iFlags & (spElapsed | spEnd)) ? 0.0 : pTrack->Length(); // nie dolicza� d�ugo�ci gdy: // 32-minięty początek, // 64-jazda do końca toru +#else + auto const &lastspeedpoint = sSpeedTable[ iLast ]; + pTrack = lastspeedpoint.trTrack; + assert( pTrack != nullptr ); + // flaga ustawiona, gdy Point2 toru jest blizej + fLastDir = ( + TestFlag( lastspeedpoint.iFlags, spReverse ) ? + -1.0 : + 1.0 ); + // aktualna odleglosc do jego Point1 + fCurrentDistance = lastspeedpoint.fDist; + // nie doliczac dlugosci gdy: miniety początek lub jazda do konca toru + fTrackLength = ( + ( lastspeedpoint.iFlags & ( spElapsed | spEnd ) != 0 ) ? + 0.0 : + pTrack->Length() ); +#endif } - if (fCurrentDistance < fDistance) - { // jeśli w ogóle jest po co analizować - // WriteLog("TableTraceRoute: checking next tracks"); - --iLast; // jak coś się znajdzie, zostanie wpisane w tę pozycję, którą właśnie odczytano - while (fCurrentDistance < fDistance) - { - if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony - { // jeśli tor nie był jeszcze sprawdzany - // if (pTrack) - // WriteLog("TableTraceRoute: " + OwnerName() + " checking track " + - // pTrack->NameGet()); - if ((pEvent = CheckTrackEvent(fLastDir, pTrack)) != - NULL) // jeśli jest semafor na tym torze - { // trzeba sprawdzić tabelkę, bo dodawanie drugi raz tego samego przystanku nie - // jest korzystne - if (TableNotFound(pEvent)) // jeśli nie ma - if (TableAddNew()) + + if( fCurrentDistance >= fDistance ) { + // all done + return; + } + +#ifdef EU07_USE_OLD_SPEEDTABLE + // jak coś się znajdzie, zostanie wpisane w tę pozycję, którą właśnie odczytano + --iLast; +#endif + + while (fCurrentDistance < fDistance) + { + if (pTrack != tLast) // ostatni zapisany w tabelce nie był jeszcze sprawdzony + { // jeśli tor nie był jeszcze sprawdzany + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table for " + OwnerName() + " tracing through track " + pTrack->NameGet() ); + } + + if( ( pEvent = CheckTrackEvent( fLastDir, pTrack ) ) != nullptr ) // jeśli jest semafor na tym torze + { // trzeba sprawdzić tabelkę, bo dodawanie drugi raz tego samego przystanku nie jest korzystne + if (TableNotFound(pEvent)) // jeśli nie ma + if( TableAddNew() ) + { + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table for " + OwnerName() + " found new event, " + pEvent->asName ); + } +#ifdef EU07_USE_OLD_SPEEDTABLE + if( sSpeedTable[ iLast ].Set( pEvent, fCurrentDistance, OrderCurrentGet() ) ) // dodanie odczytu sygnału { + fDistance = fCurrentDistance; // jeśli sygnał stop, to nie ma + // potrzeby dalej skanować + sSemNextStop = &sSpeedTable[iLast]; + if (!sSemNext) + sSemNext = &sSpeedTable[iLast]; if (Global::iWriteLogEnabled & 8) - WriteLog("TableTraceRoute: new event found " + pEvent->asName + " by " + OwnerName()); - if (sSpeedTable[iLast].Set( pEvent, fCurrentDistance, OrderCurrentGet())) // dodanie odczytu sygnału + WriteLog("Signal stop. Next Semaphor ", false); + if (sSemNextStop) { - fDistance = fCurrentDistance; // jeśli sygnał stop, to nie ma - // potrzeby dalej skanować - sSemNextStop = &sSpeedTable[iLast]; - if (!sSemNext) - sSemNext = &sSpeedTable[iLast]; if (Global::iWriteLogEnabled & 8) - WriteLog("Signal stop. Next Semaphor ", false); - if (sSemNextStop) - { - if (Global::iWriteLogEnabled & 8) - WriteLog(sSemNextStop->GetName()); - } - else - { - if (Global::iWriteLogEnabled & 8) - WriteLog("none"); - } + WriteLog(sSemNextStop->GetName()); } else { - if (sSpeedTable[iLast].IsProperSemaphor(OrderCurrentGet()) && - sSemNext == NULL) - sSemNext = - &sSpeedTable[iLast]; // sprawdzamy czy pierwszy na drodze if (Global::iWriteLogEnabled & 8) - WriteLog("Signal forward. Next Semaphor ", false); - if (sSemNext) - { - if (Global::iWriteLogEnabled & 8) - WriteLog(sSemNext->GetName()); - } - else - { - if (Global::iWriteLogEnabled & 8) - WriteLog("none"); - } + WriteLog("none"); } } - } // event dodajemy najpierw, żeby móc sprawdzić, czy tor został dodany po - // odczytaniu prędkości następnego - if ((pTrack->VelocityGet() == 0.0) // zatrzymanie - || (pTrack->iAction) // jeśli tor ma własności istotne dla skanowania - || (pTrack->VelocityGet() != fLastVel)) // następuje zmiana prędkości - { // odcinek dodajemy do tabelki, gdy jest istotny dla ruchu - if (TableAddNew()) - { // teraz dodatkowo zapamiętanie wybranego segmentu dla skrzyżowania - sSpeedTable[iLast].Set( - pTrack, fCurrentDistance, - fLastDir < 0 ? - 5 : - 1); // dodanie odcinka do tabelki z flagą kierunku wejścia - if (pTrack->eType == tt_Cross) // na skrzyżowaniach trzeba wybrać segment, - // po którym pojedzie pojazd - { // dopiero tutaj jest ustalany kierunek segmentu na skrzyżowaniu - sSpeedTable[iLast].iFlags |= - (pTrack->CrossSegment((fLastDir < 0) ? tLast->iPrevDirection : - tLast->iNextDirection, - iRouteWanted) & - 15) - << 28; // ostatnie 4 bity pola flag - sSpeedTable[iLast].iFlags &= - ~spReverse; // usunięcie flagi kierunku, bo może być błędna - if (sSpeedTable[iLast].iFlags < 0) - sSpeedTable[iLast].iFlags |= - spReverse; // ustawienie flagi kierunku na podstawie wybranego segmentu - if (int(fLastDir) * sSpeedTable[iLast].iFlags < 0) - fLastDir = -fLastDir; - if (AIControllFlag) // dla AI na razie losujemy kierunek na kolejnym - // skrzyżowaniu - iRouteWanted = 1 + Random(3); + else { + if( sSpeedTable[ iLast ].IsProperSemaphor( OrderCurrentGet() ) && + sSemNext == NULL ) + sSemNext = + &sSpeedTable[ iLast ]; // sprawdzamy czy pierwszy na drodze + if( Global::iWriteLogEnabled & 8 ) + WriteLog( "Signal forward. Next Semaphor ", false ); + if( sSemNext ) { + if( Global::iWriteLogEnabled & 8 ) + WriteLog( sSemNext->GetName() ); + } + else { + if( Global::iWriteLogEnabled & 8 ) + WriteLog( "none" ); + } + } +#else + auto &newspeedpoint = sSpeedTable[ iLast ]; + if( newspeedpoint.Set( pEvent, fCurrentDistance, OrderCurrentGet() ) ) { + + fDistance = fCurrentDistance; // jeśli sygnał stop, to nie ma potrzeby dalej skanować +#ifdef EU07_USE_OLD_SPEEDTABLE + sSemNextStop = &newspeedpoint; + if( sSemNext == nullptr ) { + sSemNext = &newspeedpoint; + } + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "(stop signal from " + + ( sSemNextStop ? sSemNextStop->GetName() : "unknown semaphor" ) + + ")" ); + } +#else + SemNextStopIndex = iLast; + if( SemNextIndex == -1 ) { + SemNextIndex = iLast; + } + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "(stop signal from " + + ( SemNextStopIndex != -1 ? sSpeedTable[SemNextStopIndex].GetName() : "unknown semaphor" ) + + ")" ); + } +#endif + } + else { +#ifdef EU07_USE_OLD_SPEEDTABLE + if( ( true == newspeedpoint.IsProperSemaphor( OrderCurrentGet() ) ) + && ( sSemNext == nullptr ) ) { + sSemNext = &newspeedpoint; // sprawdzamy czy pierwszy na drodze + } + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "(forward signal for " + + ( sSemNext ? sSemNext->GetName() : "unknown semaphor" ) + + ")" ); + } +#else + if( ( true == newspeedpoint.IsProperSemaphor( OrderCurrentGet() ) ) + && ( SemNextIndex == -1 ) ) { + SemNextIndex = iLast; // sprawdzamy czy pierwszy na drodze + } + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "(forward signal for " + + ( SemNextIndex != -1 ? sSpeedTable[SemNextIndex].GetName() : "unknown semaphor" ) + + ")" ); + } +#endif + } +#endif + } + } // event dodajemy najpierw, żeby móc sprawdzić, czy tor został dodany po odczytaniu prędkości następnego + + if ((pTrack->VelocityGet() == 0.0) // zatrzymanie + || (pTrack->iAction) // jeśli tor ma własności istotne dla skanowania + || (pTrack->VelocityGet() != fLastVel)) // następuje zmiana prędkości + { // odcinek dodajemy do tabelki, gdy jest istotny dla ruchu + if (TableAddNew()) + { // teraz dodatkowo zapamiętanie wybranego segmentu dla skrzyżowania + sSpeedTable[ iLast ].Set( + pTrack, fCurrentDistance, + ( fLastDir < 0 ? + spEnabled | spReverse : + spEnabled ) ); // dodanie odcinka do tabelki z flagą kierunku wejścia + if (pTrack->eType == tt_Cross) { + // na skrzyżowaniach trzeba wybrać segment, po którym pojedzie pojazd + // dopiero tutaj jest ustalany kierunek segmentu na skrzyżowaniu + sSpeedTable[iLast].iFlags |= + ( ( pTrack->CrossSegment( + ( fLastDir < 0 ? + tLast->iPrevDirection : + tLast->iNextDirection ), + iRouteWanted ) & 0xf ) << 28 ); // ostatnie 4 bity pola flag + sSpeedTable[iLast].iFlags &= ~spReverse; // usunięcie flagi kierunku, bo może być błędna + if( sSpeedTable[ iLast ].iFlags < 0 ) { + sSpeedTable[ iLast ].iFlags |= spReverse; // ustawienie flagi kierunku na podstawie wybranego segmentu + } + if( int( fLastDir ) * sSpeedTable[ iLast ].iFlags < 0 ) { + fLastDir = -fLastDir; + } + if( AIControllFlag ) { + // dla AI na razie losujemy kierunek na kolejnym skrzyżowaniu + iRouteWanted = 1 + Random( 3 ); } } } - else if ((pTrack->fRadius != 0.0) // odległość na łuku lepiej aproksymować cięciwami - || (tLast ? tLast->fRadius != 0.0 : false)) // koniec łuku też jest istotny - { // albo dla liczenia odległości przy pomocy cięciw - te usuwać po przejechaniu - if (TableAddNew()) - sSpeedTable[iLast].Set(pTrack, fCurrentDistance, - fLastDir < 0 ? 0x85 : - 0x81); // dodanie odcinka do tabelki - // 0x85 = spEnabled, spReverse, SpCurve + } + else if ( ( pTrack->fRadius != 0.0 ) // odległość na łuku lepiej aproksymować cięciwami + || ( ( tLast != nullptr ) + && ( tLast->fRadius != 0.0 ) )) // koniec łuku też jest istotny + { // albo dla liczenia odległości przy pomocy cięciw - te usuwać po przejechaniu + if (TableAddNew()) + sSpeedTable[iLast].Set( + pTrack, fCurrentDistance, + ( fLastDir < 0 ? + spEnabled | spCurve | spReverse : + spEnabled | spCurve ) ); // dodanie odcinka do tabelki + } + } + + fCurrentDistance += fTrackLength; // doliczenie kolejnego odcinka do przeskanowanej długości + tLast = pTrack; // odhaczenie, że sprawdzony + fLastVel = pTrack->VelocityGet(); // prędkość na poprzednio sprawdzonym odcinku + pTrack = pTrack->Neightbour( + ( pTrack->eType == tt_Cross ? + (sSpeedTable[iLast].iFlags >> 28) : + static_cast(fLastDir) ), + fLastDir); // może być NULL + + if (pTrack != nullptr ) + { // jeśli kolejny istnieje + if( tLast != nullptr ) { + if( ( pTrack->VelocityGet() < 0 ? + tLast->VelocityGet() > 0 : + pTrack->VelocityGet() > tLast->VelocityGet() ) ) { + // jeśli kolejny ma większą prędkość niż poprzedni, to zapamiętać poprzedni (do czasu wyjechania) + if( ( ( ( iLast != -1 ) + && ( TestFlag( sSpeedTable[ iLast ].iFlags, spEnabled | spTrack ) ) ) ? + ( sSpeedTable[ iLast ].trTrack != tLast ) : + true ) ) { + // jeśli nie był dodany do tabelki + if( TableAddNew() ) { + // zapisanie toru z ograniczeniem prędkości + sSpeedTable[ iLast ].Set( + tLast, fCurrentDistance, + ( fLastDir > 0 ? + pTrack->iPrevDirection : + pTrack->iNextDirection ) ? + spEnabled : + spEnabled | spReverse ); + } + } } } - fCurrentDistance += - fTrackLength; // doliczenie kolejnego odcinka do przeskanowanej długości - tLast = pTrack; // odhaczenie, że sprawdzony - // Track->ScannedFlag=true; //do pokazywania przeskanowanych torów - fLastVel = pTrack->VelocityGet(); // prędkość na poprzednio sprawdzonym odcinku - pTrack = pTrack->Neightbour( - (pTrack->eType == tt_Cross) ? (sSpeedTable[iLast].iFlags >> 28) : int(fLastDir), - fLastDir); // może być NULL - /* - if (fLastDir>0) - {//jeśli szukanie od Point1 w kierunku Point2 - pTrack=pTrack->CurrentNext(); //może być NULL - if (pTrack) //jeśli dalej brakuje toru, to zostajemy na tym samym, z tą samą - orientacją - if (tLast->iNextDirection) - fLastDir=-fLastDir; //można by zamiętać i zmienić tylko jeśli jest pTrack - } - else //if (fDirection<0) - {//jeśli szukanie od Point2 w kierunku Point1 - pTrack=pTrack->CurrentPrev(); //może być NULL - if (pTrack) //jeśli dalej brakuje toru, to zostajemy na tym samym, z tą samą - orientacją - if (!tLast->iPrevDirection) - fLastDir=-fLastDir; - } - */ - if (pTrack) - { // jeśli kolejny istnieje - if (tLast) - if (pTrack->VelocityGet() < 0 ? tLast->VelocityGet() > 0 : - pTrack->VelocityGet() > tLast->VelocityGet()) - { // jeśli kolejny ma większą prędkość niż poprzedni, to zapamiętać poprzedni - // (do czasu wyjechania) - if ((sSpeedTable[iLast].iFlags & 3) == 3 ? - (sSpeedTable[iLast].trTrack != tLast) : - true) // jeśli nie był dodany do tabelki - if (TableAddNew()) - sSpeedTable[iLast].Set( - tLast, fCurrentDistance, - (fLastDir > 0 ? pTrack->iPrevDirection : - pTrack->iNextDirection) ? - 1 : - 5); // zapisanie toru z ograniczeniem prędkości - } +#ifdef EU07_USE_OLD_SPEEDTABLE + if( ( ( iLast + 3 ) % iSpeedTableSize == iFirst ) ? + true : + ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? + { // jest ryzyko nieznalezienia ograniczenia - ograniczyć prędkość do pozwalającej + // na zatrzymanie na końcu przeskanowanej drogi + TablePurger(); // usunąć pilnie zbędne pozycje if (((iLast + 3) % iSpeedTableSize == iFirst) ? true : ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? - { // jest ryzyko nieznalezienia ograniczenia - ograniczyć prędkość do pozwalającej - // na zatrzymanie na końcu przeskanowanej drogi - TablePurger(); // usunąć pilnie zbędne pozycje - if (((iLast + 3) % iSpeedTableSize == iFirst) ? - true : - ((iLast + 2) % iSpeedTableSize == iFirst)) // czy tabelka się nie zatka? - { // jeśli odtykacz nie pomógł (TODO: zwiększyć rozmiar tabelki) - if (TableAddNew()) - sSpeedTable[iLast].Set( - pTrack, fCurrentDistance, - fLastDir < 0 ? - 0x10045 : - 0x10041); // zapisanie toru jako końcowego (ogranicza prędkosć) - // zapisać w logu, że należy poprawić scenerię? - return; // nie skanujemy dalej, bo nie ma miejsca - } + { // jeśli odtykacz nie pomógł (TODO: zwiększyć rozmiar tabelki) + if (TableAddNew()) + sSpeedTable[iLast].Set( + pTrack, fCurrentDistance, + fLastDir < 0 ? + 0x10045 : + 0x10041); // zapisanie toru jako końcowego (ogranicza prędkosć) + // zapisać w logu, że należy poprawić scenerię? + return; // nie skanujemy dalej, bo nie ma miejsca } - fTrackLength = pTrack->Length(); // zwiększenie skanowanej odległości tylko jeśli - // istnieje dalszy tor } - else - { // definitywny koniec skanowania, chyba że dalej puszczamy samochód po gruncie... - if (TableAddNew()) // kolejny, bo się cofnęliśmy o 1 +#endif + // zwiększenie skanowanej odległości tylko jeśli istnieje dalszy tor + fTrackLength = pTrack->Length(); + } + else + { // definitywny koniec skanowania, chyba że dalej puszczamy samochód po gruncie... + if( ( iLast == -1 ) + || ( false == TestFlag( sSpeedTable[iLast].iFlags, spEnabled | spEnd ) ) ) { + // only if we haven't already marked end of the track + if( TableAddNew() ) sSpeedTable[iLast].Set( tLast, fCurrentDistance, - fLastDir < 0 ? 0x45 : 0x41); // zapisanie ostatniego sprawdzonego toru - return; // to ostatnia pozycja, bo NULL nic nie da, a może się podpiąć obrotnica, - // czy jakieś transportery + ( fLastDir < 0 ? + spEnabled | spEnd | spReverse : + spEnabled | spEnd )); // zapisanie ostatniego sprawdzonego toru } + // to ostatnia pozycja, bo NULL nic nie da, a może się podpiąć obrotnica, czy jakieś transportery + return; } - if (TableAddNew()) - sSpeedTable[iLast].Set(pTrack, fCurrentDistance, - fLastDir < 0 ? 4 : 0); // zapisanie ostatniego sprawdzonego toru + } + if( TableAddNew() ) { + // zapisanie ostatniego sprawdzonego toru + sSpeedTable[ iLast ].Set( + pTrack, fCurrentDistance, + ( fLastDir < 0 ? + spNone | spReverse : + spNone ) ); } }; void TController::TableCheck(double fDistance) { // przeliczenie odległości w tabelce, ewentualnie doskanowanie (bez analizy prędkości itp.) - if (iTableDirection != iDirection) - TableTraceRoute(fDistance, - pVehicles[1]); // jak zmiana kierunku, to skanujemy od końca składu + if( iTableDirection != iDirection ) { + // jak zmiana kierunku, to skanujemy od końca składu + TableTraceRoute( fDistance, pVehicles[ 1 ] ); + } else if (iTableDirection) { // trzeba sprawdzić, czy coś się zmieniło - vector3 dir = - pVehicles[0]->VectorFront() * pVehicles[0]->DirectionGet(); // wektor kierunku jazdy + vector3 dir = pVehicles[0]->VectorFront() * pVehicles[0]->DirectionGet(); // wektor kierunku jazdy vector3 pos = pVehicles[0]->HeadPosition(); // zaczynamy od pozycji pojazdu - // double lastspeed=-1; //prędkość na torze do usunięcia double len = 0.0; // odległość będziemy zliczać narastająco - for (int i = iFirst; i != iLast; i = (i + 1) % iSpeedTableSize) + for( int i = 0; i <= iLast; ++i ) { // aktualizacja rekordów z wyjątkiem ostatniego if (sSpeedTable[i].iFlags & spEnabled) // jeśli pozycja istotna { if (sSpeedTable[i].Update(&pos, &dir, len)) { - if (Global::iWriteLogEnabled & 8) - WriteLog("TableCheck: Switch change. Delete next entries. (" + sSpeedTable[i].trTrack->NameGet() + ")"); - int k = (iLast + 1) % iSpeedTableSize; // skanujemy razem z ostatnią pozycją - for (int j = (i+1) % iSpeedTableSize; j != k; j = (j + 1) % iSpeedTableSize) - { // kasowanie wszystkich rekordów za zmienioną zwrotnicą - if (Global::iWriteLogEnabled & 8) - WriteLog("TableCheck: Delete from table: " + sSpeedTable[j].GetName()); - sSpeedTable[j].iFlags = 0; - if (&sSpeedTable[j] == sSemNext) - sSemNext = NULL; // przy kasowaniu tabelki zrzucamy także semafor - if (&sSpeedTable[j] == sSemNextStop) - sSemNextStop = NULL; // przy kasowaniu tabelki zrzucamy także semafor + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table for " + OwnerName() + " detected switch change at " + sSpeedTable[ i ].trTrack->NameGet() + " (generating fresh trace)" ); } - if (Global::iWriteLogEnabled & 8) - { - WriteLog("TableCheck: Delete entries OK."); - WriteLog("TableCheck: New last element: " + sSpeedTable[i].GetName()); - } - iLast = i; // pokazujemy gdzie jest ostatni kawałek - break; // nie kontynuujemy pętli, trzeba doskanować ciąg dalszy + // NOTE: dirty trick to perform scan from the beginning + // a workaround for current routines not preserving properly scan distance if started from the middle + // and the scan extending far beyond specified limit as result + iTableDirection = -iDirection; + TableTraceRoute( fDistance, pVehicles[ 1 ] ); + // nie kontynuujemy pętli, trzeba doskanować ciąg dalszy + break; } if (sSpeedTable[i].iFlags & spTrack) // jeśli odcinek { if (sSpeedTable[i].fDist < -fLength) // a skład wyjechał całą długością poza { // degradacja pozycji - // WriteLog( "TableCheck: Track is behind. Delete from table: " + sSpeedTable[i].trTrack->NameGet()); sSpeedTable[i].iFlags &= ~spEnabled; // nie liczy się } - else if ((sSpeedTable[i].iFlags & 0xF0000028) == - spElapsed) // jest z tyłu (najechany) i nie jest zwrotnicą ani skrzyżowaniem - if (sSpeedTable[i].fVelNext < 0) // a nie ma ograniczenia prędkości + else if( ( sSpeedTable[ i ].iFlags & 0xF0000028 ) == spElapsed ) { + // jest z tyłu (najechany) i nie jest zwrotnicą ani skrzyżowaniem + if( sSpeedTable[ i ].fVelNext < 0 ) // a nie ma ograniczenia prędkości { - sSpeedTable[i].iFlags = - 0; // to nie ma go po co trzymać (odtykacz usunie ze środka) - // WriteLog("TableCheck: Track without speed. Delete from table: " + sSpeedTable[i].trTrack->NameGet()); + sSpeedTable[ i ].iFlags = 0; // to nie ma go po co trzymać (odtykacz usunie ze środka) } + } } else if (sSpeedTable[i].iFlags & spEvent) // jeśli event { - if (sSpeedTable[i].fDist < (sSpeedTable[i].evEvent->Type == tp_PutValues ? - -fLength : - 0)) // jeśli jest z tyłu + if (sSpeedTable[i].fDist < ( + sSpeedTable[i].evEvent->Type == tp_PutValues ? + -fLength : + 0)) // jeśli jest z tyłu if ((mvOccupied->CategoryFlag & 1) ? false : sSpeedTable[i].fDist < -fLength) - { // pociąg staje zawsze, a samochód tylko jeśli nie przejedzie całą - // długością (może być zaskoczony zmianą) + { // pociąg staje zawsze, a samochód tylko jeśli nie przejedzie całą długością (może być zaskoczony zmianą) // WriteLog("TableCheck: Event is behind. Delete from table: " + sSpeedTable[i].evEvent->asName); - sSpeedTable[i].iFlags &= ~1; // degradacja pozycji dla samochodu; - // semafory usuwane tylko przy sprawdzaniu, - // bo wysyłają komendy + sSpeedTable[i].iFlags &= ~spEnabled; // degradacja pozycji dla samochodu; + // semafory usuwane tylko przy sprawdzaniu, bo wysyłają komendy } } - // if (sSpeedTable[i].fDist<-20.0*fLength) //jeśli to coś jest 20 razy dalej niż - // długość składu - //{sSpeedTable[i].iFlags&=~1; //to jest to jakby błąd w scenerii - // //WriteLog("Error: too distant object in scan table"); - //} - // if (sSpeedTable[i].fDist>20.0*fLength) //jeśli to coś jest 20 razy dalej niż - // długość składu - //{sSpeedTable[i].iFlags&=~1; //to jest to jakby błąd w scenerii - // //WriteLog("Error: too distant object in scan table"); - //} - } - if (i == iFirst) // jeśli jest pierwszą pozycją tabeli - { // pozbycie się początkowej pozycji - if ((sSpeedTable[i].iFlags & 1) == - 0) // jeśli pozycja istotna (po Update() może się zmienić) - // if (iFirst!=iLast) //ostatnia musi zostać - to załatwia for() - iFirst = (iFirst + 1) % - iSpeedTableSize; // kolejne sprawdzanie będzie już od następnej pozycji } } sSpeedTable[iLast].Update(&pos, &dir, len); // aktualizacja ostatniego // WriteLog("TableCheck: Upate last track. Dist=" + AnsiString(sSpeedTable[iLast].fDist)); - if (sSpeedTable[iLast].fDist < fDistance) - TableTraceRoute(fDistance, pVehicles[1]); // doskanowanie dalszego odcinka + if( sSpeedTable[ iLast ].fDist < fDistance ) { + TableTraceRoute( fDistance, pVehicles[ 1 ] ); // doskanowanie dalszego odcinka + } + // garbage collection + TablePurger(); } }; @@ -796,12 +897,10 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN double d_to_next_sem = 10000.0; //ustaiwamy na pewno dalej niż widzi AI TCommandType go = cm_Unknown; eSignNext = NULL; - int i, k = iLast - iFirst + 1; - if (k < 0) - k += iSpeedTableSize; // ilość pozycji do przeanalizowania - iDrivigFlags &= ~(moveTrackEnd | moveSwitchFound | moveSemaphorFound | - moveSpeedLimitFound); // te flagi są ustawiane tutaj, w razie potrzeby - for (i = iFirst; k > 0; --k, i = (i + 1) % iSpeedTableSize) + // te flagi są ustawiane tutaj, w razie potrzeby + iDrivigFlags &= ~(moveTrackEnd | moveSwitchFound | moveSemaphorFound | moveSpeedLimitFound); + + for( std::size_t i = 0; i < sSpeedTable.size(); ++i ) { // sprawdzenie rekordów od (iFirst) do (iLast), o ile są istotne if (sSpeedTable[i].iFlags & spEnabled) // badanie istotności { // o ile dana pozycja tabelki jest istotna @@ -810,21 +909,20 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // first 19 chars of the command is expected to be "PassengerStopPoint:" so we skip them if ( ToLower(sSpeedTable[i].evEvent->CommandGet()).compare( 19, sizeof(asNextStop), ToLower(asNextStop)) != 0 ) { // jeśli nazwa nie jest zgodna - if (sSpeedTable[i].fDist < -fLength) // jeśli został przejechany - sSpeedTable[i].iFlags = - 0; // to można usunąć (nie mogą być usuwane w skanowaniu) + if( sSpeedTable[ i ].fDist < -fLength ) { + // jeśli został przejechany + sSpeedTable[ i ].iFlags = 0; // to można usunąć (nie mogą być usuwane w skanowaniu) + } continue; // ignorowanie jakby nie było tej pozycji } - else if (iDrivigFlags & - moveStopPoint) // jeśli pomijanie W4, to nie sprawdza czasu odjazdu + else if (iDrivigFlags & moveStopPoint) // jeśli pomijanie W4, to nie sprawdza czasu odjazdu { // tylko gdy nazwa zatrzymania się zgadza if (!TrainParams->IsStop()) { // jeśli nie ma tu postoju sSpeedTable[i].fVelNext = -1; // maksymalna prędkość w tym miejscu - if (sSpeedTable[i].fDist < - 200.0) // przy 160km/h jedzie 44m/s, to da dokładność rzędu 5 sekund - { // zaliczamy posterunek w pewnej odległości przed (choć W4 nie zasłania -// już semafora) + // przy 160km/h jedzie 44m/s, to da dokładność rzędu 5 sekund + if (sSpeedTable[i].fDist < 200.0) { + // zaliczamy posterunek w pewnej odległości przed (choć W4 nie zasłania już semafora) #if LOGSTOPS WriteLog( pVehicle->asName + " as " + TrainParams->TrainName @@ -879,56 +977,43 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN int p2 = int(floor(sSpeedTable[i].evEvent->ValueGet(2))) % 10; // p7=platform side (1:left, 2:right, 3:both) - int lewe = (iDirection > 0) ? 1 : 2; // jeśli jedzie do - // tyłu, to drzwi - // otwiera - // odwrotnie + int lewe = (iDirection > 0) ? 1 : 2; // jeśli jedzie do tyłu, to drzwi otwiera odwrotnie int prawe = (iDirection > 0) ? 2 : 1; if (p2 & lewe) mvOccupied->DoorLeft(true); if (p2 & prawe) mvOccupied->DoorRight(true); - // if (p2&3) //żeby jeszcze poczekał chwilę, zanim - // zamknie + // if (p2&3) //żeby jeszcze poczekał chwilę, zanim zamknie // WaitingSet(10); //10 sekund (wziąć z rozkładu????) } } else - { // otwieranie drzwi w składach wagonowych - docelowo wysyłać - // komendę zezwolenia na otwarcie drzwi - int p7, lewe, - prawe; // p7=platform side (1:left, 2:right, 3:both) - p7 = int(floor(sSpeedTable[i].evEvent->ValueGet(2))) % - 10; // tu będzie jeszcze długość peronu zaokrąglona do 10m + { // otwieranie drzwi w składach wagonowych - docelowo wysyłać komendę zezwolenia na otwarcie drzwi + int p7, lewe, prawe; // p7=platform side (1:left, 2:right, 3:both) + // tu będzie jeszcze długość peronu zaokrąglona do 10m // (20m bezpieczniej, bo nie modyfikuje bitu 1) + p7 = int(std::floor(sSpeedTable[i].evEvent->ValueGet(2))) % 10; TDynamicObject *p = pVehicles[0]; // pojazd na czole składu while (p) - { // otwieranie drzwi w pojazdach - flaga zezwolenia była by - // lepsza - lewe = (p->DirectionGet() > 0) ? 1 : 2; // jeśli jedzie do - // tyłu, to drzwi - // otwiera odwrotnie + { // otwieranie drzwi w pojazdach - flaga zezwolenia była by lepsza + // jeśli jedzie do tyłu, to drzwi otwiera odwrotnie + lewe = (p->DirectionGet() > 0) ? 1 : 2; prawe = 3 - lewe; - p->MoverParameters->BatterySwitch(true); // wagony muszą - // mieć baterię - // załączoną do - // otwarcia - // drzwi... + // wagony muszą mieć baterię załączoną do otwarcia drzwi... + p->MoverParameters->BatterySwitch(true); if (p7 & lewe) p->MoverParameters->DoorLeft(true); if (p7 & prawe) p->MoverParameters->DoorRight(true); - p = p->Next(); // pojazd podłączony z tyłu (patrząc od - // czoła) + // pojazd podłączony z tyłu (patrząc od czoła) + p = p->Next(); } // if (p7&3) //żeby jeszcze poczekał chwilę, zanim zamknie // WaitingSet(10); //10 sekund (wziąć z rozkładu????) } - if (fStopTime > - -5) // na końcu rozkładu się ustawia 60s i tu by było skrócenie + if (fStopTime > -5) // na końcu rozkładu się ustawia 60s i tu by było skrócenie WaitingSet(10); // 10 sekund (wziąć z rozkładu????) - czekanie - // niezależne od sposobu obsługi drzwi, bo - // opóźnia również kierownika + // niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika } if (TrainParams->UpdateMTable( simulation::Time, asNextStop) ) { // to się wykona tylko raz po zatrzymaniu na W4 @@ -1062,35 +1147,36 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN else if (sSpeedTable[i].iFlags & spEvent) // W4 może się deaktywować { // jeżeli event, może być potrzeba wysłania komendy, aby ruszył // sprawdzanie eventów pasywnych miniętych - if (sSpeedTable[i].fDist < 0.0 && sSemNext == &sSpeedTable[i]) + if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextIndex == i) ) { - if (Global::iWriteLogEnabled & 8) - WriteLog("TableUpdate: semaphor " + sSemNext->GetName() + " passed by " + OwnerName()); - sSemNext = NULL; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze - // zmiennej sprawdzającej dla skanowania w przód + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextIndex ].GetName() ); + } + SemNextIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód } - if (sSpeedTable[i].fDist < 0.0 && sSemNextStop == &sSpeedTable[i]) + if( (sSpeedTable[ i ].fDist < 0.0) && (SemNextStopIndex == i) ) { - if (Global::iWriteLogEnabled & 8) - WriteLog("TableUpdate: semaphor " + sSemNextStop->GetName() + " passed by " + OwnerName()); - sSemNextStop = NULL; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze - // zmiennej sprawdzającej dla skanowania w przód + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table update for " + OwnerName() + ", passed semaphor " + sSpeedTable[ SemNextStopIndex ].GetName() ); + } + SemNextStopIndex = -1; // jeśli minęliśmy semafor od ograniczenia to go kasujemy ze zmiennej sprawdzającej dla skanowania w przód } if (sSpeedTable[i].fDist > 0.0 && sSpeedTable[i].IsProperSemaphor(OrderCurrentGet())) { - if (!sSemNext) - { - sSemNext = &sSpeedTable[i]; // jeśli jest mienięty poprzedni - // semafor a wcześniej - // byl nowy to go dorzucamy do zmiennej, żeby cały - // czas widział najbliższy - if (Global::iWriteLogEnabled & 8) - WriteLog("TableUpdate: Next semaphor: " + sSemNext->GetName() + " by " + OwnerName()); + if( SemNextIndex == -1 ) { + // jeśli jest mienięty poprzedni semafor a wcześniej + // byl nowy to go dorzucamy do zmiennej, żeby cały czas widział najbliższy + SemNextIndex = i; + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table update for " + OwnerName() + ", next semaphor is " + sSpeedTable[ SemNextIndex ].GetName() ); + } + } + if( ( SemNextStopIndex == -1 ) + || ( ( sSpeedTable[SemNextStopIndex].fVelNext != 0 ) + && ( sSpeedTable[ i ].fVelNext == 0 ) ) ) { + SemNextStopIndex = i; } - if (!sSemNextStop || (sSemNextStop && sSemNextStop->fVelNext != 0 && - sSpeedTable[i].fVelNext == 0)) - sSemNextStop = &sSpeedTable[i]; } if (sSpeedTable[i].iFlags & spOutsideStation) { // jeśli W5, to reakcja zależna od trybu jazdy @@ -1373,56 +1459,53 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN void TController::TablePurger() { // odtykacz: usuwa mniej istotne pozycje ze środka tabelki, aby uniknąć zatkania //(np. brak ograniczenia pomiędzy zwrotnicami, usunięte sygnały, minięte odcinki łuku) - if (Global::iWriteLogEnabled & 8) - WriteLog("TablePurger: Czyszczenie tabelki."); - int i, j, k = iLast - iFirst; // może być 15 albo 16 pozycji, ostatniej nie ma co sprawdzać - if (k < 0) - k += iSpeedTableSize; // ilość pozycji do przeanalizowania - for (i = iFirst; k > 0; --k, i = (i + 1) % iSpeedTableSize) - { // sprawdzenie rekordów od (iFirst) do (iLast), o ile są istotne - if ((sSpeedTable[i].iFlags & spEnabled) ? - (sSpeedTable[i].fVelNext < 0) && ((sSpeedTable[i].iFlags & 0xAB) == 0xA3) : - true) - { // jeśli jest to minięty (0x20) tor (0x03) do liczenia cięciw (0x80), a nie zwrotnica - // (0x08) - for (; k > 0; --k, i = (i + 1) % iSpeedTableSize) - { - sSpeedTable[i] = sSpeedTable[(i + 1) % iSpeedTableSize]; // skopiowanie - if (&sSpeedTable[(i + 1) % iSpeedTableSize] == sSemNext) - sSemNext = &sSpeedTable[i]; // przeniesienie znacznika o semaforze - if (&sSpeedTable[(i + 1) % iSpeedTableSize] == sSemNextStop) - sSemNextStop = &sSpeedTable[i]; // przeniesienie znacznika o semaforze - } - if (Global::iWriteLogEnabled & 8) - WriteLog("Odtykacz usuwa pozycję"); - iLast = (iLast - 1 + iSpeedTableSize) % iSpeedTableSize; // cofnięcie z zawinięciem - return; + // simplest approach should be good enough for start -- just copy whatever is still relevant, then swap + // do a trial run first, to see if we need to bother at all + std::size_t trimcount{ 0 }; + for( std::size_t idx = 0; idx < sSpeedTable.size() - 1; ++idx ) { + auto const &speedpoint = sSpeedTable[ idx ]; + if( ( 0 == ( speedpoint.iFlags & spEnabled ) ) + || ( ( speedpoint.iFlags & ( spElapsed | spTrack | spCurve | spSwitch ) == ( spElapsed | spTrack | spCurve ) ) + && ( speedpoint.fVelNext < 0.0 ) ) ) { + // NOTE: we could break out early here, but running through entire thing gives us exact size needed for new table + ++trimcount; } } - // jeśli powyższe odtykane nie pomoże, można usunąć coś więcej, albo powiększyć tabelkę - TSpeedPos *t = new TSpeedPos[iSpeedTableSize + 16]; // zwiększenie - k = iLast - iFirst + 1; // tym razem wszystkie - if (k < 0) - k += iSpeedTableSize; // ilość pozycji do przeanalizowania - for (j = -1, i = iFirst; k > 0; --k) - { // przepisywanie rekordów iFirst..iLast na 0..k - t[++j] = sSpeedTable[i]; - if (&sSpeedTable[i] == sSemNext) - sSemNext = &t[j]; // przeniesienie znacznika o semaforze - if (&sSpeedTable[i] == sSemNextStop) - sSemNextStop = &t[j]; // przeniesienie znacznika o semaforze - i = (i + 1) % iSpeedTableSize; // kolejna pozycja mogą być zawinięta + if( trimcount == 0 ) { + // there'd be no gain, may as well bail + return; } - iFirst = 0; // teraz będzie od zera - iLast = j; // ostatnia - delete[] sSpeedTable; // to już nie potrzebne - sSpeedTable = t; // bo jest nowe - iSpeedTableSize += 16; - if (Global::iWriteLogEnabled & 8) - WriteLog("Tabelka powiększona do "+std::to_string(iSpeedTableSize)+" pozycji"); + std::vector trimmedtable; trimmedtable.reserve( sSpeedTable.size() - trimcount ); + // we can only update pointers safely after new table is finalized, so record their indices until then + for( std::size_t idx = 0; idx < sSpeedTable.size() - 1; ++idx ) { + // cache placement of semaphors in the new table, if we encounter them + // NOTE: we rely on the semaphor actually getting added in the next step rather than skipped, but it's a pretty safe bet + if( idx == SemNextIndex ) { + SemNextIndex = trimmedtable.size(); + } + if( idx == SemNextStopIndex ) { + SemNextStopIndex = trimmedtable.size(); + } + auto const &speedpoint = sSpeedTable[ idx ]; + if( ( 0 == ( speedpoint.iFlags & spEnabled ) ) + || ( ( speedpoint.iFlags & ( spElapsed | spTrack | spCurve | spSwitch ) == ( spElapsed | spTrack | spCurve ) ) + && ( speedpoint.fVelNext < 0.0 ) ) ) { + continue; + } + // we're left with useful speed point record we should copy + trimmedtable.emplace_back( speedpoint ); + } + // always copy the last entry + trimmedtable.emplace_back( sSpeedTable.back() ); + + if( Global::iWriteLogEnabled & 8 ) { + WriteLog( "Speed table garbage collection for " + OwnerName() + " cut away " + std::to_string( trimcount ) + ( trimcount == 1 ? " record" : " records" ) ); + } + // update the data + sSpeedTable = trimmedtable; + iLast = sSpeedTable.size() - 1; }; -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- + //--------------------------------------------------------------------------- TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, bool primary) :// czy ma aktywnie prowadzić? @@ -1473,7 +1556,6 @@ TController::TController(bool AI, TDynamicObject *NewControll, bool InitPsyche, } SetDriverPsyche(); // na końcu, bo wymaga ustawienia zmiennych - sSpeedTable = new TSpeedPos[iSpeedTableSize]; TableClear(); if( WriteLogFlag ) { @@ -1512,7 +1594,6 @@ TController::~TController() { // wykopanie mechanika z roboty delete tsGuardSignal; delete TrainParams; - delete[] sSpeedTable; CloseLog(); }; @@ -2302,7 +2383,7 @@ bool TController::IncBrake() if (mvOccupied->LocalBrake == ManualBrake) OK = mvOccupied->IncManualBrakeLevel( 1 + static_cast( std::floor( 0.5 + std::fabs(AccDesired))) ); else - OK = mvOccupied->IncLocalBrakeLevel( 1 + static_cast( std::floor( 0.5 + std::fabs(AccDesired))) ); + OK = mvOccupied->IncLocalBrakeLevel( std::floor( 1.5 + std::abs( AccDesired ) ) ); break; case Pneumatic: if ((mvOccupied->Couplers[0].Connected == NULL) && @@ -2696,8 +2777,18 @@ void TController::SpeedSet() if (ReactionTime > 0.1) ReactionTime = 0.1; // orientuj się szybciej } // if (Im>Imin) - if (fabs(mvControlling->Im) > 0.75 * mvControlling->ImaxHi) // jeśli prąd jest duży - mvControlling->SandDoseOn(); // piaskujemy tory, coby się nie ślizgać + // NOTE: this step is likely to conflict with directive to operate sandbox based on the state of slipping wheels + // TODO: gather all sandbox operating logic in one place + if( fabs( mvControlling->Im ) > 0.75 * mvControlling->ImaxHi ) { + // jeśli prąd jest duży + mvControlling->Sandbox( true ); // piaskujemy tory, coby się nie ślizgać + } + else { + // otherwise we switch the sander off, if it's active + if( mvControlling->SandDose ) { + mvControlling->Sandbox( false ); + } + } if ((fabs(mvControlling->Im) > 0.96 * mvControlling->Imax) || mvControlling->SlippingWheels) // jeśli prąd jest duży (można 690 na 750) if (mvControlling->ScndCtrlPos > 0) // jeżeli jest bocznik @@ -3241,10 +3332,16 @@ bool TController::UpdateSituation(double dt) // mvOccupied->PipePress=0.5; //yB: w SPKS są poprawnie zrobione pozycje if (mvControlling->SlippingWheels) { - mvControlling->SandDoseOn(); // piasku! + 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 ); + } + } } // ABu-160305 testowanie gotowości do jazdy // Ra: przeniesione z DynObj, skład użytkownika też jest testowany, żeby mu przekazać, że ma @@ -3293,6 +3390,16 @@ bool TController::UpdateSituation(double dt) 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 + if( ( false == AIControllFlag ) + && ( iDrivigFlags & moveDoorOpened ) + && ( mvOccupied->DoorOpenCtrl != 1 ) + && ( mvControlling->MainCtrlPos > 0 ) ) { + Doors( false ); + } + // Winger 020304 if (AIControllFlag) { @@ -4154,7 +4261,9 @@ bool TController::UpdateSituation(double dt) TrainParams ->TTVmax); // jesli nie spozniony to nie przekraczać rozkladowej if (VelDesired > 0.0) - if ((sSemNext && sSemNext->fVelNext != 0.0) || (iDrivigFlags & moveStopHere)==0) + if( ( ( SemNextIndex != -1 ) + && ( sSpeedTable[SemNextIndex].fVelNext != 0.0 ) ) + || ( ( iDrivigFlags & moveStopHere ) == 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ć @@ -5346,13 +5455,14 @@ void TController::ControllingSet() mvControlling = pVehicle->ControlledFind()->MoverParameters; // poszukiwanie członu sterowanego }; -std::string TController::TableText(int i) +std::string TController::TableText( std::size_t const Index ) { // pozycja tabelki prędkości - i = (iFirst + i) % iSpeedTableSize; // numer pozycji - if (i != iLast) // w (iLast) znajduje się kolejny tor do przeskanowania, ale nie jest ona - // aktywną - return sSpeedTable[i].TableText(); - return ""; // wskaźnik końca + if( Index < sSpeedTable.size() ) { + return sSpeedTable[ Index ].TableText(); + } + else { + return ""; + } }; int TController::CrossRoute(TTrack *tr) @@ -5360,13 +5470,15 @@ int TController::CrossRoute(TTrack *tr) // pożądany numer segmentu jest określany podczas skanowania drogi // droga powinna być określona sposobem przejazdu przez skrzyżowania albo współrzędnymi miejsca // docelowego - for (int i = iFirst; i != iLast; i = (i + 1) % iSpeedTableSize) + for( std::size_t i = 0; i < sSpeedTable.size(); ++i ) { // trzeba przejrzeć tabelę skanowania w poszukiwaniu (tr) // i jak się znajdzie, to zwrócić zapamiętany numer segmentu i kierunek przejazdu // (-6..-1,1..6) - if ((sSpeedTable[i].iFlags & 3) == 3) // jeśli pozycja istotna (1) oraz odcinek (2) - if (sSpeedTable[i].trTrack == tr) // jeśli pozycja odpowiadająca skrzyżowaniu (tr) - return (sSpeedTable[i].iFlags >> 28); // najstarsze 4 bity jako liczba -8..7 + if( ( true == TestFlag( sSpeedTable[ i ].iFlags, spEnabled | spTrack ) ) + && ( sSpeedTable[ i ].trTrack == tr ) ) { + // jeśli pozycja odpowiadająca skrzyżowaniu (tr) + return ( sSpeedTable[ i ].iFlags >> 28 ); // najstarsze 4 bity jako liczba -8..7 + } } return 0; // nic nie znaleziono? }; @@ -5374,29 +5486,35 @@ int TController::CrossRoute(TTrack *tr) void TController::RouteSwitch(int d) { // ustawienie kierunku jazdy z kabiny d &= 3; - if (d) - if (iRouteWanted != d) - { // nowy kierunek + if( d ) { + if( iRouteWanted != d ) { // nowy kierunek iRouteWanted = d; // zapamiętanie - if (mvOccupied->CategoryFlag & 2) // jeśli samochód - for (int i = iFirst; i != iLast; i = (i + 1) % iSpeedTableSize) - { // szukanie pierwszego skrzyżowania i resetowanie kierunku na nim - if ((sSpeedTable[i].iFlags & 3) == - 3) // jeśli pozycja istotna (1) oraz odcinek (2) - if ((sSpeedTable[i].iFlags & 32) == 0) // odcinek nie może być miniętym - if (sSpeedTable[i].trTrack->eType == tt_Cross) // jeśli skrzyżowanie - { // obcięcie tabelki skanowania przed skrzyżowaniem, aby ponownie - // wybrać drogę - iLast = i - 1; // ponowne skanowanie skrzyżowania (w zwrotnicach - // jest iLast=i, ale tam jest prościej) - if (iLast < 0) - iLast += iSpeedTableSize; // bo tabelka jest zapętlona - return; + if( mvOccupied->CategoryFlag & 2 ) { + // jeśli samochód + for( std::size_t i = 0; i < sSpeedTable.size(); ++i ) { + // szukanie pierwszego skrzyżowania i resetowanie kierunku na nim + if( true == TestFlag( sSpeedTable[ i ].iFlags, spEnabled | spTrack ) ) { + // jeśli pozycja istotna (1) oraz odcinek (2) + if( false == TestFlag( sSpeedTable[ i ].iFlags, spElapsed ) ) { + // odcinek nie może być miniętym + if( sSpeedTable[ i ].trTrack->eType == tt_Cross ) // jeśli skrzyżowanie + { + while( sSpeedTable.size() >= i ) { + // NOTE: we're ignoring semaphor flags and not resetting them like we do for train route trimming + // but what if there's street lights? + // TODO: investigate + sSpeedTable.pop_back(); + } + iLast = sSpeedTable.size(); } + } + } } + } } + } }; -std::string TController::OwnerName() +std::string TController::OwnerName() const { return ( pVehicle ? pVehicle->MoverParameters->Name : "none" ); }; diff --git a/Driver.h b/Driver.h index eeddc1a1..dcbd3b81 100644 --- a/Driver.h +++ b/Driver.h @@ -102,6 +102,7 @@ enum TAction enum TSpeedPosFlag { // wartości dla iFlag w TSpeedPos + spNone = 0x0, spEnabled = 0x1, // pozycja brana pod uwagę spTrack = 0x2, // to jest tor spReverse = 0x4, // odwrotnie @@ -126,11 +127,11 @@ enum TSpeedPosFlag class TSpeedPos { // pozycja tabeli prędkości dla AI public: - double fDist; // aktualna odległość (ujemna gdy minięte) - double fVelNext; // prędkość obowiązująca od tego miejsca - double fSectionVelocityDist; // długość ograniczenia prędkości + double fDist{ 0.0 }; // aktualna odległość (ujemna gdy minięte) + double fVelNext{ -1.0 }; // prędkość obowiązująca od tego miejsca + double fSectionVelocityDist{ 0.0 }; // długość ograniczenia prędkości // double fAcc; - int iFlags; // flagi typu wpisu do tabelki + int iFlags{ spNone }; // flagi typu wpisu do tabelki // 1=istotny,2=tor,4=odwrotnie,8-zwrotnica (może się zmienić),16-stan // zwrotnicy,32-minięty,64=koniec,128=łuk // 0x100=event,0x200=manewrowa,0x400=przystanek,0x800=SBL,0x1000=wysłana komenda,0x2000=W5 @@ -138,8 +139,8 @@ class TSpeedPos vector3 vPos; // współrzędne XYZ do liczenia odległości struct { - TTrack *trTrack; // wskaźnik na tor o zmiennej prędkości (zwrotnica, obrotnica) - TEvent *evEvent; // połączenie z eventem albo komórką pamięci + TTrack *trTrack{ nullptr }; // wskaźnik na tor o zmiennej prędkości (zwrotnica, obrotnica) + TEvent *evEvent{ nullptr }; // połączenie z eventem albo komórką pamięci }; void CommandCheck(); @@ -166,16 +167,14 @@ extern bool WriteLogFlag; // logowanie parametrów fizycznych class TController { private: // obsługa tabelki prędkości (musi mieć możliwość odhaczania stacji w rozkładzie) - TSpeedPos *sSpeedTable = nullptr; // najbliższe zmiany prędkości - int iSpeedTableSize = 16; // wielkość tabelki - int iFirst = 0; // aktualna pozycja w tabeli (modulo iSpeedTableSize) - int iLast = 0; // ostatnia wypełniona pozycja w tabeli sSpeedTable; double fLastVel = 0.0; // prędkość na poprzednio sprawdzonym torze TTrack *tLast = nullptr; // ostatni analizowany tor TEvent *eSignSkip = nullptr; // można pominąć ten SBL po zatrzymaniu - TSpeedPos *sSemNext = nullptr; // następny semafor na drodze zależny od trybu jazdy - TSpeedPos *sSemNextStop = nullptr; // następny semafor na drodze zależny od trybu jazdy i na stój + std::size_t SemNextIndex{ -1 }; + std::size_t SemNextStopIndex{ -1 }; private: // parametry aktualnego składu double fLength = 0.0; // długość składu (do wyciągania z ograniczeń) double fMass = 0.0; // całkowita masa do liczenia stycznej składowej grawitacji @@ -358,13 +357,15 @@ class TController TEvent *CheckTrackEvent(double fDirection, TTrack *Track); bool TableCheckEvent(TEvent *e); bool TableAddNew(); - bool TableNotFound(TEvent *e); + bool TableNotFound(TEvent const *Event) const; void TableClear(); TEvent *TableCheckTrackEvent(double fDirection, TTrack *Track); void TableTraceRoute(double fDistance, TDynamicObject *pVehicle = NULL); void TableCheck(double fDistance); TCommandType TableUpdate(double &fVelDes, double &fDist, double &fNext, double &fAcc); void TablePurger(); +public: + std::size_t TableSize() const { return sSpeedTable.size(); } private: // Ra: stare funkcje skanujące, używane do szukania sygnalizatora z tyłu bool BackwardTrackBusy(TTrack *Track); @@ -395,9 +396,9 @@ class TController }; void MoveTo(TDynamicObject *to); void DirectionInitial(); - std::string TableText(int i); + std::string TableText(std::size_t const Index); int CrossRoute(TTrack *tr); void RouteSwitch(int d); - std::string OwnerName(); + std::string OwnerName() const; TMoverParameters const *Controlling() const { return mvControlling; } }; diff --git a/DynObj.cpp b/DynObj.cpp index 36b09abb..299fc598 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -798,7 +798,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) btnOn = true; } // else btCPass2.TurnOff(); - if (MoverParameters->Battery) + if (MoverParameters->Battery || MoverParameters->ConverterFlag) { // sygnaly konca pociagu if (btEndSignals1.Active()) { @@ -900,7 +900,7 @@ void TDynamicObject::ABuLittleUpdate(double ObjSqrDist) // Ra: przechyłkę załatwiamy na etapie przesuwania modelu // if (ObjSqrDist<80000) ABuModelRoll(); //przechyłki od 400m } - if (MoverParameters->Battery) + if( MoverParameters->Battery || MoverParameters->ConverterFlag ) { // sygnały czoła pociagu //Ra: wyświetlamy bez // ograniczeń odległości, by były widoczne z // daleka @@ -1753,52 +1753,45 @@ TDynamicObject::Init(std::string Name, // nazwa pojazdu, np. "EU07-424" // wylaczanie hamulca if (ActPar.find("<>") != std::string::npos) // wylaczanie na probe hamowania naglego { - MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz } if (ActPar.find('0') != std::string::npos) // wylaczanie na sztywno { - MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); // odluznij automatycznie } if (ActPar.find('E') != std::string::npos) // oprozniony { MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); // odluznij automatycznie MoverParameters->Pipe->CreatePress(0); MoverParameters->Pipe2->CreatePress(0); } if (ActPar.find('Q') != std::string::npos) // oprozniony { - // MoverParameters->Hamulec->ForceEmptiness(); //TODO: sprawdzic, - // dlaczego - // pojawia sie blad przy uzyciu tej linijki w lokomotywie - MoverParameters->BrakeReleaser(1); // odluznij automatycznie + MoverParameters->Hamulec->ForceEmptiness(); MoverParameters->Pipe->CreatePress(0.0); MoverParameters->PipePress = 0.0; MoverParameters->Pipe2->CreatePress(0.0); MoverParameters->ScndPipePress = 0.0; - MoverParameters->PantVolume = 1; - MoverParameters->PantPress = 0; - MoverParameters->CompressedVolume = 0; + MoverParameters->PantVolume = 0.1; + MoverParameters->PantPress = 0.0; + MoverParameters->CompressedVolume = 0.0; } if (ActPar.find('1') != std::string::npos) // wylaczanie 10% { if (Random(10) < 1) // losowanie 1/10 { - MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); // odluznij automatycznie } } if (ActPar.find('X') != std::string::npos) // agonalny wylaczanie 20%, usrednienie przekladni { if (Random(100) < 20) // losowanie 20/100 { - MoverParameters->BrakeStatus |= 128; // wylacz + MoverParameters->Hamulec->SetBrakeStatus( MoverParameters->Hamulec->GetBrakeStatus() | b_dmg ); // wylacz MoverParameters->Hamulec->ForceEmptiness(); - MoverParameters->BrakeReleaser(1); // odluznij automatycznie } if (MoverParameters->BrakeCylMult[2] * MoverParameters->BrakeCylMult[1] > 0.01) // jesli jest nastawiacz mechaniczny PL @@ -2443,43 +2436,61 @@ bool TDynamicObject::Update(double dt, double dt1) if (!bEnabled) return false; // a normalnie powinny mieć bEnabled==false - // Ra: przeniosłem - no już lepiej tu, niż w wyświetlaniu! - // if ((MoverParameters->ConverterFlag==false) && - // (MoverParameters->TrainType!=dt_ET22)) - // Ra: to nie może tu być, bo wyłącza sprężarkę w rozrządczym EZT! - // if - // ((MoverParameters->ConverterFlag==false)&&(MoverParameters->CompressorPower!=0)) - // MoverParameters->CompressorFlag=false; - // if (MoverParameters->CompressorPower==2) - // MoverParameters->CompressorAllow=MoverParameters->ConverterFlag; - // McZapkie-260202 if ((MoverParameters->EnginePowerSource.SourceType == CurrentCollector) && (MoverParameters->Power > 1.0)) // aby rozrządczy nie opuszczał silnikowemu +/* if ((MechInside) || (MoverParameters->TrainType == dt_EZT)) { +*/ // if // ((!MoverParameters->PantCompFlag)&&(MoverParameters->CompressedVolume>=2.8)) // MoverParameters->PantVolume=MoverParameters->CompressedVolume; - if (MoverParameters->PantPress < (MoverParameters->TrainType == dt_EZT ? 2.4 : 3.5)) - { // 3.5 wg - // http://www.transportszynowy.pl/eu06-07pneumat.php - //"Wyłączniki ciśnieniowe odbieraków prądu wyłączają sterowanie - // wyłącznika szybkiego - // oraz uniemożliwiają podniesienie odbieraków prądu, gdy w instalacji - // rozrządu - // ciśnienie spadnie poniżej wartości 3,5 bara." - // Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5 - // if (!MoverParameters->PantCompFlag) - // MoverParameters->PantVolume=MoverParameters->CompressedVolume; - MoverParameters->PantFront(false); // opuszczenie pantografów przy niskim ciśnieniu - MoverParameters->PantRear(false); // to idzie w ukrotnieniu, a nie powinno... + + if( MoverParameters->PantPress < MoverParameters->EnginePowerSource.CollectorParameters.MinPress ) { + // 3.5 wg http://www.transportszynowy.pl/eu06-07pneumat.php + if( true == MoverParameters->PantPressSwitchActive ) { + // opuszczenie pantografów przy niskim ciśnieniu +/* + // NOTE: disabled, the pantographs drop by themseleves when the pantograph tank pressure gets low enough + MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); +*/ + if( MoverParameters->TrainType != dt_EZT ) { + // pressure switch safety measure -- open the line breaker, unless there's alternate source of traction voltage + if( MoverParameters->GetTrainsetVoltage() < 0.5 * MoverParameters->EnginePowerSource.MaxVoltage ) { + // TODO: check whether line breaker should be open EMU-wide + MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + } + } + else { + // specialized variant for EMU -- pwr system disables converter and heating, + // and prevents their activation until pressure switch is set again + MoverParameters->PantPressLockActive = true; + // TODO: separate 'heating allowed' from actual heating flag, so we can disable it here without messing up heating toggle + MoverParameters->ConverterSwitch( false, command_range::unit ); + } + // mark the pressure switch as spent + MoverParameters->PantPressSwitchActive = false; + } } - // Winger - automatyczne wylaczanie malej sprezarki - else if (MoverParameters->PantPress >= 4.8) - MoverParameters->PantCompFlag = false; - } // Ra: do Mover to trzeba przenieść, żeby AI też mogło sobie podpompować + else { + if( MoverParameters->PantPress >= 4.6 ) { + // prime the pressure switch + MoverParameters->PantPressSwitchActive = true; + // turn off the subsystems lock + MoverParameters->PantPressLockActive = false; + if( MoverParameters->PantPress >= 4.8 ) { + // Winger - automatyczne wylaczanie malej sprezarki + // TODO: governor lock, disables usage until pressure drop below 3.8 (should really make compressor object we could reuse) + MoverParameters->PantCompFlag = false; + } + } + } +/* + } // Ra: do Mover to trzeba przenieść, żeby AI też mogło sobie podpompować +*/ double dDOMoveLen; TLocation l; @@ -2911,37 +2922,26 @@ bool TDynamicObject::Update(double dt, double dt1) // fragment "z EXE Kursa" if (MoverParameters->Mains) // nie wchodzić w funkcję bez potrzeby - if ( ( false == MoverParameters->Battery) + if ( ( false == MoverParameters->Battery ) && ( false == MoverParameters->ConverterFlag ) // added alternative power source. TODO: more generic power check - && ( Controller == Humandriver) +/* + // NOTE: disabled on account of multi-unit setups, where the unmanned unit wouldn't be affected + && ( Controller == Humandriver ) +*/ && ( MoverParameters->EngineType != DieselEngine ) && ( MoverParameters->EngineType != WheelsDriven ) ) { // jeśli bateria wyłączona, a nie diesel ani drezyna reczna - if (MoverParameters->MainSwitch(false)) // wyłączyć zasilanie + if( MoverParameters->MainSwitch( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ) ) { + // wyłączyć zasilanie + // NOTE: we turn off entire EMU, but only the affected unit for other multi-unit consists MoverParameters->EventFlag = true; + // drop pantographs + // NOTE: this isn't universal behaviour + // TODO: have this dependant on .fiz-driven flag + MoverParameters->PantFront( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + MoverParameters->PantRear( false, ( MoverParameters->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + } } - if (MoverParameters->TrainType == dt_ET42) - { // powinny być wszystkie dwuczłony oraz EZT - /* - //Ra: to jest bez sensu, bo wyłącza WS przy przechodzeniu przez - "wewnętrzne" kabiny (z - powodu ActiveCab) - //trzeba to zrobić inaczej, np. dla członu A sprawdzać, czy jest B - //albo sprawdzać w momencie załączania WS i zmiany w sprzęgach - if - (((TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0)&&(NextConnected->MoverParameters->TrainType!=dt_ET42))||((TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0)&&(PrevConnected->MoverParameters->TrainType!=dt_ET42))) - {//sprawdzenie, czy z tyłu kabiny mamy drugi człon - if (MoverParameters->MainSwitch(false)) - MoverParameters->EventFlag=true; - } - if - ((!(TestFlag(MoverParameters->Couplers[1].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab>0))||(!(TestFlag(MoverParameters->Couplers[0].CouplingFlag,ctrain_controll))&&(MoverParameters->ActiveCab<0))) - { - if (MoverParameters->MainSwitch(false)) - MoverParameters->EventFlag=true; - } - */ - } // McZapkie-260202 - dMoveLen przyda sie przy stukocie kol dDOMoveLen = @@ -3210,21 +3210,23 @@ bool TDynamicObject::Update(double dt, double dt1) MoverParameters->PantRearVolt = 0.0; break; } // pozostałe na razie nie obsługiwane - if (MoverParameters->PantPress > - (MoverParameters->TrainType == dt_EZT ? 2.5 : 3.3)) // Ra 2013-12: - // Niebugocław - // mówi, że w EZT - // podnoszą się - // przy 2.5 - pantspeedfactor = 0.015 * (MoverParameters->PantPress) * - dt1; // z EXE Kursa //Ra: wysokość zależy od ciśnienia !!! - else + if( MoverParameters->PantPress > ( + MoverParameters->TrainType == dt_EZT ? + 2.45 : // Ra 2013-12: Niebugocław mówi, że w EZT podnoszą się przy 2.5 + 3.45 ) ) { + // z EXE Kursa + // Ra: wysokość zależy od ciśnienia !!! + pantspeedfactor = 0.015 * ( MoverParameters->PantPress ) * dt1; + } + else { pantspeedfactor = 0.0; - if (pantspeedfactor < 0) - pantspeedfactor = 0; + } + pantspeedfactor = std::max( 0.0, pantspeedfactor ); k = p->fAngleL; - if (i ? MoverParameters->PantRearUp : - MoverParameters->PantFrontUp) // jeśli ma być podniesiony + if( ( pantspeedfactor > 0.0 ) + && ( i ? + MoverParameters->PantRearUp : + MoverParameters->PantFrontUp ) )// jeśli ma być podniesiony { if (PantDiff > 0.001) // jeśli nie dolega do drutu { // jeśli poprzednia wysokość jest mniejsza niż pożądana, zwiększyć kąt @@ -3283,6 +3285,9 @@ bool TDynamicObject::Update(double dt, double dt1) sPantDown.Play(vol, 0, MechInside, vPosition); MoverParameters->PantRearSP = true; } +/* + // NOTE: disabled because it's both redundant and doesn't take into account alternative power sources + // converter and compressor will (should) turn off during their individual checks, in the mover's (fast)computemovement() calls if (MoverParameters->EnginePowerSource.SourceType == CurrentCollector) { // Winger 240404 - wylaczanie sprezarki i // przetwornicy przy braku napiecia @@ -3292,6 +3297,7 @@ bool TDynamicObject::Update(double dt, double dt1) MoverParameters->CompressorFlag = false; // Ra: to jest wątpliwe - wyłączenie sprężarki powinno być w jednym miejscu! } } +*/ } else if (MoverParameters->EnginePowerSource.SourceType == InternalSource) if (MoverParameters->EnginePowerSource.PowerType == SteamPower) @@ -4124,22 +4130,20 @@ void TDynamicObject::RenderSounds() sConverter.TurnOff(MechInside, GetPosition()); sConverter.Update(MechInside, GetPosition()); } - if (MoverParameters->WarningSignal > 0) - { - if (TestFlag(MoverParameters->WarningSignal, 1)) - sHorn1.TurnOn(MechInside, GetPosition()); - else - sHorn1.TurnOff(MechInside, GetPosition()); - if (TestFlag(MoverParameters->WarningSignal, 2)) - sHorn2.TurnOn(MechInside, GetPosition()); - else - sHorn2.TurnOff(MechInside, GetPosition()); + + if( TestFlag( MoverParameters->WarningSignal, 1 ) ) { + sHorn1.TurnOn( MechInside, GetPosition() ); } - else - { - sHorn1.TurnOff(MechInside, GetPosition()); - sHorn2.TurnOff(MechInside, GetPosition()); + else { + sHorn1.TurnOff( MechInside, GetPosition() ); } + if( TestFlag( MoverParameters->WarningSignal, 2 ) ) { + sHorn2.TurnOn( MechInside, GetPosition() ); + } + else { + sHorn2.TurnOff( MechInside, GetPosition() ); + } + if (MoverParameters->DoorClosureWarning) { if (MoverParameters->DepartureSignal) // NBMX sygnal odjazdu, MC: pod warunkiem ze jest diff --git a/Globals.h b/Globals.h index ee866146..ca665df5 100644 --- a/Globals.h +++ b/Globals.h @@ -130,7 +130,9 @@ class TTranscript float fHide; // czas ukrycia/usunięcia std::string asText; // tekst gotowy do wyświetlenia (usunięte znaczniki czasu) bool bItalic; // czy kursywa (dźwięk nieistotny dla prowadzącego) +/* int iNext; // następna używana linijka, żeby nie przestawiać fizycznie tabeli +*/ }; /* diff --git a/Ground.h b/Ground.h index 27f48a30..0c5722d7 100644 --- a/Ground.h +++ b/Ground.h @@ -69,7 +69,7 @@ struct TGroundVertex { vector3 Point; vector3 Normal; - float tu, tv; + float tu{ 0.0f }, tv{ 0.0f }; void HalfSet(const TGroundVertex &v1, const TGroundVertex &v2) { // wyliczenie współrzędnych i mapowania punktu na środku odcinka v1<->v2 Point = 0.5 * (v1.Point + v2.Point); diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index c2c53086..b381f0c8 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -139,7 +139,23 @@ static int const ctrain_passenger = 16; //mostek przejściowy static int const ctrain_scndpneumatic = 32; //przewody 8 atm (żółte; zasilanie powietrzem) static int const ctrain_heating = 64; //przewody ogrzewania WN static int const ctrain_depot = 128; //nie rozłączalny podczas zwykłych manewrów (międzyczłonowy), we wpisie wartość ujemna - +enum coupling { + faux = 0x0, + coupler = 0x1, + brakehose = 0x2, + control = 0x4, + highvoltage = 0x8, + gangway = 0x10, + mainhose = 0x20, + heating = 0x40, + permanent = 0x80 +}; +/*! przesylanie komend sterujacych*/ +enum command_range { + local, + unit, + consist +}; /*typ hamulca elektrodynamicznego*/ static int const dbrake_none = 0; static int const dbrake_passive = 1; @@ -269,7 +285,8 @@ struct TCommand std::string Command; /*komenda*/ double Value1 = 0.0; /*argumenty komendy*/ double Value2 = 0.0; - TLocation Location; + int Coupling{ ctrain_controll }; // coupler flag used to determine command propagation + TLocation Location; }; /*tory*/ @@ -360,14 +377,14 @@ struct TBoilerType { }; /*rodzaj odbieraka pradu*/ struct TCurrentCollector { - long CollectorsNo; //musi być tu, bo inaczej się kopie - double MinH; double MaxH; //zakres ruchu pantografu, nigdzie nie używany - double CSW; //szerokość części roboczej (styku) ślizgacza - double MinV; double MaxV; //minimalne i maksymalne akceptowane napięcie - double OVP; //czy jest przekaznik nadnapieciowy - double InsetV; //minimalne napięcie wymagane do załączenia - double MinPress; //minimalne ciśnienie do załączenia WS - double MaxPress; //maksymalne ciśnienie za reduktorem + long CollectorsNo{ 0 }; //musi być tu, bo inaczej się kopie + double MinH{ 0.0 }; double MaxH{ 0.0 }; //zakres ruchu pantografu, nigdzie nie używany + double CSW{ 0.0 }; //szerokość części roboczej (styku) ślizgacza + double MinV{ 0.0 }; double MaxV{ 0.0 }; //minimalne i maksymalne akceptowane napięcie + double OVP{ 0.0 }; //czy jest przekaznik nadnapieciowy + double InsetV{ 0.0 }; //minimalne napięcie wymagane do załączenia + double MinPress{ 0.0 }; //minimalne ciśnienie do załączenia WS + double MaxPress{ 0.0 }; //maksymalne ciśnienie za reduktorem //inline TCurrentCollector() { // CollectorsNo = 0; // MinH, MaxH, CSW, MinV, MaxV = 0.0; @@ -536,6 +553,12 @@ struct TTransmision enum TCouplerType { NoCoupler, Articulated, Bare, Chain, Screw, Automatic }; +struct power_coupling { + double current{ 0.0 }; + double voltage{ 0.0 }; + bool local{ false }; // whether the power comes from external or onboard source +}; + struct TCoupling { /*parametry*/ double SpringKB = 1.0; /*stala sprezystosci zderzaka/sprzegu, %tlumiennosci */ @@ -556,6 +579,9 @@ struct TCoupling { double CForce = 0.0; /*sila z jaka dzialal*/ double Dist = 0.0; /*strzalka ugiecia zderzaków*/ bool CheckCollision = false; /*czy sprawdzac sile czy pedy*/ + + power_coupling power_high; + power_coupling power_low; // TODO: implement this }; class TMoverParameters @@ -768,7 +794,17 @@ public: TRotation Rot; std::string Name; /*nazwa wlasna*/ TCoupling Couplers[2]; //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami - double HVCouplers[2][2]; //przewod WN + enum side { + front = 0, + rear + }; +#ifdef EU07_USE_OLD_HVCOUPLERS + double HVCouplers[ 2 ][ 2 ]; //przewod WN + enum hvcoupler { + current = 0, + voltage + }; +#endif int ScanCounter = 0; /*pomocnicze do skanowania sprzegow*/ bool EventFlag = false; /*!o true jesli cos nietypowego sie wydarzy*/ int SoundFlag = 0; /*!o patrz stale sound_ */ @@ -804,6 +840,7 @@ public: bool CompressorFlag = false; /*!o czy wlaczona sprezarka*/ bool PantCompFlag = false; /*!o czy wlaczona sprezarka pantografow*/ bool CompressorAllow = false; /*! zezwolenie na uruchomienie sprezarki NBMX*/ + bool CompressorGovernorLock{ false }; // indicates whether compressor pressure switch was activated due to reaching cut-out pressure bool ConverterFlag = false ; /*! czy wlaczona przetwornica NBMX*/ bool ConverterAllow = false; /*zezwolenie na prace przetwornicy NBMX*/ int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ @@ -812,7 +849,9 @@ public: int LocalBrakePos = 0; /*nastawa hamulca indywidualnego*/ int ManualBrakePos = 0; /*nastawa hamulca recznego*/ double LocalBrakePosA = 0.0; - int BrakeStatus = b_off; /*0 - odham, 1 - ham., 2 - uszk., 4 - odluzniacz, 8 - antyposlizg, 16 - uzyte EP, 32 - pozycja R, 64 - powrot z R*/ +/* + 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*/ int BrakeDelayFlag = 0; /*nastawa opoznienia ham. osob/towar/posp/exp 0/1/2/4*/ int BrakeDelays = 0; /*nastawy mozliwe do uzyskania*/ @@ -886,7 +925,9 @@ public: double RventRot = 0.0; /*!s obroty wentylatorow rozruchowych*/ bool UnBrake = false; /*w EZT - nacisniete odhamowywanie*/ double PantPress = 0.0; /*Cisnienie w zbiornikach pantografow*/ - bool s_CAtestebrake = false; //hunter-091012: zmienna dla testu ca + bool PantPressSwitchActive{ false }; // state of the pantograph pressure switch. gets primed at defined pressure level in pantograph air system + bool PantPressLockActive{ false }; // pwr system state flag. fires when pressure switch activates by pantograph pressure dropping below defined level + bool s_CAtestebrake = false; //hunter-091012: zmienna dla testu ca /*-zmienne dla lokomotywy spalinowej z przekladnia mechaniczna*/ double dizel_fill = 0.0; /*napelnienie*/ @@ -982,11 +1023,11 @@ public: /*! przesylanie komend sterujacych*/ bool SendCtrlBroadcast(std::string CtrlCommand, double ctrlvalue); - bool SendCtrlToNext(std::string CtrlCommand, double ctrlvalue, double dir); - bool SetInternalCommand(std::string NewCommand, double NewValue1, double NewValue2); + bool SendCtrlToNext(std::string const CtrlCommand, double const ctrlvalue, double const dir, int const Couplertype = ctrain_controll); + bool SetInternalCommand( std::string NewCommand, double NewValue1, double NewValue2, int const Couplertype = ctrain_controll ); double GetExternalCommand(std::string &Command); - bool RunCommand(std::string Command, double CValue1, double CValue2); - bool RunInternalCommand(void); + bool RunCommand( std::string Command, double CValue1, double CValue2, int const Couplertype = ctrain_controll ); + bool RunInternalCommand(); void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation); bool CabActivisation(void); bool CabDeactivisation(void); @@ -1002,7 +1043,7 @@ public: bool AddPulseForce(int Multipler);/*dla drezyny*/ - bool SandDoseOn(void);/*wlacza/wylacza sypanie piasku*/ + bool Sandbox( bool const State, int const Notify = command_range::consist );/*wlacza/wylacza sypanie piasku*/ /*! zbijanie czuwaka/SHP*/ void SSReset(void); @@ -1058,9 +1099,9 @@ public: /*--funkcje dla lokomotyw*/ bool DirectionBackward(void);/*! kierunek ruchu*/ - bool MainSwitch(bool State);/*! wylacznik glowny*/ - bool ConverterSwitch(bool State);/*! wl/wyl przetwornicy*/ - bool CompressorSwitch(bool State);/*! wl/wyl sprezarki*/ + bool MainSwitch( bool const State, int const Notify = command_range::consist );/*! wylacznik glowny*/ + bool ConverterSwitch( bool State, int const Notify = command_range::consist );/*! wl/wyl przetwornicy*/ + bool CompressorSwitch( bool State, int const Notify = command_range::consist );/*! wl/wyl sprezarki*/ /*-funkcje typowe dla lokomotywy elektrycznej*/ void ConverterCheck(); // przetwornica @@ -1074,7 +1115,7 @@ public: /*function ShowEngineRotation(VehN:int): integer; //Ra 2014-06: przeniesione do C++*/ /*funkcje uzalezniajace sile pociagowa od predkosci: v2n, n2r, current, momentum*/ double v2n(void); - double current(double n, double U); + double Current(double n, double U); double Momentum(double I); double MomentumF(double I, double Iw, int SCP); @@ -1086,8 +1127,8 @@ public: bool AutoRelayCheck(void);//symulacja automatycznego rozruchu bool ResistorsFlagCheck(void); //sprawdzenie kontrolki oporow rozruchowych NBMX - bool PantFront(bool State); //obsluga pantografou przedniego - bool PantRear(bool State); //obsluga pantografu tylnego + bool PantFront( bool const State, int const Notify = command_range::consist ); //obsluga pantografou przedniego + bool PantRear( bool const State, int const Notify = command_range::consist ); //obsluga pantografu tylnego /*-funkcje typowe dla lokomotywy spalinowej z przekladnia mechaniczna*/ bool dizel_EngageSwitch(double state); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index a5a10dd5..63d3095b 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -76,7 +76,7 @@ int DirF(int CouplerN) // Q: 20160716 // Obliczanie natężenie prądu w silnikach // ************************************************************************************************* -double TMoverParameters::current(double n, double U) +double TMoverParameters::Current(double n, double U) { // wazna funkcja - liczy prad plynacy przez silniki polaczone szeregowo lub rownolegle // w zaleznosci od polozenia nastawnikow MainCtrl i ScndCtrl oraz predkosci obrotowej n @@ -337,11 +337,12 @@ Name( NameInit ) Couplers[b].DmaxC = 0.1; Couplers[b].FmaxC = 1000.0; } - for(int b = 0; b < 2; ++b ) { - HVCouplers[ b ][ 0 ] = 0.0; - HVCouplers[ b ][ 1 ] = 0.0; +#ifdef EU07_USE_OLD_HVCOUPLERS + for( int side = 0; side < 2; ++side ) { + HVCouplers[ side ][ hvcoupler::current ] = 0.0; + HVCouplers[ side ][ hvcoupler::voltage ] = 0.0; } - +#endif for( int b = 0; b < 3; ++b ) { BrakeCylMult[ b ] = 0.0; } @@ -705,47 +706,76 @@ bool TMoverParameters::CurrentSwitch(int direction) }; void TMoverParameters::UpdatePantVolume(double dt) -{ // KURS90 - sprężarka pantografów; Ra 2014-07: teraz jest to zbiornik rozrządu, chociaż to jeszcze - // nie tak +{ // KURS90 - sprężarka pantografów; Ra 2014-07: teraz jest to zbiornik rozrządu, chociaż to jeszcze nie tak + + // check the pantograph compressor while at it + if( PantCompFlag ) { + if( ( false == Battery ) + && ( false == ConverterFlag ) ) { + PantCompFlag = false; + } + } + if (EnginePowerSource.SourceType == CurrentCollector) // tylko jeśli pantografujący { - // Ra 2014-07: zasadniczo, to istnieje zbiornik rozrządu i zbiornik pantografów - na razie - // mamy razem - // Ra 2014-07: kurek trójdrogowy łączy spr.pom. z pantografami i wyłącznikiem ciśnieniowym - // WS + // Ra 2014-07: zasadniczo, to istnieje zbiornik rozrządu i zbiornik pantografów - na razie mamy razem + // Ra 2014-07: kurek trójdrogowy łączy spr.pom. z pantografami i wyłącznikiem ciśnieniowym WS // Ra 2014-07: zbiornika rozrządu nie pompuje się tu, tylko pantografy; potem można zamknąć // WS i odpalić resztę if ((TrainType == dt_EZT) ? (PantPress < ScndPipePress) : bPantKurek3) // kurek zamyka połączenie z ZG - { // zbiornik pantografu połączony ze zbiornikiem głównym - małą sprężarką się tego nie - // napompuje + { // zbiornik pantografu połączony ze zbiornikiem głównym - małą sprężarką się tego nie napompuje // Ra 2013-12: Niebugocław mówi, że w EZT nie ma potrzeby odcinać kurkiem - PantPress = EnginePowerSource.CollectorParameters - .MaxPress; // ograniczenie ciśnienia do MaxPress (tylko w pantografach!) - if (PantPress > ScndPipePress) - PantPress = ScndPipePress; // oraz do ScndPipePress + PantPress = ScndPipePress; + // ograniczenie ciśnienia do MaxPress (tylko w pantografach!) + PantPress = std::min( PantPress, EnginePowerSource.CollectorParameters.MaxPress ); + PantPress = std::max( PantPress, 0.0 ); PantVolume = (PantPress + 1.0) * 0.1; // objętość, na wypadek odcięcia kurkiem } else { // zbiornik główny odcięty, można pompować pantografy - if (PantCompFlag && Battery) // włączona bateria i mała sprężarka - PantVolume += dt * (TrainType == dt_EZT ? 0.003 : 0.005) * - (2.0 * 0.45 - ((0.1 / PantVolume / 10) - 0.1)) / - 0.45; // napełnianie zbiornika pantografów - // Ra 2013-12: Niebugocław mówi, że w EZT nabija 1.5 raz wolniej niż jak było 0.005 - PantPress = (10.0 * PantVolume) - 1.0; // tu by się przydała objętość zbiornika + if( PantCompFlag ) { + // włączona mała sprężarka + PantVolume += + dt + // Ra 2013-12: Niebugocław mówi, że w EZT nabija 1.5 raz wolniej niż jak było 0.005 + * ( TrainType == dt_EZT ? 0.003 : 0.005 ) / std::max( 1.0, PantPress ) + * ( 0.45 - ( ( 0.1 / PantVolume / 10 ) - 0.1 ) ) / 0.45; + } + PantPress = std::min( (10.0 * PantVolume) - 1.0, EnginePowerSource.CollectorParameters.MaxPress ); // tu by się przydała objętość zbiornika + PantPress = std::max( PantPress, 0.0 ); } - if (!PantCompFlag && (PantVolume > 0.1)) - PantVolume -= dt * 0.0003; // nieszczelności: 0.0003=0.3l/s - if (Mains) // nie wchodzić w funkcję bez potrzeby - if (EngineType == ElectricSeriesMotor) // nie dotyczy... czego właściwie? - if (PantPress < EnginePowerSource.CollectorParameters.MinPress) - if ((TrainType & (dt_EZT | dt_ET40 | dt_ET41 | dt_ET42)) ? - (GetTrainsetVoltage() < EnginePowerSource.CollectorParameters.MinV) : - true) // to jest trochę proteza; zasilanie członu może być przez sprzęg - // WN - if (MainSwitch(false)) - EventFlag = true; // wywalenie szybkiego z powodu niskiego ciśnienia + if( !PantCompFlag && ( PantVolume > 0.1 ) ) + PantVolume -= dt * 0.0003 * std::max( 1.0, PantPress * 0.5 ); // nieszczelności: 0.0003=0.3l/s +/* + // NOTE: disabled as this is redundant with check done in dynobj.update() + // TODO: determine if this isn't a mistake -- + // though unlikely it's possible this is emulation of a different circuit than the pantograph pressure switch, with similar function? + // TBD, TODO: alternatively, move the dynobj.update() subroutine here, as it doesn't touch elements outside of the mover object + if( Mains ) { + // nie wchodzić w funkcję bez potrzeby + if( EngineType == ElectricSeriesMotor ) { + // nie dotyczy... czego właściwie? + if( ( true == PantPressSwitchActive ) + && ( PantPress < EnginePowerSource.CollectorParameters.MinPress ) ) { + // wywalenie szybkiego z powodu niskiego ciśnienia + if( GetTrainsetVoltage() < 0.5 * EnginePowerSource.MaxVoltage ) { + // to jest trochę proteza; zasilanie członu może być przez sprzęg WN + if( MainSwitch( false, ( TrainType == dt_EZT ? command_range::unit : command_range::local ) ) ) { + EventFlag = true; + } + } + + // NOTE: disabled, the flag gets set in dynobj.update() when the pantograph actually drops + // mark the pressure switch as spent, regardless whether line breaker actually opened + PantPressSwitchActive = false; + + } + } + } +*/ +/* + // NOTE: pantograph tank pressure sharing experimentally disabled for more accurate simulation if (TrainType != dt_EZT) // w EN57 pompuje się tylko w silnikowym // pierwotnie w CHK pantografy miały również rozrządcze EZT for (int b = 0; b <= 1; ++b) @@ -757,6 +787,7 @@ void TMoverParameters::UpdatePantVolume(double dt) // czy np. w ET40, ET41, ET42 pantografy członów mają połączenie pneumatyczne? // Ra 2014-07: raczej nie - najpierw się załącza jeden człon, a potem można podnieść w // drugim +*/ } else { // a tu coś dla SM42 i SM31, aby pokazywać na manometrze @@ -1059,57 +1090,114 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap { const double Vepsilon = 1e-5; const double Aepsilon = 1e-3; // ASBSpeed=0.8; - int b; - double Vprev, AccSprev, d, hvc; + double Vprev, AccSprev, d; // T_MoverParameters::ComputeMovement(dt, dt1, Shape, Track, ElectricTraction, NewLoc, NewRot); // // najpierw kawalek z funkcji w pliku mover.pas TotalCurrent = 0; - hvc = Max0R(Max0R(PantFrontVolt, PantRearVolt), ElectricTraction.TractionVoltage * 0.9); - for (b = 0; b < 2; b++) // przekazywanie napiec - if (((Couplers[b].CouplingFlag & ctrain_power) == ctrain_power) || - (((Couplers[b].CouplingFlag & ctrain_heating) == ctrain_heating) && (Heating))) - { - HVCouplers[1 - b][1] = - Max0R(abs(hvc), Couplers[b].Connected->HVCouplers[Couplers[b].ConnectedNr][1] - - HVCouplers[b][0] * 0.02); + double hvc = + std::max( + std::max( + PantFrontVolt, + PantRearVolt ), + ElectricTraction.TractionVoltage * 0.9 ); + + for( int side = 0; side < 2; ++side ) { + // przekazywanie napiec + auto const oppositeside = ( side == side::front ? side::rear : side::front ); + + if( ( Couplers[ side ].CouplingFlag & ctrain_power ) + || ( ( Heating ) + && ( Couplers[ side ].CouplingFlag & ctrain_heating ) ) ) { +#ifdef EU07_USE_OLD_HVCOUPLERS + HVCouplers[ oppositeside ][ hvcoupler::voltage ] = + std::max( + std::abs( hvc ), + Couplers[ side ].Connected->HVCouplers[ Couplers[ side ].ConnectedNr ][ hvcoupler::voltage ] - HVCouplers[ side ][ hvcoupler::current ] * 0.02 ); +#else + auto const &connectedcoupler = Couplers[ side ].Connected->Couplers[ Couplers[ side ].ConnectedNr ]; + Couplers[ oppositeside ].power_high.voltage = + std::max( + std::abs( hvc ), + connectedcoupler.power_high.voltage - Couplers[ side ].power_high.current * 0.02 ); +#endif } - else - HVCouplers[1 - b][1] = abs(hvc) - HVCouplers[b][0] * 0.02; - // Max0R(Abs(Voltage),0); - // end; + else { +#ifdef EU07_USE_OLD_HVCOUPLERS + HVCouplers[ oppositeside ][ hvcoupler::voltage ] = std::abs( hvc ) - HVCouplers[ side ][ hvcoupler::current ] * 0.02; +#else + Couplers[ oppositeside ].power_high.voltage = std::abs( hvc ) - Couplers[ side ].power_high.current * 0.02; +#endif + } + } - hvc = HVCouplers[0][1] + HVCouplers[1][1]; +#ifdef EU07_USE_OLD_HVCOUPLERS + hvc = HVCouplers[ side::front ][ hvcoupler::voltage ] + HVCouplers[ side::rear ][ hvcoupler::voltage ]; +#else + hvc = Couplers[ side::front ].power_high.voltage + Couplers[ side::rear ].power_high.voltage; +#endif - if ((abs(PantFrontVolt) + abs(PantRearVolt) < 1) && - (hvc > 1)) // bez napiecia, ale jest cos na sprzegach: - { - for (b = 0; b < 2; ++b) // przekazywanie pradow - if (((Couplers[b].CouplingFlag & ctrain_power) == ctrain_power) || - (((Couplers[b].CouplingFlag & ctrain_heating) == ctrain_heating) && - (Heating))) // jesli spiety - { - HVCouplers[b][0] = - Couplers[b].Connected->HVCouplers[1 - Couplers[b].ConnectedNr][0] + - Itot * HVCouplers[b][1] / hvc; // obciążenie rozkladane stosownie do napiec - } - else // pierwszy pojazd - { - HVCouplers[b][0] = Itot * HVCouplers[b][1] / hvc; - } + if( ( std::abs( PantFrontVolt ) + std::abs( PantRearVolt ) < 1.0 ) + && ( hvc > 1.0 ) ) { + // bez napiecia, ale jest cos na sprzegach: + // przekazywanie pradow + for( int side = 0; side < 2; ++side ) { + + Couplers[ side ].power_high.local = false; // power, if any, will be from external source + + if( ( Couplers[ side ].CouplingFlag & ctrain_power ) + || ( ( Heating ) + && ( Couplers[ side ].CouplingFlag & ctrain_heating ) ) ) { +#ifdef EU07_USE_OLD_HVCOUPLERS + auto const oppositeside = ( Couplers[side].ConnectedNr == side::front ? side::rear : side::front ); + HVCouplers[ side ][ hvcoupler::current ] = + Couplers[side].Connected->HVCouplers[oppositeside][hvcoupler::current] + + Itot * HVCouplers[side][hvcoupler::voltage] / hvc; // obciążenie rozkladane stosownie do napiec +#else + auto const &connectedsothercoupler = + Couplers[ side ].Connected->Couplers[ + ( Couplers[ side ].ConnectedNr == side::front ? + side::rear : + side::front ) ]; + Couplers[ side ].power_high.current = + connectedsothercoupler.power_high.current + + Itot * Couplers[ side ].power_high.voltage / hvc; // obciążenie rozkladane stosownie do napiec +#endif + } + else { +#ifdef EU07_USE_OLD_HVCOUPLERS + // pierwszy pojazd + HVCouplers[side][hvcoupler::current] = Itot * HVCouplers[side][hvcoupler::voltage] / hvc; +#else + Couplers[ side ].power_high.current = Itot * Couplers[ side ].power_high.voltage / hvc; +#endif + } + } } else { - if (((Couplers[0].CouplingFlag & ctrain_power) == ctrain_power) || - (((Couplers[0].CouplingFlag & ctrain_heating) == ctrain_heating) && (Heating))) - TotalCurrent += - Couplers[0].Connected->HVCouplers[1 - Couplers[0].ConnectedNr][0]; - if (((Couplers[1].CouplingFlag & ctrain_power) == ctrain_power) || - (((Couplers[1].CouplingFlag & ctrain_heating) == ctrain_heating) && (Heating))) - TotalCurrent += - Couplers[1].Connected->HVCouplers[1 - Couplers[1].ConnectedNr][0]; - HVCouplers[0][0] = 0; - HVCouplers[1][0] = 0; + for( int side = 0; side < 2; ++side ) { + + Couplers[ side ].power_high.local = true; // power is coming from local pantographs + + if( ( Couplers[ side ].CouplingFlag & ctrain_power ) + || ( ( Heating ) + && ( Couplers[ side ].CouplingFlag & ctrain_heating ) ) ) { +#ifdef EU07_USE_OLD_HVCOUPLERS + auto const oppositeside = ( Couplers[ side ].ConnectedNr == side::front ? side::rear : side::front ); + TotalCurrent += Couplers[ side ].Connected->HVCouplers[ oppositeside ][ hvcoupler::current ]; + HVCouplers[ side ][ hvcoupler::current ] = 0.0; +#else + auto const &connectedsothercoupler = + Couplers[ side ].Connected->Couplers[ + ( Couplers[ side ].ConnectedNr == side::front ? + side::rear : + side::front ) ]; + TotalCurrent += connectedsothercoupler.power_high.current; + Couplers[ side ].power_high.current = 0.0; +#endif + } + } } if (!TestFlag(DamageFlag, dtrain_out)) @@ -1225,7 +1313,7 @@ double TMoverParameters::ComputeMovement(double dt, double dt1, const TTrackShap // przesuniecie dL = (3.0 * V - Vprev) * dt / 2.0; // metoda Adamsa-Bashfortha} // ale jesli jest kolizja (zas. zach. pedu) to...} - for (b = 0; b < 2; b++) + for (int b = 0; b < 2; b++) if (Couplers[b].CheckCollision) CollisionDetect(b, dt); // zmienia niejawnie AccS, V !!! @@ -1463,10 +1551,14 @@ double TMoverParameters::ShowEngineRotation(int VehN) void TMoverParameters::ConverterCheck() { // sprawdzanie przetwornicy - if (ConverterAllow && Mains) + if( ( ConverterAllow ) + && ( false == PantPressLockActive ) + && ( Mains ) ) { ConverterFlag = true; - else + } + else { ConverterFlag = false; + } }; double TMoverParameters::ShowCurrent(int AmpN) @@ -1964,23 +2056,43 @@ bool TMoverParameters::AddPulseForce(int Multipler) // Q: 20160713 // sypanie piasku // ************************************************************************************************* -bool TMoverParameters::SandDoseOn(void) +bool TMoverParameters::Sandbox( bool const State, int const Notify ) { - bool SDO; - if (SandCapacity > 0) - { - SDO = true; - if (SandDose) - SandDose = false; - else if (Sand > 0) - SandDose = true; - if (CabNo != 0) - SendCtrlToNext("SandDoseOn", 1, CabNo); - } - else - SDO = false; + bool result{ false }; - return SDO; + if( SandDose != State ) { + if( SandDose == false ) { + // switch on + if( Sand > 0 ) { + SandDose = true; + result = true; + } + } + else { + // switch off + SandDose = false; + result = true; + } + } + + if( Notify != command_range::local ) { + // if requested pass the command on + auto const couplingtype = + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ); + + if( State == true ) { + // switch on + SendCtrlToNext( "Sandbox", 1, CabNo, couplingtype ); + } + else { + // switch off + SendCtrlToNext( "Sandbox", 0, CabNo, couplingtype ); + } + } + + return result; } void TMoverParameters::SSReset(void) @@ -2203,18 +2315,18 @@ bool TMoverParameters::DirectionBackward(void) // ************************************************************************************************* bool TMoverParameters::AntiSlippingButton(void) { - return (AntiSlippingBrake() || SandDoseOn()); + // NOTE: disabled the sandbox part, it's already controlled by another part of the AI routine + return (AntiSlippingBrake() /*|| Sandbox(true)*/); } // ************************************************************************************************* // Q: 20160713 // włączenie / wyłączenie obwodu głownego // ************************************************************************************************* -bool TMoverParameters::MainSwitch(bool State) +bool TMoverParameters::MainSwitch( bool const State, int const Notify ) { - bool MS; + bool MS = false; // Ra: przeniesione z końca - MS = false; // Ra: przeniesione z końca if ((Mains != State) && (MainCtrlPosNo > 0)) { if ((State == false) || @@ -2222,13 +2334,29 @@ bool TMoverParameters::MainSwitch(bool State) (LastSwitchingTime > CtrlDelay) && !TestFlag(DamageFlag, dtrain_out) && !TestFlag(EngDmgFlag, 1))) { - if (Mains) // jeśli był załączony - SendCtrlToNext("MainSwitch", int(State), - CabNo); // wysłanie wyłączenia do pozostałych? + if( Mains ) { + // jeśli był załączony + if( Notify != command_range::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "MainSwitch", int( State ), CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } + } Mains = State; - if (Mains) // jeśli został załączony - SendCtrlToNext("MainSwitch", int(State), - CabNo); // wyslanie po wlaczeniu albo przed wylaczeniem + if( Mains ) { + // jeśli został załączony + if( Notify != command_range::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "MainSwitch", int( State ), CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } + } MS = true; // wartość zwrotna LastSwitchingTime = 0; if ((EngineType == DieselEngine) && Mains) @@ -2237,16 +2365,6 @@ bool TMoverParameters::MainSwitch(bool State) } if (((TrainType == dt_EZT) && (!State))) ConvOvldFlag = true; - // if (State=false) then //jeśli wyłączony - // begin - // SetFlag(SoundFlag,sound_relay); //hunter-091012: przeniesione do Train.cpp, zeby sie - // nie zapetlal - // if (SecuritySystem.Status<>12) then - // SecuritySystem.Status:=0; //deaktywacja czuwaka; Ra: a nie baterią? - // end - // else - // if (SecuritySystem.Status<>12) then - // SecuritySystem.Status:=s_waiting; //aktywacja czuwaka } } // else MainSwitch:=false; @@ -2257,9 +2375,10 @@ bool TMoverParameters::MainSwitch(bool State) // Q: 20160713 // włączenie / wyłączenie przetwornicy // ************************************************************************************************* -bool TMoverParameters::ConverterSwitch(bool State) +bool TMoverParameters::ConverterSwitch( bool State, int const Notify ) { bool CS = false; // Ra: normalnie chyba false? + if (ConverterAllow != State) { ConverterAllow = State; @@ -2267,10 +2386,24 @@ bool TMoverParameters::ConverterSwitch(bool State) if (CompressorPower == 2) CompressorAllow = ConverterAllow; } - if (ConverterAllow == true) - SendCtrlToNext("ConverterSwitch", 1, CabNo); - else - SendCtrlToNext("ConverterSwitch", 0, CabNo); + if( ConverterAllow == true ) { + if( Notify != command_range::local ) { + SendCtrlToNext( + "ConverterSwitch", 1, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } + } + else { + if( Notify != command_range::local ) { + SendCtrlToNext( + "ConverterSwitch", 0, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } + } return CS; } @@ -2279,7 +2412,7 @@ bool TMoverParameters::ConverterSwitch(bool State) // Q: 20160713 // włączenie / wyłączenie sprężarki // ************************************************************************************************* -bool TMoverParameters::CompressorSwitch(bool State) +bool TMoverParameters::CompressorSwitch( bool State, int const Notify ) { bool CS = false; // Ra: normalnie chyba tak? // if State=true then @@ -2290,10 +2423,24 @@ bool TMoverParameters::CompressorSwitch(bool State) CompressorAllow = State; CS = true; } - if (CompressorAllow == true) - SendCtrlToNext("CompressorSwitch", 1, CabNo); - else - SendCtrlToNext("CompressorSwitch", 0, CabNo); + if( CompressorAllow == true ) { + if( Notify != command_range::local ) { + SendCtrlToNext( + "CompressorSwitch", 1, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } + } + else { + if( Notify != command_range::local ) { + SendCtrlToNext( + "CompressorSwitch", 0, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } + } return CS; } @@ -2763,7 +2910,7 @@ bool TMoverParameters::BrakeDelaySwitch(int BDS) { BrakeDelayFlag = BDS; rBDS = true; - BrakeStatus &= 191; + Hamulec->SetBrakeStatus( Hamulec->GetBrakeStatus() & ~64 ); // kopowanie nastawy hamulca do kolejnego czlonu - do przemyślenia if (CabNo != 0) SendCtrlToNext("BrakeDelay", BrakeDelayFlag, CabNo); @@ -2898,15 +3045,21 @@ void TMoverParameters::CompressorCheck(double dt) else CompressorFlag = (CompressorAllow) && ((ConverterFlag) || (CompressorPower == 0)) && (Mains); - if (Compressor > - MaxCompressor) // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania + if( Compressor > MaxCompressor ) { + // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania CompressorFlag = false; + CompressorGovernorLock = true; // prevent manual activation until the pressure goes below cut-in level + } } else // jeśli nie załączona - if ((Compressor < MinCompressor) && - (LastSwitchingTime > CtrlDelay)) // jeśli nie załączona, a ciśnienie za małe - { // załączenie przy małym ciśnieniu - if (CompressorPower == 5) // jeśli zasilanie z następnego członu + if( ( ( Compressor < MinCompressor ) + || ( ( Compressor < MaxCompressor ) + && ( false == CompressorGovernorLock ) ) ) + && (LastSwitchingTime > CtrlDelay) ) { + // załączenie przy małym ciśnieniu + // jeśli nie załączona, a ciśnienie za małe + // or if the switch is on and the pressure isn't maxed + if( CompressorPower == 5 ) // jeśli zasilanie z następnego członu { // zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[1].Connected != NULL) CompressorFlag = @@ -2927,8 +3080,14 @@ void TMoverParameters::CompressorCheck(double dt) else CompressorFlag = (CompressorAllow) && ((ConverterFlag) || (CompressorPower == 0)) && (Mains); - if (CompressorFlag) // jeśli została załączona + if( CompressorFlag ) { + // jeśli została załączona LastSwitchingTime = 0; // to trzeba ograniczyć ponowne włączenie + if( Compressor < MinCompressor ) { + // if the activation took place at pressure below the cut-in level, we can reset compressor governor + CompressorGovernorLock = false; + } + } } // for b:=0 to 1 do //z Megapacka // with Couplers[b] do @@ -2994,12 +3153,17 @@ void TMoverParameters::UpdatePipePressure(double dt) else dpLocalValve = LocHandle->GetPF(LocalBrakePosA, Hamulec->GetBCP(), ScndPipePress, dt, 0); - if ((BrakeHandle == FV4a) && - ((PipePress < 2.75) && ((Hamulec->GetStatus() & b_rls) == 0)) && - (BrakeSubsystem == ss_LSt) && (TrainType != dt_EZT)) + + if( ( BrakeHandle == FV4a ) + && ( ( PipePress < 2.75 ) + && ( ( Hamulec->GetStatus() & b_rls ) == 0 ) ) + && ( BrakeSubsystem == ss_LSt ) + && ( TrainType != dt_EZT ) ) { temp = PipePress + 0.00001; - else + } + else { temp = ScndPipePress; + } Handle->SetReductor(BrakeCtrlPos2); if ((BrakeOpModeFlag != bom_PS)) @@ -3141,20 +3305,21 @@ void TMoverParameters::UpdatePipePressure(double dt) if ((BrakeHandle == FVel6) && (ActiveCab != 0)) { - if ((Battery) && (ActiveDir != 0) && - (EpFuse)) // tu powinien byc jeszcze bezpiecznik EP i baterie - + if ((Battery) + && (ActiveDir != 0) + && (EpFuse)) // tu powinien byc jeszcze bezpiecznik EP i baterie - // temp = (Handle as TFVel6).GetCP temp = Handle->GetCP(); else temp = 0.0; Hamulec->SetEPS(temp); - SendCtrlToNext("Brake", temp, - CabNo); // Ra 2014-11: na tym się wysypuje, ale nie wiem, w jakich warunkach + // Ra 2014-11: na tym się wysypuje, ale nie wiem, w jakich warunkach + SendCtrlToNext("Brake", temp, CabNo); } Pipe->Act(); PipePress = Pipe->P(); - if ((BrakeStatus & 128) == 128) // jesli hamulec wyłączony + if( ( Hamulec->GetBrakeStatus() & b_dmg ) == b_dmg ) // jesli hamulec wyłączony temp = 0.0; // odetnij else temp = 1.0; // połącz @@ -3231,14 +3396,17 @@ void TMoverParameters::UpdateScndPipePressure(double dt) } Pipe2->Flow(Hamulec->GetHPFlow(ScndPipePress, dt)); - +/* + // NOTE: condition disabled to allow the air flow from the main hose to the main tank as well if (((Compressor > ScndPipePress) && (CompressorSpeed > 0.0001)) || (TrainType == dt_EZT)) { +*/ dV = PF(Compressor, ScndPipePress, Spz) * dt; CompressedVolume += dV / 1000.0; Pipe2->Flow(-dV); +/* } - +*/ Pipe2->Flow(dv1 + dv2); Pipe2->Act(); ScndPipePress = Pipe2->P(); @@ -3407,23 +3575,30 @@ void TMoverParameters::ComputeTotalForce(double dt, double dt1, bool FullVer) LastSwitchingTime += dt1; if (EngineType == ElectricSeriesMotor) LastRelayTime += dt1; - if (Mains && /*(abs(CabNo) < 2) &&*/ (EngineType == - ElectricSeriesMotor)) // potem ulepszyc! pantogtrafy! + if( Mains && /*(abs(CabNo) < 2) &&*/ ( EngineType == ElectricSeriesMotor ) ) // potem ulepszyc! pantogtrafy! { // Ra 2014-03: uwzględnienie kierunku jazdy w napięciu na silnikach, a powinien być - // zdefiniowany nawrotnik - if (CabNo == 0) + // zdefiniowany nawrotnik + if( CabNo == 0 ) Voltage = RunningTraction.TractionVoltage * ActiveDir; else Voltage = RunningTraction.TractionVoltage * DirAbsolute; // ActiveDir*CabNo; } // bo nie dzialalo - else if ((EngineType == ElectricInductionMotor) || - (((Couplers[0].CouplingFlag & ctrain_power) == ctrain_power) || - ((Couplers[1].CouplingFlag & ctrain_power) == - ctrain_power))) // potem ulepszyc! pantogtrafy! - Voltage = - Max0R(Max0R(RunningTraction.TractionVoltage, HVCouplers[0][1]), HVCouplers[1][1]); - else + else if( ( EngineType == ElectricInductionMotor ) + || ( ( ( Couplers[ side::front ].CouplingFlag & ctrain_power ) == ctrain_power ) + || ( ( Couplers[ side::rear ].CouplingFlag & ctrain_power ) == ctrain_power ) ) ) { + // potem ulepszyc! pantogtrafy! + Voltage = + std::max( + RunningTraction.TractionVoltage, +#ifdef EU07_USE_OLD_HVCOUPLERS + std::max( HVCouplers[side::front][hvcoupler::voltage], HVCouplers[side::rear][hvcoupler::voltage] ) ); +#else + std::max( Couplers[ side::front ].power_high.voltage, Couplers[ side::rear ].power_high.voltage ) ); +#endif + } + else { Voltage = 0; + } //if (Mains && /*(abs(CabNo) < 2) &&*/ ( // EngineType == ElectricInductionMotor)) // potem ulepszyc! pantogtrafy! // Voltage = RunningTraction.TractionVoltage; @@ -3936,7 +4111,7 @@ double TMoverParameters::TractionForce(double dt) // yB: szereg dwoch sekcji w ET42 if ((TrainType == dt_ET42) && (Imax == ImaxHi)) Voltage = Voltage / 2.0; - Mm = Momentum(current(enrot, Voltage)); // oblicza tez prad p/slinik + Mm = Momentum(Current(enrot, Voltage)); // oblicza tez prad p/slinik if (TrainType == dt_ET42) { @@ -3975,10 +4150,10 @@ double TMoverParameters::TractionForce(double dt) FuseOff(); // wywalanie bezpiecznika z powodu przetezenia silnikow if ((Mains)) // nie wchodzić w funkcję bez potrzeby - if ((abs(Voltage) < EnginePowerSource.CollectorParameters.MinV) || - (abs(Voltage) * EnginePowerSource.CollectorParameters.OVP > + if ( (std::max(GetTrainsetVoltage(), std::abs(Voltage)) < EnginePowerSource.CollectorParameters.MinV) || + (std::max(GetTrainsetVoltage(), std::abs(Voltage)) * EnginePowerSource.CollectorParameters.OVP > EnginePowerSource.CollectorParameters.MaxV)) - if (MainSwitch(false)) + if( MainSwitch( false, ( TrainType == dt_EZT ? command_range::unit : command_range::local ) ) ) // TODO: check whether we need to send this EMU-wide EventFlag = true; // wywalanie szybkiego z powodu niewłaściwego napięcia if (((DynamicBrakeType == dbrake_automatic) || (DynamicBrakeType == dbrake_switch)) && @@ -4130,73 +4305,85 @@ double TMoverParameters::TractionForce(double dt) case 0: { - if( ( Im <= ( MPTRelay[ ScndCtrlPos ].Iup * PosRatio ) ) && - ( ScndCtrlPos < ScndCtrlPosNo ) ) - ++ScndCtrlPos; - if( ( Im >= ( MPTRelay[ ScndCtrlPos ].Idown * PosRatio ) ) && ( ScndCtrlPos > 0 ) ) - --ScndCtrlPos; - break; - } + if( ( ScndCtrlPos < ScndCtrlPosNo ) + && ( Im <= ( MPTRelay[ ScndCtrlPos ].Iup * PosRatio ) ) ) { + ++ScndCtrlPos; + } + if( ( ScndCtrlPos > 0 ) + && ( Im >= ( MPTRelay[ScndCtrlPos].Idown * PosRatio ) ) ) { + --ScndCtrlPos; + } + break; + } case 1: { - if( ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) && ( ScndCtrlPos < ScndCtrlPosNo ) ) - ++ScndCtrlPos; - if( ( MPTRelay[ ScndCtrlPos ].Idown > Vel ) && ( ScndCtrlPos > 0 ) ) - --ScndCtrlPos; - break; - } + if( ( ScndCtrlPos < ScndCtrlPosNo ) + && ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) ) { + ++ScndCtrlPos; + } + if( ( ScndCtrlPos > 0 ) + && ( MPTRelay[ ScndCtrlPos ].Idown > Vel ) ) { + --ScndCtrlPos; + } + break; + } case 2: { - if( ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) && ( ScndCtrlPos < ScndCtrlPosNo ) && - ( EnginePower < ( tmp * 0.99 ) ) ) - ++ScndCtrlPos; - if( ( MPTRelay[ ScndCtrlPos ].Idown < Im ) && ( ScndCtrlPos > 0 ) ) - --ScndCtrlPos; - break; - } - case 41: - { - if( ( MainCtrlPos == MainCtrlPosNo ) - && ( tmpV * 3.6 > MPTRelay[ ScndCtrlPos ].Iup ) - && ( ScndCtrlPos < ScndCtrlPosNo ) ) { - ++ScndCtrlPos; - enrot = enrot * 0.73; - } - if( ( Im > MPTRelay[ ScndCtrlPos ].Idown ) - && ( ScndCtrlPos > 0 ) ) { - --ScndCtrlPos; + if( ( ScndCtrlPos < ScndCtrlPosNo ) + && ( MPTRelay[ ScndCtrlPos ].Iup < Vel ) + && ( EnginePower < ( tmp * 0.99 ) ) ) { + ++ScndCtrlPos; } - break; - } - case 45: - { - if( ( MainCtrlPos >= 10 ) && ( ScndCtrlPos < ScndCtrlPosNo ) ) { + if( ( ScndCtrlPos > 0 ) + && ( MPTRelay[ ScndCtrlPos ].Idown < Im ) ) { + --ScndCtrlPos; + } + break; + } + case 41: + { + if( ( ScndCtrlPos < ScndCtrlPosNo ) + && ( MainCtrlPos == MainCtrlPosNo ) + && ( tmpV * 3.6 > MPTRelay[ ScndCtrlPos ].Iup ) ) { + ++ScndCtrlPos; + enrot = enrot * 0.73; + } + if( ( ScndCtrlPos > 0 ) + && ( Im > MPTRelay[ ScndCtrlPos ].Idown ) ) { + --ScndCtrlPos; + } + break; + } + case 45: + { + if( ( ScndCtrlPos < ScndCtrlPosNo ) + && ( MainCtrlPos >= 10 ) ) { if( ScndCtrlPos == 0 ) { if( Im < MPTRelay[ ScndCtrlPos ].Iup ) { - ++ScndCtrlPos; + ++ScndCtrlPos; } } else { if( Vel > MPTRelay[ ScndCtrlPos ].Iup ) { - ++ScndCtrlPos; + ++ScndCtrlPos; } // check for cases where the speed drops below threshold for level 2 or 3 if( ( ScndCtrlPos > 1 ) - && ( Vel < MPTRelay[ ScndCtrlPos - 1 ].Idown ) ){ + && ( Vel < MPTRelay[ ScndCtrlPos - 1 ].Idown ) ) { --ScndCtrlPos; } } } - // malenie + // malenie if( ( ScndCtrlPos > 0 ) && ( MainCtrlPos < 10 ) ) { if( ScndCtrlPos == 1 ) { if( Im > MPTRelay[ ScndCtrlPos - 1 ].Idown ) { - --ScndCtrlPos; + --ScndCtrlPos; } } else { if( Vel < MPTRelay[ ScndCtrlPos ].Idown ) { - --ScndCtrlPos; + --ScndCtrlPos; } } } @@ -4206,13 +4393,13 @@ double TMoverParameters::TractionForce(double dt) } // ...and below position 7 field shunt drops altogether if( MainCtrlPos < 7 ) { - ScndCtrlPos = 0; - } + ScndCtrlPos = 0; + } break; } - case 46: - { - // wzrastanie + case 46: + { + // wzrastanie if( ( MainCtrlPos >= 10 ) && ( ScndCtrlPos < ScndCtrlPosNo ) ) { if( ( ScndCtrlPos ) % 2 == 0 ) { @@ -4227,18 +4414,18 @@ double TMoverParameters::TractionForce(double dt) } } } - // malenie + // malenie if( ( MainCtrlPos < 10 ) && ( ScndCtrlPos > 0 ) ) { if( ( ScndCtrlPos ) % 2 == 0 ) { if( ( MPTRelay[ ScndCtrlPos ].Idown < Im ) ) { - --ScndCtrlPos; + --ScndCtrlPos; } } else { if( ( MPTRelay[ ScndCtrlPos + 1 ].Idown < Im ) && ( MPTRelay[ ScndCtrlPos ].Idown > Vel ) ) { - --ScndCtrlPos; + --ScndCtrlPos; } } } @@ -4246,14 +4433,14 @@ double TMoverParameters::TractionForce(double dt) ScndCtrlPos = std::min( 2, ScndCtrlPos ); } if( MainCtrlPos < 7 ) { - ScndCtrlPos = 0; - } + ScndCtrlPos = 0; + } break; } default: { break; } - } // switch RelayType + } // switch RelayType } } break; @@ -4263,11 +4450,11 @@ double TMoverParameters::TractionForce(double dt) { if( ( Mains ) ) { // nie wchodzić w funkcję bez potrzeby - if( ( abs( Voltage ) < EnginePowerSource.CollectorParameters.MinV ) - || ( abs( Voltage ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) { - MainSwitch( false ); - } + if( ( std::max( std::abs( Voltage ), GetTrainsetVoltage() ) < EnginePowerSource.CollectorParameters.MinV ) + || ( std::max( std::abs( Voltage ), GetTrainsetVoltage() ) > EnginePowerSource.CollectorParameters.MaxV + 200 ) ) { + MainSwitch( false, ( TrainType == dt_EZT ? command_range::unit : command_range::local ) ); // TODO: check whether we need to send this EMU-wide } + } tmpV = abs(nrot) * (PI * WheelDiameter) * 3.6; //*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp if ((Mains)) { @@ -4332,26 +4519,28 @@ double TMoverParameters::TractionForce(double dt) dmoment = eimv[eimv_Fful]; // else // dmoment:=eimc[eimc_p_F0]*0.99; + // NOTE: the commands to operate the sandbox are likely to conflict with other similar ai decisions + // TODO: gather these in single place so they can be resolved together if ((abs((PosRatio + 9.66 * dizel_fill) * dmoment * 100) > 0.95 * Adhesive(RunningTrack.friction) * TotalMassxg)) { PosRatio = 0; tmp = 4; - SandDoseOn(); + Sandbox( true, command_range::local ); } // przeciwposlizg if ((abs((PosRatio + 9.80 * dizel_fill) * dmoment * 100) > 0.95 * Adhesive(RunningTrack.friction) * TotalMassxg)) { PosRatio = 0; tmp = 9; - SandDoseOn(); + Sandbox( true, command_range::local ); } // przeciwposlizg if ((SlippingWheels)) { // PosRatio = -PosRatio * 0; // serio -0 ??? PosRatio = 0; tmp = 9; - SandDoseOn(); + Sandbox( true, command_range::local ); } // przeciwposlizg dizel_fill += Max0R(Min0R(PosRatio - dizel_fill, 0.1), -0.1) * 2 * @@ -4979,23 +5168,39 @@ bool TMoverParameters::AutoRelayCheck(void) // Q: 20160713 // Podnosi / opuszcza przedni pantograf. Returns: state of the pantograph after the operation // ************************************************************************************************* -bool TMoverParameters::PantFront(bool State) +bool TMoverParameters::PantFront( bool const State, int const Notify ) { +/* if( ( true == Battery ) || ( true == ConverterFlag ) ) { - +*/ if( PantFrontUp != State ) { PantFrontUp = State; if( State == true ) { PantFrontStart = 0; - SendCtrlToNext( "PantFront", 1, CabNo ); + if( Notify != command_range::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "PantFront", 1, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } } else { PantFrontStart = 1; - SendCtrlToNext( "PantFront", 0, CabNo ); - } + if( Notify != command_range::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "PantFront", 0, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } } } +/* + } else { // no power, drop the pantograph // NOTE: this is a simplification as it should just drop on its own with loss of pressure without resupply from (dead) compressor @@ -5004,9 +5209,11 @@ bool TMoverParameters::PantFront(bool State) 1 : 0 ); PantFrontUp = false; - SendCtrlToNext( "PantFront", 0, CabNo ); + if( true == Multiunitcontrol ) { + SendCtrlToNext( "PantFront", 0, CabNo ); + } } - +*/ return PantFrontUp; } @@ -5014,23 +5221,39 @@ bool TMoverParameters::PantFront(bool State) // Q: 20160713 // Podnoszenie / opuszczanie pantografu tylnego // ************************************************************************************************* -bool TMoverParameters::PantRear(bool State) +bool TMoverParameters::PantRear( bool const State, int const Notify ) { +/* if( ( true == Battery ) || ( true == ConverterFlag ) ) { - +*/ if( PantRearUp != State ) { PantRearUp = State; if( State == true ) { PantRearStart = 0; - SendCtrlToNext( "PantRear", 1, CabNo ); + if( Notify != command_range::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "PantRear", 1, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } } else { PantRearStart = 1; - SendCtrlToNext( "PantRear", 0, CabNo ); - } + if( Notify != command_range::local ) { + // wysłanie wyłączenia do pozostałych? + SendCtrlToNext( + "PantRear", 0, CabNo, + ( Notify == command_range::unit ? + ctrain_controll | ctrain_depot : + ctrain_controll ) ); + } } } +/* + } else { // no power, drop the pantograph // NOTE: this is a simplification as it should just drop on its own with loss of pressure without resupply from (dead) compressor @@ -5039,9 +5262,11 @@ bool TMoverParameters::PantRear(bool State) 1 : 0 ); PantRearUp = false; - SendCtrlToNext( "PantRear", 0, CabNo ); + if( true == Multiunitcontrol ) { + SendCtrlToNext( "PantRear", 0, CabNo ); + } } - +*/ return PantRearUp; } @@ -5476,7 +5701,7 @@ std::string TMoverParameters::EngineDescription(int what) case 0: { if (DamageFlag == 255) - outstr = "Totally destroyed!"; + outstr = "WRECKED"; else { if (TestFlag(DamageFlag, dtrain_thinwheel)) @@ -5500,13 +5725,13 @@ std::string TMoverParameters::EngineDescription(int what) if (Power > 0.1) outstr = "Engine damaged,"; else - outstr = "Load destroyed!,"; + outstr = "LOAD DESTROYED,"; if (TestFlag(DamageFlag, dtrain_axle)) outstr = "Axle broken,"; if (TestFlag(DamageFlag, dtrain_out)) - outstr = "DERAILED!"; + outstr = "DERAILED"; if (outstr == "") - outstr = "OK!"; + outstr = "OK"; } break; } @@ -5523,7 +5748,30 @@ std::string TMoverParameters::EngineDescription(int what) // ************************************************************************************************* double TMoverParameters::GetTrainsetVoltage(void) {//ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT - return Max0R(HVCouplers[1][1], HVCouplers[0][1]); +#ifdef EU07_USE_OLD_HVCOUPLERS + return std::max( + HVCouplers[ side::front ][ hvcoupler::voltage ], + HVCouplers[ side::rear ][ hvcoupler::voltage ] ); +#else +/* + return std::max( + Couplers[ side::front ].power_high.voltage, + Couplers[ side::rear ].power_high.voltage ); +*/ + return std::max( + ( ( ( Couplers[side::front].Connected ) + && ( ( Couplers[ side::front ].CouplingFlag & ctrain_power ) + || ( ( Heating ) + && ( Couplers[ side::front ].CouplingFlag & ctrain_heating ) ) ) ) ? + Couplers[side::front].Connected->Couplers[ Couplers[side::front].ConnectedNr ].power_high.voltage : + 0.0 ), + ( ( ( Couplers[side::rear].Connected ) + && ( ( Couplers[ side::rear ].CouplingFlag & ctrain_power ) + || ( ( Heating ) + && ( Couplers[ side::rear ].CouplingFlag & ctrain_heating ) ) ) ) ? + Couplers[ side::rear ].Connected->Couplers[ Couplers[ side::rear ].ConnectedNr ].power_high.voltage : + 0.0 ) ); +#endif } // ************************************************************************************************* @@ -7089,8 +7337,8 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet extract_value( collectorparameters.MaxV, "MaxVoltage", Line, "" ); collectorparameters.OVP = //przekaźnik nadnapięciowy extract_value( "OverVoltProt", Line ) == "Yes" ? - 1 : - 0; + 1 : + 0; //napięcie rozłączające WS collectorparameters.MinV = 0.5 * collectorparameters.MaxV; //gdyby parametr nie podany extract_value( collectorparameters.MinV, "MinV", Line, "" ); @@ -7098,7 +7346,7 @@ void TMoverParameters::LoadFIZ_PowerParamsDecode( TPowerParameters &Powerparamet collectorparameters.InsetV = 0.6 * collectorparameters.MaxV; //gdyby parametr nie podany extract_value( collectorparameters.InsetV, "InsetV", Line, "" ); //ciśnienie rozłączające WS - extract_value( collectorparameters.MinPress, "MinPress", Line, "2.0" ); //domyślnie 2 bary do załączenia WS + extract_value( collectorparameters.MinPress, "MinPress", Line, "3.5" ); //domyślnie 2 bary do załączenia WS //maksymalne ciśnienie za reduktorem collectorparameters.MaxPress = 5.0 + 0.001 * ( Random( 50 ) - Random( 50 ) ); extract_value( collectorparameters.MaxPress, "MaxPress", Line, "" ); @@ -7524,18 +7772,20 @@ bool TMoverParameters::SendCtrlBroadcast(std::string CtrlCommand, double ctrlval // Q: 20160714 // Ustawienie komendy wraz z parametrami // ************************************************************************************************* -bool TMoverParameters::SetInternalCommand(std::string NewCommand, double NewValue1, - double NewValue2) +bool TMoverParameters::SetInternalCommand(std::string NewCommand, double NewValue1, double NewValue2, int const Couplertype) { bool SIC; - if ((CommandIn.Command == NewCommand) && (CommandIn.Value1 == NewValue1) && - (CommandIn.Value2 == NewValue2)) + if( ( CommandIn.Command == NewCommand ) + && ( CommandIn.Value1 == NewValue1 ) + && ( CommandIn.Value2 == NewValue2 ) + && ( CommandIn.Coupling == Couplertype ) ) SIC = false; else { CommandIn.Command = NewCommand; CommandIn.Value1 = NewValue1; CommandIn.Value2 = NewValue2; + CommandIn.Coupling = Couplertype; SIC = true; LastLoadChangeTime = 0; // zerowanie czasu (roz)ładowania } @@ -7547,7 +7797,7 @@ bool TMoverParameters::SetInternalCommand(std::string NewCommand, double NewValu // Q: 20160714 // wysyłanie komendy w kierunku dir (1=przód, -1=tył) do kolejnego pojazdu (jednego) // ************************************************************************************************* -bool TMoverParameters::SendCtrlToNext( std::string CtrlCommand, double ctrlvalue, double dir ) { +bool TMoverParameters::SendCtrlToNext( std::string const CtrlCommand, double const ctrlvalue, double const dir, int const Couplertype ) { bool OK; int d; // numer sprzęgu w kierunku którego wysyłamy @@ -7558,15 +7808,15 @@ bool TMoverParameters::SendCtrlToNext( std::string CtrlCommand, double ctrlvalue if( OK ) { // musi być wybrana niezerowa kabina if( ( Couplers[ d ].Connected != nullptr ) - && ( TestFlag( Couplers[ d ].CouplingFlag, ctrain_controll ) ) ) { + && ( TestFlag( Couplers[ d ].CouplingFlag, Couplertype ) ) ) { if( Couplers[ d ].ConnectedNr != d ) { // jeśli ten nastpęny jest zgodny z aktualnym - if( Couplers[ d ].Connected->SetInternalCommand( CtrlCommand, ctrlvalue, dir ) ) + if( Couplers[ d ].Connected->SetInternalCommand( CtrlCommand, ctrlvalue, dir, Couplertype ) ) OK = ( Couplers[ d ].Connected->RunInternalCommand() && OK ); // tu jest rekurencja } else { // jeśli następny jest ustawiony przeciwnie, zmieniamy kierunek - if( Couplers[ d ].Connected->SetInternalCommand( CtrlCommand, ctrlvalue, -dir ) ) + if( Couplers[ d ].Connected->SetInternalCommand( CtrlCommand, ctrlvalue, -dir, Couplertype ) ) OK = ( Couplers[ d ].Connected->RunInternalCommand() && OK ); // tu jest rekurencja } } @@ -7585,7 +7835,7 @@ bool TMoverParameters::SendCtrlToNext( std::string CtrlCommand, double ctrlvalue // Komenda musi być zdefiniowana tutaj, a jeśli się wywołuje funkcję, to ona nie może // sama przesyłać do kolejnych pojazdów. Należy też się zastanowić, czy dla uzyskania // jakiejś zmiany (np. IncMainCtrl) lepiej wywołać funkcję, czy od razu wysłać komendę. -bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CValue2) +bool TMoverParameters::RunCommand( std::string Command, double CValue1, double CValue2, int const Couplertype ) { bool OK; std::string testload; @@ -7595,7 +7845,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV { if (MainCtrlPosNo >= floor(CValue1)) MainCtrlPos = static_cast(floor(CValue1)); - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext(Command, CValue1, CValue2, Couplertype); } else if (Command == "ScndCtrl") { @@ -7609,7 +7859,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV ScndCtrlActualPos = 0; if (ScndCtrlPosNo >= floor(CValue1)) ScndCtrlPos = static_cast(floor(CValue1)); - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } /* else if command='BrakeCtrl' then begin @@ -7624,7 +7874,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV Hamulec->SetEPS(CValue1); // fBrakeCtrlPos:=BrakeCtrlPos; //to powinnno być w jednym miejscu, aktualnie w C++!!! BrakePressureActual = BrakePressureTable[BrakeCtrlPos]; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } // youby - odluzniacz hamulcow, przyda sie else if (Command == "BrakeReleaser") { @@ -7641,13 +7891,13 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV } else Mains = false; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "Direction") { ActiveDir = static_cast(floor(CValue1)); DirAbsolute = ActiveDir * CabNo; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "CabActivisation") { @@ -7668,7 +7918,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV } } DirAbsolute = ActiveDir * CabNo; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "AutoRelaySwitch") { @@ -7676,7 +7926,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV AutoRelayFlag = true; else AutoRelayFlag = false; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "FuseSwitch") { @@ -7688,7 +7938,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV // if ((EngineType=ElectricSeriesMotor)or(EngineType=DieselElectric)) and not FuseFlag and // (CValue1=0) and Mains then // FuseFlag:=true; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "ConverterSwitch") /*NBMX*/ { @@ -7696,7 +7946,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV ConverterAllow = true; else if ((CValue1 == 0)) ConverterAllow = false; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "BatterySwitch") /*NBMX*/ { @@ -7708,7 +7958,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV SecuritySystem.Status = SecuritySystem.Status || s_waiting; // aktywacja czuwaka else SecuritySystem.Status = 0; // wyłączenie czuwaka - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } // else if command='EpFuseSwitch' then {NBMX} // begin @@ -7722,7 +7972,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV CompressorAllow = true; else if ((CValue1 == 0)) CompressorAllow = false; - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "DoorOpen") /*NBMX*/ { // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów @@ -7740,7 +7990,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV if ((CValue1 == 1) || (CValue1 == 3)) DoorRightOpened = true; } - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "DoorClose") /*NBMX*/ { // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów @@ -7758,7 +8008,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV if ((CValue1 == 1) || (CValue1 == 3)) DoorRightOpened = false; } - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "PantFront") /*Winger 160204*/ { // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów @@ -7803,7 +8053,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV PantRearStart = 1; } } - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "PantRear") /*Winger 160204, ABu 310105 i 030305*/ { // Ra: uwzględnić trzeba jeszcze zgodność sprzęgów @@ -7848,7 +8098,7 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV PantFrontStart = 1; } } - OK = SendCtrlToNext(Command, CValue1, CValue2); + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } else if (Command == "MaxCurrentSwitch") { @@ -7875,15 +8125,18 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV } else if (Command == "BrakeDelay") { - BrakeDelayFlag = static_cast(floor(CValue1)); - OK = true; + auto const brakesetting = static_cast( std::floor( CValue1 ) ); + if( true == Hamulec->SetBDF( brakesetting ) ) { + BrakeDelayFlag = brakesetting; + OK = true; + } + else { + OK = false; + } } - else if (Command == "SandDoseOn") + else if (Command == "Sandbox") { - if (SandDoseOn()) - OK = true; - else - OK = false; + OK = Sandbox( CValue1 == 1, command_range::local ); } else if (Command == "CabSignal") /*SHP,Indusi*/ { // Ra: to powinno działać tylko w członie obsadzonym @@ -7934,19 +8187,19 @@ bool TMoverParameters::RunCommand(std::string Command, double CValue1, double CV // Q: 20160714 // Uruchamia funkcję RunCommand aż do skutku. Jeśli będzie pozytywny to kasuje komendę. // ************************************************************************************************* -bool TMoverParameters::RunInternalCommand(void) +bool TMoverParameters::RunInternalCommand() { bool OK; if (!CommandIn.Command.empty()) { - OK = RunCommand(CommandIn.Command, CommandIn.Value1, CommandIn.Value2); - if (OK) + OK = RunCommand( CommandIn.Command, CommandIn.Value1, CommandIn.Value2, CommandIn.Coupling ); + if (OK) { - { CommandIn.Command.clear(); // kasowanie bo rozkaz wykonany CommandIn.Value1 = 0; CommandIn.Value2 = 0; + CommandIn.Coupling = 0; CommandIn.Location.X = 0; CommandIn.Location.Y = 0; CommandIn.Location.Z = 0; diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index daab0a22..bdc01fee 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -16,6 +16,7 @@ Copyright (C) 2007-2014 Maciej Cierniak #include "hamulce.h" #include #include "Mover.h" +#include "usefull.h" //---FUNKCJE OGOLNE--- @@ -51,10 +52,10 @@ double PF_old(double P1, double P2, double S) double PF( double const P1, double const P2, double const S, double const DP ) { - double PH = std::max(P1, P2) + 1; // wyzsze cisnienie absolutne - double PL = P1 + P2 - PH + 2; // nizsze cisnienie absolutne - double sg = PL / PH; // bezwymiarowy stosunek cisnien - double FM = PH * 197 * S * Sign(P2 - P1); // najwyzszy mozliwy przeplyw, wraz z kierunkiem + double const PH = std::max(P1, P2) + 1.0; // wyzsze cisnienie absolutne + double const PL = P1 + P2 - PH + 2.0; // nizsze cisnienie absolutne + double const sg = PL / PH; // bezwymiarowy stosunek cisnien + double const FM = PH * 197.0 * S * Sign(P2 - P1); // najwyzszy mozliwy przeplyw, wraz z kierunkiem if (sg > 0.5) // jesli ponizej stosunku krytycznego if ((PH - PL) < DP) // niewielka roznica cisnien return (1.0 - sg) / DPL * FM * 2.0 * std::sqrt((DP) * (PH - DP)); @@ -69,15 +70,15 @@ double PF1( double const P1, double const P2, double const S ) { static double const DPS = 0.001; - double PH = std::max(P1, P2) + 1; // wyzsze cisnienie absolutne - double PL = P1 + P2 - PH + 2; // nizsze cisnienie absolutne - double sg = PL / PH; // bezwymiarowy stosunek cisnien - double FM = PH * 197 * S * Sign(P2 - P1); // najwyzszy mozliwy przeplyw, wraz z kierunkiem - if ((sg > 0.5)) // jesli ponizej stosunku krytycznego - if ((sg < DPS)) // niewielka roznica cisnien - return (1 - sg) / DPS * FM * 2 * std::sqrt((DPS) * (1 - DPS)); + double const PH = std::max(P1, P2) + 1.0; // wyzsze cisnienie absolutne + double const PL = P1 + P2 - PH + 2.0; // nizsze cisnienie absolutne + double const sg = PL / PH; // bezwymiarowy stosunek cisnien + double const FM = PH * 197.0 * S * Sign(P2 - P1); // najwyzszy mozliwy przeplyw, wraz z kierunkiem + if (sg > 0.5) // jesli ponizej stosunku krytycznego + if (sg < DPS) // niewielka roznica cisnien + return (1.0 - sg) / DPS * FM * 2.0 * std::sqrt((DPS) * (1.0 - DPS)); else - return FM * 2 * std::sqrt((sg) * (1 - sg)); + return FM * 2.0 * std::sqrt((sg) * (1.0 - sg)); else // powyzej stosunku krytycznego return FM; } @@ -1184,50 +1185,50 @@ void TESt3AL2::Init( double const PP, double const HPP, double const LPP, double double TLSt::GetPF( double const PP, double const dt, double const Vel ) { double result; - double dv; - double dV1; - double temp; - double VVP; - double BVP; - double BCP; - double CVP; // ValveRes.CreatePress(LBP); // LBP:=0; - BVP = BrakeRes->P(); - VVP = ValveRes->P(); - BCP = ImplsRes->P(); - CVP = CntrlRes->P(); + double const BVP{ BrakeRes->P() }; + double const VVP{ ValveRes->P() }; + double const BCP{ ImplsRes->P() }; + double const CVP{ CntrlRes->P() }; - dv = 0; - dV1 = 0; + double dV{ 0.0 }; + double dV1{ 0.0 }; // sprawdzanie stanu - if ((BrakeStatus & b_rls) == b_rls) - if ((CVP < 0)) + if( ( BrakeStatus & b_rls ) == b_rls ) { + if( CVP < 0.0 ) { BrakeStatus &= ~b_rls; + } else { // 008 - dv = PF1(CVP, BCP, 0.024) * dt; - CntrlRes->Flow(+dv); - // dV1:=+dV; //minus potem jest - // ImplsRes->Flow(-dV1); + dV = PF1( CVP, BCP, 0.024 ) * dt; + CntrlRes->Flow( dV ); +/* + // NOTE: attempted fix, disabled because it breaks when releaser is used while releasing breakes + dV = PF1(CVP, VVP, 0.024) * dt; + CntrlRes->Flow( dV ); + dV1 = dV; //minus potem jest + ImplsRes->Flow( -dV1 ); +*/ } + } - VVP = ValveRes->P(); + double temp; // przeplyw ZS <-> PG if (((CVP - BCP) * BVM > 0.5)) - temp = 0; + temp = 0.0; else if ((VVP > CVP + 0.4)) temp = 0.5; else temp = 0.5; - dv = PF1(CVP, VVP, 0.0015 * temp / 1.8 / 2) * dt; - CntrlRes->Flow(+dv); - ValveRes->Flow(-0.04 * dv); - dV1 = dV1 - 0.96 * dv; + dV = PF1(CVP, VVP, 0.0015 * temp / 1.8 / 2) * dt; + CntrlRes->Flow(+dV); + ValveRes->Flow(-0.04 * dV); + dV1 = dV1 - 0.96 * dV; // luzowanie KI {G} // if VVP>BCP then @@ -1236,26 +1237,38 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel ) // dV:=PF(VVP,BCP,0.00020*(1.33-int((CVP-BCP)*BVM>0.65)))*dt // else dV:=0; 0.00025 P /*P*/ - if (VVP > BCP) - dv = PF(VVP, BCP, - 0.00043 * (1.5 - int(((CVP - BCP) * BVM > 1) && (BrakeDelayFlag == bdelay_G))), - 0.1) * - dt; - else if ((CVP - BCP) < 1.5) - dv = PF(VVP, BCP, - 0.001472 * (1.36 - int(((CVP - BCP) * BVM > 1) && (BrakeDelayFlag == bdelay_G))), - 0.1) * - dt; - else - dv = 0; + if( VVP > BCP ) { + dV = + PF( VVP, BCP, + 0.00043 * ( 1.5 - ( + true == ( ( ( CVP - BCP ) * BVM > 1.0 ) + && ( BrakeDelayFlag == bdelay_G ) ) ? + 1.0 : + 0.0 ) ), + 0.1 ) + * dt; + } + else if( ( CVP - BCP ) < 1.5 ) { + dV = PF( VVP, BCP, + 0.001472 * ( 1.36 - ( + true == ( ( ( CVP - BCP ) * BVM > 1.0 ) + && ( BrakeDelayFlag == bdelay_G ) ) ? + 1.0 : + 0.0 ) ), + 0.1 ) + * dt; + } + else { + dV = 0; + } - ImplsRes->Flow(-dv); - ValveRes->Flow(+dv); + ImplsRes->Flow(-dV); + ValveRes->Flow(+dV); // przeplyw PG <-> rozdzielacz - dv = PF(PP, VVP, 0.01, 0.1) * dt; - ValveRes->Flow(-dv); + dV = PF(PP, VVP, 0.01, 0.1) * dt; + ValveRes->Flow(-dV); - result = dv - dV1; + result = dV - dV1; // if Vel>55 then temp:=0.72 else // temp:=1;{R} @@ -1272,18 +1285,18 @@ double TLSt::GetPF( double const PP, double const dt, double const Vel ) if ((BrakeCyl->P() > temp + 0.005) || (temp < 0.28)) // dV:=PF(0,BrakeCyl->P(),0.0015*3*sizeBC)*dt // dV:=PF(0,BrakeCyl->P(),0.005*3*sizeBC)*dt - dv = PFVd(BrakeCyl->P(), 0, 0.005 * 7 * SizeBC, temp) * dt; + dV = PFVd(BrakeCyl->P(), 0, 0.005 * 7 * SizeBC, temp) * dt; else - dv = 0; - BrakeCyl->Flow(-dv); + dV = 0; + BrakeCyl->Flow(-dV); // przeplyw ZP <-> CH if ((BrakeCyl->P() < temp - 0.005) && (temp > 0.29)) // dV:=PF(BVP,BrakeCyl->P(),0.002*3*sizeBC*2)*dt - dv = -PFVa(BVP, BrakeCyl->P(), 0.002 * 7 * SizeBC * 2, temp) * dt; + dV = -PFVa(BVP, BrakeCyl->P(), 0.002 * 7 * SizeBC * 2, temp) * dt; else - dv = 0; - BrakeRes->Flow(dv); - BrakeCyl->Flow(-dv); + dV = 0; + BrakeRes->Flow(dV); + BrakeCyl->Flow(-dV); ImplsRes->Act(); ValveRes->Act(); @@ -2198,124 +2211,145 @@ double TFV4aM::GetPF(double i_bcp, double PP, double HP, double dt, double ep) static int const LBDelay = 100; static double const xpM = 0.3; // mnoznik membrany komory pod - double LimPP; - double dpPipe; - double dpMainValve; - double ActFlowSpeed; - double DP; - double pom; - int i; + ep = (PP / 2.0) * 1.5 + (ep / 2.0) * 0.5; // SPKS!! - ep = PP / 2 * 1.5 + ep / 2 * 0.5; // SPKS!! - // ep:=pp; - // ep:=cp/3+pp/3+ep/3; - // ep:=cp; + for( int idx = 0; idx < 5; ++idx ) { + Sounds[ idx ] = 0; + } - for (i = 0; i < 5; ++i) - Sounds[i] = 0; - DP = 0; + // na wszelki wypadek, zeby nie wyszlo poza zakres + i_bcp = clamp( i_bcp, -1.999, 5.999 ); - i_bcp = Max0R(Min0R(i_bcp, 5.999), -1.999); // na wszelki wypadek, zeby nie wyszlo poza zakres - - if ((TP > 0)) - { // jesli czasowy jest niepusty - // dp:=0.07; //od cisnienia 5 do 0 w 60 sekund ((5-0)*dt/75) + double DP{ 0.0 }; + if( TP > 0.0 ) { + // jesli czasowy jest niepusty DP = 0.045; // 2.5 w 55 sekund (5,35->5,15 w PG) - TP = TP - DP * dt; + TP -= DP * dt; Sounds[s_fv4a_t] = DP; } - else //.08 - { - TP = 0; + else { + //.08 + TP = 0.0; } - if ((XP > 0)) // jesli komora pod niepusta jest niepusty - { + if (XP > 0) { + // jesli komora pod niepusta jest niepusty DP = 2.5; Sounds[s_fv4a_x] = DP * XP; - XP = XP - dt * DP * 2; // od cisnienia 5 do 0 w 10 sekund ((5-0)*dt/10) + XP -= dt * DP * 2.0; // od cisnienia 5 do 0 w 10 sekund ((5-0)*dt/10) + } + else { + // jak pusty, to pusty + XP = 0.0; } - else //.75 - XP = 0; // jak pusty, to pusty - LimPP = Min0R(LPP_RP(i_bcp) + TP * 0.08 + RedAdj, HP); // pozycja + czasowy lub zasilanie - ActFlowSpeed = BPT[lround(i_bcp) + 2][0]; + double pom; + if( EQ( i_bcp, -1.0 ) ) { + pom = std::min( HP, 5.4 + RedAdj ); + } + else { + pom = std::min( CP, HP ); + } - if ((EQ(i_bcp, -1))) - pom = Min0R(HP, 5.4 + RedAdj); - else - pom = Min0R(CP, HP); - - if ((pom > RP + 0.25)) + if( pom > RP + 0.25 ) { Fala = true; - if ((Fala)) - if ((pom > RP + 0.3)) - // if(ep>rp+0.11)then - XP = XP - 20 * PR(pom, XP) * dt; - // else - // xp:=xp-16*(ep-(ep+0.01))/(0.1)*PR(ep,xp)*dt; - else + } + if( Fala ) { + if( pom > RP + 0.3 ) { + XP = XP - 20.0 * PR( pom, XP ) * dt; + } + else { Fala = false; + } + } - if ((LimPP > CP)) // podwyzszanie szybkie - CP = CP + 5 * 60 * Min0R(abs(LimPP - CP), 0.05) * PR(CP, LimPP) * dt; // zbiornik sterujacy; - else - CP = CP + 13 * Min0R(abs(LimPP - CP), 0.05) * PR(CP, LimPP) * dt; // zbiornik sterujacy + double LimPP = std::min( + LPP_RP( i_bcp ) + TP * 0.08 + RedAdj, + HP ); // pozycja + czasowy lub zasilanie + + // zbiornik sterujacy + if( LimPP > CP ) { + // podwyzszanie szybkie + CP += + 5.0 * 60.0 + * std::min( + std::abs( LimPP - CP ), + 0.05 ) + * PR( CP, LimPP ) + * dt; + } + else { + CP += + 13 + * std::min( + std::abs( LimPP - CP ), + 0.05 ) + * PR( CP, LimPP ) + * dt; + } LimPP = pom; // cp - dpPipe = Min0R(HP, LimPP + XP * xpM); + double const dpPipe = std::min(HP, LimPP + XP * xpM); - if (dpPipe > PP) - dpMainValve = -PFVa(HP, PP, ActFlowSpeed / LBDelay, dpPipe, 0.4); - else - dpMainValve = PFVd(PP, 0, ActFlowSpeed / LBDelay, dpPipe, 0.4); + double const ActFlowSpeed = BPT[ std::lround( i_bcp ) + 2 ][ 0 ]; - if (EQ(i_bcp, -1)) - { - if ((TP < 5)) - TP = TP + dt; // 5/10 - if ((TP < 1)) - TP = TP - 0.5 * dt; // 5/10 - // dpMainValve:=dpMainValve*2; - //+1*PF(dpPipe,pp,ActFlowSpeed/LBDelay)//coby - // nie przeszkadzal przy ladowaniu z zaworu obok + double dpMainValve; + if( dpPipe > PP ) { + dpMainValve = -PFVa( HP, PP, ActFlowSpeed / LBDelay, dpPipe, 0.4 ); + } + else { + dpMainValve = PFVd( PP, 0, ActFlowSpeed / LBDelay, dpPipe, 0.4 ); } - if (EQ(i_bcp, 0)) - { - if ((TP > 2)) - dpMainValve = dpMainValve * 1.5; //+0.5*PF(dpPipe,pp,ActFlowSpeed/LBDelay)//coby nie - // przeszkadzal przy ladowaniu z zaworu obok + if (EQ(i_bcp, -1)) { + + if( TP < 5 ) { TP += dt; } + if( TP < 1 ) { TP -= 0.5 * dt; } + } + + if (EQ(i_bcp, 0)) { + + if( TP > 2 ) { + dpMainValve *= 1.5; + } } ep = dpPipe; - if ((EQ(i_bcp, 0) || (RP > ep))) - RP = RP + PF(RP, ep, 0.0007) * dt; // powolne wzrastanie, ale szybsze na jezdzie; - else - RP = RP + PF(RP, ep, 0.000093 / 2 * 2) * dt; // powolne wzrastanie i to bardzo - // jednak trzeba wydluzyc, bo - // obecnie zle dziala - if ((RP < ep) && - (RP < - BPT[lround(i_bcpno) + 2][1])) // jesli jestesmy ponizej cisnienia w sterujacym (2.9 bar) - RP = RP + PF(RP, CP, 0.005) * dt; // przypisz cisnienie w PG - wydluzanie napelniania o czas - // potrzebny do napelnienia PG + if( ( EQ( i_bcp, 0 ) + || ( RP > ep ) ) ) { + // powolne wzrastanie, ale szybsze na jezdzie; + RP += PF( RP, ep, 0.0007 ) * dt; + } + else { + // powolne wzrastanie i to bardzo + RP += PF( RP, ep, 0.000093 / 2 * 2 ) * dt; + } + // jednak trzeba wydluzyc, bo obecnie zle dziala + if( ( RP < ep ) + && ( RP < BPT[ std::lround( i_bcpno ) + 2 ][ 1 ] ) ) { + // jesli jestesmy ponizej cisnienia w sterujacym (2.9 bar) + // przypisz cisnienie w PG - wydluzanie napelniania o czas potrzebny do napelnienia PG + RP += PF( RP, CP, 0.005 ) * dt; + } - if ((EQ(i_bcp, i_bcpno)) || (EQ(i_bcp, -2))) - { - DP = PF(0, PP, ActFlowSpeed / LBDelay); + if( ( EQ( i_bcp, i_bcpno ) ) + || ( EQ( i_bcp, -2 ) ) ) { + + DP = PF( 0.0, PP, ActFlowSpeed / LBDelay ); dpMainValve = DP; Sounds[s_fv4a_e] = DP; - Sounds[s_fv4a_u] = 0; - Sounds[s_fv4a_b] = 0; - Sounds[s_fv4a_x] = 0; + Sounds[s_fv4a_u] = 0.0; + Sounds[s_fv4a_b] = 0.0; + Sounds[s_fv4a_x] = 0.0; } - else - { - if (dpMainValve > 0) - Sounds[s_fv4a_b] = dpMainValve; - else - Sounds[s_fv4a_u] = -dpMainValve; + else { + + if( dpMainValve > 0.0 ) { + Sounds[ s_fv4a_b ] = dpMainValve; + } + else { + Sounds[ s_fv4a_u ] = -dpMainValve; + } } return dpMainValve * dt; @@ -2347,17 +2381,11 @@ double TFV4aM::GetPos(int i) double TFV4aM::LPP_RP(double pos) // cisnienie z zaokraglonej pozycji; { - int i_pos; + int const i_pos = 2 + std::floor( pos ); // zaokraglone w dol - i_pos = lround(pos - 0.5) + 2; // zaokraglone w dol - double i, j, k, l; - i = BPT[i_pos][1]; - j = BPT[i_pos + 1][1]; - k = pos + 2 - i_pos; - l = i + (j - i) * k; - double r = BPT[i_pos][1] + - (BPT[i_pos + 1][1] - BPT[i_pos][1]) * (pos + 2 - i_pos); // interpolacja liniowa - return r; + return + BPT[i_pos][1] + + (BPT[i_pos + 1][1] - BPT[i_pos][1]) * ((pos + 2) - i_pos); // interpolacja liniowa } bool TFV4aM::EQ(double pos, double i_pos) { @@ -2366,8 +2394,7 @@ bool TFV4aM::EQ(double pos, double i_pos) //---FV4a/M--- nowonapisany kran bez poprawki IC -double TMHZ_EN57::GetPF(double i_bcp, double PP, double HP, double dt, double ep) -{ +double TMHZ_EN57::GetPF( double i_bcp, double PP, double HP, double dt, double ep ) { static int const LBDelay = 100; double LimPP; @@ -2376,13 +2403,11 @@ double TMHZ_EN57::GetPF(double i_bcp, double PP, double HP, double dt, double ep double ActFlowSpeed; double DP; double pom; - int i; - { - long i_end = 5; - for (i = 0; i < i_end; ++i) - Sounds[i] = 0; + for( int idx = 0; idx < 5; ++idx ) { + Sounds[ idx ] = 0; } + DP = 0; i_bcp = Max0R(Min0R(i_bcp, 9.999), -0.999); // na wszelki wypadek, zeby nie wyszlo poza zakres diff --git a/McZapkie/hamulce.h b/McZapkie/hamulce.h index 661bfc7a..25de35db 100644 --- a/McZapkie/hamulce.h +++ b/McZapkie/hamulce.h @@ -184,7 +184,7 @@ class TBrake { bool DCV = false; //podwojny zawor zwrotny double ASBP = 0.0; //cisnienie hamulca pp - int BrakeStatus = 0; //flaga stanu + int BrakeStatus{ b_off }; //flaga stanu int SoundFlag = 0; public: @@ -213,6 +213,8 @@ class TBrake { void SetASBP( double const Press ); //ustalenie cisnienia pp virtual void ForceEmptiness(); int GetSoundFlag(); + int GetBrakeStatus() const { return BrakeStatus; } + void SetBrakeStatus( int const Status ) { BrakeStatus = Status; } virtual void SetED( double const EDstate ) {}; //stan hamulca ED do luzowania }; diff --git a/Segment.cpp b/Segment.cpp index 3106ee28..27c133a0 100644 --- a/Segment.cpp +++ b/Segment.cpp @@ -801,6 +801,7 @@ void TSegment::RaRenderLoft(CVertNormTex *&Vert, const vector6 *ShapePoints, int s = fStep * iSkip; // iSkip - ile odcinków z początku pominąć i = iSkip; // domyślnie 0 t = fTsBuffer[i]; // tabela wattości t dla segmentów + // BUG: length of spline can be 0, we should skip geometry generation for such cases fOffset = 0.1 / fLength; // pierwsze 10cm pos1 = FastGetPoint(t); // wektor początku segmentu dir = FastGetDirection(t, fOffset); // wektor kierunku diff --git a/Texture.cpp b/Texture.cpp index 8f939e06..3d2c2304 100644 --- a/Texture.cpp +++ b/Texture.cpp @@ -424,7 +424,6 @@ opengl_texture::load_TGA() { else if( tgaheader[ 2 ] == 10 ) { // compressed TGA int currentpixel = 0; - int currentbyte = 0; unsigned char buffer[ 4 ] = { 255, 255, 255, 255 }; const int pixelcount = data_width * data_height; diff --git a/Train.cpp b/Train.cpp index 81d72c95..f199dcc6 100644 --- a/Train.cpp +++ b/Train.cpp @@ -925,19 +925,17 @@ void TTrain::OnCommand_sandboxactivate( TTrain *Train, command_data const &Comma return; } - if( Command.action != GLFW_RELEASE ) { - // press or hold - Train->mvControlled->SandDose = true; + if( Command.action == GLFW_PRESS ) { + // press + Train->mvControlled->Sandbox( true ); // audio feedback - if( Train->ggSandButton.GetValue() < 0.05 ) { - Train->play_sound( Train->dsbSwitch ); - } + Train->play_sound( Train->dsbSwitch ); // visual feedback Train->ggSandButton.UpdateValue( 1.0 ); } - else { + else if( Command.action == GLFW_RELEASE) { // release - Train->mvControlled->SandDose = false; + Train->mvControlled->Sandbox( false ); /* // audio feedback if( Train->ggAntiSlipButton.GetValue() > 0.5 ) { @@ -1212,41 +1210,20 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down - if( false == ( Train->mvOccupied->ActiveCab == 1 ? Train->mvControlled->PantFrontUp : Train->mvControlled->PantRearUp ) ) { + if( false == Train->mvControlled->PantFrontUp ) { // turn on... - if( Train->mvOccupied->ActiveCab == 1 ) { - // przedni gdy w kabinie 1 - Train->mvControlled->PantFrontSP = false; - if( Train->mvControlled->PantFront( true ) ) { - if( Train->mvControlled->PantFrontStart != 1 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - if( Train->ggPantFrontButton.SubModel ) { - Train->ggPantFrontButton.UpdateValue( 1.0 ); - } - if( Train->ggPantFrontButtonOff.SubModel != nullptr ) { - // pantograph control can have two-button setup - Train->ggPantFrontButtonOff.UpdateValue( 0.0 ); - } + Train->mvControlled->PantFrontSP = false; + if( Train->mvControlled->PantFront( true ) ) { + if( Train->mvControlled->PantFrontStart != 1 ) { + // sound feedback + Train->play_sound( Train->dsbSwitch ); + // visual feedback + if( Train->ggPantFrontButton.SubModel ) { + Train->ggPantFrontButton.UpdateValue( 1.0 ); } - } - } - else { - // rear otherwise - Train->mvControlled->PantRearSP = false; - if( Train->mvControlled->PantRear( true ) ) { - if( Train->mvControlled->PantRearStart != 1 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - if( Train->ggPantFrontButton.SubModel ) { - Train->ggPantFrontButton.UpdateValue( 1.0 ); - } - if( Train->ggPantFrontButtonOff.SubModel != nullptr ) { - // pantograph control can have two-button setup - Train->ggPantFrontButtonOff.UpdateValue( 0.0 ); - } + if( Train->ggPantFrontButtonOff.SubModel != nullptr ) { + // pantograph control can have two-button setup + Train->ggPantFrontButtonOff.UpdateValue( 0.0 ); } } } @@ -1261,32 +1238,15 @@ void TTrain::OnCommand_pantographtogglefront( TTrain *Train, command_data const return; } - if( Train->mvOccupied->ActiveCab == 1 ) { - // przedni gdy w kabinie 1 - Train->mvControlled->PantFrontSP = false; - if( false == Train->mvControlled->PantFront( false ) ) { - if( Train->mvControlled->PantFrontStart != 0 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - Train->ggPantFrontButton.UpdateValue( 0.0 ); - // pantograph control can have two-button setup - Train->ggPantFrontButtonOff.UpdateValue( 1.0 ); - } - } - } - else { - // rear otherwise - Train->mvControlled->PantRearSP = false; - if( false == Train->mvControlled->PantRear( false ) ) { - if( Train->mvControlled->PantRearStart != 0 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - Train->ggPantFrontButton.UpdateValue( 0.0 ); - // pantograph control can have two-button setup - Train->ggPantFrontButtonOff.UpdateValue( 1.0 ); - } + Train->mvControlled->PantFrontSP = false; + if( false == Train->mvControlled->PantFront( false ) ) { + if( Train->mvControlled->PantFrontStart != 0 ) { + // sound feedback + Train->play_sound( Train->dsbSwitch ); + // visual feedback + Train->ggPantFrontButton.UpdateValue( 0.0 ); + // pantograph control can have two-button setup + Train->ggPantFrontButtonOff.UpdateValue( 1.0 ); } } } @@ -1315,41 +1275,20 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & if( Command.action == GLFW_PRESS ) { // only reacting to press, so the switch doesn't flip back and forth if key is held down - if( false == ( Train->mvOccupied->ActiveCab == 1 ? Train->mvControlled->PantRearUp : Train->mvControlled->PantFrontUp ) ) { + if( false == Train->mvControlled->PantRearUp ) { // turn on... - if( Train->mvOccupied->ActiveCab == 1 ) { - // rear if in front cab - Train->mvControlled->PantRearSP = false; - if( Train->mvControlled->PantRear( true ) ) { - if( Train->mvControlled->PantRearStart != 1 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - if( Train->ggPantRearButton.SubModel ) { - Train->ggPantRearButton.UpdateValue( 1.0 ); - } - if( Train->ggPantRearButtonOff.SubModel != nullptr ) { - // pantograph control can have two-button setup - Train->ggPantRearButtonOff.UpdateValue( 0.0 ); - } + Train->mvControlled->PantRearSP = false; + if( Train->mvControlled->PantRear( true ) ) { + if( Train->mvControlled->PantRearStart != 1 ) { + // sound feedback + Train->play_sound( Train->dsbSwitch ); + // visual feedback + if( Train->ggPantRearButton.SubModel ) { + Train->ggPantRearButton.UpdateValue( 1.0 ); } - } - } - else { - // front otherwise - Train->mvControlled->PantFrontSP = false; - if( Train->mvControlled->PantFront( true ) ) { - if( Train->mvControlled->PantFrontStart != 1 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - if( Train->ggPantRearButton.SubModel ) { - Train->ggPantRearButton.UpdateValue( 1.0 ); - } - if( Train->ggPantRearButtonOff.SubModel != nullptr ) { - // pantograph control can have two-button setup - Train->ggPantRearButtonOff.UpdateValue( 0.0 ); - } + if( Train->ggPantRearButtonOff.SubModel != nullptr ) { + // pantograph control can have two-button setup + Train->ggPantRearButtonOff.UpdateValue( 0.0 ); } } } @@ -1364,32 +1303,15 @@ void TTrain::OnCommand_pantographtogglerear( TTrain *Train, command_data const & return; } - if( Train->mvOccupied->ActiveCab == 1 ) { - // rear if in front cab - Train->mvControlled->PantRearSP = false; - if( false == Train->mvControlled->PantRear( false ) ) { - if( Train->mvControlled->PantRearStart != 0 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - Train->ggPantRearButton.UpdateValue( 0.0 ); - // pantograph control can have two-button setup - Train->ggPantRearButtonOff.UpdateValue( 1.0 ); - } - } - } - else { - // front otherwise - Train->mvControlled->PantFrontSP = false; - if( false == Train->mvControlled->PantFront( false ) ) { - if( Train->mvControlled->PantFrontStart != 0 ) { - // sound feedback - Train->play_sound( Train->dsbSwitch ); - // visual feedback - Train->ggPantRearButton.UpdateValue( 0.0 ); - // pantograph control can have two-button setup - Train->ggPantRearButtonOff.UpdateValue( 1.0 ); - } + Train->mvControlled->PantRearSP = false; + if( false == Train->mvControlled->PantRear( false ) ) { + if( Train->mvControlled->PantRearStart != 0 ) { + // sound feedback + Train->play_sound( Train->dsbSwitch ); + // visual feedback + Train->ggPantRearButton.UpdateValue( 0.0 ); + // pantograph control can have two-button setup + Train->ggPantRearButtonOff.UpdateValue( 1.0 ); } } } @@ -1533,6 +1455,10 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // press or hold... if( Train->m_linebreakerstate == 0 ) { // ...to close the circuit + if( Command.action == GLFW_PRESS ) { + // fresh press, start fresh closing delay calculation + Train->fMainRelayTimer = 0.0f; + } if( Train->ggMainOnButton.SubModel != nullptr ) { // two separate switches to close and break the circuit // audio feedback @@ -1552,17 +1478,20 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com Train->ggMainButton.UpdateValue( 1.0 ); } // keep track of period the button is held down, to determine when/if circuit closes - if( ( false == ( Train->mvControlled->EnginePowerSource.PowerType == ElectricSeriesMotor ) || ( Train->mvControlled->EngineType == ElectricInductionMotor ) ) - || ( Train->fHVoltage > 0.0f ) ) { + if( ( false == ( ( Train->mvControlled->EngineType == ElectricSeriesMotor ) + || ( Train->mvControlled->EngineType == ElectricInductionMotor ) ) ) + || ( Train->fHVoltage > 0.5 * Train->mvControlled->EnginePowerSource.MaxVoltage ) ) { // prevent the switch from working if there's no power // TODO: consider whether it makes sense for diesel engines and such Train->fMainRelayTimer += 0.33f; // Command.time_delta * 5.0; } +/* if( Train->mvControlled->Mains != true ) { // hunter-080812: poprawka Train->mvControlled->ConverterSwitch( false ); Train->mvControlled->CompressorSwitch( false ); } +*/ if( Train->fMainRelayTimer > Train->mvControlled->InitialCtrlDelay ) { // wlaczanie WSa z opoznieniem Train->m_linebreakerstate = 2; @@ -1695,6 +1624,8 @@ void TTrain::OnCommand_linebreakertoggle( TTrain *Train, command_data const &Com // finalize the state of the line breaker Train->m_linebreakerstate = 1; } + // on button release reset the closing timer, just in case something elsewhere tries to read it + Train->fMainRelayTimer = 0.0f; } } @@ -1705,15 +1636,17 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma if( ( false == Train->mvControlled->ConverterAllow ) && ( Train->ggConverterButton.GetValue() < 0.5 ) ) { // turn on + // sound feedback + if( Train->ggConverterButton.GetValue() < 0.5 ) { + Train->play_sound( Train->dsbSwitch ); + } + // visual feedback + Train->ggConverterButton.UpdateValue( 1.0 ); +/* if( ( Train->mvControlled->EnginePowerSource.SourceType != CurrentCollector ) || ( Train->mvControlled->PantRearVolt != 0.0 ) || ( Train->mvControlled->PantFrontVolt != 0.0 ) ) { - // visual feedback - Train->ggConverterButton.UpdateValue( 1.0 ); - // sound feedback - if( Train->ggConverterButton.GetValue() < 0.5 ) { - Train->play_sound( Train->dsbSwitch ); - } +*/ // impulse type switch has no effect if there's no power // NOTE: this is most likely setup wrong, but the whole thing is smoke and mirrors anyway if( ( Train->mvOccupied->ConvSwitchType != "impulse" ) @@ -1728,7 +1661,9 @@ void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Comma } } } +/* } +*/ } else { //turn off @@ -2627,7 +2562,7 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman if( Train->ggDoorLeftButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } - Train->play_sound( Train->dsbDoorOpen ); + Train->play_sound( Train->dsbDoorClose ); } } else { @@ -2638,7 +2573,7 @@ void TTrain::OnCommand_doortoggleleft( TTrain *Train, command_data const &Comman if( Train->ggDoorRightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } - Train->play_sound( Train->dsbDoorOpen ); + Train->play_sound( Train->dsbDoorClose ); } } } @@ -2688,7 +2623,7 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma if( Train->ggDoorRightButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } - Train->play_sound( Train->dsbDoorOpen ); + Train->play_sound( Train->dsbDoorClose ); } } else { @@ -2699,7 +2634,7 @@ void TTrain::OnCommand_doortoggleright( TTrain *Train, command_data const &Comma if( Train->ggDoorLeftButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } - Train->play_sound( Train->dsbDoorOpen ); + Train->play_sound( Train->dsbDoorClose ); } } } @@ -2772,7 +2707,7 @@ void TTrain::OnCommand_hornlowactivate( TTrain *Train, command_data const &Comma else if( Command.action == GLFW_RELEASE ) { // turn off // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved - Train->mvControlled->WarningSignal &= ~( 1 | 2 ); + Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); // audio feedback if( ( Train->ggHornButton.GetValue() < -0.5 ) || ( Train->ggHornLowButton.GetValue() > 0.5 ) ) { @@ -2815,14 +2750,14 @@ void TTrain::OnCommand_hornhighactivate( TTrain *Train, command_data const &Comm else if( Command.action == GLFW_RELEASE ) { // turn off // NOTE: we turn off both low and high horn, due to unreliability of release event when shift key is involved - Train->mvControlled->WarningSignal &= ~( 1 | 2 ); + Train->mvOccupied->WarningSignal &= ~( 1 | 2 ); // audio feedback if( Train->ggHornButton.GetValue() > 0.5 ) { Train->play_sound( Train->dsbSwitch ); } // visual feedback Train->ggHornButton.UpdateValue( 0.0 ); - Train->ggHornButton.UpdateValue( 0.0 ); + Train->ggHornHighButton.UpdateValue( 0.0 ); } } @@ -3056,16 +2991,19 @@ void TTrain::OnKeyDown(int cKey) } else if (cKey == Global::Keys[k_CabForward]) { - if (!CabChange(1)) - if (TestFlag(DynamicObject->MoverParameters->Couplers[0].CouplingFlag, - ctrain_passenger)) - { // przejscie do nastepnego pojazdu + if( !CabChange( 1 ) ) { + if( TestFlag( DynamicObject->MoverParameters->Couplers[ 0 ].CouplingFlag, + ctrain_passenger ) ) { // przejscie do nastepnego pojazdu Global::changeDynObj = DynamicObject->PrevConnected; Global::changeDynObj->MoverParameters->ActiveCab = DynamicObject->PrevConnectedNo ? -1 : 1; } + } +/* + NOTE: disabled to allow 'prototypical' 'tricking' pantograph compressor to run unattended if (DynamicObject->MoverParameters->ActiveCab) mvControlled->PantCompFlag = false; // wyjście z maszynowego wyłącza sprężarkę +*/ } else if (cKey == Global::Keys[k_CabBackward]) { @@ -3077,9 +3015,12 @@ void TTrain::OnKeyDown(int cKey) Global::changeDynObj->MoverParameters->ActiveCab = DynamicObject->NextConnectedNo ? -1 : 1; } +/* + NOTE: disabled to allow 'prototypical' 'tricking' pantograph compressor to run unattended if (DynamicObject->MoverParameters->ActiveCab) mvControlled->PantCompFlag = false; // wyjście z maszynowego wyłącza sprężarkę pomocniczą +*/ } else if (cKey == Global::Keys[k_Couple]) { // ABu051104: male zmiany, zeby mozna bylo laczyc odlegle wagony @@ -3141,11 +3082,13 @@ if if (DynamicObject->Mechanik) // na wszelki wypadek DynamicObject->Mechanik->CheckVehicles(Connect); // aktualizacja flag kierunku w składzie play_sound( dsbCouplerAttach ); + // one coupling type per key press + return; } else WriteLog("Mechanical coupling failed."); } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_pneumatic)) // pneumatyka + if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_pneumatic)) // pneumatyka { if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag @@ -3155,12 +3098,16 @@ if tmp->MoverParameters->Couplers[CouplNr].Connected, (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_pneumatic))) { - rsHiss.Play(1, DSBPLAY_LOOPING, true, tmp->GetPosition()); + // TODO: dedicated 'click' sound for connecting cable-type connections + play_sound( dsbCouplerDetach ); +// rsHiss.Play( 1, DSBPLAY_LOOPING, true, tmp->GetPosition() ); DynamicObject->SetPneumatic(CouplNr != 0, true); // Ra: to mi się nie podoba !!!! tmp->SetPneumatic(CouplNr != 0, true); + // one coupling type per key press + return; } } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_scndpneumatic)) // zasilajacy + if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_scndpneumatic)) // zasilajacy { if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag @@ -3170,17 +3117,18 @@ if tmp->MoverParameters->Couplers[CouplNr].Connected, (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_scndpneumatic))) { - // rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); + // TODO: dedicated 'click' sound for connecting cable-type connections play_sound( dsbCouplerDetach ); - DynamicObject->SetPneumatic(CouplNr != 0, false); // Ra: to mi się nie podoba !!!! +// rsHiss.Play( 1, DSBPLAY_LOOPING, true, tmp->GetPosition() ); + DynamicObject->SetPneumatic( CouplNr != 0, false ); // Ra: to mi się nie podoba !!!! tmp->SetPneumatic(CouplNr != 0, false); + // one coupling type per key press + return; } } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_controll)) // ukrotnionko + if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_controll)) // ukrotnionko { - if ((tmp->MoverParameters->Couplers[CouplNr] - .Connected->Couplers[CouplNr] - .AllowedFlag & + if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & ctrain_controll) == ctrain_controll) if (tmp->MoverParameters->Attach( @@ -3188,14 +3136,15 @@ if tmp->MoverParameters->Couplers[CouplNr].Connected, (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_controll))) { + // TODO: dedicated 'click' sound for connecting cable-type connections play_sound( dsbCouplerAttach ); + // one coupling type per key press + return; } } - else if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_passenger)) // mostek + if (!TestFlag(tmp->MoverParameters->Couplers[CouplNr].CouplingFlag, ctrain_passenger)) // mostek { - if ((tmp->MoverParameters->Couplers[CouplNr] - .Connected->Couplers[CouplNr] - .AllowedFlag & + if ((tmp->MoverParameters->Couplers[CouplNr].Connected->Couplers[CouplNr].AllowedFlag & tmp->MoverParameters->Couplers[CouplNr].AllowedFlag & ctrain_passenger) == ctrain_passenger) if (tmp->MoverParameters->Attach( @@ -3203,10 +3152,29 @@ if tmp->MoverParameters->Couplers[CouplNr].Connected, (tmp->MoverParameters->Couplers[CouplNr].CouplingFlag | ctrain_passenger))) { - // rsHiss.Play(1,DSBPLAY_LOOPING,true,tmp->GetPosition()); - play_sound( dsbCouplerDetach ); + play_sound( dsbCouplerAttach ); +/* DynamicObject->SetPneumatic(CouplNr != 0, false); tmp->SetPneumatic(CouplNr != 0, false); +*/ + // one coupling type per key press + return; + } + } + if( false == TestFlag( tmp->MoverParameters->Couplers[ CouplNr ].CouplingFlag, ctrain_heating ) ) { + // heating + if( ( tmp->MoverParameters->Couplers[ CouplNr ].Connected->Couplers[ CouplNr ].AllowedFlag + & tmp->MoverParameters->Couplers[ CouplNr ].AllowedFlag + & ctrain_heating ) == ctrain_heating ) + if( tmp->MoverParameters->Attach( + CouplNr, 2, + tmp->MoverParameters->Couplers[ CouplNr ].Connected, + ( tmp->MoverParameters->Couplers[ CouplNr ].CouplingFlag | ctrain_heating ) ) ) { + + // TODO: dedicated 'click' sound for connecting cable-type connections + play_sound( dsbCouplerAttach ); + // one coupling type per key press + return; } } } @@ -3469,32 +3437,6 @@ bool TTrain::Update( double const Deltatime ) DWORD stat; double dt = Deltatime; // Timer::GetDeltaTime(); - // catch cases where the power goes out, and the linebreaker state is left as closed - if( ( m_linebreakerstate == 1 ) - && ( false == mvControlled->Mains ) - && ( ggMainButton.GetValue() < 0.05 ) ) { - // crude way to catch cases where the main was knocked out and the user is trying to restart it - // because the state of the line breaker isn't changed to match, we need to do it here manually - m_linebreakerstate = 0; - } - -/* - // NOTE: disabled while switch state isn't preserved while moving between compartments - // check whether we should raise the pantographs, based on volume in pantograph tank - if( mvControlled->PantPress > ( - mvControlled->TrainType == dt_EZT ? - 2.4 : - 3.5 ) ) { - if( ( false == mvControlled->PantFrontUp ) - && ( ggPantFrontButton.GetValue() > 0.95 ) ) { - mvControlled->PantFront( true ); - } - if( ( false == mvControlled->PantRearUp ) - && ( ggPantRearButton.GetValue() > 0.95 ) ) { - mvControlled->PantRear( true ); - } - } -*/ if (DynamicObject->mdKabina) { // Ra: TODO: odczyty klawiatury/pulpitu nie // powinny być uzależnione od istnienia modelu @@ -3502,15 +3444,14 @@ bool TTrain::Update( double const Deltatime ) tor = DynamicObject->GetTrack(); // McZapkie-180203 // McZapkie: predkosc wyswietlana na tachometrze brana jest z obrotow kol float maxtacho = 3; - fTachoVelocity = Min0R(fabs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), - mvControlled->Vmax * 1.05); + fTachoVelocity = static_cast( std::min( std::abs(11.31 * mvControlled->WheelDiameter * mvControlled->nrot), mvControlled->Vmax * 1.05) ); { // skacze osobna zmienna float ff = simulation::Time.data().wSecond; // skacze co sekunde - pol sekundy // pomiar, pol sekundy ustawienie if (ff != fTachoTimer) // jesli w tej sekundzie nie zmienial { if (fTachoVelocity > 1) // jedzie - fTachoVelocityJump = fTachoVelocity + (2 - Random(3) + Random(3)) * 0.5; + fTachoVelocityJump = fTachoVelocity + (2.0 - Random(3) + Random(3)) * 0.5; else fTachoVelocityJump = 0; // stoi fTachoTimer = ff; // juz zmienil @@ -3725,12 +3666,15 @@ bool TTrain::Update( double const Deltatime ) // przy dowolnym ustawieniu kierunkowego // Ra: to już jest w T_MoverParameters::TractionForce(), ale zależy od // kierunku - if (mvControlled->EngineType == ElectricSeriesMotor) - if (fabs(mvControlled->RunningTraction.TractionVoltage) < - 0.5 * - mvControlled->EnginePowerSource - .MaxVoltage) // minimalne napięcie pobierać z FIZ? - mvControlled->MainSwitch(false); + if( ( mvControlled->Mains ) + && ( mvControlled->EngineType == ElectricSeriesMotor ) ) { + if( std::max( mvControlled->GetTrainsetVoltage(), std::fabs( mvControlled->RunningTraction.TractionVoltage ) ) < 0.5 * mvControlled->EnginePowerSource.MaxVoltage ) { + // TODO: check whether it should affect entire consist for EMU + // TODO: check whether it should happen if there's power supplied alternatively through hvcouplers + // TODO: potentially move this to the mover module, as there isn't much reason to have this dependent on the operator presence + mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); + } + } // hunter-091012: swiatlo if (bCabLight == true) @@ -3759,7 +3703,7 @@ bool TTrain::Update( double const Deltatime ) { mvControlled->ConvOvldFlag = true; if (mvControlled->TrainType != dt_EZT) - mvControlled->MainSwitch(false); + mvControlled->MainSwitch( false, ( mvControlled->TrainType == dt_EZT ? command_range::unit : command_range::local ) ); } else if( fConverterTimer >= fConverterPrzekaznik ) { // changed switch from always true to take into account state of the compressor switch @@ -4352,7 +4296,11 @@ bool TTrain::Update( double const Deltatime ) if (mvControlled->Battery || mvControlled->ConverterFlag) { - btLampkaWylSzybki.Turn( ( m_linebreakerstate > 0 ? true : false ) ); + btLampkaWylSzybki.Turn( + ( ( (m_linebreakerstate > 0) + || (true == mvControlled->Mains) ) ? + true : + false ) ); // hunter-261211: jakis stary kod (i niezgodny z prawda), // zahaszowalem i poprawilem @@ -4383,7 +4331,7 @@ bool TTrain::Update( double const Deltatime ) // if // ((TestFlag(mvControlled->BrakeStatus,+b_Rused+b_Ractive)))//Lampka drugiego stopnia hamowania - btLampkaHamPosp.Turn((TestFlag(mvOccupied->BrakeStatus, 1))); // lampka drugiego stopnia hamowania + btLampkaHamPosp.Turn((TestFlag(mvOccupied->Hamulec->GetBrakeStatus(), 1))); // lampka drugiego stopnia hamowania //TODO: youBy wyciągnąć flagę wysokiego stopnia // hunter-121211: lampka zanikowo-pradowego wentylatorow: @@ -4702,74 +4650,20 @@ bool TTrain::Update( double const Deltatime ) ggManualBrake.UpdateValue(double(mvOccupied->ManualBrakePos)); ggManualBrake.Update(); } - if (ggBrakeProfileCtrl.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggBrakeProfileCtrl.UpdateValue( - double(mvOccupied->BrakeDelayFlag == 4 ? 2 : mvOccupied->BrakeDelayFlag - 1)); -#endif - ggBrakeProfileCtrl.Update(); - } - if (ggBrakeProfileG.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggBrakeProfileG.UpdateValue( double( mvOccupied->BrakeDelayFlag == bdelay_G ? 1 : 0 ) ); -#endif - ggBrakeProfileG.Update(); - } - if (ggBrakeProfileR.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggBrakeProfileR.UpdateValue( double( mvOccupied->BrakeDelayFlag == bdelay_R ? 1 : 0 ) ); -#endif - ggBrakeProfileR.Update(); - } - - if (ggMaxCurrentCtrl.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggMaxCurrentCtrl.UpdateValue( double( mvControlled->Imax == mvControlled->ImaxHi ) ); -#endif - ggMaxCurrentCtrl.Update(); - } - + ggBrakeProfileCtrl.Update(); + ggBrakeProfileG.Update(); + ggBrakeProfileR.Update(); + ggMaxCurrentCtrl.Update(); // NBMX wrzesien 2003 - drzwi - if (ggDoorLeftButton.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggDoorLeftButton.PutValue( mvOccupied->DoorLeftOpened ? 1 : 0 ); -#endif - ggDoorLeftButton.Update(); - } - if (ggDoorRightButton.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggDoorRightButton.PutValue( mvOccupied->DoorRightOpened ? 1 : 0 ); -#endif - ggDoorRightButton.Update(); - } - if (ggDepartureSignalButton.SubModel) - { - // ggDepartureSignalButton.UpdateValue(double()); - ggDepartureSignalButton.Update(); - } - + ggDoorLeftButton.Update(); + ggDoorRightButton.Update(); + ggDepartureSignalButton.Update(); // NBMX dzwignia sprezarki - if (ggCompressorButton.SubModel) // hunter-261211: poprawka - ggCompressorButton.Update(); - if (ggMainButton.SubModel) - ggMainButton.Update(); - if (ggRadioButton.SubModel) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggRadioButton.PutValue( mvOccupied->Radio ? 1 : 0 ); -#endif - ggRadioButton.Update(); - } - if (ggConverterButton.SubModel) - ggConverterButton.Update(); - if (ggConverterOffButton.SubModel) - ggConverterOffButton.Update(); + ggCompressorButton.Update(); + ggMainButton.Update(); + ggRadioButton.Update(); + ggConverterButton.Update(); + ggConverterOffButton.Update(); #ifdef EU07_USE_OLD_COMMAND_SYSTEM if( ( ( DynamicObject->iLights[ 0 ] ) == 0 ) && ( ( DynamicObject->iLights[ 1 ] ) == 0 ) ) @@ -4918,64 +4812,18 @@ bool TTrain::Update( double const Deltatime ) ggLightsButton.PutValue(mvOccupied->LightsPos - 1); ggLightsButton.Update(); } - if( ggDimHeadlightsButton.SubModel ) { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggDimHeadlightsButton.PutValue( DynamicObject->DimHeadlights ? 1.0 : 0.0 ); -#endif - ggDimHeadlightsButton.Update(); - } - + ggDimHeadlightsButton.Update(); //--------- // Winger 010304 - pantografy // NOTE: shouldn't the pantograph updates check whether it's front or rear cabin? - if (ggPantFrontButton.SubModel ) { - ggPantFrontButton.Update(); - } - if (ggPantRearButton.SubModel) { - ggPantRearButton.Update(); - } - if (ggPantFrontButtonOff.SubModel) { - ggPantFrontButtonOff.Update(); - } + ggPantFrontButton.Update(); + ggPantRearButton.Update(); + ggPantFrontButtonOff.Update(); + ggTrainHeatingButton.Update(); + ggSignallingButton.Update(); + ggDoorSignallingButton.Update(); // Winger 020304 - ogrzewanie - //---------- // hunter-080812: poprawka na ogrzewanie w elektrykach - usuniete uzaleznienie od przetwornicy - if( ggTrainHeatingButton.SubModel ) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - if( mvControlled->Heating ) - { - ggTrainHeatingButton.PutValue(1); - // if (mvControlled->ConverterFlag==true) - // btLampkaOgrzewanieSkladu.TurnOn(); - } - else - { - ggTrainHeatingButton.PutValue(0); - // btLampkaOgrzewanieSkladu.TurnOff(); - } -#endif - ggTrainHeatingButton.Update(); - } - if (ggSignallingButton.SubModel != nullptr) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggSignallingButton.PutValue( mvControlled->Signalling ? 1 : 0 ); -#endif - ggSignallingButton.Update(); - } - if (ggDoorSignallingButton.SubModel != nullptr) - { -#ifdef EU07_USE_OLD_COMMAND_SYSTEM - ggDoorSignallingButton.PutValue( mvControlled->DoorSignalling ? 1 : 0 ); -#endif - ggDoorSignallingButton.Update(); - } - // if (ggDistCounter.SubModel) - //{//Ra 2014-07: licznik kilometrów - // ggDistCounter.PutValue(mvControlled->DistCounter); - // ggDistCounter.Update(); - //} if ((((mvControlled->EngineType == ElectricSeriesMotor) && (mvControlled->Mains == true) && (mvControlled->ConvOvldFlag == false)) || (mvControlled->ConverterFlag)) && @@ -5373,6 +5221,8 @@ bool TTrain::Update( double const Deltatime ) false) // nie wyłączać, gdy AI mvControlled->PantCompFlag = false; // wyłączona, gdy nie trzymamy klawisza #else +/* + // NOTE: disabled to allow 'prototypical' 'tricking' pantograph compressor into running unattended if( ( ( DynamicObject->Mechanik != nullptr ) && ( false == DynamicObject->Mechanik->AIControllFlag ) ) && ( mvControlled->TrainType == dt_EZT ? @@ -5382,6 +5232,7 @@ bool TTrain::Update( double const Deltatime ) // NOTE: this will break in multiplayer setups, do a proper tracking of pantograph user then mvControlled->PantCompFlag = false; } +*/ #endif if (Console::Pressed(Global::Keys[k_Univ2])) { @@ -5875,6 +5726,46 @@ bool TTrain::Update( double const Deltatime ) } } + // catch cases where the power goes out, and the linebreaker state is left as closed + if( ( m_linebreakerstate == 1 ) + && ( false == mvControlled->Mains ) + && ( ggMainButton.GetValue() < 0.05 ) ) { + // crude way to catch cases where the main was knocked out and the user is trying to restart it + // because the state of the line breaker isn't changed to match, we need to do it here manually + m_linebreakerstate = 0; + } + + // NOTE: crude way to have the pantographs go back up if they're dropped due to insufficient pressure etc + // TODO: rework it into something more elegant, when redoing the whole consist/unit/cab etc arrangement + if( ( mvControlled->Battery ) + || ( mvControlled->ConverterFlag ) ) { + if( ( false == mvControlled->PantFrontUp ) + && ( ggPantFrontButton.GetValue() >= 1.0 ) ) { + mvControlled->PantFront( true ); + } + if( ( false == mvControlled->PantRearUp ) + && ( ggPantRearButton.GetValue() >= 1.0 ) ) { + mvControlled->PantRear( true ); + } + } +/* + // NOTE: disabled while switch state isn't preserved while moving between compartments + // check whether we should raise the pantographs, based on volume in pantograph tank + if( mvControlled->PantPress > ( + mvControlled->TrainType == dt_EZT ? + 2.4 : + 3.5 ) ) { + if( ( false == mvControlled->PantFrontUp ) + && ( ggPantFrontButton.GetValue() > 0.95 ) ) { + mvControlled->PantFront( true ); + } + if( ( false == mvControlled->PantRearUp ) + && ( ggPantRearButton.GetValue() > 0.95 ) ) { + mvControlled->PantRear( true ); + } + } +*/ + m_updated = true; return true; //(DynamicObject->Update(dt)); } // koniec update @@ -6708,31 +6599,23 @@ void TTrain::set_cab_controls() { // pantographs if( mvOccupied->PantSwitchType != "impulse" ) { ggPantFrontButton.PutValue( - ( mvOccupied->ActiveCab == 1 ? - mvControlled->PantFrontUp : - mvControlled->PantRearUp ) ? - 1.0 : - 0.0 ); + ( mvControlled->PantFrontUp ? + 1.0 : + 0.0 ) ); ggPantFrontButtonOff.PutValue( - ( mvOccupied->ActiveCab == 1 ? - mvControlled->PantFrontUp : - mvControlled->PantRearUp ) ? - 0.0 : - 1.0 ); + ( mvControlled->PantFrontUp ? + 0.0 : + 1.0 ) ); } if( mvOccupied->PantSwitchType != "impulse" ) { ggPantRearButton.PutValue( - ( mvOccupied->ActiveCab == 1 ? - mvControlled->PantRearUp : - mvControlled->PantFrontUp ) ? - 1.0 : - 0.0 ); + ( mvControlled->PantRearUp ? + 1.0 : + 0.0 ) ); ggPantRearButtonOff.PutValue( - ( mvOccupied->ActiveCab == 1 ? - mvControlled->PantRearUp : - mvControlled->PantFrontUp ) ? - 0.0 : - 1.0 ); + ( mvControlled->PantRearUp ? + 0.0 : + 1.0 ) ); } // converter if( mvOccupied->ConvSwitchType != "impulse" ) { diff --git a/World.cpp b/World.cpp index aaf67aa7..4a760c3f 100644 --- a/World.cpp +++ b/World.cpp @@ -714,6 +714,9 @@ void TWorld::OnKeyDown(int cKey) Train->OnKeyDown(cKey); // przekazanie klawisza do kabiny if (FreeFlyModeFlag) // aby nie odluźniało wagonu za lokomotywą { // operacje wykonywane na dowolnym pojeździe, przeniesione tu z kabiny +/* + // NOTE: disabled so it doesn't interfere with new system controls in outside view + // TODO: implement as part of the new system if (cKey == Global::Keys[k_Releaser]) // odluźniacz { // działa globalnie, sprawdzić zasięg TDynamicObject *temp = Global::DynamicNearest(); @@ -721,7 +724,7 @@ void TWorld::OnKeyDown(int cKey) { if (Global::ctrlState) // z ctrl odcinanie { - temp->MoverParameters->BrakeStatus ^= 128; + temp->MoverParameters->Hamulec->SetBrakeStatus( temp->MoverParameters->Hamulec->GetBrakeStatus() ^ 128 ); } else if (temp->MoverParameters->BrakeReleaser(1)) { @@ -731,7 +734,9 @@ void TWorld::OnKeyDown(int cKey) } } } - else if (cKey == Global::Keys[k_Heating]) // Ra: klawisz nie jest najszczęśliwszy + else +*/ + if (cKey == Global::Keys[k_Heating]) // Ra: klawisz nie jest najszczęśliwszy { // zmiana próżny/ładowny; Ra: zabrane z kabiny TDynamicObject *temp = Global::DynamicNearest(); if (temp) @@ -1799,12 +1804,12 @@ TWorld::Update_UI() { if( ( tmp->MoverParameters->BrakeDelayFlag & bdelay_M ) == bdelay_M ) uitextline2 += "+Mg"; - uitextline2 += ", BTP:" + to_string( tmp->MoverParameters->LoadFlag, 0 ); + uitextline2 += ", BTP: " + to_string( tmp->MoverParameters->LoadFlag, 0 ); { uitextline2 += - "; pant. " + "; pant: " + to_string( tmp->MoverParameters->PantPress, 2 ) - + ( tmp->MoverParameters->bPantKurek3 ? "MoverParameters->bPantKurek3 ? "-ZG" : "|ZG" ); } uitextline2 += @@ -1820,28 +1825,63 @@ TWorld::Update_UI() { uitextline2 += "; TC:" + to_string( tmp->MoverParameters->TotalCurrent, 0 ); +#ifdef EU07_USE_OLD_HVCOUPLERS uitextline2 += - ", HV0:" - + to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 1 ], 0 ) + ", HV0: " + + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::front ][ TMoverParameters::hvcoupler::voltage ], 0 ) + "@" - + to_string( tmp->MoverParameters->HVCouplers[ 0 ][ 0 ], 0 ); + + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::front ][ TMoverParameters::hvcoupler::current ], 0 ); uitextline2 += - ", HV1:" - + to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 1 ], 0 ) + ", HV1: " + + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::rear ][ TMoverParameters::hvcoupler::voltage ], 0 ) + "@" - + to_string( tmp->MoverParameters->HVCouplers[ 1 ][ 0 ], 0 ); + + to_string( tmp->MoverParameters->HVCouplers[ TMoverParameters::side::rear ][ TMoverParameters::hvcoupler::current ], 0 ); +#else + auto const frontcouplerhighvoltage = + to_string( tmp->MoverParameters->Couplers[ TMoverParameters::side::front ].power_high.voltage, 0 ) + + "@" + + to_string( tmp->MoverParameters->Couplers[ TMoverParameters::side::front ].power_high.current, 0 ); + auto const rearcouplerhighvoltage = + to_string( tmp->MoverParameters->Couplers[ TMoverParameters::side::rear ].power_high.voltage, 0 ) + + "@" + + to_string( tmp->MoverParameters->Couplers[ TMoverParameters::side::rear ].power_high.current, 0 ); + uitextline2 += ", HV: "; + if( tmp->MoverParameters->Couplers[ TMoverParameters::side::front ].power_high.local == false ) { + uitextline2 += + "(" + frontcouplerhighvoltage + ")-" + + ":F" + ( tmp->DirectionGet() ? "<<" : ">>" ) + "R:" + + "-(" + rearcouplerhighvoltage + ")"; + } + else { + uitextline2 += + frontcouplerhighvoltage + + ":F" + ( tmp->DirectionGet() ? "<<" : ">>" ) + "R:" + + rearcouplerhighvoltage; + } +#endif + // equipment flags + uitextline3 = ""; + uitextline3 += ( tmp->MoverParameters->Battery ? "B" : "." ); + uitextline3 += ( tmp->MoverParameters->Mains ? "M" : "." ); + uitextline3 += ( tmp->MoverParameters->PantRearUp ? ( tmp->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." );; + uitextline3 += ( tmp->MoverParameters->PantFrontUp ? ( tmp->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );; + uitextline3 += ( tmp->MoverParameters->PantPressLockActive ? "!" : ( tmp->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); + uitextline3 += ( tmp->MoverParameters->ConverterAllow ? ( tmp->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ); + uitextline3 += ( tmp->MoverParameters->ConvOvldFlag ? "!" : "." ); + uitextline3 += ( tmp->MoverParameters->CompressorAllow ? ( tmp->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ); + uitextline3 += ( tmp->MoverParameters->CompressorGovernorLock ? "!" : "." ); - uitextline3 = - "BP: " + to_string( tmp->MoverParameters->BrakePress, 2 ) - + " (" + to_string( tmp->MoverParameters->BrakeStatus, 0 ) - + "), LBP: " + to_string( tmp->MoverParameters->LocBrakePress, 2 ) - + ", PP: " + to_string( tmp->MoverParameters->PipePress, 2 ) + uitextline3 += + " TrB: " + to_string( tmp->MoverParameters->BrakePress, 2 ) + + ", " + to_hex_str( tmp->MoverParameters->Hamulec->GetBrakeStatus(), 2 ) + + ", LcB: " + to_string( tmp->MoverParameters->LocBrakePress, 2 ) + + ", pipes: " + to_string( tmp->MoverParameters->PipePress, 2 ) + "/" + to_string( tmp->MoverParameters->ScndPipePress, 2 ) + "/" + to_string( tmp->MoverParameters->EqvtPipePress, 2 ) - + ", BVP: " + to_string( tmp->MoverParameters->Volume, 3 ) - + ", " + to_string( tmp->MoverParameters->CntrlPipePress, 3 ) - + ", " + to_string( tmp->MoverParameters->Hamulec->GetCRP(), 3 ) - + ", " + to_string( tmp->MoverParameters->BrakeStatus, 0 ); + + ", MT: " + to_string( tmp->MoverParameters->CompressedVolume, 3 ) + + ", BT: " + to_string( tmp->MoverParameters->Volume, 3 ) + + ", CtlP: " + to_string( tmp->MoverParameters->CntrlPipePress, 3 ) + + ", CtlT: " + to_string( tmp->MoverParameters->Hamulec->GetCRP(), 3 ); if( tmp->MoverParameters->ManualBrakePos > 0 ) { @@ -1876,7 +1916,7 @@ TWorld::Update_UI() { + " VRd=" + to_string( tmp->Mechanik->VelRoad, 0 ); if( ( tmp->Mechanik->VelNext == 0.0 ) - && ( tmp->Mechanik->eSignNext ) ) { + && ( tmp->Mechanik->eSignNext ) ) { // jeśli ma zapamiętany event semafora, nazwa eventu semafora uitextline4 += " (" @@ -1895,13 +1935,13 @@ TWorld::Update_UI() { break; } - int i = 0; + std::size_t i = 0; std::size_t const speedtablesize = clamp( static_cast( tmp->Mechanik->TableSize() ) - 1, 0, 30 ); do { std::string scanline = tmp->Mechanik->TableText( i ); if( scanline.empty() ) { break; } UITable->text_lines.emplace_back( Global::Bezogonkow( scanline ), Global::UITextColor ); ++i; - } while( i < 16 ); // TController:iSpeedTableSize TODO: change when the table gets recoded + } while( i < speedtablesize ); // TController:iSpeedTableSize TODO: change when the table gets recoded } } else { @@ -1999,8 +2039,8 @@ TWorld::Update_UI() { } uitextline1 = - "vel: " + to_string(tmp->GetVelocity(), 2) + " km/h" - + "; dist: " + to_string(tmp->MoverParameters->DistCounter, 2) + " km" + "vel: " + to_string( tmp->GetVelocity(), 2 ) + " km/h" + ( tmp->MoverParameters->SlippingWheels ? " (!)" : "" ) + + "; dist: " + to_string( tmp->MoverParameters->DistCounter, 2 ) + " km" + "; pos: (" + to_string( tmp->GetPosition().x, 2 ) + ", " + to_string( tmp->GetPosition().y, 2 ) + ", " @@ -2533,7 +2573,7 @@ world_environment::update() { m_moon.update(); // ...determine source of key light and adjust global state accordingly... auto const sunlightlevel = m_sun.getIntensity(); - auto const moonlightlevel = m_moon.getIntensity(); + auto const moonlightlevel = m_moon.getIntensity() * 0.65f; // scaled down by arbitrary factor, it's pretty bright otherwise float keylightintensity; float twilightfactor; float3 keylightcolor; @@ -2555,8 +2595,6 @@ world_environment::update() { keylightintensity = sunlightlevel; // diffuse (sun) intensity goes down after twilight, and reaches minimum 18 degrees below horizon twilightfactor = clamp( -Global::SunAngle, 0.0f, 18.0f ) / 18.0f; - // TODO: crank orange up at dawn/dusk - keylightcolor = float3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ); float const duskfactor = 1.0f - clamp( Global::SunAngle, 0.0f, 18.0f ) / 18.0f; keylightcolor = interpolate( float3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), diff --git a/gamepadinput.h b/gamepadinput.h index 21b33cb7..ea7db03e 100644 --- a/gamepadinput.h +++ b/gamepadinput.h @@ -80,7 +80,7 @@ private: glm::vec2 m_leftstick; glm::vec2 m_rightstick; glm::vec2 m_triggers; - double m_modeaccumulator; // used to throttle command input rate for vehicle controls + double m_modeaccumulator{ 0.0 }; // used to throttle command input rate for vehicle controls }; //--------------------------------------------------------------------------- diff --git a/renderer.cpp b/renderer.cpp index afa09dfc..92e0eff5 100644 --- a/renderer.cpp +++ b/renderer.cpp @@ -871,9 +871,9 @@ opengl_renderer::Update ( double const Deltatime ) { int targetsegments; float targetfactor; - if( framerate > 65.0 ) { targetsegments = 400; targetfactor = 3.0f; } - else if( framerate > 40.0 ) { targetsegments = 225; targetfactor = 1.5f; } - else if( framerate > 15.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; } + if( framerate > 90.0 ) { targetsegments = 400; targetfactor = 3.0f; } + else if( framerate > 60.0 ) { targetsegments = 225; targetfactor = 1.5f; } + else if( framerate > 30.0 ) { targetsegments = 90; targetfactor = Global::ScreenHeight / 768.0f; } else { targetsegments = 9; targetfactor = Global::ScreenHeight / 768.0f * 0.75f; } if( targetsegments > Global::iSegmentsRendered ) { diff --git a/sun.cpp b/sun.cpp index 879709cb..d27e3619 100644 --- a/sun.cpp +++ b/sun.cpp @@ -258,8 +258,6 @@ void cSun::irradiance() { static double degrad = 57.295779513; // converts from radians to degrees static double raddeg = 0.0174532925; // converts from degrees to radians - auto const &localtime = simulation::Time.data(); // time for the calculation - m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0; double sd = sin( raddeg * m_body.dayang ); // sine of the day angle double cd = cos( raddeg * m_body.dayang ); // cosine of the day angle or delination