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.

master
sigonasr2 3 weeks ago
parent 139d4f4eac
commit 7cf3c53e91
  1. 22
      Adventures in Lestoria/Arc.cpp
  2. 4
      Adventures in Lestoria/Arc.h
  3. 8
      Adventures in Lestoria/GiantOctopus.cpp
  4. 2
      Adventures in Lestoria/MonsterAttribute.h
  5. 66
      Adventures in Lestoria/OctopusArm.cpp
  6. 6
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  7. 11
      Adventures in Lestoria/util.cpp
  8. 2
      Adventures in Lestoria/util.h

@ -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};
@ -62,10 +77,3 @@ Arc::Arc(const vf2d pos,const float radius,const float pointingAngle,const float
}
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);
}

@ -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::polygon<float>poly;
};

@ -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;
}

@ -152,4 +152,6 @@ enum class Attribute{
SPEED_RAMPUP_TIMER,
BULLET_HAS_BEEN_SHOT,
SUCTION_TIMER,
STORED_ARC,
SWING_OCCURRED,
};

@ -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<Arc>(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<Arc>(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;
}
}

@ -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
}
}

@ -213,3 +213,14 @@ 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;
}

@ -39,6 +39,7 @@ All rights reserved.
#include <stdlib.h>
#include "olcUTIL_Geometry2D.h"
#include "olcPGEX_TTF.h"
#include "Direction.h"
#include <random>
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<class T,class U>

Loading…
Cancel
Save