unit GameObjects;

interface
uses DGLEngine_header, Math, VAriables, GameUtils, OpenGL;

type
TBullet=record
Active : boolean;
X,Y,Speed,length : single;
Angle,Damage : integer;
end;

TTurel = record
Active : boolean;
X,Y : single;
Angle,Shot,Health,status : integer;
end;


TMonster=record
onturel : integer;
Active : boolean;
X,Y ,Frame: single;
Model,

Status
//0 - на игрока
//1 - на турель
//2 - на базу
//3 - огибание препятствия

 : byte;
Angle,Health : integer;
Col : TsingleRect;
end;

TBlood = record
Active : boolean;
X,Y : single;
Life : integer;
end;

var
BulletsCount : integer = 0;
Bullets : array of TBullet;
MonstersCount : integer =0;
Monsters : array of TMonster;
BloodCount : integer = 0;
Bloods : array of TBlood;
TurelsCount : integer = 0;
Turels : array of TTurel;

procedure CreateBullet(X,Y,Speed : single;Angle,Damage : integer);
procedure ProcessBullets;
procedure DrawBullets;

procedure CreateMonster(X,Y : single);
procedure ProcessMonsters;
procedure DrawMonsters;

procedure CreateBlood(X,Y : single);
procedure ProcessBLood;
procedure DrawBlood;

procedure CreateTurel(X,Y : single);
procedure ProcessTurel;
procedure DrawTurel;

implementation
uses GameMap;

procedure CreateBullet(X,Y,Speed : single;Angle,Damage : integer);
var i : integer;
begin
for i:=0 to BulletsCount do
if BulletsCount>0 then
if not Bullets[i].Active then
begin
Bullets[i].Active:=true;
Bullets[i].X:=X+cos(degtorad(Angle))*0.3;
Bullets[i].Y:=Y+sin(degtorad(Angle))*0.3;
Bullets[i].Speed:=Speed;
Bullets[i].Angle:=Angle;
Bullets[i].length:=0;
Bullets[i].Damage:=Damage;
Exit;
end;
inc(BulletsCount);
SetLength(Bullets,BulletsCount);
Bullets[BulletsCount-1].Active:=true;
Bullets[BulletsCount-1].X:=X+cos(degtorad(Angle))*0.3;
Bullets[BulletsCount-1].Y:=Y+sin(degtorad(Angle))*0.3;
Bullets[BulletsCount-1].Speed:=Speed;
Bullets[BulletsCount-1].Angle:=Angle;
Bullets[BulletsCount-1].length:=0;
Bullets[BulletsCount-1].Damage:=Damage;
end;

function TestBullCol_obj(bul : integer) : boolean;
var i : integer;
begin
result:=false;
 for i:=0 to length(m_GObjects)-1 do
  if  PointInRect(Bullets[bul].X,Bullets[bul].Y,m_GObjects[i].col.X,m_GObjects[i].col.Y,m_GObjects[i].col.Width,m_GObjects[i].col.Height) then
  begin
   result:=true;
   Exit;
  end;
end;


procedure ProcessBullets;
var i : integer;
begin
 for i:=0 to BulletsCount-1 do
 if Bullets[i].Active then
 begin
 Bullets[i].length:= Bullets[i].length+0.1;
 Bullets[i].X:=Bullets[i].X+cos(degtorad(Bullets[i].Angle))*Bullets[i].Speed;
 Bullets[i].Y:=Bullets[i].Y+sin(degtorad(Bullets[i].Angle))*Bullets[i].Speed;
  if (TestBullCol_obj(i)) or
  ((Bullets[i].X<0)or(Bullets[i].X>m_Header.CellsX_count) or (Bullets[i].Y<0)or(Bullets[i].Y>m_Header.CellsX_count))
  then Bullets[i].Active:=false;
 end;
end;

procedure DrawBullets;
var i : integer;
begin
 for i:=0 to BulletsCount-1 do
 if Bullets[i].Active then
 begin
  BeginObj3D;
   Color3D($81D1F8,150,true);
   DrawLine(Bullets[i].X,Bullets[i].Y,1.35,Bullets[i].X-cos(degtorad(Bullets[i].Angle))*Bullets[i].length,Bullets[i].Y-sin(degtorad(Bullets[i].Angle))*Bullets[i].length,1.35,1.5,true);
  EndObj3D;
 end;
end;
//------------------------------------------------------------------------------
procedure CreateMonster(X,Y : single);
var i,a :  integer;
begin
for i:=0 to MonstersCount-1 do
if MonstersCount>0 then

 if not Monsters[i].Active then
 begin
