unit UCore;

{$mode delphi}

interface

uses
  Classes, SysUtils, XMLConf, FileUtil, ActnList, Controls, Dialogs, Forms,
  UGame, UApplicationInfo, UPersistentForm, UScaleDPI, UCoolTranslator, DOM,
  URegistry, ULastOpenedList, UTheme, Registry, Menus, UFormClient, UPlayer,
  UGameServer, UGameClient, fgl, UServerList, UGameSystem, Graphics;

type

  { TCore }

  TCore = class(TDataModule)
    AAbout: TAction;
    AFullscreen: TAction;
    AToggleFogOfWar: TAction;
    AShowKeyShortcuts: TAction;
    AGameSave: TAction;
    APlayersStats: TAction;
    ANewSpectatorClient: TAction;
    AShowUnitMoves: TAction;
    AShowCharts: TAction;
    AHelp: TAction;
    AGameSaveAs: TAction;
    AGameLoad: TAction;
    ApplicationInfo: TApplicationInfo;
    ASettings: TAction;
    ActionListMain: TActionList;
    AExit: TAction;
    AGameEnd: TAction;
    AGameNew: TAction;
    AGameRestart: TAction;
    CoolTranslator1: TCoolTranslator;
    ImageListLarge: TImageList;
    ImageListSmall: TImageList;
    LastOpenedList1: TLastOpenedList;
    OpenDialog1: TOpenDialog;
    PersistentForm: TPersistentForm;
    SaveDialog1: TSaveDialog;
    ScaleDPI1: TScaleDPI;
    ThemeManager1: TThemeManager;
    XMLConfig1: TXMLConfig;
    procedure AAboutExecute(Sender: TObject);
    procedure AExitExecute(Sender: TObject);
    procedure AFullscreenExecute(Sender: TObject);
    procedure AGameEndExecute(Sender: TObject);
    procedure AGameLoadExecute(Sender: TObject);
    procedure AGameNewExecute(Sender: TObject);
    procedure AGameRestartExecute(Sender: TObject);
    procedure AGameSaveAsExecute(Sender: TObject);
    procedure AGameSaveExecute(Sender: TObject);
    procedure AHelpExecute(Sender: TObject);
    procedure ANewSpectatorClientExecute(Sender: TObject);
    procedure APlayersStatsExecute(Sender: TObject);
    procedure ASettingsExecute(Sender: TObject);
    procedure AShowChartsExecute(Sender: TObject);
    procedure AShowKeyShortcutsExecute(Sender: TObject);
    procedure AShowUnitMovesExecute(Sender: TObject);
    procedure AToggleFogOfWarExecute(Sender: TObject);
    procedure CoolTranslator1Translate(Sender: TObject);
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
    procedure LastOpenedList1Change(Sender: TObject);
  private
    FInitialized: Boolean;
    StoredDimension: TControlDimension;
    RegistryContext: TRegistryContext;
    GameLoaded: Boolean;
    FormNewTabIndex: Integer;
    OldWindowState: TWindowState;
    InFullScreenMode: Boolean;
    procedure LoadRecentExecute(Sender: TObject);
    procedure StartNewGame;
    procedure LoadGame(FileName: string);
    procedure DoPlayerChange(Sender: TObject);
    procedure DoMoveUpdated(UnitMove: TUnitMove);
    procedure DoOnWin(Player: TPlayer);
    procedure Delay(Time: Integer);
    procedure GameNewTurnExecute(Sender: TObject);
    procedure AutoSave;
    procedure CommandLineParams;
    procedure SelectClient;
    procedure UpdateOtherForms;
    procedure FormClientActions;
    procedure LoadGameSystems;
  public
    Game: TGame;
    GameSettings: TGame;
    Server: TServer;
    UseSingleView: Boolean;
    DevelMode: Boolean;
    AnimationSpeed: Integer;
    CellGridVisible: Boolean;
    UnitShapeVisible: Boolean;
    AutoSaveEnabled: Boolean;
    ReopenLastFile: Boolean;
    FormClients: TFPGObjectList<TFormClient>;
    LocalClients: TClients;
    ServerList: TServerList;
    GameSystems: TGameSystems;
    procedure ReopenGameOnInit;
    procedure LoadConfig;
    procedure SaveConfig;
    procedure SaveConfigAll;
    procedure Spectate(Player: TPlayer);
    procedure UpdateInterface;
    procedure ScaleDPI;
    procedure Init;
    procedure Done;
    property Initialized: Boolean read FInitialized;
  end;

