Setup King Slime encounter, Boss room map setup with spawn and player, made non-infinite. Implemented enemy iframes and added phase framework for the boss.

pull/28/head
sigonasr2 1 year ago
parent c9fa25a823
commit c75e56d642
  1. 53
      Crawler/Crawler.cpp
  2. 1
      Crawler/Crawler.h
  3. 3
      Crawler/Crawler.tiled-project
  4. 1
      Crawler/DEFINES.h
  5. 22
      Crawler/Monster.cpp
  6. 4
      Crawler/Monster.h
  7. 30
      Crawler/Player.cpp
  8. 1
      Crawler/Player.h
  9. 12
      Crawler/RUN_STRATEGY.cpp
  10. 29
      Crawler/SlimeKing.cpp
  11. 2
      Crawler/Version.h
  12. 2
      Crawler/Warrior.cpp
  13. 1239
      Crawler/assets/Campaigns/Boss_1_v2.tmx
  14. 2
      Crawler/assets/config/levels.txt
  15. 1
      Crawler/olcUTIL_DataFile.h

@ -129,7 +129,7 @@ bool Crawler::OnUserCreate(){
sig::Animation::SetupPlayerAnimations(); sig::Animation::SetupPlayerAnimations();
view=TileTransformedView{GetScreenSize(),{1,1}}; view=TileTransformedView{GetScreenSize(),{1,1}};
LoadLevel(CAMPAIGN_1_1); LoadLevel(BOSS_1);
InitializeClasses(); InitializeClasses();
ChangePlayerClass(WARRIOR); ChangePlayerClass(WARRIOR);
Warrior::ability4=Ranger::ability1; //Class ability swapping demonstration. Warrior::ability4=Ranger::ability1; //Class ability swapping demonstration.
@ -1180,78 +1180,65 @@ int main()
} }
datafilestringdata operator ""_s(const char*key,std::size_t len){ datafilestringdata operator ""_s(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return {DATA,std::string(key,len)}; return {DATA,std::string(key,len)};
} }
datafileintdata operator ""_i(const char*key,std::size_t len){ datafileintdata operator ""_i(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return {DATA,std::string(key,len)}; return {DATA,std::string(key,len)};
} }
datafilefloatdata operator ""_f(const char*key,std::size_t len){ datafilefloatdata operator ""_f(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return {DATA,std::string(key,len)}; return {DATA,std::string(key,len)};
} }
datafiledoubledata operator ""_d(const char*key,std::size_t len){ datafiledoubledata operator ""_d(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return {DATA,std::string(key,len)}; return {DATA,std::string(key,len)};
} }
Pixel operator ""_Pixel(const char*key,std::size_t len){ Pixel operator ""_Pixel(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return {uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(0)),uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(1)),uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(2)),uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(3))}; return {uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(0)),uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(1)),uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(2)),uint8_t(DATA.GetProperty(std::string(key,len)).GetInt(3))};
} }
std::string operator ""_S(const char*key,std::size_t len){ std::string operator ""_S(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return DATA.GetProperty(std::string(key,len)).GetString(); return DATA.GetProperty(std::string(key,len)).GetString();
} }
int operator ""_I(const char*key,std::size_t len){ int operator ""_I(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return DATA.GetProperty(std::string(key,len)).GetInt(); return DATA.GetProperty(std::string(key,len)).GetInt();
} }
float operator ""_F(const char*key,std::size_t len){ float operator ""_F(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return DATA.GetProperty(std::string(key,len)).GetReal(); return DATA.GetProperty(std::string(key,len)).GetReal();
} }
float operator ""_FRange(const char*key,std::size_t len){ float operator ""_FRange(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
return util::random(DATA.GetProperty(std::string(key,len)).GetReal(1)-DATA.GetProperty(std::string(key,len)).GetReal(0))+DATA.GetProperty(std::string(key,len)).GetReal(0); return util::random(DATA.GetProperty(std::string(key,len)).GetReal(1)-DATA.GetProperty(std::string(key,len)).GetReal(0))+DATA.GetProperty(std::string(key,len)).GetReal(0);
} }
double operator ""_D(const char*key,std::size_t len){ double operator ""_D(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ Crawler::OutputDebugInfo(key,len);
std::cout<<std::string(key,len)<<std::endl;
}
return DATA.GetProperty(std::string(key,len)).GetReal(); return DATA.GetProperty(std::string(key,len)).GetReal();
} }
datafile operator ""_A(const char*key,std::size_t len){ datafile operator ""_A(const char*key,std::size_t len){
Crawler::OutputDebugInfo(key,len);
return DATA.GetProperty(std::string(key,len));
}
void Crawler::OutputDebugInfo(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){ if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<std::string(key,len)<<std::endl; std::string k=std::string(key);
if(!k.starts_with("debug_")){
std::cout<<"Reading "<<k<<std::endl;
}
} }
return DATA.GetProperty(std::string(key,len));
} }

