mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Avoid aoe for game object
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user