var
  Core: TCore;

const
  clOrange = $009Aff;
  clBrown = $a52A2A;


implementation

{$R *.lfm}

uses
  UFormMain, UFormNew, UFormSettings, UFormAbout, UClientAI, UFormKeyShortcuts,
  UFormHelp, UFormCharts, UFormUnitMoves, UFormPlayersStats, UClientGUI;

const
  DefaultRegKey = '\Software\Chronosoft\xTactics';

resourcestring
  SPlayerWins = 'Player %s wins';
  SPlayersWins = 'Players %s win';
  SEndGame = 'End game?';
  SEndGameQuestion = 'Do you want to end current game?';
  SRestartGame = 'Restart game?';
  SRestartGameQuestion = 'Do you want to restart current game?';
  SPlayersNotInitialized = 'Not all players were initialized with start cell. Needed %d, initialized %d. Change map parameters to have more terrain cells.';
  SFileDialogFilter = 'xTactics games (.xtg)|*.xtg|All files|*.*';
  SMissingServerClientForPlayer = 'Server client for current player not found.';


{ TCore }

procedure TCore.DoOnWin(Player: TPlayer);
var
  PlayerNames: string;
  AlivePlayers: TPlayerArray;
  I: Integer;
begin
  Server.GameEnd;
  if Assigned(Player) then
    ShowMessage(Format(SPlayerWins, [Player.Name]))
  else begin
    AlivePlayers := Game.Players.GetAlivePlayers;
    PlayerNames := '';
    for I := 0 to Length(AlivePlayers) - 1 do begin
      if I > 0 then PlayerNames := PlayerNames + ', ';
      PlayerNames := PlayerNames + AlivePlayers[I].Name;
    end;
    ShowMessage(Format(SPlayersWins, [PlayerNames]))
  end;
end;

procedure TCore.Delay(Time: Integer);
const
  Slice = 50; // ms
begin
  while Time > 0 do begin
    Application.ProcessMessages;
    if Time > Slice then Sleep(Slice) else Sleep(Time);
    Dec(Time, Slice);
  end;
end;

procedure TCore.GameNewTurnExecute(Sender: TObject);
begin
  if AutoSaveEnabled then AutoSave;
end;

procedure TCore.AutoSave;
var
  OldFileName: string;
begin
  OldFileName := Game.FileName;
  Game.SaveToFile(GetAppConfigDir(False) + 'AutoSave.xtg');
  Game.FileName := OldFileName;
end;

procedure TCore.LoadConfig;
begin
  RegistryContext := TRegistryContext.Create(HKEY_CURRENT_USER, DefaultRegKey);
  PersistentForm.RegistryContext := RegistryContext;
  XMLConfig1.Filename := GetAppConfigDir(False) + 'Config.xml';

  ThemeManager1.Theme := ThemeManager1.Themes.FindByName(String(XmlConfig1.GetValue('Theme', 'System')));
  LastOpenedList1.LoadFromXMLConfig(XMLConfig1, 'RecentFiles');
  DevelMode := XMLConfig1.GetValue('DevelMode', false);
  AnimationSpeed := XMLConfig1.GetValue('AnimationSpeed', 50);
  AutoSaveEnabled := XMLConfig1.GetValue('AutoSave', True);
  ReopenLastFile := XMLConfig1.GetValue('ReopenLastFile', True);
  CoolTranslator1.Language := CoolTranslator1.Languages.SearchByCode(String(XMLConfig1.GetValue('Language', '')));
  ScaleDPI1.DPI := Point(XMLConfig1.GetValue('DPIX', 96), XMLConfig1.GetValue('DPIY', 96));
  ScaleDPI1.AutoDetect := XMLConfig1.GetValue('DPIAuto', True);
  FormNewTabIndex := XMLConfig1.GetValue('FormNewTabIndex', 0);
  CellGridVisible := XMLConfig1.GetValue('CellGridVisible', True);
  UnitShapeVisible := XMLConfig1.GetValue('UnitShapeVisible', False);
