unit mtable; (* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. *) interface uses mctools,sysutils; const MaxTTableSize=100; //można by to robić dynamicznie hrsd= '.'; Type //Ra: pozycja zerowa rozkładu chyba nie ma sensu //Ra: numeracja przystanków jest 1..StationCount TMTableLine=record km:real; //kilometraz linii vmax:real; //predkosc rozkladowa przed przystankiem //StationName:string[32]; //nazwa stacji ('_' zamiast spacji) //StationWare:string[32]; //typ i wyposazenie stacji, oddz. przecinkami} StationName:string; //nazwa stacji ('_' zamiast spacji) StationWare:string; //typ i wyposazenie stacji, oddz. przecinkami} TrackNo:byte; //ilosc torow szlakowych Ah,Am:integer; //godz. i min. przyjazdu, -1 gdy bez postoju Dh,Dm:integer; //godz. i min. odjazdu tm:real; //czas jazdy do tej stacji w min. (z kolumny) WaitTime:integer; //czas postoju (liczony plus 6 sekund) end; TMTable = array[0..MaxTTableSize] of TMTableLine; PTrainParameters= ^TTrainParameters; TTrainParameters = class(TObject) TrainName:string; TTVmax:real; Relation1,Relation2: string; //nazwy stacji danego odcinka BrakeRatio: real; LocSeries: string; //seria (typ) pojazdu LocLoad: real; TimeTable: TMTable; StationCount: integer; //ilość przystanków (0-techniczny) StationIndex: integer; //numer najbliższego (aktualnego) przystanku NextStationName: string; LastStationLatency: real; Direction: integer; {kierunek jazdy w/g kilometrazu} function CheckTrainLatency: real; {todo: str hh:mm to int i z powrotem} function ShowRelation: string; function WatchMTable(DistCounter:real): real; function NextStop:string; function IsStop:boolean; function IsTimeToGo(hh,mm:real):boolean; function UpdateMTable(hh,mm:real; NewName: string): boolean; constructor Init(NewTrainName:string); procedure NewName(NewTrainName:string); function LoadTTfile(scnpath:string;iPlus:Integer;vMax:real):boolean; function DirectionChange():boolean; procedure StationIndexInc(); end; TMTableTime = class(TObject) GameTime: real; dd,hh,mm: integer; srh,srm : integer; {wschod slonca} ssh,ssm : integer; {zachod slonca} mr:real; procedure UpdateMTableTime(deltaT:real); constructor Init(InitH,InitM,InitSRH,InitSRM,InitSSH,InitSSM:integer); end; var GlobalTime: TMTableTime; implementation function CompareTime(t1h,t1m,t2h,t2m:real):real; {roznica czasu w minutach} //zwraca różnicę czasu //jeśli pierwsza jest aktualna, a druga rozkładowa, to ujemna oznacza opóżnienie //na dłuższą metę trzeba uwzględnić datę, jakby opóżnienia miały przekraczać 12h (towarowych) var t:real; begin if (t2h<0) then CompareTime:=0 else begin t:=(t2h-t1h)*60+t2m-t1m; //jeśli t2=00:05, a t1=23:50, to różnica wyjdzie ujemna if (t<-720) then //jeśli różnica przekracza 12h na minus t:=t+1440 //to dodanie doby minut else if (t>720) then //jeśli przekracza 12h na plus t:=t-1440; //to odjęcie doby minut CompareTime:=t; end; end; function TTrainParameters.CheckTrainLatency: real; begin if (LastStationLatency>1.0) or (LastStationLatency<0) then CheckTrainLatency:=LastStationLatency {spoznienie + lub do przodu - z tolerancja 1 min} else CheckTrainLatency:=0 end; function TTrainParameters.WatchMTable(DistCounter:real): real; {zwraca odleglość do najblizszej stacji z zatrzymaniem} var dist:real; begin if Direction=1 then dist:=TimeTable[StationIndex].km-TimeTable[0].km-DistCounter else dist:=TimeTable[0].km-TimeTable[StationIndex].km-DistCounter; WatchMTable:=dist; end; function TTrainParameters.NextStop:string; //pobranie nazwy następnego miejsca zatrzymania begin if StationIndex<=StationCount then NextStop:='PassengerStopPoint:'+NextStationName //nazwa następnego przystanku else NextStop:='[End of route]'; //że niby koniec end; function TTrainParameters.IsStop:boolean; //zapytanie, czy zatrzymywać na następnym punkcie rozkładu begin if (StationIndex=0 //-1 to brak postoju else IsStop:=true; //na ostatnim się zatrzymać zawsze end; function TTrainParameters.UpdateMTable(hh,mm:real;NewName:string):boolean; {odfajkowanie dojechania do stacji (NewName) i przeliczenie opóźnienia} var OK:boolean; begin OK:=false; if StationIndex<=StationCount then //Ra: "<=", bo ostatni przystanek jest traktowany wyjątkowo begin if NewName=NextStationName then //jeśli dojechane do następnego begin //Ra: wywołanie może być powtarzane, jak stoi na W4 if TimeTable[StationIndex+1].km-TimeTable[StationIndex].km<0 then //to jest bez sensu Direction:=-1 else Direction:=1; //prowizorka bo moze byc zmiana kilometrazu //ustalenie, czy opóźniony (porównanie z czasem odjazdu) LastStationLatency:=CompareTime(hh,mm,TimeTable[StationIndex].Dh,TimeTable[StationIndex].Dm); //inc(StationIndex); //przejście do następnej pozycji StationIndex<=StationCount if StationIndex'') and (Relation2<>'') then ShowRelation:=Relation1+' - '+Relation2 else ShowRelation:=''; end; constructor TTrainParameters.Init(NewTrainName:string); {wstępne ustawienie parametrów rozkładu jazdy} begin NewName(NewTrainName); end; procedure TTrainParameters.NewName(NewTrainName:string); {wstępne ustawienie parametrów rozkładu jazdy} var i:integer; begin TrainName:=NewTrainName; StationCount:=0; StationIndex:=0; NextStationName:='nowhere'; LastStationLatency:=0; Direction:=1; Relation1:=''; Relation2:=''; for i:=0 to MaxTTableSize do with timeTable[i] do begin km:=0; vmax:=-1; StationName:='nowhere'; StationWare:=''; TrackNo:=1; Ah:=-1; Am:=-1; Dh:=-1; Dm:=-1; tm:=0; WaitTime:=0; end; TTVmax:=100; {wykasowac} end; function TTrainParameters.LoadTTfile(scnpath:string;iPlus:Integer;vMax:real):boolean; //wczytanie pliku-tabeli z rozkładem przesuniętym o (fPlus); (vMax) nie ma znaczenia var lines,s:string; fin:text; EndTable:boolean; vActual:real; i,time:Integer; //do zwiększania czasu procedure UpdateVelocity(StationCount:integer;vActual:real); //zapisywanie prędkości maksymalnej do wcześniejszych odcinków //wywoływane z numerem ostatniego przetworzonego przystanku var i:integer; begin i:=StationCount; //TTVmax:=vActual; {PROWIZORKA!!!} while (i>=0) and (TimeTable[i].vmax=-1) do begin TimeTable[i].vmax:=vActual; //prędkość dojazdu do przystanku i dec(i); //ewentualnie do poprzedniego też end; end; begin ClearPendingExceptions; ConversionError:=0; EndTable:=False; if (TrainName='') then begin //jeśli pusty rozkład //UpdateVelocity(StationCount,vMax); //ograniczenie do prędkości startowej end else begin ConversionError:=666; vActual:=-1; s:=scnpath+TrainName+'.txt'; //Ra 2014-09: ustalić zasady wyznaczenia pierwotnego pliku przy przesuniętych rozkładach (kolejny pociąg dostaje numer +2) assignfile(fin,s); s:=''; {$I-} reset(fin); {$I+} if IOresult<>0 then begin vMax:=s2r(TrainName); //nie ma pliku ale jest liczba if (vMax>10)and(vMax<200) then begin TTVmax:=vMax; //Ra 2014-07: zamiast rozkładu można podać Vmax UpdateVelocity(StationCount,vMax); //ograniczenie do prędkości startowej ConversionError:=0; end else ConversionError:=-8; {Ra: ten błąd jest niepotrzebny} end else begin {analiza rozkładu jazdy} ConversionError:=0; while not (eof(fin) or (ConversionError<>0) or EndTable) do begin readln(fin,lines); {wczytanie linii} if Pos('___________________',lines)>0 then {linia pozioma górna} if ReadWord(fin)='[' then {lewy pion} if ReadWord(fin)='Rodzaj' then {"Rodzaj i numer pociagu"} repeat until (ReadWord(fin)='|') or (eof(fin)); {środkowy pion} s:=ReadWord(fin); {nazwa pociągu} //if LowerCase(s)<>ExtractFileName(TrainName) then {musi być taka sama, jak nazwa pliku} //ConversionError:=-7 {błąd niezgodności} TrainName:=s; //nadanie nazwy z pliku TXT (bez ścieżki do pliku) //else begin {czytaj naglowek} repeat until (Pos('_______|',ReadWord(fin))>0) or eof(fin); repeat until (ReadWord(fin)='[') or (eof(fin)); {pierwsza linia z relacją} repeat s:=ReadWord(fin); until (s<>'|') or eof(fin); if s<>'|' then Relation1:=s else ConversionError:=-5; repeat until (Readword(fin)='Relacja') or (eof(fin)); {druga linia z relacją} repeat until (ReadWord(fin)='|') or (eof(fin)); Relation2:=ReadWord(fin); repeat until Readword(fin)='Wymagany'; repeat until (ReadWord(fin)='|') or (eoln(fin)); s:=ReadWord(fin); s:=Copy(s,1,Pos('%',s)-1); BrakeRatio:=s2rE(s); repeat until Readword(fin)='Seria'; repeat until (ReadWord(fin)='|') or (eof(fin)); LocSeries:=ReadWord(fin); LocLoad:=s2rE(ReadWord(fin)); repeat until (Pos('[______________',ReadWord(fin))>0) or (eof(fin)); while not eof(fin) and not EndTable do begin inc(StationCount); repeat s:=ReadWord(fin); until (s='[') or (eof(fin)); with TimeTable[StationCount] do begin if s='[' then s:=ReadWord(fin) else ConversionError:=-4; if Pos('|',s)=0 then begin km:=s2rE(s); s:=ReadWord(fin); end; if Pos('|_____|',s)>0 then {zmiana predkosci szlakowej} UpdateVelocity(StationCount,vActual) else begin s:=ReadWord(fin); if Pos('|',s)=0 then vActual:=s2rE(s); end; while Pos('|',s)=0 do s:=Readword(fin); StationName:=ReadWord(fin); repeat s:=ReadWord(fin); until (s='1') or (s='2') or eof(fin); TrackNo:=s2bE(s); s:=ReadWord(fin); if s<>'|' then begin if Pos(hrsd,s)>0 then begin ah:=s2iE(Copy(s,1,Pos(hrsd,s)-1)); //godzina przyjazdu am:=s2iE(Copy(s,Pos(hrsd,s)+1,Length(s))); //minuta przyjazdu end else begin ah:=TimeTable[StationCount-1].ah; //godzina z poprzedniej pozycji am:=s2iE(s); //bo tylko minuty podane end; end; repeat s:=ReadWord(fin); until (s<>'|') or (eof(fin)); if s<>']' then tm:=s2rE(s); repeat s:=ReadWord(fin); until (s='[') or eof(fin); s:=ReadWord(fin); if Pos('|',s)=0 then begin {tu s moze byc miejscem zmiany predkosci szlakowej} s:=ReadWord(fin); end; if Pos('|_____|',s)>0 then {zmiana predkosci szlakowej} UpdateVelocity(StationCount,vActual) else begin s:=ReadWord(fin); if Pos('|',s)=0 then vActual:=s2rE(s); end; while Pos('|',s)=0 do s:=Readword(fin); StationWare:=ReadWord(fin); repeat s:=ReadWord(fin); until (s='1') or (s='2') or eof(fin); TrackNo:=s2bE(s); s:=ReadWord(fin); if s<>'|' then begin if Pos(hrsd,s)>0 then begin dh:=s2iE(Copy(s,1,Pos(hrsd,s)-1)); //godzina odjazdu dm:=s2iE(Copy(s,Pos(hrsd,s)+1,Length(s))); //minuta odjazdu end else begin dh:=TimeTable[StationCount-1].dh; //godzina z poprzedniej pozycji dm:=s2iE(s); //bo tylko minuty podane end; end else begin dh:=ah; //odjazd o tej samej, co przyjazd (dla ostatniego też) dm:=am; //bo są używane do wyliczenia opóźnienia po dojechaniu end; if (ah>=0) then WaitTime:=Trunc(CompareTime(ah,am,dh,dm)+0.1); repeat s:=ReadWord(fin); until (s<>'|') or (eof(fin)); if s<>']' then tm:=s2rE(s); repeat s:=ReadWord(fin); until (Pos('[',s)>0) or eof(fin); if Pos('_|_',s)=0 then s:=Readword(fin); if Pos('|',s)=0 then begin {tu s moze byc miejscem zmiany predkosci szlakowej} s:=ReadWord(fin); end; if Pos('|_____|',s)>0 then {zmiana predkosci szlakowej} UpdateVelocity(StationCount,vActual) else begin s:=ReadWord(fin); if Pos('|',s)=0 then vActual:=s2rE(s); end; while Pos('|',s)=0 do s:=Readword(fin); while (Pos(']',s)=0) do s:=ReadWord(fin); if Pos('_|_',s)>0 then EndTable:=True; end; {timetableline} end; end; end; {while eof} close(fin); end; end; if ConversionError=0 then begin if (TimeTable[1].StationName=Relation1) then //jeśli nazwa pierwszego zgodna z relacją if (TimeTable[1].Ah<0) then //a nie podany czas przyjazdu begin //to mamy zatrzymanie na pierwszym, a nie przelot TimeTable[1].Ah:=TimeTable[1].Dh; TimeTable[1].Am:=TimeTable[1].Dm; end //NextStationName:=TimeTable[1].StationName; { TTVmax:=TimeTable[1].vmax; } end; if (iPlus<>0) then //jeżeli jest przesunięcie rozkładu for i:=1 to StationCount do //bez with, bo ciężko się przenosi na C++ begin if (TimeTable[i].Ah>=0) then begin time:=iPlus+TimeTable[i].Ah*60+TimeTable[i].Am; //nowe minuty TimeTable[i].Am:=time mod 60; TimeTable[i].Ah:=(time div 60) mod 60; end; if (TimeTable[i].Dh>=0) then begin time:=iPlus+TimeTable[i].Dh*60+TimeTable[i].Dm; //nowe minuty TimeTable[i].Dm:=time mod 60; TimeTable[i].Dh:=(time div 60) mod 60; end; end; LoadTTfile:=(ConversionError=0); end; procedure TMTableTime.UpdateMTableTime(deltaT:real); //dodanie czasu (deltaT) w sekundach, z przeliczeniem godziny begin mr:=mr+deltaT; //dodawanie sekund while mr>60.0 do //przeliczenie sekund do właściwego przedziału begin mr:=mr-60.0; inc(mm); end; while mm>59 do //przeliczenie minut do właściwego przedziału begin mm:=mm-60; inc(hh); end; while hh>23 do //przeliczenie godzin do właściwego przedziału begin hh:=hh-24; inc(dd); //zwiększenie numeru dnia end; GameTime:=GameTime+deltaT; end; constructor TMTableTime.Init(InitH,InitM,InitSRH,InitSRM,InitSSH,InitSSM:integer); begin GameTime:=0.0; dd:=0; hh:=InitH; mm:=InitM; srh:=InitSRH; srm:=InitSRM; ssh:=InitSSH; ssm:=InitSSM; end; function TTrainParameters.DirectionChange():boolean; //sprawdzenie, czy po zatrzymaniu wykonać kolejne komendy begin DirectionChange:=false; //przed pierwszą bez zmiany if (StationIndex>0) and (StationIndex0) then DirectionChange:=true; end; END.