Added final phase behaviors and actions to Pirate Captain Boss. Release Build 12251.
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m43s
All checks were successful
Emscripten Build / Build_and_Deploy_Web_Build (push) Successful in 6m43s
This commit is contained in:
parent
e780d2b48e
commit
f5c80b20d5
@ -56,6 +56,7 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
GHOSTSABER_SLASH=999,
|
||||
TOSS_COIN,
|
||||
HIDING,
|
||||
FINAL, //The final phase of the fight.
|
||||
};
|
||||
|
||||
enum CannonShotType{
|
||||
@ -248,16 +249,21 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
m.SetPos(m.V(A::HIDING_POS));
|
||||
m.SetVelocity({});
|
||||
m.arrowIndicator=false; //While the boss is hiding, the indicator will not show up.
|
||||
m.SetStrategyOnHitFunction([&m,&OnLastCursePhase](const HurtDamageInfo damageData,Monster&monster,const StrategyName&strategyName)->void{
|
||||
m.SetPhase(strategyName,NORMAL);
|
||||
m.arrowIndicator=true;
|
||||
m.SetStrategyOnHitFunction({});
|
||||
m.SetStrategyOnHitFunction([&OnLastCursePhase,&m,&strategy](const HurtDamageInfo damageData,Monster&monster,const StrategyName&strategyName)->void{
|
||||
monster.SetPhase(strategyName,OnLastCursePhase?FINAL:NORMAL);
|
||||
monster.arrowIndicator=true;
|
||||
monster.SetStrategyOnHitFunction({});
|
||||
if(OnLastCursePhase){
|
||||
const std::string_view PIRATES_TREASURE{"Pirate's Treasure"};
|
||||
for(std::shared_ptr<Monster>&m:MONSTER_LIST
|
||||
|std::views::filter([&PIRATES_TREASURE](std::shared_ptr<Monster>&m){return m->GetStrategyName()==PIRATES_TREASURE;})){
|
||||
m->SetPhase("Pirate's Treasure",1); //HARDCODED to the LOCKED phase for the Pirate's Treasure
|
||||
}
|
||||
for(int i:std::ranges::iota_view(0,ConfigInt("Final Ghost Saber Count"))){
|
||||
const float playerToMonsterAngle{util::pointTo(game->GetPlayer()->GetPos(),m.GetPos()).polar().y};
|
||||
const int rotationMult=((i%2==0)?1:-1);
|
||||
CreateBullet(GhostSaber)(m.GetPos(),m.GetWeakPointer(),ConfigFloat("Ghost Saber Lifetime"),ConfigFloat("Ghost Saber Distance")+i*ConfigFloat("Final Ghost Saber Separation Amount"),ConfigFloat("Ghost Saber Knockback Amt"),playerToMonsterAngle,ConfigFloat("Ghost Saber Radius"),0.f,ConfigInt("Ghost Saber Damage"),m.OnUpperLevel(),util::degToRad(ConfigFloat("Ghost Saber Rotation Spd")*rotationMult))EndBullet;
|
||||
}
|
||||
}
|
||||
});
|
||||
SETPHASE(HIDING);
|
||||
@ -306,5 +312,51 @@ void Monster::STRATEGY::GHOST_OF_PIRATE_CAPTAIN(Monster&m,float fElapsedTime,std
|
||||
m.F(A::SHRAPNEL_CANNON_TIMER)=0.f;
|
||||
}
|
||||
}break;
|
||||
case FINAL:{
|
||||
RUN_TOWARDS(m,fElapsedTime,"Run Towards");
|
||||
m.target=ConfigVec("Final Standing Spot");
|
||||
m.PerformAnimation("SLASH",Direction::SOUTH);
|
||||
m.F(A::CANNON_TIMER)+=fElapsedTime;
|
||||
if(m.F(A::CANNON_TIMER)>=ConfigFloat("Final Cannon Timer")){
|
||||
switch(m.I(A::CANNON_SHOT_TYPE)){
|
||||
case BOMBARDMENT:{
|
||||
const float randomAng{util::random_range(0,2*PI)};
|
||||
const float range{util::random_range(0,ConfigPixels("Bombardment Max Distance"))};
|
||||
const vf2d targetPos{game->GetPlayer()->GetPos()+vf2d{range,randomAng}.cart()};
|
||||
CreateBullet(FallingBullet)("cannonball.png",targetPos,ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
||||
}break;
|
||||
case PRECISE_BOMBARDMENT:{
|
||||
const float randomAng{util::random_range(0,2*PI)};
|
||||
const float range{util::random_range(0,ConfigPixels("Precise Bombardment Max Distance"))};
|
||||
const vf2d targetPos{game->GetPlayer()->GetPos()+vf2d{range,randomAng}.cart()};
|
||||
CreateBullet(FallingBullet)("cannonball.png",targetPos,ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
||||
}break;
|
||||
case LINE:{
|
||||
//Draw a line from one side of the screen to the other, drawing through the middle.
|
||||
if(m.I(A::CANNON_SHOT_COUNT)==0)m.F(A::LINE_SHOT_ANG)=util::random_range(0,2*PI);
|
||||
const vf2d targetPos{geom2d::line{game->GetPlayer()->GetPos()+vf2d{float(game->ScreenHeight()),m.F(A::LINE_SHOT_ANG)}.cart(),game->GetPlayer()->GetPos()+vf2d{float(game->ScreenHeight()),m.F(A::LINE_SHOT_ANG)+PI}.cart()}.upoint(float(m.I(A::CANNON_SHOT_COUNT))/TOTAL_CANNON_SHOTS)};
|
||||
CreateBullet(FallingBullet)("cannonball.png",targetPos,ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
||||
}break;
|
||||
case SHARPSHOOTER:{
|
||||
if(m.I(A::CANNON_SHOT_COUNT)%2==0)CreateBullet(FallingBullet)("cannonball.png",game->GetPlayer()->GetPos(),ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
||||
}break;
|
||||
case PREDICTION:{
|
||||
LOG(std::format("Previous Pos: {} Current: {}",game->GetPlayer()->GetPreviousPos().str(),game->GetPlayer()->GetPos().str()));
|
||||
const float angle{util::angleTo(game->GetPlayer()->GetPreviousPos(),game->GetPlayer()->GetPos())};
|
||||
const float range{util::random_range(0,100.f*game->GetPlayer()->GetMoveSpdMult())*ConfigFloat("Cannon Shot Impact Time")};
|
||||
LOG(std::format("Range/Angle: {}",vf2d{range,angle}.str()));
|
||||
const vf2d targetPos{game->GetPlayer()->GetPos()+vf2d{range,angle}.cart()};
|
||||
CreateBullet(FallingBullet)("cannonball.png",targetPos,ConfigVec("Cannon Vel"),ConfigFloatArr("Cannon Vel",2),ConfigFloat("Indicator Time"),ConfigPixels("Cannon Radius"),ConfigInt("Cannon Damage"),m.OnUpperLevel(),false,ConfigFloat("Cannon Knockback Amt"),ConfigFloat("Cannon Shot Impact Time"),false,ConfigPixel("Cannon Spell Circle Color"),vf2d{ConfigFloat("Cannon Radius")/100.f*1.75f,ConfigFloat("Cannon Radius")/100.f*1.75f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Circle Rotation Spd")),ConfigPixel("Cannon Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Cannon Spell Insignia Rotation Spd")))EndBullet;
|
||||
}break;
|
||||
}
|
||||
AdvanceCannonPhase();
|
||||
m.I(A::CANNON_SHOT_COUNT)++;
|
||||
}
|
||||
if(m.F(A::SHRAPNEL_CANNON_TIMER)>=ConfigFloat("Final Cannon Timer")){
|
||||
m.I(A::SHRAPNEL_SHOT_COUNT)=ConfigInt("Shrapnel Shot Bullet Count");
|
||||
m.F(A::SHRAPNEL_SHOT_FALL_TIMER)=ConfigFloat("Shrapnel Shot Bullet Separation");
|
||||
m.F(A::SHRAPNEL_CANNON_TIMER)=0.f+util::random(0.5f); // A little randomness to offset the two timers if they happen to occur at once.
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ All rights reserved.
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_PATCH 0
|
||||
#define VERSION_BUILD 12250
|
||||
#define VERSION_BUILD 12251
|
||||
|
||||
#define stringify(a) stringify_(a)
|
||||
#define stringify_(a) #a
|
||||
|
@ -1360,6 +1360,15 @@ MonsterStrategy
|
||||
Coin Toss Rise Amount = 72px
|
||||
|
||||
Shrapnel Hiding Shot Delay = 5.0s
|
||||
|
||||
# FINAL PHASE SETTINGS
|
||||
# The coordinates on the map indicating where the boss stands for the final portion of the fight.
|
||||
Final Standing Spot = 888,1104
|
||||
Final Ghost Saber Count = 10
|
||||
# Amount of separation between each ghost saber
|
||||
Final Ghost Saber Separation Amount = 24px
|
||||
# How often the cannons fire during the final phase.
|
||||
Final Cannon Timer = 5s
|
||||
}
|
||||
Pirate's Treasure
|
||||
{
|
||||
|
@ -1850,7 +1850,7 @@ Monsters
|
||||
SLASHING = 4, 0.1, OneShot
|
||||
DEATH = 4, 0.25, OneShot
|
||||
STABBING = 3, 0.1, OneShot
|
||||
SLASH = 1, 0.1, OneShot
|
||||
SLASH = 2, 0.1, OneShot
|
||||
STAB = 1, 0.1, OneShot
|
||||
SHOOTING = 3, 0.2, OneShot
|
||||
SHOOT = 1, 0.1, OneShot
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user