end;

procedure TCore.SaveConfig;
begin
  XMLConfig1.SetValue('Language', WideString(CoolTranslator1.Language.Code));
  XMLConfig1.SetValue('Theme', WideString(ThemeManager1.Theme.Name));
  LastOpenedList1.SaveToXMLConfig(XMLConfig1, 'RecentFiles');
  XMLConfig1.SetValue('DevelMode', DevelMode);
  XMLConfig1.SetValue('AnimationSpeed', AnimationSpeed);
  XMLConfig1.SetValue('AutoSave', AutoSaveEnabled);
  XMLConfig1.SetValue('ReopenLastFile', ReopenLastFile);
  XMLConfig1.SetValue('DPIX', ScaleDPI1.DPI.X);
  XMLConfig1.SetValue('DPIY', ScaleDPI1.DPI.Y);
  XMLConfig1.SetValue('DPIAuto', ScaleDPI1.AutoDetect);
  XMLConfig1.SetValue('FormNewTabIndex', FormNewTabIndex);
  XMLConfig1.SetValue('CellGridVisible', CellGridVisible);
  XMLConfig1.SetValue('UnitShapeVisible', UnitShapeVisible);
end;

procedure TCore.SaveConfigAll;
begin
  GameSettings.SaveConfig(XMLConfig1, 'Game');
  Server.SaveConfig(XMLConfig1, 'Server');
  ServerList.SaveConfig(XmlConfig1, 'ServerList');
  SaveConfig;
  XMLConfig1.Flush;
end;

procedure TCore.CommandLineParams;
var
  FileName: string;
begin
  // Command line parameter handling
  if (ParamCount > 0) then begin
    FileName := ParamStr(1);
    if FileExists(FileName) then LoadGame(FileName);
  end;
end;

procedure TCore.ScaleDPI;
var
  I: Integer;
begin
  //{$ifdef DEBUG}
  with Core.ScaleDPI1 do begin
    //DesignDPI := Point(144, 144);
    if (DesignDPI.X <> DPI.X) or (DesignDPI.Y <> DPI.Y) then begin
      //ApplyToAll(DesignDPI);
      for I := 0 to Screen.FormCount - 1 do
      if (Screen.Forms[I].WindowState = wsNormal) or
        (Screen.Forms[I].WindowState = wsMinimized) then begin
        StoreDimensions(Screen.Forms[I], StoredDimension);
        ScaleDimensions(Screen.Forms[I], StoredDimension);
      end;
      ScaleImageList(Core.ImageListSmall, DesignDPI);
      ScaleImageList(Core.ImageListLarge, DesignDPI);
    end;
  end;
  //{$endif}
end;

procedure TCore.SelectClient;
var
  FirstHuman: TPlayer;
begin
  FirstHuman := Game.Players.GetFirstHuman;
  if Assigned(FirstHuman) then FormClient.Client := TClientGUI(LocalClients.SearchPlayer(FirstHuman))
    else begin
      FormClient.Client := TClientGUI(LocalClients.New(SSpectator));
      FormClient.Client.LocalServer := Server;
      FormClient.Client.ConnectType := ctLocal;
      FormClient.Client.Active := True;
      FormClient.AZoomAll.Execute;
    end;
end;

procedure TCore.UpdateInterface;
begin
  Core.AGameEnd.Enabled := Core.Game.Running;
end;

procedure TCore.AExitExecute(Sender: TObject);
begin
  Game.Running := False;
  FormMain.Close;
  Application.Terminate;
end;

