|
|
|
#include "Monster.h"
|
|
|
|
#include "MonsterStrategyHelpers.h"
|
|
|
|
#include "DEFINES.h"
|
|
|
|
#include "Crawler.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "safemap.h"
|
|
|
|
|
|
|
|
INCLUDE_game
|
|
|
|
INCLUDE_BULLET_LIST
|
|
|
|
INCLUDE_ANIMATION_DATA
|
|
|
|
|
|
|
|
typedef Attribute A;
|
|
|
|
|
|
|
|
void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber){
|
|
|
|
|
|
|
|
float bulletSpd=ConfigFloat("BulletSpd")/100*24;
|
|
|
|
|
|
|
|
m.F(A::SHOOT_RING_TIMER)=std::max(0.f,m.F(A::SHOOT_RING_TIMER)-fElapsedTime);
|
|
|
|
m.F(A::SHOOT_RING_DELAY)=std::max(0.f,m.F(A::SHOOT_RING_DELAY)-fElapsedTime);
|
|
|
|
m.F(A::JUMP_LANDING_TIMER)=std::max(0.f,m.F(A::JUMP_LANDING_TIMER)-fElapsedTime);
|
|
|
|
|
|
|
|
auto ShootBulletRing=[&](float angleOffset){
|
|
|
|
int bulletCount=ConfigInt("Phase1.RingBulletCount");
|
|
|
|
for(int i=0;i<bulletCount;i++){
|
|
|
|
float angle=((2*PI)/bulletCount)*i+angleOffset;
|
|
|
|
BULLET_LIST.emplace_back(std::make_unique<Bullet>(m.GetPos(),vf2d{cos(angle),sin(angle)}*bulletSpd,6,ConfigInt("ProjectileDamage"),m.OnUpperLevel(),false,YELLOW,vf2d{6,6}));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
auto StartJump=[&](float jumpDuration,vf2d targetPos,float recoveryTime){
|
|
|
|
m.V(A::JUMP_ORIGINAL_POS)=m.GetPos();
|
|
|
|
m.F(A::JUMP_ORIGINAL_LANDING_TIMER)=m.F(A::JUMP_LANDING_TIMER)=jumpDuration;
|
|
|
|
m.V(A::JUMP_TARGET_POS)=targetPos;
|
|
|
|
m.F(A::RECOVERY_TIME)=recoveryTime;
|
|
|
|
m.state=State::JUMP;
|
|
|
|
};
|
|
|
|
|
|
|
|
if(m.state==State::RECOVERY){
|
|
|
|
m.F(A::RECOVERY_TIME)=std::max(0.f,m.F(A::RECOVERY_TIME)-fElapsedTime);
|
|
|
|
if(m.F(A::RECOVERY_TIME)==0){
|
|
|
|
m.state=State::NORMAL;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m.state==State::JUMP){
|
|
|
|
float jumpLandingTimerRatio=m.F(A::JUMP_LANDING_TIMER)/m.F(A::JUMP_ORIGINAL_LANDING_TIMER);
|
|
|
|
vf2d moveVel;
|
|
|
|
if(m.GetPos().x>game->GetPlayer()->GetPos().x){
|
|
|
|
m.SetX(std::max(game->GetPlayer()->GetPos().x,m.GetPos().x-ConfigInt("JumpMoveSpd")*game->GetElapsedTime()));
|
|
|
|
} else
|
|
|
|
if(m.GetPos().x<game->GetPlayer()->GetPos().x){
|
|
|
|
m.SetX(std::min(game->GetPlayer()->GetPos().x,m.GetPos().x+ConfigInt("JumpMoveSpd")*game->GetElapsedTime()));
|
|
|
|
}
|
|
|
|
if(m.GetPos().y>game->GetPlayer()->GetPos().y){
|
|
|
|
m.SetY(std::max(game->GetPlayer()->GetPos().y,m.GetPos().y-ConfigInt("JumpMoveSpd")*game->GetElapsedTime()));
|
|
|
|
} else
|
|
|
|
if(m.GetPos().y<game->GetPlayer()->GetPos().y){
|
|
|
|
m.SetY(std::min(game->GetPlayer()->GetPos().y,m.GetPos().y+ConfigInt("JumpMoveSpd")*game->GetElapsedTime()));
|
|
|
|
}
|
|
|
|
if(m.F(A::JUMP_LANDING_TIMER)>=m.F(A::JUMP_ORIGINAL_LANDING_TIMER)/2){
|
|
|
|
m.SetZ(util::lerp(0,ConfigInt("JumpHeight"),1-jumpLandingTimerRatio));
|
|
|
|
}else{
|
|
|
|
m.SetZ(util::lerp(0,ConfigInt("JumpHeight"),jumpLandingTimerRatio*2));
|
|
|
|
}
|
|
|
|
if(m.F(A::JUMP_LANDING_TIMER)==0){
|
|
|
|
m.state=State::RECOVERY;
|
|
|
|
game->SetupWorldShake(0.6);
|
|
|
|
m.SetStrategyDrawFunction([](Crawler*game){});
|
|
|
|
} else
|
|
|
|
if(m.F(A::JUMP_LANDING_TIMER)<=ConfigFloat("JumpWarningIndicatorTime")){
|
|
|
|
m.SetStrategyDrawFunction([&](Crawler*game){
|
|
|
|
Decal*dec=ANIMATION_DATA["RANGE_INDICATOR"].GetFrame(game->GetElapsedTime()).GetSourceImage()->Decal();
|
|
|
|
game->view.DrawRotatedDecal(m.GetPos(),dec,0,dec->sprite->Size()/2,vf2d{m.GetSizeMult(),m.GetSizeMult()}/2,RED);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(m.phase){
|
|
|
|
case 0:{
|
|
|
|
m.size=ConfigInt("Phase1.Size")/100;
|
|
|
|
m.diesNormally=false;
|
|
|
|
m.F(A::IFRAME_TIME_UPON_HIT)=0;
|
|
|
|
m.iframe_timer=ConfigFloat("Phase5.IframeTimePerHit");
|
|
|
|
m.phase=1;
|
|
|
|
}break;
|
|
|
|
case 1:{
|
|
|
|
if(m.hp<=m.maxhp*ConfigFloat("Phase2.Change")/100){
|
|
|
|
m.phase=2;
|
|
|
|
m.SetSize(ConfigFloat("Phase2.Size")/100,false);
|
|
|
|
}
|
|
|
|
if(m.F(A::SHOOT_RING_TIMER)==0){
|
|
|
|
if(m.I(A::PATTERN_REPEAT_COUNT)>=ConfigInt("Phase1.JumpAfter")){
|
|
|
|
StartJump(ConfigFloat("Phase1.AirborneTime"),game->GetPlayer()->GetPos(),ConfigFloat("Phase1.LandingRecoveryTime"));
|
|
|
|
m.I(A::PATTERN_REPEAT_COUNT)=0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m.I(A::SHOOT_RING_COUNTER)=ConfigInt("Phase1.ShootRingCount")-1;
|
|
|
|
m.F(A::SHOOT_RING_DELAY)=ConfigFloat("Phase1.ShootRingDelay");
|
|
|
|
ShootBulletRing(m.F(A::SHOOT_RING_OFFSET));
|
|
|
|
m.F(A::SHOOT_RING_TIMER)=ConfigFloat("Phase1.ShootRepeatTime");
|
|
|
|
m.B(A::SHOOT_RING_RIGHT)=bool(rand()%2);
|
|
|
|
m.I(A::PATTERN_REPEAT_COUNT)++;
|
|
|
|
}
|
|
|
|
if(m.I(A::SHOOT_RING_COUNTER)>0){
|
|
|
|
if(m.F(A::SHOOT_RING_DELAY)==0){
|
|
|
|
m.I(A::SHOOT_RING_COUNTER)--;
|
|
|
|
m.F(A::SHOOT_RING_DELAY)=ConfigFloat("Phase1.ShootRingDelay");
|
|
|
|
if(m.B(A::SHOOT_RING_RIGHT)){
|
|
|
|
m.F(A::SHOOT_RING_OFFSET)+=util::degToRad(ConfigFloat("Phase1.RingOffset"));
|
|
|
|
}else{
|
|
|
|
m.F(A::SHOOT_RING_OFFSET)-=util::degToRad(ConfigFloat("Phase1.RingOffset"));
|
|
|
|
}
|
|
|
|
ShootBulletRing(m.F(A::SHOOT_RING_OFFSET));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
case 2:{
|
|
|
|
if(m.hp<=m.maxhp*ConfigFloat("Phase3.Change")/100){
|
|
|
|
m.phase=3;
|
|
|
|
m.SetSize(ConfigFloat("Phase3.Size")/100,false);
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
case 3:{
|
|
|
|
if(m.hp<=m.maxhp*ConfigFloat("Phase4.Change")/100){
|
|
|
|
m.phase=4;
|
|
|
|
m.SetSize(ConfigFloat("Phase4.Size")/100,false);
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
case 4:{
|
|
|
|
if(m.hp<=0){
|
|
|
|
m.phase=5;
|
|
|
|
m.F(A::IFRAME_TIME_UPON_HIT)=1;
|
|
|
|
}
|
|
|
|
}break;
|
|
|
|
}
|
|
|
|
}
|