unit u_game;

interface

uses SysUtils, zglParticleEngine, zglGUI, zglHeader, Dialogs, u_map,
     u_const, u_player, u_ghost, u_music;

procedure Draw;
procedure Update( dt : Double );
procedure Init;
procedure Quit;
procedure AddMessage(s:string;  times:integer;_CallId:boolean);


type
    TPortal = record
      Color, ExitId:Integer;
      State:byte;
      Position:zglTPoint2D;
      lookAngle:integer;
      Counter:integer;
      DrawTwo:byte;
      Fly, Touch, Stay: TEffectSet;
    end;
    TPortalFly = record
      Position:zglTPoint2D;
      lookAngle:integer;
      PortalId:Integer;
    end;
    TMessage = record
      Time:integer;
      Text:string;
      CallId:boolean;
    end;
    

var Portals:array[1..portals_count] of TPortal = (
      (Color:$FF9400; ExitId:2; State:portal_none;),
      (Color:$006AFF; ExitId:1; State:portal_none;),
      (Color:$18CE00; ExitId:4; State:portal_opened;),
      (Color:$18CE00; ExitId:3; State:portal_opened;),
      (Color:$18CE00; ExitId:6; State:portal_opened;),
      (Color:$18CE00; ExitId:5; State:portal_opened;)
    );
    Ghosts:array[1..ghosts_count] of TGhost;
    Messages:array[1..8] of TMessage;
    MessagesCount:integer=0;
    
    PortalsFly:array[1..64] of TPortalFly;
    PortalsFlyCount:integer=0;
    zgl:TParticleEngine;
    a,s:Single;
    GameState:integer=gs_game;
    j:integer;

    Level, DieCounter, DieId:integer;

    txWalls, txSleepWalls, txEat, txWeapon, txbadWalls, txPacMan, txPortals: zglPTexture;
    txGhost, txPortalEnd, txZero, txZeroMask, txGhostScared, txGhostEaten: zglPTexture;
    sndNewMsg, sndPshoot1, sndPFly, sndPshoot2, sndPremenu, sndWk, sndEnergizer: zglPSound;
    sndPortalOpen:array[1..3] of zglPSound;
    sndPortalExit:array[1..2] of zglPSound;
    
    Map:TMap;
    Player:TPlayer;

    plus10, plus100, plus500: PEffectSet;

    RTrgt: zglPRenderTarget;


implementation

procedure AddMessage(s:string; times:integer;_CallId:boolean);
begin
  inc(MessagesCount);
  with Messages[MessagesCount] do begin
    Time:=message_time*times;
    CallId:=_CallId;
    Text:=s;
  end;
end;

