unit enemy_Unit;

{$mode delphi}

interface

uses
  Classes,
  SysUtils,
  zglHeader,
  var_const;
const
  Sentry_normal  = 7;
  Sentry_rocket  = 8;
  Sentry_sniper  = 9;
  Mode_Shooting  = 0;
  Mode_Moving    = 1;
  Mode_Repairing = 2;
  Mode_Stop      = 3;
type

  { TEnemy }

  TEnemy = class
    protected
      class_:byte;
      Direction:single;
      tex:zglPTexture;
      range:single;
      damage:integer;

      shell:TShell;
       mode:byte;
       shellEmitter:zglPEmitter2d;
      procedure Shoot(Xpos,Ypos:single;dir:single);
      procedure delShell;
    public
      shooting:boolean;
      Health:single;
      startingHealth:single;
      X,Y:byte; { 1 - 32 }
      BaricadeShoot:boolean;
      constructor Create(type_:byte;X_,Y_:Single);
      procedure Draw;
      procedure Update(delta:single);
      Procedure Kill;
      procedure Hurt(howMany:single);
      function isKilled:boolean;
      function isAbleToShoot:integer;

      procedure repair;
      procedure move;

      function TryToShoot:boolean;

  end;

implementation
uses LevelUnit,GameUnits;
{ TEnemy }

procedure TEnemy.Shoot(Xpos, Ypos: single;dir:single);
var curver:single;
begin
pengine2d_set(@particles1);
 baricadeShoot:=randomBool;
  shooting:=true;

  case class_  of
    SENTRY_NORMAL:curver:=6-random(13);
    SENTRY_Rocket:curver:=7-random(15);
    SENTRY_Sniper:curver:=4-random(9);
  end;
  shell.direction:=dir+curver;
  direction:=dir+90;
  snd_Play(BlasterSound,false,CalcX2d(Game.GetScreenW()/2),CalcY2d(Game.GetScreenH()/2));
  pengine2d_addEmitter(shellTracerEmitter,@ShellEmitter,Shell.pos.X,Shell.pos.Y);
end;

procedure TEnemy.delShell;
begin
    shooting:=false;
    Shell.pos.X:=X*32-16;
    Shell.pos.Y:=Y*32-16;
    if ShellEmitter<>nil then
     ShellEmitter.Params.Loop:=false;
end;

procedure TEnemy.repair;
begin
    health+=100;
    if TLevelScene(GameScene).movesLeft>0 then
    dec(TLevelScene(GameScene).movesLeft);
    if health>startingHealth then
     health:=startingHealth;
    TLevelScene(GameScene).repairsLeft-=1;
    snd_Play(repairSound,false,CalcX2d(Game.GetScreenW()/2),CalcY2d(Game.GetScreenH()/2));
end;

procedure TEnemy.move;
var ranX,ranY:integer;
        oldX,oldY:byte;
begin
pengine2d_set(@particles1);
pengine2d_AddEmitter(teleportEmitter,nil,X*32-16,Y*32-16);
    oldX:=X;
    oldY:=Y;
    while (oldX=X)and(oldY=Y) do
    begin
      with TLevelScene(GameScene) do
      begin
        X:=oldX;
        Y:=oldY;
        ranX:=random(3);
        ranY:=random(3);
       if  cellisFree(1-ranX+X,Y,true,true,true) then
        X:=1-ranX+X;
       if  cellisFree(X,1-ranY+Y,true,true,true) then
        Y:=1-ranY+Y;
      end;
    end;
     if X>32 then X:=32;
     if X<1 then X:=1;
     if Y>32 then Y:=32;
     if Y<1 then Y:=1;
     if TLevelScene(GameScene).movesLeft>0 then
     dec(TLevelScene(GameScene).movesLeft);

    // range.cX:=X*32-16;
     //range.cY:=Y*32-16;
     snd_Play(TeleportSound,false,CalcX2d(Game.GetScreenW()/2),CalcY2d(Game.GetScreenH()/2));
     pengine2d_AddEmitter(teleportEmitter,nil,X*32-16,Y*32-16);
end;

function TEnemy.TryToShoot:boolean;
var temp:integer;
begin
  with TLevelScene(GameScene) do
  begin
    temp:=isAbleToShoot;

      if temp>=0 then
      begin
       Shoot(wariors[temp].Pos.X,wariors[temp].Pos.Y,
       m_angle(X*32-16,Y*32-16,wariors[temp].Pos.X,wariors[temp].Pos.Y));
      if TLevelScene(GameScene).movesLeft>0 then
       dec(TLevelScene(GameScene).movesLeft);
      result:=true;
      end else result:=false;

  end;
end;


