Changeset 100 for trunk/UGame.pas


Ignore:
Timestamp:
Dec 26, 2014, 8:10:40 PM (10 years ago)
Author:
chronos
Message:
  • Added: Support for autogeneration of bridges between separated areas.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UGame.pas

    r96 r100  
    2626  TCells = class;
    2727  TMap = class;
     28  TCellLinks = class;
     29  TMapArea = class;
    2830
    2931  TFloatPoint = record
     
    3941  TCell = class
    4042  private
     43    FArea: TMapArea;
    4144    FMap: TMap;
    4245    FPower: Integer;
     46    procedure SetArea(AValue: TMapArea);
    4347    procedure SetPower(AValue: Integer);
    4448  public
     
    5458    Neighbors: TCells;
    5559    Mark: Boolean;
     60    procedure AreaExtend;
    5661    procedure FixRefId;
    5762    procedure LoadFromNode(Node: TDOMNode);
     
    6671    property Power: Integer read FPower write SetPower;
    6772    property Map: TMap read FMap write FMap;
     73    property Area: TMapArea read FArea write SetArea;
    6874  end;
    6975
     
    7884    procedure LoadFromNode(Node: TDOMNode);
    7985    procedure SaveToNode(Node: TDOMNode);
     86    procedure ClearMark;
     87  end;
     88
     89  TCellLink = class
     90    Points: array of TPoint;
     91    Cell1: TCell;
     92    Cell2: TCell;
     93  end;
     94
     95  TCellLinks = class(TObjectList)
     96
    8097  end;
    8198
     
    116133  TMapShape = (msRectangle, msImage);
    117134
     135  { TMapArea }
     136
     137  TMapArea = class
     138    Id: Integer;
     139    Map: TMap;
     140    BridgeCount: Integer;
     141    Cells: TCells;
     142    procedure GetBorderCells(List: TCells);
     143    constructor Create;
     144    destructor Destroy; override;
     145  end;
     146
     147  TMapAreas = class(TObjectList)
     148
     149  end;
     150
    118151  { TMap }
    119152
     
    136169    Shape: TMapShape;
    137170    Image: TImage;
     171    CellLinks: TCellLinks;
     172    Areas: TMapAreas;
    138173    function IsOutsideShape(Coord: TPoint): Boolean; virtual;
    139174    function IsCellsNeighbor(Cell1, Cell2: TCell): Boolean; virtual;
     
    357392    procedure UpdateRepeatMoves(Player: TPlayer);
    358393    procedure CheckCounterMove(Move: TUnitMove);
     394    function SearchDifferentCellArea(List: TCells; SourceArea, DestArea: TMapArea): TCell;
     395    procedure BuildTerrain;
     396    procedure BuildBridges;
     397    procedure BuildMapAreas;
    359398  public
    360399    Players: TPlayers;
     
    377416    FileName: string;
    378417    FogOfWar: Boolean;
     418    BridgeEnabled: Boolean;
    379419    function AttackProbability(AttackCount, DefendCount: Integer): Double;
    380420    procedure LoadConfig(Config: TXmlConfig; Path: string);
     
    499539end;
    500540
     541{ TMapArea }
     542
     543procedure TMapArea.GetBorderCells(List: TCells);
     544var
     545  I: Integer;
     546  J: Integer;
     547  NeighVoidCount: Integer;
     548begin
     549  List.Clear;
     550
     551  // Unset mark for all cells
     552  for I := 0 to Map.Cells.Count - 1 do
     553    TCell(Map.Cells[I]).Mark := False;
     554
     555  for I := 0 to Cells.Count - 1 do
     556  with TCell(Cells[I]) do begin
     557    NeighVoidCount := 0;
     558    for J := 0 to Neighbors.Count - 1 do
     559    with TCell(Neighbors[J]) do
     560      if (Terrain = ttVoid) then Inc(NeighVoidCount);
     561
     562    if (NeighVoidCount > 0) and (Area = Self) and (not Mark) then begin
     563        List.Add(TCell(Self.Cells[I]));
     564        Mark := True;
     565      end;
     566  end;
     567end;
     568
     569constructor TMapArea.Create;
     570begin
     571  Cells := TCells.Create;
     572  Cells.OwnsObjects := False;
     573end;
     574
     575destructor TMapArea.Destroy;
     576begin
     577  Cells.Free;
     578  inherited Destroy;
     579end;
     580
    501581{ TPlayerCell }
    502582
     
    641721  try
    642722    Lock;
     723    // Draw cell links
     724    Pen.Color := clBlack;
     725    Pen.Style := psSolid;
     726    Pen.Width := 3;
     727    for C := 0 to Player.Game.Map.CellLinks.Count - 1 do
     728    with TCellLink(Player.Game.Map.CellLinks[C]) do begin
     729      if Length(Points) >= 2 then begin
     730        MoveTo(View.CellToCanvasPos(Points[0]));
     731        for I := 1 to Length(Points) - 1 do
     732          LineTo(View.CellToCanvasPos(Points[I]));
     733      end;
     734    end;
     735
     736    // Draw cells
    643737    for C := 0 to Cells.Count - 1 do begin
    644738      Cell := TPlayerCell(Cells[C]);
     
    769863end;
    770864
     865procedure TCells.ClearMark;
     866var
     867  I: Integer;
     868begin
     869  for I := 0 to Count - 1 do
     870    TCell(Items[I]).Mark := False;
     871end;
     872
    771873{ TPlayers }
    772874
     
    9571059
    9581060  // Generate neighbours
    959   for Y := 0 to self.FSize.Y - 1 do
     1061  for Y := 0 to Self.FSize.Y - 1 do
    9601062  for X := 0 to FSize.X - 1 do
    9611063  with TCell(Cells[Y * FSize.X + X]) do begin
     
    12881390  I: Integer;
    12891391  NewCell: TCell;
    1290   NeighCells: TCellArray;
    12911392begin
    12921393  // Free previous
     
    13131414  Size := Point(0, 0);
    13141415  Image := TImage.Create(nil);
     1416  CellLinks := TCellLinks.Create;
     1417  Areas := TMapAreas.Create;
    13151418end;
    13161419
    13171420destructor TMap.Destroy;
    13181421begin
     1422  Areas.Free;
     1423  CellLinks.Free;
    13191424  Image.Free;
    13201425  Size := Point(0, 0);
     
    14671572    raise Exception.Create('Not allowed to substract power under zero do negative value');
    14681573  FPower := AValue;
     1574end;
     1575
     1576procedure TCell.SetArea(AValue: TMapArea);
     1577begin
     1578  if FArea = AValue then Exit;
     1579  if Assigned(FArea) then FArea.Cells.Remove(Self);
     1580  FArea := AValue;
     1581  if Assigned(FArea) then FArea.Cells.Add(Self);
     1582end;
     1583
     1584procedure TCell.AreaExtend;
     1585var
     1586  I: Integer;
     1587begin
     1588  for I := 0 to Neighbors.Count - 1 do
     1589  with TCell(Neighbors[I]) do
     1590  if (Terrain <> ttVoid) and (not Assigned(Area)) then begin
     1591    Area := Self.Area;
     1592    AreaExtend;
     1593  end;
    14691594end;
    14701595
     
    23852510end;
    23862511
     2512function TGame.SearchDifferentCellArea(List: TCells; SourceArea, DestArea: TMapArea): TCell;
     2513var
     2514  NewList: TCells;
     2515  NewListVoid: TCells;
     2516  I: Integer;
     2517  C: Integer;
     2518begin
     2519  Result := nil;
     2520  NewList := TCells.Create;
     2521  NewList.OwnsObjects := False;
     2522  NewListVoid := TCells.Create;
     2523  NewListVoid.OwnsObjects := False;
     2524
     2525  for C := 0 to List.Count - 1 do
     2526  with TCell(List[C]) do begin
     2527    for I := 0 to Neighbors.Count - 1 do
     2528    with TCell(Neighbors[I]) do
     2529    if (not Mark) and (Terrain <> ttVoid) and (Area <> SourceArea) and ((DestArea = nil) or (DestArea = Area)) then begin
     2530      NewList.Add(TCell(TCell(List[C]).Neighbors[I]));
     2531      Mark := True;
     2532    end else
     2533    if (not Mark) and (Terrain = ttVoid) then begin
     2534      NewListVoid.Add(TCell(TCell(List[C]).Neighbors[I]));
     2535      Mark := True;
     2536    end;
     2537  end;
     2538
     2539  if NewList.Count > 0 then begin
     2540    // We found cell with different area
     2541    Result := TCell(NewList[Random(NewList.Count)]);
     2542  end else
     2543  if NewListVoid.Count > 0 then begin
     2544    // Cell was not found but we have more void cells to check
     2545    Result := SearchDifferentCellArea(NewListVoid, SourceArea, DestArea);
     2546  end;
     2547
     2548  NewListVoid.Free;
     2549  NewList.Free;
     2550end;
     2551
     2552procedure TGame.BuildTerrain;
     2553var
     2554  C: Integer;
     2555begin
     2556  if (Map.Shape = msImage) and FileExists(MapImageFileName) and
     2557  (LoadedImageFileName <> MapImageFileName) then begin
     2558    LoadedImageFileName := MapImageFileName;
     2559    Map.Image.Picture.LoadFromFile(MapImageFileName);
     2560  end;
     2561
     2562  // Randomize map terrain
     2563  for C := 0 to Map.Cells.Count - 1 do
     2564  with TCell(Map.Cells[C]) do begin
     2565    if (VoidEnabled and (Random < VoidPercentage / 100)) or
     2566    (Map.IsOutsideShape(PosPx)) then Terrain := ttVoid
     2567      else begin
     2568        if CityEnabled and (Random < CityPercentage / 100) then Terrain := ttCity
     2569          else Terrain := ttNormal;
     2570      end;
     2571    Power := Random(MaxNeutralUnits + 1);
     2572    Player := nil;
     2573  end;
     2574end;
     2575
     2576procedure TGame.BuildBridges;
     2577var
     2578  List: TCells;
     2579  Cell: TCell;
     2580  FoundCell1: TCell;
     2581  FoundCell2: TCell;
     2582  I: Integer;
     2583  J: Integer;
     2584  NewLink: TCellLink;
     2585begin
     2586  // Build area bridges
     2587  if Map.Areas.Count > 1 then
     2588  for I := 0 to Map.Areas.Count - 1 do
     2589  with TMapArea(Map.Areas[I]) do begin
     2590    List := TCells.Create;
     2591    List.OwnsObjects := False;
     2592    GetBorderCells(List);
     2593    Cell := TCell(List[Random(List.Count)]);
     2594    List.Clear;
     2595    List.Add(Cell);
     2596
     2597    Map.Cells.ClearMark;
     2598
     2599    // Find nearest cell with different area
     2600    FoundCell1 := SearchDifferentCellArea(List, TMapArea(Map.Areas[I]), nil);
     2601    if Assigned(FoundCell1) then begin
     2602      // Again find back nearest cell with different area.
     2603      // This will ensure that both cells are closest ones
     2604
     2605      Map.Cells.ClearMark;
     2606      List[0] := FoundCell1;
     2607      FoundCell2 := SearchDifferentCellArea(List, FoundCell1.Area, TMapArea(Map.Areas[I]));
     2608      if Assigned(FoundCell2) then begin
     2609        FoundCell1.Neighbors.Add(FoundCell2);
     2610        FoundCell2.Neighbors.Add(FoundCell1);
     2611        NewLink := TCellLink.Create;
     2612        SetLength(NewLink.Points, 2);
     2613        NewLink.Cell1 := FoundCell2;
     2614        NewLink.Points[0] := FoundCell2.PosPx;
     2615        NewLink.Cell2 := FoundCell1;
     2616        NewLink.Points[1] := FoundCell1.PosPx;
     2617        Map.CellLinks.Add(NewLink);
     2618        Inc(BridgeCount);
     2619      end;
     2620    end;
     2621
     2622    List.Free;
     2623  end;
     2624end;
     2625
     2626procedure TGame.BuildMapAreas;
     2627var
     2628  C: Integer;
     2629  NewArea: TMapArea;
     2630begin
     2631  for C := 0 to Map.Cells.Count - 1 do
     2632  with TCell(Map.Cells[C]) do
     2633    Area := nil;
     2634  Map.Areas.Clear;
     2635  for C := 0 to Map.Cells.Count - 1 do
     2636  with TCell(Map.Cells[C]) do
     2637  if (Terrain <> ttVoid) and (not Assigned(Area)) then begin
     2638    NewArea := TMapArea(Map.Areas[Map.Areas.Add(TMapArea.Create)]);
     2639    NewArea.Id := Map.Areas.Count;
     2640    NewArea.Map := Map;
     2641    Area := NewArea;
     2642    AreaExtend;
     2643  end;
     2644end;
     2645
    23872646procedure TGame.SaveConfig(Config: TXmlConfig; Path: string);
    23882647begin
     
    23992658    SetValue(Path + '/CityEnabled', CityEnabled);
    24002659    SetValue(Path + '/CityPercentage', CityPercentage);
     2660    SetValue(Path + '/BridgeEnabled', BridgeEnabled);
    24012661    SetValue(Path + '/GrowAmount', Integer(GrowAmount));
    24022662    SetValue(Path + '/GrowCells', Integer(GrowCells));
     
    24212681    CityEnabled := GetValue(Path + '/CityEnabled', False);
    24222682    CityPercentage := GetValue(Path + '/CityPercentage', 10);
     2683    BridgeEnabled := GetValue(Path + '/BridgeEnabled', True);
    24232684    GrowAmount := TGrowAmount(GetValue(Path + '/GrowAmount', Integer(gaBySquareRoot)));
    24242685    GrowCells := TGrowCells(GetValue(Path + '/GrowCells', Integer(gcPlayerAll)));
     
    24502711      CityEnabled := ReadBoolean(RootNode, 'CityEnabled', False);
    24512712      CityPercentage := ReadInteger(RootNode, 'CityPercentage', 0);
     2713      BridgeEnabled := ReadBoolean(RootNode, 'BridgeEnabled', False);
    24522714      TurnCounter := ReadInteger(RootNode, 'TurnCounter', 0);
    24532715      WinObjective := TWinObjective(ReadInteger(RootNode, 'WinObjective', Integer(woDefeatAllOponents)));
     
    25032765      WriteBoolean(RootNode, 'CityEnabled', CityEnabled);
    25042766      WriteInteger(RootNode, 'CityPercentage', CityPercentage);
     2767      WriteBoolean(RootNode, 'BridgeEnabled', BridgeEnabled);
    25052768      WriteInteger(RootNode, 'TurnCounter', TurnCounter);
    25062769      WriteInteger(RootNode, 'WinObjective', Integer(WinObjective));
     
    26552918  Counter: Integer;
    26562919  C: Integer;
     2920  LastAreaCount: Integer;
    26572921begin
    26582922  FileName := SNewGameFile;
    26592923  TurnCounter := 1;
    26602924  Moves.Clear;
    2661   if (Map.Shape = msImage) and FileExists(MapImageFileName) and
    2662   (LoadedImageFileName <> MapImageFileName) then begin
    2663     LoadedImageFileName := MapImageFileName;
    2664     Map.Image.Picture.LoadFromFile(MapImageFileName);
    2665   end;
    2666   for C := 0 to Map.Cells.Count - 1 do
    2667   with TCell(Map.Cells[C]) do begin
    2668     if (VoidEnabled and (Random < VoidPercentage / 100)) or
    2669     (Map.IsOutsideShape(PosPx)) then Terrain := ttVoid
    2670       else begin
    2671         if CityEnabled and (Random < CityPercentage / 100) then Terrain := ttCity
    2672           else Terrain := ttNormal;
    2673       end;
    2674     Power := Random(MaxNeutralUnits + 1);
    2675     Player := nil;
     2925
     2926  BuildTerrain;
     2927  if BridgeEnabled then begin
     2928    // Connect all areas to all cells be accessible
     2929    for I := 0 to Map.CellLinks.Count - 1 do
     2930    with TCellLink(Map.CellLinks[I]) do begin
     2931      Cell1.Neighbors.Remove(Cell2);
     2932      Cell2.Neighbors.Remove(Cell1);
     2933    end;
     2934    Map.CellLinks.Clear;
     2935    BuildMapAreas;
     2936    LastAreaCount := -1;
     2937    while (Map.Areas.Count > 1) and (Map.Areas.Count <> LastAreaCount) do begin
     2938      LastAreaCount := Map.Areas.Count;
     2939      BuildBridges;
     2940      BuildMapAreas;
     2941    end;
    26762942  end;
    26772943
     
    28193085  try
    28203086    Lock;
     3087
     3088    // Draw cell links
     3089    Pen.Color := clBlack;
     3090    Pen.Style := psSolid;
     3091    Pen.Width := 3;
     3092    for C := 0 to CellLinks.Count - 1 do
     3093    with TCellLink(CellLinks[C]) do begin
     3094      if Length(Points) >= 2 then begin
     3095        MoveTo(Points[0]);
     3096        for I := 1 to Length(Points) - 1 do
     3097          LineTo(Points[I]);
     3098      end;
     3099    end;
     3100
     3101    // Draw cells
    28213102    for C := 0 to Cells.Count - 1 do begin
    28223103      Cell := TCell(Cells[C]);
Note: See TracChangeset for help on using the changeset viewer.