Changeset 93 for trunk/UEngine.pas


Ignore:
Timestamp:
Sep 26, 2022, 10:39:03 PM (20 months ago)
Author:
chronos
Message:
  • Added: Support for train carriages.
  • Added: City support implementation preparation.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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);
Note: See TracChangeset for help on using the changeset viewer.