unit u_game;

interface

uses zglHeader, zglGui, u_var, u_const, u_player, zglChipmunk, zglParticleEngine, u_bullets,
      Classes;

procedure Draw;
procedure Update( dt : Double );
procedure Init;
procedure Quit;
procedure DrawAllShit(cm: zglPCamera2D);
procedure SlowProc;

type
  TLogo = record
    txName: string;
    txDescription: string;
    txData: zglPTexture;
  end;

const
  logos_count = 7;

var
  Logos: array[0 .. logos_count -1 ] of TLogo = (
    (txName: 'logo.png'; txDescription: ''),
    (txName: 'logo/1.png'; txDescription: 'Однажды было изобретено новое химическое супероружие'),
    (txName: 'logo/2.png'; txDescription: 'После известия оба супергосударства захотели завладеть им, любой ценой'),
    (txName: 'logo/3.png'; txDescription: 'После нескольких лет охоты коалиция таки вышла на него'),
    (txName: 'logo/4.png'; txDescription: 'Изобретатель, понимая опасность, немедленно покинул планету, прихватив яд с собой'),
    (txName: 'logo/5.png'; txDescription: 'Ваша задача - доставить изобретателя на другую планету'),
    (txName: 'info.png'; txDescription: '')
  );

implementation

procedure SlowProc;
var i: integer;
begin
  repeat
    i  := Random(4) + 1;
  until rnd <> i;
  rnd := i;
end;

procedure DrawAllShit(cm: zglPCamera2D);
var i: integer;
begin
  cam2d_Set(cm);
  for i := 0 to stars_count -1 do begin
    pr2d_Circle(stars[i].X,  stars[i].Y, 3, $FFFFFF, 128, 4, PR2D_FILL);
  end;
  for i := Players.Count -1 downto 0 do
    TPlayer(Players.Items[i]).Draw;
  if (PlFire <> nil) and (Round(xxx) mod 100 > 50) then begin
    pr2d_Circle(PlFire.X^, PlFire.Y^, 64, $FF0094, 128, 8, PR2D_FILL);
  end;
  pe.Draw;
  BulletsDraw;
  //cpDrawSpace(space, false);
  cam2d_Set(nil);
end;

procedure Draw;
var i, j, px, py: integer;
    a, p: single;
    b: PBullet;
    pl: TPlayer;
    bl: Boolean;