Monsters[i].Active:=true;
Monsters[i].X:=X;
Monsters[i].Y:=Y;
Monsters[i].Angle:=0;
Monsters[i].Health:=100;
Monsters[i].Frame:=0;
Monsters[i].onturel:=-1;

if (turelscount>0) and (random(2)=0) then
for a:=0 to turelscount-1 do
 if (turels[a].Active) and (turels[a].Health>0) then
      Monsters[i].onturel:=a;
Monsters[i].Model:=mdl_Enemy_Run;
Monsters[i].Status:=0;
Exit;
 end;

inc(MonstersCount);
SetLength(Monsters,MonstersCount);
Monsters[MonstersCount-1].Active:=true;
Monsters[MonstersCount-1].X:=X;
Monsters[MonstersCount-1].Y:=Y;
Monsters[MonstersCount-1].Angle:=0;
Monsters[MonstersCount-1].Health:=100;
Monsters[MonstersCount-1].Frame:=0;
Monsters[MonstersCount-1].Model:=mdl_Enemy_Run;
Monsters[MonstersCount-1].Status:=0;
Monsters[MonstersCount-1].onturel:=-1;

if (turelscount>0) and (random(2)=0) then
for a:=0 to turelscount-1 do
 if (turels[a].Active) and (turels[a].Health>0) then
      Monsters[MonstersCount-1].onturel:=a;

end;


function TestMonstrCol_obj(m : integer) : boolean;
var i : integer;
begin
result:=false;
 for i:=0 to length(m_GObjects)-1 do
  if  RectInRect(Monsters[m].Col,m_GObjects[i].col) then
  begin
   result:=true;
   Exit;
  end;
end;

function TestMonstrCol_monstr(m : integer) : boolean;
var i : integer;
begin
result:=false;
 for i:=0 to MonstersCount-1 do
 if m<>i then
  if  (RectInRect(Monsters[m].Col,Monsters[i].Col)) and (Monsters[i].Status<>5) then
  begin
   result:=true;
   Exit;
  end;
end;

function TestMonstrCol_Turrel(m : integer) : boolean;
var i : integer;
begin
result:=false;
 for i:=0 to TurelsCount-1 do
 if Turels[i].active then
  if (RectInRect(Monsters[m].Col,boundsS(Turels[i].X,Turels[i].Y,1.0,1.0)))
  and (Turels[i].Health>0) then
  begin
   result:=true;
   Monsters[m].Status:=4;
   Monsters[m].Model:=mdl_Enemy_Attack;
   Monsters[m].Frame:=0;
   Turels[i].Health:=Turels[i].Health-25;
   Exit;
  end;
end;


function TestMonstrCol_bul(m : integer) : boolean;
var i,a : integer;Col : Tsinglerect;
begin
result:=false;
Col:=boundss(Monsters[m].X-0.25,Monsters[m].Y-0.25,1,1);
 for i:=0 to BulletsCount-1 do
 if Monsters[m].Status<>5 then
  if  PointInRect(Bullets[i].X,Bullets[i].Y,col.X,col.Y,col.Width,col.Height) then
  if Bullets[i].Active then
  begin
    for a:=0 to 6 do
    CreateBlood(Bullets[i].X+cos(degtorad(Bullets[i].Angle))*(a*a/11),Bullets[i].Y+sin(degtorad(Bullets[i].Angle))*(a*a/11));
   Monsters[m].Health:=Monsters[m].Health-Bullets[i].Damage;
   Bullets[i].Active:=false;
   if random(10)=5 then PlaySample(s_pain2)
   else
   PlaySample(s_hit);

   result:=true;
   Exit;
  end;
end;

procedure ProcessMonsters;
function noturels : boolean;
var i : integer;
begin
if turelscount>0 then
for i:=0 to turelscount-1 do
 if (turels[i].Active) and (turels[i].Health>0) then
 begin
 result:=false;
 exit;
 end;
 result:=true;