procedure Draw;
var n, j, i:Integer;
begin
  mouse_ClearState;
  guiFocus;
    case GameState of
      gs_die:begin
        case DieId of
          0:begin
            j:=Round((1-DieCounter/DieTime[DieId])*sX*0.6+sX*0.1);
            asprite2d_Draw(txPacMan, j, sY/2,
              item_size, item_size, 0, Player.Anim);
            for i:=1 to ghosts_count do begin
              fx2d_SetColor(Pincs[i]);
              asprite2d_Draw(txGhost, j+(i+1)*item_size, sY/2,
                item_size, item_size, 0, Player.Anim,
                255, FX_BLEND or FX_COLOR);
              fx2d_SetColor($FFFFFF);
              asprite2d_Draw(txGhost, j+(i+1)*item_size, sY/2,
                item_size, item_size, 0, 7);
            end;
          end;
          1:begin
            j:=Round((1-DieCounter/DieTime[DieId])*sX*0.6+sX*0.1);
            asprite2d_Draw(txPacMan, j+6*item_size, sY/2,
              item_size, item_size, 0, Player.Anim);
              
            for i:=1 to ghosts_count do begin
              fx2d_SetColor(Pincs[i]);
              asprite2d_Draw(txGhost, j+i*item_size, sY/2,
                item_size, item_size, 0, Player.Anim,
                255, FX_BLEND or FX_COLOR);
              fx2d_SetColor($FFFFFF);
              asprite2d_Draw(txGhost, j+i*item_size, sY/2,
                item_size, item_size, 0, 7);
            end;
          end;
        end;
        pr2d_Rect(0, 0, sX div 4, sY, 0, 255, PR2D_FILL);
        pr2d_Rect(sX*0.75, 0, sX div 4, sY, 0, 255, PR2D_FILL);
        pr2d_Line(sX*0.25, sY*0.25, sX*0.25, sY*0.75);
        pr2d_Line(sX*0.75, sY*0.25, sX*0.75, sY*0.75);
      end;
      gs_game: begin

        Map.Render( Player.Pos.X*item_size-sX div 2,Player.Pos.Y*item_size -Sy div 2, Player.AngleOffset, 0);
        for n:=1 to MessagesCount do begin
          guiDrawText(Messages[n].Text, sX/2, sY-(MessagesCount-n+1)*16-64, align_center, true);
        end;
        guiDrawProgressBar(10, 10, 100, 1-Map.EatCount/Map.EatCountMax);
        guiDrawText('Собрано', 60, 10, align_center);
        for n:=1 to Player.Lives do begin
          asprite2d_Draw(txPacMan, 10+(n-1)*item_size, 36,
              item_size, item_size, 0, 3);
        end;
        guiDrawText(inttostr(player.Score), Player.Lives*item_size+10, 36, align_left, true);
      end;
      gs_choose: begin
        Map.Render( Player.Pos.X*item_size-sX div 2,Player.Pos.Y*item_size -Sy div 2, Player.AngleOffset, 0);
        guiDrawText('Тренировка', -Player.Pos.X*item_size+sX div 2, (1.5-Player.Pos.Y)*item_size+sY div 2,align_right);

        guiDrawText(DiffNames[1], (Map.MapW-1-Player.Pos.X)*item_size+sX div 2, (1.5-Player.Pos.Y)*item_size+sY div 2,align_left);
        guiDrawText(DiffNames[2], (Map.MapW-1-Player.Pos.X)*item_size+sX div 2, (3.5-Player.Pos.Y)*item_size+sY div 2,align_left);
        guiDrawText(DiffNames[3], (Map.MapW-1-Player.Pos.X)*item_size+sX div 2, (5.5-Player.Pos.Y)*item_size+sY div 2,align_left);
      end;
    end;
  guiDraw;
  guiDrawMouse;
end;

procedure Update( dt : Double );
var v, x, FireDst:zglTPoint2D;
    n, i, j_, b, a, la:integer;
    bt:Boolean;
