Phase 4 implemented.

pull/28/head
sigonasr2 1 year ago
parent 76d45f2563
commit de04905983
  1. 1
      Crawler/Crawler.vcxproj
  2. 3
      Crawler/Crawler.vcxproj.filters
  3. 4
      Crawler/Monster.cpp
  4. 1
      Crawler/Monster.h
  5. 2
      Crawler/MonsterAttribute.h
  6. 3
      Crawler/RUN_STRATEGY.cpp
  7. 80
      Crawler/RunAway.cpp
  8. 50
      Crawler/SlimeKing.cpp
  9. 2
      Crawler/Version.h
  10. 16
      Crawler/assets/config/MonsterStrategies.txt
  11. 4
      Crawler/assets/config/Monsters.txt

@ -308,6 +308,7 @@
<ClCompile Include="LightningBoltEmitter.cpp" /> <ClCompile Include="LightningBoltEmitter.cpp" />
<ClCompile Include="Map.cpp" /> <ClCompile Include="Map.cpp" />
<ClCompile Include="Meteor.cpp" /> <ClCompile Include="Meteor.cpp" />
<ClCompile Include="RunAway.cpp" />
<ClCompile Include="RunTowards.cpp" /> <ClCompile Include="RunTowards.cpp" />
<ClCompile Include="Pathfinding.cpp" /> <ClCompile Include="Pathfinding.cpp" />
<ClCompile Include="pixelGameEngine.cpp" /> <ClCompile Include="pixelGameEngine.cpp" />

@ -242,6 +242,9 @@
<ClCompile Include="FallingDebris.h"> <ClCompile Include="FallingDebris.h">
<Filter>Source Files\Effects</Filter> <Filter>Source Files\Effects</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="RunAway.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="cpp.hint" /> <None Include="cpp.hint" />

@ -83,7 +83,7 @@ bool Monster::SetX(float x){
} else { } else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size}; geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
collision.pos+=tilePos; collision.pos+=tilePos;
if(!geom2d::overlaps(newPos,collision)){ if(!geom2d::overlaps(geom2d::circle<float>(newPos,12*GetSizeMult()),collision)){
pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult())); pos.x=std::clamp(x,12.f*GetSizeMult(),float(game->WORLD_SIZE.x*24-12*GetSizeMult()));
Moved(); Moved();
return true; return true;
@ -102,7 +102,7 @@ bool Monster::SetY(float y){
} else { } else {
geom2d::rect<float>collision={collisionRect.pos,collisionRect.size}; geom2d::rect<float>collision={collisionRect.pos,collisionRect.size};
collision.pos+=tilePos; collision.pos+=tilePos;
if(!geom2d::overlaps(newPos,collision)){ if(!geom2d::overlaps(geom2d::circle<float>(newPos,12*GetSizeMult()),collision)){
pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult())); pos.y=std::clamp(y,12.f*GetSizeMult(),float(game->WORLD_SIZE.y*24-12*GetSizeMult()));
Moved(); Moved();
return true; return true;

@ -156,6 +156,7 @@ private:
static void SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumber); static void SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumber);
static void TURRET(Monster&m,float fElapsedTime,int strategyNumber); static void TURRET(Monster&m,float fElapsedTime,int strategyNumber);
static void SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber); static void SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber);
static void RUN_AWAY(Monster&m,float fElapsedTime,int strategyNumber);
}; };
}; };

@ -26,4 +26,6 @@ enum class Attribute{
JUMP_COUNT, JUMP_COUNT,
CASTING_TIMER, CASTING_TIMER,
TELEPORT_TO_PLAYER, TELEPORT_TO_PLAYER,
RUN_AWAY_TIMER,
PHASE_REPEAT_COUNT,
}; };

@ -40,5 +40,8 @@ void Monster::STRATEGY::RUN_STRATEGY(Monster&m,float fElapsedTime){
case 3:{//Slime King case 3:{//Slime King
Monster::STRATEGY::SLIMEKING(m,fElapsedTime,m.strategy); Monster::STRATEGY::SLIMEKING(m,fElapsedTime,m.strategy);
}break; }break;
case 4:{//Run Away Strategy
Monster::STRATEGY::RUN_AWAY(m,fElapsedTime,m.strategy);
}break;
} }
} }

