unit u_game;

interface

uses zglGui, zglHeader, u_const, u_parser, zglParticleEngine, u_map,
      u_portal, u_player;

  procedure Init;
  procedure Draw;
  procedure Update( dt : Double );
  procedure Quit;

  function Min(f, d: Single): Single;
  function Max(f, d: Single): Single;

const
  dStage = 120;


var
  fntMain: zglPFont;
  txLogo, txTiles, txPortal, txZeroMask, txPortalEnd,
    txFar, txPlayer, txCube, txDoor: zglPTexture;
  mscMainMenu, pX, pY: integer;
  imbStartGame, imbExitGame: zglTImageButton;
  chHelp: zglTCheckBox;
  frmMainMenu, frmStage: zglTFrame;
  letterO: peTPaticleSet;
  cnt: single;

implementation


function Min(f, d: Single): Single;
begin
  if f > d then Result := d
    else Result := f;
end;

function Max(f, d: Single): Single;
begin
  if f < d then Result := d
    else Result := f;
end;


procedure StartGame(Sender: zglTGUIObject; var handleParentClick: boolean);
begin
  snd_StopFile(mscMainMenu);
  mscMainMenu := snd_PlayFile('Data/Music/SelectStage.ogg', True);
  frmMainMenu.Hide;
  frmStage.MoveToCenter;
  frmStage.Show;
  GameState := gsSelectStage;
end;

procedure StartStage(Sender: zglTGUIObject; var handleParentClick: boolean);
begin
  Map.LoadFromFile(Sender.Data);
  GameState := gsGame;
  frmStage.Hide;
end;

function fStage(data: TDataObjectRecord): TStage;
begin
  Result := TStage.Create;
  data.GetData('Name', @Result.Name);
  data.GetData('Data', @Result.Data);
  data.GetData('Music', @Result.Music);
  data.GetData('Image', @Result.ImageName);
  Result.Image := tex_LoadFromFile(Result.ImageName^, $FF000000, TEX_STRICT);
end;

function fAddStage(data: TStage): Pointer;
var b: zglTImageButton;
begin
  b := zglTImageButton.Create(gui, pX * 64, pY * 64, 64, 64,
    32, 32, data.Image);
  b.Data := data;
  b.OnClick := @StartStage;
  frmStage.Items.Add(b);
  inc(pX);
  if pX >= 4 then begin
    pX := 0;
    inc(pY);
    frmStage.Resize(256, (pY + 1) * 64);
  end;
end;

procedure Init;
var txBtn: zglPTexture;
begin
  snd_Init;

  pX := 0; pY := 0; Randomize;

  txLogo := tex_LoadFromFile('Data/Textures/txLogo.tga',
    $FF000000, TEX_STRICT);
  txTiles := tex_LoadFromFile('Data/Textures/txTiles.tga',
    $FF000000, TEX_STRICT);
  tex_SetFrameSize(txTiles, BLOCKSIZE, BLOCKSIZE);
  txPortal := tex_LoadFromFile('Data/Textures/txPortal.tga',
    $FF000000, TEX_STRICT);
  tex_SetFrameSize(txPortal, BLOCKSIZE * 2, BLOCKSIZE * 2);
  txFar := tex_LoadFromFile('Data/Textures/txFar.tga',
    $FF000000, TEX_DEFAULT_2D);
  tex_SetFrameSize(txFar, 32, 32);
  txPlayer := tex_LoadFromFile('Data/Textures/txPlayer.tga',
    $FF000000, TEX_DEFAULT_2D);
  tex_SetFrameSize(txPlayer, 16, 16);
  txCube := tex_LoadFromFile('Data/Textures/txCube.tga',
    $FF000000, TEX_STRICT);
  txDoor := tex_LoadFromFile('Data/Textures/txDoor.tga',
    $FF000000, TEX_STRICT);
  tex_SetFrameSize(txDoor, 16, 64);
  fntMain := font_LoadFromFile('Data/Main.zfi');
  Gui := zglTGui.Create('Data/GUI',
    sX, sY, zglTFontContainer.Create(
        zglTFontObject.Create(fntMain, 1, $FFFFFF, 255),
        zglTFontObject.Create(fntMain, 1, $33FF33, 255)
      ));

  txBtn := tex_LoadFromFile('Data/Textures/txStartGame.tga', $FF000000,
      TEX_STRICT);
  txZeroMask := tex_LoadFromFile('Data/Textures/txZeroMask.tga', $FF000000,
      TEX_DEFAULT_2D);
  txPortalEnd := tex_LoadFromFile('Data/Textures/txPortalEnd.tga', $FF000000,
      TEX_STRICT);
  frmMainMenu := zglTFrame.Create(gui, 10, 10, 96, 96);
  frmStage := zglTFrame.Create(gui, 0, 0, 256, 0, false);

  chHelp := zglTCheckBox.Create(gui, 0, 0, 96, 16, 'Подсказки');
  chHelp.Checked := true;
  frmMainMenu.Items.Add(chHelp);
  imbStartGame := zglTImageButton.Create(gui, 16, 32, 64, 32, 32, 16,
    txBtn);
  frmMainMenu.Items.Add(imbStartGame);

  imbStartGame.OnClick := @StartGame;
  imbExitGame := zglTImageButton.Create(gui, 16, 64, 64, 32, 32, 16,
    txBtn, 3);
  imbExitGame.OnClick := @zgl_exit;
  frmMainMenu.Items.Add(imbExitGame);
  Gui.Items.Add(frmMainMenu);
  Gui.Items.Add(frmStage);
  frmMainMenu.MoveToCenter;

  FileParser := TFilesParser.Create;
  PE := peTParticleEngine.Create(getcpv(0, GRAVITATION));

  with FileParser.RegisterType('Stage', dStage, nil, ct_record, @fStage) do begin
    RegisterVariable('Name', dString);
    RegisterVariable('Data', dString);
    RegisterVariable('Image', dString);
    RegisterVariable('Music', dString);
  end;

  FileParser.RegisterFunction('AddStage', dStage, @fAddStage);

  FileParser.LoadData('Data/Main');
  letterO := peTPaticleSet.Create('menu');

  mscMainMenu := snd_PlayFile('Data/Music/MainMenu.ogg', True);

  Map := TMap.Create;
