unit UEnemy;

interface

uses
  JEN_Header,
  JEN_Math,
  UWeapon;

type
  TEnemyKind = (ekNone, ekTriangle, ekStupidShip, ekCube, ekCruiser, ekFighter, ekBoss);
  TSpawnType = (stAll, stMidlle, st2Lines);

const
  EnemyParam : array[TEnemyKind] of record
    Life  : Single;
    Size  : Single;
    Speed : Single;
    WeaponType: TWeaponType;
    BonusChance : Single;
    Scores: LongInt;
    Color : TVec4f;
  end = (
         (Life: 0; Size: 0; Speed: 0; WeaponType: wtNone; Scores: 0; Color: (X:0; Y:0; Z:0; W:0)),
         (Life: 50; Size: 32; Speed: 0.1; WeaponType: wtNone; Scores: 100; Color: (X:0.9; Y:0.2; Z:0.2; W:1)),
         (Life: 30; Size: 32; Speed: 0.07; WeaponType: wtEnemyLaser1; Scores: 150; Color: (X:1.0; Y:0.6; Z:0.0; W:1)),
         (Life: 140; Size: 32; Speed: 0.07; WeaponType: wtEnemyPlasma; BonusChance: 0.7; Scores: 500; Color: (X:0.0; Y:0.7; Z:0.7; W:1)),
         (Life: 110; Size: 64; Speed: 0.05; WeaponType: wtEnemyLaserGun2; BonusChance: 0.3; Scores: 400; Color: (X:0.7; Y:0.0; Z:0.7; W:1)),
         (Life: 50; Size: 32; Speed: 0.5; WeaponType: wtEnemyLaserGun; BonusChance: 0.05; Scores: 200; Color: (X:0.0; Y:0.7; Z: 0; W:1)),
         (Life: 3000; Size: 128; Speed: 0.04; WeaponType: wtBossGun; BonusChance: 0; Scores: 2000; Color: (X:1; Y:0; Z:0; W:1))
        );

const
  SpawnCount = 28;
  EnemySpawn : array[1..SpawnCount] of record
    Kind  : TEnemyKind;
    Spawn : TSpawnType;
    Count : LongInt;
    Time  : LongInt;
    Duration : LongInt;
  end = (
          (Kind: ekTriangle; Spawn: stAll; Count: 30; Time: 2000; Duration: 10000),
          (Kind: ekStupidShip; Spawn: stAll; Count: 10; Time:13000; Duration: 10000),
          (Kind: ekTriangle; Spawn: stAll; Count: 20; Time: 25000; Duration:10000),
          (Kind: ekStupidShip; Spawn: stAll; Count: 15; Time: 30000; Duration: 10000),

          (Kind: ekTriangle; Spawn: stAll; Count: 20; Time: 45000; Duration: 10000),
          (Kind: ekCruiser; Spawn: st2Lines; Count: 1; Time: 45000; Duration: 1),
          (Kind: ekCruiser; Spawn: st2Lines; Count: 1; Time: 50000; Duration: 1),

          (Kind: ekStupidShip; Spawn: stAll; Count: 20; Time: 60000; Duration: 10000),
          (Kind: ekFighter; Spawn: st2Lines; Count: 3; Time: 60000; Duration: 1),

          (Kind: ekTriangle; Spawn: stAll; Count: 10; Time: 72000; Duration: 10000),
          (Kind: ekFighter; Spawn: st2Lines; Count: 4; Time: 75000; Duration: 1),
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 72000; Duration: 1),
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 78000; Duration: 1),

          (Kind: ekCruiser; Spawn: stAll; Count: 6; Time: 90000; Duration: 15000),
          (Kind: ekStupidShip; Spawn: stAll; Count: 30; Time: 90000; Duration: 10000),

          (Kind: ekTriangle; Spawn: stAll; Count: 50; Time: 110000; Duration: 10000),
          (Kind: ekStupidShip; Spawn: stAll; Count: 50; Time: 110000; Duration: 10000),

          (Kind: ekCruiser; Spawn: st2Lines; Count: 4; Time: 130000; Duration: 1),
          (Kind: ekFighter; Spawn: st2Lines; Count: 5; Time: 130000; Duration: 1),

          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 145000; Duration: 1),
          (Kind: ekCruiser; Spawn: stMidlle; Count: 4; Time: 145000; Duration: 1),
          (Kind: ekTriangle; Spawn: stAll; Count: 20; Time: 145000; Duration: 10000),
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 150000; Duration: 1),

          (Kind: ekFighter; Spawn: st2Lines; Count: 9; Time: 150000; Duration: 1),
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 200000; Duration: 1),
          (Kind: ekFighter; Spawn: st2Lines; Count: 9; Time: 210000; Duration: 1),
          (Kind: ekFighter; Spawn: st2Lines; Count: 15; Time: 230000; Duration: 1),
          (Kind: ekBoss; Spawn: stMidlle; Count: 1; Time: 270000; Duration: 1)










          {,
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 12000; Duration: 1),
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 13000; Duration: 1),
          (Kind: ekCube; Spawn: st2Lines; Count: 1; Time: 14000; Duration: 1)  }
        );

