unit u_ghost;

interface

uses zglHeader, u_const, PathFind, u_music;

type
  TGhost = object
    Enabled:Boolean;
    Pos, ToPos, Home: zglTPoint2D;
    Angle: integer;
    AnimId, PathId:integer;
    State, ScareTime, TestTime, OutTime: Integer;
    iId: byte;
    Path, OldPath:TPathGroup;

    procedure Init(Id,X,Y:integer);
    procedure Draw;
    procedure Update;
  end;

var Pincs:array[1..ghosts_count] of Integer = (
       $FF5703,
       $FFAB57,
       $FFABFF,
       $0383FF
    );

    TestId:integer;

implementation

uses u_game;

function GhostTest(X,Y,Direction : Integer):integer;
var i:integer;
begin
 for i:=1 to ghosts_count do
    if (i<>TestId) and (ghosts[TestId].State=gss_go) and (Round(ghosts[i].ToPos.X)=x) and (Round(ghosts[i].ToPos.Y)=Y) then begin
      result:=10;
      Exit;
    end;
  if Direction mod 2 = 0 then begin
    case Direction of
      0:i:=90; //270
      2:i:=180; //0
      4:i:=270; //90
      else i:=0; //180
    end;
    if Map.CkeckPos(X,Y,i,false) then result:=1 else result:=-1;
  end else result:=-1;
end;

procedure TGhost.Init(Id,X,Y:integer);
begin
  Pos.X:=X;
  Pos.Y:=Y;
  Home.X:=X;
  Home.Y:=Y;
  ToPos.X:=X;
  ToPos.Y:=Y;
  Enabled:=True;
  AnimId:=1;
  iId:=Id;
  State:=gss_go;
end;

procedure TGhost.Update;
var i,px,py,dx,dy,d,px_,py_:Integer;
    s:single;
    x: zglTPoint2D;
begin
  if j mod 64 = 0 then begin
    Inc(AnimId);
    if AnimId>4 then AnimId:=1;
    i:=Round(m_Angle(ToPos.X, ToPos.Y, Pos.X, Pos.Y));
    Map.aNormalize(i);
    Angle:=i;
  end;

  if OutTime>0 then begin
    dec(OutTime);
    exit;
  end;

  if m_Distance(Pos.X, Pos.Y, Player.Pos.X, Player.Pos.Y)<0.5 then begin
    case State of
      gss_go:begin
        StopMusic;
        Dec(Player.Lives);
        Map.Reload;
        DieCounter:=0;
        GameState:=gs_die;
        DieId:=Random(die_count);
        snd_Play(sndPremenu);
      end;
      gss_back:begin
        x.X:=Pos.X*item_size;
        x.Y:=Pos.Y*item_size;
        zgl.CreateEffect(@plus500, x, -Player.AngleOffset-90);
        Player.AddScore(500);
        snd_Play(sndEnergizer);
        State:=gss_eaten;
      end;
    end;
  end;
  if ScareTime>0 then dec(ScareTime);
  if m_Distance(Pos.X, Pos.Y, ToPos.X, ToPos.Y)>ghost_speed*Diffs[Player.Diff]*2 then begin
    case State of
      gss_go: s:=ghost_speed;
      gss_back: s:=ghost_speed*0.75;
      gss_eaten: s:=ghost_speed*2;
    end;
    Pos.X:=Pos.X+m_cos(Angle)*s*Diffs[Player.Diff];
    Pos.Y:=Pos.Y+m_sin(Angle)*s*Diffs[Player.Diff];

  end else begin
    for i:=1 to portals_count do
      if (Portals[i].State=portal_opened) and (Portals[Portals[i].ExitId].State=portal_opened) then
      if (abs(Portals[i].Position.X-Pos.X)<ghost_speed*Diffs[Player.Diff]*2) and (abs(Portals[i].Position.Y-Pos.Y)<ghost_speed*Diffs[Player.Diff]*2) and
        (Map.InCenter(Pos.X, Pos.Y)) then begin
        Pos:=Portals[Portals[i].ExitId].Position;
        Angle:=Portals[Portals[i].ExitId].lookAngle;
        ToPos.X:=Pos.X+m_cos(Angle);
        ToPos.Y:=Pos.Y+m_sin(Angle);
        Pos.X:=Pos.X-m_cos(Angle)*ghost_speed*Diffs[Player.Diff]*4;
        Pos.Y:=Pos.Y-m_sin(Angle)*ghost_speed*Diffs[Player.Diff]*4;
      end;
    TestId:=iId;
    if TestTime<=0 then begin
      case State of
        gss_go:begin
          if m_Distance(Pos.X, Pos.Y, Player.Pos.X, Player.Pos.Y)<0.1 then begin

          end else begin
            FindPath(Path,
              Round(Pos.X),Round(Pos.Y),
              Round(Player.Pos.X),Round(Player.Pos.Y), GhostTest);
            if Path.Size<=1 then begin
              TestTime:=test_time;
            end;
          end;
        end;
        gss_back, gss_eaten:begin
          if m_Distance(Pos.X, Pos.Y, Home.X, Home.Y)<0.1 then begin
            if State = gss_eaten then State:=gss_go;
          end else begin
            FindPath(Path,
              Round(Pos.X),Round(Pos.Y),
              Round(Home.X),Round(Home.Y), GhostTest);
            if Path.Size<=1 then begin
              TestTime:=test_time;
            end;
          end;
          if State = gss_back then begin
            if ScareTime<=0 then State:=gss_go;
          end;
        end;
      end;
      if Path.Size>1 then begin
        ToPos.X:=Path.Path[1].X;
        ToPos.Y:=Path.Path[1].Y;
      end;
    end else Dec(TestTime);
  end;

end;

procedure TGhost.Draw;
var i:integer;
    p:zglPTexture;
begin
  case State of
    gss_go: begin
      p:=txGhost;
      fx2d_SetColor(Pincs[iId]);
    end;
    gss_back:begin
      p:=txGhostScared;
      if (ScareTime<scare_time/6) and (j mod 4=0) then begin
        pr2d_Circle(Pos.X*item_size, Pos.Y*item_size, item_size/2+3, $999999, 128, 32, PR2D_FILL);
      end;
    end;
    gss_eaten:begin
      p:=txGhostEaten;
    end;
  end;
  i:=Angle+Player.AngleOffset+45; 
  Map.aNormalize(i);
  asprite2d_Draw(p, (Pos.X-0.5)*item_size, (Pos.Y-0.5)*item_size,
    item_size, item_size, -Player.AngleOffset, AnimId,
    255, FX_BLEND or FX_COLOR);
  fx2d_SetColor($FFFFFF);
  asprite2d_Draw(p, (Pos.X-0.5)*item_size, (Pos.Y-0.5)*item_size,
    item_size, item_size, -Player.AngleOffset, 4+(i div 90)+1);
end;

end.
