Changeset 265 for trunk/UPlayer.pas


Ignore:
Timestamp:
Jan 15, 2019, 1:03:40 AM (6 years ago)
Author:
chronos
Message:
  • Modified: Cell power is now internally represented as unit power (TUnit class).
  • Modified: Allow to have only one player in the game.
  • Added: New win objective None to just play freely without any win objective.
  • Added: New win objective to capture entire map.
  • Added: TGameSystem class to represent various game play systems of other existing games.
  • Fixed: Clear correctly defender player from unit moves if his cell is captured.
  • Fixed: Do not allow to remove too many players to have at least minimum players.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/UPlayer.pas

    r262 r265  
    66
    77uses
    8   Classes, SysUtils, Graphics, UMap, DOM, fgl, XMLConf,
    9   UXMLUtils, Math, UGeometry;
     8  Classes, SysUtils, Graphics, UMap, DOM, fgl, XMLConf, UXMLUtils, Math,
     9  UGeometry, UUnit;
    1010
    1111type
     
    9696    FMode: TPlayerMode;
    9797    FOnMove: TMoveEvent;
     98    procedure MoveUnit(UnitMove: TUnitMove);
    9899    procedure SetGame(AValue: TObject); // TGame
    99100    procedure Attack(var AttackPower, DefendPower: Integer);
     
    118119    TurnStats: TGameTurnStats;
    119120    Moves: TUnitMoves;
     121    Units: TUnits;
    120122    procedure ReduceMovesPower;
    121123    procedure RemoveInvalidMoves;
     
    148150  public
    149151    Game: TObject; //TGame;
    150     NewPlayerId: Integer;
     152    NewId: Integer;
    151153    function FindById(Id: Integer): TPlayer;
    152154    procedure New(Name: string; Color: TColor; Mode: TPlayerMode);
    153     function GetNewPlayerId: Integer;
     155    function GetNewId: Integer;
    154156    procedure LoadFromNode(Node: TDOMNode);
    155157    procedure SaveToNode(Node: TDOMNode);
     
    259261  UnitMove: TUnitMove;
    260262begin
    261   Result := MapCell.Power;
     263  if Assigned(MapCell.OneUnit) then Result := MapCell.OneUnit.Power
     264    else Result := 0;
    262265  for UnitMove in MovesFrom do
    263266    Result := Result - UnitMove.CountOnce;
     
    433436  with TPlayerCell(Cells[I]) do begin
    434437    for J := 0 to MapCell.Neighbors.Count - 1 do
    435       ConnectTo(TCell(MapCell.Neighbors[J]).PlayerCell);
     438      ConnectTo(TPlayerCell(TCell(MapCell.Neighbors[J]).PlayerCell));
    436439  end;
    437440end;
     
    511514  NewPlayer.Color := Color;
    512515  NewPlayer.Mode := Mode;
    513   NewPlayer.Id := GetNewPlayerId;
     516  NewPlayer.Id := GetNewId;
    514517  if Mode = pmComputer then
    515518    NewPlayer.Agressivity := caMedium;
     
    517520end;
    518521
    519 function TPlayers.GetNewPlayerId: Integer;
    520 begin
    521   Result := NewPlayerId;
    522   Inc(NewPlayerId);
     522function TPlayers.GetNewId: Integer;
     523begin
     524  Result := NewId;
     525  Inc(NewId);
    523526end;
    524527
     
    554557begin
    555558  inherited;
    556   NewPlayerId := 1;
     559  NewId := 1;
    557560end;
    558561
     
    579582    Items[I].Game := Game;
    580583  end;
    581   NewPlayerId := Source.NewPlayerId;
     584  NewId := Source.NewId;
    582585end;
    583586
     
    589592  with Config do begin
    590593    NewCount := GetValue(DOMString(Path + '/Count'), -1);
    591     NewPlayerId := 1;
    592     if NewCount >= 2 then begin
     594    NewId := 1;
     595    if NewCount >= MinPlayerCount then begin
    593596      Self.Clear;
    594597      Count := NewCount;
    595598      for I := 0 to Count - 1 do begin
    596599        Items[I] := TPlayer.Create;
    597         Items[I].Id := GetNewPlayerId;
     600        Items[I].Id := GetNewId;
    598601        Items[I].Game := Game;
    599602        Items[I].LoadConfig(Config, Path + '/Player' + IntToStr(I));
     
    683686
    684687procedure TUnitMove.SetCellFrom(AValue: TPlayerCell);
     688var
     689  OldValue: TPlayerCell;
    685690begin
    686691  if FCellFrom = AValue then Exit;
    687   if Assigned(AValue) and not Assigned(FCellFrom) then begin
    688     if AValue.MovesFrom.IndexOf(Self) = -1 then
    689       AValue.MovesFrom.Add(Self)
     692  OldValue := FCellFrom;
     693  FCellFrom := nil;
     694  if Assigned(OldValue) then begin
     695    if OldValue.MovesFrom.IndexOf(Self) <> -1 then
     696      OldValue.MovesFrom.Remove(Self)
     697      else raise Exception.Create('Unit move not found');
     698  end;
     699  FCellFrom := AValue;
     700  if Assigned(FCellFrom) then begin
     701    if FCellFrom.MovesFrom.IndexOf(Self) = -1 then
     702      FCellFrom.MovesFrom.Add(Self)
    690703      else raise Exception.Create('Unit move already exists');
    691704  end else
    692   if not Assigned(AValue) and Assigned(FCellFrom) then begin
    693     if FCellFrom.MovesFrom.IndexOf(Self) <> -1 then
    694       FCellFrom.MovesFrom.Remove(Self)
     705end;
     706
     707procedure TUnitMove.SetCellTo(AValue: TPlayerCell);
     708var
     709  OldValue: TPlayerCell;
     710begin
     711  if FCellTo = AValue then Exit;
     712  OldValue := FCellTo;
     713  FCellTo := nil;
     714  if Assigned(OldValue) then begin
     715    if OldValue.MovesTo.IndexOf(Self) <> -1 then
     716      OldValue.MovesTo.Remove(Self)
    695717      else raise Exception.Create('Unit move not found');
    696718  end;
    697   FCellFrom := AValue;
    698 end;
    699 
    700 procedure TUnitMove.SetCellTo(AValue: TPlayerCell);
    701 begin
    702   if FCellTo = AValue then Exit;
    703   if Assigned(AValue) and not Assigned(FCellTo) then begin
    704     AValue.MovesTo.Add(Self);
     719  FCellTo := AValue;
     720  if Assigned(FCellTo) then begin
     721    if FCellTo.MovesTo.IndexOf(Self) = -1 then
     722      FCellTo.MovesTo.Add(Self)
     723      else raise Exception.Create('Unit move already exists');
    705724  end else
    706   if not Assigned(AValue) and Assigned(FCellTo) then begin
    707     FCellTo.MovesTo.Remove(Self);
    708   end;
    709   FCellTo := AValue;
    710725end;
    711726
     
    829844constructor TPlayer.Create;
    830845begin
     846  Units := TUnits.Create(False);
    831847  Moves := TUnitMoves.Create;
    832848  Moves.Player := Self;
     
    844860  FreeAndNil(PlayerMap);
    845861  FreeAndNil(Moves);
     862  FreeAndNil(Units);
    846863  inherited Destroy;
    847864end;
     
    937954
    938955function CellCompare(const Item1, Item2: TPlayerCell): Integer;
    939 begin
    940   if Item1.MapCell.Power > Item2.MapCell.Power then Result := 1
    941   else if Item1.MapCell.Power < Item2.MapCell.Power then Result := -1
     956var
     957  Stack1, Stack2: Integer;
     958begin
     959  if Assigned(Item1.MapCell.OneUnit) then Stack1 := Item1.MapCell.OneUnit.Power
     960    else Stack1 := 0;
     961  if Assigned(Item2.MapCell.OneUnit) then Stack2 := Item2.MapCell.OneUnit.Power
     962    else Stack2 := 0;
     963  if Stack1 > Stack1 then Result := 1
     964  else if Stack1 < Stack2 then Result := -1
    942965  else Result := 0;
    943966end;
    944967
    945968function CellCompareDescending(const Item1, Item2: TPlayerCell): Integer;
    946 begin
    947   if Item1.MapCell.Power > Item2.MapCell.Power then Result := -1
    948   else if Item1.MapCell.Power < Item2.MapCell.Power then Result := 1
     969var
     970  Stack1, Stack2: Integer;
     971begin
     972  if Assigned(Item1.MapCell.OneUnit) then Stack1 := Item1.MapCell.OneUnit.Power
     973    else Stack1 := 0;
     974  if Assigned(Item2.MapCell.OneUnit) then Stack2 := Item2.MapCell.OneUnit.Power
     975    else Stack2 := 0;
     976  if Stack1 > Stack2 then Result := -1
     977  else if Stack1 < Stack2 then Result := 1
    949978  else Result := 0;
    950979end;
    951980
    952 procedure TPlayer.MoveAll;
     981procedure TPlayer.MoveUnit(UnitMove: TUnitMove);
    953982var
    954983  AttackerPower: Integer;
    955984  DefenderPower: Integer;
    956985  UnitCount: Integer;
     986begin
     987  with UnitMove do begin
     988    UnitCount := CountOnce;
     989    if CountOnce > CellFrom.MapCell.OneUnit.Power then
     990      UnitCount := CellFrom.MapCell.OneUnit.Power;
     991    CountOnce := 0;
     992    if not Assigned(CellTo.MapCell.OneUnit) then begin
     993      CellTo.MapCell.OneUnit := TGame(Game).Units.AddNew(CellFrom.MapCell.OneUnit.Kind, 0);
     994      CellTo.MapCell.Player := Self;
     995    end;
     996
     997    if CellTo.MapCell.OneUnit.Player = Self then begin
     998      // Inner move
     999      CellTo.MapCell.OneUnit.Power := CellTo.MapCell.OneUnit.Power + UnitCount;
     1000    end else begin
     1001      AttackerPower := UnitCount;
     1002      if Assigned(CellTo.MapCell.OneUnit) then
     1003        DefenderPower := CellTo.MapCell.OneUnit.Power
     1004        else DefenderPower := 0;
     1005      Attack(AttackerPower, DefenderPower);
     1006      if DefenderPower = 0 then begin
     1007        // Attacker wins with possible loses
     1008        ClearMovesFromCell(CellTo);
     1009        CellTo.MapCell.Player := Self;
     1010        CellTo.MapCell.OneUnit.Player := Self;
     1011        CellTo.MapCell.OneUnit.Power := AttackerPower;
     1012      end else
     1013      if AttackerPower = 0 then begin
     1014        // Defender wins with possible loses
     1015        CellTo.MapCell.OneUnit.Power := DefenderPower;
     1016      end else
     1017        raise Exception.Create(SUnfinishedBattle);
     1018    end;
     1019    CellFrom.MapCell.OneUnit.Power := CellFrom.MapCell.OneUnit.Power - UnitCount;
     1020  end;
     1021end;
     1022
     1023procedure TPlayer.MoveAll;
     1024var
    9571025  UnitMove: TUnitMove;
    9581026begin
    9591027  for UnitMove in Moves do
    960   with UnitMove do begin
     1028  with UnitMove do
    9611029  if CountOnce > 0 then begin
    9621030    if CellFrom.MapCell.Player = Self then begin
    963       UnitCount := CountOnce;
    964       if CountOnce > CellFrom.MapCell.Power then
    965         UnitCount := CellFrom.MapCell.Power;
    966       CountOnce := 0;
    967       if CellTo.MapCell.Player = Self then begin
    968         // Inner move
    969         CellTo.MapCell.Power := CellTo.MapCell.Power + UnitCount;
    970       end else begin
    971         AttackerPower := UnitCount;
    972         DefenderPower := CellTo.MapCell.Power;
    973         Attack(AttackerPower, DefenderPower);
    974         if DefenderPower = 0 then begin
    975           // Attacker wins with possible loses
    976           ClearMovesFromCell(CellTo);
    977           CellTo.MapCell.Player := Self;
    978           CellTo.MapCell.Power := AttackerPower;
    979         end else
    980         if AttackerPower = 0 then begin
    981           // Defender wins with possible loses
    982           CellTo.MapCell.Power := DefenderPower;
    983         end else
    984           raise Exception.Create(SUnfinishedBattle);
    985       end;
    986       CellFrom.MapCell.Power := CellFrom.MapCell.Power - UnitCount;
    987     end;
     1031      MoveUnit(UnitMove);
    9881032    end;
    9891033  end;
     
    10201064var
    10211065  I: Integer;
    1022 begin
    1023   for I := Cell.MovesFrom.Count - 1 downto 0 do
    1024     Cell.MovesFrom.Delete(I);
     1066  OtherPlayerCell: TPlayerCell;
     1067begin
     1068  if Assigned(Cell.MapCell.Player) then
     1069  with TPlayer(Cell.MapCell.Player) do begin
     1070    OtherPlayerCell := PlayerMap.Cells.SearchCell(Cell.MapCell);
     1071    if Assigned(OtherPlayerCell) then begin
     1072    for I := OtherPlayerCell.MovesFrom.Count - 1 downto 0 do
     1073      Moves.Remove(OtherPlayerCell.MovesFrom[I]);
     1074    end;
     1075  end;
    10251076end;
    10261077
     
    10821133var
    10831134  Move: TUnitMove;
     1135  AvailPower: Integer;
    10841136begin
    10851137  for Move in Moves do
    10861138  with Move do begin
    1087     if CellFrom.MapCell.Player = Self then
    1088       if CountRepeat <= CellFrom.GetAvialPower then
     1139    if CellFrom.MapCell.Player = Self then begin
     1140      AvailPower := CellFrom.GetAvialPower + Move.CountOnce;
     1141      if CountRepeat <= AvailPower then
    10891142        CountOnce := CountRepeat
    1090         else CountOnce := CellFrom.GetAvialPower;
     1143        else CountOnce := AvailPower;
     1144    end;
    10911145  end;
    10921146  RemoveEmptyUnitMoves;
     
    10971151  I: Integer;
    10981152begin
    1099   if TGame(Game).EmptyCellsNeutral then
     1153  if TGame(Game).GameSystem.EmptyCellsNeutral then
    11001154  for I := 0 to PlayerMap.Cells.Count - 1 do
    11011155  with TPlayerCell(PlayerMap.Cells[I]) do begin
    1102     if MapCell.Power = 0 then MapCell.Player := nil;
     1156    if MapCell.OneUnit.Power = 0 then MapCell.Player := nil;
    11031157  end;
    11041158end;
     
    11081162  I: Integer;
    11091163begin
    1110   // Remove empty moves
    11111164  for I := Moves.Count - 1 downto 0 do
    11121165  if (TUnitMove(Moves[I]).CellFrom.MapCell.Player = Self) and
     
    11681221  with TGame(Game).Map do
    11691222  for I := 0 to Cells.Count - 1 do
    1170   with Cells[I] do begin
     1223  with TCell(Cells[I]) do begin
    11711224    if (Player = Self) and ((TGame(Game).GrowCells = gcPlayerAll) or
    11721225    ((TGame(Game).GrowCells = gcPlayerCities) and (Terrain = ttCity))) then begin
    1173       if Power < MaxPower then begin
     1226      if OneUnit.Power < MaxPower then begin
    11741227        // Increase units count
    11751228        Addition := 0;
     
    11781231        end else
    11791232        if TGame(Game).GrowAmount = gaBySquareRoot then begin
    1180           Addition := Trunc(Sqrt(Power));
     1233          Addition := Trunc(Sqrt(OneUnit.Power));
    11811234          if Addition = 0 then Addition := 1;
    11821235        end;
    1183         Power := Min(Power + Addition, MaxPower);
     1236        OneUnit.Power := Min(OneUnit.Power + Addition, MaxPower);
    11841237      end else
    1185       if Power > MaxPower then begin
     1238      if OneUnit.Power > MaxPower then begin
    11861239        // Reduce units count
    11871240        // If cell has more then MaxPower units then additional units dies
    11881241        // in twice of squeare root of unites over MaxPower
    1189         Dies := 2 * Trunc(Sqrt(Power - MaxPower));
    1190         Power := Max(Power - Dies, 0);
     1242        Dies := 2 * Trunc(Sqrt(OneUnit.Power - MaxPower));
     1243        OneUnit.Power := Max(OneUnit.Power - Dies, 0);
    11911244      end;
    11921245    end;
Note: See TracChangeset for help on using the changeset viewer.