Changeset 93


Ignore:
Timestamp:
Sep 26, 2022, 10:39:03 PM (19 months ago)
Author:
chronos
Message:
  • Added: Support for train carriages.
  • Added: City support implementation preparation.
Location:
trunk
Files:
2 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/BigMetro.lpi

    r91 r93  
    8989      </Item2>
    9090    </RequiredPackages>
    91     <Units Count="11">
     91    <Units Count="12">
    9292      <Unit0>
    9393        <Filename Value="BigMetro.lpr"/>
     
    140140        <IsPartOfProject Value="True"/>
    141141      </Unit10>
     142      <Unit11>
     143        <Filename Value="UCity.pas"/>
     144        <IsPartOfProject Value="True"/>
     145      </Unit11>
    142146    </Units>
    143147  </ProjectOptions>
  • trunk/BigMetro.lpr

    r91 r93  
    99  Interfaces, // this includes the LCL widgetset
    1010  Forms, SysUtils, UFormMain, UFormImages, Common, UMenu, UControls,
    11 UMetroPassenger, UColors, UView, URiver;
     11UMetroPassenger, UColors, UView, URiver, UCity;
    1212
    1313{$R *.res}
  • trunk/Forms/UFormImages.lfm

    r86 r93  
    8585  object ImageTunnel: TImage
    8686    Left = 48
    87     Height = 76
     87    Height = 52
    8888    Top = 156
    89     Width = 84
     89    Width = 48
    9090    Picture.Data = {
    9191      1754506F727461626C654E6574776F726B47726170686963E40E000089504E47
     
    654654    Stretch = True
    655655  end
     656  object ImageCarriage: TImage
     657    Left = 51
     658    Height = 34
     659    Top = 326
     660    Width = 37
     661    Picture.Data = {
     662      1754506F727461626C654E6574776F726B47726170686963D100000089504E47
     663      0D0A1A0A0000000D494844520000002000000020080300000044A48AC6000000
     664      1B504C5445000000000000010101020202030303050505070707080808090909
     665      2516B4820000000174524E530040E6D8660000006449444154789CED91DB0AC0
     666      3008434D6CD7FDFF17AF17A43A287D1B1BEC3C04A251B015F931B062D747B600
     667      55D51455696A81A61C6E4C8DD2BB029B877828A022C935CCCECFB86D72D54EC2
     668      BCB0A2D1F670F113C01117886490482BDB38C9E22CA2FD3E176AF201C23336DB
     669      110000000049454E44AE426082
     670    }
     671  end
    656672end
  • trunk/Forms/UFormImages.pas

    r86 r93  
    1111
    1212  TFormImages = class(TForm)
     13    ImageCarriage: TImage;
    1314    ImageFastForward: TImage;
    1415    ImagePause: TImage;
  • trunk/Forms/UFormMain.pas

    r86 r93  
    196196      Translator1.Language := Translator1.Languages.SearchByCode(LangCode);
    197197    end else Translator1.Language := Translator1.Languages.SearchByCode('');
    198     Engine.DarkMode := ReadBoolWithDefault('DarkMode', False);
    199     Engine.HighestServedPassengerCount := ReadIntegerWithDefault('HighestPassengers', 0);
    200     Engine.HighestServedDaysCount := ReadIntegerWithDefault('HighestDays', 0);
     198    Engine.LoadFromRegistry(CurrentContext);
    201199  finally
    202200    Free;
     
    213211      WriteString('LanguageCode', Translator1.Language.Code)
    214212      else DeleteValue('LanguageCode');
    215     WriteBool('DarkMode', Engine.DarkMode);
    216     WriteInteger('HighestPassengers', Engine.HighestServedPassengerCount);
    217     WriteInteger('HighestDays', Engine.HighestServedDaysCount);
     213    Engine.SaveToRegistry(CurrentContext);
    218214  finally
    219215    Free;
     
    227223  CopyImage(Engine.ImageLocomotive.Bitmap, FormImages.ImageLocomotive.Picture.Bitmap);
    228224  CopyImage(Engine.ImageLocomotive.BitmapDisabled, FormImages.ImageLocomotive.Picture.Bitmap, True);
     225  CopyImage(Engine.ImageCarriage.Bitmap, FormImages.ImageCarriage.Picture.Bitmap);
     226  CopyImage(Engine.ImageCarriage.BitmapDisabled, FormImages.ImageCarriage.Picture.Bitmap, True);
    229227  CopyImage(Engine.ButtonBack.Bitmap, FormImages.ImageLeftArrow.Picture.Bitmap);
    230228  CopyImage(Engine.ButtonBack.BitmapDisabled, FormImages.ImageLeftArrow.Picture.Bitmap, True);
     
    240238    BitmapInvert(Engine.ImageLocomotive.Bitmap);
    241239    BitmapInvert(Engine.ImageLocomotive.BitmapDisabled);
     240    BitmapInvert(Engine.ImageCarriage.Bitmap);
     241    BitmapInvert(Engine.ImageCarriage.BitmapDisabled);
    242242    BitmapInvert(Engine.ButtonBack.Bitmap);
    243243    BitmapInvert(Engine.ButtonBack.BitmapDisabled);
  • trunk/Languages/BigMetro.cs.po

    r91 r93  
    11msgid ""
    22msgstr ""
    3 "Content-Type: text/plain; charset=UTF-8\n"
    43"Project-Id-Version: \n"
    54"POT-Creation-Date: \n"
     
    76"Last-Translator: Chronos <robie@centrum.cz>\n"
    87"Language-Team: \n"
     8"Language: cs\n"
    99"MIME-Version: 1.0\n"
     10"Content-Type: text/plain; charset=UTF-8\n"
    1011"Content-Transfer-Encoding: 8bit\n"
    11 "Language: cs\n"
    12 "X-Generator: Poedit 2.4.1\n"
     12"X-Generator: Poedit 3.0.1\n"
    1313
    1414#: tformimages.caption
    1515msgid "FormImages"
    16 msgstr ""
     16msgstr "FormImages"
    1717
    1818#: tformmain.applicationinfo1.description
    1919msgid "Enjoyable real-time metro building game."
    20 msgstr ""
     20msgstr "Zábavná stavitelská hra metra v reálném čase."
    2121
    2222#: tformmain.caption
     
    4242msgstr "%d cestujících cestovalo ve vašem metru během %d dnů."
    4343
     44#: uengine.slondon
     45msgid "London"
     46msgstr "Londýn"
     47
    4448#: uengine.snewhighscore
    4549msgid "New high score!"
    4650msgstr "Nové vysoké skóre!"
    4751
     52#: uengine.snewyork
     53msgid "New York"
     54msgstr "New York"
     55
    4856#: uengine.snooldstationtoconnectnew
    4957msgid "No old line station to connect new station"
    50 msgstr ""
     58msgstr "Není stará stanice linky k připojení k nové stanici"
    5159
    5260#: uengine.soldhighscore
     
    5563msgstr "Dřívější vysoké skóre bylo %d cestujících v %d dnech."
    5664
     65#: uengine.sparis
     66msgid "Paris"
     67msgstr "Paříž"
     68
     69#: uengine.sprague
     70msgid "Prague"
     71msgstr "Praha"
     72
    5773#: uengine.sstationnotdefined
    5874msgid "Station have to be defined"
    59 msgstr ""
     75msgstr "Stanice musí být určena"
    6076
    6177#: uengine.sstationwithoutmapstation
    6278msgid "Station have to have MapStation"
    63 msgstr ""
     79msgstr "Stanice musí mít MapStation"
     80
     81#: uengine.stokyo
     82msgid "Tokyo"
     83msgstr "Tokyo"
    6484
    6585#: umenu.sautomatic
     
    120140
    121141#: utrack.salreadyconnectedtrackpoint
    122 #, fuzzy
    123142msgctxt "utrack.salreadyconnectedtrackpoint"
    124143msgid "Trying to connect already connected track point"
     
    126145
    127146#: utrack.salreadydisconnectedtrackpoint
    128 #, fuzzy
    129147msgctxt "utrack.salreadydisconnectedtrackpoint"
    130148msgid "Trying to disconnect not connected track point"
     
    135153msgctxt "utrack.strackpointnotfound"
    136154msgid "Track point %d not found"
    137 msgstr ""
     155msgstr "Bod trasy %d nebyl nalezen"
    138156
    139157#: uview.szerozoomnotalowed
    140 #, fuzzy
    141158msgctxt "uview.szerozoomnotalowed"
    142159msgid "Zero zoom not allowed"
    143160msgstr "Nulové přiblížení není povoleno"
    144 
  • trunk/Languages/BigMetro.de.po

    r91 r93  
    4242msgstr "%d Passagiere fuhren mit deiner Metro über %d Tage."
    4343
     44#: uengine.slondon
     45msgid "London"
     46msgstr ""
     47
    4448#: uengine.snewhighscore
    4549msgid "New high score!"
    4650msgstr "Neuer Highscore!"
     51
     52#: uengine.snewyork
     53msgid "New York"
     54msgstr ""
    4755
    4856#: uengine.snooldstationtoconnectnew
     
    5563msgstr "Der alte Highscore war %d passager in %d Tagen."
    5664
     65#: uengine.sparis
     66msgid "Paris"
     67msgstr ""
     68
     69#: uengine.sprague
     70msgid "Prague"
     71msgstr ""
     72
    5773#: uengine.sstationnotdefined
    5874msgid "Station have to be defined"
     
    6177#: uengine.sstationwithoutmapstation
    6278msgid "Station have to have MapStation"
     79msgstr ""
     80
     81#: uengine.stokyo
     82msgid "Tokyo"
    6383msgstr ""
    6484
  • trunk/Languages/BigMetro.fr.po

    r92 r93  
    4242msgstr "%d passagers ont pris votre métro pendant %d jours."
    4343
     44#: uengine.slondon
     45msgid "London"
     46msgstr ""
     47
    4448#: uengine.snewhighscore
    4549msgid "New high score!"
    4650msgstr "Nouveau highscore!"
     51
     52#: uengine.snewyork
     53msgid "New York"
     54msgstr ""
    4755
    4856#: uengine.snooldstationtoconnectnew
     
    5563msgstr "Le vieux highscore était %d passagers pendant %d jours."
    5664
     65#: uengine.sparis
     66msgid "Paris"
     67msgstr ""
     68
     69#: uengine.sprague
     70msgid "Prague"
     71msgstr ""
     72
    5773#: uengine.sstationnotdefined
    5874msgid "Station have to be defined"
     
    6177#: uengine.sstationwithoutmapstation
    6278msgid "Station have to have MapStation"
     79msgstr ""
     80
     81#: uengine.stokyo
     82msgid "Tokyo"
    6383msgstr ""
    6484
  • trunk/Languages/BigMetro.pot

    r91 r93  
    3232msgstr ""
    3333
     34#: uengine.slondon
     35msgid "London"
     36msgstr ""
     37
    3438#: uengine.snewhighscore
    3539msgid "New high score!"
     40msgstr ""
     41
     42#: uengine.snewyork
     43msgid "New York"
    3644msgstr ""
    3745
     
    4553msgstr ""
    4654
     55#: uengine.sparis
     56msgid "Paris"
     57msgstr ""
     58
     59#: uengine.sprague
     60msgid "Prague"
     61msgstr ""
     62
    4763#: uengine.sstationnotdefined
    4864msgid "Station have to be defined"
     
    5167#: uengine.sstationwithoutmapstation
    5268msgid "Station have to have MapStation"
     69msgstr ""
     70
     71#: uengine.stokyo
     72msgid "Tokyo"
    5373msgstr ""
    5474
  • trunk/Packages/Common/UGeometric.pas

    r86 r93  
    88type
    99  TPointArray = array of TPoint;
     10
     11  { TVector }
     12
     13  TVector = record
     14    Position: TPoint;
     15    Direction: TPoint;
     16    function GetLength: Integer;
     17    function GetAngle: Double;
     18  end;
    1019
    1120function Distance(P1, P2: TPoint): Integer;
     
    162171end;
    163172
     173{ TVector }
     174
     175function TVector.GetLength: Integer;
     176begin
     177  Result := Trunc(Sqrt(Sqr(Direction.X) + Sqr(Direction.Y)));
     178end;
     179
     180function TVector.GetAngle: Double;
     181begin
     182  Result := ArcTan2(Direction.Y, Direction.X);
     183end;
    164184
    165185end.
  • trunk/UEngine.pas

    r91 r93  
    77uses
    88  {$IFDEF DARWIN}MacOSAll, CocoaAll, CocoaUtils,{$ENDIF}
    9   Classes, SysUtils, Graphics, Controls, ExtCtrls, Math, DateUtils,
     9  Classes, SysUtils, Graphics, Controls, ExtCtrls, Math, DateUtils, URegistry,
    1010  UMetaCanvas, Generics.Collections, Generics.Defaults, UMenu, UControls,
    11   UMetroPassenger, UColors, UView, URiver, UTrack;
     11  UMetroPassenger, UColors, UView, URiver, UTrack, UCity, UGeometric;
    1212
    1313type
    14   TStationShapeSet = set of TStationShape;
    1514  TEngine = class;
    1615  TMetroLines = class;
     
    1817  TMetroTrains = class;
    1918  TLineStation = class;
     19  TMetroTrain = class;
    2020
    2121  { TMapStation }
     
    8989  end;
    9090
    91   TMetroTrain = class;
    92 
    9391  { TMetroCarriage }
    9492
    9593  TMetroCarriage = class
    9694    Train: TMetroTrain;
     95    Passengers: TMetroPassengers;
     96    function GetTrackPosition: TTrackPosition;
     97    function GetVector: TVector;
     98    constructor Create;
     99    destructor Destroy; override;
    97100  end;
    98101
     
    100103
    101104  TMetroCarriages = class(TObjectList<TMetroCarriage>)
     105    function GetUnused: TMetroCarriage;
     106    function GetUnusedCount: Integer;
     107    function AddNew: TMetroCarriage;
    102108  end;
    103109
     
    113119  public
    114120    Passengers: TMetroPassengers;
    115     BaseTrackPoint: TTrackPoint;
    116     RelPos: Double;
     121    TrackPosition: TTrackPosition;
    117122    Direction: Integer;
    118123    InStation: Boolean;
     
    122127    function GetPosition: TPoint;
    123128    function GetAngle: Double;
     129    function GetVector: TVector;
    124130    constructor Create;
    125131    destructor Destroy; override;
     
    130136
    131137  TMetroTrains = class(TObjectList<TMetroTrain>)
    132     function GetUnusedTrain: TMetroTrain;
     138    function GetUnused: TMetroTrain;
    133139    function GetUnusedCount: Integer;
    134140    function AddNew: TMetroTrain;
     
    174180    function GetTrackOnPos(Pos: TPoint): TTrackLink;
    175181    function GetTrainOnPos(Pos: TPoint): TMetroTrain;
     182    function GetCarriageOnPos(Pos: TPoint): TMetroCarriage;
    176183    procedure DrawLine(Canvas: TCanvas; Pos: TPoint);
    177184    procedure DrawShape(Canvas: TCanvas; Position: TPoint; Shape: TStationShape;
     
    207214    procedure FullScreenChanged(Sender: TObject);
    208215    procedure UpdateInterface;
     216    procedure InitCities;
    209217  public
    210218    Colors: TColors;
     
    213221    Lines: TMetroLines;
    214222    Trains: TMetroTrains;
     223    Carriages: TMetroCarriages;
    215224    ShapeCount: Integer;
    216225    Map: TMap;
    217226    View: TView;
     227    Cities: TCities;
    218228    SelectedLine: TMetroLine;
    219229    SelectedTrain: TMetroTrain;
     230    SelectedCarriage: TMetroCarriage;
    220231    TrackStationDown: TTrackPoint;
    221232    TrackStationUp: TTrackPoint;
     
    228239    ImagePause: TImage;
    229240    ImageFastForward: TImage;
     241    ImageCarriage: TImage;
    230242    HighestServedPassengerCount: Integer;
    231243    HighestServedDaysCount: Integer;
     
    239251    procedure NewGame;
    240252    procedure Redraw;
     253    procedure LoadFromRegistry(Context: TRegistryContext);
     254    procedure SaveToRegistry(Context: TRegistryContext);
    241255    constructor Create;
    242256    destructor Destroy; override;
     
    262276  PassengerSize = 15;
    263277  TrainSize = 40;
     278  TrainGap = 5;
    264279  LineColorsDist = 50;
    265280  TrainSpeed = 2000;
     
    292307
    293308uses
    294   UGeometric, UFormMain, ULanguages;
     309  UFormMain, ULanguages;
    295310
    296311resourcestring
     
    305320  SStationWithoutMapStation = 'Station have to have MapStation';
    306321
     322  // Cities
     323  SPrague = 'Prague';
     324  SLondon = 'London';
     325  SParis = 'Paris';
     326  SNewYork = 'New York';
     327  STokyo = 'Tokyo';
     328
     329{ TMetroCarriage }
     330
     331function TMetroCarriage.GetTrackPosition: TTrackPosition;
     332begin
     333  if Assigned(Train) then begin
     334    Result := Train.TrackPosition;
     335    Result.Move(-Train.Direction * (TrainSize + TrainGap) * (Train.Carriages.IndexOf(Self) + 1));
     336  end;
     337end;
     338
     339function TMetroCarriage.GetVector: TVector;
     340begin
     341  Result := Train.GetVector;
     342  Result.Position := AddPoint(Result.Position, Point(TrainSize, TrainSize));
     343end;
     344
     345constructor TMetroCarriage.Create;
     346begin
     347  Passengers := TMetroPassengers.Create;
     348  Passengers.OwnsObjects := False;
     349end;
     350
     351destructor TMetroCarriage.Destroy;
     352begin
     353  FreeAndNil(Passengers);
     354  inherited;
     355end;
     356
     357{ TMetroCarriages }
     358
     359function TMetroCarriages.GetUnused: TMetroCarriage;
     360var
     361  I: Integer;
     362begin
     363  I := 0;
     364  while (I < Count) and (Assigned(Items[I].Train)) do Inc(I);
     365  if I < Count then Result := Items[I]
     366    else Result := nil;
     367end;
     368
     369function TMetroCarriages.GetUnusedCount: Integer;
     370var
     371  I: Integer;
     372begin
     373  Result := 0;
     374  for I := 0 to Count - 1 do
     375    if not Assigned(Items[I].Train) then Inc(Result);
     376end;
     377
     378function TMetroCarriages.AddNew: TMetroCarriage;
     379begin
     380  Result := TMetroCarriage.Create;
     381  Add(Result);
     382end;
     383
    307384{ TMap }
    308385
     
    332409{ TMetroTrains }
    333410
    334 function TMetroTrains.GetUnusedTrain: TMetroTrain;
     411function TMetroTrains.GetUnused: TMetroTrain;
    335412var
    336413  I: Integer;
     
    519596  // Place one train if at least two stations present
    520597  if (LineStations.Count = 2) then begin
    521     Train := Engine.Trains.GetUnusedTrain;
     598    Train := Engine.Trains.GetUnused;
    522599    if Assigned(Train) then begin
    523600      Train.Line := Self;
    524601      Train.TargetStation := LineStations[0];
    525       Train.BaseTrackPoint := Track.Points.First;
     602      Train.TrackPosition.BaseTrackPoint := Track.Points.First;
    526603      Trains.Add(Train);
    527604    end;
     
    551628    IsOnTrack := False;
    552629    for J := Track.Points.IndexOf(TP1) to Track.Points.IndexOf(TP2) do
    553     if Track.Points[J] = BaseTrackPoint then begin
     630    if Track.Points[J] = TrackPosition.BaseTrackPoint then begin
    554631      IsOnTrack := True;
    555632      Break;
    556633    end;
    557634    if IsOnTrack then begin
    558       if Assigned(BaseTrackPoint) and Assigned(BaseTrackPoint.GetUp) and (BaseTrackPoint.GetUp <> ALineStation.TrackPoint) then
    559         BaseTrackPoint := BaseTrackPoint.GetUp
     635      if Assigned(TrackPosition.BaseTrackPoint) and Assigned(TrackPosition.BaseTrackPoint.GetUp) and
     636        (TrackPosition.BaseTrackPoint.GetUp <> ALineStation.TrackPoint) then
     637        TrackPosition.BaseTrackPoint := TrackPosition.BaseTrackPoint.GetUp
    560638      else
    561       if Assigned(BaseTrackPoint) and Assigned(BaseTrackPoint.GetDown) and (BaseTrackPoint.GetDown <> ALineStation.TrackPoint) then
    562         BaseTrackPoint := BaseTrackPoint.GetDown
    563       else BaseTrackPoint := nil;
     639      if Assigned(TrackPosition.BaseTrackPoint) and Assigned(TrackPosition.BaseTrackPoint.GetDown) and
     640        (TrackPosition.BaseTrackPoint.GetDown <> ALineStation.TrackPoint) then
     641        TrackPosition.BaseTrackPoint := TrackPosition.BaseTrackPoint.GetDown
     642      else TrackPosition.BaseTrackPoint := nil;
    564643    end;
    565644  end;
     
    633712  FLine := AValue;
    634713  if AValue = nil then begin
    635     RelPos := 0;
    636     BaseTrackPoint := nil;
     714    TrackPosition.RelPos := 0;
     715    TrackPosition.BaseTrackPoint := nil;
    637716    TargetStation := nil;
    638717  end;
     
    646725begin
    647726  Result := 0;
    648   if Assigned(BaseTrackPoint) and Assigned(TargetStation) then begin
    649   Current := Line.Track.Points.IndexOf(BaseTrackPoint);
     727  if Assigned(TrackPosition.BaseTrackPoint) and Assigned(TargetStation) then begin
     728  Current := Line.Track.Points.IndexOf(TrackPosition.BaseTrackPoint);
    650729  Target := Line.Track.Points.IndexOf(TargetStation.TrackPoint);
    651730  if Current < Target then begin
    652731    for I := Current to Target - 1 do
    653732      Result := Result + Line.Track.Points[I].GetDistance;
    654     Result := Result - Trunc(RelPos);
     733    Result := Result - Trunc(TrackPosition.RelPos);
    655734  end else
    656735  if Current > Target then begin
    657736    for I := Current - 1 downto Target do
    658737      Result := Result + Line.Track.Points[I].GetDistance;
    659     Result := Result + Trunc(RelPos);
    660   end else Result := Trunc(RelPos);
     738    Result := Result + Trunc(TrackPosition.RelPos);
     739  end else Result := Trunc(TrackPosition.RelPos);
    661740  end;
    662741end;
     
    669748begin
    670749  Result := Point(0, 0);
    671   if Assigned(BaseTrackPoint) then
    672   with BaseTrackPoint do begin
    673     UpPoint := BaseTrackPoint.GetNeighUp;
     750  if Assigned(TrackPosition.BaseTrackPoint) then
     751  with TrackPosition.BaseTrackPoint do begin
     752    UpPoint := TrackPosition.BaseTrackPoint.GetNeighUp;
    674753    if Assigned(UpPoint) then begin
    675754      D := Distance(UpPoint.Position, Position);
    676755      if D > 0 then begin
    677756        Delta := SubPoint(UpPoint.Position, Position);
    678         Result := Point(Trunc(Position.X + Delta.X * RelPos / D),
    679           Trunc(Position.Y + Delta.Y * RelPos / D));
     757        Result := Point(Trunc(Position.X + Delta.X * TrackPosition.RelPos / D),
     758          Trunc(Position.Y + Delta.Y * TrackPosition.RelPos / D));
    680759      end;
    681760    end;
     
    688767begin
    689768  Result := 0;
    690   if Assigned(BaseTrackPoint) then
    691   with BaseTrackPoint do begin
    692     UpPoint := BaseTrackPoint.GetNeighUp;
     769  if Assigned(TrackPosition.BaseTrackPoint) then
     770  with TrackPosition.BaseTrackPoint do begin
     771    UpPoint := TrackPosition.BaseTrackPoint.GetNeighUp;
    693772    if Assigned(UpPoint) then begin
    694773      Result := ArcTan2(UpPoint.Position.Y - Position.Y,
     
    698777end;
    699778
     779function TMetroTrain.GetVector: TVector;
     780var
     781  D: Integer;
     782  UpPoint: TTrackPoint;
     783begin
     784  Result.Position := Point(0, 0);
     785  if Assigned(TrackPosition.BaseTrackPoint) then
     786  with TrackPosition.BaseTrackPoint do begin
     787    UpPoint := TrackPosition.BaseTrackPoint.GetNeighUp;
     788    if Assigned(UpPoint) then begin
     789      D := Distance(UpPoint.Position, Position);
     790      if D > 0 then begin
     791        Result.Direction := SubPoint(UpPoint.Position, Position);
     792        Result.Position := Point(Trunc(Position.X + Result.Direction.X * TrackPosition.RelPos / D),
     793          Trunc(Position.Y + Result.Direction.Y * TrackPosition.RelPos / D));
     794      end;
     795    end;
     796  end;
     797end;
     798
    700799constructor TMetroTrain.Create;
    701800begin
     
    703802  Passengers.OwnsObjects := False;
    704803  Carriages := TMetroCarriages.Create;
     804  Carriages.OwnsObjects := False;
    705805  Direction := 1;
    706806  Line := nil;
     
    9761076      Result := Trains[I];
    9771077      MinDistance := D;
     1078    end;
     1079  end;
     1080end;
     1081
     1082function TEngine.GetCarriageOnPos(Pos: TPoint): TMetroCarriage;
     1083var
     1084  I: Integer;
     1085  J: Integer;
     1086  MinDistance: Integer;
     1087  D: Integer;
     1088begin
     1089  Result := nil;
     1090  MinDistance := High(Integer);
     1091  for I := 0 to Trains.Count - 1 do
     1092  with TMetroTrain(Trains[I]) do begin
     1093    for J := 0 to Carriages.Count - 1 do
     1094    with TMetroCarriage(Carriages[J]) do begin
     1095      D := Distance(GetTrackPosition.GetVector.Position, Pos);
     1096      if (D < (TrainSize div 2)) and (D < MinDistance) then begin
     1097        Result := Carriages[J];
     1098        MinDistance := D;
     1099      end;
    9781100    end;
    9791101  end;
     
    12161338var
    12171339  I: Integer;
     1340  J: Integer;
    12181341  CurrentStation: TLineStation;
    12191342  P: Integer;
     
    12231346  PosChange: Double;
    12241347  TP: TTrackPoint;
     1348  Done: Boolean;
    12251349begin
    12261350  // Move trains
    12271351  for I := 0 to Trains.Count - 1 do
    12281352  with TMetroTrain(Trains[I]) do begin
    1229     if not Assigned(TargetStation) and Assigned(BaseTrackPoint) then begin
     1353    if not Assigned(TargetStation) and Assigned(TrackPosition.BaseTrackPoint) then begin
    12301354      if (Direction <> 1) and (Direction <> -1) then Direction := 1
    12311355        else Direction := -Direction;
    1232       TP := BaseTrackPoint.GetUp;
     1356      TP := TrackPosition.BaseTrackPoint.GetUp;
    12331357      if Assigned(TP) then TargetStation := TLineStation(TP.OwnerPoint)
    12341358      else begin
    1235         TP := BaseTrackPoint.GetDown;
     1359        TP := TrackPosition.BaseTrackPoint.GetDown;
    12361360        if Assigned(TP) then TargetStation := TLineStation(TP.OwnerPoint);
    12371361      end;
     
    12471371            if Line.IsCircular then begin
    12481372              TargetStationIndex := Line.LineStations.Count - 2;
    1249               BaseTrackPoint := Line.LineStations.Last.TrackPoint;
    1250               RelPos := 0;
     1373              TrackPosition.BaseTrackPoint := Line.LineStations.Last.TrackPoint;
     1374              TrackPosition.RelPos := 0;
    12511375            end else begin
    12521376              TargetStationIndex := 1;
     
    12571381            if Line.IsCircular then begin
    12581382              TargetStationIndex := 1;
    1259               BaseTrackPoint := Line.LineStations.First.TrackPoint;
    1260               RelPos := 0;
     1383              TrackPosition.BaseTrackPoint := Line.LineStations.First.TrackPoint;
     1384              TrackPosition.RelPos := 0;
    12611385            end else begin
    12621386              TargetStationIndex := Line.LineStations.Count - 2;
     
    12671391
    12681392          // Unload passengers in target station
    1269           if Assigned(CurrentStation) then
    1270           for P := Passengers.Count - 1 downto 0 do begin
    1271             if Passengers[P].Shape = CurrentStation.MapStation.Shape then begin
    1272               Passenger := Passengers[P];
    1273               Passengers.Delete(P);
    1274               Self.Passengers.Remove(Passenger);
    1275               Inc(ServedPassengerCount);
     1393          if Assigned(CurrentStation) then begin
     1394            for P := Passengers.Count - 1 downto 0 do begin
     1395              if Passengers[P].Shape = CurrentStation.MapStation.Shape then begin
     1396                Passenger := Passengers[P];
     1397                Passengers.Delete(P);
     1398                Self.Passengers.Remove(Passenger);
     1399                Inc(ServedPassengerCount);
     1400              end;
     1401            end;
     1402            for J := 0 to Carriages.Count - 1 do
     1403            with Carriages[J] do begin
     1404              for P := Passengers.Count - 1 downto 0 do begin
     1405                if Passengers[P].Shape = CurrentStation.MapStation.Shape then begin
     1406                  Passenger := Passengers[P];
     1407                  Passengers.Delete(P);
     1408                  Self.Passengers.Remove(Passenger);
     1409                  Inc(ServedPassengerCount);
     1410                end;
     1411              end;
    12761412            end;
    12771413          end;
     1414
    12781415          // Unload passengers to change line
    1279           if Assigned(CurrentStation)  then
    1280           for P := Passengers.Count - 1 downto 0 do begin
    1281             if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].Shape,
    1282             TargetStation, CurrentStation) then begin
    1283               Passenger := Passengers[P];
    1284               Passengers.Delete(P);
    1285               CurrentStation.MapStation.Passengers.Add(Passenger);
     1416          if Assigned(CurrentStation) then begin
     1417            for P := Passengers.Count - 1 downto 0 do begin
     1418              if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].Shape,
     1419              TargetStation, CurrentStation) then begin
     1420                Passenger := Passengers[P];
     1421                Passengers.Delete(P);
     1422                CurrentStation.MapStation.Passengers.Add(Passenger);
     1423              end;
     1424            end;
     1425            for J := 0 to Carriages.Count - 1 do
     1426            with Carriages[J] do begin
     1427              for P := Passengers.Count - 1 downto 0 do begin
     1428                if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].Shape,
     1429                TargetStation, CurrentStation) then begin
     1430                  Passenger := Passengers[P];
     1431                  Passengers.Delete(P);
     1432                  CurrentStation.MapStation.Passengers.Add(Passenger);
     1433                end;
     1434              end;
    12861435            end;
    12871436          end;
     
    12991448                Passengers.Add(Passenger);
    13001449              end;
    1301             end else Break; // No more space
     1450            end else begin
     1451              Done := False;
     1452              for J := 0 to Carriages.Count - 1 do
     1453              with Carriages[J] do begin
     1454                if (Passengers.Count < TrainPassengerCount) then begin
     1455                  Passenger := CurrentStation.MapStation.Passengers[P];
     1456                  if CurrentStation.MapStation.IsBestStationForShape(Passenger.Shape,
     1457                  TargetStation, CurrentStation) then begin
     1458                    CurrentStation.MapStation.Passengers.Delete(P);
     1459                    Passengers.Add(Passenger);
     1460                    Done := True;
     1461                    Break;
     1462                  end;
     1463                end;
     1464              end;
     1465              if not Done then Break;
     1466            end;
    13021467          end;
    13031468
     
    13081473      end else begin
    13091474        PosChange := Direction + Trunc(Direction * TrainSpeed * (Time - LastTrainMoveTime));
    1310         RelPos := RelPos + PosChange;
     1475        TrackPosition.RelPos := TrackPosition.RelPos + PosChange;
    13111476        LastTrainMoveTime := Time;
    13121477        Redraw;
    1313         if Assigned(BaseTrackPoint) then
    1314         while (Direction = -1) and (RelPos < 0) do begin
    1315           if BaseTrackPoint <> Line.LineStations.First.TrackPoint then begin
    1316             BaseTrackPoint := BaseTrackPoint.GetNeighDown;
    1317             if Assigned(BaseTrackPoint) then
    1318               RelPos := RelPos + BaseTrackPoint.GetDistance
     1478        if Assigned(TrackPosition.BaseTrackPoint) then
     1479        while (Direction = -1) and (TrackPosition.RelPos < 0) do begin
     1480          if TrackPosition.BaseTrackPoint <> Line.LineStations.First.TrackPoint then begin
     1481            TrackPosition.BaseTrackPoint := TrackPosition.BaseTrackPoint.GetNeighDown;
     1482            if Assigned(TrackPosition.BaseTrackPoint) then
     1483              TrackPosition.RelPos := TrackPosition.RelPos + TrackPosition.BaseTrackPoint.GetDistance
    13191484            else begin
    1320               BaseTrackPoint := Line.LineStations.First.TrackPoint;
    1321               RelPos := 0;
     1485              TrackPosition.BaseTrackPoint := Line.LineStations.First.TrackPoint;
     1486              TrackPosition.RelPos := 0;
    13221487            end;
    13231488          end else
    13241489          if Line.IsCircular then begin
    1325             BaseTrackPoint := Line.LineStations.Last.TrackPoint;
    1326             RelPos := RelPos + BaseTrackPoint.GetDistance;
     1490            TrackPosition.BaseTrackPoint := Line.LineStations.Last.TrackPoint;
     1491            TrackPosition.RelPos := TrackPosition.RelPos + TrackPosition.BaseTrackPoint.GetDistance;
    13271492          end else begin
    1328             RelPos := 0;
     1493            TrackPosition.RelPos := 0;
    13291494            Break;
    13301495          end;
    13311496        end;
    1332         if Assigned(BaseTrackPoint) then
    1333         while (Direction = 1) and (RelPos > BaseTrackPoint.GetDistance) do begin
    1334           if BaseTrackPoint <> Line.LineStations.Last.TrackPoint then begin
    1335             RelPos := RelPos - BaseTrackPoint.GetDistance;
    1336             BaseTrackPoint := BaseTrackPoint.GetNeighUp;
    1337             if not Assigned(BaseTrackPoint) then begin
    1338               BaseTrackPoint := Line.LineStations.Last.TrackPoint;
    1339               RelPos := 0;
     1497        if Assigned(TrackPosition.BaseTrackPoint) then
     1498        while (Direction = 1) and (TrackPosition.RelPos > TrackPosition.BaseTrackPoint.GetDistance) do begin
     1499          if TrackPosition.BaseTrackPoint <> Line.LineStations.Last.TrackPoint then begin
     1500            TrackPosition.RelPos := TrackPosition.RelPos - TrackPosition.BaseTrackPoint.GetDistance;
     1501            TrackPosition.BaseTrackPoint := TrackPosition.BaseTrackPoint.GetNeighUp;
     1502            if not Assigned(TrackPosition.BaseTrackPoint) then begin
     1503              TrackPosition.BaseTrackPoint := Line.LineStations.Last.TrackPoint;
     1504              TrackPosition.RelPos := 0;
    13401505            end;
    13411506          end else
    13421507          if Line.IsCircular then begin
    1343             RelPos := RelPos - BaseTrackPoint.GetDistance;
    1344             BaseTrackPoint := Line.LineStations.First.TrackPoint;
     1508            TrackPosition.RelPos := TrackPosition.RelPos - TrackPosition.BaseTrackPoint.GetDistance;
     1509            TrackPosition.BaseTrackPoint := Line.LineStations.First.TrackPoint;
    13451510          end else begin
    1346             RelPos := BaseTrackPoint.GetDistance;
     1511            TrackPosition.RelPos := TrackPosition.BaseTrackPoint.GetDistance;
    13471512            Break;
    13481513          end;
     
    13511516        if PosDelta >= LastPosDelta then begin
    13521517          // We are getting far from station, stop at station
    1353           BaseTrackPoint := TargetStation.TrackPoint;
    1354           RelPos := 0;
     1518          TrackPosition.BaseTrackPoint := TargetStation.TrackPoint;
     1519          TrackPosition.RelPos := 0;
    13551520          InStation := True;
    13561521          StationStopTime := Time;
     
    15491714end;
    15501715
     1716procedure TEngine.InitCities;
     1717begin
     1718  with Cities do begin
     1719    AddNew(SLondon);
     1720    AddNew(SNewYork);
     1721    AddNew(SPrague);
     1722    AddNew(SParis);
     1723    AddNew(STokyo);
     1724  end;
     1725end;
     1726
    15511727procedure TEngine.InitMenus;
    15521728begin
     
    17041880procedure TEngine.DrawTrains(Canvas: TCanvas);
    17051881var
     1882  I: Integer;
    17061883  P: Integer;
    17071884  Pos: TPoint;
     
    17111888  Train: TMetroTrain;
    17121889  Passenger: TMetroPassenger;
     1890  Carriage: TMetroCarriage;
     1891  Vector: TVector;
    17131892begin
    17141893  for Train in Trains do
     
    17181897      Canvas.Brush.Style := bsSolid;
    17191898      Canvas.Pen.Style := psClear;
    1720       Pos := GetPosition;
    1721       Angle := GetAngle;
     1899      Vector := GetVector;
     1900      Pos := Vector.Position;
     1901      Angle := Vector.GetAngle;
    17221902
    17231903      SetLength(Points, 4);
     
    17361916        DrawShape(Canvas, ShapePos, Shape, TrainSize div 3, Angle + Pi / 2);
    17371917        Inc(P);
     1918      end;
     1919
     1920      // Draw carriages
     1921      for Carriage in Train.Carriages do
     1922      with Carriage do begin
     1923        Canvas.Brush.Color := Line.Color;
     1924        Canvas.Brush.Style := bsSolid;
     1925        Canvas.Pen.Style := psClear;
     1926        Vector := GetTrackPosition.GetVector;
     1927        Pos := Vector.Position;
     1928        Angle := Vector.GetAngle;
     1929
     1930        SetLength(Points, 4);
     1931        Points[0] := RotatePoint(Pos, Point(Pos.X - TrainSize div 2, Pos.Y - TrainSize div 3), Angle);
     1932        Points[1] := RotatePoint(Pos, Point(Pos.X + TrainSize div 2, Pos.Y - TrainSize div 3), Angle);
     1933        Points[2] := RotatePoint(Pos, Point(Pos.X + TrainSize div 2, Pos.Y + TrainSize div 3), Angle);
     1934        Points[3] := RotatePoint(Pos, Point(Pos.X - TrainSize div 2, Pos.Y + TrainSize div 3), Angle);
     1935        Canvas.Polygon(Points);
     1936        Canvas.Brush.Color := clWhite;
     1937        P := 0;
     1938        for Passenger in Passengers do
     1939        with Passenger do begin
     1940          ShapePos := Point(Pos.X - Trunc(TrainSize div 3 * 1) + (P mod 3) * TrainSize div 3,
     1941            Pos.Y - Trunc(TrainSize div 6 * 1) + (P div 3) * TrainSize div 3);
     1942          ShapePos := RotatePoint(Pos, ShapePos, Angle);
     1943          DrawShape(Canvas, ShapePos, Shape, TrainSize div 3, Angle + Pi / 2);
     1944          Inc(P);
     1945        end;
    17381946      end;
    17391947    end;
     
    19772185    CanvasSize.Y - LineColorsDist - Canvas.TextHeight(Text) div 2, Text);
    19782186
     2187  // Draw unused carriages
     2188  Text := IntToStr(Carriages.GetUnusedCount);
     2189  Canvas.Draw(CanvasSize.X div 2 - Length(LineColors) div 2 * LineColorsDist - 200,
     2190    CanvasSize.Y - LineColorsDist - ImageCarriage.Bitmap.Height div 2, ImageCarriage.Bitmap);
     2191  Canvas.Brush.Style := bsClear;
     2192  Canvas.Font.Size := 14;
     2193  Canvas.Font.Color := Colors.Text;
     2194  Canvas.TextOut(CanvasSize.X div 2 - Length(LineColors) div 2 * LineColorsDist - 150 - Canvas.TextWidth(Text),
     2195    CanvasSize.Y - LineColorsDist - Canvas.TextHeight(Text) div 2, Text);
     2196
    19792197  // Status interface
    19802198  Text := IntToStr(ServedPassengerCount);
     
    20112229    ]);
    20122230  end;
     2231
     2232  // Show carriage grabbed by mouse
     2233  if Assigned(SelectedCarriage) then begin
     2234    Canvas.Brush.Color := Colors.Text; //SelectedTrain.Line.Color;
     2235    Canvas.Brush.Style := bsSolid;
     2236    Canvas.Pen.Style := psClear;
     2237    Pos := LastMousePos;
     2238    Angle := 0;
     2239
     2240    Canvas.Polygon([
     2241      RotatePoint(Pos, Point(Pos.X - TrainSize div 2, Pos.Y - TrainSize div 3), Angle),
     2242      RotatePoint(Pos, Point(Pos.X + TrainSize div 2, Pos.Y - TrainSize div 3), Angle),
     2243      RotatePoint(Pos, Point(Pos.X + TrainSize div 2, Pos.Y + TrainSize div 3), Angle),
     2244      RotatePoint(Pos, Point(Pos.X - TrainSize div 2, Pos.Y + TrainSize div 3), Angle)
     2245    ]);
     2246  end;
    20132247end;
    20142248
     
    20262260    LastNewWeekTime := Time;
    20272261    Trains.AddNew;
     2262    if Random < 0.2 then Carriages.AddNew;
    20282263    // TODO: Show notification screen with confirmation
    20292264    Redraw;
     
    21602395  I: Integer;
    21612396  FocusedTrack: TTrackLink;
     2397  FocusedTrain: TMetroTrain;
    21622398begin
    21632399  if Button = mbLeft then begin
     
    21932429      if Assigned(SelectedTrain) then begin
    21942430        SelectedTrain.TargetStation := nil;
    2195         SelectedTrain.BaseTrackPoint := nil;
     2431        SelectedTrain.TrackPosition.BaseTrackPoint := nil;
    21962432        if Assigned(SelectedTrain.Line) then begin
    21972433          SelectedTrain.Line.Trains.Remove(SelectedTrain);
    21982434          SelectedTrain.Line := nil;
     2435
     2436          // Remove train carriages
     2437          for I := SelectedTrain.Carriages.Count - 1 downto 0 do begin
     2438            SelectedTrain.Carriages[I].Train := nil;
     2439            SelectedTrain.Carriages.Delete(I);
     2440          end;
    21992441        end;
    22002442        FocusedTrack := GetTrackOnPos(View.PointDestToSrc(Position));
     
    22022444          SelectedTrain.Line := TMetroLine(FocusedTrack.Points[0].Track.Owner);
    22032445          SelectedTrain.Line.Trains.Add(SelectedTrain);
    2204           SelectedTrain.BaseTrackPoint := FocusedTrack.Points[0];
     2446          SelectedTrain.TrackPosition.BaseTrackPoint := FocusedTrack.Points[0];
    22052447        end else
    22062448        if Assigned(FocusedTrack.Points[1]) then begin
    22072449          SelectedTrain.Line := TMetroLine(FocusedTrack.Points[1].Track.Owner);
    22082450          SelectedTrain.Line.Trains.Add(SelectedTrain);
    2209           SelectedTrain.BaseTrackPoint := FocusedTrack.Points[1];
     2451          SelectedTrain.TrackPosition.BaseTrackPoint := FocusedTrack.Points[1];
    22102452        end;
    22112453        FocusedTrack.Free;
     2454      end;
     2455
     2456      // Place selected carriage if focused train
     2457      if Assigned(SelectedCarriage) then begin
     2458        if Assigned(SelectedCarriage.Train) then begin
     2459          SelectedCarriage.Train.Carriages.Remove(SelectedCarriage);
     2460          SelectedCarriage.Train := nil;
     2461        end;
     2462        FocusedTrain := GetTrainOnPos(View.PointDestToSrc(Position));
     2463        if Assigned(FocusedTrain) then begin
     2464          SelectedCarriage.Train := FocusedTrain;
     2465          FocusedTrain.Carriages.Add(SelectedCarriage);
     2466        end;
    22122467      end;
    22132468
     
    22382493  TrackStationUp := nil;
    22392494  SelectedTrain := nil;
     2495  SelectedCarriage := nil;
    22402496  Redraw;
    22412497end;
     
    22582514    end;
    22592515
     2516    // Carriage selection
     2517    SelectedCarriage := GetCarriageOnPos(View.PointDestToSrc(Position));
     2518    if Assigned(SelectedCarriage) then begin
     2519      Exit;
     2520    end;
     2521
    22602522    // Select unused train
    22612523    if (Distance(Position, Point(View.DestRect.Right div 2 - Length(LineColors) div 2 * LineColorsDist - 100,
    22622524      View.DestRect.Bottom - LineColorsDist)) < 30) and
    22632525    (Trains.GetUnusedCount > 0) then begin
    2264       SelectedTrain := Trains.GetUnusedTrain;
     2526      SelectedTrain := Trains.GetUnused;
     2527      Exit;
     2528    end;
     2529
     2530    // Select unused carriage
     2531    if (Distance(Position, Point(View.DestRect.Right div 2 - Length(LineColors) div 2 * LineColorsDist - 200,
     2532      View.DestRect.Bottom - LineColorsDist)) < 30) and
     2533    (Carriages.GetUnusedCount > 0) then begin
     2534      SelectedCarriage := Carriages.GetUnused;
    22652535      Exit;
    22662536    end;
     
    23122582  KeyEsc = 27;
    23132583  KeyF2 = 113;
     2584  KeyF3 = 114;
     2585  KeyF4 = 115;
    23142586begin
    23152587  if Key = KeyEsc then begin
     
    23252597    if State = gsRunning then begin
    23262598      State := gsGameOver;
     2599      Redraw;
     2600    end;
     2601  end else
     2602  if Key = KeyF3 then begin
     2603    if State = gsRunning then begin
     2604      Trains.AddNew;
     2605      Redraw;
     2606    end;
     2607  end else
     2608  if Key = KeyF4 then begin
     2609    if State = gsRunning then begin
     2610      Carriages.AddNew;
    23272611      Redraw;
    23282612    end;
     
    23882672begin
    23892673  RedrawPending := True;
     2674end;
     2675
     2676procedure TEngine.LoadFromRegistry(Context: TRegistryContext);
     2677begin
     2678  with TRegistryEx.Create do
     2679  try
     2680    CurrentContext := Context;
     2681    DarkMode := ReadBoolWithDefault('DarkMode', False);
     2682    HighestServedPassengerCount := ReadIntegerWithDefault('HighestPassengers', 0);
     2683    HighestServedDaysCount := ReadIntegerWithDefault('HighestDays', 0);
     2684  finally
     2685    Free;
     2686  end;
     2687end;
     2688
     2689procedure TEngine.SaveToRegistry(Context: TRegistryContext);
     2690begin
     2691  with TRegistryEx.Create do
     2692  try
     2693    CurrentContext := Context;
     2694
     2695    WriteBool('DarkMode', DarkMode);
     2696    WriteInteger('HighestPassengers', HighestServedPassengerCount);
     2697    WriteInteger('HighestDays', HighestServedDaysCount);
     2698  finally
     2699    Free;
     2700  end;
    23902701end;
    23912702
     
    24092720  View := TView.Create;
    24102721  Trains := TMetroTrains.Create;
     2722  Carriages := TMetroCarriages.Create;
    24112723  ImagePassenger := TImage.Create;
    24122724  ImageLocomotive := TImage.Create;
     2725  ImageCarriage := TImage.Create;
    24132726  ImagePlay := TImage.Create;
    24142727  ImagePlay.OnClick := ButtonPlay;
     
    24222735  //  ImageLocomotive.Picture.LoadFromFile(ImageLocomotiveName);
    24232736  MetaCanvas := TMetaCanvas.Create;
     2737  Cities := TCities.Create;
     2738  InitCities;
    24242739  Colors.Init(FDarkMode);
    24252740end;
     
    24272742destructor TEngine.Destroy;
    24282743begin
     2744  FreeAndNil(Cities);
    24292745  FreeAndNil(MetaCanvas);
    24302746  FreeAndNil(Trains);
     2747  FreeAndNil(Carriages);
    24312748  FreeAndNil(ImagePlay);
    24322749  FreeAndNil(ImageFastForward);
    24332750  FreeAndNil(ImagePause);
     2751  FreeAndNil(ImageCarriage);
    24342752  FreeAndNil(ImageLocomotive);
    24352753  FreeAndNil(ImagePassenger);
  • trunk/UMetroPassenger.pas

    r89 r93  
    99  TStationShape = (ssCircle, ssSquare, ssTriangle, ssStar, ssPlus, ssPentagon,
    1010    ssDiamond, ssQuarterCircle, ssHexagon, ssCross, ssHalfCircle, ssHeptagon);
     11  TStationShapeSet = set of TStationShape;
    1112
    1213  { TMetroPassenger }
  • trunk/UTrack.pas

    r91 r93  
    44
    55uses
    6   Classes, SysUtils, Math, Generics.Collections;
     6  Classes, SysUtils, Math, Generics.Collections, UGeometric;
    77
    88type
    99  TTrack = class;
     10  TTrackPoint = class;
    1011  TTrackPoints = class;
    1112  TTrackLink = class;
    1213  TTrackLinks = class;
     14
     15  { TTrackPosition }
     16
     17  TTrackPosition = record
     18    BaseTrackPoint: TTrackPoint;
     19    RelPos: Double;
     20    function GetVector: TVector;
     21    procedure Move(Distance: Double);
     22  end;
    1323
    1424  { TTrackPoint }
     
    93103implementation
    94104
    95 uses
    96   UGeometric;
    97 
    98105resourcestring
    99106  SAlreadyConnectedTrackPoint = 'Trying to connect already connected track point';
    100107  SAlreadyDisconnectedTrackPoint = 'Trying to disconnect not connected track point';
    101108  STrackPointNotFound = 'Track point %d not found';
     109
     110{ TTrackPosition }
     111
     112function TTrackPosition.GetVector: TVector;
     113var
     114  D: Integer;
     115  UpPoint: TTrackPoint;
     116begin
     117  Result.Position := Point(0, 0);
     118  if Assigned(BaseTrackPoint) then
     119  with BaseTrackPoint do begin
     120    UpPoint := BaseTrackPoint.GetNeighUp;
     121    if Assigned(UpPoint) then begin
     122      D := Distance(UpPoint.Position, Position);
     123      if D > 0 then begin
     124        Result.Direction := SubPoint(UpPoint.Position, Position);
     125        Result.Position := Point(Trunc(Position.X + Result.Direction.X * RelPos / D),
     126          Trunc(Position.Y + Result.Direction.Y * RelPos / D));
     127      end;
     128    end;
     129  end;
     130end;
     131
     132procedure TTrackPosition.Move(Distance: Double);
     133var
     134  Direction: Integer;
     135begin
     136  Direction := Sign(Distance);
     137  Distance := Abs(Distance);
     138  while Distance > 0 do begin
     139    if Direction > 0 then begin
     140      if RelPos + Distance < BaseTrackPoint.GetDistance then begin
     141        RelPos := RelPos + Distance;
     142        Distance := 0;
     143      end else begin
     144        if Assigned(BaseTrackPoint.GetNeighUp) then begin
     145          Distance := Distance - (BaseTrackPoint.GetDistance - RelPos);
     146          BaseTrackPoint := BaseTrackPoint.GetNeighUp;
     147          RelPos := 0;
     148        end else
     149          // Reverse direction at the end of track
     150          Direction := -Direction;
     151      end;
     152    end else
     153    if Direction < 0 then begin
     154      if RelPos - Distance >= 0 then begin
     155        RelPos := RelPos - Distance;
     156        Distance := 0;
     157      end else begin
     158        if Assigned(BaseTrackPoint.GetNeighDown) then begin
     159          Distance := Distance - RelPos;
     160          BaseTrackPoint := BaseTrackPoint.GetNeighDown;
     161          RelPos := BaseTrackPoint.GetDistance;
     162        end else
     163        // Reverse direction at the end of track
     164        Direction := -Direction;
     165      end;
     166    end;
     167  end;
     168end;
    102169
    103170{ TTrackLinks }
     
    349416begin
    350417  Index := Track.Points.IndexOf(Self);
    351   Result := Distance(Track.Points[Index + 1].Position, Track.Points[Index].Position);
     418  if Index + 1 < Track.Points.Count then begin
     419    Result := Distance(Track.Points[Index + 1].Position, Track.Points[Index].Position);
     420  end else Result := 0;
    352421end;
    353422
Note: See TracChangeset for help on using the changeset viewer.