Changeset 202 for trunk


Ignore:
Timestamp:
May 17, 2018, 5:41:47 PM (7 years ago)
Author:
chronos
Message:
  • Modified: AI player related code moved to UClientAI unit. It is now extension of TClient class to simulate regular human client.
  • Modified: More work on client-server architecture.
Location:
trunk
Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Forms/UFormClient.lfm

    r180 r202  
    1313  OnKeyUp = FormKeyUp
    1414  OnShow = FormShow
    15   LCLVersion = '1.8.0.6'
     15  LCLVersion = '1.8.2.0'
    1616  WindowState = wsMaximized
    1717  object StatusBar1: TStatusBar
     
    4848      Left = 1
    4949      Top = 2
    50       Action = Core.AGameEndTurn
     50      Action = AGameEndTurn
    5151    end
    5252    object ToolButton6: TToolButton
     
    128128      OnExecute = AStatusBarVisibleExecute
    129129    end
     130    object AGameEndTurn: TAction
     131      Caption = 'End turn'
     132      ImageIndex = 0
     133      OnExecute = AGameEndTurnExecute
     134    end
    130135  end
    131136  object PopupMenuToolbar: TPopupMenu
  • trunk/Forms/UFormClient.pas

    r185 r202  
    77uses
    88  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
    9   UGame, LCLType, Menus, ActnList, ComCtrls, dateutils, XMLConf, DOM,
    10   UGeometry, UGameClient;
     9  UGame, LCLType, Menus, ActnList, ComCtrls, dateutils, XMLConf, DOM, UCommPin,
     10  UGeometry, UGameClient, UGameProtocol;
    1111
    1212const
     
    1919
    2020  TFormClient = class(TForm)
     21    AGameEndTurn: TAction;
    2122    AStatusBarVisible: TAction;
    2223    AToolBarVisible: TAction;
     
    3738    ToolButton8: TToolButton;
    3839    ToolButton9: TToolButton;
     40    procedure AGameEndTurnExecute(Sender: TObject);
    3941    procedure AStatusBarVisibleExecute(Sender: TObject);
    4042    procedure AToolBarBigIconsExecute(Sender: TObject);
     
    196198    Caption := NewCaption;
    197199    Drawing := False;
     200    AGameEndTurn.Enabled := Core.Game.Running;
    198201  end;
    199202end;
     
    299302  AStatusBarVisible.Checked := not AStatusBarVisible.Checked;
    300303  ReloadView;
     304end;
     305
     306procedure TFormClient.AGameEndTurnExecute(Sender: TObject);
     307var
     308  P: TGameProtocolClient;
     309  P2: TCommPin;
     310begin
     311  P := Client.Protocol;
     312  P2 := P.Pin;
     313  Client.Protocol.TurnEnd;
    301314end;
    302315
  • trunk/Languages/xtactics.cs.po

    r198 r202  
    151151msgid "Chat:"
    152152msgstr "Pokec:"
     153
     154#: tformclient.agameendturn.caption
     155#, fuzzy
     156msgctxt "tformclient.agameendturn.caption"
     157msgid "End turn"
     158msgstr "Ukončit tah"
    153159
    154160#: tformclient.astatusbarvisible.caption
  • trunk/Languages/xtactics.po

    r198 r202  
    140140#: tformchat.label1.caption
    141141msgid "Chat:"
     142msgstr ""
     143
     144#: tformclient.agameendturn.caption
     145msgctxt "tformclient.agameendturn.caption"
     146msgid "End turn"
    142147msgstr ""
    143148
  • trunk/Packages/CoolStreaming/UVarBlockSerializer.pas

    r185 r202  
    191191  // Get bit length
    192192  Length := SizeOf(QWord) * BitAlignment;
    193   while (((Value shr Length) and 1) = 0) and (Length > 0) do
     193  while ((Value and (QWord(1) shl (Length - 1))) = 0) and (Length > 0) do
    194194    Dec(Length);
    195195  Inc(Length);
  • trunk/UCore.pas

    r199 r202  
    99  UGame, UApplicationInfo, UPersistentForm, UScaleDPI, UCoolTranslator,
    1010  URegistry, ULastOpenedList, Registry, Menus, UGeometry, UFormClient,
    11   UGameServer, UGameClient, fgl, UServerList;
     11  UGameServer, UGameClient, fgl, UServerList, UGameProtocol;
    1212
    1313type
     
    6565    GameLoaded: Boolean;
    6666    procedure LoadRecentExecute(Sender: TObject);
    67     procedure ProcessComputerTurns;
    6867    procedure StartNewGame;
    6968    procedure DoPlayerChange(Sender: TObject);
     
    9190    ReopenLastFile: Boolean;
    9291    FormClients: TFPGObjectList<TFormClient>;
    93     Clients: TClients;
     92    LocalClients: TClients;
    9493    ServerList: TServerList;
    9594    procedure Spectate(Player: TPlayer);
     
    109108
    110109uses
    111   UFormMain, UFormNew, UFormSettings, UFormAbout,
     110  UFormMain, UFormNew, UFormSettings, UFormAbout, UClientAI,
    112111  UFormHelp, UFormCharts, UFormUnitMoves, UFormPlayersStats;
    113112
     
    240239begin
    241240  FirstHuman := Game.Players.GetFirstHuman;
    242   if Assigned(FirstHuman) then FormClient.Client := Clients.SearchPlayer(FirstHuman)
    243     else FormClient.Client := TClient(Clients.First);
     241  if Assigned(FirstHuman) then FormClient.Client := LocalClients.SearchPlayer(FirstHuman)
     242    else FormClient.Client := TClient(LocalClients.First);
    244243end;
    245244
     
    275274end;
    276275
    277 procedure TCore.ProcessComputerTurns;
    278 begin
    279   while Game.Running and (Game.CurrentPlayer.Mode <> pmHuman) do begin
    280     if Game.CurrentPlayer.Mode = pmComputer then begin
    281       Game.CurrentPlayer.Computer.Process;
    282       RedrawClients;
    283       Delay(Trunc((100 - AnimationSpeed) / 100 * 2000));
    284     end;
    285     Game.NextTurn;
    286     RedrawClients;
    287     Application.ProcessMessages;
    288     Sleep(1);
    289   end;
    290 end;
    291 
    292276procedure TCore.AGameEndTurnExecute(Sender: TObject);
    293277begin
    294   Game.NextTurn;
     278  Game.NextPlayer;
    295279  RedrawClients;
    296   ProcessComputerTurns;
    297280  UpdateActions;
    298281end;
     
    399382begin
    400383  Server := TServer.Create;
    401   Clients := TClients.Create;
     384  LocalClients := TClients.Create;
    402385  GameSettings := TGame.Create;
    403386  Game := TGame.Create;
     
    407390  Game.OnPlayerChange := DoPlayerChange;
    408391  Server.Game := Game;
    409   Clients.Game := Game;
     392  LocalClients.Game := Game;
    410393  StoredDimension := TControlDimension.Create;
    411394  XMLConfig1.Filename := GetAppConfigDir(False) + 'Config.xml';
     
    424407  FreeAndNil(StoredDimension);
    425408  FreeAndNil(Server);
    426   FreeAndNil(Clients);
     409  FreeAndNil(LocalClients);
    427410  FreeAndNil(Game);
    428411  FreeAndNil(GameSettings);
     
    448431  Game.LoadFromFile(FileName);
    449432  Server.InitClients;
    450 
    451   // Create local clients for human players
     433  Server.Active := True;
     434
     435  // Create local LocalClients for human players
    452436  for Player in Game.Players do
    453437  with Player do
    454438  if Mode = pmHuman then begin
    455     NewClient := Clients.New(Name);
     439    NewClient := LocalClients.New(Name);
    456440    NewClient.ControlPlayer := Player;
    457441    NewClient.View.Clear;
    458442    NewClient.View.Zoom := 1;
     443    NewClient.LocalServer := Server;
     444    NewClient.ConnectType := ctLocal;
     445    NewClient.Active := True;
    459446    if Assigned(NewClient.ControlPlayer.StartCell) then
    460447      NewClient.View.CenterPlayerCity(NewClient.ControlPlayer)
    461448      else NewClient.View.CenterMap;
     449  end else
     450  if Mode = pmComputer then begin
     451    NewClient := TComputer.Create;
     452    NewClient.Game := Game;
     453    NewClient.Name := Name;
     454    LocalClients.Add(NewClient);
     455    NewClient.ControlPlayer := Player;
     456    NewClient.LocalServer := Server;
     457    NewClient.ConnectType := ctLocal;
     458    NewClient.Active := True;
    462459  end;
    463460
     
    493490begin
    494491  Form := TFormClient.Create(nil);
    495   Form.Client := Clients.New(SSpectator);
     492  Form.Client := LocalClients.New(SSpectator);
    496493  //Form.Client.Form := Form;
    497494  //Form.Client.ControlPlayer := Player;
     
    505502  NewClient: TClient;
    506503  Player: TPlayer;
     504  ServerClient: TServerClient;
    507505begin
    508506  Game.New;
    509507  Server.InitClients;
    510 
    511   // Create local clients for human players
     508  Server.Active := True;
     509
     510  // Create local LocalClients for human players
    512511  for Player in Game.Players do
    513512  with Player do
    514513  if Mode = pmHuman then begin
    515     NewClient := Clients.New(Name);
     514    NewClient := LocalClients.New(Name);
    516515    NewClient.ControlPlayer := Player;
    517516    NewClient.View.Clear;
    518517    NewClient.View.Zoom := 1;
     518    NewClient.LocalServer := Server;
     519    NewClient.ConnectType := ctLocal;
     520    NewClient.Active := True;
    519521    if Assigned(NewClient.ControlPlayer.StartCell) then
    520522      NewClient.View.CenterPlayerCity(NewClient.ControlPlayer)
    521523      else NewClient.View.CenterMap;
     524  end else
     525  if Mode = pmComputer then begin
     526    NewClient := TComputer.Create;
     527    NewClient.Game := Game;
     528    NewClient.Name := Name;
     529    LocalClients.Add(NewClient);
     530    NewClient.ControlPlayer := Player;
     531    NewClient.LocalServer := Server;
     532    NewClient.ConnectType := ctLocal;
     533    NewClient.Active := True;
    522534  end;
    523535
     
    528540  RedrawClients;
    529541  UpdateOtherForms;
    530   ProcessComputerTurns;
    531542  UpdateActions;
     543  ServerClient := Server.Clients.SearchByPlayer(Game.CurrentPlayer);
     544  if Assigned(ServerClient) then ServerClient.TurnStart
     545    else raise Exception.Create('Server client for current player not found.');
    532546end;
    533547
     
    535549var
    536550  PlayerClient: TClient;
     551  ServerClient: TServerClient;
    537552begin
    538553  if Assigned(Game.CurrentPlayer) then begin
    539     PlayerClient := Clients.SearchPlayer(Game.CurrentPlayer);
     554    PlayerClient := LocalClients.SearchPlayer(Game.CurrentPlayer);
    540555    if Assigned(PlayerClient) then FormClient.Client := PlayerClient;
     556
     557    ServerClient := Server.Clients.SearchByPlayer(Game.CurrentPlayer);
     558    if Assigned(ServerClient) then ServerClient.TurnStart;
    541559  end;
    542560  UpdateOtherForms;
  • trunk/UGame.pas

    r199 r202  
    290290  TPlayerMode = (pmHuman, pmComputer);
    291291  TComputerAgressivity = (caLow, caMedium, caHigh);
    292   TComputer = class;
    293292  TUnitMove = class;
    294293
     
    310309    procedure CheckCounterMove(Move: TUnitMove);
    311310    procedure SetMode(AValue: TPlayerMode);
    312     function SetMove(CellFrom, CellTo: TCell; Power: Integer; Confirmation: Boolean = True): TUnitMove;
    313311    procedure UpdateRepeatMoves;
    314312    procedure RemoveEmptyUnitMoves;
     
    328326    TurnStats: TGameTurnStats;
    329327    Moves: TUnitMoves;
    330     Computer: TComputer;
     328    function SetMove(CellFrom, CellTo: TCell; Power: Integer; Confirmation: Boolean = True): TUnitMove;
    331329    procedure Reset;
    332330    function IsAlive: Boolean;
     
    343341    property Mode: TPlayerMode read FMode write SetMode;
    344342    property OnMove: TMoveEvent read FOnMove write FOnMove;
    345   end;
    346 
    347     { TComputer }
    348 
    349   TComputer = class
    350     Game: TGame;
    351     //Targets: TFPGObjectList<TPlayer>;
    352     CellProcessDirection: Boolean;
    353     Player: TPlayer;
    354     procedure AttackNeutral;
    355     procedure AttackPlayers;
    356     procedure InnerMoves;
    357     procedure IncreaseMoves;
    358     procedure Process;
    359     procedure FallBack;
    360     function AttackersCount(Cell: TCell): Integer;
    361343  end;
    362344
     
    474456    procedure SaveToFile(FileName: string);
    475457    procedure ComputePlayerStats;
    476     procedure NextTurn;
     458    procedure NextPlayer;
    477459    procedure CheckWinObjective;
    478460    constructor Create;
     
    502484
    503485procedure InitStrings;
     486function CellCompare(const Item1, Item2: TCell): Integer;
     487function CellCompareDescending(const Item1, Item2: TCell): Integer;
    504488
    505489resourcestring
     
    20962080  FGame := AValue;
    20972081  Moves.Game := AValue;
    2098   Computer.Game := AValue;
    20992082end;
    21002083
     
    21872170  PlayerMap.Player := Self;
    21882171  TurnStats := TGameTurnStats.Create;
    2189   Computer := TComputer.Create;
    2190   Computer.Player := Self;
    21912172end;
    21922173
     
    21942175begin
    21952176  //Client := nil;
    2196   FreeAndNil(Computer);
    21972177  FreeAndNil(TurnStats);
    21982178  FreeAndNil(PlayerMap);
     
    22142194  Agressivity := Source.Agressivity;
    22152195  Defensive := Source.Defensive;
    2216   Computer.Game := Source.Computer.Game;
    2217   Computer.CellProcessDirection := Source.Computer.CellProcessDirection;
    22182196end;
    22192197
     
    23012279  else if Item1.Power < Item2.Power then Result := 1
    23022280  else Result := 0;
    2303 end;
    2304 
    2305 { TComputer }
    2306 
    2307 procedure TComputer.AttackNeutral;
    2308 var
    2309   AllCells: TCells;
    2310   TotalPower: Integer;
    2311   AttackPower: Integer;
    2312   TotalAttackPower: Integer;
    2313   CanAttack: Integer;
    2314   TargetCells: TCells;
    2315   Cell: TCell;
    2316   NeighborCell: TCell;
    2317 const
    2318   AttackDiff = 1;
    2319 begin
    2320   AllCells := Game.Map.Cells;
    2321   TargetCells := TCells.Create;
    2322   TargetCells.FreeObjects := False;
    2323 
    2324   // Get list of all attack target cells
    2325   for Cell in AllCells do
    2326   with Cell do begin
    2327     if (Terrain <> ttVoid) and (Player = nil) then begin
    2328       CanAttack := 0;
    2329       for NeighborCell in Neighbors do
    2330       if NeighborCell.Player = Game.CurrentPlayer then begin
    2331         Inc(CanAttack);
    2332       end;
    2333       if CanAttack > 0 then TargetCells.Add(Cell);
    2334     end;
    2335   end;
    2336 
    2337   // Sort ascending to attack cells with lower power first
    2338   // Low power cells are better for expanding our teritorry
    2339   TargetCells.Sort(CellCompare);
    2340 
    2341   for Cell in TargetCells do
    2342   with Cell do begin
    2343       // Attack to not owned cell yet
    2344       // Count own possible power
    2345       TotalPower := 0;
    2346       for NeighborCell in Neighbors do
    2347       if NeighborCell.Player = Game.CurrentPlayer then
    2348         TotalPower := TotalPower + NeighborCell.GetAvialPower;
    2349 
    2350       // Attack if target is weaker
    2351       if TotalPower >= (Power + AttackDiff) then begin
    2352         TotalAttackPower := 0;
    2353         for NeighborCell in Neighbors do
    2354         if NeighborCell.Player = Game.CurrentPlayer then begin
    2355           // Use only necessary power
    2356           AttackPower := Power - TotalAttackPower + AttackDiff;
    2357           if NeighborCell.GetAvialPower < AttackPower then
    2358             AttackPower := NeighborCell.GetAvialPower;
    2359           Self.Player.SetMove(NeighborCell, Cell, AttackPower, False);
    2360           TotalAttackPower := TotalAttackPower + AttackPower;
    2361         end;
    2362       end;
    2363   end;
    2364 
    2365   FreeAndNil(TargetCells);
    2366 end;
    2367 
    2368 procedure TComputer.AttackPlayers;
    2369 var
    2370   AllCells: TCells;
    2371   TotalPower: Integer;
    2372   AttackPower: Integer;
    2373   TotalAttackPower: Integer;
    2374   CanAttack: Integer;
    2375   TargetCells: TCells;
    2376   TargetCell: TCell;
    2377   NeighborCell: TCell;
    2378 begin
    2379   if Player.Defensive then Exit;
    2380 
    2381   AllCells := Game.Map.Cells;
    2382   TargetCells := TCells.Create;
    2383   TargetCells.FreeObjects := False;
    2384 
    2385   // Get list of all attack target cells
    2386   for TargetCell in AllCells do begin
    2387     if (TargetCell.Terrain <> ttVoid) and (TargetCell.Player <> Player) and
    2388       (TargetCell.Player <> nil) then begin
    2389       CanAttack := 0;
    2390       for NeighborCell in TargetCell.Neighbors do
    2391       if NeighborCell.Player = Player then begin
    2392         Inc(CanAttack);
    2393       end;
    2394       if CanAttack > 0 then TargetCells.Add(TargetCell);
    2395     end;
    2396   end;
    2397 
    2398   // Sort descending to attack cells with higher power first
    2399   // Higher power enemy cells can grow faster and is more dangerous
    2400   TargetCells.Sort(CellCompareDescending);
    2401 
    2402   for TargetCell in TargetCells do begin
    2403       // Attack to not owned cell yet
    2404       // Count own possible power
    2405       TotalPower := 0;
    2406       for NeighborCell in TargetCell.Neighbors do
    2407       if NeighborCell.Player = Player then begin
    2408         TotalPower := TotalPower + NeighborCell.GetAvialPower;
    2409       end;
    2410       // Attack if target is weaker
    2411       if Game.AttackProbability(TotalPower, TargetCell.Power) >=
    2412         ComputerAggroProbability[Player.Agressivity] then begin
    2413         // Try to limit total attacking power to necessary minimum
    2414         while Game.AttackProbability(TotalPower - 1, TargetCell.Power) >=
    2415           ComputerAggroProbability[Player.Agressivity] do
    2416           Dec(TotalPower);
    2417 
    2418         // Collect required attack units from our cells
    2419         TotalAttackPower := 0;
    2420         for NeighborCell in TargetCell.Neighbors do
    2421         if NeighborCell.Player = Player then begin
    2422           // Use only necessary power
    2423           AttackPower := TotalPower - TotalAttackPower;
    2424           if NeighborCell.GetAvialPower < AttackPower then
    2425             AttackPower := NeighborCell.GetAvialPower;
    2426           Self.Player.SetMove(NeighborCell, TargetCell, AttackPower, False);
    2427           TotalAttackPower := TotalAttackPower + AttackPower;
    2428           if TotalAttackPower >= TotalPower then Break;
    2429         end;
    2430       end;
    2431   end;
    2432 
    2433   FreeAndNil(TargetCells);
    2434 end;
    2435 
    2436 procedure TComputer.InnerMoves;
    2437 var
    2438   AllCells: TCells;
    2439   I, J: Integer;
    2440   C: Integer;
    2441   CanAttack: Integer;
    2442   TargetCells: TCells;
    2443   NewTargetCells: TCells;
    2444   Cells2: TCells;
    2445   MovedPower: Integer;
    2446 begin
    2447   // We need to move available power to borders to be available for attacks
    2448   // or defense
    2449   AllCells := Game.Map.Cells;
    2450   TargetCells := TCells.Create;
    2451   TargetCells.FreeObjects := False;
    2452   NewTargetCells := TCells.Create;
    2453   NewTargetCells.FreeObjects := False;
    2454 
    2455   // Get list of all enemy border cells
    2456   for C := 0 to AllCells.Count - 1 do
    2457   with AllCells[C] do begin
    2458     if (Player <> Game.CurrentPlayer) and (Player <> nil) and (Terrain <> ttVoid) then begin
    2459       CanAttack := 0;
    2460       for I := 0 to Neighbors.Count - 1 do
    2461       if ((Neighbors[I].Player = Game.CurrentPlayer) or
    2462       (Neighbors[I].Player = nil)) and (Neighbors[I].Terrain <> ttVoid) then begin
    2463         Inc(CanAttack);
    2464       end;
    2465       if CanAttack > 0 then TargetCells.Add(AllCells[C]);
    2466     end;
    2467   end;
    2468 
    2469   if CellProcessDirection then begin
    2470     // Reverse array
    2471     for I := 0 to (TargetCells.Count div 2) - 1 do
    2472       TargetCells.Exchange(I, TargetCells.Count - 1 - I);
    2473   end;
    2474 
    2475   Game.Map.Cells.ClearMark;
    2476 
    2477   while TargetCells.Count > 0 do begin
    2478     // Set mark for selected border cells
    2479     for C := 0 to TargetCells.Count - 1 do
    2480       TargetCells[C].Mark := True;
    2481 
    2482     // Move all power from unmarked cells and mark them
    2483     NewTargetCells.Count := 0;
    2484     for C := 0 to TargetCells.Count - 1 do
    2485     with TargetCells[C] do begin
    2486       for I := 0 to Neighbors.Count - 1 do begin
    2487         if (Neighbors[I].Terrain <> ttVoid) and (not Neighbors[I].Mark) then begin
    2488           if (TargetCells[C].Player = Game.CurrentPlayer) and
    2489           (Neighbors[I].Player = Game.CurrentPlayer) then begin
    2490             // Do not take units from front line
    2491             Cells2 := Neighbors[I].Neighbors;
    2492             CanAttack := 0;
    2493             for J := 0 to Cells2.Count - 1 do
    2494             if ((Cells2[J].Player <> Game.CurrentPlayer) or (Cells2[J].Player = nil))
    2495             and (Cells2[J].Terrain <> ttVoid) then begin
    2496               Inc(CanAttack);
    2497             end;
    2498             if CanAttack = 0 then begin
    2499               MovedPower := Neighbors[I].GetAvialPower;
    2500               if (TargetCells[C].GetAvialPower + TargetCells[C].GetAttackPower + MovedPower) > Game.Map.MaxPower then
    2501                 MovedPower := Game.Map.MaxPower - TargetCells[C].GetAvialPower - TargetCells[C].GetAttackPower;
    2502               Player.SetMove(Neighbors[I], TargetCells[C], MovedPower, False);
    2503             end;
    2504           end;
    2505           Neighbors[I].Mark := True;
    2506           NewTargetCells.Add(Neighbors[I]);
    2507         end;
    2508       end;
    2509     end;
    2510 
    2511     // Use source cells NewTargetCells as new TargetCells
    2512     FreeAndNil(TargetCells);
    2513     TargetCells := NewTargetCells;
    2514     NewTargetCells := TCells.Create;
    2515     NewTargetCells.FreeObjects := False;
    2516   end;
    2517 
    2518   FreeAndNil(TargetCells);
    2519   FreeAndNil(NewTargetCells);
    2520 end;
    2521 
    2522 procedure TComputer.IncreaseMoves;
    2523 var
    2524   Move: TUnitMove;
    2525   AvailPower: Integer;
    2526 begin
    2527   // If available power remains then use all for existed unit moves
    2528   for Move in Player.Moves do
    2529   with Move do begin
    2530     if CellFrom.GetAvialPower > 0 then begin
    2531       AvailPower := CellFrom.GetAvialPower;
    2532       CountOnce := CountOnce + Min(AvailPower div CellFrom.MovesFrom.Count, AvailPower);
    2533     end;
    2534   end;
    2535 end;
    2536 
    2537 procedure TComputer.Process;
    2538 begin
    2539   AttackPlayers;
    2540   AttackNeutral;
    2541   InnerMoves;
    2542   IncreaseMoves;
    2543   //FallBack;
    2544   CellProcessDirection := not CellProcessDirection;
    2545 end;
    2546 
    2547 procedure TComputer.FallBack;
    2548 var
    2549   C: Integer;
    2550   I: Integer;
    2551   AllCells: TCells;
    2552   BorderCells: TCells;
    2553   EnemyPower: Integer;
    2554 begin
    2555   BorderCells := TCells.Create;
    2556   BorderCells.FreeObjects := False;
    2557   AllCells := Game.Map.Cells;
    2558 
    2559   // Get list of border cells
    2560   for C := 0 to AllCells.Count - 1 do
    2561   with AllCells[C] do begin
    2562     if (Terrain <> ttVoid) and (Player = Game.CurrentPlayer)  then begin
    2563       if AttackersCount(AllCells[C]) > 0 then
    2564         BorderCells.Add(AllCells[C]);
    2565     end;
    2566   end;
    2567 
    2568   // Move all units back to inner area from weak border cells
    2569   for C := 0 to BorderCells.Count - 1 do
    2570   with BorderCells[C] do begin
    2571     // Calculate enemy power
    2572     // TODO: Do not sum different enemy power to one value
    2573     EnemyPower := 0;
    2574     for I := 0 to Neighbors.Count - 1 do
    2575     if (Neighbors[I].Player <> Game.CurrentPlayer) and (Neighbors[I].Player <> nil) then begin
    2576       Inc(EnemyPower, Neighbors[I].Power);
    2577     end;
    2578     if EnemyPower > (GetAvialPower + GetAttackPower) then begin
    2579       // Fallback
    2580       for I := MovesTo.Count - 1 downto 0 do
    2581         Player.Moves.Remove(MovesTo[I]);
    2582       for I := 0 to Neighbors.Count - 1 do
    2583       if (Neighbors[I].Player = Player) and (AttackersCount(Neighbors[I]) = 0) then begin
    2584         Player.SetMove(BorderCells[C], Neighbors[I], GetAvialPower, False);
    2585         Break;
    2586       end;
    2587     end;
    2588   end;
    2589 
    2590   FreeAndNil(BorderCells);
    2591 end;
    2592 
    2593 function TComputer.AttackersCount(Cell: TCell): Integer;
    2594 var
    2595   I: Integer;
    2596 begin
    2597   Result := 0;
    2598   for I := 0 to Cell.Neighbors.Count - 1 do
    2599   if (Cell.Neighbors[I].Player <> Game.CurrentPlayer) and
    2600     (Cell.Neighbors[I].Player <> nil) then begin
    2601       Inc(Result);
    2602   end;
    26032281end;
    26042282
     
    34573135end;
    34583136
    3459 procedure TGame.NextTurn;
     3137procedure TGame.NextPlayer;
    34603138var
    34613139  PrevPlayer: TPlayer;
    34623140begin
    3463   //TODO CurrentPlayer.View.SelectedCell := nil;
     3141  // Finalize current player
    34643142  CurrentPlayer.MoveAll;
    34653143  Map.Grow(CurrentPlayer);
    34663144  CurrentPlayer.UpdateRepeatMoves;
    34673145  ComputePlayerStats;
     3146
     3147  // Select new player
    34683148  PrevPlayer := CurrentPlayer;
    34693149  // Skip dead players
     
    34823162  CurrentPlayer.PlayerMap.CheckVisibility;
    34833163  CurrentPlayer.ReduceMovesPower;
    3484   // For computers take view from previous human
    3485   //if CurrentPlayer.Mode = pmComputer then CurrentPlayer.View.Assign(PrevPlayer.View);
    34863164  if Assigned(FOnChange) then
    34873165    FOnChange(Self);
  • trunk/UGameClient.pas

    r185 r202  
    66
    77uses
    8   Classes, SysUtils, UGame, Forms, fgl, UGameProtocol;
     8  Classes, SysUtils, UGame, Forms, fgl, UGameProtocol, UGameServer;
    99
    1010type
     11  TClientConnectType = (ctLocal, ctNetwork);
     12
    1113  { TClient }
    1214
    1315  TClient = class
    1416  private
     17    FActive: Boolean;
    1518    FForm: TForm;
    1619    FGame: TGame;
     
    1922    FOnReceive: TCommandEvent;
    2023    FOnMove: TMoveEvent;
     24    procedure SetActive(AValue: Boolean);
    2125    procedure SetControlPlayer(AValue: TPlayer);
    2226    procedure SetForm(AValue: TForm);
     
    2428    procedure PlayerMove(CellFrom, CellTo: TCell; var CountOnce, CountRepeat: Integer;
    2529      Update: Boolean; var Confirm: Boolean);
    26     procedure ReceiveCmd(Command: TCommand; DataOut, DataIn: TStream);
     30  protected
     31    procedure ReceiveCmd(Command: TCommand; DataOut, DataIn: TStream); virtual;
     32    procedure DoTurnStart(Sender: TObject); virtual;
    2733  public
    2834    Name: string;
    2935    View: TView;
     36    LocalServer: TServer;
     37    RemoteAddress: string;
     38    RemotePort: Word;
     39    ConnectType: TClientConnectType;
    3040    Protocol: TGameProtocolClient;
    3141    procedure DoChange;
     
    3848    property OnReceive: TCommandEvent read FOnReceive write FOnReceive;
    3949    property OnChange: TNotifyEvent read FOnChange write FOnChange;
     50    property Active: Boolean read FActive write SetActive;
    4051  end;
    4152
     
    107118end;
    108119
     120procedure TClient.DoTurnStart(Sender: TObject);
     121begin
     122
     123end;
     124
    109125procedure TClient.SetControlPlayer(AValue: TPlayer);
    110126begin
     
    115131  if Assigned(FControlPlayer) then begin
    116132     FControlPlayer.OnMove := PlayerMove;
     133  end;
     134end;
     135
     136procedure TClient.SetActive(AValue: Boolean);
     137var
     138  ServerClient: TServerClient;
     139begin
     140  if FActive = AValue then Exit;
     141  FActive := AValue;
     142  if FActive then begin
     143    case ConnectType of
     144      ctLocal: if LocalServer.Active then begin
     145        ServerClient := LocalServer.GetNewServerClient;
     146        ServerClient.Player := ControlPlayer;
     147        ServerClient.Protocol.Pin.Connect(Protocol.Pin);
     148      end else raise Exception.Create('Local server is not active');
     149      //ctNetwork: ;
     150    end;
     151  end else begin
     152    Protocol.Pin.Disconnect;
    117153  end;
    118154end;
     
    129165  View := TView.Create;
    130166  Protocol := TGameProtocolClient.Create;
     167  Protocol.OnTurnStart := DoTurnStart;
    131168end;
    132169
  • trunk/UGameProtocol.pas

    r185 r202  
    2222    FOnGameEnd: TNotifyEvent;
    2323    FOnGameStart: TNotifyEvent;
     24    FOnTurnStart: TNotifyEvent;
    2425    procedure Receive(Sender: TCommPin; Stream: TListByte);
     26    procedure SendCmd(Command: TCommand);
    2527  public
    2628    Pin: TCommPin;
     29    procedure TurnEnd;
    2730    procedure SendMessage(Text: string);
    2831    constructor Create;
     
    3235    property OnGameEnd: TNotifyEvent read FOnGameEnd
    3336      write FOnGameEnd;
     37    property OnTurnStart: TNotifyEvent read FOnTurnStart
     38      write FOnTurnStart;
    3439  end;
    3540
     
    4146  private
    4247    FOnSendMessage: TSendMessageEvent;
     48    FOnTurnEnd: TNotifyEvent;
    4349    procedure Receive(Sender: TCommPin; Stream: TListByte);
     50    procedure SendCmd(Command: TCommand);
    4451  public
    4552    Pin: TCommPin;
     
    4855    procedure GameStart;
    4956    procedure GameEnd;
     57    procedure TurnStart;
    5058    property OnSendMessage: TSendMessageEvent read FOnSendMessage
    5159      write FOnSendMessage;
     60    property OnTurnEnd: TNotifyEvent read FOnTurnEnd
     61      write FOnTurnEnd;
    5262  end;
    5363
     
    6979    if Command = Integer(cmdTextMessage) then begin
    7080      if Assigned(FOnSendMessage) then FOnSendMessage(Data.ReadVarString);
     81    end else
     82    if Command = Integer(cmdTurnEnd) then begin
     83      if Assigned(FOnTurnEnd) then FOnTurnEnd(Self);
    7184    end;
    7285  finally
     
    7588end;
    7689
    77 constructor TGameProtocolServer.Create;
    78 begin
    79   Pin := TCommPin.Create;
    80   Pin.OnReceive := Receive;
    81 end;
    82 
    83 destructor TGameProtocolServer.Destroy;
    84 begin
    85   Pin.Free;
    86   inherited Destroy;
    87 end;
    88 
    89 procedure TGameProtocolServer.GameStart;
     90procedure TGameProtocolServer.SendCmd(Command: TCommand);
    9091var
    9192  Data: TVarBlockSerializer;
     
    9596  Data2 := TListByte.Create;
    9697  try
    97     Data.WriteVarUInt(Integer(cmdGameStart));
     98    Data.WriteVarUInt(Integer(Command));
    9899    Data.Stream.Position := 0;
    99100    Data.ReadVarList(Data2);
     
    105106end;
    106107
     108constructor TGameProtocolServer.Create;
     109begin
     110  Pin := TCommPin.Create;
     111  Pin.OnReceive := Receive;
     112end;
     113
     114destructor TGameProtocolServer.Destroy;
     115begin
     116  Pin.Free;
     117  inherited Destroy;
     118end;
     119
     120procedure TGameProtocolServer.GameStart;
     121begin
     122  SendCmd(cmdGameStart);
     123end;
     124
    107125procedure TGameProtocolServer.GameEnd;
    108 var
    109   Data: TVarBlockSerializer;
    110   Data2: TListByte;
    111 begin
    112   Data := TVarBlockSerializer.Create;
    113   Data2 := TListByte.Create;
    114   try
    115     Data.WriteVarUInt(Integer(cmdGameEnd));
    116     Data.Stream.Position := 0;
    117     Data.ReadVarList(Data2);
    118     Pin.Send(Data2);
    119   finally
    120     Data2.Free;
    121     Data.Free;
    122   end;
     126begin
     127  SendCmd(cmdGameEnd);
     128end;
     129
     130procedure TGameProtocolServer.TurnStart;
     131begin
     132  SendCmd(cmdTurnStart);
    123133end;
    124134
     
    131141begin
    132142  Data := TVarBlockSerializer.Create;
    133   Data.ReadVarList(Stream);
     143  Data.WriteVarList(Stream);
    134144  Data.Stream.Position := 0;
    135145  Command := Data.ReadVarSInt;
     
    140150    if Command = Integer(cmdGameEnd) then begin
    141151      if Assigned(FOnGameEnd) then FOnGameEnd(Self);
     152    end else
     153    if Command = Integer(cmdTurnStart) then begin
     154      if Assigned(FOnTurnStart) then FOnTurnStart(Self);
    142155    end;
    143156  finally
    144157    Data.Free;
    145158  end;
     159end;
     160
     161procedure TGameProtocolClient.SendCmd(Command: TCommand);
     162var
     163  Data: TVarBlockSerializer;
     164  Data2: TListByte;
     165begin
     166  Data := TVarBlockSerializer.Create;
     167  Data2 := TListByte.Create;
     168  try
     169    Data.WriteVarUInt(Integer(Command));
     170    Data.Stream.Position := 0;
     171    Data.ReadVarList(Data2);
     172    Pin.Send(Data2);
     173  finally
     174    Data2.Free;
     175    Data.Free;
     176  end;
     177end;
     178
     179procedure TGameProtocolClient.TurnEnd;
     180begin
     181  SendCmd(cmdTurnEnd);
    146182end;
    147183
  • trunk/UGameServer.pas

    r199 r202  
    66
    77uses
    8   Classes, SysUtils, UGame, DOM, XMLConf, fgl,
    9   UGameProtocol;
     8  Classes, SysUtils, UGame, DOM, XMLConf, fgl, UGameProtocol;
    109
    1110type
     
    1817    FOnReceiveCmd: TCommandEvent;
    1918    procedure ReceiveCmd(Command: TCommand; DataOut, DataIn: TStream);
     19    procedure DoTurnEnd(Sender: TObject);
    2020  public
    2121    Game: TGame;
    2222    Protocol: TGameProtocolServer;
     23    Player: TPlayer;
    2324    procedure DoChange;
    2425    procedure SendCmd(Command: TCommand; DataOut, DataIn: TStream);
     26    procedure TurnStart;
    2527    property OnReceiveCmd: TCommandEvent read FOnReceiveCmd write
    2628      FOnReceiveCmd;
     
    2931  end;
    3032
     33  { TServerClients }
     34
    3135  TServerClients = class(TFPGObjectList<TServerClient>)
    3236    Game: TGame;
     37    function SearchByPlayer(Player: TPlayer): TServerClient;
    3338  end;
    3439
     
    5156    RemoteNetworkAddress: string;
    5257    RemoteNetworkPort: Word;
     58    function GetNewServerClient: TServerClient;
    5359    procedure LoadConfig(Config: TXmlConfig; Path: string);
    5460    procedure SaveConfig(Config: TXmlConfig; Path: string);
     
    6773implementation
    6874
     75{ TServerClients }
     76
     77function TServerClients.SearchByPlayer(Player: TPlayer): TServerClient;
     78var
     79  I: Integer;
     80begin
     81  I := 0;
     82  while (I < Count) and (Items[I].Player <> Player) do Inc(I);
     83  if I < Count then Result := Items[I]
     84    else Result := nil;
     85end;
     86
    6987{ TServerClient }
    7088
     
    7997end;
    8098
     99procedure TServerClient.TurnStart;
     100begin
     101  Protocol.TurnStart;
     102end;
     103
    81104constructor TServerClient.Create;
    82105begin
    83106  Protocol := TGameProtocolServer.Create;
     107  Protocol.OnTurnEnd := DoTurnEnd;
    84108end;
    85109
     
    94118  if Assigned(FOnReceiveCmd) then
    95119    FOnReceiveCmd(Command, DataOut, DataIn);
     120end;
     121
     122procedure TServerClient.DoTurnEnd(Sender: TObject);
     123begin
     124  if Game.Running then Game.NextPlayer;
    96125end;
    97126
     
    153182end;
    154183
    155 procedure TServer.DoChange;
     184procedure TServer.DoChange(Sender: TObject);
    156185var
    157186  Client: TServerClient;
     
    169198    //TODO View.Clear;
    170199  end;
     200end;
     201
     202function TServer.GetNewServerClient: TServerClient;
     203begin
     204  Result := TServerClient.Create;
     205  Clients.Add(Result);
    171206end;
    172207
  • trunk/xtactics.lpi

    r199 r202  
    104104      </Item7>
    105105    </RequiredPackages>
    106     <Units Count="25">
     106    <Units Count="27">
    107107      <Unit0>
    108108        <Filename Value="xtactics.lpr"/>
     
    247247        <ResourceBaseClass Value="Form"/>
    248248      </Unit24>
     249      <Unit25>
     250        <Filename Value="UClientAI.pas"/>
     251        <IsPartOfProject Value="True"/>
     252      </Unit25>
     253      <Unit26>
     254        <Filename Value="UGameConnection.pas"/>
     255        <IsPartOfProject Value="True"/>
     256      </Unit26>
    249257    </Units>
    250258  </ProjectOptions>
     
    280288      <Debugging>
    281289        <UseHeaptrc Value="True"/>
    282         <UseExternalDbgSyms Value="True"/>
    283290      </Debugging>
    284291      <Options>
  • trunk/xtactics.lpr

    r199 r202  
    1111  CoolTranslator, TemplateGenerics
    1212  { you can add units after this },
    13   SysUtils, UFormMain, CoolStreaming, UFormServer;
     13  SysUtils, UFormMain, CoolStreaming, UFormServer, UClientAI, UGameConnection;
    1414
    1515{$R *.res}
     
    3232  Application.CreateForm(TCore, Core);
    3333  Application.CreateForm(TFormMain, FormMain);
    34   Application.CreateForm(TFormServer, FormServer);
    3534  Application.Run;
    3635end.
Note: See TracChangeset for help on using the changeset viewer.