Changeset 42 for trunk/UGame.pas


Ignore:
Timestamp:
Mar 18, 2014, 12:16:04 AM (11 years ago)
Author:
chronos
Message:
  • Added: Min and Max buttons on unit move form for easy usual actions.
  • Added: Win objective can be selected on New game form.
  • Added: Max number of netureal starting units per cell cen be adjusted.
  • Added: Unit count is shown in move arrows.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UGame.pas

    r40 r42  
    3939    Terrain: TTerrainType;
    4040    Player: TPlayer;
    41     MovesFrom: TObjectList;
    42     MovesTo: TObjectList;
     41    MovesFrom: TObjectList; // TList<TMove>
     42    MovesTo: TObjectList; // TList<TMove>
    4343    function GetColor: TColor;
    4444    function GetAvialPower: Integer;
     
    8787    MaxPower: Integer;
    8888    DefaultCellSize: TPoint;
    89     procedure DrawArrow(Canvas: TCanvas; View: TView; Pos: TPoint; Angle: Double; Size: TPoint);
     89    procedure DrawArrow(Canvas: TCanvas; View: TView; Pos: TPoint; Angle: Double;
     90      Size: TPoint; Text: string);
    9091    function IsCellsNeighbor(Cell1, Cell2: TCell): Boolean; virtual;
    9192    function IsValidIndex(Index: TPoint): Boolean; virtual;
     
    169170    TotalUnits: Integer;
    170171    TotalCells: Integer;
     172    TotalCities: Integer;
    171173    StartUnits: Integer;
    172174    procedure ComputerTurn;
     
    184186  end;
    185187
    186   { TMove }
    187 
    188   TMove = class
     188  { TUnitMove }
     189
     190  TUnitMove = class
    189191  private
    190192    FCellFrom: TCell;
     
    194196    procedure SetCellTo(AValue: TCell);
    195197  public
    196     List: TObjectList; // TList<TMove>
     198    List: TObjectList; // TList<TUnitMove>
    197199    CountOnce: Integer;
    198200    CountRepeat: Integer;
     
    211213  TGrowCells = (gcNone, gcPlayerCities, gcPlayerAll);
    212214  TMapType = (mtNone, mtHexagon, mtSquare);
     215  TWinObjective = (woDefeatAllOponents, woDefeatAllOponentsCities,
     216    woSpecialCaptureCell, woStayAliveForDefinedTurns);
    213217
    214218  TGame = class
     
    235239    CityPercentage: Integer;
    236240    CurrentPlayer: TPlayer;
    237     Moves: TObjectList; // TList<TMove>
     241    Moves: TObjectList; // TList<TUnitMove>
    238242    TurnCounter: Integer;
     243    WinObjective: TWinObjective;
     244    SpecialCaptureCell: TCell;
     245    StayAliveForDefinedTurns: Integer;
     246    MaxNeutralUnits: Integer;
    239247    procedure SaveConfig(Config: TXmlConfig; Path: string);
    240248    procedure LoadConfig(Config: TXmlConfig; Path: string);
    241249    procedure ComputePlayerStats;
    242250    function GetAlivePlayers: TPlayerArray;
     251    function GetAlivePlayersWithCities: TPlayerArray;
    243252    procedure NextTurn;
     253    procedure CheckWinObjective;
    244254    constructor Create;
    245255    destructor Destroy; override;
    246256    procedure New;
     257    procedure EndGame(Winner: TPlayer = nil);
    247258    property Running: Boolean read FRunning write SetRunning;
    248259    property MapType: TMapType read FMapType write SetMapType;
     
    517528          for I := 0 to Cell.MovesFrom.Count - 1 do begin
    518529            PosFrom := CellToPos(Cell);
    519             PosTo := CellToPos(TMove(Cell.MovesFrom[I]).CellTo);
    520             if TMove(Cell.MovesFrom[I]).CountRepeat > 0 then Pen.Width := 2
     530            PosTo := CellToPos(TUnitMove(Cell.MovesFrom[I]).CellTo);
     531            if TUnitMove(Cell.MovesFrom[I]).CountRepeat > 0 then Pen.Width := 2
    521532              else Pen.Width := 1;
    522533            Angle := ArcTan((PosTo.Y - PosFrom.Y) / (PosTo.X - PosFrom.X));
     
    524535            DrawArrow(Canvas, View, View.CellToCanvasPos(Point(Trunc(PosFrom.X + (PosTo.X - PosFrom.X) / 3),
    525536              Trunc(PosFrom.Y + (PosTo.Y - PosFrom.Y) / 3))),
    526               Angle, Point(Trunc(HexSize.X / 4), Trunc(HexSize.Y / 4)));
     537              Angle, Point(Trunc(HexSize.X / 4), Trunc(HexSize.Y / 4)),
     538              IntToStr(TUnitMove(Cell.MovesFrom[I]).CountOnce));
    527539            Pen.Width := 1;
    528540          end;
     
    557569end;
    558570
    559 procedure TMap.DrawArrow(Canvas: TCanvas; View: TView; Pos: TPoint; Angle: Double; Size: TPoint);
     571procedure TMap.DrawArrow(Canvas: TCanvas; View: TView; Pos: TPoint;
     572  Angle: Double; Size: TPoint; Text: string);
    560573var
    561574  Points: array of TPoint;
     
    582595  for I := 0 to Length(Points) - 1 do
    583596    Points[I] := Point(Trunc(FPoints[I].X + Pos.X), Trunc(FPoints[I].Y + Pos.Y));
    584   Canvas.Polygon(Points);
     597  with Canvas do begin
     598    Polygon(Points);
     599    Brush.Style := bsClear;
     600    Font.Color := clBlack;
     601    Font.Size := Trunc(4 * View.Zoom);
     602    TextOut(Pos.X - TextWidth(Text) div 2,
     603      Pos.Y - TextHeight(Text) div 2, Text);
     604    Pen.Width := 1;
     605  end;
    585606end;
    586607
     
    656677      Player.TotalCells := Player.TotalCells + 1;
    657678      Player.TotalUnits := Player.TotalUnits + Power;
     679      if Terrain = ttCity then
     680        Player.TotalCities := Player.TotalCities + 1;
    658681    end;
    659682  end;
     
    714737end;
    715738
    716 { TMove }
    717 
    718 procedure TMove.SetCellFrom(AValue: TCell);
     739{ TUnitMove }
     740
     741procedure TUnitMove.SetCellFrom(AValue: TCell);
    719742begin
    720743  if FCellFrom = AValue then Exit;
     
    728751end;
    729752
    730 procedure TMove.SetCellTo(AValue: TCell);
     753procedure TUnitMove.SetCellTo(AValue: TCell);
    731754begin
    732755  if FCellTo = AValue then Exit;
     
    740763end;
    741764
    742 constructor TMove.Create;
     765constructor TUnitMove.Create;
    743766begin
    744767  FCellFrom := nil;
     
    746769end;
    747770
    748 destructor TMove.Destroy;
     771destructor TUnitMove.Destroy;
    749772var
    750773  LastState: Boolean;
     
    831854  Result := Power;
    832855  for I := 0 to MovesFrom.Count - 1 do
    833     Result := Result - TMove(MovesFrom[I]).CountOnce;
     856    Result := Result - TUnitMove(MovesFrom[I]).CountOnce;
    834857  if Result < 0 then Result := 0;
    835858end;
     
    849872begin
    850873  for I := MovesFrom.Count - 1 downto 0 do
    851     TMove(MovesFrom[I]).Free;
     874    TUnitMove(MovesFrom[I]).Free;
    852875  FreeAndNil(MovesFrom);
    853876  for I := MovesTo.Count - 1 downto 0 do
    854     TMove(MovesTo[I]).Free;
     877    TUnitMove(MovesTo[I]).Free;
    855878  FreeAndNil(MovesTo);
    856879  inherited Destroy;
     
    10481071  I := 0;
    10491072  while I < Moves.Count do
    1050   with TMove(Moves[I]) do begin
     1073  with TUnitMove(Moves[I]) do begin
    10511074  if CountOnce > 0 then begin
    10521075    if CellFrom.Player = Player then begin
     
    10781101  // Remove empty moves
    10791102  for I := Moves.Count - 1 downto 0 do
    1080   if (TMove(Moves[I]).CellFrom.Player = Player) and
    1081     (TMove(Moves[I]).CountOnce = 0) and (TMove(Moves[I]).CountRepeat = 0) then
     1103  if (TUnitMove(Moves[I]).CellFrom.Player = Player) and
     1104    (TUnitMove(Moves[I]).CountOnce = 0) and (TUnitMove(Moves[I]).CountRepeat = 0) then
    10821105    Moves.Delete(I);
    10831106end;
     
    10881111begin
    10891112  for I := Moves.Count - 1 downto 0 do
    1090   if TMove(Moves[I]).CellFrom = Cell then
     1113  if TUnitMove(Moves[I]).CellFrom = Cell then
    10911114    Moves.Delete(I);
    10921115end;
     
    11101133procedure TGame.SetMove(CellFrom, CellTo: TCell; Power: Integer);
    11111134var
    1112   NewMove: TMove;
    1113   OldMove: TMove;
     1135  NewMove: TUnitMove;
     1136  OldMove: TUnitMove;
    11141137  I: Integer;
    11151138  CountOnce: Integer;
     
    11181141begin
    11191142  I := 0;
    1120   while (I < Moves.Count) and ((TMove(Moves[I]).CellFrom <> CellFrom) or
    1121     (TMove(Moves[I]).CellTo <> CellTo)) do Inc(I);
    1122   if I < Moves.Count then OldMove := TMove(Moves[I])
     1143  while (I < Moves.Count) and ((TUnitMove(Moves[I]).CellFrom <> CellFrom) or
     1144    (TUnitMove(Moves[I]).CellTo <> CellTo)) do Inc(I);
     1145  if I < Moves.Count then OldMove := TUnitMove(Moves[I])
    11231146    else OldMove := nil;
    11241147  if Assigned(OldMove) then begin
     
    11381161    if (CountOnce = 0) and (CountRepeat = 0) then Moves.Delete(I)
    11391162      else begin
    1140         TMove(Moves[I]).CountOnce := CountOnce;
    1141         TMove(Moves[I]).CountRepeat := CountRepeat;
     1163        TUnitMove(Moves[I]).CountOnce := CountOnce;
     1164        TUnitMove(Moves[I]).CountRepeat := CountRepeat;
    11421165      end;
    11431166  end else begin
    11441167    // Add new move
    11451168    if (CountOnce > 0) or (CountRepeat > 0) then begin
    1146       NewMove := TMove(Moves[Moves.Add(TMove.Create)]);
     1169      NewMove := TUnitMove(Moves[Moves.Add(TUnitMove.Create)]);
    11471170      NewMove.List := Moves;
    11481171      NewMove.CellFrom := CellFrom;
     
    11771200begin
    11781201  for I := 0 to Moves.Count - 1 do
    1179   with TMove(Moves[I]) do begin
     1202  with TUnitMove(Moves[I]) do begin
    11801203    if CellFrom.Player = Player then
    11811204      if CountRepeat <= CellFrom.GetAvialPower then
     
    11971220    SetValue(Path + '/GrowAmount', Integer(GrowAmount));
    11981221    SetValue(Path + '/GrowCells', Integer(GrowCells));
     1222    SetValue(Path + '/WinObjective', Integer(WinObjective));
    11991223  end;
    12001224end;
     
    12121236    GrowAmount := TGrowAmount(GetValue(Path + '/GrowAmount', Integer(gaBySquareRoot)));
    12131237    GrowCells := TGrowCells(GetValue(Path + '/GrowCells', Integer(gcPlayerAll)));
     1238    WinObjective := TWinObjective(GetValue(Path + '/WinObjective', Integer(woDefeatAllOponents)));
    12141239  end;
    12151240end;
     
    12231248    TotalUnits := 0;
    12241249    TotalCells := 0;
     1250    TotalCities := 0;
    12251251  end;
    12261252  Map.ComputePlayerStats;
     
    12391265end;
    12401266
     1267function TGame.GetAlivePlayersWithCities: TPlayerArray;
     1268var
     1269  I: Integer;
     1270begin
     1271  SetLength(Result, 0);
     1272  for I := 0 to Players.Count - 1 do
     1273    if TPlayer(Players[I]).TotalCities > 0 then begin
     1274      SetLength(Result, Length(Result) + 1);
     1275      Result[Length(Result) - 1] := TPlayer(Players[I]);
     1276    end;
     1277end;
     1278
    12411279procedure TGame.NextTurn;
    12421280var
    12431281  PrevPlayer: TPlayer;
    1244   AlivePlayers: TPlayerArray;
    12451282begin
    12461283  MoveAll(CurrentPlayer);
     
    12531290  until CurrentPlayer.TotalCells > 0;
    12541291  if Players.IndexOf(CurrentPlayer) < Players.IndexOf(PrevPlayer) then Inc(TurnCounter);
    1255   AlivePlayers := GetAlivePlayers;
    1256   if (Length(AlivePlayers) <= 1) then begin
    1257     Running := False;
    1258     if Assigned(OnWin) and (Length(AlivePlayers) > 0) then OnWin(TPlayer(AlivePlayers[0]));
    1259   end;
     1292  CheckWinObjective;
    12601293  UpdateRepeatMoves(CurrentPlayer);
    12611294  // For computers take view from previous human
    12621295  if CurrentPlayer.Mode = pmComputer then CurrentPlayer.View.Assign(PrevPlayer.View);
     1296end;
     1297
     1298procedure TGame.CheckWinObjective;
     1299var
     1300  AlivePlayers: TPlayerArray;
     1301  Winner: TPlayer;
     1302begin
     1303  Winner := nil;
     1304  if WinObjective = woDefeatAllOponents then begin
     1305    AlivePlayers := GetAlivePlayers;
     1306    if (Length(AlivePlayers) <= 1) then begin
     1307      if Length(AlivePlayers) > 0 then Winner := TPlayer(AlivePlayers[0]);
     1308      EndGame(Winner);
     1309    end;
     1310  end else
     1311  if WinObjective = woDefeatAllOponentsCities then begin
     1312    AlivePlayers := GetAlivePlayersWithCities;
     1313    if (Length(AlivePlayers) <= 1) then begin
     1314      if Length(AlivePlayers) > 0 then Winner := TPlayer(AlivePlayers[0]);
     1315      EndGame(Winner);
     1316    end;
     1317  end else
     1318  if WinObjective = woSpecialCaptureCell then begin
     1319    if Assigned(SpecialCaptureCell) and Assigned(SpecialCaptureCell.Player) then
     1320      EndGame(SpecialCaptureCell.Player);
     1321  end else
     1322  if WinObjective = woStayAliveForDefinedTurns then begin
     1323    // TODO: Not only one can win but multiple human players can survive.
     1324    if TurnCounter > StayAliveForDefinedTurns then
     1325      EndGame(nil);
     1326  end;
    12631327end;
    12641328
     
    12871351  VoidEnabled := True;
    12881352  VoidPercentage := 20;
     1353  MaxNeutralUnits := 4;
    12891354
    12901355  Map.Game := Self;
     
    13201385          else Terrain := ttNormal;
    13211386      end;
    1322     Power := Random(4);
     1387    Power := Random(MaxNeutralUnits + 1);
    13231388    Player := nil;
    13241389  end;
     
    13361401          raise Exception.Create(SCannotSetPlayerStartCells);
    13371402      end;
    1338       if CityEnabled then StartCell.Terrain := ttCity
    1339         else StartCell.Terrain := ttNormal;
     1403      StartCell.Terrain := ttCity;
    13401404      StartCell.Player := TPlayer(Players[I]);
    13411405      StartCell.Power := TPlayer(Players[I]).StartUnits;
     
    13451409  end;
    13461410  CurrentPlayer := TPlayer(Players[0]);
     1411end;
     1412
     1413procedure TGame.EndGame(Winner: TPlayer = nil);
     1414begin
     1415  Running := False;
     1416  if Assigned(OnWin) and Assigned(Winner) then OnWin(Winner);
    13471417end;
    13481418
     
    15331603  PosFrom, PosTo: TPoint;
    15341604  Angle: Double;
     1605  ArrowCenter: TPoint;
    15351606
    15361607procedure PaintHexagon(Pos: TPoint; Text: string);
     
    15961667          for I := 0 to Cell.MovesFrom.Count - 1 do begin
    15971668            PosFrom := CellToPos(Cell);
    1598             PosTo := CellToPos(TMove(Cell.MovesFrom[I]).CellTo);
    1599             if TMove(Cell.MovesFrom[I]).CountRepeat > 0 then Pen.Width := 2
     1669            PosTo := CellToPos(TUnitMove(Cell.MovesFrom[I]).CellTo);
     1670            if TUnitMove(Cell.MovesFrom[I]).CountRepeat > 0 then Pen.Width := 2
    16001671              else Pen.Width := 1;
    16011672            Angle := ArcTan((PosTo.Y - PosFrom.Y) / (PosTo.X - PosFrom.X));
    16021673            if Sign(PosTo.X - PosFrom.X) = -1 then Angle := Angle + Pi;
    1603             DrawArrow(Canvas, View, View.CellToCanvasPos(Point(Trunc(PosFrom.X + (PosTo.X - PosFrom.X) / 3),
    1604               Trunc(PosFrom.Y + (PosTo.Y - PosFrom.Y) / 3))),
    1605               Angle, Point(Trunc(HexSize.X / 4), Trunc(HexSize.Y / 4)));
    1606             Pen.Width := 1;
     1674            ArrowCenter := View.CellToCanvasPos(Point(Trunc(PosFrom.X + (PosTo.X - PosFrom.X) / 3),
     1675              Trunc(PosFrom.Y + (PosTo.Y - PosFrom.Y) / 3)));
     1676            DrawArrow(Canvas, View, ArrowCenter,
     1677              Angle, Point(Trunc(HexSize.X / 4), Trunc(HexSize.Y / 4)),
     1678              IntToStr(TUnitMove(Cell.MovesFrom[I]).CountOnce));
    16071679          end;
    16081680        end;
Note: See TracChangeset for help on using the changeset viewer.