mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
4211 lines
199 KiB
C++
4211 lines
199 KiB
C++
//---------------------------------------------------------------------------
|
||
/*
|
||
MaSzyna EU07 locomotive simulator
|
||
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
||
|
||
*/
|
||
|
||
|
||
#include "system.hpp"
|
||
#include "classes.hpp"
|
||
#pragma hdrstop
|
||
|
||
#include "Driver.h"
|
||
#include <mtable.hpp>
|
||
#include "DynObj.h"
|
||
#include <math.h>
|
||
#include "Globals.h"
|
||
#include "Event.h"
|
||
#include "Ground.h"
|
||
#include "MemCell.h"
|
||
#include "World.h"
|
||
#include "dir.h"
|
||
|
||
#define LOGVELOCITY 0
|
||
#define LOGORDERS 0
|
||
#define LOGSTOPS 1
|
||
#define LOGBACKSCAN 0
|
||
#define LOGPRESS 0
|
||
/*
|
||
|
||
Moduł obsługujący sterowanie pojazdami (składami pociągów, samochodami).
|
||
Ma działać zarówno jako AI oraz przy prowadzeniu przez człowieka. W tym
|
||
drugim przypadku jedynie informuje za pomocą napisów o tym, co by zrobił
|
||
w tym pierwszym. Obejmuje zarówno maszynistę jak i kierownika pociągu
|
||
(dawanie sygnału do odjazdu).
|
||
|
||
Przeniesiona tutaj została zawartość ai_driver.pas przerobiona na C++.
|
||
Również niektóre funkcje dotyczące składów z DynObj.cpp.
|
||
|
||
Teoria jest wtedy kiedy wszystko wiemy, ale nic nie działa.
|
||
Praktyka jest wtedy, kiedy wszystko działa, ale nikt nie wie dlaczego.
|
||
Tutaj łączymy teorię z praktyką - tu nic nie działa i nikt nie wie dlaczego…
|
||
|
||
*/
|
||
|
||
|
||
//zrobione:
|
||
//0. pobieranie komend z dwoma parametrami
|
||
//1. przyspieszanie do zadanej predkosci, ew. hamowanie jesli przekroczona
|
||
//2. hamowanie na zadanym odcinku do zadanej predkosci (ze stabilizacja przyspieszenia)
|
||
//3. wychodzenie z sytuacji awaryjnych: bezpiecznik nadmiarowy, poslizg
|
||
//4. przygotowanie pojazdu do drogi, zmiana kierunku ruchu
|
||
//5. dwa sposoby jazdy - manewrowy i pociagowy
|
||
//6. dwa zestawy psychiki: spokojny i agresywny
|
||
//7. przejscie na zestaw spokojny jesli wystepuje duzo poslizgow lub wybic nadmiarowego.
|
||
//8. lagodne ruszanie (przedluzony czas reakcji na 2 pierwszych nastawnikach)
|
||
//9. unikanie jazdy na oporach rozruchowych
|
||
//10. logowanie fizyki //Ra: nie przeniesione do C++
|
||
//11. kasowanie czuwaka/SHP
|
||
//12. procedury wspomagajace "patrzenie" na odlegle semafory
|
||
//13. ulepszone procedury sterowania
|
||
//14. zglaszanie problemow z dlugim staniem na sygnale S1
|
||
//15. sterowanie EN57
|
||
//16. zmiana kierunku //Ra: z przesiadką po ukrotnieniu
|
||
//17. otwieranie/zamykanie drzwi
|
||
//18. Ra: odczepianie z zahamowaniem i podczepianie
|
||
//19. dla Humandriver: tasma szybkosciomierza - zapis do pliku!
|
||
|
||
//do zrobienia:
|
||
//1. kierownik pociagu
|
||
//2. madrzejsze unikanie grzania oporow rozruchowych i silnika
|
||
//3. unikanie szarpniec, zerwania pociagu itp
|
||
//4. obsluga innych awarii
|
||
//5. raportowanie problemow, usterek nie do rozwiazania
|
||
//7. samouczacy sie algorytm hamowania
|
||
|
||
//stałe
|
||
const double EasyReactionTime=0.5; //[s] przebłyski świadomości dla zwykłej jazdy
|
||
const double HardReactionTime=0.2;
|
||
const double EasyAcceleration=0.5; //[m/ss]
|
||
const double HardAcceleration=0.9;
|
||
const double PrepareTime =2.0; //[s] przebłyski świadomości przy odpalaniu
|
||
bool WriteLogFlag=false;
|
||
|
||
AnsiString StopReasonTable[]=
|
||
{//przyczyny zatrzymania ruchu AI
|
||
"", //stopNone, //nie ma powodu - powinien jechać
|
||
"Off", //stopSleep, //nie został odpalony, to nie pojedzie
|
||
"Semaphore", //stopSem, //semafor zamknięty
|
||
"Time", //stopTime, //czekanie na godzinę odjazdu
|
||
"End of track", //stopEnd, //brak dalszej części toru
|
||
"Change direction", //stopDir, //trzeba stanąć, by zmienić kierunek jazdy
|
||
"Joining", //stopJoin, //zatrzymanie przy (p)odczepianiu
|
||
"Block", //stopBlock, //przeszkoda na drodze ruchu
|
||
"A command", //stopComm, //otrzymano taką komendę (niewiadomego pochodzenia)
|
||
"Out of station", //stopOut, //komenda wyjazdu poza stację (raczej nie powinna zatrzymywać!)
|
||
"Radiostop", //stopRadio, //komunikat przekazany radiem (Radiostop)
|
||
"External", //stopExt, //przesłany z zewnątrz
|
||
"Error", //stopError //z powodu błędu w obliczeniu drogi hamowania
|
||
};
|
||
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
|
||
void __fastcall TSpeedPos::Clear()
|
||
{
|
||
iFlags=0; //brak flag to brak reakcji
|
||
fVelNext=-1.0; //prędkość bez ograniczeń
|
||
fDist=0.0;
|
||
vPos=vector3(0,0,0);
|
||
trTrack=NULL; //brak wskaźnika
|
||
};
|
||
|
||
void __fastcall TSpeedPos::CommandCheck()
|
||
{//sprawdzenie typu komendy w evencie i określenie prędkości
|
||
TCommandType command=evEvent->Command();
|
||
double value1=evEvent->ValueGet(1);
|
||
double value2=evEvent->ValueGet(2);
|
||
if (command==cm_ShuntVelocity)
|
||
{//prędkość manewrową zapisać, najwyżej AI zignoruje przy analizie tabelki
|
||
fVelNext=value1; //powinno być value2, bo druga określa "za"?
|
||
iFlags|=0x200;
|
||
}
|
||
else if (command==cm_SetVelocity)
|
||
{//w semaforze typu "m" jest ShuntVelocity dla Ms2 i SetVelocity dla S1
|
||
//SetVelocity * 0 -> można jechać, ale stanąć przed
|
||
//SetVelocity 0 20 -> stanąć przed, potem można jechać 20 (SBL)
|
||
//SetVelocity -1 100 -> można jechać, przy następnym ograniczenie (SBL)
|
||
//SetVelocity 40 -1 -> PutValues: jechać 40 aż do minięcia (koniec ograniczenia(
|
||
fVelNext=value1;
|
||
iFlags&=~0xE00; //nie manewrowa, nie przystanek, nie zatrzymać na SBL
|
||
if (value1==0.0) //jeśli pierwsza zerowa
|
||
if (value2!=0.0) //a druga nie
|
||
{//S1 na SBL, można przejechać po zatrzymaniu (tu nie mamy prędkości ani odległości)
|
||
fVelNext=value2; //normalnie będzie zezwolenie na jazdę, aby się usunął z tabelki
|
||
iFlags|=0x800; //flaga, że ma zatrzymać; na pewno nie zezwoli na manewry
|
||
}
|
||
}
|
||
else if (command==cm_PassengerStopPoint) //nie ma dostępu do rozkładu
|
||
{//przystanek, najwyżej AI zignoruje przy analizie tabelki
|
||
if ((iFlags&0x400)==0)
|
||
fVelNext=0.0; //TrainParams->IsStop()?0.0:-1.0; //na razie tak
|
||
iFlags|=0x400; //niestety nie da się w tym miejscu współpracować z rozkładem
|
||
}
|
||
else if (command==cm_SetProximityVelocity)
|
||
{//ignorować
|
||
fVelNext=-1;
|
||
}
|
||
else if (command==cm_OutsideStation)
|
||
{//w trybie manewrowym: skanować od niej wstecz i stanąć po wyjechaniu za sygnalizator i zmienić kierunek
|
||
//w trybie pociągowym: można przyspieszyć do wskazanej prędkości (po zjechaniu z rozjazdów)
|
||
fVelNext=-1;
|
||
iFlags|=0x2100; //W5
|
||
}
|
||
else
|
||
{//inna komenda w evencie skanowanym powoduje zatrzymanie i wysłanie tej komendy
|
||
iFlags&=~0xE00; //nie manewrowa, nie przystanek, nie zatrzymać na SBL
|
||
fVelNext=0; //jak nieznana komenda w komórce sygnałowej, to ma stać
|
||
}
|
||
};
|
||
|
||
bool __fastcall 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?)
|
||
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
|
||
{//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&32) //32 ustawione, gdy obiekt już został minięty
|
||
{//jeśli minięty (musi być minięty również przez końcówkę składu)
|
||
}
|
||
else
|
||
{iFlags^=32; //32-minięty - będziemy liczyć odległość względem przeciwnego końca toru (nadal może być z przodu i ogdaniczać)
|
||
if ((iFlags&0x43)==3) //tylko jeśli (istotny) tor, bo eventy są punktowe
|
||
if (trTrack) //może być NULL, jeśli koniec toru (????)
|
||
vPos=(iFlags&4)?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&32)==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ć problem z wektorem kierunku)
|
||
len=fDist=len+fDist; //zliczanie dlugości narastająco
|
||
*p=vPos; //nowy punkt odniesienia
|
||
*dir=Normalize(v); //nowy wektor kierunku od poprzedniego obiektu do aktualnego
|
||
}
|
||
if (iFlags&2) //jeśli tor
|
||
{
|
||
if (trTrack) //może być NULL, jeśli koniec toru (???)
|
||
{fVelNext=trTrack->VelocityGet(); //aktualizacja prędkości (może być zmieniana eventem)
|
||
int i;
|
||
if ((i=iFlags&0xF0000000)!=0)
|
||
{//jeśli skrzyżowanie, ograniczyć prędkość przy skręcaniu
|
||
if (abs(i)>0x10000000) //±1 to jazda na wprost, ±2 nieby też, ale z przecięciem głównej drogi - chyba że jest równorzędne...
|
||
fVelNext=30.0; //uzależnić prędkość od promienia; albo niech będzie ograniczona w skrzyżowaniu (velocity z ujemną wartością)
|
||
if ((iFlags&32)==0) //jeśli nie wjechał
|
||
if (trTrack->iNumDynamics>0) //a skrzyżowanie zawiera pojazd
|
||
fVelNext=0.0; //to zabronić wjazdu (chyba że ten z przodu też jedzie prosto)
|
||
}
|
||
if (iFlags&8) //jeśli odcinek zmienny
|
||
{if (bool(trTrack->GetSwitchState()&1)!=bool(iFlags&16)) //czy stan się zmienił?
|
||
{//Ra: zakładam, że są tylko 2 możliwe stany
|
||
iFlags^=16;
|
||
//fVelNext=trTrack->VelocityGet(); //nowa prędkość
|
||
if ((iFlags&32)==0) return true; //jeszcze trzeba skanowanie wykonać od tego toru
|
||
//problem jest chyba, jeśli zwrotnica się przełoży zaraz po zjechaniu z niej
|
||
//na Mydelniczce potrafi skanować na wprost mimo pojechania na bok
|
||
}
|
||
//poniższe nie dotyczy trybu łączenia?
|
||
if ((iFlags&32)?false:trTrack->iNumDynamics>0) //jeśli jeszcze nie wjechano na tor, a coś na nim jest
|
||
fDist-=30.0,fVelNext=0.0; //to niech stanie w zwiększonej odległości
|
||
//else if (fVelNext==0.0) //jeśli została wyzerowana
|
||
// fVelNext=trTrack->VelocityGet(); //odczyt prędkości
|
||
}
|
||
}
|
||
}
|
||
else if (iFlags&0x100) //jeśli event
|
||
{//odczyt komórki pamięci najlepiej by było zrobić jako notyfikację, czyli zmiana komórki wywoła jakąś podaną funkcję
|
||
CommandCheck(); //sprawdzenie typu komendy w evencie i określenie prędkości
|
||
}
|
||
return false;
|
||
};
|
||
|
||
AnsiString __fastcall TSpeedPos::TableText()
|
||
{//pozycja tabelki prędkości
|
||
if (iFlags&0x1)
|
||
{//o ile pozycja istotna
|
||
if (iFlags&0x2) //jeśli tor
|
||
return "Flags=#"+IntToHex(iFlags,8)+", Dist="+FloatToStrF(fDist,ffFixed,7,1)+", Vel="+AnsiString(fVelNext)+", Track="+trTrack->NameGet();
|
||
else if (iFlags&0x100) //jeśli event
|
||
return "Flags=#"+IntToHex(iFlags,8)+", Dist="+FloatToStrF(fDist,ffFixed,7,1)+", Vel="+AnsiString(fVelNext)+", Event="+evEvent->asName;
|
||
}
|
||
return "Empty";
|
||
}
|
||
|
||
bool __fastcall TSpeedPos::Set(TEvent *e,double d)
|
||
{//zapamiętanie zdarzenia
|
||
fDist=d;
|
||
iFlags=0x101; //event+istotny
|
||
evEvent=e;
|
||
vPos=e->PositionGet(); //współrzędne eventu albo komórki pamięci (zrzutować na tor?)
|
||
CommandCheck(); //sprawdzenie typu komendy w evencie i określenie prędkości
|
||
return fVelNext==0.0; //true gdy zatrzymanie, wtedy nie ma po co skanować dalej
|
||
};
|
||
|
||
void __fastcall TSpeedPos::Set(TTrack *t,double d,int f)
|
||
{//zapamiętanie zmiany prędkości w torze
|
||
fDist=d; //odległość do początku toru
|
||
trTrack=t; //TODO: (t) może być NULL i nie odczytamy końca poprzedniego :/
|
||
if (trTrack)
|
||
{iFlags=f|(trTrack->eType==tt_Normal?2:10); //zapamiętanie kierunku wraz z typem
|
||
if (iFlags&8) if (trTrack->GetSwitchState()&1) iFlags|=16;
|
||
fVelNext=trTrack->VelocityGet();
|
||
if (trTrack->iDamageFlag&128) fVelNext=0.0; //jeśli uszkodzony, to też stój
|
||
if (iFlags&64)
|
||
fVelNext=(trTrack->iCategoryFlag&1)?0.0:20.0; //jeśli koniec, to pociąg stój, a samochód zwolnij
|
||
vPos=(bool(iFlags&4)!=bool(iFlags&64))?trTrack->CurrentSegment()->FastGetPoint_1():trTrack->CurrentSegment()->FastGetPoint_0();
|
||
}
|
||
};
|
||
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
|
||
void __fastcall TController::TableClear()
|
||
{//wyczyszczenie tablicy
|
||
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
|
||
};
|
||
|
||
TEvent* __fastcall TController::CheckTrackEvent(double fDirection,TTrack *Track)
|
||
{//sprawdzanie eventów na podanym torze do podstawowego skanowania
|
||
TEvent* e=(fDirection>0)?Track->evEvent2:Track->evEvent1;
|
||
if (!e) return NULL;
|
||
if (e->bEnabled) return NULL;
|
||
//jednak wszystkie W4 do tabelki, bo jej czyszczenie na przystanku wprowadza zamieszanie
|
||
return e;
|
||
}
|
||
|
||
bool __fastcall TController::TableAddNew()
|
||
{//zwiększenie użytej tabelki o jeden rekord
|
||
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)
|
||
return true; //false gdy się nałoży
|
||
};
|
||
|
||
bool __fastcall TController::TableNotFound(TEvent *e)
|
||
{//sprawdzenie, czy nie został już dodany do tabelki (np. podwójne W4 robi problemy)
|
||
int i,j=(iLast+1)%iSpeedTableSize; //j, aby sprawdzić też ostatnią pozycję
|
||
for (i=iFirst;i!=j;i=(i+1)%iSpeedTableSize)
|
||
if ((sSpeedTable[i].iFlags&0x101)==0x101) //o ile używana pozycja
|
||
if (sSpeedTable[i].evEvent==e)
|
||
return false; //już jest, drugi raz dodawać nie ma po co
|
||
return true; //nie ma, czyli można dodać
|
||
};
|
||
|
||
void __fastcall TController::TableTraceRoute(double fDistance,TDynamicObject *pVehicle)
|
||
{//skanowanie trajektorii na odległość (fDistance) od (pVehicle) w kierunku przodu składu i uzupełnianie tabelki
|
||
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
|
||
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
|
||
fLastVel=pTrack->VelocityGet(); //aktualna prędkość
|
||
iTableDirection=iDirection; //ustalenie w jakim kierunku jest wypełniana tabelka względem pojazdu
|
||
iFirst=iLast=0;
|
||
tLast=NULL; //żaden nie sprawdzony
|
||
}
|
||
else
|
||
{//kontynuacja skanowania od ostatnio sprawdzonego toru (w ostatniej pozycji zawsze jest tor)
|
||
if (sSpeedTable[iLast].iFlags&0x10000) //zatkanie
|
||
{//jeśli zapełniła się tabelka
|
||
if ((iLast+1)%iSpeedTableSize==iFirst) //jeśli nadal jest zapełniona
|
||
return; //nic się nie da zrobić
|
||
if ((iLast+2)%iSpeedTableSize==iFirst) //musi być jeszcze miejsce wolne na ewentualny event, bo tor jeszcze nie sprawdzony
|
||
return; //już lepiej, ale jeszcze nie tym razem
|
||
sSpeedTable[iLast].iFlags&=0xBE; //kontynuować próby doskanowania
|
||
}
|
||
else
|
||
if (VelNext==0) return; //znaleziono semafor lub tor z prędkością zero i nie ma co dalej sprawdzać
|
||
pTrack=sSpeedTable[iLast].trTrack; //ostatnio sprawdzony tor
|
||
if (!pTrack) return; //koniec toru, to nie ma co sprawdzać (nie ma prawa tak być)
|
||
fLastDir=sSpeedTable[iLast].iFlags&4?-1.0:1.0; //flaga ustawiona, gdy Point2 toru jest bliżej
|
||
fCurrentDistance=sSpeedTable[iLast].fDist; //aktualna odległość do jego Point1
|
||
fTrackLength=sSpeedTable[iLast].iFlags&0x60?0.0:pTrack->Length(); //nie doliczać długości gdy: 32-minięty początek, 64-jazda do końca toru
|
||
}
|
||
if (fCurrentDistance<fDistance)
|
||
{//jeśli w ogóle jest po co analizować
|
||
--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 ((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 (sSpeedTable[iLast].Set(pEvent,fCurrentDistance)) //dodanie odczytu sygnału
|
||
fDistance=fCurrentDistance; //jeśli sygnał stop, to nie ma potrzeby dalej skanować
|
||
}
|
||
} //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&=~4; //usunięcie flagi kierunku, bo może być błędna
|
||
if (sSpeedTable[iLast].iFlags<0) sSpeedTable[iLast].iFlags|=4; //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
|
||
}
|
||
}
|
||
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
|
||
}
|
||
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
|
||
}
|
||
}
|
||
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
|
||
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
|
||
}
|
||
}
|
||
if (TableAddNew())
|
||
sSpeedTable[iLast].Set(pTrack,fCurrentDistance,fLastDir<0?4:0); //zapisanie ostatniego sprawdzonego toru
|
||
}
|
||
};
|
||
|
||
void __fastcall 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
|
||
else if (iTableDirection)
|
||
{//trzeba sprawdzić, czy coś się zmieniło
|
||
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)
|
||
{//aktualizacja rekordów z wyjątkiem ostatniego
|
||
if (sSpeedTable[i].iFlags&1) //jeśli pozycja istotna
|
||
{if (sSpeedTable[i].Update(&pos,&dir,len))
|
||
{iLast=i; //wykryta zmiana zwrotnicy - konieczne ponowne przeskanowanie dalszej części
|
||
break; //nie kontynuujemy pętli, trzeba doskanować ciąg dalszy
|
||
}
|
||
if (sSpeedTable[i].iFlags&2) //jeśli odcinek
|
||
{if (sSpeedTable[i].fDist<-fLength) //a skład wyjechał całą długością poza
|
||
{//degradacja pozycji
|
||
sSpeedTable[i].iFlags&=~1; //nie liczy się
|
||
}
|
||
else if ((sSpeedTable[i].iFlags&0xF0000028)==0x20) //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)
|
||
}
|
||
else if (sSpeedTable[i].iFlags&0x100) //jeśli event
|
||
{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ą)
|
||
sSpeedTable[i].iFlags&=~1; //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
|
||
if (sSpeedTable[iLast].fDist<fDistance)
|
||
TableTraceRoute(fDistance,pVehicles[1]); //doskanowanie dalszego odcinka
|
||
}
|
||
};
|
||
|
||
TCommandType __fastcall TController::TableUpdate(double &fVelDes,double &fDist,double &fNext,double &fAcc)
|
||
{//ustalenie parametrów, zwraca typ komendy, jeśli sygnał podaje prędkość do jazdy
|
||
//fVelDes - prędkość zadana
|
||
//fDist - dystans w jakim należy rozważyć ruch
|
||
//fNext - prędkość na końcu tego dystansu
|
||
//fAcc - zalecane przyspieszenie w chwili obecnej - kryterium wyboru dystansu
|
||
double a; //przyspieszenie
|
||
double v; //prędkość
|
||
double d; //droga
|
||
TCommandType go=cm_Unknown;
|
||
eSignNext=NULL;
|
||
int i,k=iLast-iFirst+1;
|
||
if (k<0) k+=iSpeedTableSize; //ilość pozycji do przeanalizowania
|
||
iDrivigFlags&=~(moveTrackEnd|moveSwitchFound); //te flagi są ustawiane tutaj, w razie potrzeby
|
||
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&1) //badanie istotności
|
||
{//o ile dana pozycja tabelki jest istotna
|
||
if (sSpeedTable[i].iFlags&0x400)
|
||
{//jeśli przystanek, trzeba obsłużyć wg rozkładu
|
||
if (sSpeedTable[i].evEvent->CommandGet()!=asNextStop)
|
||
{//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)
|
||
continue; //ignorowanie jakby nie było tej pozycji
|
||
}
|
||
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)
|
||
#if LOGSTOPS
|
||
WriteLog(pVehicle->asName+" as "+TrainParams->TrainName+": at "+AnsiString(GlobalTime->hh)+":"+AnsiString(GlobalTime->mm)+" skipped "+asNextStop); //informacja
|
||
#endif
|
||
fLastStopExpDist=mvOccupied->DistCounter+0.250+0.001*fLength; //przy jakim dystansie (stanie licznika) ma przesunąć na następny postój
|
||
TrainParams->UpdateMTable(GlobalTime->hh,GlobalTime->mm,asNextStop.SubString(20,asNextStop.Length()));
|
||
TrainParams->StationIndexInc(); //przejście do następnej
|
||
asNextStop=TrainParams->NextStop(); //pobranie kolejnego miejsca zatrzymania
|
||
//TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł
|
||
sSpeedTable[i].iFlags=0; //nie liczy się już
|
||
sSpeedTable[i].fVelNext=-1; //jechać
|
||
continue; //nie analizować prędkości
|
||
}
|
||
} //koniec obsługi przelotu na W4
|
||
else
|
||
{//zatrzymanie na W4
|
||
if (!eSignNext) eSignNext=sSpeedTable[i].evEvent;
|
||
if (mvOccupied->Vel>0.3) //jeśli jedzie (nie trzeba czekać, aż się drgania wytłumią - drzwi zamykane od 1.0)
|
||
sSpeedTable[i].fVelNext=0; //to będzie zatrzymanie
|
||
//else if ((iDrivigFlags&moveStopCloser)?sSpeedTable[i].fDist<=fMaxProximityDist*(AIControllFlag?1.0:10.0):true)
|
||
else if ((iDrivigFlags&moveStopCloser)?sSpeedTable[i].fDist+fLength<=Max0R(sSpeedTable[i].evEvent->ValueGet(2),fMaxProximityDist+fLength):true)
|
||
//Ra 2F1I: odległość plus długość pociągu musi być mniejsza od długości peronu, chyba że pociąg jest dłuższy, to wtedy minimalna
|
||
//jeśli długość peronu ((sSpeedTable[i].evEvent->ValueGet(2)) nie podana, przyjąć odległość fMinProximityDist
|
||
{//jeśli się zatrzymał przy W4, albo stał w momencie zobaczenia W4
|
||
if (!AIControllFlag) //AI tylko sobie otwiera drzwi
|
||
iDrivigFlags&=~moveStopCloser; //w razie przełączenia na AI ma nie podciągać do W4, gdy użytkownik zatrzymał za daleko
|
||
if ((iDrivigFlags&moveDoorOpened)==0)
|
||
{//drzwi otwierać jednorazowo
|
||
iDrivigFlags|=moveDoorOpened; //nie wykonywać drugi raz
|
||
if (mvOccupied->DoorOpenCtrl==1) //(mvOccupied->TrainType==dt_EZT)
|
||
{//otwieranie drzwi w EZT
|
||
if (AIControllFlag) //tylko AI otwiera drzwi EZT, użytkownik musi samodzielnie
|
||
if (!mvOccupied->DoorLeftOpened&&!mvOccupied->DoorRightOpened)
|
||
{//otwieranie drzwi
|
||
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 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
|
||
// 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 (20m bezpieczniej, bo nie modyfikuje bitu 1)
|
||
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
|
||
prawe=3-lewe;
|
||
p->MoverParameters->BatterySwitch(true); //wagony muszą mieć baterię załączoną do otwarcia drzwi...
|
||
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)
|
||
}
|
||
//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
|
||
WaitingSet(10); //10 sekund (wziąć z rozkładu????) - czekanie niezależne od sposobu obsługi drzwi, bo opóźnia również kierownika
|
||
}
|
||
if (TrainParams->UpdateMTable(GlobalTime->hh,GlobalTime->mm,asNextStop.SubString(20,asNextStop.Length())))
|
||
{//to się wykona tylko raz po zatrzymaniu na W4
|
||
if (TrainParams->CheckTrainLatency()<0.0)
|
||
iDrivigFlags|=moveLate; //odnotowano spóźnienie
|
||
else
|
||
iDrivigFlags&=~moveLate; //przyjazd o czasie
|
||
if (TrainParams->DirectionChange()) //jeśli "@" w rozkładzie, to wykonanie dalszych komend
|
||
{//wykonanie kolejnej komendy, nie dotyczy ostatniej stacji
|
||
if (iDrivigFlags&movePushPull) //SN61 ma się też nie ruszać, chyba że ma wagony
|
||
{iDrivigFlags|=moveStopHere; //EZT ma stać przy peronie
|
||
if (OrderNextGet()!=Change_direction)
|
||
{OrderPush(Change_direction); //zmiana kierunku
|
||
OrderPush(TrainParams->StationIndex<TrainParams->StationCount?Obey_train:Shunt); //to dalej wg rozkładu
|
||
}
|
||
}
|
||
else //a dla lokomotyw...
|
||
iDrivigFlags&=~(moveStopPoint|moveStopHere); //pozwolenie na przejechanie za W4 przed czasem i nie ma stać
|
||
JumpToNextOrder(); //przejście do kolejnego rozkazu (zmiana kierunku, odczepianie)
|
||
iDrivigFlags&=~moveStopCloser; //ma nie podjeżdżać pod W4 po przeciwnej stronie
|
||
sSpeedTable[i].iFlags=0; //ten W4 nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||
sSpeedTable[i].fVelNext=-1; //jechać
|
||
continue; //nie analizować prędkości
|
||
}
|
||
}
|
||
if (OrderCurrentGet()==Shunt)
|
||
{OrderNext(Obey_train); //uruchomić jazdę pociągową
|
||
CheckVehicles(); //zmienić światła
|
||
}
|
||
if (TrainParams->StationIndex<TrainParams->StationCount)
|
||
{//jeśli są dalsze stacje, czekamy do godziny odjazdu
|
||
if (TrainParams->IsTimeToGo(GlobalTime->hh,GlobalTime->mm))
|
||
{//z dalszą akcją czekamy do godziny odjazdu
|
||
//if (TrainParams->CheckTrainLatency()<0.0) //jak się ma odjazd do czasu odjazdu?
|
||
// iDrivigFlags|=moveLate1; //oflagować, gdy odjazd ze spóźnieniem, będzie jechał forsowniej
|
||
fLastStopExpDist=mvOccupied->DistCounter+0.050+0.001*fLength; //przy jakim dystansie (stanie licznika) ma przesunąć na następny postój
|
||
// Controlled-> //zapisać odległość do przejechania
|
||
TrainParams->StationIndexInc(); //przejście do następnej
|
||
asNextStop=TrainParams->NextStop(); //pobranie kolejnego miejsca zatrzymania
|
||
//TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł
|
||
#if LOGSTOPS
|
||
WriteLog(pVehicle->asName+" as "+TrainParams->TrainName+": at "+AnsiString(GlobalTime->hh)+":"+AnsiString(GlobalTime->mm)+" next "+asNextStop); //informacja
|
||
#endif
|
||
if (int(floor(sSpeedTable[i].evEvent->ValueGet(1)))&1)
|
||
iDrivigFlags|=moveStopHere; //nie podjeżdżać do semafora, jeśli droga nie jest wolna
|
||
iDrivigFlags|=moveStopCloser; //do następnego W4 podjechać blisko (z dociąganiem)
|
||
iDrivigFlags&=~moveStartHorn; //bez trąbienia przed odjazdem
|
||
sSpeedTable[i].iFlags=0; //nie liczy się już zupełnie (nie wyśle SetVelocity)
|
||
sSpeedTable[i].fVelNext=-1; //można jechać za W4
|
||
if (go==cm_Unknown) //jeśli nie było komendy wcześniej
|
||
go=cm_Ready; //gotów do odjazdu z W4 (semafor może zatrzymać)
|
||
if (tsGuardSignal) //jeśli mamy głos kierownika, to odegrać
|
||
iDrivigFlags|=moveGuardSignal;
|
||
continue; //nie analizować prędkości
|
||
} //koniec startu z zatrzymania
|
||
} //koniec obsługi początkowych stacji
|
||
else
|
||
{//jeśli dojechaliśmy do końca rozkładu
|
||
#if LOGSTOPS
|
||
WriteLog(pVehicle->asName+" as "+TrainParams->TrainName+": at "+AnsiString(GlobalTime->hh)+":"+AnsiString(GlobalTime->mm)+" end of route."); //informacja
|
||
#endif
|
||
asNextStop=TrainParams->NextStop(); //informacja o końcu trasy
|
||
TrainParams->NewName("none"); //czyszczenie nieaktualnego rozkładu
|
||
//TableClear(); //aby od nowa sprawdziło W4 z inną nazwą już - to nie jest dobry pomysł
|
||
iDrivigFlags&=~(moveStopCloser|moveStopPoint); //ma nie podjeżdżać pod W4 i ma je pomijać
|
||
sSpeedTable[i].iFlags=0; //W4 nie liczy się już (nie wyśle SetVelocity)
|
||
sSpeedTable[i].fVelNext=-1; //można jechać za W4
|
||
fLastStopExpDist=-1.0f; //nie ma rozkładu, nie ma usuwania stacji
|
||
WaitingSet(60); //tak ze 2 minuty, aż wszyscy wysiądą
|
||
JumpToNextOrder(); //wykonanie kolejnego rozkazu (Change_direction albo Shunt)
|
||
iDrivigFlags|=moveStopHere|moveStartHorn; //ma się nie ruszać aż do momentu podania sygnału
|
||
continue; //nie analizować prędkości
|
||
} //koniec obsługi ostatniej stacji
|
||
} //if (MoverParameters->Vel==0.0)
|
||
} //koniec obsługi zatrzymania na W4
|
||
} //koniec warunku pomijania W4 podczas zmiany czoła
|
||
else
|
||
{//skoro pomijanie, to jechać i ignorować W4
|
||
sSpeedTable[i].iFlags=0; //W4 nie liczy się już (nie zatrzymuje jazdy)
|
||
sSpeedTable[i].fVelNext=-1;
|
||
continue; //nie analizować prędkości
|
||
}
|
||
} //koniec obsługi W4
|
||
v=sSpeedTable[i].fVelNext; //odczyt prędkości do zmiennej pomocniczej
|
||
if (sSpeedTable[i].iFlags&8) //zwrotnice są usuwane z tabelki dopiero po zjechaniu z nich
|
||
iDrivigFlags|=moveSwitchFound; //rozjazd z przodu/pod ogranicza np. sens skanowania wstecz
|
||
else if (sSpeedTable[i].iFlags&0x100) //W4 może się deaktywować
|
||
{//jeżeli event, może być potrzeba wysłania komendy, aby ruszył
|
||
if (sSpeedTable[i].iFlags&0x2000)
|
||
{//jeśli W5, to reakcja zależna od trybu jazdy
|
||
if (OrderCurrentGet()&Obey_train)
|
||
{//w trybie pociągowym: można przyspieszyć do wskazanej prędkości (po zjechaniu z rozjazdów)
|
||
v=-1.0; //ignorować?
|
||
if (sSpeedTable[i].fDist<0.0) //jeśli wskaźnik został minięty
|
||
{VelSignal=v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to
|
||
// iStationStart=TrainParams->StationIndex; //zaktualizować wyświetlanie rozkładu
|
||
}
|
||
else if (!(iDrivigFlags&moveSwitchFound)) //jeśli rozjazdy już minięte
|
||
VelSignal=v; //!!! to też koniec ograniczenia
|
||
}
|
||
else
|
||
{//w trybie manewrowym: skanować od niego wstecz, stanąć po wyjechaniu za sygnalizator i zmienić kierunek
|
||
v=0.0; //zmiana kierunku może być podanym sygnałem, ale wypadało by zmienić światło wcześniej
|
||
if (!(iDrivigFlags&moveSwitchFound)) //jeśli nie ma rozjazdu
|
||
iDrivigFlags|=moveTrackEnd; //to dalsza jazda trwale ograniczona (W5, koniec toru)
|
||
}
|
||
}
|
||
else if (sSpeedTable[i].iFlags&0x800)
|
||
{//jeśli S1 na SBL
|
||
if (mvOccupied->Vel<2.0) //stanąć nie musi, ale zwolnić przynajmniej
|
||
if (sSpeedTable[i].fDist<fMaxProximityDist) //jest w maksymalnym zasięgu
|
||
{eSignSkip=sSpeedTable[i].evEvent; //to można go pominąć (wziąć drugą prędkosć)
|
||
iDrivigFlags|=moveVisibility; //jazda na widoczność - skanować możliwość kolizji i nie podjeżdżać zbyt blisko
|
||
//usunąć flagę po podjechaniu blisko semafora zezwalającego na jazdę
|
||
//ostrożnie interpretować sygnały - semafor może zezwalać na jazdę pociągu z przodu!
|
||
}
|
||
if (eSignSkip!=sSpeedTable[i].evEvent) //jeśli ten SBL nie jest do pominięcia
|
||
v=sSpeedTable[i].evEvent->ValueGet(1); //to ma 0 odczytywać
|
||
}
|
||
if ((mvOccupied->CategoryFlag&1)?sSpeedTable[i].fDist>pVehicles[0]->fTrackBlock-20.0:false) //jak sygnał jest dalej niż zawalidroga
|
||
v=0.0; //to może być podany dla tamtego: jechać tak, jakby tam stop był
|
||
else
|
||
{//zawalidrogi nie ma (albo pojazd jest samochodem), sprawdzić sygnał
|
||
if (sSpeedTable[i].iFlags&0x200) //jeśli Tm - w zasadzie to sprawdzić komendę!
|
||
{//jeśli podana prędkość manewrowa
|
||
if ((OrderCurrentGet()&Obey_train)?v==0.0:false)
|
||
{//jeśli tryb pociągowy a tarcze ma ShuntVelocity 0 0
|
||
v=-1; //ignorować, chyba że prędkość stanie się niezerowa
|
||
if (sSpeedTable[i].iFlags&0x20) //a jak przejechana
|
||
sSpeedTable[i].iFlags=0; //to można usunąć, bo podstawowy automat usuwa tylko niezerowe
|
||
}
|
||
else
|
||
if (go<=cm_Ready) //jeśli jeszcze nie ma komendy
|
||
if (v!=0.0) //komenda jest tylko gdy ma jechać, bo stoi na podstawie tabelki
|
||
{//jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie VelSignal
|
||
go=cm_ShuntVelocity; //w trybie pociągowym tylko jeśli włącza tryb manewrowy (v!=0.0)
|
||
//Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo Tm może być daleko
|
||
//VelSignal=v; //nie do końca tak, to jest druga prędkość
|
||
if (VelSignal==0.0) VelSignal=v; //aby stojący ruszył
|
||
if (sSpeedTable[i].fDist<0.0) //jeśli przejechany
|
||
{VelSignal=v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to
|
||
sSpeedTable[i].iFlags=0; //to można usunąć (nie mogą być usuwane w skanowaniu)
|
||
}
|
||
}
|
||
}
|
||
else //if (sSpeedTable[i].iFlags&0x100) //jeśli semafor !!! Komendę trzeba sprawdzić !!!!
|
||
if (go<=cm_Ready) //jeśli nie było komendy wcześniej - pierwsza się liczy - ustawianie VelSignal
|
||
if (v<0.0?true:v>=1.0) //bo wartość 0.1 służy do hamowania tylko
|
||
{go=cm_SetVelocity; //może odjechać
|
||
//Ra 2014-06: (VelSignal) nie może być tu ustawiane, bo semafor może być daleko
|
||
//VelSignal=v; //nie do końca tak, to jest druga prędkość; -1 nie wpisywać...
|
||
if (VelSignal==0.0) VelSignal=v; //aby stojący ruszył
|
||
if (sSpeedTable[i].fDist<0.0) //jeśli przejechany
|
||
{VelSignal=v; //!!! ustawienie, gdy przejechany jest lepsze niż wcale, ale to jeszcze nie to
|
||
if (sSpeedTable[i].iFlags&0x100) //jeśli semafor
|
||
if ((sSpeedTable[i].evEvent!=eSignSkip)?true:(sSpeedTable[i].fVelNext!=0.0)) //ale inny niż ten, na którym minięto S1, chyba że się już zmieniło
|
||
iDrivigFlags&=~moveVisibility; //sygnał zezwalający na jazdę wyłącza jazdę na widoczność (S1 na SBL)
|
||
sSpeedTable[i].iFlags=0; //to można usunąć (nie mogą być usuwane w skanowaniu)
|
||
}
|
||
}
|
||
else if (sSpeedTable[i].evEvent->StopCommand())
|
||
{//jeśli prędkość jest zerowa, a komórka zawiera komendę
|
||
eSignNext=sSpeedTable[i].evEvent; //dla informacji
|
||
if (iDrivigFlags&moveStopHere) //jeśli ma stać, dostaje komendę od razu
|
||
go=cm_Command; //komenda z komórki, do wykonania po zatrzymaniu
|
||
else if (sSpeedTable[i].fDist<=20.0) //jeśli ma dociągnąć, to niech dociąga (moveStopCloser dotyczy dociągania do W4, nie semafora)
|
||
go=cm_Command; //komenda z komórki, do wykonania po zatrzymaniu
|
||
}
|
||
} //jeśli nie ma zawalidrogi
|
||
} //jeśli event
|
||
if (v>=0.0)
|
||
{//pozycje z prędkością -1 można spokojnie pomijać
|
||
d=sSpeedTable[i].fDist;
|
||
if ((sSpeedTable[i].iFlags&0x20)?false:d>0.0) //sygnał lub ograniczenie z przodu (+32=przejechane)
|
||
{//2014-02: jeśli stoi, a ma do przejechania kawałek, to niech jedzie
|
||
if ((mvOccupied->Vel==0.0)?((sSpeedTable[i].iFlags&0x501)==0x501)&&(d>fMaxProximityDist):false)
|
||
a=(iDrivigFlags&moveStopCloser)?fAcc:0.0; //ma podjechać bliżej - czy na pewno w tym miejscu taki warunek?
|
||
else
|
||
{a=(v*v-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //przyspieszenie: ujemne, gdy trzeba hamować
|
||
if (d<fMinProximityDist) //jak jest już blisko
|
||
if (v<fVelDes) fVelDes=v; //ograniczenie aktualnej prędkości
|
||
}
|
||
}
|
||
else
|
||
if (sSpeedTable[i].iFlags&2) //jeśli tor
|
||
{//tor ogranicza prędkość, dopóki cały skład nie przejedzie,
|
||
//d=fLength+d; //zamiana na długość liczoną do przodu
|
||
if (v>=1.0) //EU06 się zawieszało po dojechaniu na koniec toru postojowego
|
||
if (d<-fLength)
|
||
continue; //zapętlenie, jeśli już wyjechał za ten odcinek
|
||
if (v<fVelDes) fVelDes=v; //ograniczenie aktualnej prędkości aż do wyjechania za ograniczenie
|
||
//if (v==0.0) fAcc=-0.9; //hamowanie jeśli stop
|
||
continue; //i tyle wystarczy
|
||
}
|
||
else //event trzyma tylko jeśli VelNext=0, nawet po przejechaniu (nie powinno dotyczyć samochodów?)
|
||
a=(v==0.0?-1.0:fAcc); //ruszanie albo hamowanie
|
||
if (a<fAcc)
|
||
{//mniejsze przyspieszenie to mniejsza możliwość rozpędzenia się albo konieczność hamowania
|
||
//jeśli droga wolna, to może być a>1.0 i się tu nie załapuje
|
||
//if (mvOccupied->Vel>10.0)
|
||
fAcc=a; //zalecane przyspieszenie (nie musi być uwzględniane przez AI)
|
||
fNext=v; //istotna jest prędkość na końcu tego odcinka
|
||
fDist=d; //dlugość odcinka
|
||
}
|
||
else if ((fAcc>0)&&(v>0)&&(v<=fNext))
|
||
{//jeśli nie ma wskazań do hamowania, można podać drogę i prędkość na jej końcu
|
||
fNext=v; //istotna jest prędkość na końcu tego odcinka
|
||
fDist=d; //dlugość odcinka (kolejne pozycje mogą wydłużać drogę, jeśli prędkość jest stała)
|
||
}
|
||
} //if (v>=0.0)
|
||
if (fNext>=0.0)
|
||
{//jeśli ograniczenie
|
||
if ((sSpeedTable[i].iFlags&0x101)==0x101) //tylko sygnał przypisujemy
|
||
if (!eSignNext) //jeśli jeszcze nic nie zapisane tam
|
||
eSignNext=sSpeedTable[i].evEvent; //dla informacji
|
||
if (fNext==0.0)
|
||
break; //nie ma sensu analizować tabelki dalej
|
||
}
|
||
} //if (sSpeedTable[i].iFlags&1)
|
||
} //for
|
||
return go;
|
||
};
|
||
|
||
void __fastcall 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)
|
||
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&1)?(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
|
||
//WriteLog("Odtykacz usuwa pozycję");
|
||
iLast=(iLast-1+iSpeedTableSize)%iSpeedTableSize; //cofnięcie z zawinięciem
|
||
return;
|
||
}
|
||
}
|
||
//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];
|
||
i=(i+1)%iSpeedTableSize; //kolejna pozycja mogą być zawinięta
|
||
}
|
||
iFirst=0; //teraz będzie od zera
|
||
iLast=j; //ostatnia
|
||
delete[] sSpeedTable; //to już nie potrzebne
|
||
sSpeedTable=t; //bo jest nowe
|
||
iSpeedTableSize+=16;
|
||
//WriteLog("Tabelka powiększona do "+AnsiString(iSpeedTableSize)+" pozycji");
|
||
};
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
//---------------------------------------------------------------------------
|
||
|
||
__fastcall TController::TController
|
||
(bool AI,
|
||
TDynamicObject *NewControll,
|
||
bool InitPsyche,
|
||
bool primary //czy ma aktywnie prowadzić?
|
||
)
|
||
{
|
||
iEngineActive=0;
|
||
LastUpdatedTime=0.0;
|
||
ElapsedTime=0.0;
|
||
//inicjalizacja zmiennych
|
||
Psyche=InitPsyche;
|
||
VelDesired=0.0; //prędkosć początkowa
|
||
VelforDriver=-1;
|
||
LastReactionTime=0.0;
|
||
HelpMeFlag=false;
|
||
//fProximityDist=1; //nie używane
|
||
ActualProximityDist=1;
|
||
vCommandLocation.x=0;
|
||
vCommandLocation.y=0;
|
||
vCommandLocation.z=0;
|
||
VelSignal=0.0; //normalnie na początku ma stać, no chyba że jedzie
|
||
VelLimit=-1.0; //brak ograniczenia prędkości
|
||
VelNext=120.0;
|
||
AIControllFlag=AI;
|
||
pVehicle=NewControll;
|
||
ControllingSet(); //utworzenie połączenia do sterowanego pojazdu
|
||
pVehicles[0]=pVehicle->GetFirstDynamic(0); //pierwszy w kierunku jazdy (Np. Pc1)
|
||
pVehicles[1]=pVehicle->GetFirstDynamic(1); //ostatni w kierunku jazdy (końcówki)
|
||
/*
|
||
switch (mvOccupied->CabNo)
|
||
{
|
||
case -1: SendCtrlBroadcast("CabActivisation",1); break;
|
||
case 1: SendCtrlBroadcast("CabActivisation",2); break;
|
||
default: AIControllFlag:=False; //na wszelki wypadek
|
||
}
|
||
*/
|
||
iDirection=0;
|
||
iDirectionOrder=mvOccupied->CabNo; //1=do przodu (w kierunku sprzęgu 0)
|
||
VehicleName=mvOccupied->Name;
|
||
//TrainParams=NewTrainParams;
|
||
//if (TrainParams)
|
||
// asNextStop=TrainParams->NextStop();
|
||
//else
|
||
TrainParams=new TTrainParameters("none"); //rozkład jazdy
|
||
//OrderCommand="";
|
||
//OrderValue=0;
|
||
OrdersClear();
|
||
MaxVelFlag=false; MinVelFlag=false; //Ra: to nie jest używane
|
||
iDriverFailCount=0;
|
||
Need_TryAgain=false; //true, jeśli druga pozycja w elektryku nie załapała
|
||
Need_BrakeRelease=true;
|
||
deltalog=0.05;//1.0;
|
||
|
||
if (WriteLogFlag)
|
||
{
|
||
mkdir("physicslog\\");
|
||
LogFile.open(AnsiString("physicslog\\"+VehicleName+".dat").c_str(),std::ios::in | std::ios::out | std::ios::trunc);
|
||
#if LOGPRESS==0
|
||
LogFile << AnsiString(" Time [s] Velocity [m/s] Acceleration [m/ss] Coupler.Dist[m] Coupler.Force[N] TractionForce [kN] FrictionForce [kN] BrakeForce [kN] BrakePress [MPa] PipePress [MPa] MotorCurrent [A] MCP SCP BCP LBP DmgFlag Command CVal1 CVal2").c_str() << "\r\n";
|
||
#endif
|
||
#if LOGPRESS==1
|
||
LogFile << AnsiString("t\tVel\tAcc\tPP\tVVP\tBP\tBVP\tCVP").c_str() << "\n";
|
||
#endif
|
||
LogFile.flush();
|
||
}
|
||
/*
|
||
if (WriteLogFlag)
|
||
{
|
||
assignfile(AILogFile,VehicleName+".txt");
|
||
rewrite(AILogFile);
|
||
writeln(AILogFile,"AI driver log: started OK");
|
||
close(AILogFile);
|
||
}
|
||
*/
|
||
|
||
//VelMargin=2; //Controlling->Vmax*0.015;
|
||
fWarningDuration=0.0; //nic do wytrąbienia
|
||
WaitingExpireTime=31.0; //tyle ma czekać, zanim się ruszy
|
||
WaitingTime=0.0;
|
||
fMinProximityDist=30.0; //stawanie między 30 a 60 m przed przeszkodą
|
||
fMaxProximityDist=50.0;
|
||
iVehicleCount=-2; //wartość neutralna
|
||
//Prepare2press=false; //bez dociskania
|
||
eStopReason=stopSleep; //na początku śpi
|
||
fLength=0.0;
|
||
fMass=0.0; //[kg]
|
||
eSignNext=NULL; //sygnał zmieniający prędkość, do pokazania na [F2]
|
||
fShuntVelocity=40; //domyślna prędkość manewrowa
|
||
fStopTime=0.0; //czas postoju przed dalszą jazdą (np. na przystanku)
|
||
iDrivigFlags=moveStopPoint; //podjedź do W4 możliwie blisko
|
||
iDrivigFlags|=moveStopHere; //nie podjeżdżaj do semafora, jeśli droga nie jest wolna
|
||
iDrivigFlags|=moveStartHorn; //podaj sygnał po podaniu wolnej drogi
|
||
if (primary)
|
||
iDrivigFlags|=movePrimary; //aktywnie prowadzące pojazd
|
||
Ready=false;
|
||
if (mvOccupied->CategoryFlag&2)
|
||
{//samochody: na podst. http://www.prawko-kwartnik.info/hamowanie.html
|
||
//fDriverBraking=0.0065; //mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m]
|
||
fDriverBraking=0.03; //coś nie hamują te samochody zbyt dobrze
|
||
fDriverDist=5.0; //5m - zachowywany odstęp przed kolizją
|
||
fVelPlus=10.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=2.0; //margines prędkości powodujący załączenie napędu
|
||
}
|
||
else
|
||
{//pociągi i statki
|
||
fDriverBraking=0.06; //mnożone przez (v^2+40*v) [km/h] daje prawie drogę hamowania [m]
|
||
fDriverDist=50.0; //50m - zachowywany odstęp przed kolizją
|
||
fVelPlus=5.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=5.0; //margines prędkości powodujący załączenie napędu
|
||
}
|
||
SetDriverPsyche(); //na końcu, bo wymaga ustawienia zmiennych
|
||
AccDesired=AccPreferred;
|
||
fVelMax=-1; //ustalenie prędkości dla składu
|
||
fBrakeTime=0.0; //po jakim czasie przekręcić hamulec
|
||
iVehicles=0; //na wszelki wypadek
|
||
iSpeedTableSize=16;
|
||
sSpeedTable=new TSpeedPos[iSpeedTableSize];
|
||
TableClear();
|
||
iRadioChannel=1; //numer aktualnego kanału radiowego
|
||
fActionTime=0.0;
|
||
eAction=actSleep;
|
||
tsGuardSignal=NULL; //komunikat od kierownika
|
||
iGuardRadio=0; //nie przez radio
|
||
iStationStart=0; //nic?
|
||
//fAccThreshold może podlegać uczeniu się - hamowanie powinno być rejestrowane, a potem analizowane
|
||
fAccThreshold=(mvOccupied->TrainType&dt_EZT)?-0.6:-0.2; //próg opóźnienia dla zadziałania hamulca
|
||
fLastStopExpDist=-1.0f;
|
||
iRouteWanted=3; //powiedzmy, że ma jechać prosto (1=w lewo)
|
||
iCoupler=0; //sprzęg; niezerowy gdy ma być podłączanie; samo podłączanie w trybie Connect (wcześniej może być np. Prepare_engine)
|
||
fOverhead1=3000.0; //informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!)
|
||
fOverhead2=-1.0; //informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i ograniczeniem prędkości)
|
||
iOverheadZero=0; //suma bitowa jezdy bezprądowej, bity ustawiane przez pojazdy z podniesionymi pantografami
|
||
iOverheadDown=0; //suma bitowa opuszczenia pantografów, bity ustawiane przez pojazdy z podniesionymi pantografami
|
||
fAccDesiredAv=0.0; //uśrednione przyspieszenie z kolejnych przebłysków świadomości, żeby ograniczyć migotanie
|
||
fVoltage=0.0; //uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas
|
||
};
|
||
|
||
void __fastcall TController::CloseLog()
|
||
{
|
||
if (WriteLogFlag)
|
||
{
|
||
LogFile.close();
|
||
//if WriteLogFlag)
|
||
// CloseFile(AILogFile);
|
||
/* append(AIlogFile);
|
||
writeln(AILogFile,ElapsedTime5:2,": QUIT");
|
||
close(AILogFile); */
|
||
}
|
||
};
|
||
|
||
__fastcall TController::~TController()
|
||
{//wykopanie mechanika z roboty
|
||
delete tsGuardSignal;
|
||
delete TrainParams;
|
||
delete[] sSpeedTable;
|
||
CloseLog();
|
||
};
|
||
|
||
AnsiString __fastcall TController::Order2Str(TOrders Order)
|
||
{//zamiana kodu rozkazu na opis
|
||
if (Order&Change_direction) return "Change_direction"; //może być nałożona na inną i wtedy ma priorytet
|
||
if (Order==Wait_for_orders) return "Wait_for_orders";
|
||
if (Order==Prepare_engine) return "Prepare_engine";
|
||
if (Order==Shunt) return "Shunt";
|
||
if (Order==Connect) return "Connect";
|
||
if (Order==Disconnect) return "Disconnect";
|
||
if (Order==Obey_train) return "Obey_train";
|
||
if (Order==Release_engine) return "Release_engine";
|
||
if (Order==Jump_to_first_order) return "Jump_to_first_order";
|
||
/* Ra: wersja ze switch nie działa prawidłowo (czemu?)
|
||
switch (Order)
|
||
{
|
||
Wait_for_orders: return "Wait_for_orders";
|
||
Prepare_engine: return "Prepare_engine";
|
||
Shunt: return "Shunt";
|
||
Change_direction: return "Change_direction";
|
||
Obey_train: return "Obey_train";
|
||
Release_engine: return "Release_engine";
|
||
Jump_to_first_order: return "Jump_to_first_order";
|
||
}
|
||
*/
|
||
return "Undefined!";
|
||
}
|
||
|
||
AnsiString __fastcall TController::OrderCurrent()
|
||
{//pobranie aktualnego rozkazu celem wyświetlenia
|
||
return AnsiString(OrderPos)+". "+Order2Str(OrderList[OrderPos]);
|
||
};
|
||
|
||
void __fastcall TController::OrdersClear()
|
||
{//czyszczenie tabeli rozkazów na starcie albo po dojściu do końca
|
||
OrderPos=0;
|
||
OrderTop=1; //szczyt stosu rozkazów
|
||
for (int b=0;b<maxorders;b++)
|
||
OrderList[b]=Wait_for_orders;
|
||
#if LOGORDERS
|
||
WriteLog("--> OrdersClear");
|
||
#endif
|
||
};
|
||
|
||
void __fastcall TController::Activation()
|
||
{//umieszczenie obsady w odpowiednim członie, wykonywane wyłącznie gdy steruje AI
|
||
iDirection=iDirectionOrder; //kierunek (względem sprzęgów pojazdu z AI) właśnie został ustalony (zmieniony)
|
||
if (iDirection)
|
||
{//jeśli jest ustalony kierunek
|
||
TDynamicObject *old=pVehicle,*d=pVehicle; //w tym siedzi AI
|
||
TController *drugi; //jakby były dwa, to zamienić miejscami, a nie robić wycieku pamięci poprzez nadpisanie
|
||
int brake=mvOccupied->LocalBrakePos;
|
||
while (mvControlling->MainCtrlPos) //samo zapętlenie DecSpeed() nie wystarcza :/
|
||
DecSpeed(true); //wymuszenie zerowania nastawnika jazdy
|
||
while (mvOccupied->ActiveDir<0) mvOccupied->DirectionForward(); //kierunek na 0
|
||
while (mvOccupied->ActiveDir>0) mvOccupied->DirectionBackward();
|
||
if (TestFlag(d->MoverParameters->Couplers[iDirectionOrder<0?1:0].CouplingFlag,ctrain_controll))
|
||
{mvControlling->MainSwitch(false); //dezaktywacja czuwaka, jeśli przejście do innego członu
|
||
mvOccupied->DecLocalBrakeLevel(10); //zwolnienie hamulca w opuszczanym pojeździe
|
||
// mvOccupied->BrakeLevelSet((mvOccupied->BrakeHandle==FVel6)?4:-2); //odcięcie na zaworze maszynisty, FVel6 po drugiej stronie nie luzuje
|
||
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_NP)); //odcięcie na zaworze maszynisty
|
||
}
|
||
mvOccupied->ActiveCab=mvOccupied->CabNo; //użytkownik moze zmienić ActiveCab wychodząc
|
||
mvOccupied->CabDeactivisation(); //tak jest w Train.cpp
|
||
//przejście AI na drugą stronę EN57, ET41 itp.
|
||
while (TestFlag(d->MoverParameters->Couplers[iDirection<0?1:0].CouplingFlag,ctrain_controll))
|
||
{//jeśli pojazd z przodu jest ukrotniony, to przechodzimy do niego
|
||
d=iDirection*d->DirectionGet()<0?d->Next():d->Prev(); //przechodzimy do następnego członu
|
||
if (d)
|
||
{drugi=d->Mechanik; //zapamiętanie tego, co ewentualnie tam siedzi, żeby w razie dwóch zamienić miejscami
|
||
d->Mechanik=this; //na razie bilokacja
|
||
d->MoverParameters->SetInternalCommand("",0,0); //usunięcie ewentualnie zalegającej komendy (Change_direction?)
|
||
if (d->DirectionGet()!=pVehicle->DirectionGet()) //jeśli są przeciwne do siebie
|
||
iDirection=-iDirection; //to będziemy jechać w drugą stronę względem zasiedzianego pojazdu
|
||
pVehicle->Mechanik=drugi; //wsadzamy tego, co ewentualnie był (podwójna trakcja)
|
||
pVehicle->MoverParameters->CabNo=0; //wyłączanie kabin po drodze
|
||
pVehicle->MoverParameters->ActiveCab=0; //i zaznaczenie, że nie ma tam nikogo
|
||
pVehicle=d; //a mechu ma nowy pojazd (no, człon)
|
||
}
|
||
else break; //jak koniec składu, to mechanik dalej nie idzie
|
||
}
|
||
if (pVehicle!=old)
|
||
{//jeśli zmieniony został pojazd prowadzony
|
||
Global::pWorld->CabChange(old,pVehicle); //ewentualna zmiana kabiny użytkownikowi
|
||
ControllingSet(); //utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT
|
||
}
|
||
if (mvControlling->EngineType==DieselEngine) //dla 2Ls150 - przed ustawieniem kierunku - można zmienić tryb pracy
|
||
if (mvControlling->ShuntModeAllow)
|
||
mvControlling->CurrentSwitch((OrderList[OrderPos]&Shunt)||(fMass>224000.0)); //do tego na wzniesieniu może nie dać rady na liniowym
|
||
//Ra: to przełączanie poniżej jest tu bez sensu
|
||
mvOccupied->ActiveCab=iDirection; //aktywacja kabiny w prowadzonym pojeżdzie (silnikowy może być odwrotnie?)
|
||
//mvOccupied->CabNo=iDirection;
|
||
//mvOccupied->ActiveDir=0; //żeby sam ustawił kierunek
|
||
mvOccupied->CabActivisation(); //uruchomienie kabin w członach
|
||
DirectionForward(true); //nawrotnik do przodu
|
||
if (brake) //hamowanie tylko jeśli był wcześniej zahamowany (bo możliwe, że jedzie!)
|
||
mvOccupied->IncLocalBrakeLevel(brake); //zahamuj jak wcześniej
|
||
CheckVehicles(); //sprawdzenie składu, AI zapali światła
|
||
TableClear(); //resetowanie tabelki skanowania torów
|
||
}
|
||
};
|
||
|
||
void __fastcall TController::AutoRewident()
|
||
{//autorewident: nastawianie hamulców w składzie
|
||
int r=0,g=0,p=0; //ilości wagonów poszczególnych typów
|
||
TDynamicObject* d=pVehicles[0]; //pojazd na czele składu
|
||
//1. Zebranie informacji o składzie pociągu — przejście wzdłuż składu i odczyt parametrów:
|
||
// · ilość wagonów -> są zliczane, wszystkich pojazdów jest (iVehicles)
|
||
// · długość (jako suma) -> jest w (fLength)
|
||
// · masa (jako suma) -> jest w (fMass)
|
||
while (d)
|
||
{//klasyfikacja pojazdów wg BrakeDelays i mocy (licznik)
|
||
if (d->MoverParameters->Power<1) // - lokomotywa - Power>1 - ale może być nieczynna na końcu...
|
||
if (TestFlag(d->MoverParameters->BrakeDelays,bdelay_R))
|
||
++r; // - wagon pospieszny - jest R
|
||
else if (TestFlag(d->MoverParameters->BrakeDelays,bdelay_G))
|
||
++g; // - wagon towarowy - jest G (nie ma R)
|
||
else
|
||
++p; // - wagon osobowy - reszta (bez G i bez R)
|
||
d=d->Next(); //kolejny pojazd, podłączony od tyłu (licząc od czoła)
|
||
}
|
||
//2. Określenie typu pociągu i nastawy:
|
||
int ustaw; //+16 dla pasażerskiego
|
||
if (r+g+p==0)
|
||
ustaw=16+bdelay_R; //lokomotywa luzem (może być wieloczłonowa)
|
||
else
|
||
{//jeśli są wagony
|
||
ustaw=(g<min(4,r+p)?16:0);
|
||
if (ustaw) //jeśli towarowe < Min(4, pospieszne+osobowe)
|
||
{//to skład pasażerski - nastawianie pasażerskiego
|
||
ustaw+=(g&&(r<g+p))?bdelay_P:bdelay_R;
|
||
//jeżeli towarowe>0 oraz pospiesze<=towarowe+osobowe to P (0)
|
||
//inaczej R (2)
|
||
}
|
||
else
|
||
{//inaczej towarowy - nastawianie towarowego
|
||
if ((fLength<300.0)&&(fMass<600000.0)) //[kg]
|
||
ustaw|=bdelay_P; //jeżeli długość<300 oraz masa<600 to P (0)
|
||
else if ((fLength<500.0)&&(fMass<1300000.0))
|
||
ustaw|=bdelay_R; //jeżeli długość<500 oraz masa<1300 to GP (2)
|
||
else
|
||
ustaw|=bdelay_G; //inaczej G (1)
|
||
}
|
||
//zasadniczo na sieci PKP kilka lat temu na P/GP jeździły tylko kontenerowce o
|
||
//rozkładowej 90 km/h. Pozostałe jeździły 70 km/h i były nastawione na G.
|
||
}
|
||
d=pVehicles[0]; //pojazd na czele składu
|
||
p=0; //będziemy tu liczyć wagony od lokomotywy dla nastawy GP
|
||
while (d)
|
||
{//3. Nastawianie
|
||
switch (ustaw)
|
||
{
|
||
case bdelay_P: //towarowy P - lokomotywa na G, reszta na P.
|
||
d->MoverParameters->BrakeDelaySwitch(d->MoverParameters->Power>1?bdelay_G:bdelay_P);
|
||
break;
|
||
case bdelay_G: //towarowy G - wszystko na G, jeśli nie ma to P (powinno się wyłączyć hamulec)
|
||
d->MoverParameters->BrakeDelaySwitch(TestFlag(d->MoverParameters->BrakeDelays,bdelay_G)?bdelay_G:bdelay_P);
|
||
break;
|
||
case bdelay_R: //towarowy GP - lokomotywa oraz 5 pierwszych pojazdów przy niej na G, reszta na P
|
||
if (d->MoverParameters->Power>1)
|
||
{d->MoverParameters->BrakeDelaySwitch(bdelay_G);
|
||
p=0; //a jak będzie druga w środku?
|
||
}
|
||
else
|
||
d->MoverParameters->BrakeDelaySwitch(++p<=5?bdelay_G:bdelay_P);
|
||
break;
|
||
case 16+bdelay_R: //pasażerski R - na R, jeśli nie ma to P
|
||
d->MoverParameters->BrakeDelaySwitch(TestFlag(d->MoverParameters->BrakeDelays,bdelay_R)?bdelay_R:bdelay_P);
|
||
break;
|
||
case 16+bdelay_P: //pasażerski P - wszystko na P
|
||
d->MoverParameters->BrakeDelaySwitch(bdelay_P);
|
||
break;
|
||
}
|
||
d=d->Next(); //kolejny pojazd, podłączony od tyłu (licząc od czoła)
|
||
}
|
||
};
|
||
|
||
bool __fastcall TController::CheckVehicles(TOrders user)
|
||
{//sprawdzenie stanu posiadanych pojazdów w składzie i zapalenie świateł
|
||
TDynamicObject* p; //roboczy wskaźnik na pojazd
|
||
iVehicles=0; //ilość pojazdów w składzie
|
||
int d=mvOccupied->DirAbsolute; //który sprzęg jest z przodu
|
||
if (!d) //jeśli nie ma ustalonego kierunku
|
||
d=mvOccupied->CabNo; //to jedziemy wg aktualnej kabiny
|
||
iDirection=d; //ustalenie kierunku jazdy (powinno zrobić PrepareEngine?)
|
||
d=d>=0?0:1; //kierunek szukania czoła (numer sprzęgu)
|
||
pVehicles[0]=p=pVehicle->FirstFind(d); //pojazd na czele składu
|
||
//liczenie pojazdów w składzie i ustalenie parametrów
|
||
int dir=d=1-d; //a dalej będziemy zliczać od czoła do tyłu
|
||
fLength=0.0; //długość składu do badania wyjechania za ograniczenie
|
||
fMass=0.0; //całkowita masa do liczenia stycznej składowej grawitacji
|
||
fVelMax=-1; //ustalenie prędkości dla składu
|
||
bool main=true; //czy jest głównym sterującym
|
||
iDrivigFlags|=moveOerlikons; //zakładamy, że są same Oerlikony
|
||
//Ra 2014-09: ustawić moveMultiControl, jeśli wszystkie są w ukrotnieniu (i skrajne mają kabinę?)
|
||
while (p)
|
||
{//sprawdzanie, czy jest głównym sterującym, żeby nie było konfliktu
|
||
if (p->Mechanik) //jeśli ma obsadę
|
||
if (p->Mechanik!=this) //ale chodzi o inny pojazd, niż aktualnie sprawdzający
|
||
if (p->Mechanik->iDrivigFlags&movePrimary) //a tamten ma priorytet
|
||
if ((iDrivigFlags&movePrimary)&&(mvOccupied->DirAbsolute)&&(mvOccupied->BrakeCtrlPos>=-1)) //jeśli rządzi i ma kierunek
|
||
p->Mechanik->iDrivigFlags&=~movePrimary; //dezaktywuje tamtego
|
||
else
|
||
main=false; //nici z rządzenia
|
||
++iVehicles; //jest jeden pojazd więcej
|
||
pVehicles[1]=p; //zapamiętanie ostatniego
|
||
fLength+=p->MoverParameters->Dim.L; //dodanie długości pojazdu
|
||
fMass+=p->MoverParameters->TotalMass; //dodanie masy łącznie z ładunkiem
|
||
if (fVelMax<0?true:p->MoverParameters->Vmax<fVelMax)
|
||
fVelMax=p->MoverParameters->Vmax; //ustalenie maksymalnej prędkości dla składu
|
||
/* //youBy: bez przesady, to jest proteza, napelniac mozna, a nawet trzeba, ale z umiarem!
|
||
//uwzględnić jeszcze wyłączenie hamulca
|
||
if ((p->MoverParameters->BrakeSystem!=Pneumatic)&&(p->MoverParameters->BrakeSystem!=ElectroPneumatic))
|
||
iDrivigFlags&=~moveOerlikons; //no jednak nie
|
||
else if (p->MoverParameters->BrakeSubsystem!=Oerlikon)
|
||
iDrivigFlags&=~moveOerlikons; //wtedy też nie */
|
||
p=p->Neightbour(dir); //pojazd podłączony od wskazanej strony
|
||
}
|
||
if (main) iDrivigFlags|=movePrimary; //nie znaleziono innego, można się porządzić
|
||
/* //tabelka z listą pojazdów jest na razie nie potrzebna
|
||
delete[] pVehicles;
|
||
pVehicles=new TDynamicObject*[iVehicles];
|
||
*/
|
||
ControllingSet(); //ustalenie członu do sterowania (może być inny niż zasiedziany)
|
||
int pantmask=1;
|
||
if (iDrivigFlags&movePrimary)
|
||
{//jeśli jest aktywnie prowadzącym pojazd, może zrobić własny porządek
|
||
p=pVehicles[0];
|
||
while (p)
|
||
{
|
||
if (TrainParams)
|
||
if (p->asDestination=="none")
|
||
p->DestinationSet(TrainParams->Relation2); //relacja docelowa, jeśli nie było
|
||
if (AIControllFlag) //jeśli prowadzi komputer
|
||
p->RaLightsSet(0,0); //gasimy światła
|
||
if (p->MoverParameters->EnginePowerSource.SourceType==CurrentCollector)
|
||
{//jeśli pojazd posiada pantograf, to przydzielamy mu maskę, którą będzie informował o jeździe bezprądowej
|
||
p->iOverheadMask=pantmask;
|
||
pantmask<<1; //przesunięcie bitów, max. 32 pojazdy z pantografami w składzie
|
||
}
|
||
d=p->DirectionSet(d?1:-1); //zwraca położenie następnego (1=zgodny,0=odwrócony - względem czoła składu)
|
||
p->fScanDist=300.0; //odległość skanowania w poszukiwaniu innych pojazdów
|
||
p->ctOwner=this; //dominator oznacza swoje terytorium
|
||
p=p->Next(); //pojazd podłączony od tyłu (licząc od czoła)
|
||
}
|
||
if (AIControllFlag)
|
||
{//jeśli prowadzi komputer
|
||
if (OrderCurrentGet()==Obey_train) //jeśli jazda pociągowa
|
||
{Lights(1+4+16,2+32+64); //światła pociągowe (Pc1) i końcówki (Pc5)
|
||
#if LOGPRESS==0
|
||
AutoRewident(); //nastawianie hamulca do jazdy pociągowej
|
||
#endif
|
||
}
|
||
else if (OrderCurrentGet()&(Shunt|Connect))
|
||
{Lights(16,(pVehicles[1]->MoverParameters->CabNo)?1:0); //światła manewrowe (Tb1) na pojeździe z napędem
|
||
if (OrderCurrentGet()&Connect) //jeśli łączenie, skanować dalej
|
||
pVehicles[0]->fScanDist=5000.0; //odległość skanowania w poszukiwaniu innych pojazdów
|
||
}
|
||
else if (OrderCurrentGet()==Disconnect)
|
||
if (mvOccupied->ActiveDir>0) //jak ma kierunek do przodu
|
||
Lights(16,0); //światła manewrowe (Tb1) tylko z przodu, aby nie pozostawić odczepionego ze światłem
|
||
else //jak dociska
|
||
Lights(0,16); //światła manewrowe (Tb1) tylko z przodu, aby nie pozostawić odczepionego ze światłem
|
||
}
|
||
else //Ra 2014-02: lepiej tu niż w pętli obsługującej komendy, bo tam się zmieni informacja o składzie
|
||
switch (user) //gdy człowiek i gdy nastąpiło połącznie albo rozłączenie
|
||
{
|
||
case Change_direction:
|
||
while (OrderCurrentGet()&(Change_direction))
|
||
JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania!
|
||
break;
|
||
case Connect:
|
||
while (OrderCurrentGet()&(Change_direction))
|
||
JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania!
|
||
if (OrderCurrentGet()&(Connect))
|
||
{//jeśli miało być łączenie, zakładamy, że jest dobrze (sprawdzić?)
|
||
iCoupler=0; //koniec z doczepianiem
|
||
iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania
|
||
JumpToNextOrder(); //wykonanie następnej komendy
|
||
if (OrderCurrentGet()&(Change_direction))
|
||
JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania!
|
||
}
|
||
break;
|
||
case Disconnect:
|
||
while (OrderCurrentGet()&(Change_direction))
|
||
JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania!
|
||
if (OrderCurrentGet()&(Disconnect))
|
||
{//wypadało by sprawdzić, czy odczepiono wagony w odpowiednim miejscu (iVehicleCount)
|
||
JumpToNextOrder(); //wykonanie następnej komendy
|
||
if (OrderCurrentGet()&(Change_direction))
|
||
JumpToNextOrder(); //zmianę kierunku też można olać, ale zmienić kierunek skanowania!
|
||
}
|
||
}
|
||
//Ra 2014-09: tymczasowo prymitywne ustawienie warunku pod kątem SN61
|
||
if ((mvOccupied->TrainType==dt_EZT)||(iVehicles==1))
|
||
iDrivigFlags|=movePushPull; //zmiana czoła przez zmianę kabiny
|
||
else
|
||
iDrivigFlags&=~movePushPull; //zmiana czoła przez manewry
|
||
} //blok wykonywany, gdy aktywnie prowadzi
|
||
return true;
|
||
}
|
||
|
||
void __fastcall TController::Lights(int head,int rear)
|
||
{//zapalenie świateł w skłądzie
|
||
pVehicles[0]->RaLightsSet(head,-1); //zapalenie przednich w pierwszym
|
||
pVehicles[1]->RaLightsSet(-1,rear); //zapalenie końcówek w ostatnim
|
||
}
|
||
|
||
void __fastcall TController::DirectionInitial()
|
||
{//ustawienie kierunku po wczytaniu trainset (może jechać na wstecznym
|
||
mvOccupied->CabActivisation(); //załączenie rozrządu (wirtualne kabiny)
|
||
if (mvOccupied->Vel>0.0)
|
||
{//jeśli na starcie jedzie
|
||
iDirection=iDirectionOrder=(mvOccupied->V>0?1:-1); //początkowa prędkość wymusza kierunek jazdy
|
||
DirectionForward(mvOccupied->V*mvOccupied->CabNo>=0.0); //a dalej ustawienie nawrotnika
|
||
}
|
||
CheckVehicles(); //sprawdzenie świateł oraz skrajnych pojazdów do skanowania
|
||
};
|
||
|
||
int __fastcall TController::OrderDirectionChange(int newdir,TMoverParameters *Vehicle)
|
||
{//zmiana kierunku jazdy, niezależnie od kabiny
|
||
int testd=newdir;
|
||
if (Vehicle->Vel<0.5)
|
||
{//jeśli prawie stoi, można zmienić kierunek, musi być wykonane dwukrotnie, bo za pierwszym razem daje na zero
|
||
switch (newdir*Vehicle->CabNo)
|
||
{//DirectionBackward() i DirectionForward() to zmiany względem kabiny
|
||
case -1: //if (!Vehicle->DirectionBackward()) testd=0; break;
|
||
DirectionForward(false); break;
|
||
case 1: //if (!Vehicle->DirectionForward()) testd=0; break;
|
||
DirectionForward(true); break;
|
||
}
|
||
if (testd==0)
|
||
VelforDriver=-1; //kierunek został zmieniony na żądany, można jechać
|
||
}
|
||
else //jeśli jedzie
|
||
VelforDriver=0; //ma się zatrzymać w celu zmiany kierunku
|
||
if ((Vehicle->ActiveDir==0)&&(VelforDriver<Vehicle->Vel)) //Ra: to jest chyba bez sensu
|
||
IncBrake(); //niech hamuje
|
||
if (Vehicle->ActiveDir==testd*Vehicle->CabNo)
|
||
VelforDriver=-1; //można jechać, bo kierunek jest zgodny z żądanym
|
||
if (Vehicle->TrainType==dt_EZT)
|
||
if (Vehicle->ActiveDir>0)
|
||
//if () //tylko jeśli jazda pociągowa (tego nie wiemy w momencie odpalania silnika)
|
||
Vehicle->DirectionForward(); //Ra: z przekazaniem do silnikowego
|
||
return (int)VelforDriver; //zwraca prędkość mechanika
|
||
}
|
||
|
||
void __fastcall TController::WaitingSet(double Seconds)
|
||
{//ustawienie odczekania po zatrzymaniu (ustawienie w trakcie jazdy zatrzyma)
|
||
fStopTime=-Seconds; //ujemna wartość oznacza oczekiwanie (potem >=0.0)
|
||
}
|
||
|
||
void __fastcall TController::SetVelocity(double NewVel,double NewVelNext,TStopReason r)
|
||
{//ustawienie nowej prędkości
|
||
WaitingTime=-WaitingExpireTime; //przypisujemy -WaitingExpireTime, a potem porównujemy z zerem
|
||
MaxVelFlag=False; //Ra: to nie jest używane
|
||
MinVelFlag=False; //Ra: to nie jest używane
|
||
/* nie używane
|
||
if ((NewVel>NewVelNext) //jeśli oczekiwana większa niż następna
|
||
|| (NewVel<mvOccupied->Vel)) //albo aktualna jest mniejsza niż aktualna
|
||
fProximityDist=-800.0; //droga hamowania do zmiany prędkości
|
||
else
|
||
fProximityDist=-300.0; //Ra: ujemne wartości są ignorowane
|
||
*/
|
||
if (NewVel==0.0) //jeśli ma stanąć
|
||
{if (r!=stopNone) //a jest powód podany
|
||
eStopReason=r; //to zapamiętać nowy powód
|
||
}
|
||
else
|
||
{
|
||
eStopReason=stopNone; //podana prędkość, to nie ma powodów do stania
|
||
//to całe poniżej to warunki zatrąbienia przed ruszeniem
|
||
if (OrderList[OrderPos]?OrderList[OrderPos]&(Obey_train|Shunt|Connect|Prepare_engine):true) //jeśli jedzie w dowolnym trybie
|
||
if ((mvOccupied->Vel<1.0)) //jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem)
|
||
if (iDrivigFlags&moveStartHorn) //jezeli trąbienie włączone
|
||
if (!(iDrivigFlags&(moveStartHornDone|moveConnect))) //jeśli nie zatrąbione i nie jest to moment podłączania składu
|
||
if (mvOccupied->CategoryFlag&1) //tylko pociągi trąbią (unimogi tylko na torach, więc trzeba raczej sprawdzać tor)
|
||
if ((NewVel>=1.0)||(NewVel<0.0)) //o ile prędkość jest znacząca
|
||
{//fWarningDuration=0.3; //czas trąbienia
|
||
//if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie
|
||
// mvOccupied->WarningSignal=pVehicle->iHornWarning; //wysokość tonu (2=wysoki)
|
||
//iDrivigFlags|=moveStartHornDone; //nie trąbić aż do ruszenia
|
||
iDrivigFlags|=moveStartHornNow; //zatrąb po odhamowaniu
|
||
}
|
||
}
|
||
VelSignal=NewVel; //prędkość zezwolona na aktualnym odcinku
|
||
VelNext=NewVelNext; //prędkość przy następnym obiekcie
|
||
}
|
||
|
||
/* //funkcja do niczego nie potrzebna (ew. do przesunięcia pojazdu o odległość NewDist)
|
||
bool __fastcall TController::SetProximityVelocity(double NewDist,double NewVelNext)
|
||
{//informacja o prędkości w pewnej odległości
|
||
#if 0
|
||
if (NewVelNext==0.0)
|
||
WaitingTime=0.0; //nie trzeba już czekać
|
||
//if ((NewVelNext>=0)&&((VelNext>=0)&&(NewVelNext<VelNext))||(NewVelNext<VelSignal))||(VelNext<0))
|
||
{MaxVelFlag=False; //Ra: to nie jest używane
|
||
MinVelFlag=False; //Ra: to nie jest używane
|
||
VelNext=NewVelNext;
|
||
fProximityDist=NewDist; //dodatnie: przeliczyć do punktu; ujemne: wziąć dosłownie
|
||
return true;
|
||
}
|
||
//else return false
|
||
#endif
|
||
}
|
||
*/
|
||
|
||
void __fastcall TController::SetDriverPsyche()
|
||
{
|
||
//double maxdist=0.5; //skalowanie dystansu od innego pojazdu, zmienic to!!!
|
||
if ((Psyche==Aggressive)&&(OrderList[OrderPos]==Obey_train))
|
||
{
|
||
ReactionTime=HardReactionTime; //w zaleznosci od charakteru maszynisty
|
||
//if (pOccupied)
|
||
if (mvOccupied->CategoryFlag&2)
|
||
{WaitingExpireTime=1; //tyle ma czekać samochód, zanim się ruszy
|
||
AccPreferred=3.0; //[m/ss] agresywny
|
||
}
|
||
else
|
||
{WaitingExpireTime=61; //tyle ma czekać, zanim się ruszy
|
||
AccPreferred=HardAcceleration; //agresywny
|
||
}
|
||
}
|
||
else
|
||
{
|
||
ReactionTime=EasyReactionTime; //spokojny
|
||
if (mvOccupied->CategoryFlag&2)
|
||
{WaitingExpireTime=3; //tyle ma czekać samochód, zanim się ruszy
|
||
AccPreferred=2.0; //[m/ss]
|
||
}
|
||
else
|
||
{WaitingExpireTime=65; //tyle ma czekać, zanim się ruszy
|
||
AccPreferred=EasyAcceleration;
|
||
}
|
||
}
|
||
if (mvControlling&&mvOccupied)
|
||
{//with Controlling do
|
||
if (mvControlling->MainCtrlPos<3)
|
||
ReactionTime=mvControlling->InitialCtrlDelay+ReactionTime;
|
||
if (mvOccupied->BrakeCtrlPos>1)
|
||
ReactionTime=0.5*ReactionTime;
|
||
/*
|
||
if (mvOccupied->Vel>0.1) //o ile jedziemy
|
||
{//sprawdzenie jazdy na widoczność
|
||
TCoupling *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzęg z przodu składu
|
||
if (c->Connected) //a mamy coś z przodu
|
||
if (c->CouplingFlag==0) //jeśli to coś jest podłączone sprzęgiem wirtualnym
|
||
{//wyliczanie optymalnego przyspieszenia do jazdy na widoczność (Ra: na pewno tutaj?)
|
||
double k=c->Connected->Vel; //prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!)
|
||
if (k<=mvOccupied->Vel) //porównanie modułów prędkości [km/h]
|
||
{if (pVehicles[0]->fTrackBlock<fMaxProximityDist) //porównianie z minimalną odległością kolizyjną
|
||
k=-AccPreferred; //hamowanie maksymalne, bo jest za blisko
|
||
else
|
||
{//jeśli tamten jedzie szybciej, to nie potrzeba modyfikować przyspieszenia
|
||
double d=(pVehicles[0]->fTrackBlock-0.5*fabs(mvOccupied->V)-fMaxProximityDist); //bezpieczna odległość za poprzednim
|
||
//a=(v2*v2-v1*v1)/(25.92*(d-0.5*v1))
|
||
//(v2*v2-v1*v1)/2 to różnica energii kinetycznych na jednostkę masy
|
||
//jeśli v2=50km/h,v1=60km/h,d=200m => k=(192.9-277.8)/(25.92*(200-0.5*16.7)=-0.0171 [m/s^2]
|
||
//jeśli v2=50km/h,v1=60km/h,d=100m => k=(192.9-277.8)/(25.92*(100-0.5*16.7)=-0.0357 [m/s^2]
|
||
//jeśli v2=50km/h,v1=60km/h,d=50m => k=(192.9-277.8)/(25.92*( 50-0.5*16.7)=-0.0786 [m/s^2]
|
||
//jeśli v2=50km/h,v1=60km/h,d=25m => k=(192.9-277.8)/(25.92*( 25-0.5*16.7)=-0.1967 [m/s^2]
|
||
if (d>0) //bo jak ujemne, to zacznie przyspieszać, aby się zderzyć
|
||
k=(k*k-mvOccupied->Vel*mvOccupied->Vel)/(25.92*d); //energia kinetyczna dzielona przez masę i drogę daje przyspieszenie
|
||
else
|
||
k=0.0; //może lepiej nie przyspieszać -AccPreferred; //hamowanie
|
||
//WriteLog(pVehicle->asName+" "+AnsiString(k));
|
||
}
|
||
if (d<fBrakeDist) //bo z daleka nie ma co hamować
|
||
AccPreferred=Min0R(k,AccPreferred);
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
};
|
||
|
||
bool __fastcall TController::PrepareEngine()
|
||
{//odpalanie silnika
|
||
bool OK;
|
||
bool voltfront,voltrear;
|
||
voltfront=false;
|
||
voltrear=false;
|
||
LastReactionTime=0.0;
|
||
ReactionTime=PrepareTime;
|
||
iDrivigFlags|=moveActive; //może skanować sygnały i reagować na komendy
|
||
//with Controlling do
|
||
if (((mvControlling->EnginePowerSource.SourceType==CurrentCollector)/*||(mvOccupied->TrainType==dt_EZT)*/))
|
||
{
|
||
if (mvControlling->GetTrainsetVoltage()) //sprawdzanie, czy zasilanie jest może w innym członie
|
||
{
|
||
voltfront=true;
|
||
voltrear=true;
|
||
}
|
||
}
|
||
// begin
|
||
// if Couplers[0].Connected<>nil)
|
||
// begin
|
||
// if Couplers[0].Connected^.PantFrontVolt or Couplers[0].Connected^.PantRearVolt)
|
||
// voltfront:=true
|
||
// else
|
||
// voltfront:=false;
|
||
// end
|
||
// else
|
||
// voltfront:=false;
|
||
// if Couplers[1].Connected<>nil)
|
||
// begin
|
||
// if Couplers[1].Connected^.PantFrontVolt or Couplers[1].Connected^.PantRearVolt)
|
||
// voltrear:=true
|
||
// else
|
||
// voltrear:=false;
|
||
// end
|
||
// else
|
||
// voltrear:=false;
|
||
// end
|
||
else
|
||
//if EnginePowerSource.SourceType<>CurrentCollector)
|
||
if (mvOccupied->TrainType!=dt_EZT)
|
||
voltfront=true; //Ra 2014-06: to jest wirtualny prąd dla spalinowych???
|
||
if (AIControllFlag) //jeśli prowadzi komputer
|
||
{//część wykonawcza dla sterowania przez komputer
|
||
mvOccupied->BatterySwitch(true);
|
||
if (mvControlling->EnginePowerSource.SourceType==CurrentCollector)
|
||
{//jeśli silnikowy jest pantografującym
|
||
if (mvControlling->PantPress>4.3)
|
||
{//jeżeli jest wystarczające ciśnienie w pantografach
|
||
if ((!mvControlling->bPantKurek3)||(mvControlling->PantPress<=mvControlling->ScndPipePress)) //kurek przełączony albo główna już pompuje
|
||
mvControlling->PantCompFlag=false; //sprężarkę pantografów można już wyłączyć
|
||
mvControlling->PantFront(true);
|
||
mvControlling->PantRear(true);
|
||
}
|
||
else if (mvControlling->PantPress<4.2) //żeby nie załączał zaraz po przekroczeniu 4.0
|
||
{//załączenie małej sprężarki
|
||
mvControlling->bPantKurek3=false; //odłączenie zbiornika głównego, bo z nim nie da rady napompować
|
||
mvControlling->PantCompFlag=true; //załączenie sprężarki pantografów
|
||
}
|
||
}
|
||
//if (mvOccupied->TrainType==dt_EZT)
|
||
//{//Ra 2014-12: po co to tutaj?
|
||
// mvControlling->PantFront(true);
|
||
// mvControlling->PantRear(true);
|
||
//}
|
||
//if (mvControlling->EngineType==DieselElectric)
|
||
// mvControlling->Battery=true; //Ra: to musi być tak?
|
||
}
|
||
if (mvControlling->PantFrontVolt||mvControlling->PantRearVolt||voltfront||voltrear)
|
||
{//najpierw ustalamy kierunek, jeśli nie został ustalony
|
||
if (!iDirection) //jeśli nie ma ustalonego kierunku
|
||
if (mvOccupied->V==0)
|
||
{//ustalenie kierunku, gdy stoi
|
||
iDirection=mvOccupied->CabNo; //wg wybranej kabiny
|
||
if (!iDirection) //jeśli nie ma ustalonego kierunku
|
||
if ((mvControlling->PantFrontVolt!=0.0)||(mvControlling->PantRearVolt!=0.0)||voltfront||voltrear)
|
||
{if (mvOccupied->Couplers[1].CouplingFlag==ctrain_virtual) //jeśli z tyłu nie ma nic
|
||
iDirection=-1; //jazda w kierunku sprzęgu 1
|
||
if (mvOccupied->Couplers[0].CouplingFlag==ctrain_virtual) //jeśli z przodu nie ma nic
|
||
iDirection=1; //jazda w kierunku sprzęgu 0
|
||
}
|
||
}
|
||
else //ustalenie kierunku, gdy jedzie
|
||
if ((mvControlling->PantFrontVolt!=0.0)||(mvControlling->PantRearVolt!=0.0)||voltfront||voltrear)
|
||
if (mvOccupied->V<0) //jedzie do tyłu
|
||
iDirection=-1; //jazda w kierunku sprzęgu 1
|
||
else //jak nie do tyłu, to do przodu
|
||
iDirection=1; //jazda w kierunku sprzęgu 0
|
||
if (AIControllFlag) //jeśli prowadzi komputer
|
||
{//część wykonawcza dla sterowania przez komputer
|
||
if (mvControlling->ConvOvldFlag)
|
||
{//wywalił bezpiecznik nadmiarowy przetwornicy
|
||
while (DecSpeed(true)); //zerowanie napędu
|
||
mvControlling->ConvOvldFlag=false; //reset nadmiarowego
|
||
}
|
||
else if (!mvControlling->Mains)
|
||
{
|
||
//if TrainType=dt_SN61)
|
||
// begin
|
||
// OK:=(OrderDirectionChange(ChangeDir,Controlling)=-1);
|
||
// OK:=IncMainCtrl(1);
|
||
// end;
|
||
while (DecSpeed(true)); //zerowanie napędu
|
||
OK=mvControlling->MainSwitch(true);
|
||
if (mvControlling->EngineType==DieselEngine)
|
||
{//Ra 2014-06: dla SN61 trzeba wrzucić pierwszą pozycję - nie wiem, czy tutaj... kiedyś działało...
|
||
if (!mvControlling->MainCtrlPos)
|
||
{if (mvControlling->RList[0].R==0.0) //gdy na pozycji 0 dawka paliwa jest zerowa, to zgaśnie
|
||
mvControlling->IncMainCtrl(1); //dlatego trzeba zwiększyć pozycję
|
||
if (!mvControlling->ScndCtrlPos) //jeśli bieg nie został ustawiony
|
||
if (!mvControlling->MotorParam[0].AutoSwitch) //gdy biegi ręczne
|
||
if (mvControlling->MotorParam[0].mIsat==0.0) //bl,mIsat,fi,mfi
|
||
mvControlling->IncScndCtrl(1); //pierwszy bieg
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{//Ra: iDirection określa, w którą stronę jedzie skład względem sprzęgów pojazdu z AI
|
||
OK=(OrderDirectionChange(iDirection,mvOccupied)==-1);
|
||
//w EN57 sprężarka w ra jest zasilana z silnikowego
|
||
mvControlling->CompressorSwitch(true);
|
||
mvControlling->ConverterSwitch(true);
|
||
mvControlling->CompressorSwitch(true);
|
||
}
|
||
}
|
||
else OK=mvControlling->Mains;
|
||
}
|
||
else
|
||
OK=false;
|
||
OK=OK&&(mvOccupied->ActiveDir!=0)&&(mvControlling->CompressorAllow);
|
||
if (OK)
|
||
{
|
||
if (eStopReason==stopSleep) //jeśli dotychczas spał
|
||
eStopReason==stopNone; //teraz nie ma powodu do stania
|
||
iEngineActive=1;
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
iEngineActive=0;
|
||
return false;
|
||
}
|
||
};
|
||
|
||
bool __fastcall TController::ReleaseEngine()
|
||
{//wyłączanie silnika (test wyłączenia, a część wykonawcza tylko jeśli steruje komputer)
|
||
bool OK=false;
|
||
LastReactionTime=0.0;
|
||
ReactionTime=PrepareTime;
|
||
if (AIControllFlag)
|
||
{//jeśli steruje komputer
|
||
if (mvOccupied->DoorOpenCtrl==1)
|
||
{//zamykanie drzwi
|
||
if (mvOccupied->DoorLeftOpened) mvOccupied->DoorLeft(false);
|
||
if (mvOccupied->DoorRightOpened) mvOccupied->DoorRight(false);
|
||
}
|
||
if (mvOccupied->ActiveDir==0)
|
||
if (mvControlling->Mains)
|
||
{
|
||
mvControlling->CompressorSwitch(false);
|
||
mvControlling->ConverterSwitch(false);
|
||
if (mvControlling->EnginePowerSource.SourceType==CurrentCollector)
|
||
{
|
||
mvControlling->PantFront(false);
|
||
mvControlling->PantRear(false);
|
||
}
|
||
OK=mvControlling->MainSwitch(false);
|
||
}
|
||
else
|
||
OK=true;
|
||
}
|
||
else
|
||
if (mvOccupied->ActiveDir==0)
|
||
OK=mvControlling->Mains; //tylko to testujemy dla pojazdu człowieka
|
||
if (AIControllFlag)
|
||
if (!mvOccupied->DecBrakeLevel()) //tu moze zmieniać na -2, ale to bez znaczenia
|
||
if (!mvOccupied->IncLocalBrakeLevel(1))
|
||
{
|
||
while (DecSpeed(true)); //zerowanie nastawników
|
||
while (mvOccupied->ActiveDir>0)
|
||
mvOccupied->DirectionBackward();
|
||
while (mvOccupied->ActiveDir<0)
|
||
mvOccupied->DirectionForward();
|
||
}
|
||
OK=OK&&(mvOccupied->Vel<0.01);
|
||
if (OK)
|
||
{//jeśli się zatrzymał
|
||
iEngineActive=0;
|
||
eStopReason=stopSleep; //stoimy z powodu wyłączenia
|
||
eAction=actSleep; //śpi (wygaszony)
|
||
if (AIControllFlag)
|
||
{Lights(0,0); //gasimy światła
|
||
mvOccupied->BatterySwitch(false);
|
||
}
|
||
OrderNext(Wait_for_orders); //żeby nie próbował coś robić dalej
|
||
TableClear(); //zapominamy ograniczenia
|
||
iDrivigFlags&=~moveActive; //ma nie skanować sygnałów i nie reagować na komendy
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
bool __fastcall TController::IncBrake()
|
||
{//zwiększenie hamowania
|
||
bool OK=false;
|
||
switch (mvOccupied->BrakeSystem)
|
||
{
|
||
case Individual:
|
||
OK=mvOccupied->IncLocalBrakeLevel(1+floor(0.5+fabs(AccDesired)));
|
||
break;
|
||
case Pneumatic:
|
||
if ((mvOccupied->Couplers[0].Connected==NULL)&&(mvOccupied->Couplers[1].Connected==NULL))
|
||
OK=mvOccupied->IncLocalBrakeLevel(1+floor(0.5+fabs(AccDesired))); //hamowanie lokalnym bo luzem jedzie
|
||
else
|
||
{if (mvOccupied->BrakeCtrlPos+1==mvOccupied->BrakeCtrlPosNo)
|
||
{
|
||
if (AccDesired<-1.5) //hamowanie nagle
|
||
OK=mvOccupied->IncBrakeLevel();
|
||
else
|
||
OK=false;
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
if (AccDesired>-0.2) and ((Vel<20) or (Vel-VelNext<10)))
|
||
begin
|
||
if BrakeCtrlPos>0)
|
||
OK:=IncBrakeLevel
|
||
else;
|
||
OK:=IncLocalBrakeLevel(1); //finezyjne hamowanie lokalnym
|
||
end
|
||
else
|
||
*/
|
||
//dodane dla towarowego
|
||
if (mvOccupied->BrakeDelayFlag==bdelay_G?-AccDesired*6.6>Min0R(2,mvOccupied->BrakeCtrlPos):true)
|
||
{
|
||
OK=mvOccupied->IncBrakeLevel();
|
||
}
|
||
else
|
||
OK=false;
|
||
}
|
||
}
|
||
if (mvOccupied->BrakeCtrlPos>0) mvOccupied->BrakeReleaser(0);
|
||
break;
|
||
case ElectroPneumatic:
|
||
if(mvOccupied->fBrakeCtrlPos!=mvOccupied->Handle->GetPos(bh_EPB))
|
||
{
|
||
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPB));
|
||
if (mvOccupied->Handle->GetPos(bh_EPR)-mvOccupied->Handle->GetPos(bh_EPN)<0.1)
|
||
mvOccupied->SwitchEPBrake(1); //to nie chce działać
|
||
OK=true;
|
||
}
|
||
else OK=false;
|
||
// if (mvOccupied->BrakeCtrlPos<mvOccupied->BrakeCtrlPosNo)
|
||
// if (mvOccupied->BrakePressureTable[mvOccupied->BrakeCtrlPos+1+2].BrakeType==ElectroPneumatic) //+2 to indeks Pascala
|
||
// OK=mvOccupied->IncBrakeLevel();
|
||
// else
|
||
// OK=false;
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
bool __fastcall TController::DecBrake()
|
||
{//zmniejszenie siły hamowania
|
||
bool OK=false;
|
||
switch (mvOccupied->BrakeSystem)
|
||
{
|
||
case Individual:
|
||
OK=mvOccupied->DecLocalBrakeLevel(1+floor(0.5+fabs(AccDesired)));
|
||
break;
|
||
case Pneumatic:
|
||
if (mvOccupied->BrakeCtrlPos>0)
|
||
OK=mvOccupied->DecBrakeLevel();
|
||
if (!OK)
|
||
OK=mvOccupied->DecLocalBrakeLevel(2);
|
||
if (mvOccupied->PipePress<3.0)
|
||
Need_BrakeRelease=true;
|
||
break;
|
||
case ElectroPneumatic:
|
||
if(mvOccupied->fBrakeCtrlPos!=mvOccupied->Handle->GetPos(bh_EPR))
|
||
{
|
||
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPR));
|
||
if (mvOccupied->Handle->GetPos(bh_EPR)-mvOccupied->Handle->GetPos(bh_EPN)<0.1)
|
||
mvOccupied->SwitchEPBrake(1);
|
||
OK=true;
|
||
}
|
||
else OK=false;
|
||
if (!OK)
|
||
OK=mvOccupied->DecLocalBrakeLevel(2);
|
||
break;
|
||
}
|
||
return OK;
|
||
};
|
||
|
||
bool __fastcall TController::IncSpeed()
|
||
{//zwiększenie prędkości; zwraca false, jeśli dalej się nie da zwiększać
|
||
if (tsGuardSignal) //jeśli jest dźwięk kierownika
|
||
if (tsGuardSignal->GetStatus()&DSBSTATUS_PLAYING) //jeśli gada, to nie jedziemy
|
||
return false;
|
||
bool OK=true;
|
||
if (iDrivigFlags&moveDoorOpened)
|
||
Doors(false); //zamykanie drzwi - tutaj wykonuje tylko AI (zmienia fActionTime)
|
||
if (fActionTime<0.0) //gdy jest nakaz poczekać z jazdą, to nie ruszać
|
||
return false;
|
||
if (mvControlling->SlippingWheels)
|
||
return false; //jak poślizg, to nie przyspieszamy
|
||
switch (mvOccupied->EngineType)
|
||
{
|
||
case None: //McZapkie-041003: wagon sterowniczy
|
||
if (mvControlling->MainCtrlPosNo>0) //jeśli ma czym kręcić
|
||
iDrivigFlags|=moveIncSpeed; //ustawienie flagi jazdy
|
||
return false;
|
||
case ElectricSeriesMotor:
|
||
if (mvControlling->EnginePowerSource.SourceType==CurrentCollector) //jeśli pantografujący
|
||
{if (fOverhead2>=0.0) //a jazda bezprądowa ustawiana eventami (albo opuszczenie)
|
||
return false; //to nici z ruszania
|
||
if (iOverheadZero) //jazda bezprądowa z poziomu toru ustawia bity
|
||
return false; //to nici z ruszania
|
||
}
|
||
if (!mvControlling->FuseFlag) //&&mvControlling->StLinFlag) //yBARC
|
||
if ((mvControlling->MainCtrlPos==0)||(mvControlling->StLinFlag)) //youBy polecił dodać 2012-09-08 v367
|
||
//na pozycji 0 przejdzie, a na pozostałych będzie czekać, aż się załączą liniowe (zgaśnie DelayCtrlFlag)
|
||
if (Ready||(iDrivigFlags&movePress))
|
||
if (fabs(mvControlling->Im)<(fReady<0.4?mvControlling->Imin:mvControlling->IminLo))
|
||
{//Ra: wywalał nadmiarowy, bo Im może być ujemne; jak nie odhamowany, to nie przesadzać z prądem
|
||
if ((mvOccupied->Vel<=30)||(mvControlling->Imax>mvControlling->ImaxLo)
|
||
|| (fVoltage+fVoltage<mvControlling->EnginePowerSource.CollectorParameters.MinV+mvControlling->EnginePowerSource.CollectorParameters.MaxV))
|
||
{//bocznik na szeregowej przy ciezkich bruttach albo przy wysokim rozruchu pod górę albo przy niskim napięciu
|
||
if (mvControlling->MainCtrlPos?mvControlling->RList[mvControlling->MainCtrlPos].R>0.0:true) //oporowa
|
||
{
|
||
OK=(mvControlling->DelayCtrlFlag?true:mvControlling->IncMainCtrl(1)); //kręcimy nastawnik jazdy
|
||
if ((OK)&&(mvControlling->MainCtrlPos==1)) //czekaj na 1 pozycji, zanim się nie włączą liniowe
|
||
iDrivigFlags|=moveIncSpeed;
|
||
else
|
||
iDrivigFlags&=~moveIncSpeed; //usunięcie flagi czekania
|
||
}
|
||
else //jeśli bezoporowa (z wyjątekiem 0)
|
||
OK=false; //to dać bocznik
|
||
}
|
||
else
|
||
{//przekroczone 30km/h, można wejść na jazdę równoległą
|
||
if (mvControlling->ScndCtrlPos) //jeśli ustawiony bocznik
|
||
if (mvControlling->MainCtrlPos<mvControlling->MainCtrlPosNo-1) //a nie jest ostatnia pozycja
|
||
mvControlling->DecScndCtrl(2); //to bocznik na zero po chamsku (ktoś miał to poprawić...)
|
||
OK=mvControlling->IncMainCtrl(1);
|
||
}
|
||
if ((mvControlling->MainCtrlPos>2)&&(mvControlling->Im==0)) //brak prądu na dalszych pozycjach
|
||
Need_TryAgain=true; //nie załączona lokomotywa albo wywalił nadmiarowy
|
||
else if (!OK) //nie da się wrzucić kolejnej pozycji
|
||
OK=mvControlling->IncScndCtrl(1); //to dać bocznik
|
||
}
|
||
mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania
|
||
break;
|
||
case Dumb:
|
||
case DieselElectric:
|
||
if (!mvControlling->FuseFlag)
|
||
if (Ready||(iDrivigFlags&movePress)) //{(BrakePress<=0.01*MaxBrakePress)}
|
||
{
|
||
OK=mvControlling->IncMainCtrl(1);
|
||
if (!OK)
|
||
OK=mvControlling->IncScndCtrl(1);
|
||
}
|
||
break;
|
||
case WheelsDriven:
|
||
if (!mvControlling->CabNo)
|
||
mvControlling->CabActivisation();
|
||
if (sin(mvControlling->eAngle)>0)
|
||
mvControlling->IncMainCtrl(3+3*floor(0.5+fabs(AccDesired)));
|
||
else
|
||
mvControlling->DecMainCtrl(3+3*floor(0.5+fabs(AccDesired)));
|
||
break;
|
||
case DieselEngine:
|
||
if (mvControlling->ShuntModeAllow)
|
||
{//dla 2Ls150 można zmienić tryb pracy, jeśli jest w liniowym i nie daje rady (wymaga zerowania kierunku)
|
||
//mvControlling->ShuntMode=(OrderList[OrderPos]&Shunt)||(fMass>224000.0);
|
||
}
|
||
if ((mvControlling->Vel>mvControlling->dizel_minVelfullengage)&&(mvControlling->RList[mvControlling->MainCtrlPos].Mn>0))
|
||
OK=mvControlling->IncMainCtrl(1);
|
||
if (mvControlling->RList[mvControlling->MainCtrlPos].Mn==0)
|
||
OK=mvControlling->IncMainCtrl(1);
|
||
if (!mvControlling->Mains)
|
||
{
|
||
mvControlling->MainSwitch(true);
|
||
mvControlling->ConverterSwitch(true);
|
||
mvControlling->CompressorSwitch(true);
|
||
}
|
||
break;
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
bool __fastcall TController::DecSpeed(bool force)
|
||
{//zmniejszenie prędkości (ale nie hamowanie)
|
||
bool OK=false; //domyślnie false, aby wyszło z pętli while
|
||
switch (mvOccupied->EngineType)
|
||
{
|
||
case None: //McZapkie-041003: wagon sterowniczy
|
||
iDrivigFlags&=~moveIncSpeed; //usunięcie flagi jazdy
|
||
if (force) //przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania
|
||
if (mvControlling->MainCtrlPosNo>0) //McZapkie-041003: wagon sterowniczy, np. EZT
|
||
mvControlling->DecMainCtrl(1+(mvControlling->MainCtrlPos>2?1:0));
|
||
mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania
|
||
return false;
|
||
case ElectricSeriesMotor:
|
||
OK=mvControlling->DecScndCtrl(2); //najpierw bocznik na zero
|
||
if (!OK)
|
||
OK=mvControlling->DecMainCtrl(1+(mvControlling->MainCtrlPos>2?1:0));
|
||
mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania
|
||
break;
|
||
case Dumb:
|
||
case DieselElectric:
|
||
OK=mvControlling->DecScndCtrl(2);
|
||
if (!OK)
|
||
OK=mvControlling->DecMainCtrl(2+(mvControlling->MainCtrlPos/2));
|
||
break;
|
||
case WheelsDriven:
|
||
if (!mvControlling->CabNo)
|
||
mvControlling->CabActivisation();
|
||
if (sin(mvControlling->eAngle)<0)
|
||
mvControlling->IncMainCtrl(3+3*floor(0.5+fabs(AccDesired)));
|
||
else
|
||
mvControlling->DecMainCtrl(3+3*floor(0.5+fabs(AccDesired)));
|
||
break;
|
||
case DieselEngine:
|
||
if ((mvControlling->Vel>mvControlling->dizel_minVelfullengage))
|
||
{
|
||
if (mvControlling->RList[mvControlling->MainCtrlPos].Mn>0)
|
||
OK=mvControlling->DecMainCtrl(1);
|
||
}
|
||
else
|
||
while ((mvControlling->RList[mvControlling->MainCtrlPos].Mn>0)&&(mvControlling->MainCtrlPos>1))
|
||
OK=mvControlling->DecMainCtrl(1);
|
||
if (force) //przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania
|
||
OK=mvControlling->DecMainCtrl(1+(mvControlling->MainCtrlPos>2?1:0));
|
||
break;
|
||
}
|
||
return OK;
|
||
};
|
||
|
||
void __fastcall TController::SpeedSet()
|
||
{//Ra: regulacja prędkości, wykonywana w każdym przebłysku świadomości AI
|
||
//ma dokręcać do bezoporowych i zdejmować pozycje w przypadku przekroczenia prądu
|
||
switch (mvOccupied->EngineType)
|
||
{
|
||
case None: //McZapkie-041003: wagon sterowniczy
|
||
if (fActionTime>=-1.0)
|
||
mvOccupied->DepartureSignal=false; //trochę niech pobuczy, zanim pojedzie
|
||
if (mvControlling->MainCtrlPosNo>0)
|
||
{//jeśli ma czym kręcić
|
||
//TODO: sprawdzanie innego czlonu //if (!FuseFlagCheck())
|
||
if ((AccDesired<fAccGravity-0.05)||(mvOccupied->Vel>VelDesired)) //jeśli nie ma przyspieszać
|
||
mvControlling->DecMainCtrl(2); //na zero
|
||
else
|
||
if (fActionTime>=0.0)
|
||
{//jak już można coś poruszać, przetok rozłączać od razu
|
||
if (iDrivigFlags&moveIncSpeed)
|
||
{//jak ma jechać
|
||
if (fReady<0.4) //0.05*Controlling->MaxBrakePress)
|
||
{//jak jest odhamowany
|
||
if (mvOccupied->ActiveDir>0) mvOccupied->DirectionForward(); //żeby EN57 jechały na drugiej nastawie
|
||
{
|
||
if (mvControlling->MainCtrlPos&&!mvControlling->StLinFlag) //jak niby jedzie, ale ma rozłączone liniowe
|
||
mvControlling->DecMainCtrl(2); //to na zero i czekać na przewalenie kułakowego
|
||
else
|
||
switch (mvControlling->MainCtrlPos)
|
||
{//ruch nastawnika uzależniony jest od aktualnie ustawionej pozycji
|
||
case 0:
|
||
if (mvControlling->MainCtrlActualPos) //jeśli kułakowy nie jest wyzerowany
|
||
break; //to czekać na wyzerowanie
|
||
mvControlling->IncMainCtrl(1); //przetok; bez "break", bo nie ma czekania na 1. pozycji
|
||
case 1:
|
||
if (VelDesired>=20) mvControlling->IncMainCtrl(1); //szeregowa
|
||
case 2:
|
||
if (VelDesired>=50) mvControlling->IncMainCtrl(1); //równoległa
|
||
case 3:
|
||
if (VelDesired>=80) mvControlling->IncMainCtrl(1); //bocznik 1
|
||
case 4:
|
||
if (VelDesired>=90) mvControlling->IncMainCtrl(1); //bocznik 2
|
||
case 5:
|
||
if (VelDesired>=100) mvControlling->IncMainCtrl(1); //bocznik 3
|
||
}
|
||
if (mvControlling->MainCtrlPos) //jak załączył pozycję
|
||
{fActionTime=-5.0; //niech trochę potrzyma
|
||
mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{while (mvControlling->MainCtrlPos)
|
||
mvControlling->DecMainCtrl(1); //na zero
|
||
fActionTime=-5.0; //niech trochę potrzyma
|
||
mvControlling->AutoRelayCheck(); //sprawdzenie logiki sterowania
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case ElectricSeriesMotor:
|
||
if ((!mvControlling->StLinFlag)&&(!mvControlling->DelayCtrlFlag)&&(!iDrivigFlags&moveIncSpeed)) //styczniki liniowe rozłączone yBARC
|
||
// if (iDrivigFlags&moveIncSpeed) {} //jeśli czeka na załączenie liniowych
|
||
// else
|
||
while (DecSpeed()); //zerowanie napędu
|
||
else
|
||
if (Ready||(iDrivigFlags&movePress)) //o ile może jechać
|
||
if (fAccGravity<-0.10) //i jedzie pod górę większą niż 10 promil
|
||
{//procedura wjeżdżania na ekstremalne wzniesienia
|
||
if (fabs(mvControlling->Im)>0.85*mvControlling->Imax) //a prąd jest większy niż 85% nadmiarowego
|
||
//if (mvControlling->Imin*mvControlling->Voltage/(fMass*fAccGravity)<-2.8) //a na niskim się za szybko nie pojedzie
|
||
if (mvControlling->Imax*mvControlling->Voltage/(fMass*fAccGravity)<-2.8) //a na niskim się za szybko nie pojedzie
|
||
{//włączenie wysokiego rozruchu; (I*U)[A*V=W=kg*m*m/sss]/(m[kg]*a[m/ss])=v[m/s]; 2.8m/ss=10km/h
|
||
if (mvControlling->RList[mvControlling->MainCtrlPos].Bn>1)
|
||
{//jeśli jedzie na równoległym, to zbijamy do szeregowego, aby włączyć wysoki rozruch
|
||
if (mvControlling->ScndCtrlPos>0) //jeżeli jest bocznik
|
||
mvControlling->DecScndCtrl(2); //wyłączyć bocznik, bo może blokować skręcenie NJ
|
||
do //skręcanie do bezoporowej na szeregowym
|
||
mvControlling->DecMainCtrl(1); //kręcimy nastawnik jazdy o 1 wstecz
|
||
while (mvControlling->MainCtrlPos?mvControlling->RList[mvControlling->MainCtrlPos].Bn>1:false); //oporowa zapętla
|
||
}
|
||
if (mvControlling->Imax<mvControlling->ImaxHi) //jeśli da się na wysokim
|
||
mvControlling->CurrentSwitch(true); //rozruch wysoki (za to może się ślizgać)
|
||
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ć
|
||
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
|
||
mvControlling->DecScndCtrl(2); //zmniejszyć bocznik
|
||
else
|
||
mvControlling->DecMainCtrl(1); //kręcimy nastawnik jazdy o 1 wstecz
|
||
}
|
||
else //gdy nie jedzie ambitnie pod górę
|
||
{//sprawdzenie, czy rozruch wysoki jest potrzebny
|
||
if (mvControlling->Imax>mvControlling->ImaxLo)
|
||
if (mvOccupied->Vel>=30.0) //jak się rozpędził
|
||
if (fAccGravity>-0.02) //a i pochylenie mnijsze niż 2‰
|
||
mvControlling->CurrentSwitch(false); //rozruch wysoki wyłącz
|
||
//dokręcanie do bezoporowej, bo IncSpeed() może nie być wywoływane
|
||
//if (mvOccupied->Vel<VelDesired)
|
||
// if (AccDesired>-0.1) //nie ma hamować
|
||
// if (Controlling->RList[MainCtrlPos].R>0.0)
|
||
// if (Im<1.3*Imin) //lekkie przekroczenie miimalnego prądu jest dopuszczalne
|
||
// IncMainCtrl(1); //zwieksz nastawnik skoro możesz - tak aby się ustawic na bezoporowej
|
||
}
|
||
break;
|
||
case Dumb:
|
||
case DieselElectric:
|
||
break;
|
||
//WheelsDriven :
|
||
// begin
|
||
// OK:=False;
|
||
// end;
|
||
case DieselEngine:
|
||
//Ra 2014-06: "automatyczna" skrzynia biegów...
|
||
if (!mvControlling->MotorParam[mvControlling->ScndCtrlPos].AutoSwitch) //gdy biegi ręczne
|
||
if ((mvControlling->ShuntMode?mvControlling->AnPos:1.0)*mvControlling->Vel>0.6*mvControlling->MotorParam[mvControlling->ScndCtrlPos].mfi)
|
||
//if (mvControlling->enrot>0.95*mvControlling->dizel_nMmax) //youBy: jeśli obroty > 0,95 nmax, wrzuć wyższy bieg - Ra: to nie działa
|
||
{//jak prędkość większa niż 0.6 maksymalnej na danym biegu, wrzucić wyższy
|
||
mvControlling->DecMainCtrl(2);
|
||
if (mvControlling->IncScndCtrl(1))
|
||
if (mvControlling->MotorParam[mvControlling->ScndCtrlPos].mIsat==0.0) //jeśli bieg jałowy
|
||
mvControlling->IncScndCtrl(1); //to kolejny
|
||
}
|
||
else if ((mvControlling->ShuntMode?mvControlling->AnPos:1.0)*mvControlling->Vel<mvControlling->MotorParam[mvControlling->ScndCtrlPos].fi)
|
||
{//jak prędkość mniejsza niż minimalna na danym biegu, wrzucić niższy
|
||
mvControlling->DecMainCtrl(2);
|
||
mvControlling->DecScndCtrl(1);
|
||
if (mvControlling->MotorParam[mvControlling->ScndCtrlPos].mIsat==0.0) //jeśli bieg jałowy
|
||
if (mvControlling->ScndCtrlPos) //a jeszcze zera nie osiągnięto
|
||
mvControlling->DecScndCtrl(1); //to kolejny wcześniejszy
|
||
else
|
||
mvControlling->IncScndCtrl(1); //a jak zeszło na zero, to powrót
|
||
}
|
||
break;
|
||
}
|
||
};
|
||
|
||
void __fastcall TController::Doors(bool what)
|
||
{//otwieranie/zamykanie drzwi w składzie albo (tylko AI) EZT
|
||
if (what)
|
||
{//otwarcie
|
||
}
|
||
else
|
||
{//zamykanie
|
||
if (mvOccupied->DoorOpenCtrl==1)
|
||
{//jeśli drzwi sterowane z kabiny
|
||
if (AIControllFlag)
|
||
if (mvOccupied->DoorLeftOpened||mvOccupied->DoorRightOpened)
|
||
{//AI zamyka drzwi przed odjazdem
|
||
if (mvOccupied->DoorClosureWarning)
|
||
mvOccupied->DepartureSignal=true; //załącenie bzyczka
|
||
mvOccupied->DoorLeft(false); //zamykanie drzwi
|
||
mvOccupied->DoorRight(false);
|
||
//Ra: trzeba by ustawić jakiś czas oczekiwania na zamknięcie się drzwi
|
||
fActionTime=-1.5-0.1*random(10); //czekanie sekundę, może trochę dłużej
|
||
iDrivigFlags&=~moveDoorOpened; //nie wykonywać drugi raz
|
||
}
|
||
}
|
||
else
|
||
{//jeśli nie, to zamykanie w składzie wagonowym
|
||
TDynamicObject *p=pVehicles[0]; //pojazd na czole składu
|
||
while (p)
|
||
{//zamykanie drzwi w pojazdach - flaga zezwolenia była by lepsza
|
||
p->MoverParameters->DoorLeft(false); //w lokomotywie można by nie zamykać...
|
||
p->MoverParameters->DoorRight(false);
|
||
p=p->Next(); //pojazd podłączony z tyłu (patrząc od czoła)
|
||
}
|
||
//WaitingSet(5); //10 sekund tu to za długo, opóźnia odjazd o pół minuty
|
||
fActionTime=-1.5-0.1*random(10); //czekanie sekundę, może trochę dłużej
|
||
iDrivigFlags&=~moveDoorOpened; //zostały zamknięte - nie wykonywać drugi raz
|
||
}
|
||
}
|
||
};
|
||
|
||
void __fastcall TController::RecognizeCommand()
|
||
{//odczytuje i wykonuje komendę przekazaną lokomotywie
|
||
TCommand *c=&mvOccupied->CommandIn;
|
||
PutCommand(c->Command,c->Value1,c->Value2,c->Location,stopComm);
|
||
c->Command=""; //usunięcie obsłużonej komendy
|
||
}
|
||
|
||
|
||
void __fastcall TController::PutCommand(AnsiString NewCommand,double NewValue1,double NewValue2,const TLocation &NewLocation,TStopReason reason)
|
||
{//wysłanie komendy przez event PutValues, jak pojazd ma obsadę, to wysyła tutaj, a nie do pojazdu bezpośrednio
|
||
vector3 sl;
|
||
sl.x=-NewLocation.X; //zamiana na współrzędne scenerii
|
||
sl.z= NewLocation.Y;
|
||
sl.y= NewLocation.Z;
|
||
if (!PutCommand(NewCommand,NewValue1,NewValue2,&sl,reason))
|
||
mvOccupied->PutCommand(NewCommand,NewValue1,NewValue2,NewLocation);
|
||
}
|
||
|
||
|
||
bool __fastcall TController::PutCommand(AnsiString NewCommand,double NewValue1,double NewValue2,const vector3 *NewLocation,TStopReason reason)
|
||
{//analiza komendy
|
||
if (NewCommand=="CabSignal")
|
||
{//SHP wyzwalane jest przez człon z obsadą, ale obsługiwane przez silnikowy
|
||
//nie jest to najlepiej zrobione, ale bez symulacji obwodów lepiej nie będzie
|
||
//Ra 2014-04: jednak przeniosłem do rozrządczego
|
||
mvOccupied->PutCommand(NewCommand,NewValue1,NewValue2,mvOccupied->Loc);
|
||
mvOccupied->RunInternalCommand(); //rozpoznaj komende bo lokomotywa jej nie rozpoznaje
|
||
return true; //załatwione
|
||
}
|
||
if (NewCommand=="Overhead")
|
||
{//informacja o stanie sieci trakcyjnej
|
||
fOverhead1=NewValue1; //informacja o napięciu w sieci trakcyjnej (0=brak drutu, zatrzymaj!)
|
||
fOverhead2=NewValue2; //informacja o sposobie jazdy (-1=normalnie, 0=bez prądu, >0=z opuszczonym i ograniczeniem prędkości)
|
||
return true; //załatwione
|
||
}
|
||
else if (NewCommand=="Emergency_brake") //wymuszenie zatrzymania, niezależnie kto prowadzi
|
||
{//Ra: no nadal nie jest zbyt pięknie
|
||
SetVelocity(0,0,reason);
|
||
mvOccupied->PutCommand("Emergency_brake",1.0,1.0,mvOccupied->Loc);
|
||
return true; //załatwione
|
||
}
|
||
else if (NewCommand.Pos("Timetable:")==1)
|
||
{//przypisanie nowego rozkładu jazdy, również prowadzonemu przez użytkownika
|
||
NewCommand.Delete(1,10); //zostanie nazwa pliku z rozkładem
|
||
#if LOGSTOPS
|
||
WriteLog("New timetable for "+pVehicle->asName+": "+NewCommand); //informacja
|
||
#endif
|
||
if (!TrainParams)
|
||
TrainParams=new TTrainParameters(NewCommand); //rozkład jazdy
|
||
else
|
||
TrainParams->NewName(NewCommand); //czyści tabelkę przystanków
|
||
delete tsGuardSignal; tsGuardSignal=NULL; //wywalenie kierownika
|
||
if (NewCommand!="none")
|
||
{if (!TrainParams->LoadTTfile(Global::asCurrentSceneryPath,floor(NewValue2+0.5),NewValue1)) //pierwszy parametr to przesunięcie rozkładu w czasie
|
||
{
|
||
if (ConversionError==-8)
|
||
ErrorLog("Missed timetable: "+NewCommand);
|
||
WriteLog("Cannot load timetable file "+NewCommand+"\r\nError "+ConversionError+" in position "+TrainParams->StationCount);
|
||
NewCommand=""; //puste, dla wymiennej tekstury
|
||
}
|
||
else
|
||
{//inicjacja pierwszego przystanku i pobranie jego nazwy
|
||
TrainParams->UpdateMTable(GlobalTime->hh,GlobalTime->mm,TrainParams->NextStationName);
|
||
TrainParams->StationIndexInc(); //przejście do następnej
|
||
iStationStart=TrainParams->StationIndex;
|
||
asNextStop=TrainParams->NextStop();
|
||
iDrivigFlags|=movePrimary; //skoro dostał rozkład, to jest teraz głównym
|
||
NewCommand=Global::asCurrentSceneryPath+NewCommand+".wav"; //na razie jeden
|
||
if (FileExists(NewCommand))
|
||
{//wczytanie dźwięku odjazdu podawanego bezpośrenido
|
||
tsGuardSignal=new TTextSound();
|
||
tsGuardSignal->Init(NewCommand.c_str(),30,pVehicle->GetPosition().x,pVehicle->GetPosition().y,pVehicle->GetPosition().z,false);
|
||
//rsGuardSignal->Stop();
|
||
iGuardRadio=0; //nie przez radio
|
||
}
|
||
else
|
||
{NewCommand.Insert("radio",NewCommand.Length()-3); //wstawienie przed kropką
|
||
if (FileExists(NewCommand))
|
||
{//wczytanie dźwięku odjazdu w wersji radiowej (słychać tylko w kabinie)
|
||
tsGuardSignal=new TTextSound();
|
||
tsGuardSignal->Init(NewCommand.c_str(),-1,pVehicle->GetPosition().x,pVehicle->GetPosition().y,pVehicle->GetPosition().z,false);
|
||
iGuardRadio=iRadioChannel;
|
||
}
|
||
}
|
||
NewCommand=TrainParams->Relation2; //relacja docelowa z rozkładu
|
||
}
|
||
//jeszcze poustawiać tekstury na wyświetlaczach
|
||
TDynamicObject *p=pVehicles[0];
|
||
while (p)
|
||
{
|
||
p->DestinationSet(NewCommand); //relacja docelowa
|
||
p=p->Next(); //pojazd podłączony od tyłu (licząc od czoła)
|
||
}
|
||
}
|
||
if (NewLocation) //jeśli podane współrzędne eventu/komórki ustawiającej rozkład (trainset nie podaje)
|
||
{vector3 v=*NewLocation-pVehicle->GetPosition(); //wektor do punktu sterującego
|
||
vector3 d=pVehicle->VectorFront(); //wektor wskazujący przód
|
||
iDirectionOrder=((v.x*d.x+v.z*d.z)*NewValue1>0)?1:-1; //do przodu, gdy iloczyn skalarny i prędkość dodatnie
|
||
/*
|
||
if (NewValue1!=0.0) //jeśli ma jechać
|
||
if (iDirectionOrder==0) //a kierunek nie był określony (normalnie określany przez reardriver/headdriver)
|
||
iDirectionOrder=NewValue1>0?1:-1; //ustalenie kierunku jazdy względem sprzęgów
|
||
else
|
||
if (NewValue1<0) //dla ujemnej prędkości
|
||
iDirectionOrder=-iDirectionOrder; //ma jechać w drugą stronę
|
||
*/
|
||
if (AIControllFlag) //jeśli prowadzi komputer
|
||
Activation(); //umieszczenie obsługi we właściwym członie, ustawienie nawrotnika w przód
|
||
}
|
||
/*
|
||
else
|
||
if (!iDirectionOrder)
|
||
{//jeśli nie ma kierunku, trzeba ustalić
|
||
if (mvOccupied->V!=0.0)
|
||
iDirectionOrder=mvOccupied->V>0?1:-1;
|
||
else
|
||
iDirectionOrder=mvOccupied->ActiveCab;
|
||
if (!iDirectionOrder) iDirectionOrder=1;
|
||
}
|
||
*/
|
||
//jeśli wysyłane z Trainset, to wszystko jest już odpowiednio ustawione
|
||
//if (!NewLocation) //jeśli wysyłane z Trainset
|
||
// if (mvOccupied->CabNo*mvOccupied->V*NewValue1<0) //jeśli zadana prędkość niezgodna z aktualnym kierunkiem jazdy
|
||
// DirectionForward(false); //jedziemy do tyłu (nawrotnik do tyłu)
|
||
//CheckVehicles(); //sprawdzenie składu, AI zapali światła
|
||
TableClear(); //wyczyszczenie tabelki prędkości, bo na nowo trzeba określić kierunek i sprawdzić przystanki
|
||
OrdersInit(fabs(NewValue1)); //ustalenie tabelki komend wg rozkładu oraz prędkości początkowej
|
||
//if (NewValue1!=0.0) if (!AIControllFlag) DirectionForward(NewValue1>0.0); //ustawienie nawrotnika użytkownikowi (propaguje się do członów)
|
||
//if (NewValue1>0)
|
||
// TrainNumber=floor(NewValue1); //i co potem ???
|
||
return true; //załatwione
|
||
}
|
||
if (NewCommand=="SetVelocity")
|
||
{
|
||
if (NewLocation)
|
||
vCommandLocation=*NewLocation;
|
||
if ((NewValue1!=0.0)&&(OrderList[OrderPos]!=Obey_train))
|
||
{//o ile jazda
|
||
if (!iEngineActive)
|
||
OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw, światła ustawi JumpToNextOrder()
|
||
//if (OrderList[OrderPos]!=Obey_train) //jeśli nie pociągowa
|
||
OrderNext(Obey_train); //to uruchomić jazdę pociągową (od razu albo po odpaleniu silnika
|
||
OrderCheck(); //jeśli jazda pociągowa teraz, to wykonać niezbędne operacje
|
||
}
|
||
if (NewValue1!=0.0) //jeśli jechać
|
||
iDrivigFlags&=~moveStopHere; //podjeżanie do semaforów zezwolone
|
||
else
|
||
iDrivigFlags|=moveStopHere; //stać do momentu podania komendy jazdy
|
||
SetVelocity(NewValue1,NewValue2,reason); //bylo: nic nie rob bo SetVelocity zewnetrznie jest wywolywane przez dynobj.cpp
|
||
}
|
||
else if (NewCommand=="SetProximityVelocity")
|
||
{
|
||
/*
|
||
if (SetProximityVelocity(NewValue1,NewValue2))
|
||
if (NewLocation)
|
||
vCommandLocation=*NewLocation;
|
||
*/
|
||
}
|
||
else if (NewCommand=="ShuntVelocity")
|
||
{//uruchomienie jazdy manewrowej bądź zmiana prędkości
|
||
if (NewLocation)
|
||
vCommandLocation=*NewLocation;
|
||
//if (OrderList[OrderPos]=Obey_train) and (NewValue1<>0))
|
||
if (!iEngineActive)
|
||
OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw
|
||
OrderNext(Shunt); //zamieniamy w aktualnej pozycji, albo dodajey za odpaleniem silnika
|
||
if (NewValue1!=0.0)
|
||
{
|
||
//if (iVehicleCount>=0) WriteLog("Skasowano ilosć wagonów w ShuntVelocity!");
|
||
iVehicleCount=-2; //wartość neutralna
|
||
CheckVehicles(); //zabrać to do OrderCheck()
|
||
}
|
||
//dla prędkości ujemnej przestawić nawrotnik do tyłu? ale -1=brak ograniczenia !!!!
|
||
//if (iDrivigFlags&movePress) WriteLog("Skasowano docisk w ShuntVelocity!");
|
||
iDrivigFlags&=~movePress; //bez dociskania
|
||
SetVelocity(NewValue1,NewValue2,reason);
|
||
if (NewValue1!=0.0)
|
||
iDrivigFlags&=~moveStopHere; //podjeżanie do semaforów zezwolone
|
||
else
|
||
iDrivigFlags|=moveStopHere; //ma stać w miejscu
|
||
if (fabs(NewValue1)>2.0) //o ile wartość jest sensowna (-1 nie jest konkretną wartością)
|
||
fShuntVelocity=fabs(NewValue1); //zapamiętanie obowiązującej prędkości dla manewrów
|
||
}
|
||
else if (NewCommand=="Wait_for_orders")
|
||
{//oczekiwanie; NewValue1 - czas oczekiwania, -1 = na inną komendę
|
||
if (NewValue1>0.0?NewValue1>fStopTime:false)
|
||
fStopTime=NewValue1; //Ra: włączenie czekania bez zmiany komendy
|
||
else
|
||
OrderList[OrderPos]=Wait_for_orders; //czekanie na komendę (albo dać OrderPos=0)
|
||
}
|
||
else if (NewCommand=="Prepare_engine")
|
||
{//włączenie albo wyłączenie silnika (w szerokim sensie)
|
||
OrdersClear(); //czyszczenie tabelki rozkazów, aby nic dalej nie robił
|
||
if (NewValue1==0.0)
|
||
OrderNext(Release_engine); //wyłączyć silnik (przygotować pojazd do jazdy)
|
||
else if (NewValue1>0.0)
|
||
OrderNext(Prepare_engine); //odpalić silnik (wyłączyć wszystko, co się da)
|
||
//po załączeniu przejdzie do kolejnej komendy, po wyłączeniu na Wait_for_orders
|
||
}
|
||
else if (NewCommand=="Change_direction")
|
||
{
|
||
TOrders o=OrderList[OrderPos]; //co robił przed zmianą kierunku
|
||
if (!iEngineActive)
|
||
OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw
|
||
if (NewValue1==0.0)
|
||
iDirectionOrder=-iDirection; //zmiana na przeciwny niż obecny
|
||
else
|
||
if (NewLocation) //jeśli podane współrzędne eventu/komórki ustawiającej rozkład (trainset nie podaje)
|
||
{vector3 v=*NewLocation-pVehicle->GetPosition(); //wektor do punktu sterującego
|
||
vector3 d=pVehicle->VectorFront(); //wektor wskazujący przód
|
||
iDirectionOrder=((v.x*d.x+v.z*d.z)*NewValue1>0)?1:-1; //do przodu, gdy iloczyn skalarny i prędkość dodatnie
|
||
//iDirectionOrder=1; else if (NewValue1<0.0) iDirectionOrder=-1;
|
||
}
|
||
if (iDirectionOrder!=iDirection)
|
||
OrderNext(Change_direction); //zadanie komendy do wykonania
|
||
if (o>=Shunt) //jeśli jazda manewrowa albo pociągowa
|
||
OrderNext(o); //to samo robić po zmianie
|
||
else if (!o) //jeśli wcześniej było czekanie
|
||
OrderNext(Shunt); //to dalej jazda manewrowa
|
||
if (mvOccupied->Vel>=1.0) //jeśli jedzie
|
||
iDrivigFlags&=~moveStartHorn; //to bez trąbienia po ruszeniu z zatrzymania
|
||
//Change_direction wykona się samo i następnie przejdzie do kolejnej komendy
|
||
}
|
||
else if (NewCommand=="Obey_train")
|
||
{
|
||
if (!iEngineActive)
|
||
OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw
|
||
OrderNext(Obey_train);
|
||
//if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ???
|
||
OrderCheck(); //jeśli jazda pociągowa teraz, to wykonać niezbędne operacje
|
||
}
|
||
else if (NewCommand=="Shunt")
|
||
{//NewValue1 - ilość wagonów (-1=wszystkie); NewValue2: 0=odczep, 1..63=dołącz, -1=bez zmian
|
||
//-3,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać w trybie pociągowym
|
||
//-2,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać
|
||
//-2, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i czekać
|
||
//-1,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać w powrotną stronę
|
||
//-1, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać dalej
|
||
//-1, 0 - tryb manewrowy bez zmian (odczepianie z pozostawieniem wagonów nie ma sensu)
|
||
// 0, 0 - odczepienie lokomotywy
|
||
// 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x) wagonów
|
||
// 1, 0 - odczepienie lokomotywy z jednym wagonem
|
||
iDrivigFlags&=~moveStopHere; //podjeżanie do semaforów zezwolone
|
||
if (!iEngineActive)
|
||
OrderNext(Prepare_engine); //trzeba odpalić silnik najpierw
|
||
if (NewValue2!=0) //jeśli podany jest sprzęg
|
||
{iCoupler=floor(fabs(NewValue2)); //jakim sprzęgiem
|
||
OrderNext(Connect); //najpierw połącz pojazdy
|
||
if (NewValue1>=0.0) //jeśli ilość wagonów inna niż wszystkie
|
||
{//to po podpięciu należy się odczepić
|
||
iDirectionOrder=-iDirection; //zmiana na ciągnięcie
|
||
OrderPush(Change_direction); //najpierw zmień kierunek, bo odczepiamy z tyłu
|
||
OrderPush(Disconnect); //a odczep już po zmianie kierunku
|
||
}
|
||
else if (NewValue2<0.0) //jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku po podczepieniu
|
||
{//np. Shunt -1 -3
|
||
iDirectionOrder=-iDirection; //jak się podczepi, to jazda w przeciwną stronę
|
||
OrderNext(Change_direction);
|
||
}
|
||
WaitingTime=0.0; //nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie
|
||
}
|
||
else //if (NewValue2==0.0) //zerowy sprzęg
|
||
if (NewValue1>=0.0) //jeśli ilość wagonów inna niż wszystkie
|
||
{//będzie odczepianie, ale jeśli wagony są z przodu, to trzeba najpierw zmienić kierunek
|
||
if ((mvOccupied->Couplers[mvOccupied->DirAbsolute>0?1:0].CouplingFlag==0)? //z tyłu nic
|
||
(mvOccupied->Couplers[mvOccupied->DirAbsolute>0?0:1].CouplingFlag>0):false) //a z przodu skład
|
||
{iDirectionOrder=-iDirection; //zmiana na ciągnięcie
|
||
OrderNext(Change_direction); //najpierw zmień kierunek (zastąpi Disconnect)
|
||
OrderPush(Disconnect); //a odczep już po zmianie kierunku
|
||
}
|
||
else
|
||
if (mvOccupied->Couplers[mvOccupied->DirAbsolute>0?1:0].CouplingFlag>0) //z tyłu coś
|
||
OrderNext(Disconnect); //jak ciągnie, to tylko odczep (NewValue1) wagonów
|
||
WaitingTime=0.0; //nie ma co dalej czekać, można zatrąbić i jechać, chyba że już jedzie
|
||
}
|
||
if (NewValue1==-1.0)
|
||
{iDrivigFlags&=~moveStopHere; //ma jechać
|
||
WaitingTime=0.0; //nie ma co dalej czekać, można zatrąbić i jechać
|
||
}
|
||
if (NewValue1<-1.5) //jeśli -2/-3, czyli czekanie z ruszeniem na sygnał
|
||
iDrivigFlags|=moveStopHere; //nie podjeżdżać do semafora, jeśli droga nie jest wolna (nie dotyczy Connect)
|
||
if (NewValue1<-2.5) //jeśli
|
||
OrderNext(Obey_train); //to potem jazda pociągowa
|
||
else
|
||
OrderNext(Shunt); //to potem manewruj dalej
|
||
CheckVehicles(); //sprawdzić światła
|
||
//if ((iVehicleCount>=0)&&(NewValue1<0)) WriteLog("Skasowano ilosć wagonów w Shunt!");
|
||
if (NewValue1!=iVehicleCount)
|
||
iVehicleCount=floor(NewValue1); //i co potem ? - trzeba zaprogramowac odczepianie
|
||
/*
|
||
if (NewValue1!=-1.0)
|
||
if (NewValue2!=0.0)
|
||
|
||
if (VelDesired==0)
|
||
SetVelocity(20,0); //to niech jedzie
|
||
*/
|
||
}
|
||
else if (NewCommand=="Jump_to_first_order")
|
||
JumpToFirstOrder();
|
||
else if (NewCommand=="Jump_to_order")
|
||
{
|
||
if (NewValue1==-1.0)
|
||
JumpToNextOrder();
|
||
else
|
||
if ((NewValue1>=0)&&(NewValue1<maxorders))
|
||
{OrderPos=floor(NewValue1);
|
||
if (!OrderPos) OrderPos=1; //zgodność wstecz: dopiero pierwsza uruchamia
|
||
#if LOGORDERS
|
||
WriteLog("--> Jump_to_order");
|
||
OrdersDump();
|
||
#endif
|
||
}
|
||
/*
|
||
if (WriteLogFlag)
|
||
{
|
||
append(AIlogFile);
|
||
writeln(AILogFile,ElapsedTime:5:2," - new order: ",Order2Str( OrderList[OrderPos])," @ ",OrderPos);
|
||
close(AILogFile);
|
||
}
|
||
*/
|
||
}
|
||
/* //ta komenda jest teraz skanowana, więc wysyłanie jej eventem nie ma sensu
|
||
else if (NewCommand=="OutsideStation") //wskaznik W5
|
||
{
|
||
if (OrderList[OrderPos]==Obey_train)
|
||
SetVelocity(NewValue1,NewValue2,stopOut); //koniec stacji - predkosc szlakowa
|
||
else //manewry - zawracaj
|
||
{
|
||
iDirectionOrder=-iDirection; //zmiana na przeciwny niż obecny
|
||
OrderNext(Change_direction); //zmiana kierunku
|
||
OrderNext(Shunt); //a dalej manewry
|
||
iDrivigFlags&=~moveStartHorn; //bez trąbienia po zatrzymaniu
|
||
}
|
||
}
|
||
*/
|
||
else if (NewCommand=="Warning_signal")
|
||
{
|
||
if (AIControllFlag) //poniższa komenda nie jest wykonywana przez użytkownika
|
||
if (NewValue1>0)
|
||
{
|
||
fWarningDuration=NewValue1; //czas trąbienia
|
||
mvOccupied->WarningSignal=(NewValue2>1)?2:1; //wysokość tonu
|
||
}
|
||
}
|
||
else if (NewCommand=="Radio_channel")
|
||
{//wybór kanału radiowego (którego powinien używać AI, ręczny maszynista musi go ustawić sam)
|
||
if (NewValue1>=0) //wartości ujemne są zarezerwowane, -1 = nie zmieniać kanału
|
||
{iRadioChannel=NewValue1;
|
||
if (iGuardRadio)
|
||
iGuardRadio=iRadioChannel; //kierownikowi też zmienić
|
||
}
|
||
//NewValue2 może zawierać dodatkowo oczekiwany kod odpowiedzi, np. dla W29 "nawiązać łączność radiową z dyżurnym ruchu odcinkowym"
|
||
}
|
||
else return false; //nierozpoznana - wysłać bezpośrednio do pojazdu
|
||
return true; //komenda została przetworzona
|
||
};
|
||
|
||
void __fastcall TController::PhysicsLog()
|
||
{//zapis logu - na razie tylko wypisanie parametrów
|
||
if (LogFile.is_open())
|
||
{
|
||
#if LOGPRESS==0
|
||
LogFile << ElapsedTime<<" "<<fabs(11.31*mvOccupied->WheelDiameter*mvOccupied->nrot)<<" ";
|
||
LogFile << mvControlling->AccS<<" "<<mvOccupied->Couplers[1].Dist<<" "<<mvOccupied->Couplers[1].CForce<<" ";
|
||
LogFile << mvOccupied->Ft<<" "<<mvOccupied->Ff<<" "<<mvOccupied->Fb<<" "<<mvOccupied->BrakePress<<" ";
|
||
LogFile << mvOccupied->PipePress<<" "<<mvControlling->Im<<" "<<int(mvControlling->MainCtrlPos)<<" ";
|
||
LogFile << int(mvControlling->ScndCtrlPos)<<" "<<int(mvOccupied->BrakeCtrlPos)<<" "<<int(mvOccupied->LocalBrakePos)<<" ";
|
||
LogFile << int(mvControlling->ActiveDir)<<" "<<mvOccupied->CommandIn.Command.c_str()<<" "<<mvOccupied->CommandIn.Value1<<" ";
|
||
LogFile << mvOccupied->CommandIn.Value2<<" "<<int(mvControlling->SecuritySystem.Status)<<" "<<int(mvControlling->SlippingWheels)<<"\r\n";
|
||
#endif
|
||
#if LOGPRESS==1
|
||
LogFile << ElapsedTime<<"\t"<<fabs(11.31*mvOccupied->WheelDiameter*mvOccupied->nrot)<<"\t";
|
||
LogFile << Controlling->AccS<<"\t";
|
||
LogFile << mvOccupied->PipePress<<"\t"<<mvOccupied->CntrlPipePress<<"\t"<<mvOccupied->BrakePress<<"\t";
|
||
LogFile << mvOccupied->Volume<<"\t"<<mvOccupied->Hamulec->GetCRP()<<"\n";
|
||
#endif
|
||
LogFile.flush();
|
||
}
|
||
};
|
||
|
||
bool __fastcall TController::UpdateSituation(double dt)
|
||
{//uruchamiać przynajmniej raz na sekundę
|
||
if ((iDrivigFlags&movePrimary)==0) return true; //pasywny nic nie robi
|
||
double AbsAccS;
|
||
//double VelReduced; //o ile km/h może przekroczyć dozwoloną prędkość bez hamowania
|
||
bool UpdateOK=false;
|
||
if (AIControllFlag)
|
||
{//yb: zeby EP nie musial sie bawic z ciesnieniem w PG
|
||
// if (mvOccupied->BrakeSystem==ElectroPneumatic)
|
||
// mvOccupied->PipePress=0.5; //yB: w SPKS są poprawnie zrobione pozycje
|
||
if (mvControlling->SlippingWheels)
|
||
{
|
||
mvControlling->SandDoseOn(); //piasku!
|
||
//Controlling->SlippingWheels=false; //a to tu nie ma sensu, flaga używana w dalszej części
|
||
}
|
||
}
|
||
//ABu-160305 testowanie gotowości do jazdy
|
||
//Ra: przeniesione z DynObj, skład użytkownika też jest testowany, żeby mu przekazać, że ma odhamować
|
||
Ready=true; //wstępnie gotowy
|
||
fReady=0.0; //założenie, że odhamowany
|
||
fAccGravity=0.0; //przyspieszenie wynikające z pochylenia
|
||
double dy; //składowa styczna grawitacji, w przedziale <0,1>
|
||
TDynamicObject *p=pVehicles[0]; //pojazd na czole składu
|
||
while (p)
|
||
{//sprawdzenie odhamowania wszystkich połączonych pojazdów
|
||
if (Ready) //bo jak coś nie odhamowane, to dalej nie ma co sprawdzać
|
||
//if (p->MoverParameters->BrakePress>=0.03*p->MoverParameters->MaxBrakePress)
|
||
if (p->MoverParameters->BrakePress>=0.4) //wg UIC określone sztywno na 0.04
|
||
{Ready=false; //nie gotowy
|
||
//Ra: odluźnianie przeładowanych lokomotyw, ciągniętych na zimno - prowizorka...
|
||
if (AIControllFlag) //skład jak dotąd był wyluzowany
|
||
{if (mvOccupied->BrakeCtrlPos==0) //jest pozycja jazdy
|
||
if ((p->MoverParameters->PipePress-5.0)>-0.1) //jeśli ciśnienie jak dla jazdy
|
||
if (p->MoverParameters->Hamulec->GetCRP()>p->MoverParameters->PipePress+0.12) //za dużo w zbiorniku
|
||
p->MoverParameters->BrakeReleaser(1); //indywidualne luzowanko
|
||
if (p->MoverParameters->Power>0.01) //jeśli ma silnik
|
||
if (p->MoverParameters->FuseFlag) //wywalony nadmiarowy
|
||
Need_TryAgain=true; //reset jak przy wywaleniu nadmiarowego
|
||
}
|
||
}
|
||
if (fReady<p->MoverParameters->BrakePress)
|
||
fReady=p->MoverParameters->BrakePress; //szukanie najbardziej zahamowanego
|
||
if ((dy=p->VectorFront().y)!=0.0) //istotne tylko dla pojazdów na pochyleniu
|
||
fAccGravity-=p->DirectionGet()*p->MoverParameters->TotalMassxg*dy; //ciężar razy składowa styczna grawitacji
|
||
p=p->Next(); //pojazd podłączony z tyłu (patrząc od czoła)
|
||
}
|
||
if (iDirection)
|
||
fAccGravity/=iDirection*fMass; //siłę generują pojazdy na pochyleniu ale działa ona całość składu, więc a=F/m
|
||
if (!Ready) //v367: jeśli wg powyższych warunków skład nie jest odhamowany
|
||
if (fAccGravity<-0.05) //jeśli ma pod górę na tyle, by się stoczyć
|
||
//if (mvOccupied->BrakePress<0.08) //to wystarczy, że zadziałają liniowe (nie ma ich jeszcze!!!)
|
||
if (fReady<0.8) //delikatniejszy warunek, obejmuje wszystkie wagony
|
||
Ready=true; //żeby uznać za odhamowany
|
||
HelpMeFlag=false;
|
||
//Winger 020304
|
||
if (AIControllFlag)
|
||
{
|
||
if (mvControlling->EnginePowerSource.SourceType==CurrentCollector)
|
||
{
|
||
if (mvOccupied->ScndPipePress>4.3) //gdy główna sprężarka bezpiecznie nabije ciśnienie
|
||
mvControlling->bPantKurek3=true; //to można przestawić kurek na zasilanie pantografów z głównej pneumatyki
|
||
fVoltage=0.5*(fVoltage+fabs(mvControlling->RunningTraction.TractionVoltage)); //uśrednione napięcie sieci: przy spadku poniżej wartości minimalnej opóźnić rozruch o losowy czas
|
||
if (fVoltage<mvControlling->EnginePowerSource.CollectorParameters.MinV) //gdy rozłączenie WS z powodu niskiego napięcia
|
||
if (fActionTime>=0) //jeśli czas oczekiwania nie został ustawiony
|
||
fActionTime=-2-random(10); //losowy czas oczekiwania przed ponownym załączeniem jazdy
|
||
}
|
||
if (mvOccupied->Vel>0.0)
|
||
{//jeżeli jedzie
|
||
if (iDrivigFlags&moveDoorOpened) //jeśli drzwi otwarte
|
||
if (mvOccupied->Vel>1.0) //nie zamykać drzwi przy drganiach, bo zatrzymanie na W4 akceptuje niewielkie prędkości
|
||
Doors(false);
|
||
//przy prowadzeniu samochodu trzeba każdą oś odsuwać oddzielnie, inaczej kicha wychodzi
|
||
if (mvOccupied->CategoryFlag&2) //jeśli samochód
|
||
//if (fabs(mvOccupied->OffsetTrackH)<mvOccupied->Dim.W) //Ra: szerokość drogi tu powinna być?
|
||
if (!mvOccupied->ChangeOffsetH(-0.01*mvOccupied->Vel*dt)) //ruch w poprzek drogi
|
||
mvOccupied->ChangeOffsetH(0.01*mvOccupied->Vel*dt); //Ra: co to miało być, to nie wiem
|
||
if (mvControlling->EnginePowerSource.SourceType==CurrentCollector)
|
||
{
|
||
if ((fOverhead2>=0.0)||iOverheadZero)
|
||
{//jeśli jazda bezprądowa albo z opuszczonym pantografem
|
||
while (DecSpeed(true)); //zerowanie napędu
|
||
}
|
||
if ((fOverhead2>0.0)||iOverheadDown)
|
||
{//jazda z opuszczonymi pantografami
|
||
mvControlling->PantFront(false);
|
||
mvControlling->PantRear(false);
|
||
}
|
||
else
|
||
{//jeśli nie trzeba opuszczać pantografów
|
||
if (iDirection>=0) //jak jedzie w kierunku sprzęgu 0
|
||
mvControlling->PantRear(true); //jazda na tylnym
|
||
else
|
||
mvControlling->PantFront(true);
|
||
}
|
||
if (mvOccupied->Vel>10) //opuszczenie przedniego po rozpędzeniu się
|
||
{
|
||
if (mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo>1) //o ile jest więcej niż jeden
|
||
if (iDirection>=0) //jak jedzie w kierunku sprzęgu 0
|
||
{//poczekać na podniesienie tylnego
|
||
if (mvControlling->PantRearVolt!=0.0) //czy jest napięcie zasilające na tylnym?
|
||
mvControlling->PantFront(false); //opuszcza od sprzęgu 0
|
||
}
|
||
else
|
||
{//poczekać na podniesienie przedniego
|
||
if (mvControlling->PantFrontVolt!=0.0) //czy jest napięcie zasilające na przednim?
|
||
mvControlling->PantRear(false); //opuszcza od sprzęgu 1
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (iDrivigFlags&moveStartHornNow) //czy ma zatrąbić przed ruszeniem?
|
||
if (Ready) //gotów do jazdy
|
||
if (iEngineActive) //jeszcze się odpalić musi
|
||
if (fStopTime>=0) //i nie musi czekać
|
||
{//uruchomienie trąbienia
|
||
fWarningDuration=0.3; //czas trąbienia
|
||
//if (AIControllFlag) //jak siedzi krasnoludek, to włączy trąbienie
|
||
mvOccupied->WarningSignal=pVehicle->iHornWarning; //wysokość tonu (2=wysoki)
|
||
iDrivigFlags|=moveStartHornDone; //nie trąbić aż do ruszenia
|
||
iDrivigFlags&=~moveStartHornNow; //trąbienie zostało zorganizowane
|
||
}
|
||
}
|
||
ElapsedTime+=dt;
|
||
WaitingTime+=dt;
|
||
fBrakeTime-=dt; //wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca
|
||
fStopTime+=dt; //zliczanie czasu postoju, nie ruszy dopóki ujemne
|
||
fActionTime+=dt; //czas używany przy regulacji prędkości i zamykaniu drzwi
|
||
if (WriteLogFlag)
|
||
{
|
||
if (LastUpdatedTime>deltalog)
|
||
{//zapis do pliku DAT
|
||
PhysicsLog();
|
||
if (fabs(mvOccupied->V)>0.1) //Ra: [m/s]
|
||
deltalog=0.05;//0.2;
|
||
else deltalog=0.05;//1.0;
|
||
LastUpdatedTime=0.0;
|
||
}
|
||
else
|
||
LastUpdatedTime=LastUpdatedTime+dt;
|
||
}
|
||
//Ra: skanowanie również dla prowadzonego ręcznie, aby podpowiedzieć prędkość
|
||
if ((LastReactionTime>Min0R(ReactionTime,2.0)))
|
||
{
|
||
//Ra: nie wiem czemu ReactionTime potrafi dostać 12 sekund, to jest przegięcie, bo przeżyna STÓJ
|
||
//yB: otóż jest to jedna trzecia czasu napełniania na towarowym; może się przydać przy wdrażaniu hamowania, żeby nie ruszało kranem jak głupie
|
||
//Ra: ale nie może się budzić co pół minuty, bo przeżyna semafory
|
||
//Ra: trzeba by tak:
|
||
// 1. Ustalić istotną odległość zainteresowania (np. 3×droga hamowania z V.max).
|
||
fBrakeDist=fDriverBraking*mvOccupied->Vel*(40.0+mvOccupied->Vel); //przybliżona droga hamowania
|
||
//dla hamowania -0.2 [m/ss] droga wynosi 0.389*Vel*Vel [km/h], czyli 600m dla 40km/h, 3.8km dla 100km/h i 9.8km dla 160km/h
|
||
//dla hamowania -0.4 [m/ss] droga wynosi 0.096*Vel*Vel [km/h], czyli 150m dla 40km/h, 1.0km dla 100km/h i 2.5km dla 160km/h
|
||
//ogólnie droga hamowania przy stałym opóźnieniu to Vel*Vel/(3.6*3.6*a) [m]
|
||
//fBrakeDist powinno być wyznaczane dla danego składu za pomocą sieci neuronowych, w zależności od prędkości i siły (ciśnienia) hamowania
|
||
//następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane zalecane ciśnienie
|
||
if (fMass>1000000.0) fBrakeDist*=2.0; //korekta dla ciężkich, bo przeżynają - da to coś?
|
||
if (mvOccupied->BrakeDelayFlag==bdelay_G) fBrakeDist=fBrakeDist+2*mvOccupied->Vel; //dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji
|
||
//double scanmax=(mvOccupied->Vel>0.0)?3*fDriverDist+fBrakeDist:10.0*fDriverDist;
|
||
double scanmax=(mvOccupied->Vel>5.0)?400+fBrakeDist:50.0*fDriverDist; //1000m dla stojących pociągów; Ra 2015-01: przy dłuższej drodze skanowania AI jeździ spokojniej
|
||
// 2. Sprawdzić, czy tabelka pokrywa założony odcinek (nie musi, jeśli jest STOP).
|
||
// 3. Sprawdzić, czy trajektoria ruchu przechodzi przez zwrotnice - jeśli tak, to sprawdzić, czy stan się nie zmienił.
|
||
// 4. Ewentualnie uzupełnić tabelkę informacjami o sygnałach i ograniczeniach, jeśli się "zużyła".
|
||
TableCheck(scanmax); //wypełnianie tabelki i aktualizacja odległości
|
||
// 5. Sprawdzić stany sygnalizacji zapisanej w tabelce, wyznaczyć prędkości.
|
||
// 6. Z tabelki wyznaczyć krytyczną odległość i prędkość (najmniejsze przyspieszenie).
|
||
// 7. Jeśli jest inny pojazd z przodu, ewentualnie skorygować odległość i prędkość.
|
||
// 8. Ustalić częstotliwość świadomości AI (zatrzymanie precyzyjne - częściej, brak atrakcji - rzadziej).
|
||
if (AIControllFlag)
|
||
{//tu bedzie logika sterowania
|
||
if (mvOccupied->CommandIn.Command!="")
|
||
if (!mvOccupied->RunInternalCommand()) //rozpoznaj komende bo lokomotywa jej nie rozpoznaje
|
||
RecognizeCommand(); //samo czyta komendę wstawioną do pojazdu?
|
||
if (mvOccupied->SecuritySystem.Status>1) //jak zadziałało CA/SHP
|
||
if (!mvOccupied->SecuritySystemReset()) //to skasuj
|
||
//if ((TestFlag(mvOccupied->SecuritySystem.Status,s_ebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0))
|
||
if ((TestFlag(mvOccupied->SecuritySystem.Status,s_SHPebrake)||TestFlag(mvOccupied->SecuritySystem.Status,s_CAebrake))&&(mvOccupied->BrakeCtrlPos==0)&&(AccDesired>0.0))
|
||
mvOccupied->BrakeLevelSet(0); //!!! hm, może po prostu normalnie sterować hamulcem?
|
||
}
|
||
switch (OrderList[OrderPos])
|
||
{//ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach
|
||
case Connect: //podłączanie do składu
|
||
if (iDrivigFlags&moveConnect)
|
||
{//jeśli stanął już blisko, unikając zderzenia i można próbować podłączyć
|
||
fMinProximityDist=-0.01; fMaxProximityDist=0.0; //[m] dojechać maksymalnie
|
||
fVelPlus=0.5; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=0.5; //margines prędkości powodujący załączenie napędu
|
||
if (AIControllFlag)
|
||
{//to robi tylko AI, wersję dla człowieka trzeba dopiero zrobić
|
||
//sprzęgi sprawdzamy w pierwszej kolejności, bo jak połączony, to koniec
|
||
bool ok; //true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym)
|
||
if (pVehicles[0]->DirectionGet()>0) //jeśli sprzęg 0
|
||
{//sprzęg 0 - próba podczepienia
|
||
if (pVehicles[0]->MoverParameters->Couplers[0].Connected) //jeśli jest coś wykryte (a chyba jest, nie?)
|
||
if (pVehicles[0]->MoverParameters->Attach(0,2,pVehicles[0]->MoverParameters->Couplers[0].Connected,iCoupler))
|
||
{
|
||
//pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX);
|
||
//pVehicles[0]->dsbCouplerAttach->Play(0,0,0);
|
||
}
|
||
//WriteLog("CoupleDist[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CoupleDist)+", Connected[0]="+AnsiString(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag));
|
||
ok=(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag==iCoupler); //udało się? (mogło częściowo)
|
||
}
|
||
else //if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1
|
||
{//sprzęg 1 - próba podczepienia
|
||
if (pVehicles[0]->MoverParameters->Couplers[1].Connected) //jeśli jest coś wykryte (a chyba jest, nie?)
|
||
if (pVehicles[0]->MoverParameters->Attach(1,2,pVehicles[0]->MoverParameters->Couplers[1].Connected,iCoupler))
|
||
{
|
||
//pVehicles[0]->dsbCouplerAttach->SetVolume(DSBVOLUME_MAX);
|
||
//pVehicles[0]->dsbCouplerAttach->Play(0,0,0);
|
||
}
|
||
//WriteLog("CoupleDist[1]="+AnsiString(Controlling->Couplers[1].CoupleDist)+", Connected[0]="+AnsiString(Controlling->Couplers[1].CouplingFlag));
|
||
ok=(pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag==iCoupler); //udało się? (mogło częściowo)
|
||
}
|
||
if (ok)
|
||
{//jeżeli został podłączony
|
||
iCoupler=0; //dalsza jazda manewrowa już bez łączenia
|
||
iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania
|
||
SetVelocity(0,0,stopJoin); //wyłączyć przyspieszanie
|
||
CheckVehicles(); //sprawdzić światła nowego składu
|
||
JumpToNextOrder(); //wykonanie następnej komendy
|
||
}
|
||
else
|
||
SetVelocity(2.0,0.0); //jazda w ustawionym kierunku z prędkością 2 (18s)
|
||
} //if (AIControllFlag) //koniec zblokowania, bo była zmienna lokalna
|
||
/* //Ra 2014-02: lepiej tam, bo jak tam się odźwieży skład, to tu pVehicles[0] będzie czymś innym
|
||
else
|
||
{//jeśli człowiek ma podłączyć, to czekamy na zmianę stanu sprzęgów na końcach dotychczasowego składu
|
||
bool ok; //true gdy się podłączy (uzyskany sprzęg będzie zgodny z żądanym)
|
||
if (pVehicles[0]->DirectionGet()>0) //jeśli sprzęg 0
|
||
ok=(pVehicles[0]->MoverParameters->Couplers[0].CouplingFlag>0); //==iCoupler); //udało się? (mogło częściowo)
|
||
else //if (pVehicles[0]->MoverParameters->DirAbsolute<0) //jeśli sprzęg 1
|
||
ok=(pVehicles[0]->MoverParameters->Couplers[1].CouplingFlag>0); //==iCoupler); //udało się? (mogło częściowo)
|
||
if (ok)
|
||
{//jeżeli został podłączony
|
||
iDrivigFlags&=~moveConnect; //zdjęcie flagi doczepiania
|
||
JumpToNextOrder(); //wykonanie następnej komendy
|
||
}
|
||
}
|
||
*/
|
||
}
|
||
else
|
||
{//jak daleko, to jazda jak dla Shunt na kolizję
|
||
fMinProximityDist=0.0; fMaxProximityDist=5.0; //[m] w takim przedziale odległości powinien stanąć
|
||
fVelPlus=2.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=1.0; //margines prędkości powodujący załączenie napędu
|
||
//VelReduced=5; //[km/h]
|
||
//if (mvOccupied->Vel<0.5) //jeśli już prawie stanął
|
||
if (pVehicles[0]->fTrackBlock<=20.0) //przy zderzeniu fTrackBlock nie jest miarodajne
|
||
iDrivigFlags|=moveConnect; //początek podczepiania, z wyłączeniem sprawdzania fTrackBlock
|
||
}
|
||
break;
|
||
case Disconnect: //20.07.03 - manewrowanie wagonami
|
||
fMinProximityDist=1.0; fMaxProximityDist=10.0; //[m]
|
||
fVelPlus=1.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=0.5; //margines prędkości powodujący załączenie napędu
|
||
if (AIControllFlag)
|
||
{if (iVehicleCount>=0) //jeśli była podana ilość wagonów
|
||
{
|
||
if (iDrivigFlags&movePress) //jeśli dociskanie w celu odczepienia
|
||
{//3. faza odczepiania.
|
||
SetVelocity(2,0); //jazda w ustawionym kierunku z prędkością 2
|
||
if ((mvControlling->MainCtrlPos>0)||(mvOccupied->BrakeSystem==ElectroPneumatic)) //jeśli jazda
|
||
{
|
||
//WriteLog("Odczepianie w kierunku "+AnsiString(mvOccupied->DirAbsolute));
|
||
TDynamicObject *p=pVehicle; //pojazd do odczepienia, w (pVehicle) siedzi AI
|
||
int d; //numer sprzęgu, który sprawdzamy albo odczepiamy
|
||
int n=iVehicleCount; //ile wagonów ma zostać
|
||
do
|
||
{//szukanie pojazdu do odczepienia
|
||
d=p->DirectionGet()>0?0:1; //numer sprzęgu od strony czoła składu
|
||
//if (p->MoverParameters->Couplers[d].CouplerType==Articulated) //jeśli sprzęg typu wózek (za mało)
|
||
if (p->MoverParameters->Couplers[d].CouplingFlag&ctrain_depot) //jeżeli sprzęg zablokowany
|
||
//if (p->GetTrack()->) //a nie stoi na torze warsztatowym (ustalić po czym poznać taki tor)
|
||
++n; //to liczymy człony jako jeden
|
||
p->MoverParameters->BrakeReleaser(1); //wyluzuj pojazd, aby dało się dopychać
|
||
p->MoverParameters->BrakeLevelSet(0); //hamulec na zero, aby nie hamował
|
||
if (n)
|
||
{//jeśli jeszcze nie koniec
|
||
p=p->Prev(); //kolejny w stronę czoła składu (licząc od tyłu), bo dociskamy
|
||
if (!p) iVehicleCount=-2,n=0; //nie ma co dalej sprawdzać, doczepianie zakończone
|
||
}
|
||
} while (n--);
|
||
if (p?p->MoverParameters->Couplers[d].CouplingFlag==0:true)
|
||
iVehicleCount=-2; //odczepiono, co było do odczepienia
|
||
else
|
||
if (!p->Dettach(d)) //zwraca maskę bitową połączenia; usuwa własność pojazdów
|
||
{//tylko jeśli odepnie
|
||
//WriteLog("Odczepiony od strony ");
|
||
iVehicleCount=-2;
|
||
} //a jak nie, to dociskać dalej
|
||
}
|
||
if (iVehicleCount>=0) //zmieni się po odczepieniu
|
||
if (!mvOccupied->DecLocalBrakeLevel(1))
|
||
{//dociśnij sklad
|
||
//WriteLog("Dociskanie");
|
||
//mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę
|
||
//Ready=true; //zamiast sprawdzenia odhamowania całego składu
|
||
IncSpeed(); //dla (Ready)==false nie ruszy
|
||
}
|
||
}
|
||
if ((mvOccupied->Vel==0.0)&&!(iDrivigFlags&movePress))
|
||
{//2. faza odczepiania: zmień kierunek na przeciwny i dociśnij
|
||
//za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach powino zostać wyłączone)
|
||
//WriteLog("Zahamowanie składu");
|
||
//while ((mvOccupied->BrakeCtrlPos>3)&&mvOccupied->DecBrakeLevel());
|
||
//while ((mvOccupied->BrakeCtrlPos<3)&&mvOccupied->IncBrakeLevel());
|
||
mvOccupied->BrakeLevelSet(mvOccupied->BrakeSystem==ElectroPneumatic?1:3);
|
||
double p=mvOccupied->BrakePressureActual.PipePressureVal; //tu może być 0 albo -1 nawet
|
||
if (p<3.9) p=3.9; //TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu
|
||
if (mvOccupied->BrakeSystem==ElectroPneumatic?mvOccupied->BrakePress>2:mvOccupied->PipePress<p+0.1)
|
||
{//jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na pozycji 3, zwyle 0.37)
|
||
if (mvOccupied->BrakeSystem==ElectroPneumatic)
|
||
mvOccupied->BrakeLevelSet(0); //wyłączenie EP, gdy wystarczy (może nie być potrzebne, bo na początku jest)
|
||
//WriteLog("Luzowanie lokomotywy i zmiana kierunku");
|
||
mvOccupied->BrakeReleaser(1); //wyluzuj lokomotywę; a ST45?
|
||
mvOccupied->DecLocalBrakeLevel(10); //zwolnienie hamulca
|
||
iDrivigFlags|=movePress; //następnie będzie dociskanie
|
||
DirectionForward(mvOccupied->ActiveDir<0); //zmiana kierunku jazdy na przeciwny (dociskanie)
|
||
CheckVehicles(); //od razu zmienić światła (zgasić) - bez tego się nie odczepi
|
||
fStopTime=0.0; //nie ma na co czekać z odczepianiem
|
||
}
|
||
}
|
||
} //odczepiania
|
||
else //to poniżej jeśli ilość wagonów ujemna
|
||
if (iDrivigFlags&movePress)
|
||
{//4. faza odczepiania: zwolnij i zmień kierunek
|
||
SetVelocity(0,0,stopJoin); //wyłączyć przyspieszanie
|
||
if (!DecSpeed()) //jeśli już bardziej wyłączyć się nie da
|
||
{//ponowna zmiana kierunku
|
||
//WriteLog("Ponowna zmiana kierunku");
|
||
DirectionForward(mvOccupied->ActiveDir<0); //zmiana kierunku jazdy na właściwy
|
||
iDrivigFlags&=~movePress; //koniec dociskania
|
||
JumpToNextOrder(); //zmieni światła
|
||
TableClear(); //skanowanie od nowa
|
||
iDrivigFlags&=~moveStartHorn; //bez trąbienia przed ruszeniem
|
||
SetVelocity(fShuntVelocity,fShuntVelocity); //ustawienie prędkości jazdy
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case Shunt:
|
||
//na jaką odleglość i z jaką predkością ma podjechać
|
||
fMinProximityDist=2.0; fMaxProximityDist=4.0; //[m]
|
||
fVelPlus=2.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=3.0; //margines prędkości powodujący załączenie napędu
|
||
if (fVelMinus>0.1*fShuntVelocity)
|
||
fVelMinus=0.1*fShuntVelocity; //były problemy z jazdą np. 3km/h podczas ładowania wagonów
|
||
break;
|
||
case Obey_train:
|
||
//na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody
|
||
if (mvOccupied->CategoryFlag&1) //jeśli pociąg
|
||
{
|
||
fMinProximityDist=10.0;
|
||
fMaxProximityDist=(mvOccupied->Vel>0.0)?20.0:50.0; //[m] jak stanie za daleko, to niech nie dociąga paru metrów
|
||
if (iDrivigFlags&moveLate)
|
||
{fVelMinus=1.0; //jeśli spóźniony, to gna
|
||
fVelPlus=5.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
}
|
||
else
|
||
{//gdy nie musi się sprężać
|
||
fVelMinus=int(0.05*VelDesired); //margines prędkości powodujący załączenie napędu
|
||
if (fVelMinus>5.0) fVelMinus=5.0;
|
||
else if (fVelMinus<1.0) fVelMinus=1.0; //żeby nie ruszał przy 0.1
|
||
fVelPlus=int(0.5+0.05*VelDesired); //normalnie dopuszczalne przekroczenie to 5% prędkości
|
||
if (fVelPlus>5.0) fVelPlus=5.0; //ale nie więcej niż 5km/h
|
||
}
|
||
}
|
||
else //samochod (sokista też)
|
||
{
|
||
fMinProximityDist=7.0; fMaxProximityDist=10.0; //[m]
|
||
fVelPlus=10.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=2.0; //margines prędkości powodujący załączenie napędu
|
||
}
|
||
//VelReduced=4; //[km/h]
|
||
break;
|
||
default:
|
||
fMinProximityDist=0.01; fMaxProximityDist=2.0; //[m]
|
||
fVelPlus=2.0; //dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania
|
||
fVelMinus=5.0; //margines prędkości powodujący załączenie napędu
|
||
} //switch
|
||
switch (OrderList[OrderPos])
|
||
{//co robi maszynista
|
||
case Prepare_engine: //odpala silnik
|
||
//if (AIControllFlag)
|
||
if (PrepareEngine()) //dla użytkownika tylko sprawdza, czy uruchomił
|
||
{//gotowy do drogi?
|
||
SetDriverPsyche();
|
||
//OrderList[OrderPos]:=Shunt; //Ra: to nie może tak być, bo scenerie robią Jump_to_first_order i przechodzi w manewrowy
|
||
JumpToNextOrder(); //w następnym jest Shunt albo Obey_train, moze też być Change_direction, Connect albo Disconnect
|
||
//if OrderList[OrderPos]<>Wait_for_Orders)
|
||
// if BrakeSystem=Pneumatic) //napelnianie uderzeniowe na wstepie
|
||
// if BrakeSubsystem=Oerlikon)
|
||
// if (BrakeCtrlPos=0))
|
||
// DecBrakeLevel;
|
||
}
|
||
break;
|
||
case Release_engine:
|
||
if (ReleaseEngine()) //zdana maszyna?
|
||
JumpToNextOrder();
|
||
break;
|
||
case Jump_to_first_order:
|
||
if (OrderPos>1)
|
||
OrderPos=1; //w zerowym zawsze jest czekanie
|
||
else
|
||
++OrderPos;
|
||
#if LOGORDERS
|
||
WriteLog("--> Jump_to_first_order");
|
||
OrdersDump();
|
||
#endif
|
||
break;
|
||
case Wait_for_orders: //jeśli czeka, też ma skanować, żeby odpalić się od semafora
|
||
/*
|
||
if ((mvOccupied->ActiveDir!=0))
|
||
{//jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy
|
||
VelDesired=fVelMax; //wstępnie prędkość maksymalna dla pojazdu(-ów), będzie następnie ograniczana
|
||
SetDriverPsyche(); //ustawia AccPreferred (potrzebne tu?)
|
||
//Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci
|
||
AccDesired=AccPreferred; //AccPreferred wynika z osobowości mechanika
|
||
VelNext=VelDesired; //maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu
|
||
ActualProximityDist=scanmax; //funkcja Update() może pozostawić wartości bez zmian
|
||
//hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak VelSignal - a teraz jak to zrobić?
|
||
TCommandType comm=TableUpdate(mvOccupied->Vel,VelDesired,ActualProximityDist,VelNext,AccDesired); //szukanie optymalnych wartości
|
||
}
|
||
*/
|
||
//break;
|
||
case Shunt:
|
||
case Obey_train:
|
||
case Connect:
|
||
case Disconnect:
|
||
case Change_direction: //tryby wymagające jazdy
|
||
case Change_direction|Shunt: //zmiana kierunku podczas manewrów
|
||
case Change_direction|Connect: //zmiana kierunku podczas podłączania
|
||
if (OrderList[OrderPos]!=Obey_train) //spokojne manewry
|
||
{
|
||
VelSignal=Min0R(VelSignal,40); //jeśli manewry, to ograniczamy prędkość
|
||
if (AIControllFlag)
|
||
{//to poniżej tylko dla AI
|
||
if (iVehicleCount>=0) //jeśli jest co odczepić
|
||
if (!(iDrivigFlags&movePress))
|
||
if (mvOccupied->Vel>0.0)
|
||
if (!iCoupler) //jeśli nie ma wcześniej potrzeby podczepienia
|
||
{SetVelocity(0,0,stopJoin); //1. faza odczepiania: zatrzymanie
|
||
//WriteLog("Zatrzymanie w celu odczepienia");
|
||
}
|
||
}
|
||
}
|
||
else
|
||
SetDriverPsyche(); //Ra: było w PrepareEngine(), potrzebne tu?
|
||
//no albo przypisujemy -WaitingExpireTime, albo porównujemy z WaitingExpireTime
|
||
//if ((VelSignal==0.0)&&(WaitingTime>WaitingExpireTime)&&(mvOccupied->RunningTrack.Velmax!=0.0))
|
||
if (OrderList[OrderPos]&(Shunt|Obey_train|Connect)) //odjechać sam może tylko jeśli jest w trybie jazdy
|
||
{//automatyczne ruszanie po odstaniu albo spod SBL
|
||
if ((VelSignal==0.0)&&(WaitingTime>0.0)&&(mvOccupied->RunningTrack.Velmax!=0.0))
|
||
{//jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość
|
||
/*
|
||
if (WriteLogFlag)
|
||
{
|
||
append(AIlogFile);
|
||
writeln(AILogFile,ElapsedTime:5:2,": ",Name," V=0 waiting time expired! (",WaitingTime:4:1,")");
|
||
close(AILogFile);
|
||
}
|
||
*/
|
||
if ((OrderList[OrderPos]&(Obey_train|Shunt))?(iDrivigFlags&moveStopHere):false)
|
||
WaitingTime=-WaitingExpireTime; //zakaz ruszania z miejsca bez otrzymania wolnej drogi
|
||
else if (mvOccupied->CategoryFlag&1)
|
||
{//jeśli pociąg
|
||
if (AIControllFlag)
|
||
{PrepareEngine(); //zmieni ustawiony kierunek
|
||
SetVelocity(20,20); //jak się nastał, to niech jedzie 20km/h
|
||
WaitingTime=0.0;
|
||
fWarningDuration=1.5; //a zatrąbić trochę
|
||
mvOccupied->WarningSignal=1;
|
||
}
|
||
else
|
||
SetVelocity(20,20); //użytkownikowi zezwalamy jechać
|
||
}
|
||
else
|
||
{//samochód ma stać, aż dostanie odjazd, chyba że stoi przez kolizję
|
||
if (eStopReason==stopBlock)
|
||
if (pVehicles[0]->fTrackBlock>fDriverDist)
|
||
if (AIControllFlag)
|
||
{PrepareEngine(); //zmieni ustawiony kierunek
|
||
SetVelocity(-1,-1); //jak się nastał, to niech jedzie
|
||
WaitingTime=0.0;
|
||
}
|
||
else
|
||
SetVelocity(-1,-1); //użytkownikowi pozwalamy jechać (samochodem?)
|
||
}
|
||
}
|
||
else if ((VelSignal==0.0)&&(VelNext>0.0)&&(mvOccupied->Vel<1.0))
|
||
if (iCoupler?true:(iDrivigFlags&moveStopHere)==0) //Ra: tu jest coś nie tak, bo bez tego warunku ruszało w manewrowym !!!!
|
||
SetVelocity(VelNext,VelNext,stopSem); //omijanie SBL
|
||
} //koniec samoistnego odjeżdżania
|
||
if (AIControllFlag)
|
||
if ((HelpMeFlag)||(mvControlling->DamageFlag>0))
|
||
{
|
||
HelpMeFlag=false;
|
||
/*
|
||
if (WriteLogFlag)
|
||
with Controlling do
|
||
{
|
||
append(AIlogFile);
|
||
writeln(AILogFile,ElapsedTime:5:2,": ",Name," HelpMe! (",DamageFlag,")");
|
||
close(AILogFile);
|
||
}
|
||
*/
|
||
}
|
||
if (AIControllFlag)
|
||
if (OrderList[OrderPos]&Change_direction) //może być zmieszane z jeszcze jakąś komendą
|
||
{//sprobuj zmienic kierunek
|
||
SetVelocity(0,0,stopDir); //najpierw trzeba się zatrzymać
|
||
if (mvOccupied->Vel<0.1)
|
||
{//jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon
|
||
Activation(); //ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI
|
||
PrepareEngine();
|
||
JumpToNextOrder(); //następnie robimy, co jest do zrobienia (Shunt albo Obey_train)
|
||
if (OrderList[OrderPos]&(Shunt|Connect)) //jeśli dalej mamy manewry
|
||
if ((iDrivigFlags&moveStopHere)==0) //o ile nie stać w miejscu
|
||
{//jechać od razu w przeciwną stronę i nie trąbić z tego tytułu
|
||
iDrivigFlags&=~moveStartHorn; //bez trąbienia przed ruszeniem
|
||
SetVelocity(fShuntVelocity,fShuntVelocity); //to od razu jedziemy
|
||
}
|
||
//iDrivigFlags|=moveStartHorn; //a później już można trąbić
|
||
/*
|
||
if (WriteLogFlag)
|
||
{
|
||
append(AIlogFile);
|
||
writeln(AILogFile,ElapsedTime:5:2,": ",Name," Direction changed!");
|
||
close(AILogFile);
|
||
}
|
||
*/
|
||
}
|
||
//else
|
||
// VelSignal:=0.0; //na wszelki wypadek niech zahamuje
|
||
} //Change_direction (tylko dla AI)
|
||
//ustalanie zadanej predkosci
|
||
if (AIControllFlag) //jeśli prowadzi AI
|
||
if (!iEngineActive) //jeśli silnik nie odpalony, to próbować naprawić
|
||
if (OrderList[OrderPos]&(Change_direction|Connect|Disconnect|Shunt|Obey_train)) //jeśli coś ma robić
|
||
PrepareEngine(); //to niech odpala do skutku
|
||
if (iDrivigFlags&moveActive) //jeśli może skanować sygnały i reagować na komendy
|
||
{//jeśli jest wybrany kierunek jazdy, można ustalić prędkość jazdy
|
||
//Ra: tu by jeszcze trzeba było wstawić uzależnienie (VelDesired) od odległości od przeszkody
|
||
// no chyba żeby to uwzgldnić już w (ActualProximityDist)
|
||
VelDesired=fVelMax; //wstępnie prędkość maksymalna dla pojazdu(-ów), będzie następnie ograniczana
|
||
if (TrainParams) //jeśli ma rozkład
|
||
if (TrainParams->TTVmax>0.0) //i ograniczenie w rozkładzie
|
||
VelDesired=Min0R(VelDesired,TrainParams->TTVmax); //to nie przekraczać rozkladowej
|
||
SetDriverPsyche(); //ustawia AccPreferred (potrzebne tu?)
|
||
//Ra: odczyt (ActualProximityDist), (VelNext) i (AccPreferred) z tabelki prędkosci
|
||
AccDesired=AccPreferred; //AccPreferred wynika z osobowości mechanika
|
||
VelNext=VelDesired; //maksymalna prędkość wynikająca z innych czynników niż trajektoria ruchu
|
||
ActualProximityDist=scanmax; //funkcja Update() może pozostawić wartości bez zmian
|
||
//hm, kiedyś semafory wysyłały SetVelocity albo ShuntVelocity i ustawły tak VelSignal - a teraz jak to zrobić?
|
||
TCommandType comm=TableUpdate(VelDesired,ActualProximityDist,VelNext,AccDesired); //szukanie optymalnych wartości
|
||
//if (VelSignal!=VelDesired) //jeżeli prędkość zalecana jest inna (ale tryb też może być inny)
|
||
switch (comm)
|
||
{//ustawienie VelSignal - trochę proteza = do przemyślenia
|
||
case cm_Ready: //W4 zezwolił na jazdę
|
||
TableCheck(scanmax); //ewentualne doskanowanie trasy za W4, który zezwolił na jazdę
|
||
TableUpdate(VelDesired,ActualProximityDist,VelNext,AccDesired); //aktualizacja po skanowaniu
|
||
//if (comm!=cm_SetVelocity) //jeśli dalej jest kolejny W4, to ma zwrócić cm_SetVelocity
|
||
if (VelNext==0.0) break; //ale jak coś z przodu zamyka, to ma stać
|
||
if (iDrivigFlags&moveStopCloser)
|
||
VelSignal=VelDesired; //niech jedzie, jak W4 puściło - nie, ma czekać na sygnał z sygnalizatora!
|
||
case cm_SetVelocity: //od wersji 357 semafor nie budzi wyłączonej lokomotywy
|
||
if (!(OrderList[OrderPos]&~(Obey_train|Shunt))) //jedzie w dowolnym trybie albo Wait_for_orders
|
||
if (fabs(VelSignal)>=1.0) //0.1 nie wysyła się do samochodow, bo potem nie ruszą
|
||
PutCommand("SetVelocity",VelSignal,VelNext,NULL); //komenda robi dodatkowe operacje
|
||
break;
|
||
case cm_ShuntVelocity: //od wersji 357 Tm nie budzi wyłączonej lokomotywy
|
||
if (!(OrderList[OrderPos]&~(Obey_train|Shunt))) //jedzie w dowolnym trybie albo Wait_for_orders
|
||
PutCommand("ShuntVelocity",VelSignal,VelNext,NULL);
|
||
else if (iCoupler) //jeśli jedzie w celu połączenia
|
||
SetVelocity(VelSignal,VelNext);
|
||
break;
|
||
case cm_Command: //komenda z komórki
|
||
if (!(OrderList[OrderPos]&~(Obey_train|Shunt))) //jedzie w dowolnym trybie albo Wait_for_orders
|
||
if (mvOccupied->Vel<0.1) //dopiero jak stanie
|
||
//iDrivigFlags|=moveStopHere moveStopCloser) //chyba że stanął za daleko (SU46 w WK staje za daleko)
|
||
{PutCommand(eSignNext->CommandGet(),eSignNext->ValueGet(1),eSignNext->ValueGet(2),NULL);
|
||
eSignNext->StopCommandSent(); //się wykonało już
|
||
}
|
||
break;
|
||
}
|
||
if (VelNext==0.0)
|
||
if (!(OrderList[OrderPos]&~(Shunt|Connect))) //jedzie w Shunt albo Connect, albo Wait_for_orders
|
||
{//jeżeli wolnej drogi nie ma, a jest w trybie manewrowym albo oczekiwania
|
||
//if ((OrderList[OrderPos]&Connect)?pVehicles[0]->fTrackBlock>ActualProximityDist:true) //pomiar odległości nie działa dobrze?
|
||
//w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie ma taboru do podłączenia
|
||
//Ra 2F1H: z tym (fTrackBlock) to nie jest najlepszy pomysł, bo lepiej by było porównać z odległością od sygnalizatora z przodu
|
||
if ((OrderList[OrderPos]|Connect)?pVehicles[0]->fTrackBlock>2000:true)
|
||
if ((comm=BackwardScan())!=cm_Unknown) //jeśli w drugą można jechać
|
||
{//należy sprawdzać odległość od znalezionego sygnalizatora,
|
||
//aby w przypadku prędkości 0.1 wyciągnąć najpierw skład za sygnalizator
|
||
//i dopiero wtedy zmienić kierunek jazdy, oczekując podania prędkości >0.5
|
||
if (comm==cm_Command) //jeśli komenda Shunt
|
||
iDrivigFlags|=moveStopHere; //to ją odbierz bez przemieszczania się (np. odczep wagony po dopchnięciu do końca toru)
|
||
iDirectionOrder=-iDirection; //zmiana kierunku jazdy
|
||
OrderList[OrderPos]=TOrders(OrderList[OrderPos]|Change_direction); //zmiana kierunku bez psucia kolejnych komend
|
||
}
|
||
}
|
||
double vel=mvOccupied->Vel; //prędkość w kierunku jazdy
|
||
if (iDirection*mvOccupied->V<0) vel=-vel; //ujemna, gdy jedzie w przeciwną stronę, niż powinien
|
||
if (VelDesired<0.0) VelDesired=fVelMax; //bo VelDesired<0 oznacza prędkość maksymalną
|
||
//Ra: jazda na widoczność
|
||
if (pVehicles[0]->fTrackBlock<1000.0) //przy 300m stał z zapamiętaną kolizją
|
||
{//Ra 2F3F: przy jeździe pociągowej nie powinien dojeżdżać do poprzedzającego składu
|
||
if ((mvOccupied->CategoryFlag&1)?((OrderCurrentGet()&(Connect|Obey_train))==Obey_train):false) //jeśli jesteśmy pociągiem a jazda pociągowa i nie ściąganie ze szlaku
|
||
{pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(),1000.0); //skanowanie sprawdzające
|
||
//Ra 2F3F: i jest problem, jak droga za semaforem kieruje na jakiś pojazd (np. w Skwarkach na ET22)
|
||
if (pVehicles[0]->fTrackBlock<1000.0) //i jeśli nadal coś jest
|
||
if (VelNext!=0.0) //a następny sygnał zezwala na jazdę
|
||
if (pVehicles[0]->fTrackBlock<ActualProximityDist) //i jest bliżej (tu by trzeba było wstawić odległość do semafora, z pominięciem SBL
|
||
VelDesired=0.0; //to stoimy
|
||
}
|
||
else
|
||
pVehicles[0]->ABuScanObjects(pVehicles[0]->DirectionGet(),300.0); //skanowanie sprawdzające
|
||
}
|
||
//if (mvOccupied->Vel>=0.1) //o ile jedziemy; jak stoimy to też trzeba jakoś zatrzymywać
|
||
if ((iDrivigFlags&moveConnect)==0) //przy końcówce podłączania nie hamować
|
||
{//sprawdzenie jazdy na widoczność
|
||
TCoupling *c=pVehicles[0]->MoverParameters->Couplers+(pVehicles[0]->DirectionGet()>0?0:1); //sprzęg z przodu składu
|
||
if (c->Connected) //a mamy coś z przodu
|
||
if (c->CouplingFlag==0) //jeśli to coś jest podłączone sprzęgiem wirtualnym
|
||
{//wyliczanie optymalnego przyspieszenia do jazdy na widoczność
|
||
double k=c->Connected->Vel; //prędkość pojazdu z przodu (zakładając, że jedzie w tę samą stronę!!!)
|
||
if (k<vel+10) //porównanie modułów prędkości [km/h]
|
||
{//zatroszczyć się trzeba, jeśli tamten nie jedzie znacząco szybciej
|
||
double d=pVehicles[0]->fTrackBlock-0.5*vel-fMaxProximityDist; //odległość bezpieczna zależy od prędkości
|
||
if (d<0) //jeśli odległość jest zbyt mała
|
||
{//AccPreferred=-0.9; //hamowanie maksymalne, bo jest za blisko
|
||
if (k<10.0) //k - prędkość tego z przodu
|
||
{//jeśli tamten porusza się z niewielką prędkością albo stoi
|
||
if (OrderCurrentGet()&Connect)
|
||
{//jeśli spinanie, to jechać dalej
|
||
AccPreferred=0.2; //nie hamuj
|
||
VelNext=VelDesired=2.0; //i pakuj się na tamtego
|
||
}
|
||
else //a normalnie to hamować
|
||
{AccPreferred=-1.0; //to hamuj maksymalnie
|
||
VelNext=VelDesired=0.0; //i nie pakuj się na tamtego
|
||
}
|
||
}
|
||
else //jeśli oba jadą, to przyhamuj lekko i ogranicz prędkość
|
||
{if (k<vel) //jak tamten jedzie wolniej
|
||
if (d<fBrakeDist) //a jest w drodze hamowania
|
||
{if (AccPreferred>fAccThreshold) AccPreferred=fAccThreshold; //to przyhamuj troszkę
|
||
VelNext=VelDesired=int(k); //to chyba już sobie dohamuje według uznania
|
||
}
|
||
}
|
||
ReactionTime=0.1; //orientuj się, bo jest goraco
|
||
}
|
||
else
|
||
{//jeśli odległość jest większa, ustalić maksymalne możliwe przyspieszenie (hamowanie)
|
||
k=(k*k-vel*vel)/(25.92*d); //energia kinetyczna dzielona przez masę i drogę daje przyspieszenie
|
||
if (k>0.0) k*=1.5; //jedź szybciej, jeśli możesz
|
||
//double ak=(c->Connected->V>0?1.0:-1.0)*c->Connected->AccS; //przyspieszenie tamtego
|
||
if (d<fBrakeDist) //a jest w drodze hamowania
|
||
if (k<AccPreferred)
|
||
{//jeśli nie ma innych powodów do wolniejszej jazdy
|
||
AccPreferred=k;
|
||
if (VelNext>c->Connected->Vel)
|
||
{VelNext=c->Connected->Vel; //ograniczenie do prędkości tamtego
|
||
ActualProximityDist=d; //i odległość od tamtego jest istotniejsza
|
||
}
|
||
ReactionTime=0.2; //zwiększ czujność
|
||
}
|
||
#if LOGVELOCITY
|
||
WriteLog("Collision: AccPreferred="+AnsiString(k));
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//sprawdzamy możliwe ograniczenia prędkości
|
||
if (OrderCurrentGet()&(Shunt|Obey_train)) //w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu
|
||
if (iDrivigFlags&moveStopHere) //jeśli ma czekać na wolną drogę
|
||
if (vel==0.0) //a stoi
|
||
if (VelNext==0.0) //a wyjazdu nie ma
|
||
VelDesired=0.0; //to ma stać
|
||
if (fStopTime<0) //czas postoju przed dalszą jazdą (np. na przystanku)
|
||
VelDesired=0.0; //jak ma czekać, to nie ma jazdy
|
||
//else if (VelSignal<0)
|
||
//VelDesired=fVelMax; //ile fabryka dala (Ra: uwzględione wagony)
|
||
else
|
||
if (VelSignal>=0) //VelSignal>0 jest ograniczeniem prędkości (z semafora)
|
||
VelDesired=Min0R(VelDesired,VelSignal);
|
||
if (mvOccupied->RunningTrack.Velmax>=0) //ograniczenie prędkości z trajektorii ruchu
|
||
VelDesired=Min0R(VelDesired,mvOccupied->RunningTrack.Velmax); //uwaga na ograniczenia szlakowej!
|
||
if (VelforDriver>=0) //tu jest zero przy zmianie kierunku jazdy
|
||
VelDesired=Min0R(VelDesired,VelforDriver); //Ra: tu może być 40, jeśli mechanik nie ma znajomości szlaaku, albo kierowca jeździ 70
|
||
if (TrainParams)
|
||
if (TrainParams->CheckTrainLatency()<5.0)
|
||
if (TrainParams->TTVmax>0.0)
|
||
VelDesired=Min0R(VelDesired,TrainParams->TTVmax); //jesli nie spozniony to nie przekraczać rozkladowej
|
||
if (VelDesired>0.0)
|
||
if (VelNext>0.0)
|
||
{//jeśli można jechać, to odpalić dźwięk kierownika oraz zamknąć drzwi w składzie
|
||
if (iDrivigFlags&moveGuardSignal)
|
||
{//komunikat od kierownika tu, bo musi być wolna droga i odczekany czas stania
|
||
iDrivigFlags&=~moveGuardSignal; //tylko raz nadać
|
||
tsGuardSignal->Stop();
|
||
//w zasadzie to powinien mieć flagę, czy jest dźwiękiem radiowym, czy bezpośrednim
|
||
//albo trzeba zrobić dwa dźwięki, jeden bezpośredni, słyszalny w pobliżu, a drugi radiowy, słyszalny w innych lokomotywach
|
||
//na razie zakładam, że to nie jest dźwięk radiowy, bo trzeba by zrobić obsługę kanałów radiowych itd.
|
||
if (!iGuardRadio) //jeśli nie przez radio
|
||
tsGuardSignal->Play(1.0,0,!FreeFlyModeFlag,pVehicle->GetPosition()); //dla true jest głośniej
|
||
else
|
||
//if (iGuardRadio==iRadioChannel) //zgodność kanału
|
||
//if (!FreeFlyModeFlag) //obserwator musi być w środku pojazdu (albo może mieć radio przenośne) - kierownik mógłby powtarzać przy braku reakcji
|
||
if (SquareMagnitude(pVehicle->GetPosition()-Global::pCameraPosition)<2000*2000) //w odległości mniejszej niż 2km
|
||
tsGuardSignal->Play(1.0,0,true,pVehicle->GetPosition()); //dźwięk niby przez radio
|
||
}
|
||
if (iDrivigFlags&moveDoorOpened) //jeśli drzwi otwarte
|
||
if (!mvOccupied->DoorOpenCtrl) //jeśli drzwi niesterowane przez maszynistę
|
||
Doors(false); //a EZT zamknie dopiero po odegraniu komunikatu kierownika
|
||
}
|
||
if (mvOccupied->V==0.0) AbsAccS=fAccGravity; //Ra 2014-03: jesli skład stoi, to działa na niego składowa styczna grawitacji
|
||
else AbsAccS=iDirection*mvOccupied->AccS; //przyspieszenie chwilowe, liczone jako różnica skierowanej prędkości w czasie
|
||
//if (mvOccupied->V<0.0) AbsAccS=-AbsAccS; //Ra 2014-03: to trzeba przemyśleć
|
||
//if (vel<0) //jeżeli się stacza w tył; 2014-03: to jest bez sensu, bo vel>=0
|
||
// AbsAccS=-AbsAccS; //to przyspieszenie też działa wtedy w nieodpowiednią stronę
|
||
//AbsAccS+=fAccGravity; //wypadkowe przyspieszenie (czy to ma sens?)
|
||
#if LOGVELOCITY
|
||
//WriteLog("VelDesired="+AnsiString(VelDesired)+", VelSignal="+AnsiString(VelSignal));
|
||
WriteLog("Vel="+AnsiString(vel)+", AbsAccS="+AnsiString(AbsAccS)+", AccGrav="+AnsiString(fAccGravity));
|
||
#endif
|
||
//ustalanie zadanego przyspieszenia
|
||
//(ActualProximityDist) - odległość do miejsca zmniejszenia prędkości
|
||
//(AccPreferred) - wynika z psychyki oraz uwzglęnia już ewentualne zderzenie z pojazdem z przodu, ujemne gdy należy hamować
|
||
//(AccDesired) - uwzględnia sygnały na drodze ruchu, ujemne gdy należy hamować
|
||
//(fAccGravity) - chwilowe przspieszenie grawitacyjne, ujemne działa przeciwnie do zadanego kierunku jazdy
|
||
//(AbsAccS) - chwilowe przyspieszenie pojazu (uwzględnia grawitację), ujemne działa przeciwnie do zadanego kierunku jazdy
|
||
//(AccDesired) porównujemy z (fAccGravity) albo (AbsAccS)
|
||
//if ((VelNext>=0.0)&&(ActualProximityDist>=0)&&(mvOccupied->Vel>=VelNext)) //gdy zbliza sie i jest za szybko do NOWEGO
|
||
if ((VelNext>=0.0)&&(ActualProximityDist<=scanmax)&&(vel>=VelNext))
|
||
{//gdy zbliża się i jest za szybki do nowej prędkości, albo stoi na zatrzymaniu
|
||
if (vel>0.0)
|
||
{//jeśli jedzie
|
||
if ((vel<VelNext)?(ActualProximityDist>fMaxProximityDist*(1+0.1*vel)):false) //dojedz do semafora/przeszkody
|
||
{//jeśli jedzie wolniej niż można i jest wystarczająco daleko, to można przyspieszyć
|
||
if (AccPreferred>0.0) //jeśli nie ma zawalidrogi
|
||
AccDesired=AccPreferred;
|
||
//VelDesired:=Min0R(VelDesired,VelReduced+VelNext);
|
||
}
|
||
else if (ActualProximityDist>fMinProximityDist)
|
||
{//jedzie szybciej, niż trzeba na końcu ActualProximityDist, ale jeszcze jest daleko
|
||
if (vel<VelNext+40.0) //dwustopniowe hamowanie - niski przy małej różnicy
|
||
{//jeśli jedzie wolniej niż VelNext+35km/h //Ra: 40, żeby nie kombinował na zwrotnicach
|
||
if (VelNext==0.0)
|
||
{//jeśli ma się zatrzymać, musi być to robione precyzyjnie i skutecznie
|
||
if (ActualProximityDist<fMaxProximityDist) //jak minął już maksymalny dystans
|
||
{//po prostu hamuj (niski stopień) //ma stanąć, a jest w drodze hamowania albo ma jechać
|
||
AccDesired=fAccThreshold; //hamowanie tak, aby stanąć
|
||
VelDesired=0.0; //Min0R(VelDesired,VelNext);
|
||
}
|
||
else if (ActualProximityDist>fBrakeDist)
|
||
{//jeśli ma stanąć, a mieści się w drodze hamowania
|
||
if (vel<10.0) //jeśli prędkość jest łatwa do zatrzymania
|
||
{//tu jest trochę problem, bo do punktu zatrzymania dobija na raty
|
||
//AccDesired=AccDesired<0.0?0.0:0.1*AccPreferred;
|
||
AccDesired=AccPreferred; //proteza trochę; jak tu wychodzi 0.05, to loki mają problem utrzymać takie przyspieszenie
|
||
}
|
||
else if (vel<=30.0) //trzymaj 30 km/h
|
||
AccDesired=Min0R(0.5*AccDesired,AccPreferred); //jak jest tu 0.5, to samochody się dobijają do siebie
|
||
else
|
||
AccDesired=0.0;
|
||
}
|
||
else //25.92 (=3.6*3.6*2) - przelicznik z km/h na m/s
|
||
if (vel<VelNext+fVelPlus) //jeśli niewielkie przekroczenie
|
||
//AccDesired=0.0;
|
||
AccDesired=Min0R(0.0,AccPreferred); //proteza trochę: to niech nie hamuje, chyba że coś z przodu
|
||
else
|
||
AccDesired=-(vel*vel)/(25.92*(ActualProximityDist+0.1));//-fMinProximityDist));//-0.1; //mniejsze opóźnienie przy małej różnicy
|
||
ReactionTime=0.1; //i orientuj się szybciej, jak masz stanąć
|
||
}
|
||
else if (vel<VelNext+fVelPlus) //jeśli niewielkie przekroczenie, ale ma jechać
|
||
AccDesired=Min0R(0.0,AccPreferred); //to olej (zacznij luzować)
|
||
else
|
||
{//jeśli większe przekroczenie niż fVelPlus [km/h], ale ma jechać
|
||
//Ra 2F1I: jak było (VelNext+fVelPlus) tu, to hamował zbyt późno przed 40, a potem zbyt mocno i zwalniał do 30
|
||
AccDesired=(VelNext*VelNext-vel*vel)/(25.92*ActualProximityDist+0.1); //mniejsze opóźnienie przy małej różnicy
|
||
if (ActualProximityDist<fMaxProximityDist)
|
||
ReactionTime=0.1; //i orientuj się szybciej, jeśli w krytycznym przedziale
|
||
}
|
||
}
|
||
else //przy dużej różnicy wysoki stopień (1,25 potrzebnego opoznienia)
|
||
AccDesired=(VelNext*VelNext-vel*vel)/(20.73*ActualProximityDist+0.1); //najpierw hamuje mocniej, potem zluzuje
|
||
if (AccPreferred<AccDesired)
|
||
AccDesired=AccPreferred; //(1+abs(AccDesired))
|
||
//ReactionTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia hamulcow
|
||
//fBrakeTime=0.5*mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]; //aby szybkosc hamowania zalezala od przyspieszenia i opoznienia hamulcow
|
||
}
|
||
else
|
||
{//jest bliżej niż fMinProximityDist
|
||
VelDesired=Min0R(VelDesired,VelNext); //utrzymuj predkosc bo juz blisko
|
||
if (vel<VelNext+fVelPlus) //jeśli niewielkie przekroczenie, ale ma jechać
|
||
AccDesired=Min0R(0.0,AccPreferred); //to olej (zacznij luzować)
|
||
ReactionTime=0.1; //i orientuj się szybciej
|
||
}
|
||
}
|
||
else //zatrzymany (vel==0.0)
|
||
//if (iDrivigFlags&moveStopHere) //to nie dotyczy podczepiania
|
||
//if ((VelNext>0.0)||(ActualProximityDist>fMaxProximityDist*1.2))
|
||
if (VelNext>0.0)
|
||
AccDesired=AccPreferred; //można jechać
|
||
else //jeśli daleko jechać nie można
|
||
if (ActualProximityDist>fMaxProximityDist) //ale ma kawałek do sygnalizatora
|
||
{//if ((iDrivigFlags&moveStopHere)?false:AccPreferred>0)
|
||
if (AccPreferred>0)
|
||
AccDesired=AccPreferred; //dociagnij do semafora;
|
||
else
|
||
VelDesired=0.0;//,AccDesired=-fabs(fAccGravity); //stoj (hamuj z siłą równą składowej stycznej grawitacji)
|
||
}
|
||
else
|
||
VelDesired=0.0; //VelNext=0 i stoi bliżej niż fMaxProximityDist
|
||
}
|
||
else //gdy jedzie wolniej niż potrzeba, albo nie ma przeszkód na drodze
|
||
AccDesired=(VelDesired!=0.0?AccPreferred:-0.01); //normalna jazda
|
||
//koniec predkosci nastepnej
|
||
if ((VelDesired>=0.0)&&(vel>VelDesired)) //jesli jedzie za szybko do AKTUALNEGO
|
||
if (VelDesired==0.0) //jesli stoj, to hamuj, ale i tak juz za pozno :)
|
||
AccDesired=-0.9; //hamuj solidnie
|
||
else
|
||
if ((vel<VelDesired+fVelPlus)) //o 5 km/h to olej
|
||
{if ((AccDesired>0.0))
|
||
AccDesired=0.0;
|
||
}
|
||
else
|
||
AccDesired=fAccThreshold; //hamuj tak średnio
|
||
//koniec predkosci aktualnej
|
||
if (fAccThreshold>-0.3) //bez sensu, ale dla towarowych korzystnie
|
||
{//Ra 2014-03: to nie uwzględnia odległości i zaczyna hamować, jak tylko zobaczy W4
|
||
if ((AccDesired>0.0)&&(VelNext>=0.0)) //wybieg bądź lekkie hamowanie, warunki byly zamienione
|
||
if (vel>VelNext+100.0) //lepiej zaczac hamowac
|
||
AccDesired=fAccThreshold;
|
||
else
|
||
if (vel>VelNext+70.0)
|
||
AccDesired=0.0; //nie spiesz się, bo będzie hamowanie
|
||
//koniec wybiegu i hamowania
|
||
}
|
||
if (AIControllFlag)
|
||
{//część wykonawcza tylko dla AI, dla człowieka jedynie napisy
|
||
if (mvControlling->ConvOvldFlag||!mvControlling->Mains) //WS może wywalić z powodu błędu w drutach
|
||
{//wywalił bezpiecznik nadmiarowy przetwornicy
|
||
//while (DecSpeed()); //zerowanie napędu
|
||
//Controlling->ConvOvldFlag=false; //reset nadmiarowego
|
||
PrepareEngine(); //próba ponownego załączenia
|
||
}
|
||
//włączanie bezpiecznika
|
||
if ((mvControlling->EngineType==ElectricSeriesMotor)||(mvControlling->TrainType&dt_EZT)||(mvControlling->EngineType==DieselElectric))
|
||
if (mvControlling->FuseFlag||Need_TryAgain)
|
||
{Need_TryAgain=false; //true, jeśli druga pozycja w elektryku nie załapała
|
||
//if (!Controlling->DecScndCtrl(1)) //kręcenie po mału
|
||
// if (!Controlling->DecMainCtrl(1)) //nastawnik jazdy na 0
|
||
mvControlling->DecScndCtrl(2); //nastawnik bocznikowania na 0
|
||
mvControlling->DecMainCtrl(2); //nastawnik jazdy na 0
|
||
mvControlling->MainSwitch(true); //Ra: dodałem, bo EN57 stawały po wywaleniu
|
||
if (!mvControlling->FuseOn())
|
||
HelpMeFlag=true;
|
||
else
|
||
{
|
||
++iDriverFailCount;
|
||
if (iDriverFailCount>maxdriverfails)
|
||
Psyche=Easyman;
|
||
if (iDriverFailCount>maxdriverfails*2)
|
||
SetDriverPsyche();
|
||
}
|
||
}
|
||
if (mvOccupied->BrakeSystem==Pneumatic) //napełnianie uderzeniowe
|
||
if (mvOccupied->BrakeHandle==FV4a)
|
||
{
|
||
if (mvOccupied->BrakeCtrlPos==-2)
|
||
mvOccupied->BrakeLevelSet(0);
|
||
// if ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->PipeBrakePress<0.01))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)})
|
||
// mvOccupied->IncBrakeLevel();
|
||
if ((mvOccupied->PipePress<3.0)&&(AccDesired>-0.03)) mvOccupied->BrakeReleaser(1);
|
||
if ((mvOccupied->BrakeCtrlPos==0)&&(AbsAccS<0.0)&&(AccDesired>-0.03))
|
||
//if FuzzyLogicAI(CntrlPipePress-PipePress,0.01,1))
|
||
// if ((mvOccupied->BrakePress>0.5)&&(mvOccupied->LocalBrakePos<0.5))//{((Volume/BrakeVVolume/10)<0.485)})
|
||
if ((mvOccupied->EqvtPipePress<4.95)&&(fReady>0.35))//{((Volume/BrakeVVolume/10)<0.485)})
|
||
{if (iDrivigFlags&moveOerlikons) //a reszta składu jest na to gotowa
|
||
mvOccupied->BrakeLevelSet(-1); //napełnianie w Oerlikonie
|
||
}
|
||
else
|
||
if (Need_BrakeRelease)
|
||
{
|
||
Need_BrakeRelease=false;
|
||
mvOccupied->BrakeReleaser(1);
|
||
//DecBrakeLevel(); //z tym by jeszcze miało jakiś sens
|
||
}
|
||
// if ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->BrakePress<0.3))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)})
|
||
if ((mvOccupied->BrakeCtrlPos<0)&&(mvOccupied->EqvtPipePress>(fReady<0.25?5.1:5.2)))//{(CntrlPipePress-(Volume/BrakeVVolume/10)<0.01)})
|
||
mvOccupied->IncBrakeLevel();
|
||
}
|
||
#if LOGVELOCITY
|
||
WriteLog("Dist="+FloatToStrF(ActualProximityDist,ffFixed,7,1)+", VelDesired="+FloatToStrF(VelDesired,ffFixed,7,1)+", AccDesired="+FloatToStrF(AccDesired,ffFixed,7,3)+", VelSignal="+AnsiString(VelSignal)+", VelNext="+AnsiString(VelNext));
|
||
#endif
|
||
if (AccDesired>0.1)
|
||
if (vel<10.0) //Ra 2F1H: jeśli prędkość jest mała, a można przyspieszać, to nie ograniczać przyspieszenia do 0.5m/ss
|
||
AccDesired=0.9; //przy małych prędkościach może być trudno utrzymać małe przyspieszenie
|
||
//Ra 2F1I: wyłączyć kiedyś to uśrednianie i przeanalizować skanowanie, czemu migocze
|
||
if (AccDesired>-0.15) //hamowania lepeiej nie uśredniać
|
||
AccDesired=fAccDesiredAv=0.2*AccDesired+0.8*fAccDesiredAv; //uśrednione, żeby ograniczyć migotanie
|
||
if (VelDesired==0.0) if (AccDesired>=-0.01) AccDesired=-0.01; //Ra 2F1J: jeszcze jedna prowizoryczna łatka
|
||
if (AccDesired>=0.0)
|
||
if (iDrivigFlags&movePress)
|
||
mvOccupied->BrakeReleaser(1); //wyluzuj lokomotywę - może być więcej!
|
||
else
|
||
if (OrderList[OrderPos]!=Disconnect) //przy odłączaniu nie zwalniamy tu hamulca
|
||
if ((AccDesired>0.0)||(fAccGravity*fAccGravity<0.001)) //luzuj tylko na plaskim lub przy ruszaniu
|
||
{while (DecBrake()); //jeśli przyspieszamy, to nie hamujemy
|
||
if (mvOccupied->BrakePress>0.4)
|
||
mvOccupied->BrakeReleaser(1); //wyluzuj lokomotywę, to szybciej ruszymy
|
||
}
|
||
//margines dla prędkości jest doliczany tylko jeśli oczekiwana prędkość jest większa od 5km/h
|
||
if (!(iDrivigFlags&movePress))
|
||
{//jeśli nie dociskanie
|
||
if (AccDesired<-0.1)
|
||
while (DecSpeed()); //jeśli hamujemy, to nie przyspieszamy
|
||
else if (((fAccGravity<-0.01)?AccDesired<0.0:AbsAccS>AccDesired)||(vel>VelDesired)) //jak za bardzo przyspiesza albo prędkość przekroczona
|
||
DecSpeed(); //pojedyncze cofnięcie pozycji, bo na zero to przesada
|
||
}
|
||
//yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej
|
||
//zwiekszanie predkosci
|
||
//Ra 2F1H: jest konflikt histerezy pomiędzy nastawioną pozycją a uzyskiwanym przyspieszeniem - utrzymanie pozycji powoduje przekroczenie przyspieszenia
|
||
if (AbsAccS<AccDesired) //jeśli przyspieszenie pojazdu jest mniejsze niż żądane oraz
|
||
if (vel<VelDesired-fVelMinus) //jeśli prędkość w kierunku czoła jest mniejsza od dozwolonej o margines
|
||
if ((ActualProximityDist>fMaxProximityDist)?true:(vel<VelNext))
|
||
IncSpeed(); //to można przyspieszyć
|
||
//if ((AbsAccS<AccDesired)&&(vel<VelDesired))
|
||
//if (!MaxVelFlag) //Ra: to nie jest używane
|
||
//if (!IncSpeed()) //Ra: to tutaj jest bez sensu, bo nie dociągnie do bezoporowej
|
||
// MaxVelFlag=true; //Ra: to nie jest używane
|
||
//else
|
||
// MaxVelFlag=false; //Ra: to nie jest używane
|
||
//if (Vel<VelDesired*0.85) and (AccDesired>0) and (EngineType=ElectricSeriesMotor)
|
||
// and (RList[MainCtrlPos].R>0.0) and (not DelayCtrlFlag))
|
||
// if (Im<Imin) and Ready=True {(BrakePress<0.01*MaxBrakePress)})
|
||
// IncMainCtrl(1); //zwieksz nastawnik skoro możesz - tak aby się ustawic na bezoporowej
|
||
|
||
//yB: usunięte różne dziwne warunki, oddzielamy część zadającą od wykonawczej
|
||
//zmniejszanie predkosci
|
||
if (mvOccupied->TrainType&dt_EZT) //właściwie, to warunek powinien być na działający EP
|
||
{//Ra: to dobrze hamuje EP w EZT
|
||
if ((AccDesired<=fAccThreshold)? //jeśli hamować - u góry ustawia się hamowanie na fAccThreshold
|
||
((AbsAccS>AccDesired)||(mvOccupied->BrakeCtrlPos<0)):false) //hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired)
|
||
IncBrake();
|
||
else
|
||
if (OrderList[OrderPos]!=Disconnect) //przy odłączaniu nie zwalniamy tu hamulca
|
||
if (AbsAccS<AccDesired-0.05) //jeśli opóźnienie większe od wymaganego (z histerezą)
|
||
{//luzowanie, gdy za dużo
|
||
if (mvOccupied->BrakeCtrlPos>=0)
|
||
DecBrake(); //tutaj zmniejszało o 1 przy odczepianiu
|
||
}
|
||
else if (mvOccupied->Handle->TimeEP)
|
||
{
|
||
if (mvOccupied->Handle->GetPos(bh_EPR)-mvOccupied->Handle->GetPos(bh_EPN)<0.1)
|
||
mvOccupied->SwitchEPBrake(0);
|
||
else
|
||
mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_EPN));
|
||
}
|
||
// else if (mvOccupied->BrakeCtrlPos<0) IncBrake(); //ustawienie jazdy (pozycja 0)
|
||
// else if (mvOccupied->BrakeCtrlPos>0) DecBrake();
|
||
}
|
||
else
|
||
{//a stara wersja w miarę dobrze działa na składy wagonowe
|
||
// if (mvOccupied->Handle->Time)
|
||
// mvOccupied->BrakeLevelSet(mvOccupied->Handle->GetPos(bh_MB)); //najwyzej sobie przestawi
|
||
if (((fAccGravity<-0.05)&&(vel<0))||((AccDesired<fAccGravity-0.1)&&(AbsAccS>AccDesired+0.05))) //u góry ustawia się hamowanie na fAccThreshold
|
||
//if not MinVelFlag)
|
||
if (fBrakeTime<0?true:(AccDesired<fAccGravity-0.3)||(mvOccupied->BrakeCtrlPos<=0))
|
||
if (!IncBrake()) //jeśli upłynął czas reakcji hamulca, chyba że nagłe albo luzował
|
||
MinVelFlag=true;
|
||
else
|
||
{MinVelFlag=false;
|
||
fBrakeTime=3+0.5*(mvOccupied->BrakeDelay[2+2*mvOccupied->BrakeDelayFlag]-3);
|
||
//Ra: ten czas należy zmniejszyć, jeśli czas dojazdu do zatrzymania jest mniejszy
|
||
fBrakeTime*=0.5; //Ra: tymczasowo, bo przeżyna S1
|
||
}
|
||
if ((AccDesired<fAccGravity-0.05)&&(AbsAccS<AccDesired-0.2))
|
||
//if ((AccDesired<0.0)&&(AbsAccS<AccDesired-0.1)) //ST44 nie hamuje na czas, 2-4km/h po minięciu tarczy
|
||
//if (fBrakeTime<0)
|
||
{//jak hamuje, to nie tykaj kranu za często
|
||
//yB: luzuje hamulec dopiero przy różnicy opóźnień rzędu 0.2
|
||
if (OrderList[OrderPos]!=Disconnect) //przy odłączaniu nie zwalniamy tu hamulca
|
||
DecBrake(); //tutaj zmniejszało o 1 przy odczepianiu
|
||
fBrakeTime=(mvOccupied->BrakeDelay[1+2*mvOccupied->BrakeDelayFlag])/3.0;
|
||
fBrakeTime*=0.5; //Ra: tymczasowo, bo przeżyna S1
|
||
}
|
||
}
|
||
//Mietek-end1
|
||
SpeedSet(); //ciągla regulacja prędkości
|
||
#if LOGVELOCITY
|
||
WriteLog("BrakePos="+AnsiString(mvOccupied->BrakeCtrlPos)+", MainCtrl="+AnsiString(mvControlling->MainCtrlPos));
|
||
#endif
|
||
|
||
/* //Ra: mamy teraz wskażnik na człon silnikowy, gorzej jak są dwa w ukrotnieniu...
|
||
//zapobieganie poslizgowi w czlonie silnikowym; Ra: Couplers[1] powinno być
|
||
if (Controlling->Couplers[0].Connected!=NULL)
|
||
if (TestFlag(Controlling->Couplers[0].CouplingFlag,ctrain_controll))
|
||
if (Controlling->Couplers[0].Connected->SlippingWheels)
|
||
if (Controlling->ScndCtrlPos>0?!Controlling->DecScndCtrl(1):true)
|
||
{
|
||
if (!Controlling->DecMainCtrl(1))
|
||
if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo)
|
||
mvOccupied->DecBrakeLevel();
|
||
++iDriverFailCount;
|
||
}
|
||
*/
|
||
//zapobieganie poslizgowi u nas
|
||
if (mvControlling->SlippingWheels)
|
||
{
|
||
if (!mvControlling->DecScndCtrl(2)) //bocznik na zero
|
||
mvControlling->DecMainCtrl(1);
|
||
if (mvOccupied->BrakeCtrlPos==mvOccupied->BrakeCtrlPosNo) //jeśli ostatnia pozycja hamowania
|
||
mvOccupied->DecBrakeLevel(); //to cofnij hamulec
|
||
else
|
||
mvControlling->AntiSlippingButton();
|
||
++iDriverFailCount;
|
||
mvControlling->SlippingWheels=false; //flaga już wykorzystana
|
||
}
|
||
if (iDriverFailCount>maxdriverfails)
|
||
{
|
||
Psyche=Easyman;
|
||
if (iDriverFailCount>maxdriverfails*2)
|
||
SetDriverPsyche();
|
||
}
|
||
} //if (AIControllFlag)
|
||
else
|
||
{//tu mozna dać komunikaty tekstowe albo słowne: przyspiesz, hamuj (lekko, średnio, mocno)
|
||
}
|
||
} //kierunek różny od zera
|
||
else
|
||
{//tutaj, gdy pojazd jest wyłączony
|
||
if (!AIControllFlag) //jeśli sterowanie jest w gestii użytkownika
|
||
if (mvOccupied->Battery) //czy użytkownik załączył baterię?
|
||
if (mvOccupied->ActiveDir) //czy ustawił kierunek
|
||
{//jeśli tak, to uruchomienie skanowania
|
||
CheckVehicles(); //sprawdzić skład
|
||
TableClear(); //resetowanie tabelki skanowania
|
||
PrepareEngine(); //uruchomienie
|
||
}
|
||
}
|
||
if (AIControllFlag)
|
||
{//odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy
|
||
if ((OrderList[OrderPos]&(Disconnect|Connect))==0) //przy (p)odłączaniu nie zwalniamy tu hamulca
|
||
if ((mvOccupied->V==0.0)&&((VelDesired==0.0)||(AccDesired==0.0)))
|
||
if ((mvOccupied->BrakeCtrlPos<1)||!mvOccupied->DecBrakeLevel())
|
||
mvOccupied->IncLocalBrakeLevel(1); //dodatkowy na pozycję 1
|
||
}
|
||
break; //rzeczy robione przy jezdzie
|
||
} //switch (OrderList[OrderPos])
|
||
//kasowanie licznika czasu
|
||
LastReactionTime=0.0;
|
||
UpdateOK=true;
|
||
} //if ((LastReactionTime>Min0R(ReactionTime,2.0)))
|
||
else
|
||
LastReactionTime+=dt;
|
||
|
||
if((fLastStopExpDist>0.0)&&(mvOccupied->DistCounter>fLastStopExpDist))
|
||
{
|
||
iStationStart=TrainParams->StationIndex; //zaktualizować wyświetlanie rozkładu
|
||
fLastStopExpDist=-1.0f; //usunąć licznik
|
||
}
|
||
|
||
if (AIControllFlag)
|
||
{
|
||
if (fWarningDuration>0.0) //jeśli pozostało coś do wytrąbienia
|
||
{//trąbienie trwa nadal
|
||
fWarningDuration=fWarningDuration-dt;
|
||
if (fWarningDuration<0.05)
|
||
mvOccupied->WarningSignal=0; //a tu się kończy
|
||
if (ReactionTime>fWarningDuration)
|
||
ReactionTime=fWarningDuration; //wcześniejszy przebłysk świadomości, by zakończyć trąbienie
|
||
}
|
||
if (mvOccupied->Vel>=3.0) //jesli jedzie, można odblokować trąbienie, bo się wtedy nie włączy
|
||
{iDrivigFlags&=~moveStartHornDone; //zatrąbi dopiero jak następnym razem stanie
|
||
iDrivigFlags|=moveStartHorn; //i trąbić przed następnym ruszeniem
|
||
}
|
||
return UpdateOK;
|
||
}
|
||
else //if (AIControllFlag)
|
||
return false; //AI nie obsługuje
|
||
}
|
||
|
||
void __fastcall TController::JumpToNextOrder()
|
||
{//wykonanie kolejnej komendy z tablicy rozkazów
|
||
if (OrderList[OrderPos]!=Wait_for_orders)
|
||
{
|
||
if (OrderList[OrderPos]&Change_direction) //jeśli zmiana kierunku
|
||
if (OrderList[OrderPos]!=Change_direction) //ale nałożona na coś
|
||
{OrderList[OrderPos]=TOrders(OrderList[OrderPos]&~Change_direction); //usunięcie zmiany kierunku z innej komendy
|
||
OrderCheck();
|
||
return;
|
||
}
|
||
if (OrderPos<maxorders-1)
|
||
++OrderPos;
|
||
else
|
||
OrderPos=0;
|
||
}
|
||
OrderCheck();
|
||
#if LOGORDERS
|
||
WriteLog("--> JumpToNextOrder");
|
||
OrdersDump(); //normalnie nie ma po co tego wypisywać
|
||
#endif
|
||
};
|
||
|
||
void __fastcall TController::JumpToFirstOrder()
|
||
{//taki relikt
|
||
OrderPos=1;
|
||
if (OrderTop==0) OrderTop=1;
|
||
OrderCheck();
|
||
#if LOGORDERS
|
||
WriteLog("--> JumpToFirstOrder");
|
||
OrdersDump(); //normalnie nie ma po co tego wypisywać
|
||
#endif
|
||
};
|
||
|
||
void __fastcall TController::OrderCheck()
|
||
{//reakcja na zmianę rozkazu
|
||
if (OrderList[OrderPos]&(Shunt|Connect|Obey_train))
|
||
CheckVehicles(); //sprawdzić światła
|
||
if (OrderList[OrderPos]&Change_direction) //może być nałożona na inną i wtedy ma priorytet
|
||
iDirectionOrder=-iDirection; //trzeba zmienić jawnie, bo się nie domyśli
|
||
else if (OrderList[OrderPos]==Obey_train)
|
||
iDrivigFlags|=moveStopPoint; //W4 są widziane
|
||
else if (OrderList[OrderPos]==Disconnect)
|
||
iVehicleCount=iVehicleCount<0?0:iVehicleCount; //odczepianie lokomotywy
|
||
else if (OrderList[OrderPos]==Connect)
|
||
iDrivigFlags&=~moveStopPoint; //podczas jazdy na połączenie nie zwracać uwagi na W4
|
||
else if (OrderList[OrderPos]==Wait_for_orders)
|
||
OrdersClear(); //czyszczenie rozkazów i przeskok do zerowej pozycji
|
||
}
|
||
|
||
void __fastcall TController::OrderNext(TOrders NewOrder)
|
||
{//ustawienie rozkazu do wykonania jako następny
|
||
if (OrderList[OrderPos]==NewOrder)
|
||
return; //jeśli robi to, co trzeba, to koniec
|
||
if (!OrderPos) OrderPos=1; //na pozycji zerowej pozostaje czekanie
|
||
OrderTop=OrderPos; //ale może jest czymś zajęty na razie
|
||
if (NewOrder>=Shunt) //jeśli ma jechać
|
||
{//ale może być zajęty chwilowymi operacjami
|
||
while (OrderList[OrderTop]?OrderList[OrderTop]<Shunt:false) //jeśli coś robi
|
||
++OrderTop; //pomijamy wszystkie tymczasowe prace
|
||
}
|
||
else
|
||
{//jeśli ma ustawioną jazdę, to wyłączamy na rzecz operacji
|
||
while (OrderList[OrderTop]?(OrderList[OrderTop]<Shunt)&&(OrderList[OrderTop]!=NewOrder):false) //jeśli coś robi
|
||
++OrderTop; //pomijamy wszystkie tymczasowe prace
|
||
}
|
||
OrderList[OrderTop++]=NewOrder; //dodanie rozkazu jako następnego
|
||
#if LOGORDERS
|
||
WriteLog("--> OrderNext");
|
||
OrdersDump(); //normalnie nie ma po co tego wypisywać
|
||
#endif
|
||
}
|
||
|
||
void __fastcall TController::OrderPush(TOrders NewOrder)
|
||
{//zapisanie na stosie kolejnego rozkazu do wykonania
|
||
if (OrderPos==OrderTop) //jeśli miałby być zapis na aktalnej pozycji
|
||
if (OrderList[OrderPos]<Shunt) //ale nie jedzie
|
||
++OrderTop; //niektóre operacje muszą zostać najpierw dokończone => zapis na kolejnej
|
||
if (OrderList[OrderTop]!=NewOrder) //jeśli jest to samo, to nie dodajemy
|
||
OrderList[OrderTop++]=NewOrder; //dodanie rozkazu na stos
|
||
//if (OrderTop<OrderPos) OrderTop=OrderPos;
|
||
if (OrderTop>=maxorders)
|
||
ErrorLog("Commands overflow: The program will now crash");
|
||
#if LOGORDERS
|
||
WriteLog("--> OrderPush");
|
||
OrdersDump(); //normalnie nie ma po co tego wypisywać
|
||
#endif
|
||
}
|
||
|
||
void __fastcall TController::OrdersDump()
|
||
{//wypisanie kolejnych rozkazów do logu
|
||
WriteLog("Orders for "+pVehicle->asName+":");
|
||
for (int b=0;b<maxorders;++b)
|
||
{WriteLog(AnsiString(b)+": "+Order2Str(OrderList[b])+(OrderPos==b?" <-":""));
|
||
if (b) //z wyjątkiem pierwszej pozycji
|
||
if (OrderList[b]==Wait_for_orders) //jeśli końcowa komenda
|
||
break; //dalej nie trzeba
|
||
}
|
||
};
|
||
|
||
TOrders __fastcall TController::OrderCurrentGet()
|
||
{
|
||
return OrderList[OrderPos];
|
||
}
|
||
|
||
TOrders __fastcall TController::OrderNextGet()
|
||
{
|
||
return OrderList[OrderPos+1];
|
||
}
|
||
|
||
void __fastcall TController::OrdersInit(double fVel)
|
||
{//wypełnianie tabelki rozkazów na podstawie rozkładu
|
||
//ustawienie kolejności komend, niezależnie kto prowadzi
|
||
//Mechanik->OrderPush(Wait_for_orders); //czekanie na lepsze czasy
|
||
//OrderPos=OrderTop=0; //wypełniamy od pozycji 0
|
||
OrdersClear(); //usunięcie poprzedniej tabeli
|
||
OrderPush(Prepare_engine); //najpierw odpalenie silnika
|
||
if (TrainParams->TrainName==AnsiString("none"))
|
||
{//brak rozkładu to jazda manewrowa
|
||
if (fVel>0.05) //typowo 0.1 oznacza gotowość do jazdy, 0.01 tylko załączenie silnika
|
||
OrderPush(Shunt); //jeśli nie ma rozkładu, to manewruje
|
||
}
|
||
else
|
||
{//jeśli z rozkładem, to jedzie na szlak
|
||
if ((fVel>0.0)&&(fVel<0.02))
|
||
OrderPush(Shunt); //dla prędkości 0.01 włączamy jazdę manewrową
|
||
else if (TrainParams?
|
||
(TrainParams->TimeTable[1].StationWare.Pos("@")? //jeśli obrót na pierwszym przystanku
|
||
((iDrivigFlags&movePushPull)? //SZT również! SN61 zależnie od wagonów...
|
||
(TrainParams->TimeTable[1].StationName==TrainParams->Relation1):false):false):true)
|
||
OrderPush(Shunt); //a teraz start będzie w manewrowym, a tryb pociągowy włączy W4
|
||
else
|
||
//jeśli start z pierwszej stacji i jednocześnie jest na niej zmiana kierunku, to EZT ma mieć Shunt
|
||
OrderPush(Obey_train); //dla starych scenerii start w trybie pociagowym
|
||
if (DebugModeFlag) //normalnie nie ma po co tego wypisywać
|
||
WriteLog("/* Timetable: "+TrainParams->ShowRelation());
|
||
TMTableLine *t;
|
||
for (int i=0;i<=TrainParams->StationCount;++i)
|
||
{t=TrainParams->TimeTable+i;
|
||
if (DebugModeFlag) //normalnie nie ma po co tego wypisywać
|
||
WriteLog(AnsiString(t->StationName)+" "+AnsiString((int)t->Ah)+":"+AnsiString((int)t->Am)+", "+AnsiString((int)t->Dh)+":"+AnsiString((int)t->Dm)+" "+AnsiString(t->StationWare));
|
||
if (AnsiString(t->StationWare).Pos("@"))
|
||
{//zmiana kierunku i dalsza jazda wg rozkładu
|
||
if (iDrivigFlags&movePushPull) //SZT również! SN61 zależnie od wagonów...
|
||
{//jeśli skład zespolony, wystarczy zmienić kierunek jazdy
|
||
OrderPush(Change_direction); //zmiana kierunku
|
||
}
|
||
else
|
||
{//dla zwykłego składu wagonowego odczepiamy lokomotywę
|
||
OrderPush(Disconnect); //odczepienie lokomotywy
|
||
OrderPush(Shunt); //a dalej manewry
|
||
if (i<=TrainParams->StationCount) //130827: to się jednak nie sprawdza
|
||
{//"@" na ostatniej robi tylko odpięcie
|
||
//OrderPush(Change_direction); //zmiana kierunku
|
||
//OrderPush(Shunt); //jazda na drugą stronę składu
|
||
//OrderPush(Change_direction); //zmiana kierunku
|
||
//OrderPush(Connect); //jazda pod wagony
|
||
}
|
||
}
|
||
if (i<TrainParams->StationCount) //jak nie ostatnia stacja
|
||
OrderPush(Obey_train); //to dalej wg rozkładu
|
||
}
|
||
}
|
||
if (DebugModeFlag) //normalnie nie ma po co tego wypisywać
|
||
WriteLog("*/");
|
||
OrderPush(Shunt); //po wykonaniu rozkładu przełączy się na manewry
|
||
}
|
||
//McZapkie-100302 - to ma byc wyzwalane ze scenerii
|
||
if (fVel==0.0)
|
||
SetVelocity(0,0,stopSleep); //jeśli nie ma prędkości początkowej, to śpi
|
||
else
|
||
{//jeśli podana niezerowa prędkość
|
||
if ((fVel>=1.0)||(fVel<0.02)) //jeśli ma jechać - dla 0.01 ma podjechać manewrowo po podaniu sygnału
|
||
iDrivigFlags=(iDrivigFlags&~moveStopHere)|moveStopCloser; //to do następnego W4 ma podjechać blisko
|
||
else
|
||
iDrivigFlags|=moveStopHere; //czekać na sygnał
|
||
JumpToFirstOrder();
|
||
if (fVel>=1.0) //jeśli ma jechać
|
||
SetVelocity(fVel,-1); //ma ustawić żądaną prędkość
|
||
else
|
||
SetVelocity(0,0,stopSleep); //prędkość w przedziale (0;1) oznacza, że ma stać
|
||
}
|
||
#if LOGORDERS
|
||
WriteLog("--> OrdersInit");
|
||
#endif
|
||
if (DebugModeFlag) //normalnie nie ma po co tego wypisywać
|
||
OrdersDump(); //wypisanie kontrolne tabelki rozkazów
|
||
//McZapkie! - zeby w ogole AI ruszyl to musi wykonac powyzsze rozkazy
|
||
//Ale mozna by je zapodac ze scenerii
|
||
};
|
||
|
||
|
||
AnsiString __fastcall TController::StopReasonText()
|
||
{//informacja tekstowa o przyczynie zatrzymania
|
||
if (eStopReason!=7) //zawalidroga będzie inaczej
|
||
return StopReasonTable[eStopReason];
|
||
else
|
||
return "Blocked by "+(pVehicles[0]->PrevAny()->GetName());
|
||
};
|
||
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
//McZapkie: skanowanie semaforów
|
||
//Ra: stare funkcje skanujące, używane podczas manewrów do szukania sygnalizatora z tyłu
|
||
//- nie reagują na PutValues, bo nie ma takiej potrzeby
|
||
//- rozpoznają tylko zerową prędkość (jako koniec toru i brak podstaw do dalszego skanowania)
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
|
||
/* //nie używane
|
||
double __fastcall TController::Distance(vector3 &p1,vector3 &n,vector3 &p2)
|
||
{//Ra:obliczenie odległości punktu (p1) od płaszczyzny o wektorze normalnym (n) przechodzącej przez (p2)
|
||
return n.x*(p1.x-p2.x)+n.y*(p1.y-p2.y)+n.z*(p1.z-p2.z); //ax1+by1+cz1+d, gdzie d=-(ax2+by2+cz2)
|
||
};
|
||
*/
|
||
|
||
bool __fastcall TController::BackwardTrackBusy(TTrack *Track)
|
||
{//najpierw sprawdzamy, czy na danym torze są pojazdy z innego składu
|
||
if (Track->iNumDynamics)
|
||
{//jeśli tylko z własnego składu, to tor jest wolny
|
||
for (int i=0;i<Track->iNumDynamics;++i)
|
||
if (Track->Dynamics[i]->ctOwner!=this) //jeśli jest jakiś cudzy
|
||
return true; //to tor jest zajęty i skanowanie nie obowiązuje
|
||
}
|
||
return false; //wolny
|
||
};
|
||
|
||
TEvent* __fastcall TController::CheckTrackEventBackward(double fDirection,TTrack *Track)
|
||
{//sprawdzanie eventu w torze, czy jest sygnałowym - skanowanie do tyłu
|
||
TEvent* e=(fDirection>0)?Track->evEvent2:Track->evEvent1;
|
||
if (e)
|
||
if (!e->bEnabled) //jeśli sygnałowy (nie dodawany do kolejki)
|
||
if (e->Type==tp_GetValues) //PutValues nie może się zmienić
|
||
return e;
|
||
return NULL;
|
||
};
|
||
|
||
TTrack* __fastcall TController::BackwardTraceRoute(double &fDistance,double &fDirection,TTrack *Track,TEvent*&Event)
|
||
{//szukanie sygnalizatora w kierunku przeciwnym jazdy (eventu odczytu komórki pamięci)
|
||
TTrack *pTrackChVel=Track; //tor ze zmianą prędkości
|
||
TTrack *pTrackFrom; //odcinek poprzedni, do znajdywania końca dróg
|
||
double fDistChVel=-1; //odległość do toru ze zmianą prędkości
|
||
double fCurrentDistance=pVehicle->RaTranslationGet(); //aktualna pozycja na torze
|
||
double s=0;
|
||
if (fDirection>0) //jeśli w kierunku Point2 toru
|
||
fCurrentDistance=Track->Length()-fCurrentDistance;
|
||
if (BackwardTrackBusy(Track))
|
||
{//jak tor zajęty innym składem, to nie ma po co skanować
|
||
fDistance=0; //to na tym torze stoimy
|
||
return NULL; //stop, skanowanie nie dało sensownych rezultatów
|
||
}
|
||
if ((Event=CheckTrackEventBackward(fDirection,Track))!=NULL)
|
||
{//jeśli jest semafor na tym torze
|
||
fDistance=0; //to na tym torze stoimy
|
||
return Track;
|
||
}
|
||
if ((Track->VelocityGet()==0.0)||(Track->iDamageFlag&128))
|
||
{//jak prędkosć 0 albo uszkadza, to nie ma po co skanować
|
||
fDistance=0; //to na tym torze stoimy
|
||
return NULL; //stop, skanowanie nie dało sensownych rezultatów
|
||
}
|
||
while (s<fDistance)
|
||
{
|
||
//Track->ScannedFlag=true; //do pokazywania przeskanowanych torów
|
||
pTrackFrom=Track; //zapamiętanie aktualnego odcinka
|
||
s+=fCurrentDistance; //doliczenie kolejnego odcinka do przeskanowanej długości
|
||
if (fDirection>0)
|
||
{//jeśli szukanie od Point1 w kierunku Point2
|
||
if (Track->iNextDirection)
|
||
fDirection=-fDirection;
|
||
Track=Track->CurrentNext(); //może być NULL
|
||
}
|
||
else //if (fDirection<0)
|
||
{//jeśli szukanie od Point2 w kierunku Point1
|
||
if (!Track->iPrevDirection)
|
||
fDirection=-fDirection;
|
||
Track=Track->CurrentPrev(); //może być NULL
|
||
}
|
||
if (Track==pTrackFrom) Track=NULL; //koniec, tak jak dla torów
|
||
if (Track?(Track->VelocityGet()==0.0)||(Track->iDamageFlag&128)||BackwardTrackBusy(Track):true)
|
||
{//gdy dalej toru nie ma albo zerowa prędkość, albo uszkadza pojazd
|
||
fDistance=s;
|
||
return NULL; //zwraca NULL, że skanowanie nie dało sensownych rezultatów
|
||
}
|
||
fCurrentDistance=Track->Length();
|
||
if ((Event=CheckTrackEventBackward(fDirection,Track))!=NULL)
|
||
{//znaleziony tor z eventem
|
||
fDistance=s;
|
||
return Track;
|
||
}
|
||
}
|
||
Event=NULL; //jak dojdzie tu, to nie ma semafora
|
||
if (fDistChVel<0)
|
||
{//zwraca ostatni sprawdzony tor
|
||
fDistance=s;
|
||
return Track;
|
||
}
|
||
fDistance=fDistChVel; //odległość do zmiany prędkości
|
||
return pTrackChVel; //i tor na którym się zmienia
|
||
}
|
||
|
||
|
||
//sprawdzanie zdarzeń semaforów i ograniczeń szlakowych
|
||
void __fastcall TController::SetProximityVelocity(double dist,double vel,const vector3 *pos)
|
||
{//Ra:przeslanie do AI prędkości
|
||
/*
|
||
//!!!! zastąpić prawidłową reakcją AI na SetProximityVelocity !!!!
|
||
if (vel==0)
|
||
{//jeśli zatrzymanie, to zmniejszamy dystans o 10m
|
||
dist-=10.0;
|
||
};
|
||
if (dist<0.0) dist=0.0;
|
||
if ((vel<0)?true:dist>0.1*(MoverParameters->Vel*MoverParameters->Vel-vel*vel)+50)
|
||
{//jeśli jest dalej od umownej drogi hamowania
|
||
*/
|
||
PutCommand("SetProximityVelocity",dist,vel,pos);
|
||
/*
|
||
}
|
||
else
|
||
{//jeśli jest zagrożenie, że przekroczy
|
||
Mechanik->SetVelocity(floor(0.2*sqrt(dist)+vel),vel,stopError);
|
||
}
|
||
*/
|
||
}
|
||
|
||
TCommandType __fastcall TController::BackwardScan()
|
||
{//sprawdzanie zdarzeń semaforów z tyłu pojazdu, zwraca komendę
|
||
//dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda na kozioł
|
||
//ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie przydatny
|
||
//zwraca true, jeśli należy odwrócić kierunek jazdy pojazdu
|
||
if ((OrderList[OrderPos]&~(Shunt|Connect)))
|
||
return cm_Unknown; //skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na rozkazy
|
||
vector3 sl;
|
||
int startdir=-pVehicles[0]->DirectionGet(); //kierunek jazdy względem sprzęgów pojazdu na czele
|
||
if (startdir==0) //jeśli kabina i kierunek nie jest określony
|
||
return cm_Unknown; //nie robimy nic
|
||
double scandir=startdir*pVehicles[0]->RaDirectionGet(); //szukamy od pierwszej osi w wybranym kierunku
|
||
if (scandir!=0.0) //skanowanie toru w poszukiwaniu eventów GetValues (PutValues nie są przydatne)
|
||
{//Ra: przy wstecznym skanowaniu prędkość nie ma znaczenia
|
||
//scanback=pVehicles[1]->NextDistance(fLength+1000.0); //odległość do następnego pojazdu, 1000 gdy nic nie ma
|
||
double scanmax=1000; //1000m do tyłu, żeby widział przeciwny koniec stacji
|
||
double scandist=scanmax; //zmodyfikuje na rzeczywiście przeskanowane
|
||
TEvent *e=NULL; //event potencjalnie od semafora
|
||
//opcjonalnie może być skanowanie od "wskaźnika" z przodu, np. W5, Tm=Ms1, koniec toru
|
||
TTrack *scantrack=BackwardTraceRoute(scandist,scandir,pVehicles[0]->RaTrackGet(),e); //wg drugiej osi w kierunku ruchu
|
||
vector3 dir=startdir*pVehicles[0]->VectorFront(); //wektor w kierunku jazdy/szukania
|
||
if (!scantrack) //jeśli wstecz wykryto koniec toru
|
||
return cm_Unknown; //to raczej nic się nie da w takiej sytuacji zrobić
|
||
else
|
||
{//a jeśli są dalej tory
|
||
double vmechmax; //prędkość ustawiona semaforem
|
||
if (e)
|
||
{//jeśli jest jakiś sygnał na widoku
|
||
#if LOGBACKSCAN
|
||
AnsiString edir=pVehicle->asName+" - "+AnsiString((scandir>0)?"Event2 ":"Event1 ");
|
||
#endif
|
||
//najpierw sprawdzamy, czy semafor czy inny znak został przejechany
|
||
vector3 pos=pVehicles[1]->RearPosition(); //pozycja tyłu
|
||
vector3 sem; //wektor do sygnału
|
||
if (e->Type==tp_GetValues)
|
||
{//przesłać info o zbliżającym się semaforze
|
||
#if LOGBACKSCAN
|
||
edir+="("+(e->Params[8].asGroundNode->asName)+"): ";
|
||
#endif
|
||
sl=e->PositionGet(); //położenie komórki pamięci
|
||
sem=sl-pos; //wektor do komórki pamięci od końca składu
|
||
//sem=e->Params[8].asGroundNode->pCenter-pos; //wektor do komórki pamięci
|
||
if (dir.x*sem.x+dir.z*sem.z<0) //jeśli został minięty
|
||
//if ((mvOccupied->CategoryFlag&1)?(VelNext!=0.0):true) //dla pociągu wymagany sygnał zezwalający
|
||
{//iloczyn skalarny jest ujemny, gdy sygnał stoi z tyłu
|
||
#if LOGBACKSCAN
|
||
WriteLog(edir+"- ignored as not passed yet");
|
||
#endif
|
||
return cm_Unknown; //nic
|
||
}
|
||
vmechmax=e->ValueGet(1); //prędkość przy tym semaforze
|
||
//przeliczamy odległość od semafora - potrzebne by były współrzędne początku składu
|
||
//scandist=(pos-e->Params[8].asGroundNode->pCenter).Length()-0.5*mvOccupied->Dim.L-10; //10m luzu
|
||
scandist=sem.Length()-2; //2m luzu przy manewrach wystarczy
|
||
if (scandist<0) scandist=0; //ujemnych nie ma po co wysyłać
|
||
bool move=false; //czy AI w trybie manewerowym ma dociągnąć pod S1
|
||
if (e->Command()==cm_SetVelocity)
|
||
if ((vmechmax==0.0)?(OrderCurrentGet()&(Shunt|Connect)):(OrderCurrentGet()&Connect)) //przy podczepianiu ignorować wyjazd?
|
||
move=true; //AI w trybie manewerowym ma dociągnąć pod S1
|
||
else
|
||
{//
|
||
if ((scandist>fMinProximityDist)?(mvOccupied->Vel>0.0)&&(OrderCurrentGet()!=Shunt):false)
|
||
{//jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości
|
||
//jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył
|
||
//Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl);
|
||
#if LOGBACKSCAN
|
||
//WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" "+AnsiString(vmechmax));
|
||
WriteLog(edir);
|
||
#endif
|
||
//SetProximityVelocity(scandist,vmechmax,&sl);
|
||
return (vmechmax>0)?cm_SetVelocity:cm_Unknown;
|
||
}
|
||
else //ustawiamy prędkość tylko wtedy, gdy ma ruszyć, stanąć albo ma stać
|
||
//if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli stoi lub ma stanąć/stać
|
||
{//semafor na tym torze albo lokomtywa stoi, a ma ruszyć, albo ma stanąć, albo nie ruszać
|
||
//stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam
|
||
//PutCommand("SetVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem);
|
||
#if LOGBACKSCAN
|
||
WriteLog(edir+"SetVelocity "+AnsiString(vmechmax)+" "+AnsiString(e->Params[9].asMemCell->Value2()));
|
||
#endif
|
||
return (vmechmax>0)?cm_SetVelocity:cm_Unknown;
|
||
}
|
||
}
|
||
if (OrderCurrentGet()?OrderCurrentGet()&(Shunt|Connect):true) //w Wait_for_orders też widzi tarcze
|
||
{//reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe
|
||
if (move?true:e->Command()==cm_ShuntVelocity)
|
||
{//jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1
|
||
if ((scandist>fMinProximityDist)?(mvOccupied->Vel>0.0)||(vmechmax==0.0):false)
|
||
{//jeśli tarcza jest daleko, to:
|
||
//- jesli pojazd jedzie, to informujemy o zmianie prędkości
|
||
//- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą tarczę
|
||
if (mvOccupied->Vel>0.0) //tylko jeśli jedzie
|
||
{//Mechanik->PutCommand("SetProximityVelocity",scandist,vmechmax,sl);
|
||
#if LOGBACKSCAN
|
||
//WriteLog(edir+"SetProximityVelocity "+AnsiString(scandist)+" "+AnsiString(vmechmax));
|
||
WriteLog(edir);
|
||
#endif
|
||
//SetProximityVelocity(scandist,vmechmax,&sl);
|
||
return (iDrivigFlags&moveTrackEnd)?cm_ChangeDirection:cm_Unknown; //jeśli jedzie na W5 albo koniec toru, to można zmienić kierunek
|
||
}
|
||
}
|
||
else //ustawiamy prędkość tylko wtedy, gdy ma ruszyć, albo stanąć albo ma stać pod tarczą
|
||
{//stop trzeba powtarzać, bo inaczej zatrąbi i pojedzie sam
|
||
//if ((MoverParameters->Vel==0.0)||(vmechmax==0.0)) //jeśli jedzie lub ma stanąć/stać
|
||
{//nie dostanie komendy jeśli jedzie i ma jechać
|
||
//PutCommand("ShuntVelocity",vmechmax,e->Params[9].asMemCell->Value2(),&sl,stopSem);
|
||
#if LOGBACKSCAN
|
||
WriteLog(edir+"ShuntVelocity "+AnsiString(vmechmax)+" "+AnsiString(e->ValueGet(2)));
|
||
#endif
|
||
return (vmechmax>0)?cm_ShuntVelocity:cm_Unknown;
|
||
}
|
||
}
|
||
if ((vmechmax!=0.0)&&(scandist<100.0))
|
||
{//jeśli Tm w odległości do 100m podaje zezwolenie na jazdę, to od razu ją ignorujemy, aby móc szukać kolejnej
|
||
//eSignSkip=e; //wtedy uznajemy ignorowaną przy poszukiwaniu nowej
|
||
#if LOGBACKSCAN
|
||
WriteLog(edir+"- will be ignored due to Ms2");
|
||
#endif
|
||
return (vmechmax>0)?cm_ShuntVelocity:cm_Unknown;
|
||
}
|
||
} //if (move?...
|
||
} //if (OrderCurrentGet()==Shunt)
|
||
if (!e->bEnabled) //jeśli skanowany
|
||
if (e->StopCommand()) //a podłączona komórka ma komendę
|
||
return cm_Command; //to też się obrócić
|
||
} //if (e->Type==tp_GetValues)
|
||
} //if (e)
|
||
} //if (scantrack)
|
||
} //if (scandir!=0.0)
|
||
return cm_Unknown; //nic
|
||
};
|
||
|
||
AnsiString __fastcall TController::NextStop()
|
||
{//informacja o następnym zatrzymaniu, wyświetlane pod [F1]
|
||
if (asNextStop.Length()<20) return ""; //nie zawiera nazwy stacji, gdy dojechał do końca
|
||
//dodać godzinę odjazdu
|
||
if (!TrainParams)
|
||
return ""; //tu nie powinno nigdy wejść
|
||
TMTableLine *t=TrainParams->TimeTable+TrainParams->StationIndex;
|
||
if (t->Dh>=0) //jeśli jest godzina odjazdu
|
||
return
|
||
asNextStop.SubString(20,30)
|
||
+AnsiString(" ")
|
||
+AnsiString(int(t->Dh))
|
||
+AnsiString(":")
|
||
+AnsiString(int(100+t->Dm)).SubString(2,2); //odjazd
|
||
else if (t->Ah>=0) //przyjazd
|
||
return
|
||
asNextStop.SubString(20,30)
|
||
+AnsiString(" (")
|
||
+AnsiString(int(t->Ah))
|
||
+AnsiString(":")
|
||
+AnsiString(int(100+t->Am)).SubString(2,2)
|
||
+AnsiString(")"); //przyjazd
|
||
return "";
|
||
};
|
||
|
||
//-----------koniec skanowania semaforow
|
||
|
||
void __fastcall TController::TakeControl(bool yes)
|
||
{//przejęcie kontroli przez AI albo oddanie
|
||
if (AIControllFlag==yes) return; //już jest jak ma być
|
||
if (yes) //żeby nie wykonywać dwa razy
|
||
{//teraz AI prowadzi
|
||
AIControllFlag=AIdriver;
|
||
pVehicle->Controller=AIdriver;
|
||
iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć
|
||
//gdy zgaszone światła, flaga podjeżdżania pod semafory pozostaje bez zmiany
|
||
if (OrderCurrentGet()) //jeśli coś robi
|
||
PrepareEngine(); //niech sprawdzi stan silnika
|
||
else //jeśli nic nie robi
|
||
if (pVehicle->iLights[mvOccupied->CabNo<0?1:0]&21) //któreś ze świateł zapalone?
|
||
{//od wersji 357 oczekujemy podania komend dla AI przez scenerię
|
||
OrderNext(Prepare_engine);
|
||
if (pVehicle->iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło zapalone
|
||
OrderNext(Obey_train); //jazda pociągowa
|
||
else
|
||
OrderNext(Shunt); //jazda manewrowa
|
||
if (mvOccupied->Vel>=1.0) //jeśli jedzie (dla 0.1 ma stać)
|
||
iDrivigFlags&=~moveStopHere; //to ma nie czekać na sygnał, tylko jechać
|
||
else
|
||
iDrivigFlags|=moveStopHere; //a jak stoi, to niech czeka
|
||
}
|
||
/* od wersji 357 oczekujemy podania komend dla AI przez scenerię
|
||
if (OrderCurrentGet())
|
||
{if (OrderCurrentGet()<Shunt)
|
||
{OrderNext(Prepare_engine);
|
||
if (pVehicle->iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło
|
||
OrderNext(Obey_train); //jazda pociągowa
|
||
else
|
||
OrderNext(Shunt); //jazda manewrowa
|
||
}
|
||
}
|
||
else //jeśli jest w stanie Wait_for_orders
|
||
JumpToFirstOrder(); //uruchomienie?
|
||
// czy dac ponizsze? to problematyczne
|
||
//SetVelocity(pVehicle->GetVelocity(),-1); //utrzymanie dotychczasowej?
|
||
if (pVehicle->GetVelocity()>0.0)
|
||
SetVelocity(-1,-1); //AI ustali sobie odpowiednią prędkość
|
||
*/
|
||
//Activation(); //przeniesie użytkownika w ostatnio wybranym kierunku
|
||
CheckVehicles(); //ustawienie świateł
|
||
TableClear(); //ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z sygnałami
|
||
}
|
||
else
|
||
{//a teraz użytkownik
|
||
AIControllFlag=Humandriver;
|
||
pVehicle->Controller=Humandriver;
|
||
}
|
||
};
|
||
|
||
void __fastcall TController::DirectionForward(bool forward)
|
||
{//ustawienie jazdy do przodu dla true i do tyłu dla false (zależy od kabiny)
|
||
while (mvControlling->MainCtrlPos) //samo zapętlenie DecSpeed() nie wystarcza
|
||
DecSpeed(true); //wymuszenie zerowania nastawnika jazdy, inaczej się może zawiesić
|
||
if (forward)
|
||
while (mvOccupied->ActiveDir<=0)
|
||
mvOccupied->DirectionForward(); //do przodu w obecnej kabinie
|
||
else
|
||
while (mvOccupied->ActiveDir>=0)
|
||
mvOccupied->DirectionBackward(); //do tyłu w obecnej kabinie
|
||
if (mvOccupied->EngineType==DieselEngine) //specjalnie dla SN61
|
||
if (iDrivigFlags&moveActive) //jeśli był już odpalony
|
||
if (mvControlling->RList[mvControlling->MainCtrlPos].Mn==0)
|
||
mvControlling->IncMainCtrl(1); //żeby nie zgasł
|
||
};
|
||
|
||
AnsiString __fastcall TController::Relation()
|
||
{//zwraca relację pociągu
|
||
return TrainParams->ShowRelation();
|
||
};
|
||
|
||
AnsiString __fastcall TController::TrainName()
|
||
{//zwraca relację pociągu
|
||
return TrainParams->TrainName;
|
||
};
|
||
|
||
int __fastcall TController::StationCount()
|
||
{//zwraca ilość stacji (miejsc zatrzymania)
|
||
return TrainParams->StationCount;
|
||
};
|
||
|
||
int __fastcall TController::StationIndex()
|
||
{//zwraca indeks aktualnej stacji (miejsca zatrzymania)
|
||
return TrainParams->StationIndex;
|
||
};
|
||
|
||
bool __fastcall TController::IsStop()
|
||
{//informuje, czy jest zatrzymanie na najbliższej stacji
|
||
return TrainParams->IsStop();
|
||
};
|
||
|
||
void __fastcall TController::MoveTo(TDynamicObject *to)
|
||
{//przesunięcie AI do innego pojazdu (przy zmianie kabiny)
|
||
//mvOccupied->CabDeactivisation(); //wyłączenie kabiny w opuszczanym
|
||
pVehicle->Mechanik=to->Mechanik; //żeby się zamieniły, jak jest jakieś drugie
|
||
pVehicle=to;
|
||
ControllingSet(); //utworzenie połączenia do sterowanego pojazdu
|
||
pVehicle->Mechanik=this;
|
||
//iDirection=0; //kierunek jazdy trzeba dopiero zgadnąć
|
||
};
|
||
|
||
void __fastcall TController::ControllingSet()
|
||
{//znajduje człon do sterowania w EZT będzie to silnikowy
|
||
//problematyczne jest sterowanie z członu biernego, dlatego damy AI silnikowy
|
||
//dzięki temu będzie wirtualna kabina w silnikowym, działająca w rozrządczym
|
||
//w plikach FIZ zostały zgubione ujemne maski sprzęgów, stąd problemy z EZT
|
||
mvOccupied=pVehicle->MoverParameters; //domyślny skrót do obiektu parametrów
|
||
mvControlling=pVehicle->ControlledFind()->MoverParameters; //poszukiwanie członu sterowanego
|
||
};
|
||
|
||
AnsiString __fastcall TController::TableText(int i)
|
||
{//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
|
||
};
|
||
|
||
int __fastcall TController::CrossRoute(TTrack *tr)
|
||
{//zwraca numer segmentu dla skrzyżowania (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)
|
||
{//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
|
||
}
|
||
return 0; //nic nie znaleziono?
|
||
};
|
||
|
||
void __fastcall TController::RouteSwitch(int d)
|
||
{//ustawienie kierunku jazdy z kabiny
|
||
d&=3;
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
AnsiString __fastcall TController::OwnerName()
|
||
{
|
||
return pVehicle?pVehicle->MoverParameters->Name:AnsiString("none");
|
||
};
|
||
|