procedure TCore.AFullscreenExecute(Sender: TObject);
begin
  if InFullScreenMode then begin
    // Workaround: WindowState has sometimes wrong value under Linux.
    // Try to switch fullscreen again before switching back.
    if FormMain.WindowState <> wsFullScreen then begin
      FormMain.WindowState := wsFullScreen;
    end;
    {$IFDEF WINDOWS}
    FormMain.BorderStyle := bsSizeable;
    {$ENDIF}
    FormMain.WindowState := OldWindowState;
    InFullScreenMode := False;
  end else begin
    OldWindowState := FormMain.WindowState;
    {$IFDEF WINDOWS}
    FormMain.BorderStyle := bsNone;
    {$ENDIF}
    FormMain.WindowState := wsFullScreen;
    InFullScreenMode := True;
  end;
end;

procedure TCore.AAboutExecute(Sender: TObject);
begin
  FormAbout := TFormAbout.Create(Self);
  try
    FormAbout.ApplicationInfo := ApplicationInfo;
    FormAbout.ShowModal;
  finally
    FreeAndNil(FormAbout);
  end;
end;

procedure TCore.AGameEndExecute(Sender: TObject);
begin
  if MessageDlg(SEndGame, SEndGameQuestion, mtConfirmation, mbYesNo, 0) = mrYes then begin
    Game.Running := False;
    Server.GameEnd;
    UpdateInterface;
  end;
end;

procedure TCore.AGameLoadExecute(Sender: TObject);
begin
  OpenDialog1.Filter := SFileDialogFilter;
  OpenDialog1.InitialDir := ExtractFileDir(Game.FileName);
  OpenDialog1.FileName := ExtractFileName(Game.FileName);
  if OpenDialog1.Execute then begin
    LoadGame(OpenDialog1.FileName);
  end;
end;

procedure TCore.AGameNewExecute(Sender: TObject);
var
  NewServer: TServer;
begin
  FormNew := TFormNew.Create(nil);
  try
    NewServer := TServer.Create;
    NewServer.Assign(Server);
    NewServer.Game := TGame.Create;
    NewServer.Game.Assign(GameSettings);
    FormNew.Server := NewServer;
    FormNew.PageControl1.TabIndex := FormNewTabIndex;
    if FormNew.ShowModal = mrOk then begin
      Server.Assign(NewServer);
      Server.Game := Game;
      Game.Running := False;
      Game.PostConfig;
      Game.Assign(NewServer.Game);
      GameSettings.Assign(NewServer.Game);
      SaveConfigAll;
      StartNewGame;
      GameLoaded := False;
    end;
    FormNewTabIndex := FormNew.PageControl1.TabIndex;
    NewServer.Game.Free;
    NewServer.Game := nil;
    NewServer.Free;
  finally
    FormNew.Free;
  end;
end;

procedure TCore.AGameRestartExecute(Sender: TObject);
begin
  if MessageDlg(SRestartGame, SRestartGameQuestion, mtConfirmation, mbYesNo, 0) = mrYes then begin
    StartNewGame;
  end;
end;

procedure TCore.AGameSaveAsExecute(Sender: TObject);
begin
  SaveDialog1.Filter := SFileDialogFilter;
  SaveDialog1.InitialDir := ExtractFileDir(Game.FileName);
  SaveDialog1.FileName := ExtractFileName(Game.FileName);
  if SaveDialog1.Execute then begin
    Game.SaveToFile(SaveDialog1.FileName);
    LastOpenedList1.AddItem(SaveDialog1.FileName);
  end;
end;

procedure TCore.AGameSaveExecute(Sender: TObject);
begin
  if FileExists(Game.FileName) then
    Game.SaveToFile(Game.FileName)
    else AGameSave.Execute;
end;

procedure TCore.AHelpExecute(Sender: TObject);
begin
  FormHelp := TFormHelp.Create(Self);
  try
    FormHelp.ShowModal;
  finally
    FreeAndNil(FormHelp);
  end;
end;

procedure TCore.ANewSpectatorClientExecute(Sender: TObject);
begin
  Spectate(nil);
end;

