@ -47,5 +47,76 @@ using A=Attribute;
INCLUDE_game
void Monster : : STRATEGY : : PIRATE_BUCCANEER ( Monster & m , float fElapsedTime , std : : string strategy ) {
# pragma region Phase, Animation, and Helper function setup
enum PhaseName {
INIT ,
MOVE ,
LOCKON ,
WINDUP ,
FIRE_ANIMATION ,
} ;
# pragma endregion
switch ( m . phase ) {
case INIT : {
m . phase = MOVE ;
} break ;
case MOVE : {
m . F ( A : : ATTACK_COOLDOWN ) + = fElapsedTime ;
float distToPlayer = m . GetDistanceFrom ( game - > GetPlayer ( ) - > GetPos ( ) ) ;
const bool outsideMaxShootingRange = distToPlayer > = ConfigPixelsArr ( " Stand Still and Shoot Range " , 1 ) ;
auto PrepareToShoot = [ & ] ( ) {
m . phase = WINDUP ;
m . F ( A : : SHOOT_TIMER ) = ConfigFloat ( " Attack Windup Time " ) ;
m . PerformAnimation ( " SHOOT " , m . GetFacingDirectionToTarget ( game - > GetPlayer ( ) - > GetPos ( ) ) ) ;
} ;
if ( outsideMaxShootingRange ) {
m . target = game - > GetPlayer ( ) - > GetPos ( ) ;
RUN_TOWARDS ( m , fElapsedTime , " Run Towards " ) ;
} else
if ( m . F ( A : : ATTACK_COOLDOWN ) > = ConfigFloat ( " Attack Reload Time " ) ) {
PrepareToShoot ( ) ;
} else
if ( distToPlayer < ConfigPixels ( " Run Away Range " ) ) {
m . target = geom2d : : line < float > ( m . GetPos ( ) , game - > GetPlayer ( ) - > GetPos ( ) ) . upoint ( - 1 ) ;
RUN_TOWARDS ( m , fElapsedTime , " Run Towards " ) ;
} else
if ( m . F ( A : : ATTACK_COOLDOWN ) > = ConfigFloat ( " Attack Reload Time " ) / 2.f ) { //Only the stand still and shoot range remains, which is twice as fast...
PrepareToShoot ( ) ;
}
} break ;
case WINDUP : {
m . F ( A : : SHOOT_TIMER ) - = fElapsedTime ;
if ( m . F ( A : : SHOOT_TIMER ) < = 0 ) {
m . F ( A : : ATTACK_COOLDOWN ) = 0.f ;
CreateBullet ( ChargedArrow ) ( " musket_bullet.png " , " musket_trail.png " , m . GetPos ( ) , util : : pointTo ( m . GetPos ( ) , m . V ( A : : LOCKON_POS ) ) * ConfigFloat ( " Arrow Spd " ) , ConfigFloat ( " Arrow Hitbox Radius " ) , m . GetAttack ( ) , m . OnUpperLevel ( ) ) EndBullet ;
m . PerformAnimation ( " SHOOTING " , m . GetFacingDirectionToTarget ( game - > GetPlayer ( ) - > GetPos ( ) ) ) ;
m . SetStrategyDrawFunction ( [ ] ( AiL * game , Monster & monster , const std : : string & strategy ) { } ) ;
m . phase = FIRE_ANIMATION ;
m . F ( A : : SHOOT_TIMER ) = m . GetCurrentAnimation ( ) . GetTotalAnimationDuration ( ) ;
} else
if ( m . F ( A : : SHOOT_TIMER ) > = ConfigFloat ( " Attack Lockon Time " ) ) {
m . V ( A : : LOCKON_POS ) = game - > GetPlayer ( ) - > GetPos ( ) ;
m . PerformAnimation ( " SHOOT " , m . GetFacingDirectionToTarget ( game - > GetPlayer ( ) - > GetPos ( ) ) ) ;
const float arrowHitboxRadius { ConfigFloat ( " Arrow Hitbox Radius " ) } ;
m . SetStrategyDrawFunction ( [ arrowHitboxRadius ] ( AiL * game , Monster & monster , const std : : string & strategy ) {
vf2d midpoint { geom2d : : line < float > ( monster . GetPos ( ) , monster . V ( A : : LOCKON_POS ) ) . rpoint ( 800.f ) } ;
float shootingAngle { util : : angleTo ( monster . GetPos ( ) , monster . V ( A : : LOCKON_POS ) ) + PI / 2 } ;
vf2d imgSize { arrowHitboxRadius * 2.f , 800.f } ;
game - > view . DrawPartialRotatedDecal ( midpoint , GFX [ " line_indicator.png " ] . Decal ( ) , shootingAngle , GFX [ " line_indicator.png " ] . Sprite ( ) - > Size ( ) / 2 , { } , GFX [ " line_indicator.png " ] . Sprite ( ) - > Size ( ) , imgSize / GFX [ " line_indicator.png " ] . Sprite ( ) - > Size ( ) ) ;
} ) ;
}
} break ;
case FIRE_ANIMATION : {
m . F ( A : : SHOOT_TIMER ) - = fElapsedTime ;
if ( m . F ( A : : SHOOT_TIMER ) < = 0.f ) {
m . PerformAnimation ( " IDLE " , m . GetFacingDirectionToTarget ( game - > GetPlayer ( ) - > GetPos ( ) ) ) ;
m . phase = MOVE ;
}
} break ;
}
}