end;
var i,a,j,ang,n : integer;
ox,oy : single;
begin
for i:=0 to MonstersCount-1 do
if Monsters[i].Active then
 begin

 if (Monsters[i].Health<0) and (Monsters[i].Status<>5) then
 begin
 Player[0].Points:=Player[0].Points+25;
  PlaySample(s_death2);
  Monsters[i].Status:=5;
  Monsters[i].Model:=mdl_Enemy_Die;
  Monsters[i].Frame:=0;
 end;
  if (Monsters[i].Status<>5) and (Monsters[i].Status<>4) then
  Monsters[i].Frame:=Monsters[i].Frame+1 else
  Monsters[i].Frame:=Monsters[i].Frame+0.35;

  if round(Monsters[i].Frame)=ModelFramesCount(Monsters[i].Model) then
  begin

  if Monsters[i].Status=4 then
  begin
  Monsters[i].Status:=0;
  Monsters[i].Model:=mdl_Enemy_Run;
  end;

  if Monsters[i].Status=5 then
  begin
  Monsters[i].Frame:=ModelFramesCount(Monsters[i].Model)-1;
  dec(Monsters[i].Health);
  end;
  if Monsters[i].Status<>5 then
  Monsters[i].Frame:=0;

  end;

  ox:=Monsters[i].X;
  oy:=Monsters[i].Y;

 TestMonstrCol_bul(i);

 if (Monsters[i].Status<>4) and (Monsters[i].Status<>5) then
 begin
 if (Monsters[i].Status<>1) then
  begin
  if (Monsters[i].onturel=-1) or( noturels) then
  Monsters[i].Angle:=-trunc(RadToDeg(ArcTan2(Player[0].Y-Monsters[i].Y, Player[0].X-Monsters[i].X))) else
  Monsters[i].Angle:=-trunc(RadToDeg(ArcTan2(Turels[Monsters[i].onturel].Y-Monsters[i].Y, Turels[Monsters[i].onturel].X-Monsters[i].X)));
  end;
  Monsters[i].X:=Monsters[i].X+cos(degtorad(-Monsters[i].Angle))*0.085;
  Monsters[i].Y:=Monsters[i].Y+sin(degtorad(-Monsters[i].Angle))*0.085;
 end;

if Monsters[i].Status=1 then if random(25)=10 then Monsters[i].Status:=0;

if (Monsters[i].Status<>4) and (Monsters[i].Status<>5) then
begin
  Monsters[i].Col:=boundss(Monsters[i].X,Monsters[i].Y,0.5,0.5);

  if TestMonstrCol_obj(i) or TestMonstrCol_monstr(i) then
   begin
   Monsters[i].X:=Ox;
   Monsters[i].Y:=Oy;
   Monsters[i].Status:=1;
   if random(2)=0 then Monsters[i].Angle:=Monsters[i].Angle+90 else Monsters[i].Angle:=Monsters[i].Angle-90;
   end;


  if TestMonstrCol_Turrel(i) then
  begin
   Monsters[i].X:=Ox;
   Monsters[i].Y:=Oy;
  end;

  if RectInRect(Monsters[i].Col,boundsS(Player[0].X,Player[0].Y,0.150,0.150)) then
  begin
   Monsters[i].X:=Ox;
   Monsters[i].Y:=Oy;
   Monsters[i].Status:=4;
   Monsters[i].Model:=mdl_Enemy_Attack;
   Monsters[i].Frame:=0;
   PlaySample(s_pain);
   Player[0].Health:=Player[0].Health-35;
  for j:=0 to 3 do
  begin
  if random(2)=0 then ang:=-(10+random(35)) else ang:=10+random(35);
   for a:=0 to 4 do
    CreateBlood(Player[0].X+cos(degtorad(-Monsters[i].Angle+ang))*(a*a/11),Player[0].Y+sin(degtorad(-Monsters[i].Angle+ang))*(a*a/11));
  end;
  end;

  end;

if Monsters[i].Health<-50 then Monsters[i].Active:=false;

end;



end;

procedure DrawMonsters;
var i : integer;
begin
for i:=0 to MonstersCount-1 do
if Monsters[i].Active then
 begin
  BeginObj3D;
  glEnable(GL_LIGHTING);
  if Monsters[i].Status = 5 then
  Position3D(Monsters[i].X,Monsters[i].Y,0.1-(-Monsters[i].Health/100))
  else
  Position3D(Monsters[i].X,Monsters[i].Y,0.1);

  RotateZ(Monsters[i].Angle-90);

  if Monsters[i].Model = mdl_Enemy_Attack then Position3D(0,0,0.2);

     Scale3D(0.02);

  if Monsters[i].Model = mdl_Enemy_Run then
   case round(Monsters[i].Frame) of
   3: Position3D(0,7,0);
   4: Position3D(0,3,0);
   5:Position3D(0,-2,0);
   7:Position3D(0,5,0);
   8:Position3D(0,13,0);
   end;

  SetTexture(tex_Enemy);
  DrawModel(Monsters[i].Model,round(Monsters[i].Frame),true);
  glDisable(GL_LIGHTING);
  EndObj3D;
 end;