@ -0,0 +1,80 @@
#include "Monster.h"
#include "DEFINES.h"
#include "Crawler.h"
#include "MonsterStrategyHelpers.h"
INCLUDE_BULLET_LIST
INCLUDE_game
void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,int strategyNumber){
m.targetAcquireTimer=std::max(0.f,m.targetAcquireTimer-fElapsedTime);
m.attackCooldownTimer=std::max(0.f,m.attackCooldownTimer-fElapsedTime);
geom2d::line line(m.pos,game->GetPlayer()->GetPos());
if(m.targetAcquireTimer==0&&m.queueShotTimer==0){
m.targetAcquireTimer=1;
if(line.length()<24.f*ConfigInt("Range")/100.f){
m.target=line.upoint(-1.2);
if(m.canMove){
m.SetState(State::MOVE_AWAY);
} else {
m.SetState(State::NORMAL);
}
} else
if(line.length()>24.f*ConfigInt("CloseInRange")/100.0f){
m.target=line.upoint(1.2);
m.SetState(State::MOVE_TOWARDS);
} else {
m.SetState(State::NORMAL);
}
}
m.canMove=true;
geom2d::line moveTowardsLine=geom2d::line(m.pos,m.target);
bool pathfindingDecision=false;
switch(m.state){
case State::MOVE_TOWARDS:{
if(moveTowardsLine.length()>1){
vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
bool movedX=m.SetX(newPos.x);
bool movedY=m.SetY(newPos.y);
pathfindingDecision=movedX|movedY;
m.canMove=movedX&&movedY;
}
if(!pathfindingDecision){
m.StartPathfinding(2.5);
}else
if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f){
m.SetState(State::NORMAL);
}
if(moveTowardsLine.vector().x>0){
m.facingDirection=RIGHT;
} else {
m.facingDirection=LEFT;
}
m.PerformJumpAnimation();
}break;
case State::MOVE_AWAY:{
if(moveTowardsLine.length()>1){
vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
bool movedX=m.SetX(newPos.x);
bool movedY=m.SetY(newPos.y);
pathfindingDecision=movedX|movedY;
m.canMove=movedX&&movedY;
}
if(!pathfindingDecision){
m.StartPathfinding(2.5);
}else
if(line.length()>=24.f*ConfigInt("Range")/100.f){
m.SetState(State::NORMAL);
}
if(moveTowardsLine.vector().x>0){
m.facingDirection=RIGHT;
} else {
m.facingDirection=LEFT;
}
m.PerformJumpAnimation();
}break;
case State::PATH_AROUND:{
m.PathAroundBehavior(fElapsedTime);
}break;
}
}