begin
  case GameState of
    gs_fail: begin
      text_Draw(fntMain, sX/2, sY/2, 'Ты проиграл. Тебя или твоего спутника уничножили.', TEXT_HALIGN_CENTER);
    end;
    gs_logo: begin
      if LogoTimer < logo_time * 0.25 then begin
        j := round(255* (LogoTimer / (logo_time * 0.25)));
      end else
      if LogoTimer > logo_time * 0.75 then begin
        j := round(255* (1 - (LogoTimer - logo_time) / (logo_time * 0.25)));
      end else j := 255;
      ssprite2d_Draw(Logos[LogoId].txData, sX/2 - Logos[LogoId].txData.Width/2,
                                            sY/2 - Logos[LogoId].txData.Height/2,
                                            Logos[LogoId].txData.Width, Logos[LogoId].txData.Height, 0, j);
      text_Draw(fntMain, sX/2, sY/2 + Logos[LogoId].txData.Height/2 + 10,
         Logos[LogoId].txDescription, TEXT_HALIGN_CENTER);
    end;
    gs_mainmenu: begin
      gui.Draw;
    end;
    gs_game: begin       
      cam.X := Player.X^ - sX/2;// + cos(Player.Angle^) * ((sY/3) - 16) / Cam.Zoom.X;
      cam.Y := Player.Y^ - sY/2 ;//+ sin(Player.Angle^) * ((sY/3) - 16) / Cam.Zoom.X;

      DrawAllShit(@cam);

      ssprite2d_Draw(txRadar, 0, sY - 128, 128, 128, 0);
      ssprite2d_Draw(txRadarDt, 0, sY - 128, 128, 128, Player.Angle^ * rad2deg);
      ssprite2d_Draw(txRadarDr, 0, sY - 128, 128, 128, Player.Rad * rad2deg);

      for i := 0 to Bullets.Count -1 do begin
        b := Bullets.Items[i];
        p := (m_Distance(Player.X^, Player.Y^, b^.PbODY.p.x, b^.pBody.p.y)/ (sX * 8)) * 64;
        if p > 60 then p := 60;
        a := m_Angle(Player.X^, Player.Y^, b^.pBody.p.x, b^.pBody.p.y);
        case b^.classOf of
          bullet_easy: begin
            pr2d_Circle(64 - Cos(a * deg2rad) * p, sY - 64 - Sin(a * deg2rad) * p, 1, $FFFFFF, 128, 4, PR2D_FILL);
          end;
          bullet_rocket: begin
            if b^.Author = Player then
              j := $FFFFFF
            else j := $FF3333;
            if Round(xxx) mod 400 > 100 then
              pr2d_Circle(64 - Cos(a * deg2rad) * p, sY - 64 - Sin(a * deg2rad) * p, 3, j, 255, 4, PR2D_FILL);
          end;
        end;
      end;

      if key_Down(K_CTRL) then begin
        text_Draw(fntMain, sX - cam_size - 10, sY - cam_size - 25, 'КАМЕРА_РАКЕТЫ_01');
        ssprite2d_Draw(rtarget.Surface,
          sX - cam_size - 10, sY - cam_size - 10, cam_size, cam_size, 0);
      end;

      for i := Players.Count -1 downto 0 do begin
        pl := Players.Items[i];
        if pl.classOf in [cof_enemy, cof_user] then begin
          p := (m_Distance(Player.X^, Player.Y^, pl.X^, pl.Y^)/ (sX * 8)) * 64;
          if p > 60 then p := 60;
          a := m_Angle(Player.X^, Player.Y^, pl.X^, pl.Y^);
          case pl.classOf of
            cof_enemy: j :=  $0094FF;
            cof_user: j := $FFD800;
          end;
          pr2d_Circle(64 - Cos(a * deg2rad) * p, sY - 64 - Sin(a * deg2rad) * p, 4, j, 128, 8, PR2D_FILL);
          if PlFire = pl then begin
            pr2d_Circle(64 - Cos(a * deg2rad) * p, sY - 64 - Sin(a * deg2rad) * p, 8, $FF0094, 128, 8, PR2D_FILL);
          end;
        end;
      end;
      text_Draw(fntMain, 10, sY - 158, 'Скорость: ' + u_FloatToStr(cpvlength(Player.pBody.v)) + #13#10 +
        'Корабль: ' + u_IntToStr(Player.Health) );
      if (PlFire <> nil) and (Round(xxx) mod 100 > 50) then begin
        text_DrawEx(fntMain, 10, sY - 178, 1, 0, 'РАКЕТА НАВЕДЕНА!', 255, $FF2222);
      end;
    end;
  end;
  ssprite2d_Draw(txMouse, mouse_X, mouse_Y, 32, 32, 0);
end;

procedure Update( dt : Double );
var i, j: integer;
    d: Single;
    pl: TPlayer;
begin
  xxx := xxx + dt;
  case GameState of
    gs_logo: begin
      LogoTimer := LogoTimer + dt;
      if (LogoTimer >= logo_time - 4) or (mouse_Click(M_BLEFT)) or key_Press(K_SPACE) then begin
        mouse_ClearState;
        key_ClearState;
        Inc (LogoId);
        LogoTimer := 0;
        if LogoId >= logos_count then begin
          GameState := gs_mainmenu;
        end;
      end;

    end;
    gs_mainmenu: begin
      gui.Update(dt);
    end;
    gs_game: begin
      BulletsUpdate(dt);
      for i := Players.Count -1 downto 0 do
        TPlayer(Players.Items[i]).Update(dt);
      cpSpaceStep(Space,  dt /  100  );  
      d := (1 / cpvlength(Player.pBody.v)) * 40;
      if d > 0.5 then d := 0.5;
      if d < 0.15 then d := 0.15;
      Cam.Zoom.X := d;
      cam.Zoom.Y := d;

      for i := 0 to stars_count -1 do begin
        if m_Distance( stars[i].X,  stars[i].Y, Player.X^, Player.Y^) > sX * 2 then begin
          d := Player.Angle^ + (45 - random(90)) * deg2rad;
          stars[i].X := Player.X^ + Cos(d) * sX * 1.9;
          stars[i].Y := Player.Y^ + Sin(d) * sX * 1.9;
        end;
      end;
      Player.RotateAngle := Round(m_Angle(mouse_X, mouse_Y, sX/2, sY/2));

      PlFire := nil;
      for i := Players.Count -1 downto 0 do begin
        pl := Players.Items[i];
        if pl.classOf in [cof_enemy] then begin
           d := Abs( Player.Rad * rad2deg - m_Angle(pl.X^, pl.Y^, Player.X^, Player.Y^));
           if d < 0 then d := d + 360;
           if d > 360 then d := d - 360;
           if (d < 20) or (d > 340) then begin
             PlFire := pl
           end;


           pl.RotateAngle := Round(m_Angle(Player.X^, Player.Y^,
                      pl.X^, pl.Y^)) + Random(4) - 2;

          if pl.Bullets > 0 then begin
            if pl.Fire(not pl.Rocket, Player) then dec(pl.Bullets);
            if pl.Bullets = 0 then begin
              pl.Tm := 100 + Random(2000);
            end;
          end else begin
            pl.Tm := pl.Tm - dt;
            if pl.Tm < 0 then begin
              pl.Rocket := Random(10) > 7;
              if pl.Rocket then pl.Bullets := 1 else
                pl.Bullets := 2 + Random(4);
            end;

          end;

        end;
      end;
      if mouse_Down(M_BLEFT) then
        Player.Fire(true, PlFire);
      if mouse_Down(M_BRIGHT) then
        Player.Fire(false, PlFire);


      if Players.Count < 3 then begin
        PauseTime := PauseTime + dt;
        if PauseTime > 5000 then begin
          PauseTime := 0;
          pl := TPlayer.Create(cof_enemy,  Random(80) + 20, bot_speed, txEnemy, Random(25) + 1, 56, 56);
          pl.X^ := Player.X^ + Random(20000) - 10000;
          pl.Y^ := Player.Y^ + Random(20000) - 10000;
          Players.Add(pl);
        end;
      end;
    end;
  end;
  pe.Process(dt);
