Changeset 127 for trunk/UEngine.pas


Ignore:
Timestamp:
Apr 25, 2023, 10:52:20 PM (13 months ago)
Author:
chronos
Message:
  • Added: Configurable station styles.
  • Added: Configurable map visual styles.
  • Added: Metro lines can be configured to be not movable.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UEngine.pas

    r126 r127  
    2020  TMetroTrain = class;
    2121
     22  TStationStyle = (ssShapes, ssLinear, ssAlpha);
     23
    2224  { TMapStation }
    2325
     
    2830  public
    2931    Engine: TEngine;
    30     Shape: TStationShape;
     32    DestinationIndex: TDestinationIndex;
    3133    Position: TPoint;
    3234    Passengers: TMetroPassengers;
    3335    Lines: TMetroLines;
    34     ShapeDistance: array[TStationShape] of Integer;
     36    DestinationDistance: array of Integer;
    3537    OverloadDuration: TDateTime;
    3638    IsTerminal: Boolean;
    3739    function GetMaxPassengers: Integer;
    38     function IsBestStationForShape(Shape: TStationShape; Check, Current: TLineStation): Boolean;
     40    function IsBestStationForShape(DestinationIndex: TDestinationIndex; Check, Current: TLineStation): Boolean;
    3941    procedure LoadFromXmlNode(Node: TDOMNode);
    4042    procedure SaveToXmlNode(Node: TDOMNode);
     
    183185  end;
    184186
     187  TVisualStyle = (vsLondon, vsPrague);
     188
    185189  { TEngine }
    186190
     
    189193    FDarkMode: Boolean;
    190194    FFullScreen: Boolean;
     195    FMovableTracks: Boolean;
    191196    FOnDarkModeChange: TNotifyEvent;
    192197    FOnExit: TNotifyEvent;
    193198    FOnFullScreenChange: TFullScrenChangeEvent;
    194199    FState: TGameState;
     200    FStationStyle: TStationStyle;
    195201    FTranslator: TTranslator;
     202    FVisualStyle: TVisualStyle;
    196203    LastMousePos: TPoint;
    197204    LastFocusedStation: TMapStation;
     
    210217    MenuCareer: TMenu;
    211218    MenuGame: TMenu;
     219    MenuCustomGame: TMenu;
    212220    LastState: TGameState;
    213221    TimePerSecond: TDateTime;
     
    220228    GrabbedTrainDirection: Integer;
    221229    LastGrabbedTrain: TMetroTrain;
     230    function GetMetroLineThickness: Integer;
    222231    function GetServedDaysCount: Integer;
     232    function DestinationIndexToText(DestinationIndex: TDestinationIndex): string;
     233    function DestinationIndexToShape(DestinationIndex: TDestinationIndex): TDestinationShape;
    223234    procedure ResizeView(Force: Boolean);
    224     function GetExistStationShapes: TStationShapeSet;
     235    function GetExistStationDestinationIndex(DestinationIndex: TDestinationIndex): Boolean;
    225236    function GetStationOnPos(Pos: TPoint): TMapStation;
    226237    function GetTrackOnPos(Pos: TPoint; out Intersect: TPoint): TTrackLink;
     
    229240    procedure DrawFrame(Canvas: TCanvas; Rect: TRect);
    230241    procedure DrawLine(Canvas: TCanvas; Pos: TPoint);
    231     procedure DrawShape(Canvas: TCanvas; Position: TPoint; Shape: TStationShape;
     242    procedure DrawShape(Canvas: TCanvas; Position: TPoint; Shape: TDestinationShape;
    232243      Size: Integer; Angle: Double);
    233244    procedure DrawClock(Canvas: TCanvas; CanvasSize: TPoint);
     
    244255    procedure DrawGrabbed(Canvas: TCanvas; CanvasSize: TPoint);
    245256    procedure ComputeShapeDistance;
    246     procedure ComputeShapeDistanceStation(Station: TMapStation;
    247       UpdatedShape: TStationShape; Distance: Integer);
     257    procedure ComputeDestinationIndexDistanceStation(Station: TMapStation;
     258      UpdatedDestinationIndex: TDestinationIndex; Distance: Integer);
    248259    procedure SetDarkMode(AValue: Boolean);
    249260    procedure SetFullScreen(AValue: Boolean);
     
    258269    procedure MenuItemCareer(Sender: TObject);
    259270    procedure MenuItemOptions(Sender: TObject);
     271    procedure MenuItemCustomGame(Sender: TObject);
     272    procedure MenuItemCustomPlay(Sender: TObject);
    260273    procedure MenuItemGameContinue(Sender: TObject);
    261274    procedure MenuItemGameExit(Sender: TObject);
     
    272285    procedure LanguageChanged(Sender: TObject);
    273286    procedure FullScreenChanged(Sender: TObject);
     287    procedure MovableTrackChanged(Sender: TObject);
     288    procedure StationStyleChanged(Sender: TObject);
     289    procedure VisualStyleChanged(Sender: TObject);
    274290    procedure UpdateInterface;
    275291    function GetImprovementText(Improvement: TMetroImprovement): string;
     
    288304    Trains: TMetroTrains;
    289305    Carriages: TMetroCarriages;
    290     ShapeCount: Integer;
     306    DestinationCount: Integer;
    291307    Map: TMap;
    292308    View: TView;
     
    344360    property ServedDaysCount: Integer read GetServedDaysCount;
    345361  published
     362    property MovableTracks: Boolean read FMovableTracks write FMovableTracks;
     363    property VisualStyle: TVisualStyle read FVisualStyle write FVisualStyle;
     364    property StationStyle: TStationStyle read FStationStyle write FStationStyle;
    346365    property DarkMode: Boolean read FDarkMode write SetDarkMode;
    347366    property FullScreen: Boolean read FFullScreen write SetFullScreen;
     
    402421  STrain = 'Train';
    403422  SPlay = 'Play';
     423  SCustomGame = 'Custom game';
    404424  SOptions = 'Options';
    405425  SExit = 'Exit';
     
    407427  SDarkMode = 'Dark mode';
    408428  SLanguage = 'Language';
     429  SMovableTrack = 'Movable track';
    409430  SCzech = 'Czech';
    410431  SEnglish = 'English';
     
    425446  SUnlockedCity = 'City %s is now unlocked.';
    426447  SWrongFileFormat = 'Wrong file format';
     448  SVisualStyle = 'Visual style';
     449  SStationStyle = 'Station style';
    427450
    428451  // Cities
     
    435458  SSeoul = 'Seoul';
    436459  SBeijing = 'Beijing';
     460
     461  // Station styles
     462  SShapes = 'Shapes';
     463  SLinear = 'Linear';
     464  SAlpha = 'Alpha';
     465
     466var
     467  StationStyleText: array[TStationStyle] of string = (SShapes, SLinear, SAlpha);
     468  VisualStyleText: array[TVisualStyle] of string = (SLondon, SPrague);
    437469
    438470{ TClock }
     
    659691  until (MinD > StationMinDistance) or
    660692    (Pass > 1000) or (Engine.Stations.Count = 0);
    661   Result.Shape := TStationShape(Random(Integer(Engine.ShapeCount)));
     693  Result.DestinationIndex := Random(Engine.DestinationCount);
    662694  Add(Result);
    663695  Engine.ComputeShapeDistance;
     
    11391171        // Get orthogonal angle
    11401172        HAngle := (Angle + Pi / 2) mod Pi;
    1141         NewShift.X := Trunc(MetroLineThickness * Cos(HAngle) * (J - (TrackLinks.Count - 1) / 2));
    1142         NewShift.Y := Trunc(MetroLineThickness * Sin(HAngle) * (J - (TrackLinks.Count - 1) / 2));
     1173        NewShift.X := Trunc(Engine.GetMetroLineThickness * Cos(HAngle) * (J - (TrackLinks.Count - 1) / 2));
     1174        NewShift.Y := Trunc(Engine.GetMetroLineThickness * Sin(HAngle) * (J - (TrackLinks.Count - 1) / 2));
    11431175        Shift := NewShift;
    11441176      end;
     
    11671199end;
    11681200
    1169 function TMapStation.IsBestStationForShape(Shape: TStationShape;
     1201function TMapStation.IsBestStationForShape(DestinationIndex: TDestinationIndex;
    11701202  Check, Current: TLineStation): Boolean;
    11711203var
     
    12131245      end else DirectionUp := False;
    12141246    end;
    1215     if DirectionDown and (NextStationDown.MapStation.ShapeDistance[Shape] <> -1) and
    1216       (NextStationDown.MapStation.ShapeDistance[Shape] < Distance) then begin
    1217       Distance := NextStationDown.MapStation.ShapeDistance[Shape];
    1218     end;
    1219     if DirectionUp and (NextStationUp.MapStation.ShapeDistance[Shape] <> -1) and
    1220       (NextStationUp.MapStation.ShapeDistance[Shape] < Distance) then begin
    1221       Distance := NextStationUp.MapStation.ShapeDistance[Shape];
    1222     end;
    1223   end;
    1224   Result := (Check.MapStation.ShapeDistance[Shape] <> -1) and
    1225     (Check.MapStation.ShapeDistance[Shape] <= Distance);
     1247    if DirectionDown and (NextStationDown.MapStation.DestinationDistance[DestinationIndex] <> -1) and
     1248      (NextStationDown.MapStation.DestinationDistance[DestinationIndex] < Distance) then begin
     1249      Distance := NextStationDown.MapStation.DestinationDistance[DestinationIndex];
     1250    end;
     1251    if DirectionUp and (NextStationUp.MapStation.DestinationDistance[DestinationIndex] <> -1) and
     1252      (NextStationUp.MapStation.DestinationDistance[DestinationIndex] < Distance) then begin
     1253      Distance := NextStationUp.MapStation.DestinationDistance[DestinationIndex];
     1254    end;
     1255  end;
     1256  Result := (Check.MapStation.DestinationDistance[DestinationIndex] <> -1) and
     1257    (Check.MapStation.DestinationDistance[DestinationIndex] <= Distance);
    12261258end;
    12271259
     
    12301262  Position.X := ReadInteger(Node, 'PositionX', Position.X);
    12311263  Position.Y := ReadInteger(Node, 'PositionY', Position.Y);
    1232   Shape := TStationShape(ReadInteger(Node, 'Shape', Integer(Shape)));
     1264  DestinationIndex := ReadInteger(Node, 'DestinationIndex', Integer(DestinationIndex));
    12331265  IsTerminal := ReadBoolean(Node, 'IsTerminal', IsTerminal);
    12341266end;
     
    12381270  WriteInteger(Node, 'PositionX', Position.X);
    12391271  WriteInteger(Node, 'PositionY', Position.Y);
    1240   WriteInteger(Node, 'Shape', Integer(Shape));
     1272  WriteInteger(Node, 'DestinationIndex', DestinationIndex);
    12411273  WriteBoolean(Node, 'IsTerminal', IsTerminal);
    12421274end;
     
    12481280  Lines := TMetroLines.Create;
    12491281  Lines.OwnsObjects := False;
     1282  SetLength(DestinationDistance, Integer(High(TDestinationShape)) + 1);
    12501283end;
    12511284
     
    12871320end;
    12881321
     1322function TEngine.GetMetroLineThickness: Integer;
     1323begin
     1324  case VisualStyle of
     1325    vsLondon: Result := MetroLineThickness;
     1326    vsPrague: Result := Round(3 * MetroLineThickness);
     1327  end;
     1328end;
     1329
    12891330function TEngine.GetServedDaysCount: Integer;
    12901331begin
     
    12921333end;
    12931334
    1294 function TEngine.GetExistStationShapes: TStationShapeSet;
     1335function TEngine.GetExistStationDestinationIndex(
     1336  DestinationIndex: TDestinationIndex): Boolean;
    12951337var
    12961338  Station: TMapStation;
    12971339begin
    1298   Result := [];
     1340  Result := False;
    12991341  for Station in Stations do
    1300     Result := Result + [Station.Shape];
     1342    if Station.DestinationIndex = DestinationIndex then
     1343      Result := True;
    13011344end;
    13021345
     
    14091452end;
    14101453
    1411 procedure TEngine.DrawShape(Canvas: TCanvas; Position: TPoint; Shape: TStationShape;
     1454procedure TEngine.DrawShape(Canvas: TCanvas; Position: TPoint; Shape: TDestinationShape;
    14121455  Size: Integer; Angle: Double);
    14131456var
     
    15391582procedure TEngine.ComputeShapeDistance;
    15401583var
    1541   S: TStationShape;
     1584  S: TDestinationIndex;
    15421585  Station: TMapStation;
    15431586begin
     
    15451588  for Station in Stations do
    15461589  with Station do begin
    1547     for S := Low(ShapeDistance) to High(ShapeDistance) do
    1548       ShapeDistance[S] := -1;
     1590    for S := Low(DestinationDistance) to High(DestinationDistance) do
     1591      DestinationDistance[S] := -1;
    15491592  end;
    15501593
     
    15531596  for Station in Stations do
    15541597  with Station do begin
    1555     ComputeShapeDistanceStation(Station, Shape, 0);
    1556   end;
    1557 end;
    1558 
    1559 procedure TEngine.ComputeShapeDistanceStation(Station: TMapStation;
    1560   UpdatedShape: TStationShape; Distance: Integer);
     1598    ComputeDestinationIndexDistanceStation(Station, DestinationIndex, 0);
     1599  end;
     1600end;
     1601
     1602procedure TEngine.ComputeDestinationIndexDistanceStation(Station: TMapStation;
     1603  UpdatedDestinationIndex: TDestinationIndex; Distance: Integer);
    15611604var
    15621605  I: Integer;
     
    15671610begin
    15681611  with Station do begin
    1569     if (Distance < ShapeDistance[UpdatedShape]) or (ShapeDistance[UpdatedShape] = -1) then begin
    1570       ShapeDistance[UpdatedShape] := Distance;
     1612    if (Distance < DestinationDistance[UpdatedDestinationIndex]) or (DestinationDistance[UpdatedDestinationIndex] = -1) then begin
     1613      DestinationDistance[UpdatedDestinationIndex] := Distance;
    15711614      // Do for all lines connected to station
    15721615      for I := 0 to Lines.Count - 1 do
     
    15771620          // Update for all adjecent stations
    15781621          if StationIndex > 0 then
    1579             ComputeShapeDistanceStation(LineStations[StationIndex - 1].MapStation,
    1580             UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     1622            ComputeDestinationIndexDistanceStation(LineStations[StationIndex - 1].MapStation,
     1623            UpdatedDestinationIndex, Station.DestinationDistance[UpdatedDestinationIndex] + 1);
    15811624          if (StationIndex >= 0) and (StationIndex < LineStations.Count - 1) then
    1582             ComputeShapeDistanceStation(LineStations[StationIndex + 1].MapStation,
    1583             UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     1625            ComputeDestinationIndexDistanceStation(LineStations[StationIndex + 1].MapStation,
     1626            UpdatedDestinationIndex, Station.DestinationDistance[UpdatedDestinationIndex] + 1);
    15841627        end else begin
    15851628          // If circular then trains might go in single direction so passengers
     
    15911634            if Trains[T].Direction = -1 then DirectionDown := True;
    15921635          end;
     1636
    15931637          // Update for all adjecent stations
    15941638          if DirectionUp then begin
    15951639            if StationIndex = 0 then
    1596               ComputeShapeDistanceStation(LineStations[LineStations.Count - 2].MapStation,
    1597               UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     1640              ComputeDestinationIndexDistanceStation(LineStations[LineStations.Count - 2].MapStation,
     1641              UpdatedDestinationIndex, Station.DestinationDistance[UpdatedDestinationIndex] + 1);
    15981642            if StationIndex > 0 then
    1599               ComputeShapeDistanceStation(LineStations[StationIndex - 1].MapStation,
    1600               UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     1643              ComputeDestinationIndexDistanceStation(LineStations[StationIndex - 1].MapStation,
     1644              UpdatedDestinationIndex, Station.DestinationDistance[UpdatedDestinationIndex] + 1);
    16011645          end;
    16021646          if DirectionDown then begin
    16031647            if (StationIndex >= 0) and (StationIndex = LineStations.Count - 1) then
    1604               ComputeShapeDistanceStation(LineStations[1].MapStation,
    1605               UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     1648              ComputeDestinationIndexDistanceStation(LineStations[1].MapStation,
     1649              UpdatedDestinationIndex, Station.DestinationDistance[UpdatedDestinationIndex] + 1);
    16061650            if (StationIndex >= 0) and (StationIndex < LineStations.Count - 1) then
    1607               ComputeShapeDistanceStation(LineStations[StationIndex + 1].MapStation,
    1608               UpdatedShape, Station.ShapeDistance[UpdatedShape] + 1);
     1651              ComputeDestinationIndexDistanceStation(LineStations[StationIndex + 1].MapStation,
     1652              UpdatedDestinationIndex, Station.DestinationDistance[UpdatedDestinationIndex] + 1);
    16091653          end;
    16101654        end;
     
    16891733          if Assigned(CurrentStation) then begin
    16901734            for P := Passengers.Count - 1 downto 0 do begin
    1691               if Passengers[P].Shape = CurrentStation.MapStation.Shape then begin
     1735              if Passengers[P].DestinationIndex = CurrentStation.MapStation.DestinationIndex then begin
    16921736                Passenger := Passengers[P];
    16931737                Passengers.Delete(P);
     
    16991743            with Carriages[J] do begin
    17001744              for P := Passengers.Count - 1 downto 0 do begin
    1701                 if Passengers[P].Shape = CurrentStation.MapStation.Shape then begin
     1745                if Passengers[P].DestinationIndex = CurrentStation.MapStation.DestinationIndex then begin
    17021746                  Passenger := Passengers[P];
    17031747                  Passengers.Delete(P);
     
    17121756          if Assigned(CurrentStation) then begin
    17131757            for P := Passengers.Count - 1 downto 0 do begin
    1714               if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].Shape,
     1758              if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].DestinationIndex,
    17151759              TargetStation, CurrentStation) then begin
    17161760                Passenger := Passengers[P];
     
    17221766            with Carriages[J] do begin
    17231767              for P := Passengers.Count - 1 downto 0 do begin
    1724                 if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].Shape,
     1768                if not CurrentStation.MapStation.IsBestStationForShape(Passengers[P].DestinationIndex,
    17251769                TargetStation, CurrentStation) then begin
    17261770                  Passenger := Passengers[P];
     
    17391783            if (Passengers.Count < TrainPassengerCount) then begin
    17401784              Passenger := CurrentStation.MapStation.Passengers[P];
    1741               if CurrentStation.MapStation.IsBestStationForShape(Passenger.Shape,
     1785              if CurrentStation.MapStation.IsBestStationForShape(Passenger.DestinationIndex,
    17421786              TargetStation, CurrentStation) then begin
    17431787                CurrentStation.MapStation.Passengers.Delete(P);
     
    17501794                if (Passengers.Count < TrainPassengerCount) then begin
    17511795                  Passenger := CurrentStation.MapStation.Passengers[P];
    1752                   if CurrentStation.MapStation.IsBestStationForShape(Passenger.Shape,
     1796                  if CurrentStation.MapStation.IsBestStationForShape(Passenger.DestinationIndex,
    17531797                  TargetStation, CurrentStation) then begin
    17541798                    CurrentStation.MapStation.Passengers.Delete(P);
     
    19351979
    19361980procedure TEngine.MenuItemOptions(Sender: TObject);
     1981var
     1982  VisualStyleIndex: TVisualStyle;
     1983  StationStyleIndex: TStationStyle;
    19371984begin
    19381985  MenuOptions.Parent := MenuMain;
     
    19672014      Checked := FullScreen;
    19682015    end;
     2016      with AddComboBox(SVisualStyle, [], VisualStyleChanged) do begin
     2017      TextSize := 40;
     2018      TextColor := Colors.MenuItemText;
     2019      TextDisabledColor := Colors.MenuItemDisabledText;
     2020      BackgroundColor := Colors.MenuItemBackground;
     2021      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
     2022      for VisualStyleIndex := Low(TVisualStyle) to High(TVisualStyle) do
     2023        States.AddObject(VisualStyleText[VisualStyleIndex], TObject(VisualStyleIndex));
     2024      Index := States.IndexOfObject(TObject(VisualStyle));
     2025      if Index = -1 then Index := 0;
     2026    end;
     2027    with AddComboBox(SStationStyle, [], StationStyleChanged) do begin
     2028      TextSize := 40;
     2029      TextColor := Colors.MenuItemText;
     2030      TextDisabledColor := Colors.MenuItemDisabledText;
     2031      BackgroundColor := Colors.MenuItemBackground;
     2032      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
     2033      for StationStyleIndex := Low(TStationStyle) to High(TStationStyle) do
     2034        States.AddObject(StationStyleText[StationStyleIndex], TObject(StationStyleIndex));
     2035      Index := States.IndexOfObject(TObject(StationStyle));
     2036      if Index = -1 then Index := 0;
     2037    end;
     2038    with AddCheckBox(SMovableTrack, MovableTrackChanged) do begin
     2039      TextSize := 40;
     2040      TextColor := Colors.MenuItemText;
     2041      TextDisabledColor := Colors.MenuItemDisabledText;
     2042      BackgroundColor := Colors.MenuItemBackground;
     2043      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
     2044      Checked := MovableTracks;
     2045    end;
    19692046    with AddButton(SBack, MenuItemBack) do begin
    19702047      TextSize := 40;
     
    19812058end;
    19822059
     2060procedure TEngine.MenuItemCustomGame(Sender: TObject);
     2061var
     2062  VisualStyleIndex: TVisualStyle;
     2063  StationStyleIndex: TStationStyle;
     2064begin
     2065  MenuCustomGame.Parent := MenuMain;
     2066  with MenuCustomGame, Items do begin
     2067    Clear;
     2068    with AddButton(SPlay, MenuItemCustomPlay) do begin
     2069      TextSize := 40;
     2070      TextColor := Colors.MenuItemText;
     2071      TextDisabledColor := Colors.MenuItemDisabledText;
     2072      BackgroundColor := Colors.MenuItemBackground;
     2073      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
     2074    end;
     2075    with AddButton(SBack, MenuItemBack) do begin
     2076      TextSize := 40;
     2077      TextColor := Colors.MenuItemText;
     2078      TextDisabledColor := Colors.MenuItemDisabledText;
     2079      BackgroundColor := Colors.MenuItemBackground;
     2080      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
     2081    end;
     2082    OnExit := MenuItemBack;
     2083  end;
     2084
     2085  Menu := MenuCustomGame;
     2086  Redraw;
     2087end;
     2088
     2089procedure TEngine.MenuItemCustomPlay(Sender: TObject);
     2090begin
     2091  City := nil;
     2092  NewGame;
     2093end;
     2094
    19832095procedure TEngine.MenuItemBack(Sender: TObject);
    19842096begin
     
    21122224end;
    21132225
     2226procedure TEngine.MovableTrackChanged(Sender: TObject);
     2227begin
     2228  MovableTracks := TMenuItemCheckBox(Sender).Checked;
     2229end;
     2230
     2231procedure TEngine.StationStyleChanged(Sender: TObject);
     2232begin
     2233  StationStyle := TStationStyle(TMenuItemComboBox(Sender).States.Objects[TMenuItemComboBox(Sender).Index]);
     2234end;
     2235
     2236procedure TEngine.VisualStyleChanged(Sender: TObject);
     2237begin
     2238  VisualStyle := TVisualStyle(TMenuItemComboBox(Sender).States.Objects[TMenuItemComboBox(Sender).Index]);
     2239end;
     2240
    21142241procedure TEngine.UpdateInterface;
    21152242begin
     
    21982325    miTerminal: Inc(AvailableTerminals);
    21992326  end;
     2327end;
     2328
     2329function TEngine.DestinationIndexToText(DestinationIndex: TDestinationIndex): string;
     2330begin
     2331  case StationStyle of
     2332    ssShapes: Result := '';
     2333    ssAlpha: Result := Chr(Ord('A') + Integer(DestinationIndex));
     2334    ssLinear: Result := IntToStr(1 + Integer(DestinationIndex));
     2335  end;
     2336end;
     2337
     2338function TEngine.DestinationIndexToShape(DestinationIndex: TDestinationIndex): TDestinationShape;
     2339begin
     2340  if StationStyle = ssShapes then Result := TDestinationShape(DestinationIndex)
     2341    else Result := ssCircle;
    22002342end;
    22012343
     
    22262368      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
    22272369    end;
     2370    {
     2371    with AddButton(SCustomGame, MenuItemCustomGame) do begin
     2372      TextSize := 40;
     2373      TextColor := Colors.MenuItemText;
     2374      TextDisabledColor := Colors.MenuItemDisabledText;
     2375      BackgroundColor := Colors.MenuItemBackground;
     2376      BackgroundSelectedColor := Colors.MenuItemBackgroundSelected;
     2377    end;
     2378    }
    22282379    with AddButton(SCareer, MenuItemCareer) do begin
    22292380      TextSize := 40;
     
    23512502  Carriage: TMetroCarriage;
    23522503  Vector: TVector;
     2504  Text: string;
    23532505begin
    23542506  for Train in Trains do
     
    23572509      Canvas.Brush.Color := Line.Color;
    23582510      Canvas.Brush.Style := bsSolid;
    2359       Canvas.Pen.Style := psClear;
     2511      Canvas.Pen.Width := 1;
     2512      case VisualStyle of
     2513        vsLondon: Canvas.Pen.Style := psClear;
     2514        vsPrague: begin
     2515          Canvas.Pen.Style := psSolid;
     2516          Canvas.Pen.Color := Colors.Text;
     2517        end;
     2518      end;
    23602519      Vector := TrackPosition.GetVector;
    23612520      Pos := Vector.Position;
     
    23682527      Points[3] := RotatePoint(Pos, Point(Pos.X - TrainSize div 2, Pos.Y + TrainSize div 3), Angle);
    23692528      Canvas.Polygon(Points);
     2529
     2530      Canvas.Pen.Style := psClear;
    23702531      Canvas.Brush.Color := clWhite;
    23712532      P := 0;
     
    23752536          Pos.Y - Trunc(TrainSize div 6 * 1) + (P div 3) * TrainSize div 3);
    23762537        ShapePos := RotatePoint(Pos, ShapePos, Angle);
    2377         DrawShape(Canvas, ShapePos, Shape, TrainSize div 3, Angle + Pi / 2);
     2538        if StationStyle = ssShapes then begin
     2539          DrawShape(Canvas, ShapePos, DestinationIndexToShape(DestinationIndex), TrainSize div 3, Angle + Pi / 2);
     2540        end else begin
     2541          Text := DestinationIndexToText(DestinationIndex);
     2542          if Text <> '' then begin
     2543            Canvas.Brush.Style := bsClear;
     2544            Canvas.Font.Color := clWhite;
     2545            Canvas.Font.Size := Round(TrainSize * 0.15);
     2546            Canvas.Font.Orientation := Round((-Angle / Pi * 180) * 10);
     2547            Canvas.TextOut(ShapePos.X - Round(TrainSize * 0.15),
     2548              ShapePos.Y - Round(TrainSize * 0.15), Text);
     2549            Canvas.Font.Orientation := 0;
     2550          end;
     2551        end;
    23782552        Inc(P);
    23792553      end;
     
    23842558        Canvas.Brush.Color := Line.Color;
    23852559        Canvas.Brush.Style := bsSolid;
    2386         Canvas.Pen.Style := psClear;
     2560        case VisualStyle of
     2561          vsLondon: Canvas.Pen.Style := psClear;
     2562          vsPrague: begin
     2563            Canvas.Pen.Style := psSolid;
     2564            Canvas.Pen.Color := Colors.Text;
     2565          end;
     2566        end;
    23872567        Vector := GetTrackPosition.GetVector;
    23882568        Pos := Vector.Position;
     
    23952575        Points[3] := RotatePoint(Pos, Point(Pos.X - TrainSize div 2, Pos.Y + TrainSize div 3), Angle);
    23962576        Canvas.Polygon(Points);
     2577
     2578        Canvas.Pen.Style := psClear;
    23972579        Canvas.Brush.Color := clWhite;
    23982580        P := 0;
     
    24022584            Pos.Y - Trunc(TrainSize div 6 * 1) + (P div 3) * TrainSize div 3);
    24032585          ShapePos := RotatePoint(Pos, ShapePos, Angle);
    2404           DrawShape(Canvas, ShapePos, Shape, TrainSize div 3, Angle + Pi / 2);
     2586          if StationStyle = ssShapes then begin
     2587            DrawShape(Canvas, ShapePos, DestinationIndexToShape(DestinationIndex), TrainSize div 3, Angle + Pi / 2);
     2588          end else begin
     2589            Text := DestinationIndexToText(DestinationIndex);
     2590            if Text <> '' then begin
     2591              Canvas.Brush.Style := bsClear;
     2592              Canvas.Font.Color := clWhite;
     2593              Canvas.Font.Size := Round(TrainSize * 0.15);
     2594              Canvas.Font.Orientation := Round((-Angle / Pi * 180) * 10);
     2595              Canvas.TextOut(ShapePos.X - Round(TrainSize * 0.15),
     2596                ShapePos.Y - Round(TrainSize * 0.15), Text);
     2597              Canvas.Font.Orientation := 0;
     2598            end;
     2599          end;
    24052600          Inc(P);
    24062601        end;
     
    26722867    Canvas.Pen.Color := Color;
    26732868    Canvas.Pen.Style := psSolid;
    2674     Canvas.Pen.Width := MetroLineThickness;
     2869    Canvas.Pen.Width := GetMetroLineThickness;
    26752870    if Track.Points.Count > 0 then Canvas.MoveTo(Track.Points[0].Position);
    26762871    for S := 1 to Track.Points.Count - 1 do begin
     
    26922887(*    Canvas.Pen.Color := Color;
    26932888    Canvas.Pen.Style := psSolid;
    2694     Canvas.Pen.Width := MetroLineThickness div 2;
     2889    Canvas.Pen.Width := GetMetroLineThickness div 2;
    26952890    if Track.Points.Count > 0 then Canvas.MoveTo(Track.Points[0].PositionDesigned);
    26962891    for S := 1 to Track.Points.Count - 1 do begin
     
    27482943  Direction: Integer;
    27492944  UsedStationSize: Integer;
     2945  Text: string;
    27502946begin
    27512947  Canvas.Pen.Width := 5;
     
    27572953
    27582954    if Assigned(SelectedLine) and (Lines.IndexOf(SelectedLine) <> -1) then begin
     2955      case VisualStyle of
     2956        vsLondon: begin
     2957          Canvas.Brush.Style := bsClear;
     2958          Canvas.Pen.Style := psSolid;
     2959          Canvas.Pen.Color := SelectedLine.Color;
     2960        end;
     2961        vsPrague: begin
     2962          Canvas.Brush.Style := bsSolid;
     2963          Canvas.Brush.Color := SelectedLine.Color;
     2964          Canvas.Pen.Style := psClear;
     2965          Canvas.Pen.Color := Colors.Background;
     2966        end;
     2967      end;
     2968      DrawShape(Canvas, Position, DestinationIndexToShape(Integer(DestinationIndex)),
     2969        UsedStationSize + Canvas.Pen.Width + 4, 0);
     2970    end;
     2971
     2972    case VisualStyle of
     2973      vsLondon: begin
     2974        Canvas.Brush.Style := bsSolid;
     2975        Canvas.Brush.Color := Colors.ShapeBackground;
     2976        Canvas.Pen.Color := Colors.Text;
     2977      end;
     2978      vsPrague: begin
     2979        if Lines.Count = 0 then begin
     2980          Canvas.Brush.Style := bsSolid;
     2981          Canvas.Brush.Color := Colors.Background2;
     2982        end else Canvas.Brush.Style := bsClear;
     2983        Canvas.Pen.Style := psClear;
     2984      end;
     2985    end;
     2986    DrawShape(Canvas, Position, DestinationIndexToShape(Integer(DestinationIndex)),
     2987      UsedStationSize, 0);
     2988    Text := DestinationIndexToText(Integer(DestinationIndex));
     2989    if Text <> '' then begin
    27592990      Canvas.Brush.Style := bsClear;
    2760       Canvas.Pen.Color := SelectedLine.Color;
    2761       DrawShape(Canvas, Position, Shape, UsedStationSize + Canvas.Pen.Width + 4, 0);
    2762     end;
    2763 
    2764     Canvas.Brush.Color := Colors.ShapeBackground;
    2765     Canvas.Brush.Style := bsSolid;
    2766     Canvas.Pen.Color := Colors.Text;
    2767     DrawShape(Canvas, Position, Shape, UsedStationSize, 0);
     2991      Canvas.Font.Size := Round(UsedStationSize * 0.4);
     2992      Canvas.Font.Color := Colors.Text;
     2993      Canvas.Font.Style := [fsBold];
     2994      Canvas.TextOut(Position.X - Canvas.TextWidth(Text) div 2,
     2995        Position.Y - Canvas.TextHeight(Text) div 2, Text);
     2996    end;
     2997
     2998    // Draw station border
     2999    if (VisualStyle = vsPrague) and (Lines.Count > 0) then begin
     3000      Canvas.Brush.Style := bsClear;
     3001      Canvas.Pen.Style := psSolid;
     3002      Canvas.Pen.Color := Colors.Background;
     3003      DrawShape(Canvas, Position, DestinationIndexToShape(Integer(DestinationIndex)),
     3004        UsedStationSize + Canvas.Pen.Width + 4, 0);
     3005    end;
    27683006
    27693007    // Draw passengers
     
    27743012    for Passenger in Passengers do
    27753013    with Passenger do begin
    2776       DrawShape(Canvas, Point(Position.X + StationSize + PassengerPos.X,
    2777         Position.Y - StationSize div 2 + PassengerPos.Y),
    2778         Shape, PassengerSize, 0);
     3014      if StationStyle = ssShapes then begin
     3015        DrawShape(Canvas, Point(Position.X + StationSize + PassengerPos.X,
     3016          Position.Y - StationSize div 2 + PassengerPos.Y),
     3017          DestinationIndexToShape(DestinationIndex), PassengerSize, 0);
     3018      end else begin
     3019        Text := DestinationIndexToText(Integer(DestinationIndex));
     3020        if Text <> '' then begin
     3021          Canvas.Brush.Style := bsClear;
     3022          Canvas.Font.Size := Round(StationSize * 0.3);
     3023          Canvas.Font.Color := Colors.Text;
     3024          Canvas.Font.Style := [fsBold];
     3025          Canvas.TextOut(Position.X + StationSize + PassengerPos.X - Canvas.TextWidth(Text) div 2,
     3026            Position.Y - StationSize div 2 + PassengerPos.Y - Canvas.TextHeight(Text) div 2, Text);
     3027        end;
     3028      end;
    27793029      PassengerPos := Point(PassengerPos.X + Direction * (PassengerSize + 2), PassengerPos.Y);
    27803030      if PassengerPos.X >= (PassengerSize + 2) * VisiblePassengersPerLine then begin
     
    27943044      Text := '';
    27953045      for P := 0 to 5 do
    2796         Text := Text + IntToStr(ShapeDistance[TStationShape(P)]) + ',';
     3046        Text := Text + IntToStr(DestinationDistance[TDestinationIndex(P)]) + ',';
    27973047      Canvas.TextOut(Position.X + StationSize div 2, Position.Y + StationSize div 2, Text);
    27983048    end;
     
    30363286    if (Time - LastNewShapeTime) > NewShapePeriod then begin
    30373287      LastNewShapeTime := Time;
    3038       if ShapeCount <= Integer(High(TStationShape)) then Inc(ShapeCount);
     3288      if DestinationCount < Integer(High(TDestinationShape)) then Inc(DestinationCount);
    30393289      Redraw;
    30403290    end;
     
    30553305      if Random < NewPassengerProbability then begin
    30563306        Passenger := Self.Passengers.AddNew;
    3057         Passenger.Shape := TStationShape(Random(Integer(ShapeCount)));
     3307        Passenger.DestinationIndex := Random(DestinationCount);
    30583308        Passengers.Add(Passenger);
    30593309
    3060         // Passenger is not allowed to have same shape
    3061         while (Passenger.Shape = Shape) or
    3062         not (Passenger.Shape in GetExistStationShapes) do
    3063           Passenger.Shape := TStationShape((Integer(Passenger.Shape) + 1) mod Integer(ShapeCount));
     3310        // Passenger is not allowed to have same DestinationIndex
     3311        while (Passenger.DestinationIndex = DestinationIndex) or
     3312        not GetExistStationDestinationIndex(Passenger.DestinationIndex) do
     3313          Passenger.DestinationIndex := (Passenger.DestinationIndex + 1) mod DestinationCount;
    30643314        Redraw;
    30653315      end;
     
    31343384    if Assigned(Line) and not Assigned(LastFocusedStation) and Assigned(FocusedStation) then begin
    31353385      if Assigned(TrackStationDown) and (TLineStation(TrackStationDown.OwnerPoint).MapStation = FocusedStation) then begin
    3136         // Disconnect down
    3137         CurrentTrackPoint := TrackStationDown;
    3138         TrackStationDown := TrackStationDown.GetDown;
    3139         Line.DisconnectStation(TLineStation(CurrentTrackPoint.OwnerPoint));
     3386        if MovableTracks then begin
     3387          // Disconnect down
     3388          CurrentTrackPoint := TrackStationDown;
     3389          TrackStationDown := TrackStationDown.GetDown;
     3390          Line.DisconnectStation(TLineStation(CurrentTrackPoint.OwnerPoint));
     3391        end;
    31403392      end else
    31413393      if Assigned(TrackStationUp) and (TLineStation(TrackStationUp.OwnerPoint).MapStation = FocusedStation) then begin
    3142         // Disconnect up
    3143         CurrentTrackPoint := TrackStationUp;
    3144         if Assigned(TrackStationUp) then
    3145           TrackStationUp := TrackStationUp.GetUp;
    3146         Line.DisconnectStation(TLineStation(CurrentTrackPoint.OwnerPoint));
     3394        if MovableTracks then begin
     3395          // Disconnect up
     3396          CurrentTrackPoint := TrackStationUp;
     3397          if Assigned(TrackStationUp) then
     3398            TrackStationUp := TrackStationUp.GetUp;
     3399          Line.DisconnectStation(TLineStation(CurrentTrackPoint.OwnerPoint));
     3400        end;
    31473401      end else
    31483402      if Assigned(Line) and ((not Line.IsCircular) or ((TrackStationDown <> nil) and (TrackStationUp <> nil))) and
     
    33613615            else TrackStationUp := nil;
    33623616        end;
     3617
     3618        if not MovableTracks and (Assigned(TrackStationDown) and Assigned(TrackStationUp)) then begin
     3619          TrackStationDown := nil;
     3620          TrackStationUp := nil;
     3621          SelectedLine := nil;
     3622        end;
     3623
    33633624        Track.Free;
    33643625        Exit;
     
    34913752  end;
    34923753  AvailableImprovements := [miCarriage, miLine, miTerminal];
    3493   ShapeCount := 3;
     3754  DestinationCount := 3;
    34943755
    34953756  // Start with 3 stations with each different shape
     
    34973758  for I := 0 to InitialStationCount - 1 do begin
    34983759    NewStation := Stations.AddNew;
    3499     if I = 0 then NewStation.Shape := ssSquare
    3500     else if I = 1 then NewStation.Shape := ssCircle
    3501     else if I = 2 then NewStation.Shape := ssTriangle;
     3760    if I = 0 then NewStation.DestinationIndex := Integer(ssSquare)
     3761    else if I = 1 then NewStation.DestinationIndex := Integer(ssCircle)
     3762    else if I = 2 then NewStation.DestinationIndex := Integer(ssTriangle);
    35023763  end;
    35033764
     
    35343795    HighestServedPassengerCount := ReadIntegerWithDefault('HighestPassengers', 0);
    35353796    HighestServedDaysCount := ReadIntegerWithDefault('HighestDays', 0);
     3797    StationStyle := TStationStyle(ReadIntegerWithDefault('StationStyle', Integer(ssShapes)));
     3798    VisualStyle := TVisualStyle(ReadIntegerWithDefault('VisualStyle', Integer(vsLondon)));
     3799    MovableTracks := ReadBoolWithDefault('MovableTracks', MovableTracks);
    35363800    Cities.LoadFromRegistry(TRegistryContext.Create(RegistryContext.RootKey, RegistryContext.Key + '\Cities'));
    35373801  finally
     
    35493813    WriteInteger('HighestPassengers', HighestServedPassengerCount);
    35503814    WriteInteger('HighestDays', HighestServedDaysCount);
     3815    WriteInteger('StationStyle', Integer(StationStyle));
     3816    WriteInteger('VisualStyle', Integer(VisualStyle));
     3817    WriteBool('MovableTracks', MovableTracks);
    35513818    Cities.SaveToRegistry(TRegistryContext.Create(RegistryContext.RootKey, RegistryContext.Key + '\Cities'));
    35523819  finally
     
    36253892begin
    36263893  inherited;
     3894  MovableTracks := True;
    36273895  Colors := TColors.Create;
    36283896  Colors.Init(FDarkMode);
     
    36393907  MenuCareer := TMenu.Create;
    36403908  MenuGame := TMenu.Create;
     3909  MenuCustomGame := TMenu.Create;
    36413910  Menu := MenuMain;
    36423911  InitMenus;
     
    36993968  FreeAndNil(MenuMain);
    37003969  FreeAndNil(MenuOptions);
     3970  FreeAndNil(MenuCustomGame);
    37013971  FreeAndNil(MenuCareer);
    37023972  FreeAndNil(MenuGame);
Note: See TracChangeset for help on using the changeset viewer.