Avoid aoe for game object

This commit is contained in:
Yunfan Li
2024-04-15 20:36:44 +08:00
parent 09ae42ea30
commit 56881c3a4d
4 changed files with 107 additions and 17 deletions

View File

@@ -3,6 +3,7 @@
*/ */
#include "MovementActions.h" #include "MovementActions.h"
#include "GameObject.h"
#include "Map.h" #include "Map.h"
#include "MotionMaster.h" #include "MotionMaster.h"
#include "MoveSplineInitArgs.h" #include "MoveSplineInitArgs.h"
@@ -13,6 +14,7 @@
#include "PlayerbotAIConfig.h" #include "PlayerbotAIConfig.h"
#include "Random.h" #include "Random.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "SpellInfo.h"
#include "TargetedMovementGenerator.h" #include "TargetedMovementGenerator.h"
#include "Event.h" #include "Event.h"
#include "LastMovementValue.h" #include "LastMovementValue.h"
@@ -1486,17 +1488,21 @@ bool FleeWithPetAction::Execute(Event event)
bool AvoidAoeAction::isUseful() bool AvoidAoeAction::isUseful()
{ {
return AI_VALUE(Aura*, "area debuff"); GuidVector traps = AI_VALUE(GuidVector, "nearest trap with damage");
return AI_VALUE(Aura*, "area debuff") || !traps.empty();
} }
bool AvoidAoeAction::Execute(Event event) bool AvoidAoeAction::Execute(Event event)
{ {
// Case #1: Aura with dynamic object // Case #1: Aura with dynamic object (e.g. rain of fire)
if (AvoidAuraWithDynamicObj()) { if (AvoidAuraWithDynamicObj()) {
return true; return true;
} }
// Case #2: Trap game object with spell // Case #2: Trap game object with spell (e.g. lava bomb)
// Case #3: Trigger npc if (AvoidGameObjectWithDamage()) {
return true;
}
// Case #3: Trigger npc (e.g. Lesser shadow fissure)
return false; return false;
} }
@@ -1506,10 +1512,11 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
if (!aura) { if (!aura) {
return false; return false;
} }
if (!aura->GetSpellInfo()) { const SpellInfo* spellInfo = aura->GetSpellInfo();
if (!spellInfo) {
return false; return false;
} }
if (!bot->HasAura(aura->GetSpellInfo()->Id)) { if (!bot->HasAura(spellInfo->Id)) {
return false; return false;
} }
DynamicObject* dynOwner = aura->GetDynobjOwner(); DynamicObject* dynOwner = aura->GetDynobjOwner();
@@ -1520,6 +1527,69 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
if (bot->GetDistance(dynOwner) > radius) { if (bot->GetDistance(dynOwner) > radius) {
return false; return false;
} }
std::ostringstream name;
name << "[" << spellInfo->SpellName[0] << "](aura)";
if (FleePostion(dynOwner->GetPosition(), radius, name.str())) {
return true;
}
return false;
}
bool AvoidAoeAction::AvoidGameObjectWithDamage()
{
GuidVector traps = AI_VALUE(GuidVector, "nearest trap with damage");
if (traps.empty()) {
return false;
}
for (ObjectGuid &guid : traps) {
GameObject* go = botAI->GetGameObject(guid);
if (!go || !go->IsInWorld()) {
continue;
}
if (go->GetGoType() != GAMEOBJECT_TYPE_TRAP)
{
continue;
}
const GameObjectTemplate* goInfo = go->GetGOInfo();
if (!goInfo)
{
continue;
}
uint32 spellId = goInfo->trap.spellId;
if (!spellId)
{
continue;
}
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (spellInfo->IsPositive()) {
continue;
}
float radius = 5.0f;
for (int i = 0; i < MAX_SPELL_EFFECTS; i++) {
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) {
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) {
radius = spellInfo->Effects[i].CalcRadius();
break;
}
} else if (spellInfo->Effects[i].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) {
break;
}
}
if (bot->GetDistance(go) > radius) {
return false;
}
std::ostringstream name;
name << "[" << spellInfo->SpellName[0] << "](object)";
if (FleePostion(go->GetPosition(), radius, name.str())) {
return true;
}
}
return false;
}
bool AvoidAoeAction::FleePostion(Position pos, float radius, std::string name)
{
Unit* currentTarget = AI_VALUE(Unit*, "current target"); Unit* currentTarget = AI_VALUE(Unit*, "current target");
std::vector<float> possibleAngles; std::vector<float> possibleAngles;
if (currentTarget) { if (currentTarget) {
@@ -1528,26 +1598,26 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
possibleAngles.push_back(angleLeft); possibleAngles.push_back(angleLeft);
possibleAngles.push_back(angleRight); possibleAngles.push_back(angleRight);
} else { } else {
float angleTo = bot->GetAngle(dynOwner) - M_PI; float angleTo = bot->GetAngle(&pos) - M_PI;
possibleAngles.push_back(angleTo); possibleAngles.push_back(angleTo);
} }
float farestDis = 0.0f; float farestDis = 0.0f;
Position bestPos; Position bestPos;
for (float &angle : possibleAngles) { for (float &angle : possibleAngles) {
float fleeDis = sPlayerbotAIConfig->fleeDistance; float fleeDis = sPlayerbotAIConfig->fleeDistance;
Position pos{bot->GetPositionX() + cos(angle) * fleeDis, Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis,
bot->GetPositionZ()}; bot->GetPositionZ()};
// todo (Yunfan): check carefully // todo (Yunfan): check carefully
if (dynOwner->GetExactDist(pos) > farestDis) { if (pos.GetExactDist(fleePos) > farestDis) {
farestDis = dynOwner->GetExactDist(pos); farestDis = pos.GetExactDist(fleePos);
bestPos = pos; bestPos = fleePos;
} }
} }
if (farestDis > 0.0f) { if (farestDis > 0.0f) {
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) {
std::ostringstream out; std::ostringstream out;
out << "I'm avoiding aoe spell [" << aura->GetSpellInfo()->SpellName[0] << "]..."; out << "I'm avoiding aoe spell " << name << "...";
bot->Say(out.str(), LANG_UNIVERSAL); bot->Say(out.str(), LANG_UNIVERSAL);
return true; return true;
} }

