unit BaseEnemy;

interface   

uses
  _Geometry,
  Frost.Engine,
  Frost.GL,
  _PNG;

type
TBaseEnemy = class(TComponent)    
  private
    class var FMesh: TMesh;        
    class var FTowerMesh: TMesh;
    class var FMaterial: TMaterial;     
    class var FDeathMaterial: TMaterial;
  protected
    FLife: Integer;
    FRenderer: TMeshRenderer;
    FTowerRenderer: TMeshRenderer;
    FActive: Boolean;
    FBounds: TVector3;
    FTower: TGameObject;
    FNeedTowerAngle,      
    FTowerAngle,
    FStartAngle: Single;
    FHitRadiusSQR: Single;   
    FRocketRadiusSQR: Single;
    FBullets: Integer;
    FReloadTimer,
    FReloadTime: Single;
    procedure CreateMesh(Mesh, TowerMesh: TMesh; Material: TMaterial; Bounds: TVector3; Life: Integer);
  public
    procedure OnStart; override;
    procedure OnUpdate(const Delta: Double); override;
    procedure OnDestroy; override;
  end;

implementation

uses
  Bullet,
  Rocket,
  Hero,
  SolidParticle,
  BlowEffect;

{$REGION 'Base enemy'}
procedure TBaseEnemy.CreateMesh(Mesh, TowerMesh: TMesh; Material: TMaterial; Bounds: TVector3; Life: Integer);
begin                                                                
  FTower := TGameObject.Create(GameObject);
  FRenderer := TMeshRenderer.CreateMeshRenderer(Mesh, Material);
  GameObject.AddComponent(FRenderer);
  FTowerRenderer := TMeshRenderer.CreateMeshRenderer(TowerMesh, Material);
  FTower.AddComponent(FTowerRenderer);
  FActive := True;
  FLife := Life;
  FBounds := Bounds;
  FHitRadiusSQR := 1 * 1;
  FRocketRadiusSQR := 1.4 * 1.4;    
  FBullets := 20;
end;

procedure TBaseEnemy.OnStart;
begin            
  if FMesh = nil then
  begin
    FMesh := Resources.LoadMMSMesh('data/models/antiair.mms', 0.14); 
    FTowerMesh := Resources.LoadMMSMesh('data/models/antiair_tower.mms', 0.14);
    FMaterial := TTexturedMaterial.Create(LoadPNGTexture('data/textures/anti_air.png'));
    FDeathMaterial := TColorMaterial.Create(Vector3(0,0,0));
  end;
  CreateMesh(FMesh, FTowerMesh, FMaterial, Vector3(1,1,0.5), 10);
  FStartAngle := Random(360);
  FNeedTowerAngle := FStartAngle;
  GameObject.LocalRotation := Rotate(FStartAngle, Vector3(0,0,1));  
  FReloadTimer := 0;
  FReloadTime := 0.8;
end;

procedure TBaseEnemy.OnUpdate(const Delta: Double);    
var
  i, j: Integer;
  SQRDistance, SideAngle, TopAngle: Single;
  ToHeroVector: TVector3; 
begin
  if (GameObject.Enabled <> FActive) then
  begin
    FActive := GameObject.Enabled;
    if (FLife > 0) then
    begin
      FRenderer.Enable := FActive;
      FTowerRenderer.Enable := FActive;
    end;
  end;

  if (GameObject.Enabled) and (FLife > 0) then
  begin
    for i := 0 to MAX_BULLETS do
    if (Bullets[i].Active) and (Bullets[i].Owner = THero.FInstance.GameObject) then
    begin
      if
        ((Bullets[i].GameObject.Position - GameObject.LocalPosition).SQRMagnitude < FHitRadiusSQR) then
        begin
          Bullets[i].Hide;
          FLife := FLife - 1;
        end;
    end;           
    for i := 0 to MAX_ROCKETS do
    if (Rockets[i].Active) and (Rockets[i].Owner = THero.FInstance.GameObject) then
    begin
      if
        ((Rockets[i].GameObject.Position - GameObject.LocalPosition).SQRMagnitude < FRocketRadiusSQR) then
        begin
          Rockets[i].Hit ;
          FLife := FLife - 10;
        end;
    end;
    if (FLife <= 0) then
    begin
      TBlowEffect.Blow(
          Vector3(GameObject.LocalPosition.X, GameObject.LocalPosition.Y,0),
          0.5 + Random(10) * 0.02);
      FRenderer.Material := FDeathMaterial;
      FTowerRenderer.Enable := false;
    end;
    ToHeroVector := THero.FInstance.GameObject.LocalPosition - GameObject.LocalPosition;
    SQRDistance := ToHeroVector.SQRMagnitude;
    if (SQRDistance < 9 * 9) then
    begin
      FNeedTowerAngle := GetAngle(ToHeroVector);
      FTowerAngle := RotateToAngle(FTowerAngle, FNeedTowerAngle, 5);
      FTower.LocalRotation := Rotate(-FStartAngle - 180 - FTowerAngle, VECTOR3_FORWARD);
      if (FReloadTimer > 0) then
      begin
        FReloadTimer := FReloadTimer - Delta;
      end
      else
      begin
        if (Abs(FTowerAngle - FNeedTowerAngle) < 3) then
        begin
          TopAngle := sqrt(SQRDistance);
          TBullet.Fire(GameObject,
            GameObject.LocalPosition + Vector3(0,0,0.2),
            TVector3(GetVector(FTowerAngle, 4 * Delta)) +
              Vector3(0,0, (HERO_HEIGHT - 0.2) * 4 * Delta / TopAngle),
            Rotate(GetAngle(Vector2(TopAngle, HERO_HEIGHT - 0.2)), Vector3(1,0,0)) * Rotate(FTowerAngle, Vector3(0,0,-1)));
        end;
        FReloadTimer := FReloadTime;
        Dec(FBullets);
        if (FBullets < 0) then
        begin
          FBullets := 20;
          FReloadTimer := FReloadTime * 5;
        end;
      end;
    end;
  end;
end;

procedure TBaseEnemy.OnDestroy;
begin

end;
{$ENDREGION}
end.