@ -107,4 +107,5 @@ public:
datafilefloatdata GetFloatList(std::string key); datafilefloatdata GetFloatList(std::string key);
double GetDouble(std::string key); double GetDouble(std::string key);
datafiledoubledata GetDoubleList(std::string key); datafiledoubledata GetDoubleList(std::string key);
static void OutputDebugInfo(const char*key,std::size_t len);
}; };

@ -123,7 +123,8 @@
"Blue Slime", "Blue Slime",
"Red Slime", "Red Slime",
"Yellow Slime", "Yellow Slime",
"Flower Turret" "Flower Turret",
"Slime King"
], ],
"valuesAsFlags": false "valuesAsFlags": false
}, },

@ -10,6 +10,7 @@
#define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<Emitter>>EMITTER_LIST; #define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<Emitter>>EMITTER_LIST;
#define INCLUDE_DATA extern utils::datafile DATA; #define INCLUDE_DATA extern utils::datafile DATA;
#define INCLUDE_STRATEGY_DATA extern safemap<std::string,int>STRATEGY_DATA; #define INCLUDE_STRATEGY_DATA extern safemap<std::string,int>STRATEGY_DATA;
#define INCLUDE_STRATEGY_ID_DATA extern safemap<std::string,int>STRATEGY_ID_DATA;
#define ACCESS_PLAYER Player*p=game->GetPlayer(); #define ACCESS_PLAYER Player*p=game->GetPlayer();

