unit uEnemies;

interface

uses  QuadEngine,
      uSMath,
      uCommonGameTypes;

type
  cEnemy = class
    private
    protected
      rules       : array of rRuleMove;
      currentRule : Word;

      MoveStartTime : Double;
      MoveAllTime   : Double;

      CPos      : rVec2f;
      PrevCPos  : rVec2f;
      NextCPos  : rVec2f;

      APos      : Single;
      PrevAPos  : Single;
      NextAPos  : Single;

      RPos      : Single;
      PrevRPos  : Single;
      NextRPos  : Single;

      Health    : Word;
      _damage   : Word;

      bullet        : rBulletInitParam;
      lastShootTime : Double;
      rdyToShoot    : Boolean;

      stDead  : Boolean;

      scorePrice  : LongInt;
      game        : TObject;
    public
      constructor Create; virtual;
      destructor  Destroy; override;

      procedure Init( param: Pointer ); virtual;
      procedure Draw( layer: Word ); virtual;
      procedure Update( dt, currentTime : Double ); virtual;
      procedure UpdateFrame( dt, currentTime : Double ); virtual;

      function  CollideVsBullet( bullet: pBullet ): Boolean; virtual;
      function  CollideVsCircle( const _circle: rCircle ): Boolean; virtual;
      function  CollideVsRect( const _rect: rRect ): Boolean; virtual;
      procedure GetDamage( dam: Word ); virtual;
      procedure Kill; virtual;
      function  GetPosition(): rVec2f; virtual;

      procedure Shoot; virtual;

      property Dead   : Boolean read stDead;
      property Points : LongInt read scorePrice;
      property Damage : Word read _damage;
      property Life   : Word read Health;end;

  cEnemy_1 = class ( cEnemy )
    private
    protected
      sprite    : IQuadTexture;
      sprite_2  : IQuadTexture;
      frame     : Word;
      lastFUpdt : Double;
      angle     : Single;
    public
      constructor Create; override;
      destructor  Destroy;   override;

      procedure Init( param: Pointer ); override;
      procedure Draw( layer: Word ); override;
      procedure Update( dt, currentTime : Double ); override;
      procedure UpdateFrame( dt, currentTime : Double ); override;

      function  CollideVsBullet( bullet: pBullet ): Boolean; override;
      function  CollideVsCircle( const _circle: rCircle ): Boolean; override;
      function  CollideVsRect( const _rect: rRect ): Boolean; override;

      procedure Shoot; override;
  end;

  cEnemy_2 = class ( cEnemy )
    private
    protected
      sprite    : IQuadTexture;
      angle     : Single;
      frame     : Word;
      lastFUpdt : Double;
    public
      constructor Create; override;
      destructor  Destroy;   override;

      procedure Init( param: Pointer ); override;
      procedure Draw( layer: Word ); override;
      procedure Update( dt, currentTime : Double ); override;
      procedure UpdateFrame( dt, currentTime : Double ); override;

      function  CollideVsBullet( bullet: pBullet ): Boolean; override;
      function  CollideVsCircle( const _circle: rCircle ): Boolean; override;
      function  CollideVsRect( const _rect: rRect ): Boolean; override;

      procedure Shoot; override;
  end;

  cEnemy_3 = class ( cEnemy )
    private
    protected
      sprite    : IQuadTexture;
      sprite_2  : IQuadTexture;
      frame     : Word;
      lastFUpdt : Double;
    public
      constructor Create; override;
      destructor  Destroy;   override;

      procedure Init( param: Pointer ); override;
      procedure Draw( layer: Word ); override;
      procedure Update( dt, currentTime : Double ); override;
      procedure UpdateFrame( dt, currentTime : Double ); override;

      function  CollideVsBullet( bullet: pBullet ): Boolean; override;
      function  CollideVsCircle( const _circle: rCircle ): Boolean; override;
      function  CollideVsRect( const _rect: rRect ): Boolean; override;

      procedure Shoot; override;
  end;

  cBoss_1 = class ( cEnemy )
    private
    protected
      sprite    : IQuadTexture;

      bullet_oth      : rBulletInitParam;
      lastShootTime_2 : Double;
      shoot_oth       : Boolean;

      stDeadMove  : Boolean;
      deadPosS    : rVec2f;
      deadPosF    : rVec2f;
    public
      constructor Create; override;
      destructor  Destroy;   override;

      procedure Init( param: Pointer ); override;
      procedure Draw( layer: Word ); override;
      procedure Update( dt, currentTime : Double ); override;
      procedure UpdateFrame( dt, currentTime : Double ); override;

      function  CollideVsBullet( bullet: pBullet ): Boolean; override;
      function  CollideVsCircle( const _circle: rCircle ): Boolean; override;
      function  CollideVsRect( const _rect: rRect ): Boolean; override;

      procedure GetDamage( dam: Word ); override;
      procedure Shoot; override;
      procedure Kill; override;
  end;

implementation

uses  uUtils,
      uVar,
      uGameTypes;

const
  ENEMY_1_FRAME_UPDT_TIME = 0.08;
  ENEMY_1_MAX_FRAME       = 2;
  ENEMY_1_COL_RADIUS      = 32;

  //ENEMY_2_FRAME_UPDT_TIME = 0.035;
  //ENEMY_2_MAX_FRAME       = 27;
  ENEMY_2_COL_RADIUS      = 26;

  ENEMY_3_FRAME_UPDT_TIME = 0.04;
  ENEMY_3_MAX_FRAME       = 27;
  ENEMY_3_COL_RADIUS      = 28;

  BOSS_1_DEAD_MOVE_TIME   = 2.000;

////////////////////////////////////////////////////////////////////////////////
///  cEnemy  ///////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
{$REGION '  cEnemy  '}
constructor cEnemy.Create;
begin
  SetLength( rules, 0 );
  currentRule := 0;
  CPos  := Vec2f( -500, -500 );
  APos  := 0;
  RPos  := 0;
  scorePrice  := 0;
  stDead := false;
end;

destructor cEnemy.Destroy;
begin
  inherited;
  SetLength( rules, 0 );
end;

procedure cEnemy.Init(param: Pointer);
begin

end;

procedure cEnemy.Draw;
begin

end;

procedure cEnemy.Update(dt: Double; currentTime: Double);
var progress : Double;
begin
  if Length( rules ) <= currentRule then Exit;

  progress := ( currentTime - MoveStartTime ) / rules[ currentRule ].allTime;
  CPos  := rules[ currentRule ].cStartPoint.Lerp( rules[ currentRule ].cEndPoint, progress );
  APos  := rules[ currentRule ].aStartPoint + ( rules[ currentRule ].aEndPoint - rules[ currentRule ].aStartPoint ) * progress;
  RPos  := rules[ currentRule ].rStartPoint + ( rules[ currentRule ].rEndPoint - rules[ currentRule ].rStartPoint ) * progress;

  if rules[ currentRule ].Shoot then begin
    if currentTime - lastShootTime >= rules[ currentRule ].ShootTime then begin
      lastShootTime := currentTime;
      Shoot;
    end;
  end;

  if progress >= 1.0 then begin
    if rules[ currentRule ].nextRule = currentRule then begin
      stDead := True;
      Exit;
    end;
    currentRule := rules[ currentRule ].nextRule;

    CPos := rules[ currentRule ].cStartPoint;
    APos := rules[ currentRule ].aStartPoint;
    RPos := rules[ currentRule ].rStartPoint;

    MoveStartTime := currentTime;
    lastShootTime := currentTime;
  end;
end;

procedure cEnemy.UpdateFrame(dt: Double; currentTime: Double);
begin

end;

function cEnemy.CollideVsBullet(bullet: pBullet): Boolean;
begin
  Result := False;
end;

function cEnemy.CollideVsCircle(const _circle: rCirclef): Boolean;
begin
  Result := False;
end;

function cEnemy.CollideVsRect(const _rect: rRectf): Boolean;
begin
  Result := False;
end;

procedure cEnemy.GetDamage( dam: Word );
begin
  if dam < Health then begin
    Health := Health - dam;
  end else begin
    Health := 0;
    stDead := True;
  end;
end;

procedure cEnemy.Kill;
begin
  stDead := True;
end;

function cEnemy.GetPosition(): rVec2f;
begin
  Result := CPos + Vec2f( Sin( APos * DegToRad ), -Cos( APos * DegToRad ) ) * RPos;
end;

procedure cEnemy.Shoot;
begin

end;
{$ENDREGION}
////////////////////////////////////////////////////////////////////////////////
///  cEnemy_1  /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
{$REGION '  cEnemy_1  '}
constructor cEnemy_1.Create;
begin
  inherited;
  sprite      := Enemy_2;
  sprite_2    := Enemy_2_flm;
  frame       := 0;
  lastFUpdt   := 0;
  scorePrice  := 10;
  angle       := 0;
  Health      := 1;
  _damage     := 5;

  bullet.shape   := sCircle;
  bullet.circle  := Circle( Vec2f( 0, 0 ), 7 );
  bullet.sprite  := Bullet_3;
  bullet.frame   := 0;
  bullet.maxFrame:= 7;
  bullet.frameDT := 0.02;
  bullet.speed   := Vec2f( -350, 0 );
  bullet.damage  := 1;
end;

destructor cEnemy_1.Destroy;
begin
  inherited;
end;

procedure cEnemy_1.Init(param: Pointer);
var num : Word;
    vec : rVec2f;
begin
  game  := pEnemyInitParam( param ).game;
  num   := pEnemyInitParam( param ).moveType;
  case num of
    {$REGION '  1..2  '}
    1: begin
      SetLength( rules, 2 );
      currentRule := 0;

      vec := Vec2f( AppScrW, -AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, 0 ) + vec.Normalized * 100;
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, -100 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.6;
      rules[ 0 ].allTime      := 6;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, -100 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, -150 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 4.5;
      rules[ 1 ].nextRule     := 1;
    end;

    2: begin
      SetLength( rules, 2 );
      currentRule := 0;

      vec := Vec2f( AppScrW, AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) + vec.Normalized * 100;
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, 100 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.6;
      rules[ 0 ].allTime      := 6;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, 100 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH + 150 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 4.5;
      rules[ 1 ].nextRule     := 1;
    end;
    {$ENDREGION}

    {$REGION '  3  '}
    3: begin
      SetLength( rules, 2 );
      currentRule := 0;

      vec := Vec2f( AppScrW, AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, -AppScrH );
      rules[ 0 ].cEndPoint    := Vec2f( 0, -AppScrH );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := False;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 6;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( 0, -AppScrH );
      rules[ 1 ].cEndPoint    := Vec2f( AppScrW, -AppScrH );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 6;
      rules[ 1 ].nextRule     := 0;
    end;
    {$ENDREGION}

    {$REGION '  4..5  '}
    4: begin
      SetLength( rules, 2 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 200, -AppScrH * 0.35 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, -AppScrH * 0.35 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 3.5;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, -AppScrH * 0.35 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -200, -AppScrH * 0.35 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 3.5;
      rules[ 1 ].nextRule     := 1;
    end;

    5: begin
      SetLength( rules, 2 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 200, AppScrH * 0.35 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, AppScrH * 0.35 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 3.5;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, AppScrH * 0.35 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -200, AppScrH * 0.35 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 3.5;
      rules[ 1 ].nextRule     := 1;
    end;
    {$ENDREGION}

    {$REGION '  6..7  '}
    6: begin
      SetLength( rules, 2 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 200, -AppScrH * 0.1 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, -AppScrH * 0.1 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 3.5;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, -AppScrH * 0.1 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -200, -AppScrH * 0.1 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 3.5;
      rules[ 1 ].nextRule     := 1;
    end;

    7: begin
      SetLength( rules, 2 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 200, AppScrH * 0.1 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, AppScrH * 0.1 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 3.5;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 0, AppScrH * 0.1 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -200, AppScrH * 0.1 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 3.5;
      rules[ 1 ].nextRule     := 1;
    end;
    {$ENDREGION}

    {$REGION '  8..9  '}
    8: begin
      SetLength( rules, 2 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, -AppScrH * 0.2 );
      rules[ 0 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.2 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := False;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 10;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.2 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.2 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 2;
      rules[ 1 ].nextRule     := 0;
    end;

    9: begin
      SetLength( rules, 3 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, AppScrH * 0.1 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, -AppScrH * 0.1 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := False;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 1.5;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, -AppScrH * 0.1 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.1 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 10;
      rules[ 1 ].nextRule     := 2;

      rules[ 2 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.1 );
      rules[ 2 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.1 );
      rules[ 2 ].aStartPoint  := 0;
      rules[ 2 ].aEndPoint    := 0;
      rules[ 2 ].rStartPoint  := 0;
      rules[ 2 ].rEndPoint    := 0;
      rules[ 2 ].Shoot        := False;
      rules[ 2 ].ShootTime    := 1.5;
      rules[ 2 ].allTime      := 2 - 1.5;
      rules[ 2 ].nextRule     := 0;
    end;
    {$ENDREGION}

    {$REGION '  10..11  '}
    10: begin
      SetLength( rules, 3 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.2 );
      rules[ 0 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.2 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := False;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 6;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.2 );
      rules[ 1 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, AppScrH * 0.2 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 10;
      rules[ 1 ].nextRule     := 2;

      rules[ 2 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.2 );
      rules[ 2 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.2 );
      rules[ 2 ].aStartPoint  := 0;
      rules[ 2 ].aEndPoint    := 0;
      rules[ 2 ].rStartPoint  := 0;
      rules[ 2 ].rEndPoint    := 0;
      rules[ 2 ].Shoot        := False;
      rules[ 2 ].ShootTime    := 1.5;
      rules[ 2 ].allTime      := 2;
      rules[ 2 ].nextRule     := 1;

      sprite  := Enemy_2_2;
      sprite_2:= Enemy_2_2_flm;
    end;

    11: begin
      SetLength( rules, 3 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.1 );
      rules[ 0 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.1 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := False;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 6 + 1.5;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.1 );
      rules[ 1 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, AppScrH * 0.1 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 10;
      rules[ 1 ].nextRule     := 2;

      rules[ 2 ].cStartPoint  := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, AppScrH * 0.1 );
      rules[ 2 ].cEndPoint    := Vec2f( 0, AppScrH * 0.5 ) + Vec2f( -300, -AppScrH * 0.1 );
      rules[ 2 ].aStartPoint  := 0;
      rules[ 2 ].aEndPoint    := 0;
      rules[ 2 ].rStartPoint  := 0;
      rules[ 2 ].rEndPoint    := 0;
      rules[ 2 ].Shoot        := False;
      rules[ 2 ].ShootTime    := 1.5;
      rules[ 2 ].allTime      := 2;
      rules[ 2 ].nextRule     := 1;

      sprite  := Enemy_2_2;
      sprite_2:= Enemy_2_2_flm;
    end;
    {$ENDREGION}

    {$REGION '  12..13  '}
    12: begin
      SetLength( rules, 1 );
      currentRule := 0;

      vec := Vec2f( AppScrW, -AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 100, 0 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW * 0.2, 0 ) + Vec2f( 0, -200 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.6;
      rules[ 0 ].allTime      := 8;
      rules[ 0 ].nextRule     := 0;
    end;

    13: begin
      SetLength( rules, 1 );
      currentRule := 0;

      vec := Vec2f( AppScrW, -AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 100, 0 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW * 0.2, AppScrH ) + Vec2f( 0, 200 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.6;
      rules[ 0 ].allTime      := 8;
      rules[ 0 ].nextRule     := 0;
    end;
    {$ENDREGION}
  end;

  MoveStartTime := Timer.GetWholeTime;
  lastShootTime := MoveStartTime;
end;

procedure cEnemy_1.Draw( layer: Word );
var DPos : rVec2f;
begin
  case layer of
    1: begin
      DPos := GetPosition;
      sprite.DrawRotAxis( DPos.X, DPos.Y, APos + angle, 1.0,
                          DPos.X + 21, DPos.Y + 31, $FFFFFFFF, frame );
    end;

    2: begin
      DPos := GetPosition;
      sprite_2.DrawRotAxis( DPos.X, DPos.Y, APos + angle, 1.0,
                            DPos.X + 21, DPos.Y + 31, $EFFFFFFF, frame );
    end;
  end;
end;

procedure cEnemy_1.Update(dt: Double; currentTime: Double);
begin
  inherited;
end;

procedure cEnemy_1.UpdateFrame(dt: Double; currentTime: Double);
begin
  if currentTime - lastFUpdt >= ENEMY_1_FRAME_UPDT_TIME then begin
    lastFUpdt := currentTime;
    Inc( Frame );
    if frame > ENEMY_1_MAX_FRAME then begin
      frame := 0;
    end;
  end;
end;

function cEnemy_1.CollideVsBullet(bullet: pBullet): Boolean;
begin
  Result := bullet.CollideWithCircle( Circle( GetPosition, ENEMY_1_COL_RADIUS ) );
end;

function cEnemy_1.CollideVsCircle(const _circle: rCirclef): Boolean;
begin
  Result  := collideCircleVsCircle( Circle( GetPosition, ENEMY_1_COL_RADIUS ), _circle );
end;

function cEnemy_1.CollideVsRect(const _rect: rRectf): Boolean;
begin
  Result  := collideCircleVsRect( Circle( GetPosition, ENEMY_1_COL_RADIUS ), _rect );
end;

procedure cEnemy_1.Shoot;
var BPos: rVec2f;
begin
  BPos  := GetPosition - Vec2f( 16, -6 );
  (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );
end;
{$ENDREGION}
////////////////////////////////////////////////////////////////////////////////
///  cEnemy_2  /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
{$REGION '  cEnemy_2  '}
constructor cEnemy_2.Create;
begin
  inherited;
  sprite      := Enemy_1;
  frame       := 1;
  lastFUpdt   := 0;
  angle       := 0;
  scorePrice  := 75;
  Health      := 5;
  _damage     := 10;

  bullet.shape   := sCircle;
  bullet.circle  := Circle( Vec2f( 0, 0 ), 7 );
  bullet.sprite  := Bullet_3;
  bullet.frame   := 0;
  bullet.maxFrame:= 7;
  bullet.frameDT := 0.02;
  bullet.speed   := Vec2f( -350, 0 );
  bullet.damage  := 2;
end;

destructor cEnemy_2.Destroy;
begin
  inherited;
end;

procedure cEnemy_2.Init(param: Pointer);
var num : Word;
    vec : rVec2f;
begin
  game  := pEnemyInitParam( param ).game;
  num   := pEnemyInitParam( param ).moveType;
  case num of
    {$REGION ' 1..2 '}
    1: begin
      SetLength( rules, 3 );
      currentRule := 0;
      angle := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 200, 240 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, 240 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 150;
      rules[ 0 ].rEndPoint    := 150;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.5;
      rules[ 0 ].allTime      := 3;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, 240 );
      rules[ 1 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, 240 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := -90;
      rules[ 1 ].rStartPoint  := 150;
      rules[ 1 ].rEndPoint    := 150;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 0.5;
      rules[ 1 ].allTime      := 1.5;
      rules[ 1 ].nextRule     := 2;

      rules[ 2 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, 240 );
      rules[ 2 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, AppScrH * 0.5 + 200 );
      rules[ 2 ].aStartPoint  := -90;
      rules[ 2 ].aEndPoint    := -90;
      rules[ 2 ].rStartPoint  := 150;
      rules[ 2 ].rEndPoint    := 150;
      rules[ 2 ].Shoot        := False;
      rules[ 2 ].ShootTime    := 0.5;
      rules[ 2 ].allTime      := 1.7;
      rules[ 2 ].nextRule     := 2;
    end;

    2: begin
      SetLength( rules, 3 );
      currentRule := 0;
      angle := -180;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 200, -240 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, -240 );
      rules[ 0 ].aStartPoint  := -180;
      rules[ 0 ].aEndPoint    := -180;
      rules[ 0 ].rStartPoint  := 150;
      rules[ 0 ].rEndPoint    := 150;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.5;
      rules[ 0 ].allTime      := 3;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, -240 );
      rules[ 1 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, -240 );
      rules[ 1 ].aStartPoint  := -180;
      rules[ 1 ].aEndPoint    := -90;
      rules[ 1 ].rStartPoint  := 150;
      rules[ 1 ].rEndPoint    := 150;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 1.5;
      rules[ 1 ].nextRule     := 2;

      rules[ 2 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( 50, -240 );
      rules[ 2 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 - Vec2f( -50, AppScrH * 0.5 + 200 );
      rules[ 2 ].aStartPoint  := -90;
      rules[ 2 ].aEndPoint    := -90;
      rules[ 2 ].rStartPoint  := 150;
      rules[ 2 ].rEndPoint    := 150;
      rules[ 2 ].Shoot        := False;
      rules[ 2 ].ShootTime    := 1.5;
      rules[ 2 ].allTime      := 1.7;
      rules[ 2 ].nextRule     := 2;
    end;
    {$ENDREGION}

    {$REGION ' 3..4 '}
    3: begin
      SetLength( rules, 1 );
      currentRule := 0;
      angle := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 100, 0 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW * 0.1, 0 ) - Vec2f( 0, 130 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.7;
      rules[ 0 ].allTime      := 5;
      rules[ 0 ].nextRule     := 0;
    end;

    4: begin
      SetLength( rules, 1 );
      currentRule := 0;
      angle := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 100, 0 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW * 0.1, AppScrH ) + Vec2f( 0, 130 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.7;
      rules[ 0 ].allTime      := 5;
      rules[ 0 ].nextRule     := 0;
    end;
    {$ENDREGION}
  end;

  MoveStartTime := Timer.GetWholeTime;
  lastShootTime := MoveStartTime;
end;

procedure cEnemy_2.Draw( layer: Word );
var DPos : rVec2f;
begin
  case layer of
    1: begin
      DPos := GetPosition;
      sprite.DrawRotAxis( DPos.X, DPos.Y, APos - angle, 1.0,
                          DPos.X + 76.5, DPos.Y + 63.5, $FFFFFFFF, frame );
    end;
  end;
end;

procedure cEnemy_2.Update(dt: Double; currentTime: Double);
begin
  inherited;
end;

procedure cEnemy_2.UpdateFrame(dt: Double; currentTime: Double);
begin

end;

function cEnemy_2.CollideVsBullet(bullet: pBullet): Boolean;
begin
  Result := bullet.CollideWithCircle( Circle( GetPosition, ENEMY_2_COL_RADIUS) );
end;

function cEnemy_2.CollideVsCircle(const _circle: rCirclef): Boolean;
begin
  Result  := collideCircleVsCircle( Circle( GetPosition, ENEMY_2_COL_RADIUS ), _circle );
end;

function cEnemy_2.CollideVsRect(const _rect: rRectf): Boolean;
var Pos : rVec2f;
begin
  Result  := collideCircleVsRect( Circle( GetPosition, ENEMY_2_COL_RADIUS ), _rect );
end;

procedure cEnemy_2.Shoot;
var Pos : rVec2f;
    BPos: rVec2f;
begin
  Pos   := CPos + Vec2f( Sin( APos * DegToRad ), -Cos( APos * DegToRad ) ) * RPos;
  BPos  := Vec2f( 6.5, 23.5 );
  BPos  := Pos - BPos;
  (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );
  BPos  := Vec2f( 6.5, -24.5 );
  BPos  := Pos - BPos;
  (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );
end;
{$ENDREGION}
////////////////////////////////////////////////////////////////////////////////
///  cEnemy_3  /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
{$REGION '  cEnemy_3 '}
constructor cEnemy_3.Create;
begin
  inherited;
  sprite      := Enemy_3;
  sprite_2    := Enemy_3_flm;
  frame       := 0;
  lastFUpdt   := 0;
  scorePrice  := 25;
  Health      := 2;
  _damage     := 10;

  bullet.shape   := sCircle;
  bullet.circle  := Circle( Vec2f( 0, 0 ), 7 );
  bullet.sprite  := Bullet_2;
  bullet.frame   := 0;
  bullet.maxFrame:= 7;
  bullet.frameDT := 0.02;
  bullet.speed   := Vec2f( -350, 0 );
  bullet.damage  := 2;
end;

destructor cEnemy_3.Destroy;
begin
  inherited;
end;

procedure cEnemy_3.Init(param: Pointer);
var num : Word;
    vec : rVec2f;
begin
  game  := pEnemyInitParam( param ).game;
  num   := pEnemyInitParam( param ).moveType;
  case num of
    {$REGION '  1..2  '}
    1: begin
      SetLength( rules, 2 );
      currentRule := 0;

      vec := Vec2f( AppScrW, -AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, 0 ) + vec.Normalized * 100;
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, -100 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 0.8;
      rules[ 0 ].allTime      := 3;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, -100 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, -350 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 3;
      rules[ 1 ].nextRule     := 1;
    end;

    2: begin
      SetLength( rules, 2 );
      currentRule := 0;

      vec := Vec2f( AppScrW, AppScrH );
      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) + vec.Normalized * 100;
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, 100 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := True;
      rules[ 0 ].ShootTime    := 1.5;
      rules[ 0 ].allTime      := 3;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH ) * 0.5 + Vec2f( -100, 100 );
      rules[ 1 ].cEndPoint    := Vec2f( 0, AppScrH + 350 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := False;
      rules[ 1 ].ShootTime    := 1.5;
      rules[ 1 ].allTime      := 3;
      rules[ 1 ].nextRule     := 1;
    end;
    {$ENDREGION}
  end;

  MoveStartTime := Timer.GetWholeTime;
  lastShootTime := MoveStartTime;
end;

procedure cEnemy_3.Draw( layer: Word );
var DPos : rVec2f;
begin
  case layer of
    1: begin
      DPos := GetPosition;
      sprite.DrawRotAxis( DPos.X, DPos.Y, APos, 1.0,
                          DPos.X + 25, DPos.Y + 20, $FFFFFFFF, frame );
    end;

    2: begin
      DPos := GetPosition;
      sprite_2.DrawRotAxis( DPos.X, DPos.Y, APos, 1.0,
                            DPos.X + 25, DPos.Y + 20, $EFFFFFFF, frame );
    end;
  end;
end;

procedure cEnemy_3.Update(dt: Double; currentTime: Double);
begin
  inherited;
end;

procedure cEnemy_3.UpdateFrame(dt: Double; currentTime: Double);
begin
  if currentTime - lastFUpdt >= ENEMY_3_FRAME_UPDT_TIME then begin
    lastFUpdt := currentTime;
    Inc( Frame );
    if frame > ENEMY_3_MAX_FRAME then begin
      frame := 8;
    end;
  end;
end;

function cEnemy_3.CollideVsBullet(bullet: pBullet): Boolean;
begin
  Result := bullet.CollideWithCircle( Circle( GetPosition, ENEMY_3_COL_RADIUS ) );
end;

function cEnemy_3.CollideVsCircle(const _circle: rCirclef): Boolean;
begin
  Result := collideCircleVsCircle( Circle( GetPosition, ENEMY_3_COL_RADIUS ), _circle );
end;

function cEnemy_3.CollideVsRect(const _rect: rRectf): Boolean;
begin
  Result := collideCircleVsRect( Circle( GetPosition, ENEMY_3_COL_RADIUS ), _rect );
end;

procedure cEnemy_3.Shoot;
var Pos : rVec2f;
    BPos: rVec2f;
begin
  Pos   := GetPosition;
  BPos  := Vec2f( 9, -5 );
  BPos  := Pos - BPos;
  Pos   := (game as cGame).GetPlayerPosition - BPos;
  bullet.speed := Pos.Normalized * 350;
  (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );
end;
{$ENDREGION}
////////////////////////////////////////////////////////////////////////////////
///  cBoss_1  //////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
{$REGION '  cBoss_1 '}
constructor cBoss_1.Create;
begin
  inherited;
  sprite      := Enemy_6;
  scorePrice  := 750;
  Health      := 100;
  _damage     := 10;

  lastShootTime_2 := 0;
  shoot_oth       := False;

  bullet.shape   := sCircle;
  bullet.circle  := Circle( Vec2f( 0, 0 ), 7 );
  bullet.sprite  := Bullet_2;
  bullet.frame   := 0;
  bullet.maxFrame:= 7;
  bullet.frameDT := 0.02;
  bullet.speed   := Vec2f( -350, 0 );
  bullet.damage  := 6;

  bullet_oth.shape   := sCircle;
  bullet_oth.circle  := Circle( Vec2f( 0, 0 ), 7 );
  bullet_oth.sprite  := Bullet_1;
  bullet_oth.frame   := 0;
  bullet_oth.maxFrame:= 7;
  bullet_oth.frameDT := 0.02;
  bullet_oth.speed   := Vec2f( -350, 0 );
  bullet_oth.damage  := 12;
end;

destructor cBoss_1.Destroy;
begin
  inherited;
end;

procedure cBoss_1.Init(param: Pointer);
var num : Word;
    vec : rVec2f;
begin
  game  := pEnemyInitParam( param ).game;
  num   := pEnemyInitParam( param ).moveType;
  case num of
    {$REGION '  1  '}
    1: begin
      SetLength( rules, 9 );
      currentRule := 0;

      rules[ 0 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, 0 );
      rules[ 0 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, 0 );
      rules[ 0 ].aStartPoint  := 0;
      rules[ 0 ].aEndPoint    := 0;
      rules[ 0 ].rStartPoint  := 0;
      rules[ 0 ].rEndPoint    := 0;
      rules[ 0 ].Shoot        := False;
      rules[ 0 ].ShootTime    := 0.8;
      rules[ 0 ].allTime      := 4;
      rules[ 0 ].nextRule     := 1;

      rules[ 1 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, 0 );
      rules[ 1 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, AppScrH * 0.4 );
      rules[ 1 ].aStartPoint  := 0;
      rules[ 1 ].aEndPoint    := 0;
      rules[ 1 ].rStartPoint  := 0;
      rules[ 1 ].rEndPoint    := 0;
      rules[ 1 ].Shoot        := True;
      rules[ 1 ].ShootTime    := 1.4;
      rules[ 1 ].allTime      := 4;
      rules[ 1 ].nextRule     := 2;

      rules[ 2 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, AppScrH * 0.4 );
      rules[ 2 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, -AppScrH * 0.4 );
      rules[ 2 ].aStartPoint  := 0;
      rules[ 2 ].aEndPoint    := 0;
      rules[ 2 ].rStartPoint  := 0;
      rules[ 2 ].rEndPoint    := 0;
      rules[ 2 ].Shoot        := True;
      rules[ 2 ].ShootTime    := 1.4;
      rules[ 2 ].allTime      := 8;
      rules[ 2 ].nextRule     := 3;

      rules[ 3 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, -AppScrH * 0.4 );
      rules[ 3 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, AppScrH * 0.4 );
      rules[ 3 ].aStartPoint  := 0;
      rules[ 3 ].aEndPoint    := 0;
      rules[ 3 ].rStartPoint  := 0;
      rules[ 3 ].rEndPoint    := 0;
      rules[ 3 ].Shoot        := True;
      rules[ 3 ].ShootTime    := 1.4;
      rules[ 3 ].allTime      := 8;
      rules[ 3 ].nextRule     := 4;

      rules[ 4 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, AppScrH * 0.4 );
      rules[ 4 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, -AppScrH * 0.4 );
      rules[ 4 ].aStartPoint  := 0;
      rules[ 4 ].aEndPoint    := 0;
      rules[ 4 ].rStartPoint  := 0;
      rules[ 4 ].rEndPoint    := 0;
      rules[ 4 ].Shoot        := True;
      rules[ 4 ].ShootTime    := 1.4;
      rules[ 4 ].allTime      := 8;
      rules[ 4 ].nextRule     := 5;

      rules[ 5 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, -AppScrH * 0.4 );
      rules[ 5 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, AppScrH * 0.4 );
      rules[ 5 ].aStartPoint  := 0;
      rules[ 5 ].aEndPoint    := 0;
      rules[ 5 ].rStartPoint  := 0;
      rules[ 5 ].rEndPoint    := 0;
      rules[ 5 ].Shoot        := True;
      rules[ 5 ].ShootTime    := 1.4;
      rules[ 5 ].allTime      := 8;
      rules[ 5 ].nextRule     := 6;

      rules[ 6 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, AppScrH * 0.4 );
      rules[ 6 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, -AppScrH * 0.4 );
      rules[ 6 ].aStartPoint  := 0;
      rules[ 6 ].aEndPoint    := 0;
      rules[ 6 ].rStartPoint  := 0;
      rules[ 6 ].rEndPoint    := 0;
      rules[ 6 ].Shoot        := True;
      rules[ 6 ].ShootTime    := 1.4;
      rules[ 6 ].allTime      := 8;
      rules[ 6 ].nextRule     := 7;

      rules[ 7 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, -AppScrH * 0.4 );
      rules[ 7 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, 0 );
      rules[ 7 ].aStartPoint  := 0;
      rules[ 7 ].aEndPoint    := 0;
      rules[ 7 ].rStartPoint  := 0;
      rules[ 7 ].rEndPoint    := 0;
      rules[ 7 ].Shoot        := True;
      rules[ 7 ].ShootTime    := 1.4;
      rules[ 7 ].allTime      := 4;
      rules[ 7 ].nextRule     := 8;

      rules[ 8 ].cStartPoint  := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( -55, 0 );
      rules[ 8 ].cEndPoint    := Vec2f( AppScrW, AppScrH * 0.5 ) + Vec2f( 300, 0 );
      rules[ 8 ].aStartPoint  := 0;
      rules[ 8 ].aEndPoint    := 0;
      rules[ 8 ].rStartPoint  := 0;
      rules[ 8 ].rEndPoint    := 0;
      rules[ 8 ].Shoot        := False;
      rules[ 8 ].ShootTime    := 0.8;
      rules[ 8 ].allTime      := 3;
      rules[ 8 ].nextRule     := 8;
    end;
    {$ENDREGION}
  end;

  MoveStartTime := Timer.GetWholeTime;
  lastShootTime := MoveStartTime;
end;

procedure cBoss_1.Draw( layer: Word );
var DPos : rVec2f;
begin
  case layer of
    1: begin
      DPos := GetPosition;
      sprite.DrawRot( DPos.X, DPos.Y, APos, 1.0, $FFFFFFFF );
    end;
  end;
end;

procedure cBoss_1.Update(dt: Double; currentTime: Double);
var progress : Double;
begin
  if stDeadMove then begin
    CPos := deadPosS.Lerp( deadPosF, ( currentTime - MoveStartTime ) / BOSS_1_DEAD_MOVE_TIME );
    if currentTime - MoveStartTime >= BOSS_1_DEAD_MOVE_TIME then begin
      stDead := True;
    end;
    Exit;
  end;

  if Length( rules ) <= currentRule then Exit;

  progress := ( currentTime - MoveStartTime ) / rules[ currentRule ].allTime;
  CPos  := rules[ currentRule ].cStartPoint.Lerp( rules[ currentRule ].cEndPoint, progress );
  APos  := rules[ currentRule ].aStartPoint + ( rules[ currentRule ].aEndPoint - rules[ currentRule ].aStartPoint ) * progress;
  RPos  := rules[ currentRule ].rStartPoint + ( rules[ currentRule ].rEndPoint - rules[ currentRule ].rStartPoint ) * progress;

  if rules[ currentRule ].Shoot then begin
    if currentTime - lastShootTime >= rules[ currentRule ].ShootTime then begin
      lastShootTime := currentTime;
      Shoot;
    end;
  end;

  if progress >= 1.0 then begin
    if rules[ currentRule ].nextRule = currentRule then begin
      stDead := True;
      Exit;
    end;
    currentRule := rules[ currentRule ].nextRule;

    CPos := rules[ currentRule ].cStartPoint;
    APos := rules[ currentRule ].aStartPoint;
    RPos := rules[ currentRule ].rStartPoint;

    MoveStartTime := currentTime;
    lastShootTime := currentTime;
  end;

  if rules[ currentRule ].Shoot then begin
    if currentTime - lastShootTime_2 >= 2 * rules[ currentRule ].ShootTime then begin
      shoot_oth       := True;
      lastShootTime_2 := currentTime;
      Shoot;
    end;
  end;
end;

procedure cBoss_1.UpdateFrame(dt: Double; currentTime: Double);
begin

end;

function cBoss_1.CollideVsBullet(bullet: pBullet): Boolean;
var Pos   : rVec2f;
    A, B  : rVec2f;
begin
  Pos := GetPosition;
  A := Pos - Vec2f( 98, 14.5 );
  B := A + Vec2f( 195, 30 );
  Result := bullet.CollideWithRect( Rect( A, B ) );

  A := Pos - Vec2f( 82, 43.5 );
  B := A + Vec2f( 179, 87 );
  Result := Result or bullet.CollideWithRect( Rect( A, B ) );

  A := Pos - Vec2f( 12, 70.5 );
  B := A + Vec2f( 99, 141 );
  Result := Result or bullet.CollideWithRect( Rect( A, B ) );
end;

function cBoss_1.CollideVsCircle(const _circle: rCirclef): Boolean;
var Pos   : rVec2f;
    A, B  : rVec2f;
begin
  Pos := GetPosition;
  A := Pos - Vec2f( 98, 14.5 );
  B := A + Vec2f( 195, 30 );
  Result := collideCircleVsRect( _circle, Rect( A, B ) );

  A := Pos - Vec2f( 82, 43.5 );
  B := A + Vec2f( 179, 87 );
  Result := Result or collideCircleVsRect( _circle, Rect( A, B ) );

  A := Pos - Vec2f( 12, 70.5 );
  B := A + Vec2f( 99, 141 );
  Result := Result or collideCircleVsRect( _circle, Rect( A, B ) );
end;

function cBoss_1.CollideVsRect(const _rect: rRectf): Boolean;
var Pos   : rVec2f;
    A, B  : rVec2f;
begin
  Pos := GetPosition;
  A := Pos - Vec2f( 98, 14.5 );
  B := A + Vec2f( 195, 30 );
  Result := collideRectVsRect( _rect, Rect( A, B ) );

  A := Pos - Vec2f( 82, 43.5 );
  B := A + Vec2f( 179, 87 );
  Result := Result or collideRectVsRect( _rect, Rect( A, B ) );

  A := Pos - Vec2f( 12, 70.5 );
  B := A + Vec2f( 99, 141 );
  Result := Result or collideRectVsRect( _rect, Rect( A, B ) );
end;

procedure cBoss_1.Shoot;
var Pos : rVec2f;
    BPos: rVec2f;
begin
  if shoot_oth then begin
    Pos   := GetPosition;
    BPos  := Vec2f( -8, 67.5 );
    BPos  := Pos - BPos;
    Pos   := (game as cGame).GetPlayerPosition - BPos;
    bullet.speed := Pos.Normalized * 400;
    (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );

    Pos   := GetPosition;
    BPos  := Vec2f( -8, -68.5 );
    BPos  := Pos - BPos;
    Pos   := (game as cGame).GetPlayerPosition - BPos;
    bullet.speed := Pos.Normalized * 400;
    (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );

    shoot_oth := False;
  end else begin
    Pos   := GetPosition;
    BPos  := Vec2f( 83, 35.5 );
    BPos  := Pos - BPos;
    bullet.speed := Vec2f( -400, 0 );
    (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );
    BPos  := Vec2f( 83, -34.5 );
    BPos  := Pos - BPos;
    (game as cGame).AddBullet( @bullet, BPos, True, Timer.GetWholeTime );
  end;
end;

procedure cBoss_1.GetDamage(dam: Word);
var param : rExplosionInitParam;
begin
  if stDeadMove then Exit;
  if dam < Health then begin
    Health := Health - dam;
  end else begin
    Health := 0;
    stDeadMove := True;
    deadPosS := GetPosition;
    deadPosF := deadPosS + Vec2f( 400, 0 );
    MoveStartTime   := Timer.GetWholeTime;
    param.sprite    := Explosion_1;
    param.frame     := 1;
    param.maxFrame  := 21;
    param.frameDT   := 0.05;
    param.speed     := Vec2f( 60, 0 );
    (game as cGame).AddExplosion( @param, GetPosition + Vec2f( -20, -50 ), Timer.GetWholeTime );
  end;
end;

procedure cBoss_1.Kill;
begin
  stDeadMove := True;
  deadPosS := GetPosition;
  deadPosF := deadPosS + Vec2f( 400, 0 );
  MoveStartTime   := Timer.GetWholeTime;
end;
{$ENDREGION}
////////////////////////////////////////////////////////////////////////////////
end.
