diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index d4419670..d701b293 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -155,22 +155,25 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, !bot->IsFlying() && !bot->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING) && !bot->IsInWater(); if (!generatePath) { float distance = bot->GetExactDist(x, y, z); - WaitForReach(distance); - - if (bot->IsSitState()) - bot->SetStandState(UNIT_STAND_STATE_STAND); - - if (bot->IsNonMeleeSpellCast(true)) + if (distance > sPlayerbotAIConfig->contactDistance) { - bot->CastStop(); - botAI->InterruptSpell(); + WaitForReach(distance); + + if (bot->IsSitState()) + bot->SetStandState(UNIT_STAND_STATE_STAND); + + if (bot->IsNonMeleeSpellCast(true)) + { + bot->CastStop(); + botAI->InterruptSpell(); + } + MotionMaster &mm = *bot->GetMotionMaster(); + + mm.Clear(); + mm.MovePoint(mapId, x, y, z, generatePath); + AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); + return true; } - MotionMaster &mm = *bot->GetMotionMaster(); - - mm.Clear(); - mm.MovePoint(mapId, x, y, z, generatePath); - AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); - return true; } else { float modifiedZ; Movement::PointsArray path = SearchForBestPath(x, y, z, modifiedZ, sPlayerbotAIConfig->maxMovementSearchTime); @@ -197,7 +200,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation()); return true; } - } return false; @@ -1484,11 +1486,62 @@ bool FleeWithPetAction::Execute(Event event) bool AvoidAoeAction::isUseful() { - return false; + return AI_VALUE(Aura*, "area debuff"); } bool AvoidAoeAction::Execute(Event event) { + // Case #1: Aura with dynamic object + Aura* aura = AI_VALUE(Aura*, "area debuff"); + if (!aura) { + return false; + } + if (!aura->GetSpellInfo()) { + return false; + } + if (!bot->HasAura(aura->GetSpellInfo()->Id)) { + return false; + } + DynamicObject* dynOwner = aura->GetDynobjOwner(); + if (!dynOwner || !dynOwner->IsInWorld()) { + return false; + } + float radius = dynOwner->GetRadius(); + if (bot->GetExactDist(dynOwner) > radius) { + return false; + } + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + std::vector possibleAngles; + if (currentTarget) { + float angleLeft = bot->GetAngle(currentTarget) + M_PI / 2; + float angleRight = bot->GetAngle(currentTarget) - M_PI / 2; + possibleAngles.push_back(angleLeft); + possibleAngles.push_back(angleRight); + } else { + float angleTo = bot->GetAngle(dynOwner) - M_PI; + possibleAngles.push_back(angleTo); + } + float farestDis = 0.0f; + Position bestPos; + // float disToDyn = bot->GetExactDist(dynOwner); + // float maxDisToGo = radius > disToDyn ? std::sqrt(radius * radius - disToDyn * disToDyn) + 0.5f : 0.5f; + for (float &angle : possibleAngles) { + float fleeDis = sPlayerbotAIConfig->fleeDistance; + Position pos{bot->GetPositionX() + cos(angle) * fleeDis, + bot->GetPositionY() + sin(angle) * fleeDis, + bot->GetPositionZ()}; + // todo(Yunfan): check carefully + if (dynOwner->GetExactDist(pos) > farestDis) { + farestDis = dynOwner->GetExactDist(pos); + bestPos = pos; + } + } + if (farestDis > 0.0f) { + std::ostringstream out; + out << "I'm avoiding aoe spell [" << aura->GetSpellInfo()->SpellName[0] << "]..."; + bot->Say(out.str(), LANG_UNIVERSAL); + return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true); + } return false; } diff --git a/src/strategy/actions/TellLosAction.cpp b/src/strategy/actions/TellLosAction.cpp index 6d7df103..234bebcc 100644 --- a/src/strategy/actions/TellLosAction.cpp +++ b/src/strategy/actions/TellLosAction.cpp @@ -37,6 +37,11 @@ bool TellLosAction::Execute(Event event) ListUnits("--- Friendly players ---", *context->GetValue("nearest friendly players")); } + if (param.empty() || param == "triggers") + { + ListUnits("--- Triggers ---", *context->GetValue("possible triggers")); + } + return true; } @@ -46,8 +51,9 @@ void TellLosAction::ListUnits(std::string const title, GuidVector units) for (ObjectGuid const guid : units) { - if (Unit* unit = botAI->GetUnit(guid)) + if (Unit* unit = botAI->GetUnit(guid)) { botAI->TellMaster(unit->GetName()); + } } } diff --git a/src/strategy/values/AoeValues.cpp b/src/strategy/values/AoeValues.cpp index 67f7d1e0..3d93640c 100644 --- a/src/strategy/values/AoeValues.cpp +++ b/src/strategy/values/AoeValues.cpp @@ -116,4 +116,27 @@ bool HasAreaDebuffValue::Calculate() } return false; +} + +Aura* AreaDebuffValue::Calculate() +{ + Unit::AuraApplicationMap& map = bot->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator i = map.begin(); i != map.end(); ++i) + { + Aura *aura = i->second->GetBase(); + if (!aura) + continue; + + AuraObjectType type = aura->GetType(); + // bool is_area = aura->IsArea(); + bool isPositive = aura->GetSpellInfo()->IsPositive(); + if (type == DYNOBJ_AURA_TYPE && !isPositive) { + DynamicObject* dynOwner = aura->GetDynobjOwner(); + if (!dynOwner) { + continue; + } + return aura; + } + } + return nullptr; } \ No newline at end of file diff --git a/src/strategy/values/AoeValues.h b/src/strategy/values/AoeValues.h index 04ca3f37..a6cde02a 100644 --- a/src/strategy/values/AoeValues.h +++ b/src/strategy/values/AoeValues.h @@ -41,4 +41,13 @@ class HasAreaDebuffValue : public BoolCalculatedValue, public Qualified virtual bool Calculate(); }; +class AreaDebuffValue : public CalculatedValue +{ + public: + AreaDebuffValue(PlayerbotAI* botAI) : + CalculatedValue(botAI, "area debuff", 1 * 1000) { } + + Aura* Calculate() override; +}; + #endif diff --git a/src/strategy/values/ExpectedLifetimeValue.h b/src/strategy/values/ExpectedLifetimeValue.h index 65780bed..8b5e994d 100644 --- a/src/strategy/values/ExpectedLifetimeValue.h +++ b/src/strategy/values/ExpectedLifetimeValue.h @@ -34,13 +34,4 @@ class ExpectedGroupDpsValue : public FloatCalculatedValue float Calculate() override; }; -class AreaDebuffValue : public CalculatedValue -{ - public: - AreaDebuffValue(PlayerbotAI* botAI) : - CalculatedValue(botAI, "area debuff", 20 * 1000) { } - - Aura* Calculate() override; -}; - #endif diff --git a/src/strategy/values/PossibleTargetsValue.cpp b/src/strategy/values/PossibleTargetsValue.cpp index 50e29788..729c0ae0 100644 --- a/src/strategy/values/PossibleTargetsValue.cpp +++ b/src/strategy/values/PossibleTargetsValue.cpp @@ -8,6 +8,7 @@ #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "Playerbots.h" +#include "Unit.h" void PossibleTargetsValue::FindUnits(std::list& targets) { @@ -20,3 +21,17 @@ bool PossibleTargetsValue::AcceptUnit(Unit* unit) { return AttackersValue::IsPossibleTarget(unit, bot, range); } + +void PossibleTriggersValue::FindUnits(std::list& targets) +{ + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(bot, bot, range); + Acore::UnitListSearcher searcher(bot, targets, u_check); + Cell::VisitAllObjects(bot, searcher, range); +} + +bool PossibleTriggersValue::AcceptUnit(Unit* unit) +{ + return unit->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) && unit->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + return true; // AttackersValue::IsPossibleTarget(unit, bot, range); +} + diff --git a/src/strategy/values/PossibleTargetsValue.h b/src/strategy/values/PossibleTargetsValue.h index e52b653a..81cd2bd3 100644 --- a/src/strategy/values/PossibleTargetsValue.h +++ b/src/strategy/values/PossibleTargetsValue.h @@ -27,4 +27,14 @@ class AllTargetsValue : public PossibleTargetsValue AllTargetsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance) : PossibleTargetsValue(botAI, "all targets", range, true) { } }; +class PossibleTriggersValue : public NearestUnitsValue +{ + public: + PossibleTriggersValue(PlayerbotAI* botAI, std::string const name = "possible targets", float range = sPlayerbotAIConfig->sightDistance, bool ignoreLos = true): + NearestUnitsValue(botAI, name, range, ignoreLos) { } + + protected: + void FindUnits(std::list& targets) override; + bool AcceptUnit(Unit* unit) override; +}; #endif diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index c90dbd49..9cba19d4 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -110,6 +110,7 @@ class ValueContext : public NamedObjectContext creators["nearest enemy players"] = &ValueContext::nearest_enemy_players; creators["possible targets"] = &ValueContext::possible_targets; creators["possible targets no los"] = &ValueContext::possible_targets_no_los; + creators["possible triggers"] = &ValueContext::possible_triggers; creators["possible adds"] = &ValueContext::possible_adds; creators["all targets"] = &ValueContext::all_targets; creators["possible rpg targets"] = &ValueContext::possible_rpg_targets; @@ -377,6 +378,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* nearest_corpses(PlayerbotAI* botAI) { return new NearestCorpsesValue(botAI); } static UntypedValue* possible_rpg_targets(PlayerbotAI* botAI) { return new PossibleRpgTargetsValue(botAI); } static UntypedValue* possible_targets(PlayerbotAI* botAI) { return new PossibleTargetsValue(botAI); } + static UntypedValue* possible_triggers(PlayerbotAI* botAI) { return new PossibleTriggersValue(botAI); } static UntypedValue* possible_targets_no_los(PlayerbotAI* botAI) { return new PossibleTargetsValue(botAI, "possible targets", sPlayerbotAIConfig->sightDistance, true); } static UntypedValue* possible_adds(PlayerbotAI* botAI) { return new PossibleAddsValue(botAI); } static UntypedValue* all_targets(PlayerbotAI* botAI) { return new AllTargetsValue(botAI); }