begin
  mouse_ClearState;
  s:=s+dt;
  while s>=1 do begin
    s:=s-1; j:=j+1;
    case GameState of
      gs_die:begin
        if j mod 64 = 0 then begin
          Inc(Player.Anim);
          if Player.Anim>4 then Player.Anim:=1;
        end;
        inc(DieCounter);
        if DieCounter>=DieTime[DieId] then begin
          if Player.Lives<=0 then begin
            Level:=1;
            Map.LoadFromFile('Data/Maps/menu.bmp');
            Player.Score:=0;
            Player.Lives:=player_lives;
            GameState:=gs_choose;
          end else
          GameState:=gs_game;
          PlayMusic;
        end;
      end;
      gs_game, gs_choose: begin
        Player.Update;
        for i:=1 to ghosts_count do
          if Ghosts[i].Enabled then Ghosts[i].Update;

        for n:=PortalsFlyCount downto 1 do begin

          PortalsFly[n].Position.X:=PortalsFly[n].Position.X-m_cos(PortalsFly[n].lookAngle)*portal_speed;
          PortalsFly[n].Position.Y:=PortalsFly[n].Position.Y-m_sin(PortalsFly[n].lookAngle)*portal_speed;
          x.X:=PortalsFly[n].Position.X*item_size;
          x.Y:=PortalsFly[n].Position.Y*item_size;
          b:=Map.MapData[Round(PortalsFly[n].Position.X), Round(PortalsFly[n].Position.Y)].btWallId;
          for i:=1 to portals_count do
            if (Portals[i].State=portal_opened) and (Portals[Portals[i].ExitId].State=portal_opened) then
            if (Round(Portals[i].Position.X)=Round(PortalsFly[n].Position.X)) and
               (round(Portals[i].Position.Y)=Round(PortalsFly[n].Position.Y))
               and Map.InRec(b,PortalsFly[n].Position.X,PortalsFly[n].Position.Y) then begin
              PortalsFly[n].Position:=Portals[Portals[i].ExitId].Position;
              if (Portals[Portals[i].ExitId].lookAngle-Portals[i].lookAngle) mod 180 = 0 then j_:=180 else j_:=0;
              PortalsFly[n].lookAngle:=PortalsFly[n].lookAngle+j_+Portals[i].lookAngle-Portals[Portals[i].ExitId].lookAngle;
              PortalsFly[n].Position.X:=PortalsFly[n].Position.X+m_cos(Portals[Portals[i].ExitId].lookAngle)*0.501;
              PortalsFly[n].Position.Y:=PortalsFly[n].Position.Y+m_sin(Portals[Portals[i].ExitId].lookAngle)*0.501;
              snd_Play(sndPFly);
            end;
          if j mod 10=0 then
            zgl.CreateEffect(@Portals[PortalsFly[n].PortalId].Fly, x, PortalsFly[n].lookAngle);


          if (not Map.CkeckPos(PortalsFly[n].Position.X,PortalsFly[n].Position.Y, PortalsFly[n].lookAngle, false))
             and Map.InRec(b,PortalsFly[n].Position.X,PortalsFly[n].Position.Y) then begin
            x.X:=Round(PortalsFly[n].Position.X);
            x.Y:=Round(PortalsFly[n].Position.Y);
            //Player.Say:=IntToStr(b); player.SayTime:=1000;
            if ((b and 9=9) or (b and 6=6) or (b in [1,2,4,8])) and
               (Map.MapData[Round(PortalsFly[n].Position.X), Round(PortalsFly[n].Position.Y)].btType=bt_wall) then
            with Portals[PortalsFly[n].PortalId] do begin
              State:=portal_opened;
              Position:=x;
              snd_Play(sndPortalOpen[Random(3)+1]);

              if (b and 9=9) or (b in [1,8]) then begin
                if PortalsFly[n].Position.X>x.X then a:=0 else a:=180;
              end else begin
                if PortalsFly[n].Position.Y>x.Y then a:=90 else a:=270;
              end;
              lookAngle:=a;
            end;
            x.X:=PortalsFly[n].Position.X*item_size;
            x.Y:=PortalsFly[n].Position.Y*item_size;
            zgl.CreateEffect(@Portals[PortalsFly[n].PortalId].Touch, x, PortalsFly[n].lookAngle);
            PortalsFly[n]:=PortalsFly[PortalsFlyCount];
            Dec(PortalsFlyCount);
          end;
        end;
        for n:=1 to portals_count do begin
          if (Portals[n].State=portal_opened) and (Portals[Portals[n].ExitId].State=portal_opened) then
          if j mod 128=0 then begin
            x.X:=Portals[n].Position.X*item_size;
            x.Y:=Portals[n].Position.Y*item_size;

            zgl.CreateEffect(@Portals[n].Stay, x, Portals[n].lookAngle);
          end;
          if Portals[n].Counter>0 then Dec(Portals[n].Counter);
        end;
        for n:=MessagesCount downto 1 do begin
          dec(Messages[n].Time);
          if (Messages[n].Time=400) and (Messages[n].CallId) then begin
              inc(WizardId);
              AddMessage(
                Wizards[WizardId].Text,
                Wizards[WizardId].Times,
                Wizards[WizardId].CallId);
              snd_Play(sndNewMsg);
              snd_Play(Wizards[WizardId].snd);
              end;
          if Messages[n].Time<0 then begin
            for i:=n to MessagesCount-1 do
              Messages[i]:=Messages[i+1];
            Dec(MessagesCount);
          end;
        end;
        if key_Press(K_ESCAPE) then zgl_Exit;

      end;

    end;

  end;
  guiProcess;
  zgl.Process(dt);

end;