procedure TCore.APlayersStatsExecute(Sender: TObject);
begin
  if not Assigned(FormPlayersStats) then
    FormPlayersStats := TFormPlayersStats.Create(nil);
  FormPlayersStats.Show;
end;

procedure TCore.ASettingsExecute(Sender: TObject);
begin
  FormSettings := TFormSettings.Create(nil);
  try
    FormSettings.Load;
    if FormSettings.ShowModal = mrOk then begin
      FormSettings.Save;
      Game.SaveConfig(XMLConfig1, 'Game');
      Server.SaveConfig(XMLConfig1, 'Server');
      XMLConfig1.Flush;
      ThemeManager1.UseTheme(FormMain);
    end;
  finally
    FreeAndNil(FormSettings);
  end;
end;

procedure TCore.AShowChartsExecute(Sender: TObject);
begin
  if not Assigned(FormCharts) then FormCharts := TFormCharts.Create(nil);
  FormCharts.Show;
end;

procedure TCore.AShowKeyShortcutsExecute(Sender: TObject);
begin
  if not Assigned(FormKeyShortcuts) then FormKeyShortcuts := TFormKeyShortcuts.Create(nil);
  FormKeyShortcuts.Show;
end;

procedure TCore.AShowUnitMovesExecute(Sender: TObject);
begin
  if not Assigned(FormUnitMoves) then FormUnitMoves := TFormUnitMoves.Create(nil);
  FormUnitMoves.Show;
end;

procedure TCore.AToggleFogOfWarExecute(Sender: TObject);
begin
  Game.FogOfWar := not Game.FogOfWar;
  Server.DoChange(Self);
end;

procedure TCore.CoolTranslator1Translate(Sender: TObject);
begin
  UGame.InitStrings;
  CoolTranslator1.TranslateComponentRecursive(FormClient);
end;

procedure TCore.DataModuleCreate(Sender: TObject);
begin
  GameSystems := TGameSystems.Create;
  Server := TServer.Create;
  LocalClients := TClients.Create;
  GameSettings := TGame.Create;
  GameSettings.FileName := 'Settings';
  Game := TGame.Create;
  Game.OnMoveUpdated := DoMoveUpdated;
  Game.OnWin := DoOnWin;
  Game.OnNewTurn := GameNewTurnExecute;
  Game.OnPlayerChange := DoPlayerChange;
  Server.Game := Game;
  LocalClients.Game := Game;
  StoredDimension := TControlDimension.Create;
  XMLConfig1.Filename := GetAppConfigDir(False) + 'Config.xml';
  ForceDirectories(GetAppConfigDir(False));
  FormClients := TFPGObjectList<TFormClient>.Create;
  ServerList := TServerList.Create;

  {$IFDEF Linux}
  // If installed in Linux system then use installation directory for po files
  if Application.ExeName = '/usr/bin/xtactics' then
    CoolTranslator1.POFilesFolder := '/usr/share/xtactics/languages';
  {$ENDIF}
end;

procedure TCore.DataModuleDestroy(Sender: TObject);
begin
  FreeAndNil(ServerList);
  if Assigned(FormPlayersStats) then FreeAndNil(FormPlayersStats);
  if Assigned(FormUnitMoves) then FreeAndNil(FormUnitMoves);
  if Assigned(FormCharts) then FreeAndNil(FormCharts);
  if Assigned(FormKeyShortcuts) then FreeAndNil(FormKeyShortcuts);
  FreeAndNil(FormClients);
  FreeAndNil(StoredDimension);
  FreeAndNil(Server);
  FreeAndNil(LocalClients);
  FreeAndNil(Game);
  FreeAndNil(GameSettings);
  FreeAndNil(GameSystems);
end;

procedure TCore.LastOpenedList1Change(Sender: TObject);
begin
  LastOpenedList1.LoadToMenuItem(FormMain.MenuItemLoadRecent, LoadRecentExecute);
end;

procedure TCore.LoadRecentExecute(Sender: TObject);
begin
  LoadGame((Sender as TMenuItem).Caption);
