Fix Pirate Buccaneer's aiming sight remaining on the field after death. Make aiming sight target line pulse. Fix bug with Frog Tongue one-shotting the player. Release Build 11815.

master
sigonasr2 2 months ago
parent c9a29b2705
commit f94d22ff48
  1. 3
      Adventures in Lestoria/FrogTongue.cpp
  2. 32
      Adventures in Lestoria/GiantOctopus.cpp
  3. 3
      Adventures in Lestoria/Monster.cpp
  4. 1
      Adventures in Lestoria/Monster.h
  5. 2
      Adventures in Lestoria/MonsterAttribute.h
  6. 7
      Adventures in Lestoria/OctopusArm.cpp
  7. 13
      Adventures in Lestoria/Pirate_Buccaneer.cpp
  8. 2
      Adventures in Lestoria/Version.h
  9. 2
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  10. BIN
      x64/Release/Adventures in Lestoria.exe

@ -61,8 +61,9 @@ void FrogTongue::Update(float fElapsedTime){
vf2d tongueEndPos=geom2d::line<float>(pos+drawVec,targetPos).upoint(pow(sin((lifetime*PI)/duration),20.f)); vf2d tongueEndPos=geom2d::line<float>(pos+drawVec,targetPos).upoint(pow(sin((lifetime*PI)/duration),20.f));
geom2d::line<float>tongueLine(pos+drawVec,tongueEndPos); geom2d::line<float>tongueLine(pos+drawVec,tongueEndPos);
if(!friendly&&geom2d::overlaps(game->GetPlayer()->Hitbox(),tongueLine)){ if(!friendly&&hitList.find(game->GetPlayer())==hitList.end()&&geom2d::overlaps(game->GetPlayer()->Hitbox(),tongueLine)){
_PlayerHit(game->GetPlayer()); _PlayerHit(game->GetPlayer());
hitList.insert(game->GetPlayer());
} }
if(friendly){ if(friendly){
for(std::shared_ptr<Monster>&m:MONSTER_LIST){ for(std::shared_ptr<Monster>&m:MONSTER_LIST){

@ -49,11 +49,18 @@ INCLUDE_MONSTER_LIST
void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string strategy){ void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string strategy){
enum PhaseName{ enum PhaseName{
INIT,
IDENTIFY_ARMS, IDENTIFY_ARMS,
NORMAL, NORMAL,
}; };
switch(PHASE()){ switch(PHASE()){
case INIT:{
m.F(A::BREAK_TIME)=0.5f;
SETPHASE(IDENTIFY_ARMS);
}break;
case IDENTIFY_ARMS:{ case IDENTIFY_ARMS:{
m.F(A::BREAK_TIME)-=fElapsedTime;
if(m.F(A::BREAK_TIME)<=0.f){
m.F(A::CASTING_TIMER)=util::random_range(ConfigFloatArr("Tentacle Move Timer",0),ConfigFloatArr("Tentacle Move Timer",1)); m.F(A::CASTING_TIMER)=util::random_range(ConfigFloatArr("Tentacle Move Timer",0),ConfigFloatArr("Tentacle Move Timer",1));
for(std::shared_ptr<Monster>&arm:MONSTER_LIST){ for(std::shared_ptr<Monster>&arm:MONSTER_LIST){
const std::string OCTOPUS_ARM_NAME{"Octopus Arm"}; const std::string OCTOPUS_ARM_NAME{"Octopus Arm"};
@ -63,22 +70,37 @@ void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string s
m.VEC(A::ARM_LOCATIONS).emplace_back(armPtr.lock()->GetPos()); m.VEC(A::ARM_LOCATIONS).emplace_back(armPtr.lock()->GetPos());
} }
} }
SETPHASE(NORMAL);
}
}break; }break;
case NORMAL:{ case NORMAL:{
m.F(A::CASTING_TIMER)-=fElapsedTime; m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)<=0.f){ if(m.F(A::CASTING_TIMER)<=0.f){
int deadMonsterCount{0}; int deadMonsterCount{0};
std::vector<vf2d>tempArmLocs; std::vector<vf2d>tempArmLocs;
for(size_t i=0U;std::any&arm:m.VEC(A::ARM_LIST)){ std::vector<std::any>liveArms{std::find_if(m.VEC(A::ARM_LIST).begin(),m.VEC(A::ARM_LIST).end(),[](const std::any&arm){
const std::weak_ptr<Monster>&m{std::any_cast<std::weak_ptr<Monster>>(arm)}; const std::weak_ptr<Monster>&m{std::any_cast<std::weak_ptr<Monster>>(arm)};
if(m.expired()||m.lock()->IsDead()){ return !m.expired()&&m.lock()->IsAlive();
})};
for(int index{0};std::any&arm:m.VEC(A::ARM_LIST)){
const std::weak_ptr<Monster>&armM{std::any_cast<std::weak_ptr<Monster>>(arm)};
if(armM.expired()||armM.lock()->IsDead()){
deadMonsterCount++; deadMonsterCount++;
tempArmLocs.emplace_back(std::any_cast<vf2d>(m.lock()->VEC(A::ARM_LOCATIONS))); if(!armM.expired())tempArmLocs.emplace_back(std::any_cast<vf2d>(armM.lock()->VEC(A::ARM_LOCATIONS)[index]));
} }
index++;
} }
if(deadMonsterCount>0){ const bool AtLeastOneArmAlive{deadMonsterCount!=m.VEC(A::ARM_LIST).size()};
if(deadMonsterCount>0&&AtLeastOneArmAlive){
const std::weak_ptr<Monster>&randomArm{std::any_cast<std::weak_ptr<Monster>>(liveArms[util::random()%liveArms.size()])};
const vf2d&randomLoc{std::any_cast<vf2d>(randomArm.lock()->VEC(A::ARM_LOCATIONS))};
randomArm.lock()->PerformAnimation("SUBMERGE");
randomArm.lock()->SetPhase(strategy,randomArm.lock()->I(A::SUBMERGE_STRAT_ID));
randomArm.lock()->GetFloat(A::RECOVERY_TIME)=randomArm.lock()->GetCurrentAnimation().GetTotalAnimationDuration();
randomArm.lock()->SetCollisionRadius(0.f);
randomArm.lock()->V(A::JUMP_TARGET_POS)=randomLoc;
} }
m.F(A::CASTING_TIMER)=util::random_range(ConfigFloatArr("Tentacle Move Timer",0),ConfigFloatArr("Tentacle Move Timer",1));
} }
}break; }break;
} }

@ -1669,3 +1669,6 @@ const float Monster::GetOriginalCollisionRadius()const{
void Monster::SetCollisionRadius(const float collisionRadius){ void Monster::SetCollisionRadius(const float collisionRadius){
this->collisionRadius=collisionRadius; this->collisionRadius=collisionRadius;
} }
void Monster::SetLifetime(const float lifetime){
this->lifetime=lifetime;
}

@ -198,6 +198,7 @@ public:
//If an object has a lifetime set, returns it. //If an object has a lifetime set, returns it.
const std::optional<float>GetLifetime()const; const std::optional<float>GetLifetime()const;
const std::optional<float>GetTotalLifetime()const; const std::optional<float>GetTotalLifetime()const;
void SetLifetime(const float lifetime);
//If an object has a collision radius, returns it. //If an object has a collision radius, returns it.
const float GetCollisionRadius()const; const float GetCollisionRadius()const;
const bool IsDead()const; const bool IsDead()const;

@ -156,4 +156,6 @@ enum class Attribute{
SWING_OCCURRED, SWING_OCCURRED,
ARM_LOCATIONS, ARM_LOCATIONS,
ARM_LIST, ARM_LIST,
SUBMERGE_LOCATION,
SUBMERGE_STRAT_ID,
}; };

@ -74,11 +74,12 @@ void Monster::STRATEGY::OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string str
switch(PHASE()){ switch(PHASE()){
case INIT:{ case INIT:{
m.I(A::SUBMERGE_STRAT_ID)=SUBMERGE;
if(ConfigFloat("Attack Swing Damage Wait Time")>m.GetAnimation("ATTACKING").GetTotalAnimationDuration())ERR(std::format("The Attack Swing Damage Wait Time ({}s) should not be greater than the total attack time animation duration! ({}s)",ConfigFloat("Attack Swing Damage Wait Time"),m.GetAnimation("ATTACKING").GetTotalAnimationDuration())); if(ConfigFloat("Attack Swing Damage Wait Time")>m.GetAnimation("ATTACKING").GetTotalAnimationDuration())ERR(std::format("The Attack Swing Damage Wait Time ({}s) should not be greater than the total attack time animation duration! ({}s)",ConfigFloat("Attack Swing Damage Wait Time"),m.GetAnimation("ATTACKING").GetTotalAnimationDuration()));
m.PerformAnimation("RISE",game->GetPlayer()->GetPos()); m.PerformAnimation("RISE",game->GetPlayer()->GetPos());
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration();
SETPHASE(RISE_ANIMATION); SETPHASE(RISE_ANIMATION);
m.SetStrategyDeathFunction([bossDamageOnDeath=ConfigInt("Boss Damage On Death")](GameEvent&event,Monster&m,const StrategyName&strategyName){ m.SetStrategyDeathFunction([deathFadeTime=ConfigFloat("Death Fade Time"),bossDamageOnDeath=ConfigInt("Boss Damage On Death")](GameEvent&event,Monster&m,const StrategyName&strategyName){
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){}); m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){});
const std::string GIANT_OCTOPUS_NAME{"Giant Octopus"}; const std::string GIANT_OCTOPUS_NAME{"Giant Octopus"};
const std::string OCTOPUS_ARM_NAME{"Octopus Arm"}; const std::string OCTOPUS_ARM_NAME{"Octopus Arm"};
@ -96,9 +97,12 @@ void Monster::STRATEGY::OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string str
if(m->GetName()==OCTOPUS_ARM_NAME){ if(m->GetName()==OCTOPUS_ARM_NAME){
m->PerformAnimation("SUBMERGE"); m->PerformAnimation("SUBMERGE");
m->SetPhase(strategyName,SUBMERGE); m->SetPhase(strategyName,SUBMERGE);
m->V(A::JUMP_TARGET_POS)=m->GetPos();
m->GetFloat(A::RECOVERY_TIME)=m->GetCurrentAnimation().GetTotalAnimationDuration(); m->GetFloat(A::RECOVERY_TIME)=m->GetCurrentAnimation().GetTotalAnimationDuration();
} }
}); });
m.SetLifetime(deathFadeTime);
return false; return false;
}); });
}break; }break;
@ -171,6 +175,7 @@ void Monster::STRATEGY::OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string str
m.F(A::RECOVERY_TIME)-=fElapsedTime; m.F(A::RECOVERY_TIME)-=fElapsedTime;
if(m.F(A::RECOVERY_TIME)<=0.f){ if(m.F(A::RECOVERY_TIME)<=0.f){
m.PerformAnimation("RISE"); m.PerformAnimation("RISE");
m.SetPos(m.V(A::JUMP_TARGET_POS));
m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); m.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration();
SETPHASE(RISE_ANIMATION); SETPHASE(RISE_ANIMATION);
} }

