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();
view=TileTransformedView{GetScreenSize(),{1,1}};
LoadLevel(CAMPAIGN_1_1);
LoadLevel(BOSS_1);
InitializeClasses();
ChangePlayerClass(WARRIOR);
Warrior::ability4=Ranger::ability1; //Class ability swapping demonstration.
@ -1180,78 +1180,65 @@ int main()
}
datafilestringdata operator ""_s(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return {DATA,std::string(key,len)};
}
datafileintdata operator ""_i(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return {DATA,std::string(key,len)};
}
datafilefloatdata operator ""_f(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return {DATA,std::string(key,len)};
}
datafiledoubledata operator ""_d(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return {DATA,std::string(key,len)};
}
Pixel operator ""_Pixel(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
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){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return DATA.GetProperty(std::string(key,len)).GetString();
}
int operator ""_I(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return DATA.GetProperty(std::string(key,len)).GetInt();
}
float operator ""_F(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return DATA.GetProperty(std::string(key,len)).GetReal();
}
float operator ""_FRange(const char*key,std::size_t len){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<"Reading "<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
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){
if(utils::datafile::DEBUG_ACCESS_OPTIONS){
std::cout<<std::string(key,len)<<std::endl;
}
Crawler::OutputDebugInfo(key,len);
return DATA.GetProperty(std::string(key,len)).GetReal();
}
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){
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);
double GetDouble(std::string key);
datafiledoubledata GetDoubleList(std::string key);
static void OutputDebugInfo(const char*key,std::size_t len);
};

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

@ -10,6 +10,7 @@
#define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<Emitter>>EMITTER_LIST;
#define INCLUDE_DATA extern utils::datafile 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();

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

@ -85,6 +85,9 @@ private:
int pathIndex=0;
float lastHitTimer=0;
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:
public:
Monster()=delete;
@ -128,6 +131,7 @@ public:
static void InitializeStrategies();
bool HasIframes();
float GetZ();
std::string GetStrategy();
private:
struct STRATEGY{
static int _GetInt(Monster&m,std::string param,int strategyNumber,int index=0);

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

@ -129,6 +129,7 @@ public:
//The range is the search range in tiles.
bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8);
bool CanMove();
bool CanAct();
void AddBuff(BuffType type,float duration,float intensity);
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){
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 {
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){
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 {
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){
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 {
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
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_MINOR 2
#define VERSION_PATCH 0
#define VERSION_BUILD 1041
#define VERSION_BUILD 1057
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -36,7 +36,7 @@ bool Warrior::AutoAttack(){
for(Monster&m:MONSTER_LIST){
if(m.IsAlive()
&&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){
closest_dist=geom2d::line<float>(game->GetWorldMousePos(),m.GetPos()).length();
closest=&m;

File diff suppressed because it is too large Load Diff

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

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

Loading…
Cancel
Save