end;

procedure Draw;
var
  i: Integer;
  a: single;
  p: TPortal;
begin
  case GameState of
    gsMainMenu: begin
      PE.Draw;
      ssprite2d_Draw(txLogo,
        sX div 2 - 128, sY div 4 - 32, 256, 64, 0);
    end;
    gsSelectStage: begin
     PE.Draw;
      text_Draw(fntMain, sX div 2, 10,
        'Выберите уровень.', TEXT_HALIGN_CENTER);
    end;
    gsLevelDone: begin
     PE.Draw;
      text_Draw(fntMain, sX div 2, sY div 2,
        'Уровень пройден! Нажмите пробел', TEXT_HALIGN_CENTER);
    end;
    gsGame: begin
      Map.Draw(
        Round((TPlayer(Map.Player).Position.X + TPlayer(Map.Player).Position.W / 2) * BLOCKSIZE - sX / 2),
        Round((TPlayer(Map.Player).Position.Y + TPlayer(Map.Player).Position.H / 2) * BLOCKSIZE - sY / 2),
        0, 2, true);
      for i := 0 to Map.Portals.Count - 1 do begin
        p := Map.Portals.Items[i];
        with p do begin
            if m_Distance(TPlayer(Map.Player).Position.X,
                TPlayer(Map.Player).Position.Y,
                X, Y) > sY / (BLOCKSIZE * 4) + 2
            then begin
              a := m_Angle(X, Y,
                          TPlayer(Map.Player).Position.X,
                          TPlayer(Map.Player).Position.Y);
              asprite2d_Draw(txFar,
                sX / 2 + Cos(a * deg2rad) * (sY / 2 - 32) - 16,
                sY / 2 + Sin(a * deg2rad) * (sY / 2 - 32) - 16,
                32, 32, round(a) + 180, Cardinal(ClassOf) + 1);
            end;
        end;
      end;

    end;
  end;
  Gui.Draw;
end;

procedure Update( dt : Double );
var b: boolean;
begin
  cnt := cnt + dt;
  while cnt > 1 do begin
    cnt := cnt - 1;
    Gui.Update(1);
    Pe.Update(1);
    case GameState of
      gsMainMenu: begin
        if Random(20) = 0 then
          letterO.AddEffect(sX div 2 - 64, sY div 4, 90);
      end;
      gsGame: begin
        Map.Update(1);
      end;
      gsLevelDone: begin
        if Map.Loaded then begin
          Map.Unload;
        end;
        if key_Down(K_SPACE) then begin
          StartGame(nil, b);
        end;
      end;
    end;
    if key_Down(K_ESCAPE) then
      zgl_Exit();
  end;
end;

procedure Quit;
begin
  //
end;

end.