@ -49,6 +49,7 @@ INCLUDE_game
void Monster::STRATEGY::PIRATE_BUCCANEER(Monster&m,float fElapsedTime,std::string strategy){ void Monster::STRATEGY::PIRATE_BUCCANEER(Monster&m,float fElapsedTime,std::string strategy){
#pragma region Phase, Animation, and Helper function setup #pragma region Phase, Animation, and Helper function setup
enum PhaseName{ enum PhaseName{
INIT,
MOVE, MOVE,
LOCKON, LOCKON,
WINDUP, WINDUP,
@ -57,6 +58,13 @@ void Monster::STRATEGY::PIRATE_BUCCANEER(Monster&m,float fElapsedTime,std::strin
#pragma endregion #pragma endregion
switch(PHASE()){ switch(PHASE()){
case INIT:{
m.SetStrategyDeathFunction([](GameEvent&ev,Monster&m,const std::string&strategy){
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){});
return false;
});
SETPHASE(MOVE);
}break;
case MOVE:{ case MOVE:{
m.F(A::ATTACK_COOLDOWN)+=fElapsedTime; m.F(A::ATTACK_COOLDOWN)+=fElapsedTime;
@ -100,10 +108,13 @@ void Monster::STRATEGY::PIRATE_BUCCANEER(Monster&m,float fElapsedTime,std::strin
m.PerformAnimation("SHOOT",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); m.PerformAnimation("SHOOT",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));
const float arrowHitboxRadius{ConfigFloat("Arrow Hitbox Radius")}; const float arrowHitboxRadius{ConfigFloat("Arrow Hitbox Radius")};
m.SetStrategyDrawFunction([arrowHitboxRadius](AiL*game,Monster&monster,const std::string&strategy){ m.SetStrategyDrawFunction([arrowHitboxRadius](AiL*game,Monster&monster,const std::string&strategy){
const float alphaTimer{float(std::fmod(game->GetRunTime(),2.f))};
uint8_t alpha{util::lerp(uint8_t(0),uint8_t(255),alphaTimer)};
if(alphaTimer>1.f)alpha=util::lerp(0,255,1-(alphaTimer-1));
vf2d midpoint{geom2d::line<float>(monster.GetPos(),monster.V(A::LOCKON_POS)).rpoint(800.f)}; vf2d midpoint{geom2d::line<float>(monster.GetPos(),monster.V(A::LOCKON_POS)).rpoint(800.f)};
float shootingAngle{util::angleTo(monster.GetPos(),monster.V(A::LOCKON_POS))+PI/2}; float shootingAngle{util::angleTo(monster.GetPos(),monster.V(A::LOCKON_POS))+PI/2};
vf2d imgSize{arrowHitboxRadius*2.f,800.f}; vf2d imgSize{arrowHitboxRadius*2.f,800.f};
game->view.DrawPartialRotatedDecal(midpoint,GFX["line_indicator.png"].Decal(),shootingAngle,GFX["line_indicator.png"].Sprite()->Size()/2,{},GFX["line_indicator.png"].Sprite()->Size(),imgSize/GFX["line_indicator.png"].Sprite()->Size()); game->view.DrawPartialRotatedDecal(midpoint,GFX["line_indicator.png"].Decal(),shootingAngle,GFX["line_indicator.png"].Sprite()->Size()/2,{},GFX["line_indicator.png"].Sprite()->Size(),imgSize/GFX["line_indicator.png"].Sprite()->Size(),{255,255,255,uint8_t(alpha)});
}); });
} }
}break; }break;

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 3 #define VERSION_MINOR 3
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 11808 #define VERSION_BUILD 11815
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -1217,6 +1217,8 @@ MonsterStrategy
# Amount of time the spreading aftershock effect appears for. # Amount of time the spreading aftershock effect appears for.
Attack Effect Time = 0.4s Attack Effect Time = 0.4s
Death Fade Time = 1s
} }
Giant Octopus Giant Octopus
{ {

Loading…
Cancel
Save