unit g_Tower;

interface
uses
  g_Data,g_Types,g_Utils,
  GPAHeader,
  {$INCLUDE uses.inc};

procedure Tower_Load(self : zTower);
procedure Tower_Draw(self : zTower);
procedure Tower_Add(self : zTower; pos : izPosition_f);
procedure Tower_Update(self : zTower; time : float);
procedure Gen_Spark(self:zTower;x,y,x1,y1,FracCount : word);
implementation

procedure Tower_Load(self : zTower);
var
  dir : string;
  TexFileName : string;
begin
  dir := iz_dir_local_data + 'tower.cfg';
  self^.size[0] := Cfg_ReadInt(dir,self^.name+'_SIZE',64);
  self^.size[1] := self^.size[0];
  self^.Rad := self^.size[0] div 2;
  self^.BuildDelay := Cfg_ReadInt(dir,self^.name+'_BUILD_DELAY',1000);
  self^.price := Cfg_ReadInt(dir,self^.name+'_PRICE',1);
  self^.Upgrade := 1;
  self^.ShotSpeed := Cfg_ReadInt(dir,self^.name+'_SHOT_SPEED',1000);
  self^.ShotPower := Cfg_ReadInt(dir,self^.name+'_SHOT_POWER',10);
  self^.ShotDistance := Cfg_ReadInt(dir,self^.name+'_SHOT_DISTANCE',100);
  self^.LTC := 0;
  self^.TTC := 0;
  self^.target := 0;
  self^.State := tsBuild;
  self^.aniFindStart := cfg_ReadInt(dir,self^.name+'_ANI_FIND_START',0);
  self^.aniBuildStart := cfg_ReadInt(dir,self^.name+'_ANI_BUILD_START',8);
  self^.aniBuildEnd := cfg_ReadInt(dir,self^.name+'_ANI_BUILD_END',10);
  self^.aniBuildDelay := cfg_ReadInt(dir,self^.name+'_ANI_BUILD_DELAY',200);
  self^.aniShotStart := cfg_ReadInt(dir,self^.name+'_ANI_SHOT_START',8);
  self^.aniShotEnd := cfg_ReadInt(dir,self^.name+'_ANI_SHOT_END',10);
  self^.aniShotDelay := cfg_ReadInt(dir,self^.name+'_ANI_SHOT_DELAY',100);
  TexFileName := Cfg_ReadStr(dir,self^.name+'_TEX','tower.tga');
  GPAExtractToFileByID(GPAGetIDByName(PChar(TexFileName),false),PChar('temp\graphics\'+TexFileName));
  self^.Tex := gfx.TexMan.Load(iz_dir_local_temp_gfx + TexFileName);
  self^.Spr := gfx.SprMan.Add(gfx.TexMan.GetSize(self^.tex),self^.size);
  self^.AniBuild := gfx.SprMan.Add_Anim(self^.Spr,self^.aniBuildStart,self^.aniBuildEnd,self^.aniBuildStart,self^.aniBuildDelay);
  self^.AniShot := gfx.SprMan.Add_Anim(self^.Spr,self^.aniShotStart,self^.aniShotEnd,self^.aniShotStart,self^.aniShotDelay);
  self^.Spark.maxFract := 6;
  self^.Spark.Delay := 1;
  self^.Spark.PointCount := 2;
  SetLength(self^.Spark.Points,2);
end;

procedure Tower_Draw(self : zTower);
var
  i : word;
begin
  if ((self^.pos[0]+self^.rad > -Camera.pos[0])and
    (self^.pos[1]+self^.rad > -Camera.pos[1])and
    (self^.pos[0]-self^.rad < -Camera.pos_2[0])and
    (self^.pos[1]-self^.rad < -Camera.pos_2[1])) then begin
      gfx.TexMan.Bind(self^.tex);
      case self^.State of
        tsBuild : begin
          gfx.SprMan.Draw_Anim_Alpha(self^.Spr,self^.AniBuild,self^.pos,0);
          end;
        tsFind  : gfx.SprMan.Draw_Alpha(self^.Spr,self^.aniFindStart,self^.pos,0);
        tsShot,tsFire  : begin
          gfx.SprMan.Draw_Anim_Alpha(self^.Spr,self^.AniShot,self^.pos,0);
         glLineWidth(2);
          GLBegin(GL_LINE_STRIP);
          for i := 0 to self^.Spark.PointCount-1 do
          begin
            if i > 0 then glVertex2f(self^.Spark.Points[i-1].x,self^.Spark.Points[i-1].y);
            glVertex2f(self^.Spark.Points[i].x,self^.Spark.Points[i].y);
          end;
          glEnd;
        end;
     end;
   end;
end;

procedure Tower_Add(self : zTower; pos : izPosition_f);
var
  i,nx,ny : word;
  flag : bool;
  r : int;
  t_pos : izPosition_i;
begin
  if Game.Money >= self^.price then begin
    t_pos[0] := Round(pos[0]);
    t_pos[1] := Round(pos[1]);
    flag := true;
    nx := t_pos[0] div 64;
    ny := t_pos[1] div 64;
    if Land[nx,ny].typeID <> 0 then flag := false;
    i:=World.TowerTypeCount;
    while i < World.TowerCount do begin
      r := Distance_fast2Di(zRound(Land[nx,ny].pos),zRound(World.Tower[i].pos));
      if r <= World.Tower[World.TowerCount-1].size[0]-10 then begin
        flag := false;
        break;
      end;
      inc(i);
    end;
    if flag then begin
      inc(World.TowerCount);
      SetLength(World.Tower,World.TowerCount);
      World.Tower[World.TowerCount-1] := self^;
      World.Tower[World.TowerCount-1].pos := Land[nx,ny].pos;
      World.Tower[World.TowerCount-1].AniBuild := gfx.SprMan.Add_Anim(self^.Spr,self^.aniBuildStart,self^.aniBuildEnd,self^.aniBuildStart,self^.aniBuildDelay);
      World.Tower[World.TowerCount-1].AniShot := gfx.SprMan.Add_Anim(self^.Spr,self^.aniShotStart,self^.aniShotEnd,self^.aniShotStart,self^.aniShotDelay);
      World.Tower[World.TowerCount-1].LTC := getTickCount;
      dec(game.Money,self^.price);
    end;
  end;
end;

procedure Tower_Update(self : zTower; time : float);
var
  i,r : word;
begin
  case self^.State of
    tsBuild : begin
      gfx.SprMan.Anim_Update(self^.spr,self^.AniBuild,time);
      self^.TTC := GetTickCount;
      if self^.TTC-self^.LTC > self^.BuildDelay then begin
        self^.State := tsFind;
        self^.LTC := self^.TTC;
      end;
    end;
    tsFind : begin
      i := World.MonsterTypeCount;
      while i < World.EndCharAC do begin
        if ((World.Characters[i].State <> csDeath)and(World.Characters[i].State <> csDead)) then begin
          r := Distance_fast2Di(zRound(self^.pos),zRound(World.Characters[i].pos));
          if r < self^.ShotDistance then begin
            self^.target := i;
            self^.State := tsShot;
            break;
          end;
        end;
      inc(i);
      end;
    end;
    tsShot : if ((World.Characters[self^.target].State = csDeath)or(World.Characters[self^.target].State = csDead)) then self^.State := tsFind else
    begin
      r := Distance_fast2Di(zRound(self^.pos),zRound(World.Characters[self^.target].pos));
      if (r < self^.ShotDistance) then begin
          self^.State := tsFire;
          World.Characters[self^.target].Life := World.Characters[self^.target].Life - self^.ShotPower;
      end else self^.State := tsFind;
    end;
    tsFire : begin
      gfx.SprMan.Anim_Update(self^.spr,self^.AniShot,time*20);
      self^.TTC := GetTickCount;
      if self^.TTC-self^.LTC > self^.ShotSpeed then begin
        self^.State := tsShot;
        self^.LTC := self^.TTC;
      end;
      self^.Spark.TTC := GetTickCount;
      if self^.Spark.TTC - self^.Spark.LTC > self^.Spark.Delay then begin
        self^.Spark.PointCount := 0;
        SetLength(self^.Spark.Points,self^.Spark.PointCount);
        Gen_Spark(self,round(self.pos[0]),round(self.pos[1]),round(World.Characters[self^.target].pos[0]),round(World.Characters[self^.target].pos[1]),0);
        self^.Spark.LTC := self^.Spark.TTC;
      end;
   end;
 end;
end;

procedure Gen_Spark(self:zTower;x,y,x1,y1,FracCount : word);
var
  x2,y2 : word;
begin
  inc(FracCount);
  if FracCount > self^.Spark.MaxFract then
  begin
    inc(self^.Spark.PointCount);
    SetLength(self^.Spark.Points,self^.Spark.PointCount);
    self^.Spark.Points[self^.Spark.PointCount-1].x := x1;
    self^.Spark.Points[self^.Spark.PointCount-1].y := y1;
    Exit;
  end;
  if x>x1 then x2 := (x1+(x-x1)div 2)+random(5)-random(5) else x2 := (x+(x1-x)div 2)+random(5)-random(5);
  if y>y1 then y2 := (y1+(y-y1)div 2)+random(5)-random(5) else y2 := (y+(y1-y)div 2)+random(5)-random(5);
  Gen_Spark(self,x,y,x2,y2,FracCount);
  Gen_Spark(self,x2,y2,x1,y1,FracCount);
end;

end.