procedure Init;
var n:integer;
begin
  Randomize;

  guiInit('Data/GUI');

  GameState:=gs_choose;

  MusicInit;

  for n:=1 to wzrds_count do
    Wizards[n].snd:= snd_LoadFromFile('Data/Voice/'+inttostr(n)+'.wav',1);

  txZero :=  tex_CreateZero( 128, 128, $00000000, TEX_DEFAULT_2D );
  txZeroMask:= tex_LoadFromFile('Data/Textures/txZeroMask.tga',  $FF000000,TEX_DEFAULT_2D);

  RTrgt := rtarget_Add(txZero, RT_DEFAULT);

  Level:=1;
  Map.LoadFromFile('Data/Maps/menu.bmp');
  PlayMusic;
  
  Player.Score:=0;
  Player.Lives:=player_lives;

  sndPFly:= snd_LoadFromFile('Data/Sound/portalfly.wav');
  sndNewMsg:= snd_LoadFromFile('Data/Sound/newmsg.wav');
  sndPshoot1:= snd_LoadFromFile('Data/Sound/portalgun_shoot1.wav');
  sndPshoot2:= snd_LoadFromFile('Data/Sound/portalgun_shoot2.wav');
  sndPremenu:= snd_LoadFromFile('Data/Sound/premenu.wav');
  sndWk:= snd_LoadFromFile('Data/Sound/wk.wav');
  sndEnergizer:= snd_LoadFromFile('Data/Sound/energizer.wav');
  for n:=1 to 2 do
    sndPortalExit[n]:= snd_LoadFromFile('Data/Sound/portalexit'+inttostr(n)+'.wav');
  for n:=1 to 3 do
    sndPortalOpen[n]:= snd_LoadFromFile('Data/Sound/portalopen'+inttostr(n)+'.wav');

  txWeapon:= tex_LoadFromFile('Data/Textures/txWeapon.tga',1,TEX_DEFAULT_2D);
  txPortalEnd:= tex_LoadFromFile('Data/Textures/txPortalEnd.tga',1,TEX_DEFAULT_2D);
  txEat:= tex_LoadFromFile('Data/Textures/txEat.tga',1,TEX_DEFAULT_2D);
  tex_SetFrameSize(txEat, item_size, item_size);
  txPacMan:= tex_LoadFromFile('Data/Textures/txPacMan.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txPacMan, item_size, item_size);
  txWalls:= tex_LoadFromFile('Data/Textures/txWalls.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txWalls, item_size, item_size);
  txGhost:= tex_LoadFromFile('Data/Textures/txGhost.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txGhost, item_size, item_size);
  txGhostScared:= tex_LoadFromFile('Data/Textures/txGhostScared.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txGhostScared, item_size, item_size);
  txGhostEaten:= tex_LoadFromFile('Data/Textures/txGhostEaten.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txGhostEaten, item_size, item_size);
  txSleepWalls:= tex_LoadFromFile('Data/Textures/txSleepWalls.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txSleepWalls, item_size, item_size);
  txbadWalls:= tex_LoadFromFile('Data/Textures/txBadWalls.tga',0,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txbadWalls, item_size, item_size);
  txPortals:= tex_LoadFromFile('Data/Textures/txPortals.tga',1,TEX_DEFAULT_2D xor TEX_FILTER_LINEAR or TEX_FILTER_NEAREST);
  tex_SetFrameSize(txPortals, item_size, item_size*2);

  zgl.Clear;
  zgl.LoadFromFile('Data\Effects\index.ini');

  for n:=1 to 2 do begin
    zgl.SetEffect(@Portals[n].Fly, 'PortalFly'+inttostr(n));
    zgl.SetEffect(@Portals[n].Touch, 'PortalTouch'+inttostr(n)+'|16');
    zgl.SetEffect(@Portals[n].Stay, 'PortalStay'+inttostr(n));
  end;
  for n:=3 to portals_count do begin
    zgl.SetEffect(@Portals[n].Fly, 'PortalFly3');
    zgl.SetEffect(@Portals[n].Touch, 'PortalTouch3|16');
    zgl.SetEffect(@Portals[n].Stay, 'PortalStay3');
  end;
  zgl.SetEffect(@plus10, 'plus10');
  zgl.SetEffect(@plus100, 'plus100');
  zgl.SetEffect(@plus500, 'plus500');
end;

procedure Quit;
begin
 //
end;

end.