end;

function PlayerVsBullet( arb : PcpArbiter; space : PcpSpace; data : Pointer ) : cpBool; cdecl;
var blt: PBullet;
    pl: TPlayer;
    shape_a, shape_b : PcpShape;
begin
  cpArbiterGetShapes(arb, @shape_a, @shape_b);

  blt := shape_b.data;
  pl := shape_a.data;

  if blt.Author <> pl then begin
    blt^.Time := -101;
    pl.Health := pl.Health - ClassData[blt.classOf].heal;
  end;
  Result := blt.Author <> pl;

end;

function PlayerVsPlayer( arb : PcpArbiter; space : PcpSpace; data : Pointer ) : cpBool; cdecl;
begin
  snd_Play(sndBigCrash);
end;

function BulletVsBullet( arb : PcpArbiter; space : PcpSpace; data : Pointer ) : cpBool; cdecl;
var blt_a, blt_b: PBullet;
    shape_a, shape_b : PcpShape;
begin
  cpArbiterGetShapes(arb, @shape_a, @shape_b);

  blt_b := shape_b.data;
  blt_a := shape_a.data;

  Result := true;

  if Result then begin
    if  blt_a.Author <> player then  blt_a^.Time := -101;
    if  blt_b.Author <> player then  blt_b^.Time := -101;
  end;
end;

procedure StartGame(Sender: zglTGUIObject);
var pl: TPlayer;
    i: integer;
begin
  Randomize;
  frmMainMenu.Hide;
  Player := TPlayer.Create(cof_player, 1000, player_speed, txPlayer, 1, 128, 64);
  Player.X^ := 400;
  Players.Add(Player);
  Players.Add(TPlayer.Create(cof_user, 1000, player_speed * 0.5, txPlayer, 2, 128, 64));
  snd_Play(sndLoop, True);
  GameState := gs_game;
  snd_StopFile(snd_logo);
  snd_PlayFile('Data/Sounds/MainSnd.ogg', True);

  pe.SetEffect(@dstrEff, 'Explosion,ExplosionFly|16,ExplosionBFly|32');

  cpSpaceAddCollisionHandler(space, ct_player, ct_bullet, @PlayerVsBullet, nil, nil, nil, nil);
  cpSpaceAddCollisionHandler(space, ct_bullet, ct_bullet, @BulletVsBullet, nil, nil, nil, nil);
  cpSpaceAddCollisionHandler(space, ct_player, ct_player, @PlayerVsPlayer, nil, nil, nil, nil);
end;

procedure ShowAutors(Sender: zglTGUIObject);
begin
  frmMainMenu.Resize(200, 230);
end;

procedure InitPhys;
  var p: array[0..3] of cpVect;
    staticBody : PcpBody;
    ground     : PcpShape;
    e, u       : cpFloat;
begin
  cpLoad(libChipmunk);
  cpInitChipmunk;
  Space := cpSpaceNew();
  Space.gravity:= cpv(0, 0);
  space.damping    := 0.9;
  space.iterations := 10;
  e := 1;
  u := 1;
