Changeset 17


Ignore:
Timestamp:
Mar 27, 2015, 11:19:18 PM (9 years ago)
Author:
chronos
Message:
  • Modified: Divided TMetroStation to TMapStation which are stations on map and TLineStation which are stations of TMetroLine. TMetroLine.LineStations items can refer to same TMapStation from First and Last item. Then line is closed and train can travel in round in single direction. Even in such case TMetroLine.LineStations.IndexOf(CurrentStation) can determine properly current station index.

Also refering to station from TTrackPoint was replaced from numeric index to object reference. So no absolute addressing is used and further improvement of TLineStation chain manipulation is simplified.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UEngine.pas

    r16 r17  
    1717  TMetroLine = class;
    1818  TMetroTrains = class;
    19 
    20   { TMetroStation }
    21 
    22   TMetroStation = class
     19  TTrackPoint = class;
     20  TLineStation = class;
     21
     22  { TMapStation }
     23
     24  TMapStation = class
    2325  private
    2426  public
     
    2931    Lines: TMetroLines;
    3032    ShapeDistance: array[TStationShape] of Integer;
    31     function GetBestStationForShape(Shape: TStationShape; Check: TMetroStation;
    32       CurrentStationIndex: Integer): Boolean;
     33    function GetBestStationForShape(Shape: TStationShape; Check, Current: TLineStation): Boolean;
    3334    constructor Create;
    3435    destructor Destroy; override;
    3536  end;
    3637
    37   { TMetroStations }
    38 
    39   TMetroStations = class(TObjectList)
     38  { TMapStations }
     39
     40  TMapStations = class(TObjectList)
    4041    Engine: TEngine;
    41     function AddNew: TMetroStation;
     42    function AddNew: TMapStation;
     43  end;
     44
     45  TLineStation = class
     46    Line: TMetroLine;
     47    MapStation: TMapStation;
     48    TrackPoint: TTrackPoint;
     49  end;
     50
     51  { TLineStations }
     52
     53  TLineStations = class(TObjectList)
     54    Line: TMetroLine;
     55    function SearchMapStation(Station: TMapStation): TLineStation;
    4256  end;
    4357
    4458  TTrackPoint = class
    4559    Line: TMetroLine;
    46     StationIndex: Integer;
     60    LineStation: TLineStation;
    4761    Point: TPoint;
    4862    Pending: Boolean;
     
    5872    Engine: TEngine;
    5973    Color: TColor;
    60     Stations: TMetroStations;
     74    LineStations: TLineStations;
    6175    Trains: TMetroTrains;
    6276    TrackPoints: TTrackPoints;
    63     procedure ConnectStation(Station: TMetroStation);
    64     procedure DisconnectStation(Station: TMetroStation);
    65     procedure AddTrack(P1, P2: TPoint; StationIndex: Integer);
     77    procedure ConnectStation(Station: TMapStation);
     78    procedure DisconnectStation(Station: TMapStation);
     79    procedure RouteTrack(TP1, TP2: TTrackPoint);
    6680    function GetTrackLength: Integer;
    67     function GetStationTrackPos(StationIndex: Integer): Integer;
     81    function GetStationTrackPos(LineStation: TLineStation): Integer;
    6882    constructor Create;
    6983    destructor Destroy; override;
     
    8498  private
    8599    LastPosDelta: Integer;
    86     function GetTargetStation: TMetroStation;
    87100  public
    88101    Passengers: TMetroPassengers;
     
    93106    InStation: Boolean;
    94107    StationStopTime: TDateTime;
    95     TargetStationIndex: Integer;
     108    TargetStation: TLineStation;
    96109    function GetPosition: TPoint;
    97110    function GetAngle: Double;
    98111    constructor Create;
    99112    destructor Destroy; override;
    100     property TargetStation: TMetroStation read GetTargetStation;
    101113  end;
    102114
     
    112124    Engine: TEngine;
    113125    Shape: TStationShape;
    114     Station: TMetroStation;
     126    Station: TMapStation;
    115127    Train: TMetroTrain;
    116128  end;
     
    138150  private
    139151    LastMousePos: TPoint;
    140     LastSelectedStation: TMetroStation;
     152    LastSelectedStation: TMapStation;
    141153    MouseHold: Boolean;
    142154    LastNewStationTime: TDateTime;
     
    149161    FTime: TDateTime;
    150162    function GetExistStationShapes: TStationShapeSet;
    151     function GetStationOnPos(Pos: TPoint): TMetroStation;
     163    function GetStationOnPos(Pos: TPoint): TMapStation;
    152164    function GetLineOnPos(Pos: TPoint): TMetroLine;
    153165    procedure DrawLine(Canvas: TCanvas; Pos: TPoint);
     
    157169    procedure DrawTrains(Canvas: TCanvas);
    158170    procedure ComputeShapeDistance;
    159     procedure ComputeShapeDistanceStation(Station: TMetroStation;
     171    procedure ComputeShapeDistanceStation(Station: TMapStation;
    160172      UpdatedShape: TStationShape; Distance: Integer);
    161173    procedure TrainMovement;
     174    function GetUnusedLine: TMetroLine;
    162175  public
    163176    Passengers: TMetroPassengers;
    164     Stations: TMetroStations;
     177    Stations: TMapStations;
    165178    Lines: TMetroLines;
    166179    Trains: TMetroTrains;
     
    169182    View: TView;
    170183    SelectedLine: TMetroLine;
    171     SelectedStation: TMetroStation;
     184    SelectedStation: TMapStation;
    172185    ServedPassengerCount: Integer;
    173186    State: TGameState;
     
    206219  UGeometric;
    207220
     221{ TLineStations }
     222
     223function TLineStations.SearchMapStation(Station: TMapStation): TLineStation;
     224var
     225  I: Integer;
     226begin
     227  I := 0;
     228  while (I < Count) and (TLineStation(Items[I]).MapStation <> Station) do Inc(I);
     229  if I < Count then Result := TLineStation(Items[I])
     230    else Result := nil;
     231end;
     232
    208233{ TMetroPassengers }
    209234
     
    243268end;
    244269
    245 { TMetroStations }
    246 
    247 function TMetroStations.AddNew: TMetroStation;
     270{ TMapStations }
     271
     272function TMapStations.AddNew: TMapStation;
    248273var
    249274  D: Integer;
     
    256281  Step = 20;
    257282begin
    258   Result := TMetroStation.Create;
     283  Result := TMapStation.Create;
    259284  Result.Engine := Engine;
    260285  Angle := Random * 2 * Pi;
     
    267292    MinD := High(Integer);
    268293    for I := 0 to Engine.Stations.Count - 1 do begin
    269       D := Distance(TMetroStation(Engine.Stations[I]).Position, Result.Position);
     294      D := Distance(TMapStation(Engine.Stations[I]).Position, Result.Position);
    270295      if D < MinD then MinD := D;
    271296    end;
     
    301326{ TMetroLine }
    302327
    303 procedure TMetroLine.ConnectStation(Station: TMetroStation);
     328procedure TMetroLine.ConnectStation(Station: TMapStation);
    304329var
    305330  Train: TMetroTrain;
     331  NewTrackPoint: TTrackPoint;
     332  NewLineStation: TLineStation;
     333begin
     334  NewLineStation := TLineStation.Create;
     335  NewLineStation.Line := Self;
     336  NewLineStation.MapStation := Station;
     337  LineStations.Add(NewLineStation);
     338  Station.Lines.Add(Self);
     339
     340  NewTrackPoint := TTrackPoint.Create;
     341  NewTrackPoint.LineStation := NewLineStation;
     342  NewTrackPoint.Point := Station.Position;
     343  NewTrackPoint.Line := TrackPoints.Line;
     344  TrackPoints.Add(NewTrackPoint);
     345
     346  NewLineStation.TrackPoint := NewTrackPoint;
     347
     348  if LineStations.Count >= 2 then
     349    RouteTrack(TLineStation(LineStations[LineStations.Count - 2]).TrackPoint, NewLineStation.TrackPoint);
     350
     351  // Place one train if at least two stations present
     352  if (LineStations.Count = 2) then begin
     353    Train := Engine.Trains.GetUnusedTrain;
     354    if Assigned(Train) then begin
     355      Train.Line := Self;
     356      Train.TargetStation := TLineStation(LineStations[0]);
     357      Trains.Add(Train);
     358    end;
     359  end;
     360  Engine.ComputeShapeDistance;
     361end;
     362
     363procedure TMetroLine.DisconnectStation(Station: TMapStation);
     364var
     365  I: Integer;
    306366  StationIndex: Integer;
    307   NewTrackPoint: TTrackPoint;
    308 begin
    309   Stations.Add(Station);
    310   Station.Lines.Add(Self);
    311   StationIndex := Stations.Count - 1;
    312   if Stations.Count = 1 then begin
    313     NewTrackPoint := TTrackPoint.Create;
    314     NewTrackPoint.StationIndex := StationIndex;
    315     NewTrackPoint.Point := Station.Position;
    316     NewTrackPoint.Line := TrackPoints.Line;
    317     TrackPoints.Add(NewTrackPoint);
    318   end else begin
    319      if Stations.Count > 1 then
    320        AddTrack(TMetroStation(Stations[Stations.Count - 2]).Position, Station.Position, StationIndex);
    321        // Place one train if at least two stations present
    322        if (Stations.Count = 2) then begin
    323          Train := Engine.Trains.GetUnusedTrain;
    324          if Assigned(Train) then begin
    325            Train.Line := Self;
    326            Train.TargetStationIndex := 0;
    327            Trains.Add(Train);
    328          end;
    329        end;
    330   end;
    331   Engine.ComputeShapeDistance;
    332 end;
    333 
    334 procedure TMetroLine.DisconnectStation(Station: TMetroStation);
    335 var
    336   I: Integer;
    337   StationIndex: Integer;
    338 begin
    339   if (Stations.Count > 0) and (Stations.Last = Station) then begin
    340     StationIndex := Stations.Count - 1;
    341     Stations.Delete(StationIndex);
     367begin
     368  if (LineStations.Count > 0) and (TLineStation(LineStations.Last).MapStation = Station) then begin
     369    StationIndex := LineStations.Count - 1;
     370    LineStations.Delete(StationIndex);
    342371    Station.Lines.Remove(Self);
    343     if Stations.Count > 0 then begin
     372    if LineStations.Count > 0 then begin
    344373      while (TrackPoints.Count > 0) and (not ComparePoint(TTrackPoint(TrackPoints.Last).Point,
    345         TMetroStation(Stations.Last).Position)) do
     374        TLineStation(LineStations.Last).MapStation.Position)) do
    346375        TrackPoints.Delete(TrackPoints.Count - 1);
    347376    end else TrackPoints.Clear;
     377
    348378    // Remove trains if less then two stations
    349     if Stations.Count < 2 then
     379    if LineStations.Count < 2 then
    350380      for I := Trains.Count - 1 downto 0 do begin
    351381        TMetroTrain(Trains[I]).Line := nil;
     
    356386end;
    357387
    358 procedure TMetroLine.AddTrack(P1, P2: TPoint; StationIndex: Integer);
    359 var
     388procedure TMetroLine.RouteTrack(TP1, TP2: TTrackPoint);
     389var
     390  NewTrackPoint: TTrackPoint;
    360391  Delta: TPoint;
    361   NewTrackPoint: TTrackPoint;
    362 begin
     392  P1, P2: TPoint;
     393  Index1, Index2: Integer;
     394begin
     395  Index1 := TrackPoints.IndexOf(TP1);
     396  Index2 := TrackPoints.IndexOf(TP2);
     397  if Index2 <> Index1 + 1 then
     398    raise Exception.Create('Supported only two neighbor track points for routing');
     399  P1 := TTrackPoint(TrackPoints[Index1]).Point;
     400  P2 := TTrackPoint(TrackPoints[Index2]).Point;
     401  NewTrackPoint := TTrackPoint.Create;
     402  NewTrackPoint.Line := Self;
    363403  Delta := Point(P2.X - P1.X, P2.Y - P1.Y);
    364404  if Abs(Delta.X) > Abs(Delta.Y) then begin
    365     NewTrackPoint := TTrackPoint.Create;
    366     NewTrackPoint.Line := TrackPoints.Line;
    367405    NewTrackPoint.Point := Point(P2.X - Sign(Delta.X) * Abs(Delta.Y), P1.Y);
    368     NewTrackPoint.StationIndex := StationIndex - 1;
    369     TrackPoints.Add(NewTrackPoint);
    370406  end else begin
    371     NewTrackPoint := TTrackPoint.Create;
    372     NewTrackPoint.Line := TrackPoints.Line;
    373407    NewTrackPoint.Point := Point(P1.X, P2.Y - Sign(Delta.Y) * Abs(Delta.X));
    374     NewTrackPoint.StationIndex := StationIndex - 1;
    375     TrackPoints.Add(NewTrackPoint);
    376   end;
    377   NewTrackPoint := TTrackPoint.Create;
    378   NewTrackPoint.Line := TrackPoints.Line;
    379   NewTrackPoint.Point := P2;
    380   NewTrackPoint.StationIndex := StationIndex;
    381   TrackPoints.Add(NewTrackPoint);
     408  end;
     409  TrackPoints.Insert(Index1 + 1, NewTrackPoint);
    382410end;
    383411
     
    392420end;
    393421
    394 function TMetroLine.GetStationTrackPos(StationIndex: Integer): Integer;
     422function TMetroLine.GetStationTrackPos(LineStation: TLineStation): Integer;
    395423var
    396424  I: Integer;
     
    400428    if I > 0 then
    401429      Result := Result + Distance(TTrackPoint(TrackPoints[I]).Point, TTrackPoint(TrackPoints[I - 1]).Point);
    402     if TTrackPoint(TrackPoints[I]).StationIndex = StationIndex then Break;
     430    if TTrackPoint(TrackPoints[I]).LineStation = LineStation then Break;
    403431  end;
    404432end;
     
    406434constructor TMetroLine.Create;
    407435begin
    408   Stations := TMetroStations.Create;
    409   Stations.OwnsObjects := False;
     436  LineStations := TLineStations.Create;
     437  LineStations.OwnsObjects := False;
    410438  Trains := TMetroTrains.Create;
    411439  Trains.OwnsObjects := False;
     
    418446  TrackPoints.Free;
    419447  Trains.Free;
    420   Stations.Free;
     448  LineStations.Free;
    421449  inherited Destroy;
    422450end;
     
    425453begin
    426454  Result := False;
    427   if Stations.Count >= 2 then
    428     Result := (Stations.Last = Stations.First);
     455  if LineStations.Count >= 2 then
     456    Result := (TLineStation(LineStations.Last).MapStation = TLineStation(LineStations.First).MapStation);
    429457end;
    430458
    431459{ TMetroTrain }
    432 
    433 function TMetroTrain.GetTargetStation: TMetroStation;
    434 begin
    435   Result := nil;
    436   if Assigned(Line) then
    437   if (TargetStationIndex >= 0) and (TargetStationIndex < Line.Stations.Count) then
    438     Result := TMetroStation(Line.Stations[TargetStationIndex]);
    439 end;
    440460
    441461function TMetroTrain.GetPosition: TPoint;
     
    502522end;
    503523
    504 { TMetroStation }
    505 
    506 function TMetroStation.GetBestStationForShape(Shape: TStationShape;
    507   Check: TMetroStation; CurrentStationIndex: Integer): Boolean;
     524{ TMapStation }
     525
     526function TMapStation.GetBestStationForShape(Shape: TStationShape;
     527  Check, Current: TLineStation): Boolean;
    508528var
    509529  I: Integer;
     
    513533  DirectionUp: Boolean;
    514534  DirectionDown: Boolean;
    515   NextStationUp: TMetroStation;
    516   NextStationDown: TMetroStation;
     535  NextStationUp: TLineStation;
     536  NextStationDown: TLineStation;
    517537begin
    518538  Distance := High(Integer);
    519539  for I := 0 to Lines.Count - 1 do
    520540  with TMetroLine(Lines[I]) do begin
    521     StationIndex := CurrentStationIndex;
     541    StationIndex := LineStations.IndexOf(Current);
    522542    if IsCircular then begin
    523543      DirectionUp := False;
     
    528548      end;
    529549      if StationIndex = 0 then
    530         NextStationDown := TMetroStation(Stations[Stations.Count - 2])
     550        NextStationDown := TLineStation(LineStations[LineStations.Count - 2])
    531551      else
    532552      if StationIndex > 0 then
    533         NextStationDown := TMetroStation(Stations[StationIndex - 1]);
    534 
    535       if (StationIndex >= 0) and (StationIndex = Stations.Count - 1) then
    536         NextStationUp := TMetroStation(Stations[1])
     553        NextStationDown := TLineStation(LineStations[StationIndex - 1]);
     554
     555      if (StationIndex >= 0) and (StationIndex = LineStations.Count - 1) then
     556        NextStationUp := TLineStation(LineStations[1])
    537557      else
    538       if (StationIndex >= 0) and (StationIndex < Stations.Count - 1) then
    539         NextStationUp := TMetroStation(Stations[StationIndex + 1]);
     558      if (StationIndex >= 0) and (StationIndex < LineStations.Count - 1) then
     559        NextStationUp := TLineStation(LineStations[StationIndex + 1]);
    540560    end else begin
    541561      if StationIndex > 0 then begin
    542562        DirectionDown := True;
    543         NextStationDown := TMetroStation(Stations[StationIndex - 1])
     563        NextStationDown := TLineStation(LineStations[StationIndex - 1])
    544564      end else DirectionDown := False;
    545       if (StationIndex >= 0) and (StationIndex < Stations.Count - 1) then begin
     565      if (StationIndex >= 0) and (StationIndex < LineStations.Count - 1) then begin
    546566        DirectionUp := True;
    547         NextStationUp := TMetroStation(Stations[StationIndex + 1]);
     567        NextStationUp := TLineStation(LineStations[StationIndex + 1]);
    548568      end else DirectionUp := False;
    549569    end;
    550     if DirectionDown and (NextStationDown.ShapeDistance[Shape] <> -1) and
    551       (NextStationDown.ShapeDistance[Shape] < Distance) then begin
    552       Distance := NextStationDown.ShapeDistance[Shape];
    553     end;
    554     if DirectionUp and (NextStationUp.ShapeDistance[Shape] <> -1) and
    555       (NextStationUp.ShapeDistance[Shape] < Distance) then begin
    556       Distance := NextStationUp.ShapeDistance[Shape];
    557     end;
    558   end;
    559   Result := Check.ShapeDistance[Shape] = Distance;
    560 end;
    561 
    562 constructor TMetroStation.Create;
     570    if DirectionDown and (NextStationDown.MapStation.ShapeDistance[Shape] <> -1) and
     571      (NextStationDown.MapStation.ShapeDistance[Shape] < Distance) then begin
     572      Distance := NextStationDown.MapStation.ShapeDistance[Shape];
     573    end;
     574    if DirectionUp and (NextStationUp.MapStation.ShapeDistance[Shape] <> -1) and
     575      (NextStationUp.MapStation.ShapeDistance[Shape] < Distance) then begin
     576      Distance := NextStationUp.MapStation.ShapeDistance[Shape];
     577    end;
     578  end;
     579  Result := Check.MapStation.ShapeDistance[Shape] = Distance;
     580end;
     581
     582constructor TMapStation.Create;
    563583begin
    564584  Passengers := TMetroPassengers.Create;
     
    568588end;
    569589
    570 destructor TMetroStation.Destroy;
     590destructor TMapStation.Destroy;
    571591begin
    572592  Lines.Free;
     
    583603  Result := [];
    584604  for I := 0 to Stations.Count - 1 do
    585   with TMetroStation(Stations[I]) do begin
     605  with TMapStation(Stations[I]) do begin
    586606    Result := Result + [Shape];
    587607  end;
    588608end;
    589609
    590 function TEngine.GetStationOnPos(Pos: TPoint): TMetroStation;
     610function TEngine.GetStationOnPos(Pos: TPoint): TMapStation;
    591611var
    592612  I: Integer;
     
    595615begin
    596616  I := 0;
    597   while (I < Stations.Count) and (Distance(TMetroStation(Stations[I]).Position, Pos) > ClickDistance) do Inc(I);
    598   if I < Stations.Count then Result := TMetroStation(Stations[I])
     617  while (I < Stations.Count) and (Distance(TMapStation(Stations[I]).Position, Pos) > ClickDistance) do Inc(I);
     618  if I < Stations.Count then Result := TMapStation(Stations[I])
    599619    else Result := nil;
    600620end;
     
    727747  // Reset all distances
    728748  for I := 0 to Stations.Count - 1 do
    729   with TMetroStation(Stations[I]) do begin
     749  with TMapStation(Stations[I]) do begin
    730750    for S := Low(ShapeDistance) to High(ShapeDistance) do
    731751      ShapeDistance[S] := -1;
     
    735755  // Distace 0 means that station is final target
    736756  for I := 0 to Stations.Count - 1 do
    737   with TMetroStation(Stations[I]) do begin
    738     ComputeShapeDistanceStation(TMetroStation(Stations[I]), Shape, 0);
    739   end;
    740 end;
    741 
    742 procedure TEngine.ComputeShapeDistanceStation(Station: TMetroStation;
     757  with TMapStation(Stations[I]) do begin
     758    ComputeShapeDistanceStation(TMapStation(Stations[I]), Shape, 0);
     759  end;
     760end;
     761
     762procedure TEngine.ComputeShapeDistanceStation(Station: TMapStation;
    743763  UpdatedShape: TStationShape; Distance: Integer);
    744764var
     
    756776      with TMetroLine(Lines[I]) do
    757777        for StationIndex := 0 to Stations.Count - 1 do
    758         if TMetroStation(Stations[StationIndex]) = Station then begin
     778        if TMapStation(Stations[StationIndex]) = Station then begin
    759779        if not IsCircular then begin
    760780          // Update for all adjecent stations
    761781          if StationIndex > 0 then
    762             ComputeShapeDistanceStation(TMetroStation(Stations[StationIndex - 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     782            ComputeShapeDistanceStation(TMapStation(Stations[StationIndex - 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
    763783          if (StationIndex >= 0) and (StationIndex < Stations.Count - 1) then
    764             ComputeShapeDistanceStation(TMetroStation(Stations[StationIndex + 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     784            ComputeShapeDistanceStation(TMapStation(Stations[StationIndex + 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
    765785        end else begin
    766786          // If circular then trains might go in single direction so passengers
     
    775795          if DirectionUp then begin
    776796            if StationIndex = 0 then
    777               ComputeShapeDistanceStation(TMetroStation(Stations[Stations.Count - 2]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     797              ComputeShapeDistanceStation(TMapStation(Stations[Stations.Count - 2]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
    778798            if StationIndex > 0 then
    779               ComputeShapeDistanceStation(TMetroStation(Stations[StationIndex - 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     799              ComputeShapeDistanceStation(TMapStation(Stations[StationIndex - 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
    780800          end;
    781801          if DirectionDown then begin
    782802            if (StationIndex >= 0) and (StationIndex = Stations.Count - 1) then
    783               ComputeShapeDistanceStation(TMetroStation(Stations[1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     803              ComputeShapeDistanceStation(TMapStation(Stations[1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
    784804            if (StationIndex >= 0) and (StationIndex < Stations.Count - 1) then
    785               ComputeShapeDistanceStation(TMetroStation(Stations[StationIndex + 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     805              ComputeShapeDistanceStation(TMapStation(Stations[StationIndex + 1]), UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
    786806          end;
    787807        end;
     
    794814var
    795815  I: Integer;
    796   CurrentStationIndex: Integer;
    797   CurrentStation: TMetroStation;
     816  CurrentStation: TLineStation;
    798817  P: Integer;
    799818  Passenger: TMetroPassenger;
    800819  PosDelta: Integer;
     820  TargetStationIndex: Integer;
    801821begin
    802822  // Move trains
     
    806826      if InStation then begin
    807827        if (Now - StationStopTime) > OneSecond then begin
    808           CurrentStationIndex := TargetStationIndex;
    809           if CurrentStationIndex >= Line.Stations.Count then
    810             CurrentStationIndex := Line.Stations.Count - 1;
    811           CurrentStation := nil;
    812           if Assigned(Line) then
    813             if (CurrentStationIndex >= 0) and (CurrentStationIndex < Line.Stations.Count) then
    814           CurrentStation := TMetroStation(Line.Stations[CurrentStationIndex]);
     828          CurrentStation := TargetStation;
    815829
    816830          // Choose next target station
    817           TargetStationIndex := TargetStationIndex + Direction;
     831          TargetStationIndex := Line.LineStations.IndexOf(TargetStation) + Direction;
    818832          if TargetStationIndex < 0 then begin
    819             if Line.Stations.Last = Line.Stations.First then begin
    820               TargetStationIndex := Line.Stations.Count - 2;
    821               TrackPos := Line.GetStationTrackPos(Line.Stations.Count - 1);
     833            if Line.IsCircular then begin
     834              TargetStationIndex := Line.LineStations.Count - 2;
     835              TrackPos := Line.GetStationTrackPos(TLineStation(Line.LineStations.Last));
    822836            end else begin
    823837              TargetStationIndex := 1;
    824838              Direction := -Direction;
    825839            end;
    826           end else if TargetStationIndex >= Line.Stations.Count then begin
    827             if Line.Stations.Last = Line.Stations.First then begin
     840          end else if TargetStationIndex >= Line.LineStations.Count then begin
     841            if Line.IsCircular then begin
    828842              TargetStationIndex := 1;
    829843              TrackPos := 0;
    830844            end else begin
    831               TargetStationIndex := Line.Stations.Count - 2;
     845              TargetStationIndex := Line.LineStations.Count - 2;
    832846              Direction := -Direction;
    833847            end;
    834848          end;
     849          TargetStation := TLineStation(Line.LineStations[TargetStationIndex]);
    835850
    836851          // Unload passengers in target station
    837           if Assigned(CurrentStation) and (CurrentStationIndex < Line.Stations.Count) then
     852          if Assigned(CurrentStation) then
    838853          for P := Passengers.Count - 1 downto 0 do begin
    839             if TMetroPassenger(Passengers[P]).Shape = CurrentStation.Shape then begin
     854            if TMetroPassenger(Passengers[P]).Shape = CurrentStation.MapStation.Shape then begin
    840855              Passenger := TMetroPassenger(Passengers[P]);
    841856              Passengers.Delete(P);
     
    845860          end;
    846861          // Unload passengers to change line
    847           if Assigned(CurrentStation) and (CurrentStationIndex < Line.Stations.Count) then
     862          if Assigned(CurrentStation) then
    848863          for P := Passengers.Count - 1 downto 0 do begin
    849             if not CurrentStation.GetBestStationForShape(TMetroPassenger(Passengers[P]).Shape,
    850             TargetStation, CurrentStationIndex) then begin
     864            if not CurrentStation.MapStation.GetBestStationForShape(TMetroPassenger(Passengers[P]).Shape,
     865            TargetStation, CurrentStation) then begin
    851866              Passenger := TMetroPassenger(Passengers[P]);
    852867              Passengers.Delete(P);
    853               CurrentStation.Passengers.Add(Passenger);
    854               Passenger.Station := CurrentStation;
     868              CurrentStation.MapStation.Passengers.Add(Passenger);
     869              Passenger.Station := CurrentStation.MapStation;
    855870            end;
    856871          end;
    857872
    858873          // Load new passengers
    859           if Assigned(CurrentStation) and (CurrentStationIndex < Line.Stations.Count) then
    860           for P := CurrentStation.Passengers.Count - 1 downto 0 do begin
     874          if Assigned(CurrentStation) then
     875          for P := CurrentStation.MapStation.Passengers.Count - 1 downto 0 do begin
    861876            if (Passengers.Count < TrainPassengerCount) then begin
    862               Passenger := TMetroPassenger(CurrentStation.Passengers[P]);
    863               if CurrentStation.GetBestStationForShape(Passenger.Shape, TargetStation, CurrentStationIndex) then begin
     877              Passenger := TMetroPassenger(CurrentStation.MapStation.Passengers[P]);
     878              if CurrentStation.MapStation.GetBestStationForShape(Passenger.Shape,
     879            TargetStation, CurrentStation) then begin
    864880                Passenger.Station := nil;
    865                 CurrentStation.Passengers.Delete(P);
     881                CurrentStation.MapStation.Passengers.Delete(P);
    866882                Passengers.Add(Passenger);
    867883                Passenger.Train := TMetroTrain(Trains[I]);
     
    870886          end;
    871887
    872           LastPosDelta := Abs(TrackPos - Line.GetStationTrackPos(TargetStationIndex));
     888          LastPosDelta := Abs(TrackPos - Line.GetStationTrackPos(TargetStation));
    873889          InStation := False;
    874890        end;
    875891      end else begin
    876       TrackPos := TrackPos + Direction * TrainSpeed;
    877       if TrackPos < 0 then begin
    878         if Line.Stations.First = Line.Stations.Last then TrackPos := Line.GetTrackLength
    879           else TrackPos := 0;
    880       end else
    881       if TrackPos > Line.GetTrackLength then begin
    882         if Line.Stations.First = Line.Stations.Last then TrackPos := 0
    883           else TrackPos := Line.GetTrackLength;
     892        TrackPos := TrackPos + Direction * TrainSpeed;
     893        if TrackPos < 0 then begin
     894          if Line.IsCircular then TrackPos := Line.GetTrackLength
     895            else TrackPos := 0;
     896        end else
     897        if TrackPos > Line.GetTrackLength then begin
     898          if Line.IsCircular then TrackPos := 0
     899            else TrackPos := Line.GetTrackLength;
     900        end;
     901        PosDelta := Abs(TrackPos - Line.GetStationTrackPos(TargetStation));
     902        if PosDelta >= LastPosDelta then begin
     903          // We are getting far from station, stop at station
     904          TrackPos := Line.GetStationTrackPos(TargetStation);
     905          InStation := True;
     906          StationStopTime := Now;
     907        end;
     908        LastPosDelta := PosDelta;
    884909      end;
    885       PosDelta := Abs(TrackPos - Line.GetStationTrackPos(TargetStationIndex));
    886       if PosDelta >= LastPosDelta then begin
    887         // We are getting far from station, stop at station
    888         TrackPos := Line.GetStationTrackPos(TargetStationIndex);
    889         InStation := True;
    890         StationStopTime := Now;
    891       end;
    892       LastPosDelta := PosDelta;
    893       end;
    894     end;
    895   end;
     910    end;
     911  end;
     912end;
     913
     914function TEngine.GetUnusedLine: TMetroLine;
     915var
     916  I: Integer;
     917begin
     918  I := 0;
     919  while (I < Lines.Count) and (TMetroLine(Lines[I]).TrackPoints.Count > 0) do Inc(I);
     920  if I < Lines.Count then Result := TMetroLine(Lines[I])
     921    else Result := nil;
    896922end;
    897923
     
    9981024    LastNewPassengerTime := Now;
    9991025    for I := 0 to Stations.Count - 1 do
    1000     with TMetroStation(Stations[I]) do
     1026    with TMapStation(Stations[I]) do
    10011027    if Random < NewPassengerProbability then begin
    10021028      Passenger := Self.Passengers.AddNew;
    1003       Passenger.Station := TMetroStation(Stations[I]);
     1029      Passenger.Station := TMapStation(Stations[I]);
    10041030      Passengers.Add(Passenger);
    10051031
     
    10141040  // Game over
    10151041  for I := 0 to Stations.Count - 1 do
    1016   with TMetroStation(Stations[I]) do begin
     1042  with TMapStation(Stations[I]) do begin
    10171043    if Passengers.Count > MaxWaitingPassengers then State := gsGameOver;
    10181044  end;
     
    10241050procedure TEngine.MouseMove(Position: TPoint);
    10251051var
    1026   Station: TMetroStation;
     1052  Station: TMapStation;
    10271053begin
    10281054  LastMousePos := Position;
     
    10311057      Station := GetStationOnPos(Position);
    10321058      if not Assigned(LastSelectedStation) and Assigned(Station) then begin
    1033         if (SelectedLine.Stations.IndexOf(Station) = -1) then begin
     1059        if (SelectedLine.LineStations.SearchMapStation(Station) = nil) then begin
    10341060          SelectedLine.ConnectStation(Station);
    10351061          SelectedStation := Station;
    10361062        end else
    1037         if (SelectedLine.Stations.Count > 0) and (SelectedLine.Stations.Last = Station) then begin
     1063        if (SelectedLine.LineStations.Count > 0) and (TLineStation(SelectedLine.LineStations.Last).MapStation = Station) then begin
    10381064          SelectedLine.DisconnectStation(Station);
    1039           SelectedStation := TMetroStation(SelectedLine.Stations.Last);
    1040         end else if (SelectedLine.Stations.Count > 0) and (SelectedLine.Stations.First = Station) then begin
     1065          if SelectedLine.LineStations.Count > 0 then
     1066            SelectedStation := TLineStation(SelectedLine.LineStations.Last).MapStation
     1067            else SelectedStation := nil;
     1068        end else if (SelectedLine.LineStations.Count > 0) and (TLineStation(SelectedLine.LineStations.First).MapStation = Station) then begin
    10411069          SelectedLine.ConnectStation(Station);
    10421070          SelectedStation := Station;
     
    10501078procedure TEngine.MouseUp(Button: TMouseButton; Position: TPoint);
    10511079var
    1052   Station: TMetroStation;
     1080  Station: TMapStation;
    10531081  Line: TMetroLine;
    10541082  I: Integer;
     
    10731101procedure TEngine.MouseDown(Button: TMouseButton; Position: TPoint);
    10741102var
    1075   Station: TMetroStation;
     1103  Station: TMapStation;
    10761104  Line: TMetroLine;
    10771105  I: Integer;
     1106  NewLine: TMetroLine;
    10781107begin
    10791108  if Button = mbLeft then begin
     
    10871116      if not Assigned(SelectedLine) then
    10881117      for I := 0 to Lines.Count - 1 do
    1089       if TMetroLine(Lines[I]).Stations.Count = 0 then begin
     1118      if TMetroLine(Lines[I]).LineStations.Count = 0 then begin
    10901119        SelectedLine := TMetroLine(Lines[I]);
    10911120        Break;
     
    10991128      Exit;
    11001129    end;
     1130
     1131    // New track creation from selected station as start
     1132    Station := GetStationOnPos(Position);
     1133    if Assigned(Station) then begin
     1134      NewLine := GetUnusedLine;
     1135      if Assigned(NewLine) then begin
     1136        NewLine.ConnectStation(Station);
     1137        SelectedStation := Station;
     1138        LastSelectedStation := Station;
     1139      end;
     1140    end;
    11011141  end;
    11021142end;
     
    11061146  NewTrain: TMetroTrain;
    11071147  I: Integer;
    1108   NewStation: TMetroStation;
     1148  NewStation: TMapStation;
    11091149  InitialStationCount: Integer;
    11101150begin
     
    11431183constructor TEngine.Create;
    11441184begin
    1145   Stations := TMetroStations.Create;
     1185  Stations := TMapStations.Create;
    11461186  Stations.Engine := Self;
    11471187  Lines := TMetroLines.Create;
     
    12431283  Canvas.Pen.Width := 5;
    12441284  for I := 0 to Stations.Count - 1 do
    1245   with TMetroStation(Stations[I]) do begin
     1285  with TMapStation(Stations[I]) do begin
    12461286    Canvas.Pen.Style := psSolid;
    12471287    if Assigned(SelectedLine) and (Lines.IndexOf(SelectedLine) <> -1) then begin
Note: See TracChangeset for help on using the changeset viewer.