constructor TEnemy.Create(type_: byte; X_, Y_: Single);
begin
baricadeShoot:=randomBool;
 class_:=type_;
 X:=round(X_);
 Y:=round(Y_);
 Direction:=0;
 //range.cX:=X*32-16;
 //range.cY:=Y*32-16;
 Shell.pos.X:=X*32-16;
 Shell.pos.Y:=Y*32-16;
 Case type_ of
   Sentry_normal:
     begin

       tex:=Sentry_Head_Tex_0;
       range:=700;
       Shell.speed:=600;
       Shell.type_:=Shell_normal;
       Health:=150;
       Damage:=65;
     end;
   Sentry_Rocket:
     begin

       tex:=Sentry_Head_Tex_1;
       range:=500;
       Shell.speed:=600;
       Shell.type_:=Shell_rocket;
       Health:=200;
       Damage:=100
     end;
   Sentry_Sniper:
     begin

       tex:=Sentry_Head_Tex_2;
       range:=850;
       Shell.speed:=600;
       Shell.type_:=Shell_normal;
       Health:=100;
       Damage:=150;
     end;
 end;
 StartingHealth:=Health;
end;

procedure TEnemy.Draw;
begin
 if shooting then
  ssprite2d_draw(shellTex_0,shell.pos.X,shell.pos.Y,8,8,0);

  ssprite2d_draw(Sentry_Body_tex,X*32-32,Y*32-32,32,32,0);
  ssprite2d_draw(tex,X*32-16-tex^.Width div 2,Y*32-16-tex^.Height div 2,tex^.Width,tex^.Height,Direction);
end;

procedure TEnemy.Update(delta:single);
var
  objective:pointer;
  tempDamage:integer;
begin
   if (TLevelScene(GameScene).playerTurn=true) then exit;
       if shooting then
        begin
          shell.pos.X += cos((shell.direction+180)*deg2rad) * shell.speed * (delta / 1000);
          shell.pos.Y += sin((shell.direction+180)*deg2rad) * shell.speed * (delta / 1000);
          begin
          ShellEmitter.Params.Position:=Shell.pos;
          ShellEmitter.AsPoint.Direction:=Shell.direction-90;
          end;
        end;                                                                                                    {random for barikades}
        if not TLevelScene(GameScene).CellIsFree(round(shell.pos.X) div 32 + 1,round(shell.pos.Y) div 32 + 1,baricadeShoot,true) then
        begin
         objective:=TLevelScene(GameScene).GetWariorCell(round(shell.pos.X) div 32 + 1,round(shell.pos.Y) div 32 + 1);
         if objective<>nil then
         begin
          if m_Distance(X*32-16,Y*32-16,Shell.pos.X,Shell.pos.Y)>range then
                         TempDamage:=round(damage*(range/m_Distance(X*32-16,Y*32-16,Shell.pos.X,Shell.pos.Y))) else
                         TempDamage:=round(Damage);
          TGameUnit(objective).Hurt(tempDamage);
         end;
         snd_Play(MissSound,false,CalcX2d(Game.GetScreenW()/2),CalcY2d(Game.GetScreenH()/2));
          delShell;
        end;
end;

procedure TEnemy.Kill;
begin
 pengine2d_set(@particles1);
 pengine2d_AddEmitter(BoomEmitter,nil,X*32-16,Y*32-16);
 snd_Play(BoomSound,false,CalcX2d(Game.GetScreenW()/2),CalcY2d(Game.GetScreenH()/2));
end;

procedure TEnemy.Hurt(howMany:single);
begin
    Health-=HowMany;
end;

function TEnemy.isKilled: boolean;
begin
    if Health<=0 then result:=true else result:=false;
end;

function TEnemy.isAbleToShoot: integer;
var   TheLine:zglTLine;
      TempLine:zglTLine;
      SmallerPath:integer;
      i:integer;
begin
 TheLine.x0:=0;
 TheLine.y0:=0;
 TheLine.x1:=- 9999;
 TheLine.y1:=- 9999;

result:=-9999;
 with TLevelScene(GameScene) do
 begin

    if Length(wariors)>0 then
     for i:= 0 to length(wariors)-1 do
    //   if col2d_pointInCircle(wariors[i].Pos.X,wariors[i].Pos.Y,Range) then
       begin
        TempLine.x0:=X*32-16;
        TempLine.y0:=Y*32-16;
        TempLine.x1:=wariors[i].Pos.X;
        TempLine.y1:=wariors[i].Pos.Y;
        if m_Distance(TheLine.x0,TheLine.y0,TheLine.x1,TheLine.y1)>m_Distance(TempLine.x0,TempLine.y0,TempLine.x1,TempLine.y1) then
         if not  RayTrace(@TempLine) then
          begin
           TheLine:=tempLine;
           result:=i;
          end;
   end;

 end;
end;

end.