@ -24,6 +24,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
m.F(A::SHOOT_RING_DELAY)=std::max(0.f,m.F(A::SHOOT_RING_DELAY)-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); m.F(A::JUMP_LANDING_TIMER)=std::max(0.f,m.F(A::JUMP_LANDING_TIMER)-fElapsedTime);
m.F(A::CASTING_TIMER)=std::max(0.f,m.F(A::CASTING_TIMER)-fElapsedTime); m.F(A::CASTING_TIMER)=std::max(0.f,m.F(A::CASTING_TIMER)-fElapsedTime);
m.F(A::RUN_AWAY_TIMER)=std::max(0.f,m.F(A::RUN_AWAY_TIMER)-fElapsedTime);
const auto ShootBulletRing=[&](float angleOffset){ const auto ShootBulletRing=[&](float angleOffset){
int bulletCount=ConfigInt("Phase1.RingBulletCount"); int bulletCount=ConfigInt("Phase1.RingBulletCount");
@ -42,6 +43,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
const auto TransitionPhase=[&](int newPhase){ const auto TransitionPhase=[&](int newPhase){
const int MAX_ATTEMPTS=100; //Maximum number of tries to find a valid location. const int MAX_ATTEMPTS=100; //Maximum number of tries to find a valid location.
Player*player=game->GetPlayer(); Player*player=game->GetPlayer();
m.I(A::PATTERN_REPEAT_COUNT)=0;
const auto PositionInRangeOfPlayer=[&player](vf2d&pos,float radius){ const auto PositionInRangeOfPlayer=[&player](vf2d&pos,float radius){
return geom2d::line<float>(player->GetPos(),pos).length()<=player->GetSizeMult()*12*2+radius; return geom2d::line<float>(player->GetPos(),pos).length()<=player->GetSizeMult()*12*2+radius;
}; };
@ -105,6 +107,12 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
} }
}; };
if(m.F(A::RUN_AWAY_TIMER)>0){
Monster::STRATEGY::RUN_AWAY(m,fElapsedTime,4);
/*HACK ALERT!! This is kind of a hack. If the Run Away script changes the 4 would be inaccurate, but the run away script doesn't use this value so it's probably fine.*/
return;
}
if(m.GetState()==State::RECOVERY){ if(m.GetState()==State::RECOVERY){
m.F(A::RECOVERY_TIME)=std::max(0.f,m.F(A::RECOVERY_TIME)-fElapsedTime); m.F(A::RECOVERY_TIME)=std::max(0.f,m.F(A::RECOVERY_TIME)-fElapsedTime);
if(m.F(A::RECOVERY_TIME)==0){ if(m.F(A::RECOVERY_TIME)==0){
@ -116,17 +124,17 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
if(m.GetState()==State::JUMP){ if(m.GetState()==State::JUMP){
float jumpLandingTimerRatio=m.F(A::JUMP_LANDING_TIMER)/m.F(A::JUMP_ORIGINAL_LANDING_TIMER); float jumpLandingTimerRatio=m.F(A::JUMP_LANDING_TIMER)/m.F(A::JUMP_ORIGINAL_LANDING_TIMER);
if(m.GetPos().x>game->GetPlayer()->GetPos().x){ if(m.GetPos().x>m.V(A::JUMP_TARGET_POS).x){
m.SetX(std::max(game->GetPlayer()->GetPos().x,m.GetPos().x-m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime())); m.SetX(std::max(m.V(A::JUMP_TARGET_POS).x,m.GetPos().x-m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime()));
} else } else
if(m.GetPos().x<game->GetPlayer()->GetPos().x){ if(m.GetPos().x<m.V(A::JUMP_TARGET_POS).x){
m.SetX(std::min(game->GetPlayer()->GetPos().x,m.GetPos().x+m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime())); m.SetX(std::min(m.V(A::JUMP_TARGET_POS).x,m.GetPos().x+m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime()));
} }
if(m.GetPos().y>game->GetPlayer()->GetPos().y){ if(m.GetPos().y>m.V(A::JUMP_TARGET_POS).y){
m.SetY(std::max(game->GetPlayer()->GetPos().y,m.GetPos().y-m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime())); m.SetY(std::max(m.V(A::JUMP_TARGET_POS).y,m.GetPos().y-m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime()));
} else } else
if(m.GetPos().y<game->GetPlayer()->GetPos().y){ if(m.GetPos().y<m.V(A::JUMP_TARGET_POS).y){
m.SetY(std::min(game->GetPlayer()->GetPos().y,m.GetPos().y+m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime())); m.SetY(std::min(m.V(A::JUMP_TARGET_POS).y,m.GetPos().y+m.F(A::JUMP_MOVE_SPD)*game->GetElapsedTime()));
} }
if(m.F(A::JUMP_LANDING_TIMER)>=m.F(A::JUMP_ORIGINAL_LANDING_TIMER)/2){ if(m.F(A::JUMP_LANDING_TIMER)>=m.F(A::JUMP_ORIGINAL_LANDING_TIMER)/2){
m.SetZ(util::lerp(0,ConfigInt("JumpHeight"),1-jumpLandingTimerRatio)); m.SetZ(util::lerp(0,ConfigInt("JumpHeight"),1-jumpLandingTimerRatio));
@ -250,6 +258,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
if(m.hp<=m.maxhp*ConfigFloat("Phase4.Change")/100){ if(m.hp<=m.maxhp*ConfigFloat("Phase4.Change")/100){
m.phase=4; m.phase=4;
m.SetSize(ConfigFloat("Phase4.Size")/100,false); m.SetSize(ConfigFloat("Phase4.Size")/100,false);
m.AddBuff(BuffType::SLOWDOWN,9999999,ConfigFloat("Phase4.MoveSpdModifier")/100);
TransitionPhase(m.phase); TransitionPhase(m.phase);
return; return;
} }
@ -280,6 +289,31 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
TransitionPhase(m.phase); TransitionPhase(m.phase);
return; return;
} }
if(m.I(A::PHASE_REPEAT_COUNT)>=5){
m.I(A::PHASE_REPEAT_COUNT)=0;
float jumpAngle=util::angleTo(m.GetPos(),game->GetWorldSize()*24/2); //We jump towards the center to keep the player from constantly dealing with a stuck boss.
float jumpDistance=ConfigFloat("Phase4.JumpDistance")/100*24;
float jumpSpd=jumpDistance/ConfigFloat("Phase4.JumpDuration");
StartJump(ConfigFloat("Phase4.JumpDuration"),m.GetPos()+vf2d{cos(jumpAngle)*jumpDistance,sin(jumpAngle)*jumpDistance},0,jumpSpd);
}else
if(m.I(A::PATTERN_REPEAT_COUNT)<5&&m.F(A::SHOOT_TIMER)==0){
m.I(A::PATTERN_REPEAT_COUNT)++;
m.F(A::SHOOT_TIMER)=ConfigFloat("Phase4.ShootRate");
float bulletAngle=util::angleTo(m.GetPos(),game->GetPlayer()->GetPos());
float spreadAngle=util::degToRad(ConfigFloat("Phase4.RandomOffsetAngle"));
bulletAngle+=util::random(spreadAngle*2)-spreadAngle;
BULLET_LIST.emplace_back(std::make_unique<Bullet>(m.GetPos(),vf2d{cos(bulletAngle),sin(bulletAngle)}*bulletSpd,6,ConfigInt("ProjectileDamage"),m.OnUpperLevel(),false,YELLOW,vf2d{6,6}));
}else
if(m.I(A::PATTERN_REPEAT_COUNT)==5){
m.I(A::PATTERN_REPEAT_COUNT)++;
m.F(A::RUN_AWAY_TIMER)=ConfigFloat("Phase4.RunAwayTime");
}else
if(m.I(A::PATTERN_REPEAT_COUNT)==6&&m.F(A::RUN_AWAY_TIMER)==0){
m.F(A::RECOVERY_TIME)=ConfigFloat("Phase4.WaitTime");
m.SetState(State::RECOVERY);
m.I(A::PATTERN_REPEAT_COUNT)=0;
m.I(A::PHASE_REPEAT_COUNT)++;
}
}break; }break;
} }
} }

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 1390 #define VERSION_BUILD 1400
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -145,9 +145,15 @@ MonsterStrategy
# Percentage of health to transition to Phase 4 # Percentage of health to transition to Phase 4
Change = 25% Change = 25%
MonsterSpawnOnChange = Blue Slime, 2 MonsterSpawnOnChange = Blue Slime, 2
# Percentage of normal move spd the Slime King will move.
MoveSpdModifier = 50% MoveSpdModifier = 50%
ShootRate = 0.1 ShootRate = 0.1
RandomOffsetAngle = 75 RandomOffsetAngle = 35
RunAwayTime = 2.5
WaitTime = 1.0
JumpDuration = 3.0
JumpDistance = 1000 JumpDistance = 1000
} }
Phase5 Phase5
@ -159,4 +165,12 @@ MonsterStrategy
Change = 0% Change = 0%
} }
} }
4
{
Name = Run Away
# How far away the monster attempts to distance itself from the player
Range = 700
# If the player is farther than this distance, close in on them.
CloseInRange = 850
}
} }

@ -135,11 +135,11 @@ Monsters
CollisionDmg = 0 CollisionDmg = 0
MoveSpd = 0 MoveSpd = 100
Size = 800 Size = 800
Strategy = Slime King Strategy = Slime King
StartPhase = 3 StartPhase = 1
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24

Loading…
Cancel
Save