end;

procedure TCore.LoadGame(FileName: string);
var
  I: Integer;
  NewClient: TClient;
  ServerClient: TServerClient;
  Player: TPlayer;
begin
  GameLoaded := True;

  Game.LoadFromFile(FileName);
  Server.InitClients;
  Server.Active := True;

  // Create local LocalClients for human players
  LocalClients.Clear;
  FormClient.Client := nil;
  for I := 0 to Game.Players.Count - 1 do begin
    Player := TPlayer(Game.Players[I]);
    with Player do
    if Mode = pmHuman then begin
      NewClient := LocalClients.New(Name);
      NewClient.ControlPlayer := Player;
      TClientGUI(NewClient).View.Clear;
      TClientGUI(NewClient).View.Zoom := 1;
      NewClient.LocalServer := Server;
      NewClient.ConnectType := ctLocal;
      NewClient.Active := True;
      if Assigned(NewClient.ControlPlayer.StartCell) then
        TClientGUI(NewClient).View.CenterPlayerCity(NewClient.ControlPlayer)
        else TClientGUI(NewClient).View.CenterMap;
    end else
    if Mode = pmComputer then begin
      NewClient := TComputer.Create;
      NewClient.Game := TGame(Game);
      NewClient.Name := Name;
      LocalClients.Add(NewClient);
      NewClient.ControlPlayer := Player;
      NewClient.LocalServer := Server;
      NewClient.ConnectType := ctLocal;
      NewClient.Active := True;
    end;
  end;

  SelectClient;
  LastOpenedList1.AddItem(FileName);
  UpdateOtherForms;
  UpdateInterface;
  ServerClient := Server.Clients.SearchByPlayer(Game.CurrentPlayer);
  if Assigned(ServerClient) then ServerClient.TurnStart
    else raise Exception.Create(SMissingServerClientForPlayer);
  FormClient.AZoomAll.Execute;
end;

procedure TCore.UpdateOtherForms;
begin
  if Assigned(FormCharts) and FormCharts.Visible then FormCharts.Redraw;
  if Assigned(FormUnitMoves) and FormUnitMoves.Visible then FormUnitMoves.ReloadList;
  if Assigned(FormPlayersStats) and FormPlayersStats.Visible then FormPlayersStats.ReloadList;
end;

procedure TCore.FormClientActions;
var
  Action: TAction;
  I: Integer;
begin
  // Copy all actions from docked form to main form so keyboard shortcuts will be active
  for I := 0 to FormClient.ActionList1.ActionCount - 1 do begin
    Action := TAction.Create(FormMain);
    Action.Assign(TAction(FormClient.ActionList1.Actions[I]));
    Action.ActionList := FormMain.ActionList1;
  end;
end;

procedure TCore.LoadGameSystems;
var
  NewItem: TGameSystem;
begin
  if DirectoryExists('Systems') then begin
    GameSystems.LoadFromDir('Systems');
  end else begin
    NewItem := TGameSystem.Create;
    NewItem.FileName := 'Custom';
    GameSystems.Add(NewItem);
  end;
  if GameSystems.Count > 0 then begin
    GameSettings.GameSystem.Assign(GameSystems.First);
    Game.GameSystem.Assign(GameSystems.First);
  end;
end;

procedure TCore.ReopenGameOnInit;
begin
  CommandLineParams;
  if not GameLoaded and ReopenLastFile and (LastOpenedList1.Items.Count > 0) and
    FileExists(LastOpenedList1.Items[0]) then
    LoadGame(LastOpenedList1.Items[0]);

  if Game.FileName = '' then begin
    GameSettings.PostConfig;
    Game.Assign(GameSettings);
    StartNewGame;
  end;
end;

procedure TCore.Spectate(Player: TPlayer);
var
  Form: TFormClient;
begin
  Form := TFormClient.Create(nil);
  Form.Client := TClientGUI(LocalClients.New(SSpectator));
  Form.Client.LocalServer := Server;
  Form.Client.ConnectType := ctLocal;
  Form.Client.Active := True;
  //Form.Client.Form := Form;
  //Form.Client.ControlPlayer := Player;
  Form.AZoomAll.Execute;
  Form.Show;
  FormClients.Add(Form);
