From 7cf3c53e913ae9e72eb189a2e1ea64f16089b0bf Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Tue, 5 Nov 2024 20:58:36 -0800 Subject: [PATCH] Fix all octopus arm AI config variable references to actually use the Config functions instead of direct config file parameters. Add in attack cone effect. --- Adventures in Lestoria/Arc.cpp | 22 +++++-- Adventures in Lestoria/Arc.h | 4 +- Adventures in Lestoria/GiantOctopus.cpp | 10 +-- Adventures in Lestoria/MonsterAttribute.h | 2 + Adventures in Lestoria/OctopusArm.cpp | 66 ++++++++++++------- .../assets/config/MonsterStrategies.txt | 6 ++ Adventures in Lestoria/util.cpp | 11 ++++ Adventures in Lestoria/util.h | 2 + 8 files changed, 85 insertions(+), 38 deletions(-) diff --git a/Adventures in Lestoria/Arc.cpp b/Adventures in Lestoria/Arc.cpp index c1ea08c7..65a0115f 100644 --- a/Adventures in Lestoria/Arc.cpp +++ b/Adventures in Lestoria/Arc.cpp @@ -44,6 +44,21 @@ INCLUDE_game Arc::Arc(const vf2d pos,const float radius,const float pointingAngle,const float sweepAngle) :pos(pos),radius(radius),pointingAngle(pointingAngle),sweepAngle(sweepAngle){ if(sweepAngle<0.f)ERR(std::format("WARNING! Sweep angle must be greater than or equal to 0! Provided Sweep Angle: {}",sweepAngle)); + GenerateArc(); +} +void Arc::Draw(AiL*game,const Pixel col){ + game->SetDecalStructure(DecalStructure::FAN); + game->view.DrawPolygonDecal(nullptr,poly.pos,poly.pos,col); +} +const bool Arc::overlaps(const vf2d checkPos)const{ + return geom2d::overlaps(checkPos,poly); +} +void Arc::GrowRadius(const float growAmt){ + radius+=growAmt; + GenerateArc(); +} +void Arc::GenerateArc(){ + poly.pos.clear(); //Use cut-off point between two angles poly.pos.emplace_back(pos); //Always add 0,0 float smallestAng{util::radToDeg(pointingAngle-sweepAngle)+90}; @@ -61,11 +76,4 @@ Arc::Arc(const vf2d pos,const float radius,const float pointingAngle,const float poly.pos.emplace_back(pos+game->circleCooldownPoints[i]*radius); } poly.pos.emplace_back(pos); //Connect back to itself. -} -void Arc::Draw(AiL*game,const Pixel col){ - game->SetDecalStructure(DecalStructure::FAN); - game->view.DrawPolygonDecal(nullptr,poly.pos,poly.pos,col); -} -const bool Arc::overlaps(const vf2d checkPos)const{ - return geom2d::overlaps(checkPos,poly); } \ No newline at end of file diff --git a/Adventures in Lestoria/Arc.h b/Adventures in Lestoria/Arc.h index fe04bb6c..759fa096 100644 --- a/Adventures in Lestoria/Arc.h +++ b/Adventures in Lestoria/Arc.h @@ -48,10 +48,12 @@ public: Arc(const vf2d pos,const float radius,const float pointingAngle,const float sweepAngle); void Draw(AiL*game,const Pixel col); const bool overlaps(const vf2d checkPos)const; + void GrowRadius(const float growAmt); private: + void GenerateArc(); const vf2d pos; const float pointingAngle; const float sweepAngle; - const float radius; + float radius; geom2d::polygonpoly; }; \ No newline at end of file diff --git a/Adventures in Lestoria/GiantOctopus.cpp b/Adventures in Lestoria/GiantOctopus.cpp index aed661c4..157f27b2 100644 --- a/Adventures in Lestoria/GiantOctopus.cpp +++ b/Adventures in Lestoria/GiantOctopus.cpp @@ -48,14 +48,14 @@ INCLUDE_game void Monster::STRATEGY::GIANT_OCTOPUS(Monster&m,float fElapsedTime,std::string strategy){ enum PhaseName{ - RUN, - FLY_AWAY, + IDENTIFY_ARMS, + NORMAL, }; switch(PHASE()){ - case RUN:{ - + case IDENTIFY_ARMS:{ + }break; - case FLY_AWAY:{ + case NORMAL:{ }break; } diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h index 6ab639f7..8adbc06f 100644 --- a/Adventures in Lestoria/MonsterAttribute.h +++ b/Adventures in Lestoria/MonsterAttribute.h @@ -152,4 +152,6 @@ enum class Attribute{ SPEED_RAMPUP_TIMER, BULLET_HAS_BEEN_SHOT, SUCTION_TIMER, + STORED_ARC, + SWING_OCCURRED, }; \ No newline at end of file diff --git a/Adventures in Lestoria/OctopusArm.cpp b/Adventures in Lestoria/OctopusArm.cpp index c2577d93..a3a17bfb 100644 --- a/Adventures in Lestoria/OctopusArm.cpp +++ b/Adventures in Lestoria/OctopusArm.cpp @@ -53,29 +53,23 @@ void Monster::STRATEGY::OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string str RISE_ANIMATION, SEARCH, PREPARE_ATTACK, + ATTACK_ANIMATION, }; - const auto GetAttackArc=[](const Monster&m){ - float arcAngle{}; - switch(m.GetFacingDirection()){ - case Direction::NORTH:{ - arcAngle=-PI/2; - }break; - case Direction::EAST:{ - arcAngle=0.f; - }break; - case Direction::WEST:{ - arcAngle=PI; - }break; - case Direction::SOUTH:{ - arcAngle=PI/2; - }break; - } - return Arc{m.GetPos(),"Attack Radius"_F/100.f*24,arcAngle,util::degToRad("Attack Arc"_F)}; + const auto GetAttackArc=[attackRadius=ConfigFloat("Attack Radius"),attackArc=ConfigFloat("Attack Arc")](const Monster&m){ + return Arc{m.GetPos(),attackRadius/100.f*24,util::dirToAngle(m.GetFacingDirection()),util::degToRad(attackArc)}; }; + if(m.ANY(A::STORED_ARC).has_value()){ + const float growthRate=((ConfigFloat("Attack Radius")/100.f*24)/ConfigFloat("Attack Effect Time"))*fElapsedTime; + std::any_cast(m.ANY(A::STORED_ARC)).GrowRadius(growthRate); + m.F(A::ENVIRONMENT_TIMER)-=fElapsedTime; + if(m.F(A::ENVIRONMENT_TIMER)<=0.f)m.ANY(A::STORED_ARC).reset(); + } + switch(PHASE()){ case INIT:{ + 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.F(A::CASTING_TIMER)=m.GetCurrentAnimation().GetTotalAnimationDuration(); SETPHASE(RISE_ANIMATION); @@ -88,30 +82,52 @@ void Monster::STRATEGY::OCTOPUS_ARM(Monster&m,float fElapsedTime,std::string str } }break; case SEARCH:{ - if(util::distance(m.GetPos(),game->GetPlayer()->GetPos())<="Attack Radius"_F/100.f*24){ + if(util::distance(m.GetPos(),game->GetPlayer()->GetPos())<=ConfigFloat("Attack Radius")/100.f*24){ SETPHASE(PREPARE_ATTACK); - m.F(A::ATTACK_COOLDOWN)="Attack Wiggle Time Range"_FRange; - m.PerformAnimation("ATTACKING",game->GetPlayer()->GetPos()); + + m.F(A::ATTACK_COOLDOWN)=util::random_range(ConfigFloatArr("Attack Wiggle Time Range",0),ConfigFloatArr("Attack Wiggle Time Range",1)); + m.PerformAnimation("ATTACK",game->GetPlayer()->GetPos()); Arc attackArc{GetAttackArc(m)}; - m.SetStrategyDrawFunction([&attackArc](AiL*game,Monster&monster,const std::string&strategy){ + m.SetStrategyDrawFunction([&attackArc,&storedArc=m.ANY(A::STORED_ARC),&alphaTimer=m.F(A::ENVIRONMENT_TIMER),attackEffectTime=ConfigFloat("Attack Effect Time")](AiL*game,Monster&monster,const std::string&strategy){ const float alphaTimer{std::fmod(game->GetRunTime(),2.f)}; uint8_t alpha{util::lerp(0,255,alphaTimer)}; if(alphaTimer>1.f)alpha=util::lerp(0,255,1-(alphaTimer-1)); attackArc.Draw(game,{0,0,255,uint8_t(alpha)}); + if(storedArc.has_value()){ + const uint8_t effectAlpha{util::lerp(0,255,alphaTimer/attackEffectTime)}; + std::any_cast(storedArc).Draw(game,{255,255,255,effectAlpha}); + } }); } }break; case PREPARE_ATTACK:{ m.F(A::ATTACK_COOLDOWN)-=fElapsedTime; if(m.F(A::ATTACK_COOLDOWN)<=0.f){ - Arc attackArc{GetAttackArc(m)}; - if(attackArc.overlaps(game->GetPlayer()->GetPos())){ - game->GetPlayer()->Knockback(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*"Attack Knockback"_F); - game->GetPlayer()->Hurt(m.GetAttack(),m.OnUpperLevel(),m.GetZ()); + m.PerformAnimation("ATTACKING"); + m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Attack Effect Time"); + m.F(A::SWING_OCCURRED)=ConfigFloat("Attack Swing Damage Wait Time"); + } + }break; + case ATTACK_ANIMATION:{ + m.F(A::RECOVERY_TIME)-=fElapsedTime; + if(m.F(A::SWING_OCCURRED)>0.f){ + m.F(A::SWING_OCCURRED)-=fElapsedTime; + if(m.F(A::SWING_OCCURRED)<=0.f){ + Arc attackArc{GetAttackArc(m)}; + if(attackArc.overlaps(game->GetPlayer()->GetPos())){ + game->GetPlayer()->Knockback(util::pointTo(m.GetPos(),game->GetPlayer()->GetPos())*ConfigFloat("Attack Knockback")); + game->GetPlayer()->Hurt(m.GetAttack(),m.OnUpperLevel(),m.GetZ()); + } + m.F(A::RECOVERY_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration(); + m.ANY(A::STORED_ARC)=GetAttackArc(m); } } + if(m.F(A::RECOVERY_TIME)<=0.f){ + m.PerformIdleAnimation(); + SETPHASE(SEARCH); + } }break; } } \ No newline at end of file diff --git a/Adventures in Lestoria/assets/config/MonsterStrategies.txt b/Adventures in Lestoria/assets/config/MonsterStrategies.txt index df9e822f..4ecf95ae 100644 --- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt +++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt @@ -1208,6 +1208,12 @@ MonsterStrategy Attack Arc = 60deg Attack Wait Time = 1s + # For synchronization purposes. Damage doesn't come out until this amount of time has passed in the animation. + Attack Swing Damage Wait Time = 0.45s + Attack Knockback = 50 + + # Amount of time the spreading aftershock effect appears for. + Attack Effect Time = 0.4s } } \ No newline at end of file diff --git a/Adventures in Lestoria/util.cpp b/Adventures in Lestoria/util.cpp index 2400b4b1..eff52455 100644 --- a/Adventures in Lestoria/util.cpp +++ b/Adventures in Lestoria/util.cpp @@ -212,4 +212,15 @@ void util::turn_towards_direction(float&angle,float target,float rate) std::wstring util::to_wstring(const std::string&str){ return {str.begin(),str.end()}; +} + +const float util::dirToAngle(const Direction dir){ + switch(dir){ + case Direction::NORTH:return -PI/2;break; + case Direction::EAST:return 0.f;break; + case Direction::WEST:return PI;break; + case Direction::SOUTH:return PI/2;break; + } + ERR(std::format("WARNING! Could not find Direction {}! THIS SHOULD NOT BE HAPPENING!",int(dir))); + return 0.f; } \ No newline at end of file diff --git a/Adventures in Lestoria/util.h b/Adventures in Lestoria/util.h index 18f34aa5..34b8f461 100644 --- a/Adventures in Lestoria/util.h +++ b/Adventures in Lestoria/util.h @@ -39,6 +39,7 @@ All rights reserved. #include #include "olcUTIL_Geometry2D.h" #include "olcPGEX_TTF.h" +#include "Direction.h" #include namespace olc::util{ @@ -54,6 +55,7 @@ namespace olc::util{ float angleTo(vf2d posFrom,vf2d posTo); float degToRad(float deg); float radToDeg(float rad); + const float dirToAngle(const Direction dir); #pragma region Lerp templates + specializations template