type
  TEnemyEng = class
    constructor Create;
  private
    FEmemyTex : array[TEnemyKind] of ITexture;
    FSpawned: array[1..SpawnCount] of LongInt;
  public
    Enemies : array[1..150] of record
      Weapon     : TWeapon;
      Kind       : TEnemyKind;
      Dead       : Boolean;
      Dir        : TVec2f;
      Pos        : TVec2f;
      Angle      : Single;
      CreateTime : LongInt;
      Health     : Single;
      Fade       : Single;
      Data1      : LongInt;
    end;
    procedure Restart;
    procedure Coll(idx: Integer);
    procedure Hit(idx: Integer; Weapon: TWeaponType);
    procedure OnUpdate(dt : LongInt);
    procedure OnRender;
  end;


implementation

uses
  UGame,
  UMain;

constructor TEnemyEng.Create;
begin
  ResMan.Load('Media\Enemy1.dds', FEmemyTex[ekTriangle]);
  ResMan.Load('Media\Enemy2.dds', FEmemyTex[ekStupidShip]);
  ResMan.Load('Media\Enemy3.dds', FEmemyTex[ekCube]);
  ResMan.Load('Media\Enemy4.dds', FEmemyTex[ekCruiser]);
  ResMan.Load('Media\Enemy5.dds', FEmemyTex[ekFighter]);
  ResMan.Load('Media\Boss.dds', FEmemyTex[ekBoss]);
end;

procedure TEnemyEng.Restart;
var
  i : Integer;
begin
  for I := 1 to SpawnCount do
    FSpawned[i] := 0;

  for I := 1 to High(Enemies) do
    Enemies[i].Kind := ekNone;
end;

procedure TEnemyEng.Hit(idx: Integer; Weapon: TWeaponType);
begin
  Enemies[idx].Health := Enemies[idx].Health - WeaponParam[Weapon].Power;
  if Enemies[idx].Health <= 0 then
  begin
    Game.AddScore(EnemyParam[Enemies[idx].Kind].Scores, Enemies[idx].Pos);
    if Random < EnemyParam[Enemies[idx].Kind].BonusChance then
      Game.AddBonus(Enemies[idx].Pos);
    Enemies[idx].Dead := True;
  end;
end;

procedure TEnemyEng.Coll(idx: Integer);
begin
  Enemies[idx].Dead := True;
end;

procedure TEnemyEng.OnUpdate(dt : LongInt);
var
  i,j : Integer;
  SpawnNeed : Integer;
  D : TVec2f;
  Rot : Single;
  Win : Boolean;

  procedure AddEnemy(wPos, wDir: TVec2f; wKind: TEnemyKind);
  var
    j : Integer;
  begin
    for j := 1 to High(Enemies) do
    with Enemies[j] do
      if Kind = ekNone then
      begin
        Weapon.SetWeapon(EnemyParam[wKind].WeaponType);
        Kind := wKind;
        Pos  := wPos;
        Dir  := wDir;
        Fade := 1;
        Dead := False;
        Angle := 0;
        Health := EnemyParam[wKind].Life;
        CreateTime := Utils.Time;
        Exit;
      end;
  end;