end;

procedure TCore.StartNewGame;
var
  NewClient: TClient;
  Player: TPlayer;
  I: Integer;
  ServerClient: TServerClient;
begin
  Game.New;
  Server.InitClients;
  Server.Active := True;

  // Create local LocalClients for human players
  LocalClients.Clear;
  FormClient.Client := nil;
  for I := 0 to Game.Players.Count - 1 do begin
    Player := TPlayer(Game.Players[I]);
    with Player do
    if Mode = pmHuman then begin
      NewClient := LocalClients.New(Name);
      NewClient.ControlPlayer := Player;
      TClientGUI(NewClient).View.Clear;
      TClientGUI(NewClient).View.Zoom := 1;
      NewClient.LocalServer := Server;
      NewClient.ConnectType := ctLocal;
      NewClient.Active := True;
      if Assigned(NewClient.ControlPlayer.StartCell) then
        TClientGUI(NewClient).View.CenterPlayerCity(NewClient.ControlPlayer)
        else TClientGUI(NewClient).View.CenterMap;
    end else
    if Mode = pmComputer then begin
      NewClient := TComputer.Create;
      NewClient.Game := TGame(Game);
      NewClient.Name := Name;
      LocalClients.Add(NewClient);
      NewClient.ControlPlayer := Player;
      NewClient.LocalServer := Server;
      NewClient.ConnectType := ctLocal;
      NewClient.Active := True;
    end;
  end;

  Game.DevelMode := DevelMode;
  SelectClient;
  if Game.Players.GetAliveCount = Game.Players.Count then Game.Running := True
    else ShowMessage(Format(SPlayersNotInitialized, [Game.Players.Count, Game.Players.GetAliveCount]));
  UpdateOtherForms;
  UpdateInterface;
  ServerClient := Server.Clients.SearchByPlayer(Game.CurrentPlayer);
  if Assigned(ServerClient) then ServerClient.TurnStart
    else raise Exception.Create(SMissingServerClientForPlayer);
end;

procedure TCore.DoPlayerChange(Sender: TObject);
var
  PlayerClient: TClient;
  ServerClient: TServerClient;
begin
  Application.ProcessMessages;
  Server.NextPlayer;
  if Assigned(Game.CurrentPlayer) then begin
    if Game.CurrentPlayer.Mode = pmHuman then begin
      PlayerClient := LocalClients.SearchPlayer(Game.CurrentPlayer);
      if Assigned(PlayerClient) then FormClient.Client := TClientGUI(PlayerClient);
    end;

    ServerClient := Server.Clients.SearchByPlayer(Game.CurrentPlayer);
    if Assigned(ServerClient) then ServerClient.TurnStart;
  end;
  UpdateOtherForms;
end;

procedure TCore.DoMoveUpdated(UnitMove: TUnitMove);
begin
  if Assigned(FormUnitMoves) and FormUnitMoves.Visible then
    FormUnitMoves.ReloadList;
end;

procedure TCore.Init;
begin
  if not Core.Initialized then begin
    FInitialized := True;
    LoadGameSystems;

    // Update translated default player names
    GameSettings.Players[0].Name := SPlayer + ' 1';
    GameSettings.Players[1].Name := SPlayer + ' 2';

    // GameSystemName needs to be loaded before game systems config itself.
    // Players reference Nations from game system.
    GameSettings.GameSystem.Assign(GameSystems.SearchByName(string(XMLConfig1.GetValue(DOMString('Game/GameSystemName'), DOMString('HexWars')))));
    GameSettings.LoadConfig(XMLConfig1, 'Game');
    Server.LoadConfig(XMLConfig1, 'Server');
    ServerList.LoadConfig(XmlConfig1, 'ServerList');

    FormClientActions;
  end;
end;

procedure TCore.Done;
begin
  SaveConfigAll;
end;

end.

