@ -54,6 +54,7 @@ using A=Attribute;
void Monster : : STRATEGY : : STONE_GOLEM ( Monster & m , float fElapsedTime , std : : string strategy ) {
enum PhaseName {
INITIALIZE ,
BEAR_ATTACK ,
SPAWN_PILLAR_PREPARE ,
RESPAWN_PILLAR_PREPARE ,
SPAWN_PILLAR_CAST ,
@ -192,45 +193,43 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
}
} break ;
case STANDARD : {
BEAR ( m , fElapsedTime , " Bear " ) ;
//Extending the bear script's variables to read the state of it...
const bool SlamHasFinished = m . I ( A : : PHASE ) = = 0 ; //The bear script uses the internal phase variable to determine the state of things.
if ( SlamHasFinished ) {
if ( m . F ( A : : HEALTH_PCT_PHASE ) - m . GetHealthRatio ( ) > = ConfigFloat ( " Shockwave.Repeating Threshold " ) / 100.f ) {
m . F ( A : : HEALTH_PCT_PHASE ) - = ConfigFloat ( " Shockwave.Repeating Threshold " ) / 100.f ;
m . F ( A : : CASTING_TIMER ) = ConfigFloat ( " Shockwave.Cast Time " ) ;
m . SIZET ( A : : PREVIOUS_MONSTER_COUNT ) = MONSTER_LIST . size ( ) ;
PrepareSafeAreas ( ) ;
m . phase = SHOCKWAVE ;
break ;
}
if ( m . F ( A : : NEXT_HEALTH_PCT_PILLAR_PHASE ) > = m . GetHealthRatio ( ) ) {
m . F ( A : : NEXT_HEALTH_PCT_PILLAR_PHASE ) - = ConfigFloat ( " Pillar Respawns.Repeating Threshold " ) / 100.f ;
SoundEffect : : StopLoopingSFX ( m . SIZET ( A : : LOOPING_SOUND_ID ) ) ; //If we get here, a sound effect should not be playing...
const bool StoneThrowRollSucceeds = util : : random ( 100.f ) < = ConfigFloat ( " Standard Attack.Stone Throw Chance " ) ;
if ( m . F ( A : : HEALTH_PCT_PHASE ) - m . GetHealthRatio ( ) > = ConfigFloat ( " Shockwave.Repeating Threshold " ) / 100.f ) {
m . F ( A : : HEALTH_PCT_PHASE ) - = ConfigFloat ( " Shockwave.Repeating Threshold " ) / 100.f ;
m . F ( A : : CASTING_TIMER ) = ConfigFloat ( " Shockwave.Cast Time " ) ;
m . SIZET ( A : : PREVIOUS_MONSTER_COUNT ) = MONSTER_LIST . size ( ) ;
m . PerformAnimation ( " CAST " , m . GetFacingDirectionToTarget ( game - > GetPlayer ( ) - > GetPos ( ) ) ) ;
PrepareSafeAreas ( ) ;
m . phase = SHOCKWAVE ;
break ;
}
if ( m . F ( A : : NEXT_HEALTH_PCT_PILLAR_PHASE ) > = m . GetHealthRatio ( ) ) {
m . F ( A : : NEXT_HEALTH_PCT_PILLAR_PHASE ) - = ConfigFloat ( " Pillar Respawns.Repeating Threshold " ) / 100.f ;
m . F ( A : : RESPAWN_RECOVERY_TIME ) = ConfigFloat ( " Pillar Respawns.Cast Delay Time " ) ;
m . I ( A : : RESPAWN_PATTERN_REPEAT_COUNT ) + = ConfigIntArr ( " Pillar Respawns.Respawn Count " , 0 ) ;
m . I ( A : : BAD_PILLAR_SPAWN_COUNT ) + = ConfigIntArr ( " Pillar Respawns.Respawn Count " , 1 ) ;
m . I ( A : : RESPAWN_PHASE ) = RESPAWN_PILLAR_PREPARE ;
}
m . F ( A : : RESPAWN_RECOVERY_TIME ) = ConfigFloat ( " Pillar Respawns.Cast Delay Time " ) ;
m . I ( A : : RESPAWN_PATTERN_REPEAT_COUNT ) + = ConfigIntArr ( " Pillar Respawns.Respawn Count " , 0 ) ;
m . I ( A : : BAD_PILLAR_SPAWN_COUNT ) + = ConfigIntArr ( " Pillar Respawns.Respawn Count " , 1 ) ;
m . I ( A : : RESPAWN_PHASE ) = RESPAWN_PILLAR_PREPARE ;
}
const bool StoneThrowRollSucceeds = util : : random ( 100.f ) < = ConfigFloat ( " Standard Attack.Stone Throw Chance " ) ;
m . I ( A : : ATTACK_COUNT ) = m . I ( A : : BEAR_STOMP_COUNT ) ; //Make sure the slams are now reset if necessary.
if ( StoneThrowRollSucceeds ) { //The intent is one or the other attack is supposed to happen. We can't do the slam and a throw, rerolling repeatedly each tick is unncessary.
m . phase = STONE_THROW_CAST ;
m . V ( A : : LOCKON_POS ) = game - > GetPlayer ( ) - > GetPos ( ) ;
m . PerformAnimation ( " TOSS ROCK CAST " ) ;
m . F ( A : : CASTING_TIMER ) = ConfigFloat ( " Standard Attack.Stone Throw Cast Time " ) ;
game - > AddEffect ( std : : make_unique < SpellCircle > ( m . V ( A : : LOCKON_POS ) , ConfigFloat ( " Standard Attack.Stone Throw Cast Time " ) , " range_indicator.png " , " spell_insignia.png " , m . OnUpperLevel ( ) , vf2d { 1.f , 1.f } * ( ConfigPixels ( " Standard Attack.Stone Radius " ) / 12.f ) * 1.25f , 0.3f , vf2d { } , ConfigPixel ( " Standard Attack.Stone Throw Spell Circle Color " ) , util : : random ( 2 * PI ) , util : : degToRad ( ConfigFloat ( " Standard Attack.Stone Throw Spell Circle Rotation Spd " ) ) , false , vf2d { 1.f , 1.f } * ( ConfigPixels ( " Standard Attack.Stone Radius " ) / 12.f ) * 0.9f , 0.3f , vf2d { } , ConfigPixel ( " Standard Attack.Stone Throw Spell Insignia Color " ) , util : : random ( 2 * PI ) , util : : degToRad ( ConfigFloat ( " Standard Attack.Stone Throw Spell Insignia Rotation Spd " ) ) ) , true ) ;
if ( StoneThrowRollSucceeds ) { //The intent is one or the other attack is supposed to happen. We can't do the slam and a throw, rerolling repeatedly each tick is unncessary.
m . phase = STONE_THROW_CAST ;
m . V ( A : : LOCKON_POS ) = game - > GetPlayer ( ) - > GetPos ( ) ;
m . PerformAnimation ( " TOSS ROCK CAST " ) ;
m . F ( A : : CASTING_TIMER ) = ConfigFloat ( " Standard Attack.Stone Throw Cast Time " ) ;
game - > AddEffect ( std : : make_unique < SpellCircle > ( m . V ( A : : LOCKON_POS ) , ConfigFloat ( " Standard Attack.Stone Throw Cast Time " ) , " range_indicator.png " , " spell_insignia.png " , m . OnUpperLevel ( ) , vf2d { 1.f , 1.f } * ( ConfigPixels ( " Standard Attack.Stone Radius " ) / 12.f ) * 1.25f , 0.3f , vf2d { } , ConfigPixel ( " Standard Attack.Stone Throw Spell Circle Color " ) , util : : random ( 2 * PI ) , util : : degToRad ( ConfigFloat ( " Standard Attack.Stone Throw Spell Circle Rotation Spd " ) ) , false , vf2d { 1.f , 1.f } * ( ConfigPixels ( " Standard Attack.Stone Radius " ) / 12.f ) * 0.9f , 0.3f , vf2d { } , ConfigPixel ( " Standard Attack.Stone Throw Spell Insignia Color " ) , util : : random ( 2 * PI ) , util : : degToRad ( ConfigFloat ( " Standard Attack.Stone Throw Spell Insignia Rotation Spd " ) ) ) , true ) ;
//Use acceleration equation to determine how much time it takes for the stone to land based on gravity.
const float stoneTossTime { ConfigFloat ( " Standard Attack.Stone Throw Time " ) } ;
//Physics!! Kinematic equation from https://openstax.org/books/physics/pages/3-2-representing-acceleration-with-equations-and-graphs a=(2d)/(t^2)
const float acc { ( 2 * - ConfigFloat ( " Standard Attack.Stone Throw Height Offset " ) ) / std : : pow ( stoneTossTime , 2.f ) } ;
//Use acceleration equation to determine how much time it takes for the stone to land based on gravity.
const float stoneTossTime { ConfigFloat ( " Standard Attack.Stone Throw Time " ) } ;
//Physics!! Kinematic equation from https://openstax.org/books/physics/pages/3-2-representing-acceleration-with-equations-and-graphs a=(2d)/(t^2)
const float acc { ( 2 * - ConfigFloat ( " Standard Attack.Stone Throw Height Offset " ) ) / std : : pow ( stoneTossTime , 2.f ) } ;
m . SIZET ( A : : LOOPING_SOUND_ID ) = SoundEffect : : PlayLoopingSFX ( " Rock Toss Cast " , m . GetPos ( ) ) ;
m . SIZET ( A : : LOOPING_SOUND_ID ) = SoundEffect : : PlayLoopingSFX ( " Rock Toss Cast " , m . GetPos ( ) ) ;
CreateBullet ( LargeStone ) ( m . GetPos ( ) + vf2d { 0 , ConfigFloat ( " Standard Attack.Stone Throw Height Offset " ) / 2.f } , ConfigFloat ( " Standard Attack.Stone Throw Time " ) , m . V ( A : : LOCKON_POS ) , m . F ( A : : CASTING_TIMER ) , ConfigPixels ( " Standard Attack.Stone Radius " ) , ConfigFloat ( " Standard Attack.Stone Throw Height Offset " ) , acc , ConfigInt ( " Standard Attack.Stone Damage " ) , ConfigFloat ( " Standard Attack.Stone Throw Knockback Factor " ) , m . OnUpperLevel ( ) , false , INFINITY , false , WHITE , vf2d { 1 , 1 } * m . GetSizeMult ( ) , util : : random ( 2 * PI ) ) EndBullet ;
}
CreateBullet ( LargeStone ) ( m . GetPos ( ) + vf2d { 0 , ConfigFloat ( " Standard Attack.Stone Throw Height Offset " ) / 2.f } , ConfigFloat ( " Standard Attack.Stone Throw Time " ) , m . V ( A : : LOCKON_POS ) , m . F ( A : : CASTING_TIMER ) , ConfigPixels ( " Standard Attack.Stone Radius " ) , ConfigFloat ( " Standard Attack.Stone Throw Height Offset " ) , acc , ConfigInt ( " Standard Attack.Stone Damage " ) , ConfigFloat ( " Standard Attack.Stone Throw Knockback Factor " ) , m . OnUpperLevel ( ) , false , INFINITY , false , WHITE , vf2d { 1 , 1 } * m . GetSizeMult ( ) , util : : random ( 2 * PI ) ) EndBullet ;
} else {
m . phase = BEAR_ATTACK ;
}
} break ;
case STONE_THROW_CAST : {
@ -293,6 +292,18 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
PrepareSafeAreas ( ) ; //Recalculate safe areas if the shockwave attack is going off.
m . phase = SHOCKWAVE ;
} else m . F ( A : : SAFE_AREA_WAIT_TIMER ) - = fElapsedTime ;
} ;
} break ;
case BEAR_ATTACK : {
BEAR ( m , fElapsedTime , " Bear " ) ;
//Extending the bear script's variables to read the state of it...
const bool SlamHasFinished = m . I ( A : : ATTACK_COUNT ) ! = m . I ( A : : BEAR_STOMP_COUNT ) ; //The bear script uses the internal phase variable to determine the state of things.
if ( SlamHasFinished ) {
m . phase = STANDARD ;
m . I ( A : : ATTACK_COUNT ) = m . I ( A : : BEAR_STOMP_COUNT ) ;
} else
if ( m . I ( A : : PHASE ) = = 0 ) {
//Walking towards... If 7 seconds or more occurs here, fallback to a different plan.
}
} break ;
}
}