unit FormMain;

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, Game, LCLType,
  Menu, BasicControls, FormEx, DateUtils;

type
  { TKeyboard }

  TKeyboard = class
    KeyState: array[0..High(Word)] of Boolean;
    procedure ClearAll;
  end;

  { TFormMain }

  TFormMain = class(TFormEx)
    TimerDraw: TTimer;
    TimerTick: TTimer;
    procedure FormActivate(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure FormDeactivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormKeyPress(Sender: TObject; var Key: char);
    procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormPaint(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure TimerDrawTimer(Sender: TObject);
    procedure TimerTickTimer(Sender: TObject);
  private
    Activated: Boolean;
    Keyboard: TKeyboard;
    function KeyPressedExecute(Key: Word): Boolean;
    procedure MenuItemClick(Sender: TObject);
  public
    CurrentGame: TGame;
    Games: TGames;
    Menu: TMenu;
    procedure EraseBackground(DC: HDC); override;
  end;

var
  FormMain: TFormMain;


implementation

{$R *.lfm}

uses
  TugOfWar, Pong, Snake, Tetris, Ludo, Minesweeper;

{ TKeyboard }

procedure TKeyboard.ClearAll;
var
  I: Integer;
begin
  for I := 0 to High(KeyState) do
    KeyState[I] := False;
end;

{ TFormMain }

procedure TFormMain.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  KeyBoard.KeyState[Key] := True;
  if Assigned(CurrentGame) then CurrentGame.KeyDown(Key, Shift);
end;

procedure TFormMain.FormKeyPress(Sender: TObject; var Key: char);
begin
  if (Key = #27) and Assigned(CurrentGame) then begin
    CurrentGame.Stop;
    CurrentGame := nil;
    Invalidate;
  end;
end;

procedure TFormMain.FormCreate(Sender: TObject);
var
  I: Integer;
begin
  Keyboard := TKeyboard.Create;
  ControlStyle := ControlStyle + [csOpaque];
  Randomize;

  Games := TGames.Create;
  with Games do begin
    Add(TTugOfWar.Create);
    Add(TPong.Create);
    Add(TSnake.Create);
    Add(TTetris.Create);
    Add(TLudo.Create);
    Add(TMinesweeper.Create);
  end;

  Menu := TMenu.Create;
  for I := 0 to Games.Count - 1 do
  with Menu.Items.AddButton(Games[I].Name, MenuItemClick) do begin
     Enabled := True;
     TextSize := 30;
     TextColor := clWhite;
     TextDisabledColor := clGray;
     BackgroundColor := clNone;
     BackgroundSelectedColor := clBlue;
     Ref := Games[I];
   end;
end;

procedure TFormMain.FormDeactivate(Sender: TObject);
begin
  KeyBoard.ClearAll;
end;

procedure TFormMain.FormActivate(Sender: TObject);
begin
  if not Activated then begin
    Activated := True;
  end;
end;

procedure TFormMain.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  TimerDraw.Enabled := False;
  TimerTick.Enabled := False;

  if Assigned(CurrentGame) then CurrentGame.Stop;
end;

procedure TFormMain.FormDestroy(Sender: TObject);
begin
  CurrentGame := nil;
  FreeAndNil(Games);
  FreeAndNil(Keyboard);
end;

procedure TFormMain.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
  );
begin
  KeyBoard.KeyState[Key] := False;
  if Key = KeySpace then begin
    if Assigned(CurrentGame) then begin
      if CurrentGame.State = gsRunning then CurrentGame.State := gsPaused
      else if CurrentGame.State = gsPaused then CurrentGame.State := gsRunning;
    end;
  end;
  if Assigned(CurrentGame) then CurrentGame.KeyUp(Key, Shift);
end;

procedure TFormMain.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if not Assigned(CurrentGame) then begin
    Menu.MouseMove(Point(X, Y));
    Invalidate;
  end;
end;

procedure TFormMain.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Assigned(CurrentGame) then CurrentGame.MouseUp(Button, Shift, X, Y)
    else begin
      Menu.MouseUp(Button, Point(X, Y));
      Invalidate;
    end;
end;

procedure TFormMain.FormPaint(Sender: TObject);
begin
  if Assigned(CurrentGame) then CurrentGame.Draw(Canvas)
  else Menu.Paint(Canvas, Point(Width, Height));
end;

procedure TFormMain.FormResize(Sender: TObject);
begin
  if Assigned(CurrentGame) and Assigned(CurrentGame.Scene) then
    CurrentGame.Scene.Redraw;
end;

procedure TFormMain.FormShow(Sender: TObject);
begin
end;

procedure TFormMain.TimerDrawTimer(Sender: TObject);
begin
  if Assigned(CurrentGame) and Assigned(CurrentGame.Scene) and CurrentGame.Scene.RedrawPending then begin
    CurrentGame.Scene.RedrawPending := False;
    Invalidate;
  end;
end;

procedure TFormMain.TimerTickTimer(Sender: TObject);
begin
  if Assigned(CurrentGame) and (CurrentGame.State = gsRunning) then begin
    CurrentGame.Time := CurrentGame.Time + TimerTick.Interval * OneMillisecond;
    CurrentGame.Tick;
  end;
end;

procedure TFormMain.MenuItemClick(Sender: TObject);
begin
  CurrentGame := TGame(BasicControls.TControl(Sender).Ref);
  CurrentGame.OnKeyPressed := KeyPressedExecute;
  CurrentGame.Run;
end;

function TFormMain.KeyPressedExecute(Key: Word): Boolean;
begin
  Result := Keyboard.KeyState[Key];
end;

procedure TFormMain.EraseBackground(DC: HDC);
begin
  // Do nothing
end;

end.