begin


  for I := 1 to SpawnCount do
  with EnemySpawn[i] do
  begin
    if Time > Game.GameTime then Break;
    SpawnNeed := Trunc( Min((Game.GameTime - Time)/Duration * Count, Count));

    case Spawn of
      stAll:
      begin
        for J := 1 to SpawnNeed - FSpawned[i] do
        begin
          AddEnemy(Vec2f(random*WorldSize, -40), Vec2f(0,1), Kind);
          Inc(FSpawned[i]);
        end;
      end;
      st2Lines:
      begin
         for J := 1 to SpawnNeed - FSpawned[i] do
         begin
          AddEnemy(Vec2f(WorldSize/4, -J*(EnemyParam[Kind].Size +10)), Vec2f(0,1), Kind);
          AddEnemy(Vec2f(WorldSize/4*3, -J*(EnemyParam[Kind].Size +10)), Vec2f(0,1), Kind);
          Inc(FSpawned[i]);
         end;
      end;
      stMidlle:
         for J := 1 to SpawnNeed - FSpawned[i] do
         begin
          AddEnemy(Vec2f(WorldSize/2, -J*(EnemyParam[Kind].Size +10)), Vec2f(0,1), Kind);
          Inc(FSpawned[i]);
         end;
    end;

  end;

  for I := 1 to High(Enemies) do
  with Enemies[i], EnemyParam[Kind] do
    if Kind <> ekNone then
    begin
      case Kind of
        ekTriangle: Angle := Angle + dt * 0.5;
        ekFighter:
        begin
          D := (Vec2f(Screen_Width, Screen_Height-200)*0.5 - Pos);
          Rot:= Dir.Angle(D);
          Dir := Dir.Rotate(Sign(Rot)*Min(abs(Rot),dt/900)).Normal;

          Dir := Dir.Lerp(D.Normal, dt/500*(d.Length/100)).Normal;
          Angle := -Dir.Angle(Vec2f(0,1)) * rad2deg ;
        end;
        ekBoss:
        begin
          if (Pos.y > 150) and (Dir.y = 1) then
          begin
            Dir := Vec2f(1, 0);
            Data1 := Utils.Time;
          end;

          if (Utils.Time-Data1>3000) and (Dir.y = 0) then
          begin
            Dir := Vec2f(Random(2)*2-1, 0)*(2+Random(3));
            Data1 := Utils.Time;
          end;

          if Pos.x < 200 then
            Dir := Vec2f(1, 0);

          if Pos.x > WorldSize -200 then
            Dir := Vec2f(-1, 0);


        end;

      end;

      Weapon.Shoot(Pos, (Game.Player.Pos - Pos).Normal, Dir);
      if Dead then
      begin
        Fade := Fade - 0.004* dt;
        if Fade <=0 then
          Kind := ekNone;
      end;

      Pos := Pos + Dir * Speed * dt;

      if Pos.y > Screen_Height + Size then
        Kind := ekNone;

    end;

    if Game.GameTime > (EnemySpawn[SpawnCount].Time + EnemySpawn[SpawnCount].Duration) then
    begin
      Win := True;
      for I := 1 to High(Enemies) do
        if Enemies[i].Kind <> ekNone then
          Win := False;
      if Win then
        Game.Win;
    end;

end;

procedure TEnemyEng.OnRender;
var
  i : Integer;
begin
  for I := 1 to High(Enemies) do
    with Enemies[i], EnemyParam[Kind] do
      if Kind <> ekNone then
        Render2d.DrawSprite(FEmemyTex[Kind], Pos.x - Game.Camera.X-Size/2, Pos.y-Size/2, Size, Size, Color*Fade, Angle);

        end;

end.