end;
//------------------------------------------------------------------------------
procedure CreateBlood(X,Y : single);
var i : integer;
begin
if BloodCount>0 then
 for i:=0 to BloodCount do
 if not Bloods[i].Active then
 begin
 Bloods[i].Active:=true;
 Bloods[i].X:=X;
 Bloods[i].Y:=Y;
 Bloods[i].Life:=200;
 Exit;
 end;

inc(BloodCount);
SetLength(Bloods,BloodCount);
Bloods[BloodCount-1].Active:=true;
Bloods[BloodCount-1].X:=X;
Bloods[BloodCount-1].Y:=Y;
Bloods[BloodCount-1].Life:=250;
end;

procedure ProcessBLood;
var i : integer;
begin
 for i:=0 to BloodCount-1 do
 if Bloods[i].Active then
  begin
  dec(Bloods[i].Life,2);
  if Bloods[i].Life<15 then Bloods[i].Active:=false;
  end;
end;

procedure DrawBlood;
var i,a : integer;
begin
 for i:=0 to BloodCount-1 do
 if Bloods[i].Active then
 begin
  BeginObj3D;
  a:=254;
  if Bloods[i].Life<254 then a:=Bloods[i].Life;
   Color3D($FFFFFF,a,false);
   SetTexture(tex_Blood);
   Position3D(Bloods[i].X,Bloods[i].Y,0.04);
   DrawPoly3D(0.8,0.8);
  EndObj3D;
 end;
end;
//------------------------------------------------------------------------------
procedure CreateTurel(X,Y : single);
var i : integer;
begin
if TurelsCount>0 then
 for i:=0 to TurelsCount -1 do
 if not Turels[i].Active then
 begin
 Turels[i].Active:=true;
 Turels[i].X:=X;
 Turels[i].Y:=Y;
 Turels[i].Health:=49;
 Turels[i].Status:=0;
 Turels[i].Shot:=0;
 Exit;
 end;

inc(TurelsCount);
SetLength(Turels,TurelsCount);
 Turels[TurelsCount-1].Active:=true;
 Turels[TurelsCount-1].X:=X;
 Turels[TurelsCount-1].Y:=Y;
 Turels[TurelsCount-1].Health:=49;
 Turels[TurelsCount-1].Status:=0;
 Turels[TurelsCount-1].Shot:=0;
end;

procedure ProcessTurel;
var i,a, tm : integer; t,f : single;
begin
 for i:=0 to TurelsCount-1 do
 if Turels[i].Active then
  begin
  if Turels[i].Health>0 then
  begin
  t:=10000;

   for a:=0 to MonstersCount-1 do
    if (Monsters[a].Active) and (Monsters[a].Status<>5) then
    begin
    f:=sqrt((Turels[i].X-Monsters[a].X)*(Turels[i].X-Monsters[a].X)+(Turels[i].Y-Monsters[a].Y)*(Turels[i].Y-Monsters[a].Y));
     if (t>f) and (Monsters[a].Status<>5) then
     begin
     t:=f;
     tm:=a;
     end;
    end;

   Turels[i].Angle:=-trunc(RadToDeg(ArcTan2(Turels[i].Y-Monsters[tm].Y, Turels[i].X-Monsters[tm].X)));

   Turels[i].Shot:=Turels[i].Shot+1;

   if Turels[i].Shot>8 then
   begin
   Turels[i].Shot:=0;
   PlaySample(s_shot1);
   CreateBullet(Turels[i].x+0.5,Turels[i].y+0.5,0.46,-(Turels[i].Angle+180),25);
   end;

  end else
  begin
  dec(Turels[i].Health);
  if Turels[i].Health<-250 then Turels[i].Active:=false;
  end;
 end;
end;

procedure DrawTurel;
var i : integer;
begin
 for i:=0 to TurelsCount-1 do
 if Turels[i].Active then
 begin
  BeginObj3D;
   glEnable(GL_LIGHTING);
   EnableSphereMapping;

   if Turels[i].Health<0 then
   Position3D(Turels[i].X+0.5,Turels[i].Y+0.5,0.25+Turels[i].Health/200)
   else
   Position3D(Turels[i].X+0.5,Turels[i].Y+0.5,0.25);

   SetTexture(tex_reflection);
   DrawQube(0.25,0.25,0.5);

     RotateZ(Turels[i].Angle);

   Position3D(0,0,1.0);
   DrawCylinder(0.7,0.5);
   rotatey(90);
   Position3D(-0.3,0,0.7);
   DrawCylinder(0.15,2.5);

   glDisable(GL_LIGHTING);

  EndObj3D;
 end;
end;

end.