@ -16,6 +16,7 @@ INCLUDE_DATA
INCLUDE_STRATEGY_DATA INCLUDE_STRATEGY_DATA
safemap<std::string,int>STRATEGY_DATA; safemap<std::string,int>STRATEGY_DATA;
safemap<int,std::string>STRATEGY_ID_DATA;
std::map<int,Renderable*>MonsterData::imgs; std::map<int,Renderable*>MonsterData::imgs;
Monster::Monster(vf2d pos,MonsterData data,bool upperLevel): Monster::Monster(vf2d pos,MonsterData data,bool upperLevel):
@ -108,6 +109,7 @@ bool Monster::SetY(float y){
} }
bool Monster::Update(float fElapsedTime){ bool Monster::Update(float fElapsedTime){
lastHitTimer=std::max(0.f,lastHitTimer-fElapsedTime); lastHitTimer=std::max(0.f,lastHitTimer-fElapsedTime);
iframe_timer=std::max(0.f,iframe_timer-fElapsedTime);
if(IsAlive()){ if(IsAlive()){
for(std::vector<Buff>::iterator it=buffList.begin();it!=buffList.end();++it){ for(std::vector<Buff>::iterator it=buffList.begin();it!=buffList.end();++it){
Buff&b=*it; Buff&b=*it;
@ -160,7 +162,7 @@ bool Monster::Update(float fElapsedTime){
SetY(pos.y+vel.y*fElapsedTime); SetY(pos.y+vel.y*fElapsedTime);
} }
} }
if(hp<=0){ if(!IsAlive()){
deathTimer+=fElapsedTime; deathTimer+=fElapsedTime;
if(deathTimer>3){ if(deathTimer>3){
return false; return false;
@ -227,7 +229,7 @@ std::string Monster::GetDeathAnimationName(){
return MONSTER_DATA[id].GetDeathAnimation(); return MONSTER_DATA[id].GetDeathAnimation();
} }
bool Monster::Hurt(int damage,bool onUpperLevel){ bool Monster::Hurt(int damage,bool onUpperLevel){
if(hp<=0||onUpperLevel!=OnUpperLevel()||HasIframes()) return false; if(!IsAlive()||onUpperLevel!=OnUpperLevel()||HasIframes()) return false;
float mod_dmg=damage; float mod_dmg=damage;
for(Buff&b:GetBuffs(BuffType::DAMAGE_REDUCTION)){ for(Buff&b:GetBuffs(BuffType::DAMAGE_REDUCTION)){
mod_dmg-=damage*b.intensity; mod_dmg-=damage*b.intensity;
@ -242,14 +244,17 @@ bool Monster::Hurt(int damage,bool onUpperLevel){
damageNumberPtr=numb; damageNumberPtr=numb;
} }
lastHitTimer=0.05; lastHitTimer=0.05;
if(hp<=0){ if(!IsAlive()){
animation.ChangeState(internal_animState,GetDeathAnimationName()); animation.ChangeState(internal_animState,GetDeathAnimationName());
} }
if(GetStrategy()=="Slime King"&&phase==5){
iframe_timer=iframeTimeUponHit;
}
return true; return true;
} }
bool Monster::IsAlive(){ bool Monster::IsAlive(){
return hp>0; return hp>0||!diesNormally;
} }
vf2d&Monster::GetTargetPos(){ vf2d&Monster::GetTargetPos(){
return target; return target;
@ -341,10 +346,13 @@ void Monster::SetState(State newState){
void Monster::InitializeStrategies(){ void Monster::InitializeStrategies(){
int readCounter=0; int readCounter=0;
while(DATA["MonsterStrategy"].HasProperty(std::to_string(readCounter))){ while(DATA["MonsterStrategy"].HasProperty(std::to_string(readCounter))){
STRATEGY_DATA[DATA["MonsterStrategy"][std::to_string(readCounter)]["Name"].GetString()]=readCounter; std::string strategyName=DATA["MonsterStrategy"][std::to_string(readCounter)]["Name"].GetString();
STRATEGY_DATA[strategyName]=readCounter;
STRATEGY_ID_DATA[readCounter]=strategyName;
readCounter++; readCounter++;
} }
STRATEGY_DATA.SetInitialized(); STRATEGY_DATA.SetInitialized();
STRATEGY_ID_DATA.SetInitialized();
} }
bool Monster::HasIframes(){ bool Monster::HasIframes(){
@ -354,3 +362,7 @@ bool Monster::HasIframes(){
float Monster::GetZ(){ float Monster::GetZ(){
return z; return z;
} }
std::string Monster::GetStrategy(){
return STRATEGY_ID_DATA[strategy];
}

@ -85,6 +85,9 @@ private:
int pathIndex=0; int pathIndex=0;
float lastHitTimer=0; float lastHitTimer=0;
std::shared_ptr<DamageNumber>damageNumberPtr; std::shared_ptr<DamageNumber>damageNumberPtr;
int phase=0;
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 iframeTimeUponHit=0;
protected: protected:
public: public:
Monster()=delete; Monster()=delete;
@ -128,6 +131,7 @@ public:
static void InitializeStrategies(); static void InitializeStrategies();
bool HasIframes(); bool HasIframes();
float GetZ(); float GetZ();
std::string GetStrategy();
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);

@ -332,7 +332,7 @@ void Player::Update(float fElapsedTime){
SetX(newX); SetX(newX);
SetY(newY); SetY(newY);
} }
if(attack_cooldown_timer==0&&game->GetMouse(0).bHeld){ if(CanAct()&&attack_cooldown_timer==0&&game->GetMouse(0).bHeld){
AutoAttack(); AutoAttack();
} }
@ -341,19 +341,21 @@ void Player::Update(float fElapsedTime){
//If pressed is set to false, uses held instead. //If pressed is set to false, uses held instead.
auto CheckAndPerformAbility=[&](Ability&ability,HWButton key){ auto CheckAndPerformAbility=[&](Ability&ability,HWButton key){
if(ability.name!="???"){ if(ability.name!="???"){
if(ability.cooldown==0&&GetMana()>=ability.manaCost){ if(CanAct()){
if(key.bHeld||key.bReleased&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){ if(ability.cooldown==0&&GetMana()>=ability.manaCost){
if(AllowedToCast(ability)&&ability.action(this,{})){ if(key.bHeld||key.bReleased&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){
ability.cooldown=ability.COOLDOWN_TIME; if(AllowedToCast(ability)&&ability.action(this,{})){
mana-=ability.manaCost; ability.cooldown=ability.COOLDOWN_TIME;
}else mana-=ability.manaCost;
if(ability.precastInfo.precastTargetingRequired&&GetState()==State::NORMAL){ }else
PrepareCast(ability); if(ability.precastInfo.precastTargetingRequired&&GetState()==State::NORMAL){
PrepareCast(ability);
}
} }
} else
if(ability.cooldown==0&&GetMana()<ability.manaCost&&key.bPressed){
notEnoughManaDisplay={ability.name,1};
} }
} else
if(ability.cooldown==0&&GetMana()<ability.manaCost&&key.bPressed){
notEnoughManaDisplay={ability.name,1};
} }
} }
}; };
@ -480,6 +482,10 @@ bool Player::CanMove(){
return state!=State::CASTING&&state!=State::ANIMATION_LOCK; return state!=State::CASTING&&state!=State::ANIMATION_LOCK;
} }
bool Player::CanAct(){
return state!=State::CASTING&&state!=State::ANIMATION_LOCK;
}
bool Player::HasIframes(){ bool Player::HasIframes(){
return iframe_time>0; return iframe_time>0;
} }

@ -129,6 +129,7 @@ public:
//The range is the search range in tiles. //The range is the search range in tiles.
bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8); bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8);
bool CanMove(); bool CanMove();
bool CanAct();
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);

@ -6,23 +6,23 @@ INCLUDE_DATA
int Monster::STRATEGY::_GetInt(Monster&m,std::string param,int strategyNumber,int index){ int Monster::STRATEGY::_GetInt(Monster&m,std::string param,int strategyNumber,int index){
if(DATA["Monsters"][std::to_string(m.id)].HasProperty(param)){ if(DATA["Monsters"][std::to_string(m.id)].HasProperty(param)){
return DATA["Monsters"][std::to_string(m.id)][param].GetInt(index); return DATA["Monsters"][std::to_string(m.id)].GetProperty(param).GetInt(index);
} else { } else {
return DATA["MonsterStrategy"][std::to_string(strategyNumber)][param].GetInt(index); return DATA["MonsterStrategy"][std::to_string(strategyNumber)].GetProperty(param).GetInt(index);
} }
} }
float Monster::STRATEGY::_GetFloat(Monster&m,std::string param,int strategyNumber,int index){ float Monster::STRATEGY::_GetFloat(Monster&m,std::string param,int strategyNumber,int index){
if(DATA["Monsters"][std::to_string(m.id)].HasProperty(param)){ if(DATA["Monsters"][std::to_string(m.id)].HasProperty(param)){
return DATA["Monsters"][std::to_string(m.id)][param].GetReal(index); return DATA["Monsters"][std::to_string(m.id)].GetProperty(param).GetReal(index);
} else { } else {
return DATA["MonsterStrategy"][std::to_string(strategyNumber)][param].GetReal(index); return DATA["MonsterStrategy"][std::to_string(strategyNumber)].GetProperty(param).GetReal(index);
} }
} }
std::string Monster::STRATEGY::_GetString(Monster&m,std::string param,int strategyNumber,int index){ std::string Monster::STRATEGY::_GetString(Monster&m,std::string param,int strategyNumber,int index){
if(DATA["Monsters"][std::to_string(m.id)].HasProperty(param)){ if(DATA["Monsters"][std::to_string(m.id)].HasProperty(param)){
return DATA["Monsters"][std::to_string(m.id)][param].GetString(index); return DATA["Monsters"][std::to_string(m.id)].GetProperty(param).GetString(index);
} else { } else {
return DATA["MonsterStrategy"][std::to_string(strategyNumber)][param].GetString(index); return DATA["MonsterStrategy"][std::to_string(strategyNumber)].GetProperty(param).GetString(index);
} }
} }

@ -8,5 +8,32 @@ INCLUDE_game
INCLUDE_BULLET_LIST INCLUDE_BULLET_LIST
void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber){ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber){
switch(m.phase){
case 0:{
m.size=ConfigInt("Phase1.Size")/100;
m.diesNormally=false;
m.iframeTimeUponHit=ConfigFloat("Phase5.IframeTimePerHit");
m.phase=1;
}break;
case 1:{
if(m.hp<=m.maxhp*ConfigFloat("Phase2.Change")/100){
m.phase=2;
}
}break;
case 2:{
if(m.hp<=m.maxhp*ConfigFloat("Phase3.Change")/100){
m.phase=3;
}
}break;
case 3:{
if(m.hp<=m.maxhp*ConfigFloat("Phase4.Change")/100){
m.phase=4;
}
}break;
case 4:{
if(m.hp<=0){
m.phase=5;
}
}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 1041 #define VERSION_BUILD 1057
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -36,7 +36,7 @@ bool Warrior::AutoAttack(){
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
if(m.IsAlive() if(m.IsAlive()
&&m.OnUpperLevel()==OnUpperLevel() &&m.OnUpperLevel()==OnUpperLevel()
&&geom2d::overlaps(geom2d::circle<float>(GetPos()-vf2d{GetSizeMult()*12,GetSizeMult()*12},attack_range*GetSizeMult()*12),geom2d::circle<float>(m.GetPos()-vf2d{m.GetSizeMult()*12,m.GetSizeMult()*12},m.GetSizeMult()*12)) &&geom2d::overlaps(geom2d::circle<float>(GetPos(),attack_range*GetSizeMult()*12),geom2d::circle<float>(m.GetPos(),m.GetSizeMult()*12))
&&geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length()<closest_dist){ &&geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length()<closest_dist){
closest_dist=geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length(); closest_dist=geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length();
closest=&m; closest=&m;

File diff suppressed because it is too large Load Diff

@ -5,7 +5,7 @@ Levels
WORLD_MAP = World_Map.tmx WORLD_MAP = World_Map.tmx
CAMPAIGN_1_1 = 1_1.tmx CAMPAIGN_1_1 = 1_1.tmx
BOSS_1 = Boss_1.tmx BOSS_1 = Boss_1_v2.tmx
CAMPAIGN_1_2 = 1_2.tmx CAMPAIGN_1_2 = 1_2.tmx
} }

@ -87,6 +87,7 @@ namespace olc::utils
{ {
if (nItem >= m_vContent.size()){ if (nItem >= m_vContent.size()){
std::cout<<"WARNING! Accesing out-of-bounds list item "<<nItem<<" of "<<lastAccessedProperty<<"!"<<std::endl; std::cout<<"WARNING! Accesing out-of-bounds list item "<<nItem<<" of "<<lastAccessedProperty<<"!"<<std::endl;
throw;
return ""; return "";
} }
else { else {

Loading…
Cancel
Save