Bullets do not die immediately when view goes offscreen anymore. Initial jump states and setup for Slime King are now implemented.

pull/28/head
sigonasr2 1 year ago
parent efdf696d2c
commit 942e8e0ef7
  1. 1
      Crawler/Animation.cpp
  2. 3
      Crawler/Crawler.cpp
  3. 2
      Crawler/Crawler.h
  4. 36
      Crawler/Monster.cpp
  5. 13
      Crawler/Monster.h
  6. 9
      Crawler/MonsterAttribute.h
  7. 30
      Crawler/Player.cpp
  8. 6
      Crawler/Player.h
  9. 8
      Crawler/RunTowards.cpp
  10. 18
      Crawler/ShootAfar.cpp
  11. 45
      Crawler/SlimeKing.cpp
  12. 36
      Crawler/State.h
  13. 2
      Crawler/Version.h
  14. 3
      Crawler/assets/config/MonsterStrategies.txt
  15. 1
      Crawler/assets/config/gfx/gfx.txt
  16. BIN
      Crawler/assets/range_indicator.png
  17. 4
      Crawler/utils.cpp
  18. 1
      Crawler/utils.h

@ -206,6 +206,7 @@ void sig::Animation::InitializeAnimations(){
CreateStillAnimation(game->GFX_Arrow,{24,24},"ARROW"); CreateStillAnimation(game->GFX_Arrow,{24,24},"ARROW");
CreateStillAnimation(game->GFX_ChargedArrow,{48,48},"CHARGED_ARROW"); CreateStillAnimation(game->GFX_ChargedArrow,{48,48},"CHARGED_ARROW");
CreateStillAnimation(game->GFX_Laser,{5,1},"LASER"); CreateStillAnimation(game->GFX_Laser,{5,1},"LASER");
CreateStillAnimation(game->GFX_RangeIndicator,{24,24},"RANGE_INDICATOR");
} }
void sig::Animation::SetupPlayerAnimations(){ void sig::Animation::SetupPlayerAnimations(){

@ -116,6 +116,7 @@ bool Crawler::OnUserCreate(){
LOADIMG(GFX_Arrow) LOADIMG(GFX_Arrow)
LOADIMG(GFX_Laser) LOADIMG(GFX_Laser)
LOADIMG(GFX_ChargedArrow) LOADIMG(GFX_ChargedArrow)
LOADIMG(GFX_RangeIndicator)
Monster::InitializeStrategies(); Monster::InitializeStrategies();
//Animations //Animations
@ -451,7 +452,7 @@ void Crawler::UpdateBullets(float fElapsedTime){
} else { } else {
b->pos+=b->vel*fElapsedTime; b->pos+=b->vel*fElapsedTime;
} }
if(b->pos.x+b->radius<view.GetWorldTL().x||b->pos.x-b->radius>view.GetWorldBR().x||b->pos.y+b->radius<view.GetWorldTL().y||b->pos.y-b->radius>view.GetWorldBR().y){ if(b->pos.x+b->radius<view.GetWorldTL().x-WINDOW_SIZE.x||b->pos.x-b->radius>view.GetWorldBR().x+WINDOW_SIZE.x||b->pos.y+b->radius<view.GetWorldTL().y-WINDOW_SIZE.y||b->pos.y-b->radius>view.GetWorldBR().y+WINDOW_SIZE.y){
b->dead=true; b->dead=true;
continue; continue;
} }

@ -29,7 +29,7 @@ class Crawler : public olc::PixelGameEngine
GFX_Splash_Effect,GFX_LightningBolt,GFX_LightningBoltParticle1, GFX_Splash_Effect,GFX_LightningBolt,GFX_LightningBoltParticle1,
GFX_LightningBoltParticle2,GFX_LightningBoltParticle3,GFX_LightningBoltParticle4, GFX_LightningBoltParticle2,GFX_LightningBoltParticle3,GFX_LightningBoltParticle4,
GFX_ChainLightning,GFX_LightningSplash,GFX_Meteor,GFX_Arrow, GFX_ChainLightning,GFX_LightningSplash,GFX_Meteor,GFX_Arrow,
GFX_Laser,GFX_ChargedArrow; GFX_Laser,GFX_ChargedArrow,GFX_RangeIndicator;
public: public:
Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt,GFX_Circle; Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt,GFX_Circle;
Pathfinding pathfinder; Pathfinding pathfinder;

@ -129,11 +129,11 @@ bool Monster::Update(float fElapsedTime){
if(!HasIframes()){ if(!HasIframes()){
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
if(&m==this)continue; if(&m==this)continue;
if(!m.HasIframes()&&OnUpperLevel()==m.OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){ if(!m.HasIframes()&&OnUpperLevel()==m.OnUpperLevel()&&abs(m.GetZ()-GetZ())<=1&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){
m.Collision(*this); m.Collision(*this);
geom2d::line line(pos,m.GetPos()); geom2d::line line(pos,m.GetPos());
float dist = line.length(); float dist = line.length();
m.SetPosition(line.rpoint(dist*1.1)); m.SetPos(line.rpoint(dist*1.1));
if(m.IsAlive()){ if(m.IsAlive()){
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
@ -142,7 +142,7 @@ bool Monster::Update(float fElapsedTime){
if(!game->GetPlayer()->HasIframes()&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){ if(!game->GetPlayer()->HasIframes()&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){
geom2d::line line(pos,game->GetPlayer()->GetPos()); geom2d::line line(pos,game->GetPlayer()->GetPos());
float dist = line.length(); float dist = line.length();
SetPosition(line.rpoint(-0.1)); SetPos(line.rpoint(-0.1));
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
} }
@ -183,6 +183,7 @@ Key Monster::GetFacingDirection(){
return facingDirection; return facingDirection;
} }
void Monster::Draw(){ void Monster::Draw(){
strategyDraw(game);
if(GetZ()>0){ if(GetZ()>0){
vf2d shadowScale=vf2d{8*GetSizeMult()/3.f,1}/std::max(1.f,GetZ()/24); vf2d shadowScale=vf2d{8*GetSizeMult()/3.f,1}/std::max(1.f,GetZ()/24);
game->view.DrawDecal(GetPos()-vf2d{3,3}*shadowScale/2+vf2d{0,6*GetSizeMult()},game->GFX_Circle.Decal(),shadowScale,BLACK); game->view.DrawDecal(GetPos()-vf2d{3,3}*shadowScale/2+vf2d{0,6*GetSizeMult()},game->GFX_Circle.Decal(),shadowScale,BLACK);
@ -204,14 +205,14 @@ void Monster::Collision(Monster&m){
Collision(); Collision();
} }
void Monster::Collision(){ void Monster::Collision(){
if(strategy==0&&GetState()==MOVE_TOWARDS){//The run towards strategy causes state to return to normal upon a collision. if(strategy==0&&GetState()==State::MOVE_TOWARDS){//The run towards strategy causes state to return to normal upon a collision.
SetState(NORMAL); SetState(State::NORMAL);
} }
} }
void Monster::SetVelocity(vf2d vel){ void Monster::SetVelocity(vf2d vel){
this->vel=vel; this->vel=vel;
} }
bool Monster::SetPosition(vf2d pos){ bool Monster::SetPos(vf2d pos){
bool resultX=SetX(pos.x); bool resultX=SetX(pos.x);
bool resultY=SetY(pos.y); bool resultY=SetY(pos.y);
if(resultY&&!resultX){ if(resultY&&!resultX){
@ -301,7 +302,7 @@ void Monster::AddBuff(BuffType type,float duration,float intensity){
} }
void Monster::StartPathfinding(float pathingTime){ void Monster::StartPathfinding(float pathingTime){
SetState(PATH_AROUND); SetState(State::PATH_AROUND);
path=game->pathfinder.Solve_AStar(pos,target,12,OnUpperLevel()); path=game->pathfinder.Solve_AStar(pos,target,12,OnUpperLevel());
if(path.size()>0){ if(path.size()>0){
pathIndex=0; pathIndex=0;
@ -315,7 +316,7 @@ void Monster::PathAroundBehavior(float fElapsedTime){
//Move towards the new path. //Move towards the new path.
geom2d::line moveTowardsLine=geom2d::line(pos,path[pathIndex]*24); geom2d::line moveTowardsLine=geom2d::line(pos,path[pathIndex]*24);
if(moveTowardsLine.length()>2){ if(moveTowardsLine.length()>2){
SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult()); SetPos(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult());
if(moveTowardsLine.vector().x>0){ if(moveTowardsLine.vector().x>0){
facingDirection=RIGHT; facingDirection=RIGHT;
} else { } else {
@ -341,11 +342,11 @@ std::vector<Buff>Monster::GetBuffs(BuffType buff){
return filteredBuffs; return filteredBuffs;
} }
State Monster::GetState(){ State::State Monster::GetState(){
return state; return state;
} }
void Monster::SetState(State newState){ void Monster::SetState(State::State newState){
state=newState; state=newState;
} }
@ -407,4 +408,19 @@ bool&Monster::GetBool(Attribute a){
attributes[a]=false; attributes[a]=false;
} }
return std::get<bool>(attributes[a]); return std::get<bool>(attributes[a]);
}
vf2d&Monster::GetVf2d(Attribute a){
if(attributes.count(a)==0){
attributes[a]=vf2d{};
}
return std::get<vf2d>(attributes[a]);
}
void Monster::SetZ(float z){
this->z=z;
}
void Monster::SetStrategyDrawFunction(std::function<void(Crawler*)>func){
strategyDraw=func;
} }

@ -9,6 +9,7 @@
#include "MonsterAttribute.h" #include "MonsterAttribute.h"
struct Player; struct Player;
class Crawler;
enum MonsterAnimation{ enum MonsterAnimation{
IDLE, IDLE,
@ -72,7 +73,7 @@ private:
float iframe_timer=0; float iframe_timer=0;
Key facingDirection; Key facingDirection;
int strategy; int strategy;
State state=State::NORMAL; State::State state=State::NORMAL;
Animate2D::Animation<std::string>animation; Animate2D::Animation<std::string>animation;
Animate2D::AnimationState internal_animState; Animate2D::AnimationState internal_animState;
float randomFrameOffset=0.f; float randomFrameOffset=0.f;
@ -91,6 +92,7 @@ private:
bool diesNormally=true; //If set to false, the monster death is handled in a special way. Set it to true when it's time to die. bool diesNormally=true; //If set to false, the monster death is handled in a special way. Set it to true when it's time to die.
float targetSize=0; float targetSize=0;
std::map<Attribute,std::variant<VARIANTS>>attributes; std::map<Attribute,std::variant<VARIANTS>>attributes;
std::function<void(Crawler*)>strategyDraw=[](Crawler*pge){};
protected: protected:
public: public:
Monster()=delete; Monster()=delete;
@ -115,7 +117,7 @@ public:
void Collision(); void Collision();
void SetVelocity(vf2d vel); void SetVelocity(vf2d vel);
//Returns false if the monster could not be moved to the requested location due to collision. //Returns false if the monster could not be moved to the requested location due to collision.
bool SetPosition(vf2d pos); bool SetPos(vf2d pos);
//Returns false if the monster could not be moved to the requested location due to collision. //Returns false if the monster could not be moved to the requested location due to collision.
bool SetX(float x); bool SetX(float x);
//Returns false if the monster could not be moved to the requested location due to collision. //Returns false if the monster could not be moved to the requested location due to collision.
@ -129,17 +131,20 @@ public:
void PathAroundBehavior(float fElapsedTime); void PathAroundBehavior(float fElapsedTime);
void AddBuff(BuffType type,float duration,float intensity); void AddBuff(BuffType type,float duration,float intensity);
std::vector<Buff>GetBuffs(BuffType buff); std::vector<Buff>GetBuffs(BuffType buff);
State GetState(); State::State GetState();
void SetState(State newState); void SetState(State::State newState);
static void InitializeStrategies(); static void InitializeStrategies();
bool HasIframes(); bool HasIframes();
float GetZ(); float GetZ();
void SetZ(float z);
std::string GetStrategy(); std::string GetStrategy();
void SetSize(float newSize,bool immediate=true); void SetSize(float newSize,bool immediate=true);
float&GetFloat(Attribute a); float&GetFloat(Attribute a);
int&GetInt(Attribute a); int&GetInt(Attribute a);
std::string&GetString(Attribute a); std::string&GetString(Attribute a);
bool&GetBool(Attribute a); bool&GetBool(Attribute a);
vf2d&GetVf2d(Attribute a);
void SetStrategyDrawFunction(std::function<void(Crawler*)>func);
private: private:
struct STRATEGY{ struct STRATEGY{
static int _GetInt(Monster&m,std::string param,int strategyNumber,int index=0); static int _GetInt(Monster&m,std::string param,int strategyNumber,int index=0);

@ -1,10 +1,11 @@
#pragma once #pragma once
#define VARIANTS float,int,std::string,bool #define VARIANTS float,int,std::string,bool,vf2d
#include <string> #include <string>
#define F(attr) GetFloat(attr) #define F(attr) GetFloat(attr)
#define I(attr) GetInt(attr) #define I(attr) GetInt(attr)
#define S(attr) GetString(attr) #define S(attr) GetString(attr)
#define B(attr) GetBool(attr) #define B(attr) GetBool(attr)
#define V(attr) GetVf2d(attr)
enum class Attribute{ enum class Attribute{
IFRAME_TIME_UPON_HIT, IFRAME_TIME_UPON_HIT,
@ -13,4 +14,10 @@ enum class Attribute{
SHOOT_RING_COUNTER, SHOOT_RING_COUNTER,
SHOOT_RING_RIGHT, SHOOT_RING_RIGHT,
SHOOT_RING_OFFSET, SHOOT_RING_OFFSET,
PATTERN_REPEAT_COUNT,
JUMP_ORIGINAL_LANDING_TIMER,
JUMP_LANDING_TIMER,
JUMP_TARGET_POS,
JUMP_ORIGINAL_POS,
RECOVERY_TIME,
}; };

@ -160,7 +160,7 @@ float Player::GetSpinAngle(){
return spin_angle; return spin_angle;
} }
State Player::GetState(){ State::State Player::GetState(){
return state; return state;
} }
@ -207,7 +207,7 @@ void Player::Update(float fElapsedTime){
//Class-specific update events. //Class-specific update events.
OnUpdate(fElapsedTime); OnUpdate(fElapsedTime);
switch(state){ switch(state){
case SPIN:{ case State::SPIN:{
switch(facingDirection){ switch(facingDirection){
case UP:{ case UP:{
if(lastAnimationFlip==0){ if(lastAnimationFlip==0){
@ -233,7 +233,7 @@ void Player::Update(float fElapsedTime){
z="Warrior.Ability 2.SpinMaxHeight"_I*sin(3.3*(GROUND_SLAM_SPIN_TIME-spin_attack_timer)/GROUND_SLAM_SPIN_TIME); z="Warrior.Ability 2.SpinMaxHeight"_I*sin(3.3*(GROUND_SLAM_SPIN_TIME-spin_attack_timer)/GROUND_SLAM_SPIN_TIME);
spin_attack_timer=std::max(0.f,spin_attack_timer-fElapsedTime); spin_attack_timer=std::max(0.f,spin_attack_timer-fElapsedTime);
} else { } else {
SetState(NORMAL); SetState(State::NORMAL);
spin_angle=0; spin_angle=0;
z=0; z=0;
float numb=4; float numb=4;
@ -245,14 +245,14 @@ void Player::Update(float fElapsedTime){
} }
animation.UpdateState(internal_animState,fElapsedTime); animation.UpdateState(internal_animState,fElapsedTime);
}break; }break;
case BLOCK:{ case State::BLOCK:{
if(blockTimer<=0){ if(blockTimer<=0){
SetState(NORMAL); SetState(State::NORMAL);
} }
}break; }break;
case SWING_SONIC_SWORD:{ case State::SWING_SONIC_SWORD:{
if(ability3.COOLDOWN_TIME-ability3.cooldown>0.5){ if(ability3.COOLDOWN_TIME-ability3.cooldown>0.5){
SetState(NORMAL); SetState(State::NORMAL);
switch(facingDirection){ switch(facingDirection){
case DOWN:{ case DOWN:{
UpdateAnimation("WARRIOR_IDLE_S"); UpdateAnimation("WARRIOR_IDLE_S");
@ -270,11 +270,11 @@ void Player::Update(float fElapsedTime){
} }
animation.UpdateState(internal_animState,fElapsedTime); animation.UpdateState(internal_animState,fElapsedTime);
}break; }break;
case TELEPORT:{ case State::TELEPORT:{
teleportAnimationTimer=std::max(0.f,teleportAnimationTimer-fElapsedTime); teleportAnimationTimer=std::max(0.f,teleportAnimationTimer-fElapsedTime);
if(teleportAnimationTimer<=0){ if(teleportAnimationTimer<=0){
SetPos(teleportTarget); SetPos(teleportTarget);
SetState(NORMAL); SetState(State::NORMAL);
} }
animation.UpdateState(internal_animState,fElapsedTime); animation.UpdateState(internal_animState,fElapsedTime);
}break; }break;
@ -304,13 +304,13 @@ void Player::Update(float fElapsedTime){
ability4.cooldown=0; ability4.cooldown=0;
} }
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
if(!HasIframes()&&OnUpperLevel()==m.OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){ if(!HasIframes()&&abs(m.GetZ()-GetZ())<=1&&OnUpperLevel()==m.OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){
if(m.IsAlive()){ if(m.IsAlive()){
m.Collision(this); m.Collision(this);
} }
geom2d::line line(pos,m.GetPos()); geom2d::line line(pos,m.GetPos());
float dist = line.length(); float dist = line.length();
m.SetPosition(line.rpoint(dist*1.1)); m.SetPos(line.rpoint(dist*1.1));
if(m.IsAlive()){ if(m.IsAlive()){
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
@ -382,7 +382,7 @@ void Player::Update(float fElapsedTime){
#pragma region Warrior #pragma region Warrior
switch(GetState()){ switch(GetState()){
case SWING_SWORD:{ case State::SWING_SWORD:{
switch(GetFacingDirection()){ switch(GetFacingDirection()){
case UP:{ case UP:{
UpdateAnimation("WARRIOR_SWINGSWORD_N"); UpdateAnimation("WARRIOR_SWINGSWORD_N");
@ -407,9 +407,9 @@ void Player::Update(float fElapsedTime){
#pragma endregion #pragma endregion
#pragma region Ranger #pragma region Ranger
if(GetState()==SHOOT_ARROW){ if(GetState()==State::SHOOT_ARROW){
if(attack_cooldown_timer<=ARROW_ATTACK_COOLDOWN-0.3){ if(attack_cooldown_timer<=ARROW_ATTACK_COOLDOWN-0.3){
SetState(NORMAL); SetState(State::NORMAL);
} }
} }
if(retreatTimer>0){ if(retreatTimer>0){
@ -467,7 +467,7 @@ void Player::SetSwordSwingTimer(float val){
swordSwingTimer=val; swordSwingTimer=val;
} }
void Player::SetState(State newState){ void Player::SetState(State::State newState){
if(GetState()==State::BLOCK){ if(GetState()==State::BLOCK){
RemoveAllBuffs(BuffType::BLOCK_SLOWDOWN); RemoveAllBuffs(BuffType::BLOCK_SLOWDOWN);
} }

@ -41,7 +41,7 @@ private:
float manaTickTimer=0; float manaTickTimer=0;
std::pair<std::string,float> notEnoughManaDisplay={"",0}; std::pair<std::string,float> notEnoughManaDisplay={"",0};
float teleportAttemptWaitTime=0; //If a teleport fails, we wait awhile before trying again, it's expensive. float teleportAttemptWaitTime=0; //If a teleport fails, we wait awhile before trying again, it's expensive.
State state=State::NORMAL; State::State state=State::NORMAL;
Animate2D::Animation<std::string>animation; Animate2D::Animation<std::string>animation;
Animate2D::AnimationState internal_animState; Animate2D::AnimationState internal_animState;
Key lastReleasedMovementKey; Key lastReleasedMovementKey;
@ -58,7 +58,7 @@ protected:
const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F; const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F;
float ARROW_ATTACK_COOLDOWN="Ranger.Auto Attack.Cooldown"_F; float ARROW_ATTACK_COOLDOWN="Ranger.Auto Attack.Cooldown"_F;
void SetSwordSwingTimer(float val); void SetSwordSwingTimer(float val);
void SetState(State newState); void SetState(State::State newState);
void SetFacingDirection(Key direction); void SetFacingDirection(Key direction);
void SetLastReleasedMovementKey(Key k); void SetLastReleasedMovementKey(Key k);
void Spin(float duration,float spinSpd); void Spin(float duration,float spinSpd);
@ -120,7 +120,7 @@ public:
float GetSizeMult(); float GetSizeMult();
float GetAttackRangeMult(); float GetAttackRangeMult();
float GetSpinAngle(); float GetSpinAngle();
State GetState(); State::State GetState();
Key GetFacingDirection(); Key GetFacingDirection();
vf2d GetVelocity(); vf2d GetVelocity();
bool HasIframes(); bool HasIframes();

@ -18,11 +18,11 @@ void Monster::STRATEGY::RUN_TOWARDS(Monster&m,float fElapsedTime,int strategyNum
} else { } else {
m.target=desiredTargetLine.upoint(1.2); m.target=desiredTargetLine.upoint(1.2);
} }
m.SetState(MOVE_TOWARDS); m.SetState(State::MOVE_TOWARDS);
m.hasHitPlayer=false; m.hasHitPlayer=false;
} }
switch(m.state){ switch(m.state){
case MOVE_TOWARDS:{ case State::MOVE_TOWARDS:{
if(geom2d::line(m.pos,m.target).length()>100*fElapsedTime*m.GetMoveSpdMult()){ if(geom2d::line(m.pos,m.target).length()>100*fElapsedTime*m.GetMoveSpdMult()){
vf2d newPos=m.pos+geom2d::line(m.pos,m.target).vector().norm()*100*fElapsedTime*m.GetMoveSpdMult(); vf2d newPos=m.pos+geom2d::line(m.pos,m.target).vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
if(!m.SetX(newPos.x)||!m.SetY(newPos.y)){ if(!m.SetX(newPos.x)||!m.SetY(newPos.y)){
@ -30,11 +30,11 @@ void Monster::STRATEGY::RUN_TOWARDS(Monster&m,float fElapsedTime,int strategyNum
} }
m.PerformJumpAnimation(); m.PerformJumpAnimation();
} else { } else {
m.SetState(NORMAL);//Revert state once we've finished moving towards target. m.SetState(State::NORMAL);//Revert state once we've finished moving towards target.
m.UpdateAnimation(MONSTER_DATA[m.id].GetIdleAnimation()); m.UpdateAnimation(MONSTER_DATA[m.id].GetIdleAnimation());
} }
}break; }break;
case PATH_AROUND:{ case State::PATH_AROUND:{
m.PathAroundBehavior(fElapsedTime); m.PathAroundBehavior(fElapsedTime);
}break; }break;
default:{ default:{

@ -24,23 +24,23 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumb
if(line.length()<24.f*ConfigInt("Range")/100.f){ if(line.length()<24.f*ConfigInt("Range")/100.f){
m.target=line.upoint(-1.2); m.target=line.upoint(-1.2);
if(m.canMove){ if(m.canMove){
m.SetState(MOVE_AWAY); m.SetState(State::MOVE_AWAY);
} else { } else {
m.SetState(NORMAL); m.SetState(State::NORMAL);
} }
} else } else
if(line.length()>24.f*ConfigInt("CloseInRange")/100.0f){ if(line.length()>24.f*ConfigInt("CloseInRange")/100.0f){
m.target=line.upoint(1.2); m.target=line.upoint(1.2);
m.SetState(MOVE_TOWARDS); m.SetState(State::MOVE_TOWARDS);
} else { } else {
m.SetState(NORMAL); m.SetState(State::NORMAL);
} }
} }
m.canMove=true; m.canMove=true;
geom2d::line moveTowardsLine=geom2d::line(m.pos,m.target); geom2d::line moveTowardsLine=geom2d::line(m.pos,m.target);
bool pathfindingDecision=false; bool pathfindingDecision=false;
switch(m.state){ switch(m.state){
case MOVE_TOWARDS:{ case State::MOVE_TOWARDS:{
if(moveTowardsLine.length()>1){ if(moveTowardsLine.length()>1){
vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult(); vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
bool movedX=m.SetX(newPos.x); bool movedX=m.SetX(newPos.x);
@ -52,7 +52,7 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumb
m.StartPathfinding(2.5); m.StartPathfinding(2.5);
}else }else
if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f){ if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f){
m.SetState(NORMAL); m.SetState(State::NORMAL);
} }
if(moveTowardsLine.vector().x>0){ if(moveTowardsLine.vector().x>0){
m.facingDirection=RIGHT; m.facingDirection=RIGHT;
@ -61,7 +61,7 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumb
} }
m.PerformJumpAnimation(); m.PerformJumpAnimation();
}break; }break;
case MOVE_AWAY:{ case State::MOVE_AWAY:{
if(moveTowardsLine.length()>1){ if(moveTowardsLine.length()>1){
vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult(); vf2d newPos=m.pos+moveTowardsLine.vector().norm()*100*fElapsedTime*m.GetMoveSpdMult();
bool movedX=m.SetX(newPos.x); bool movedX=m.SetX(newPos.x);
@ -73,7 +73,7 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumb
m.StartPathfinding(2.5); m.StartPathfinding(2.5);
}else }else
if(line.length()>=24.f*ConfigInt("Range")/100.f){ if(line.length()>=24.f*ConfigInt("Range")/100.f){
m.SetState(NORMAL); m.SetState(State::NORMAL);
} }
if(moveTowardsLine.vector().x>0){ if(moveTowardsLine.vector().x>0){
m.facingDirection=RIGHT; m.facingDirection=RIGHT;
@ -82,7 +82,7 @@ void Monster::STRATEGY::SHOOT_AFAR(Monster&m,float fElapsedTime,int strategyNumb
} }
m.PerformJumpAnimation(); m.PerformJumpAnimation();
}break; }break;
case PATH_AROUND:{ case State::PATH_AROUND:{
m.PathAroundBehavior(fElapsedTime); m.PathAroundBehavior(fElapsedTime);
}break; }break;
default:{ default:{

@ -3,9 +3,11 @@
#include "DEFINES.h" #include "DEFINES.h"
#include "Crawler.h" #include "Crawler.h"
#include "utils.h" #include "utils.h"
#include "safemap.h"
INCLUDE_game INCLUDE_game
INCLUDE_BULLET_LIST INCLUDE_BULLET_LIST
INCLUDE_ANIMATION_DATA
typedef Attribute A; typedef Attribute A;
@ -15,6 +17,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
m.F(A::SHOOT_RING_TIMER)=std::max(0.f,m.F(A::SHOOT_RING_TIMER)-fElapsedTime); 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::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){ auto ShootBulletRing=[&](float angleOffset){
int bulletCount=ConfigInt("Phase1.RingBulletCount"); int bulletCount=ConfigInt("Phase1.RingBulletCount");
@ -23,6 +26,42 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
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})); 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);
m.SetPos(m.V(A::JUMP_ORIGINAL_POS).lerp(m.V(A::JUMP_TARGET_POS),1-jumpLandingTimerRatio));
if(m.F(A::JUMP_LANDING_TIMER)>=m.F(A::JUMP_ORIGINAL_LANDING_TIMER)/2){
m.SetZ(util::lerp(0,ConfigInt("JumpHeight"),1-jumpLandingTimerRatio*2));
}else{
m.SetZ(util::lerp(0,ConfigInt("JumpHeight"),jumpLandingTimerRatio*2));
}
if(m.F(A::JUMP_LANDING_TIMER)==0){
m.state=State::RECOVERY;
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){ switch(m.phase){
case 0:{ case 0:{
@ -38,11 +77,17 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
m.SetSize(ConfigFloat("Phase2.Size")/100,false); m.SetSize(ConfigFloat("Phase2.Size")/100,false);
} }
if(m.F(A::SHOOT_RING_TIMER)==0){ 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.I(A::SHOOT_RING_COUNTER)=ConfigInt("Phase1.ShootRingCount")-1;
m.F(A::SHOOT_RING_DELAY)=ConfigFloat("Phase1.ShootRingDelay"); m.F(A::SHOOT_RING_DELAY)=ConfigFloat("Phase1.ShootRingDelay");
ShootBulletRing(m.F(A::SHOOT_RING_OFFSET)); ShootBulletRing(m.F(A::SHOOT_RING_OFFSET));
m.F(A::SHOOT_RING_TIMER)=ConfigFloat("Phase1.ShootRepeatTime"); m.F(A::SHOOT_RING_TIMER)=ConfigFloat("Phase1.ShootRepeatTime");
m.B(A::SHOOT_RING_RIGHT)=bool(rand()%2); 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.I(A::SHOOT_RING_COUNTER)>0){
if(m.F(A::SHOOT_RING_DELAY)==0){ if(m.F(A::SHOOT_RING_DELAY)==0){

@ -1,18 +1,22 @@
#pragma once #pragma once
enum State{ namespace State{
NORMAL, enum State{
SWING_SWORD, NORMAL,
SWING_SONIC_SWORD, SWING_SWORD,
SPIN, SWING_SONIC_SWORD,
MOVE_TOWARDS, SPIN,
MOVE_AWAY, MOVE_TOWARDS,
BLOCK, MOVE_AWAY,
TELEPORT, BLOCK,
PATH_AROUND, TELEPORT,
CASTING, PATH_AROUND,
PREP_CAST, CASTING,
SHOOT_ARROW, PREP_CAST,
RETREAT, SHOOT_ARROW,
ANIMATION_LOCK, RETREAT,
}; ANIMATION_LOCK,
JUMP,
RECOVERY,
};
}

@ -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 1119 #define VERSION_BUILD 1138
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -75,7 +75,7 @@ MonsterStrategy
# How much time a jump will be pre-telegraphed. # How much time a jump will be pre-telegraphed.
JumpWarningIndicatorTime = 1.0 JumpWarningIndicatorTime = 1.0
# Distance to jump up into the sky. A higher value causes it to launch up and down seemingly faster. # Distance to jump up into the sky. A higher value causes it to launch up and down seemingly faster.
JumpHeight = 1500 JumpHeight = 300
ProjectileDamage = 10 ProjectileDamage = 10
JumpAttackDamage = 20 JumpAttackDamage = 20
@ -93,7 +93,6 @@ MonsterStrategy
RingOffset = 10.0 RingOffset = 10.0
JumpAfter = 4 shots JumpAfter = 4 shots
AirborneTime = 3.0 AirborneTime = 3.0
LandingRingCount = 1
LandingRecoveryTime = 2.0 LandingRecoveryTime = 2.0
} }
Phase2 Phase2

@ -29,4 +29,5 @@ Images
GFX_Arrow = arrow.png GFX_Arrow = arrow.png
GFX_Laser = laser.png GFX_Laser = laser.png
GFX_ChargedArrow = charged_shot_arrow.png GFX_ChargedArrow = charged_shot_arrow.png
GFX_RangeIndicator = range_indicator.png
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@ -14,4 +14,8 @@ float util::degToRad(float deg){
float util::radToDeg(float rad){ float util::radToDeg(float rad){
return rad*57.2957795130823208767; return rad*57.2957795130823208767;
}
float util::lerp(float n1,float n2,double t){
return n1*(1-t)+n2*t;
} }

@ -8,4 +8,5 @@ namespace util{
vf2d pointTo(vf2d posFrom,vf2d posTo); vf2d pointTo(vf2d posFrom,vf2d posTo);
float degToRad(float deg); float degToRad(float deg);
float radToDeg(float rad); float radToDeg(float rad);
float lerp(float n1,float n2,double t);
} }
Loading…
Cancel
Save