end;

procedure Init;
var i: integer;
begin
  snd_Init;

  Players := TList.Create;

  Cam.X := 0;
  Cam.Y := 0;
  Cam.Zoom.X := 1;
  Cam.Zoom.Y := 1;
  Cam.Angle := 0;

  RCam.X := 0;
  RCam.Y := 0;
  RCam.Zoom.X := 0.125;
  RCam.Zoom.Y := 0.125;
  RCam.Angle := 0;

  rtarget := rtarget_Add( tex_CreateZero( cam_size, cam_size ), RT_DEFAULT or RT_CLEAR_COLOR );

  InitPhys;

  for i := 0 to stars_count -1 do begin
    stars[i].X := sX - Random(sX*2);
    stars[i].Y := sX - Random(sX*2);
  end;

  pe.LoadFromFile('Data/Effects/index.ini');
  pe.SetEffect(@fly, 'Fly');

  BulletsInit;

  gui := zglTGui.Create('Data/GUI', sX, sY);

  for i := 0 to logos_count -1 do begin
    Logos[i].txData := tex_LoadFromFile('Data/Textures/' + Logos[i].txName, $FF000000, TEX_DEFAULT_2D);
  end;

  txPlayer := tex_LoadFromFile('Data/Textures/Player.png', $FF000000, TEX_DEFAULT_2D);
  tex_SetFrameSize(txPlayer, 128, 64);

  sndLoop := snd_LoadFromFile('Data/Sounds/JetLoop.wav', 2);
  sndBigCrash := snd_LoadFromFile('Data/Sounds/BigCrash.wav', 2);
  sndExploBig := snd_LoadFromFile('Data/Sounds/ExploBig.wav', 2);



  fntMain := font_LoadFromFile('Data/Main.zfi');
  txMouse := tex_LoadFromFile('Data/Mouse.tga', $FF000000, TEX_DEFAULT_2D);
  txRadar := tex_LoadFromFile('Data/Textures/Radar.png', $FF000000, TEX_DEFAULT_2D);
  txRadarDt := tex_LoadFromFile('Data/Textures/RadarDt.png', $FF000000, TEX_DEFAULT_2D);
  txRadarDr := tex_LoadFromFile('Data/Textures/RadarDr.png', $FF000000, TEX_DEFAULT_2D);
  txNoise := tex_LoadFromFile('Data/Textures/Noise.jpg', $FF000000,
      TEX_CLAMP or TEX_FILTER_NEAREST or TEX_CONVERT_TO_POT or TEX_CALCULATE_ALPHA);
  tex_SetFrameSize(txNoise, 128, 128);

  txEnemy := tex_LoadFromFile('Data/Textures/Enemy.png', $FF000000,
      TEX_CLAMP or TEX_FILTER_NEAREST or TEX_CONVERT_TO_POT or TEX_CALCULATE_ALPHA);
  tex_SetFrameSize(txEnemy, 56, 56);

  frmMainMenu := zglTForm.Create(Gui, 10, 10, 200, 120, 'Главное меню');
  frmMainMenu.Font :=zglTFontContainer.Create(
    zglTFontObject.Create( fntMain, 1, $99FF99, 255 ),
    zglTFontObject.Create( fntMain, 1, $FFFFFF, 255 ));
  frmMainMenu.CanMove := true;
  frmMainMenu.MoveToCenter;

  btnStartGame := zglTButton.Create(Gui, 0, 0, 180, 25, 'Начать игру');
  btnAutors := zglTButton.Create(Gui, 0, 27, 180, 25, 'Авторы');
  btnExit := zglTButton.Create(Gui, 0, 54, 180, 25, 'Выход');

  lblAutors := zglTLabel.Create(Gui, 0, 79, 180, 110,
    'Разработано в течении 7-х дней для #72 конкурса IGDC'#13#10#13#10'---'#13#10#13#10'Dj_smart');

  frmMainMenu.Add(btnStartGame);
  frmMainMenu.Add(btnAutors);
  frmMainMenu.Add(btnExit);
  frmMainMenu.Add(lblAutors);

  btnExit.OnClick := @zgl_Exit;
  btnStartGame.OnClick := @StartGame;
  btnAutors.OnClick := @ShowAutors;

  gui.Add(frmMainMenu);

  snd_logo := snd_PlayFile('Data/Sounds/LogoSnd.ogg', True);

  GameState := gs_logo;
  LogoTimer := 0;



end;

procedure Quit;
begin
 //
end;

end.