View File

@@ -76,6 +76,8 @@ class AvoidAoeAction : public MovementAction
protected: protected:
bool AvoidAuraWithDynamicObj(); bool AvoidAuraWithDynamicObj();
bool AvoidGameObjectWithDamage();
bool FleePostion(Position pos, float radius, std::string name);
}; };
class RunAwayAction : public MovementAction class RunAwayAction : public MovementAction

View File

@@ -8,6 +8,7 @@
#include "GridNotifiersImpl.h" #include "GridNotifiersImpl.h"
#include "Playerbots.h" #include "Playerbots.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "SpellMgr.h"
class AnyGameObjectInObjectRangeCheck class AnyGameObjectInObjectRangeCheck
{ {
@@ -58,15 +59,32 @@ GuidVector NearestTrapWithDamageValue::Calculate()
{ {
continue; continue;
} }
uint32 spellId = go->GetSpellId(); const GameObjectTemplate* goInfo = go->GetGOInfo();
if (!goInfo)
{
continue;
}
uint32 spellId = goInfo->trap.spellId;
if (!spellId) if (!spellId)
{ {
continue; continue;
} }
// if (ignoreLos || bot->IsWithinLOSInMap(go)) const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);
result.push_back(go->GetGUID()); if (spellInfo->IsPositive()) {
continue;
}
for (int i = 0; i < MAX_SPELL_EFFECTS; i++) {
if (spellInfo->Effects[i].Effect == SPELL_EFFECT_APPLY_AURA) {
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE) {
result.push_back(go->GetGUID());
break;
}
} else if (spellInfo->Effects[i].Effect == SPELL_EFFECT_SCHOOL_DAMAGE) {
result.push_back(go->GetGUID());
break;
}
}
} }
return result; return result;
} }

View File

@@ -27,7 +27,7 @@ class NearestGameObjects : public ObjectGuidListCalculatedValue
class NearestTrapWithDamageValue : public ObjectGuidListCalculatedValue class NearestTrapWithDamageValue : public ObjectGuidListCalculatedValue
{ {
public: public:
NearestTrapWithDamageValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) : NearestTrapWithDamageValue(PlayerbotAI* botAI, float range = 10.0f) :
ObjectGuidListCalculatedValue(botAI, "nearest trap with damage", 1 * 1000), range(range) { } ObjectGuidListCalculatedValue(botAI, "nearest trap with damage", 1 * 1000), range(range) { }
protected: protected: