diff --git a/src/modules/Bots/CMakeLists.txt b/src/modules/Bots/CMakeLists.txt index bec1259a5..d8a3446f8 100644 --- a/src/modules/Bots/CMakeLists.txt +++ b/src/modules/Bots/CMakeLists.txt @@ -72,6 +72,8 @@ set(BOT_SRCS playerbot/strategy/actions/BuyAction.h playerbot/strategy/actions/CastCustomSpellAction.cpp playerbot/strategy/actions/CastCustomSpellAction.h + playerbot/strategy/actions/CcActions.h + playerbot/strategy/actions/CcActions.cpp playerbot/strategy/actions/ChangeChatAction.cpp playerbot/strategy/actions/ChangeChatAction.h playerbot/strategy/actions/ChangeStrategyAction.cpp @@ -486,6 +488,8 @@ set(BOT_SRCS playerbot/strategy/values/AttackerWithoutAuraTargetValue.cpp playerbot/strategy/values/AttackerWithoutAuraTargetValue.h playerbot/strategy/values/AvailableLootValue.h + playerbot/strategy/values/CcReachTargetValue.cpp + playerbot/strategy/values/CcReachTargetValue.h playerbot/strategy/values/CcTargetValue.cpp playerbot/strategy/values/CcTargetValue.h playerbot/strategy/values/ChatValue.h diff --git a/src/modules/Bots/playerbot/strategy/actions/ActionContext.h b/src/modules/Bots/playerbot/strategy/actions/ActionContext.h index ac61da133..cdc308e38 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ActionContext.h +++ b/src/modules/Bots/playerbot/strategy/actions/ActionContext.h @@ -16,6 +16,7 @@ #include "PullActions.h" #include "FishWithMasterAction.h" #include "RestoreWeaponsAction.h" +#include "CcActions.h" namespace ai { @@ -87,6 +88,7 @@ namespace ai creators["fish with master"] = &ActionContext::fish_with_master; creators["restore weapons"] = &ActionContext::restore_weapons; creators["swim to surface"] = &ActionContext::swim_to_surface; + creators["cc reach spell"] = &ActionContext::cc_reach_spell; } private: @@ -152,6 +154,7 @@ namespace ai static Action* fish_with_master(PlayerbotAI* ai) { return new FishWithMasterAction(ai); } static Action* restore_weapons(PlayerbotAI* ai) { return new RestoreWeaponsAction(ai); } static Action* swim_to_surface(PlayerbotAI* ai) { return new SwimToSurfaceAction(ai); } + static Action* cc_reach_spell(PlayerbotAI* ai) { return new CcReachSpellAction(ai); } }; }; diff --git a/src/modules/Bots/playerbot/strategy/actions/CcActions.cpp b/src/modules/Bots/playerbot/strategy/actions/CcActions.cpp new file mode 100644 index 000000000..9938adb30 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/CcActions.cpp @@ -0,0 +1,306 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CcActions.h" + +using namespace ai; + +bool CcReachSpellAction::Execute(Event event) +{ + Unit* target = AI_VALUE(Unit*, "cc reach target"); + if (!target) + { + return false; + } + + float dist = bot->GetDistance(target); + if (dist <= sPlayerbotAIConfig.spellDistance + + sPlayerbotAIConfig.tooCloseDistance) + { + if (!bot->IsWithinLOSInMap(target)) + { + float nx, ny, nz; + if (FindNearbyLosPoint(target, nx, ny, nz)) + { + return MoveTo(bot->GetMapId(), nx, ny, nz); + } + } + return false; + } + + return MoveTo(target, sPlayerbotAIConfig.spellDistance); +} + +bool CcReachSpellAction::isUseful() +{ + Unit* target = AI_VALUE(Unit*, "cc reach target"); + if (!target) + { + return false; + } + + if (bot->GetDistance(target) > sPlayerbotAIConfig.spellDistance || + !bot->IsWithinLOSInMap(target)) + { + return true; + } + + return false; +} + +bool CastCcOnMyTargetAction::isPersistent() +{ + if (bot->getClass() == CLASS_ROGUE) + { + return false; + } + + return !m_ccWithdrawn; +} + +bool CastCcOnMyTargetAction::isUseful() +{ + if (bot->getClass() == CLASS_ROGUE) + { + return false; + } + + if (m_ccWithdrawn) + { + Player* master = GetMaster(); + if (master) + { + Unit* target = sObjectAccessor.GetUnit(*bot, master->GetSelectionGuid()); + ObjectGuid currentGuid = target ? target->GetObjectGuid() : ObjectGuid(); + ObjectGuid ccGuid = m_ccTargetGuid; + + if (currentGuid != ccGuid) + { + m_castAttempts = 0; + m_ccWithdrawn = false; + m_ccTargetGuid = ObjectGuid(); + return true; + } + } + + return false; + } + + Player* master = GetMaster(); + if (!master) + { + return false; + } + + Unit* target = sObjectAccessor.GetUnit(*bot, master->GetSelectionGuid()); + if (!target || !target->IsAlive()) + { + return false; + } + + return true; +} + +NextAction** CastCcOnMyTargetAction::getPrerequisites() +{ + if (bot->getClass() == CLASS_ROGUE) + { + return NULL; + } + + Player* master = GetMaster(); + if (!master) + { + return NULL; + } + + Unit* target = sObjectAccessor.GetUnit(*bot, master->GetSelectionGuid()); + if (!target) + { + return NULL; + } + + string ccSpell = GetCcSpell(target); + if (ccSpell.empty() || ai->HasAura(ccSpell, target)) + { + return NULL; + } + + context->GetValue("current target")->Set(target); + context->GetValue("cc reach target")->Set(target); + + return NextAction::array(0, new NextAction("cc reach spell"), NULL); +} + +bool CastCcOnMyTargetAction::Execute(Event event) +{ + Player* master = GetMaster(); + if (!master) + { + return false; + } + + Unit* target = sObjectAccessor.GetUnit(*bot, master->GetSelectionGuid()); + if (!target) + { + ai->TellMaster("You have no target"); + return false; + } + + if (bot->getClass() == CLASS_ROGUE) + { + context->GetValue("current target")->Set(target); + ai->ChangeStrategy("+sap", BOT_STATE_NON_COMBAT); + return true; + } + + string ccSpell = GetCcSpell(target); + if (ccSpell.empty()) + { + ai->TellMaster("I have no crowd control spell"); + return false; + } + + if (ai->HasAura(ccSpell, target)) + { + if (!m_ccWithdrawn) + { + m_ccTargetGuid = target->GetObjectGuid(); + WithdrawToGroupCenter(target); + m_ccWithdrawn = true; + } + return true; + } + + float range = AI_VALUE2(float, "spell range", ccSpell); + if (bot->GetDistance(target) > range || bot->IsNonMeleeSpellCasted(false)) + { + return true; + } + + uint32 spellId = AI_VALUE2(uint32, "spell id", ccSpell); + if (!spellId) + { + ostringstream msg; + msg << "I don't know spell " << ccSpell; + ai->TellMaster(msg.str()); + return false; + } + + if (m_lastCastAttempt > 0 && time(0) - m_lastCastAttempt < 1) + { + return true; + } + + ai->CastSpell(spellId, target); + m_lastCastAttempt = time(0); + + Spell* pcs = bot->GetCurrentSpell(CURRENT_GENERIC_SPELL); + + if (!pcs) + { + m_castAttempts++; + + if (m_castAttempts >= 3) + { + ai->TellMaster("I cannot cast that"); + m_ccWithdrawn = true; + return false; + } + return true; + } + + m_castAttempts = 0; + + ostringstream msg; + msg << "Casting " << ccSpell << " on " << target->GetName(); + ai->TellMasterNoFacing(msg.str()); + return true; +} + +string CastCcOnMyTargetAction::GetCcSpell(Unit* target) +{ + switch (bot->getClass()) + { + case CLASS_MAGE: + return "polymorph"; + case CLASS_WARLOCK: + { + uint32 ctype = target->GetCreatureType(); + if (ctype == CREATURE_TYPE_DEMON || + ctype == CREATURE_TYPE_ELEMENTAL) + { + return "banish"; + } + return "fear"; + } + case CLASS_HUNTER: + return "freezing trap"; + case CLASS_PRIEST: + { + if (target->GetCreatureType() == CREATURE_TYPE_UNDEAD) + { + return "shackle undead"; + } + return ""; + } + case CLASS_DRUID: + { + uint32 ctype = target->GetCreatureType(); + if (ctype == CREATURE_TYPE_BEAST || + ctype == CREATURE_TYPE_DRAGONKIN) + { + return "hibernate"; + } + return "entangling roots"; + } + default: + return ""; + } +} + +void CastCcOnMyTargetAction::WithdrawToGroupCenter(Unit* ccTarget) +{ + Group* group = bot->GetGroup(); + if (!group) + { + return; + } + + float myDist = bot->GetDistance(ccTarget); + bool amClosest = true; + + float sumX = 0.0f, sumY = 0.0f, sumZ = 0.0f; + int count = 0; + + for (GroupReference* ref = group->GetFirstMember(); + ref; ref = ref->next()) + { + Player* member = ref->getSource(); + if (!member || member == bot) + { + continue; + } + + float dist = member->GetDistance(ccTarget); + if (dist < myDist) + { + amClosest = false; + } + + sumX += member->GetPositionX(); + sumY += member->GetPositionY(); + sumZ += member->GetPositionZ(); + count++; + } + + if (!amClosest || count == 0) + { + return; + } + + float medianX = sumX / count; + float medianY = sumY / count; + float medianZ = sumZ / count; + + MoveTo(bot->GetMapId(), medianX, medianY, medianZ); +} diff --git a/src/modules/Bots/playerbot/strategy/actions/CcActions.h b/src/modules/Bots/playerbot/strategy/actions/CcActions.h new file mode 100644 index 000000000..69e000a2e --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/actions/CcActions.h @@ -0,0 +1,38 @@ +#pragma once + +#include "ObjectAccessor.h" +#include "MovementActions.h" + +namespace ai +{ + class CcReachSpellAction : public MovementAction + { + public: + CcReachSpellAction(PlayerbotAI* ai) + : MovementAction(ai, "cc reach spell") {} + + virtual bool Execute(Event event); + virtual bool isUseful(); + }; + + class CastCcOnMyTargetAction : public MovementAction + { + public: + CastCcOnMyTargetAction(PlayerbotAI* ai) + : MovementAction(ai, "cc on my target") {} + + virtual bool isPersistent(); + virtual bool isUseful(); + virtual NextAction** getPrerequisites(); + virtual bool Execute(Event event); + + private: + time_t m_lastCastAttempt = 0; + uint32 m_castAttempts = 0; + ObjectGuid m_ccTargetGuid; + bool m_ccWithdrawn = false; + + string GetCcSpell(Unit* target); + void WithdrawToGroupCenter(Unit* ccTarget); + }; +} diff --git a/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h b/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h index 2631dc109..8f9a6810c 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h +++ b/src/modules/Bots/playerbot/strategy/actions/ChatActionContext.h @@ -48,6 +48,7 @@ #include "UseMeetingStoneAction.h" #include "WhoAction.h" #include "SaveManaAction.h" +#include "CcActions.h" namespace ai { @@ -113,10 +114,12 @@ namespace ai creators["save mana"] = &ChatActionContext::save_mana; creators["max dps chat shortcut"] = &ChatActionContext::max_dps_chat_shortcut; creators["tell attackers"] = &ChatActionContext::tell_attackers; + creators["cc on my target"] = &ChatActionContext::cc_on_my_target; } private: static Action* tell_attackers(PlayerbotAI* ai) { return new TellAttackersAction(ai); } + static Action* cc_on_my_target(PlayerbotAI* ai) { return new CastCcOnMyTargetAction(ai); } static Action* max_dps_chat_shortcut(PlayerbotAI* ai) { return new MaxDpsChatShortcutAction(ai); } static Action* save_mana(PlayerbotAI* ai) { return new SaveManaAction(ai); } static Action* who(PlayerbotAI* ai) { return new WhoAction(ai); } diff --git a/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp b/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp index a4de9505e..075bbded1 100644 --- a/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp +++ b/src/modules/Bots/playerbot/strategy/actions/MovementActions.cpp @@ -554,6 +554,46 @@ bool MovementAction::IsAggroPosition(float x, float y) return CalculateAggroFreeDistance(bx, by, angle, dist) < dist; } +bool MovementAction::FindNearbyLosPoint(Unit* target, float& nx, float& ny, + float& nz, float maxRadius) +{ + if (!target) + { + return false; + } + + float bx = bot->GetPositionX(); + float by = bot->GetPositionY(); + float bz = bot->GetPositionZ(); + float tx = target->GetPositionX(); + float ty = target->GetPositionY(); + float tz = target->GetPositionZ(); + + Map* map = bot->GetMap(); + + for (float r = 2.0f; r <= maxRadius; r += 2.0f) + { + int steps = std::max(8, (int)(2.0f * M_PI * r / 2.0f)); + for (int i = 0; i < steps; i++) + { + float angle = 2.0f * M_PI * i / steps; + float x = bx + r * cos(angle); + float y = by + r * sin(angle); + float z = map->GetHeight(x, y, bz); + + if (map->IsInLineOfSight(x, y, z + 2.0f, tx, ty, tz + 2.0f) && + IsMovingAllowed(map->GetId(), x, y, z)) + { + nx = x; + ny = y; + nz = z; + return true; + } + } + } + return false; +} + bool FleeAction::Execute(Event event) { return Flee(AI_VALUE(Unit*, "current target")); diff --git a/src/modules/Bots/playerbot/strategy/actions/MovementActions.h b/src/modules/Bots/playerbot/strategy/actions/MovementActions.h index 327ded05f..62a7c26e9 100644 --- a/src/modules/Bots/playerbot/strategy/actions/MovementActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/MovementActions.h @@ -30,6 +30,8 @@ namespace ai bool Flee(Unit *target); float CalculateAggroFreeDistance(float bx, float by, float angle, float maxDist); bool IsAggroPosition(float x, float y); + bool FindNearbyLosPoint(Unit* target, float& nx, float& ny, + float& nz, float maxRadius = 20.0f); protected: Player* bot; diff --git a/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h b/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h index aad39aa52..f64104b98 100644 --- a/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h +++ b/src/modules/Bots/playerbot/strategy/actions/ReachTargetActions.h @@ -60,6 +60,79 @@ namespace ai } }; + class ReachSapAction : public MovementAction + { + public: + ReachSapAction(PlayerbotAI* ai) : MovementAction(ai, "reach sap") {} + + virtual bool Execute(Event event) + { + Unit* target = AI_VALUE(Unit*, "current target"); + if (!target) + { + return false; + } + + float tx = target->GetPositionX(); + float ty = target->GetPositionY(); + float tz = target->GetPositionZ(); + float ori = target->GetOrientation(); + + float behindX = tx - cos(ori) * 4.0f; + float behindY = ty - sin(ori) * 4.0f; + + float distBehind = bot->GetDistance(behindX, behindY, tz); + if (distBehind <= sPlayerbotAIConfig.contactDistance) + { + return false; + } + + float bx = bot->GetPositionX(); + float by = bot->GetPositionY(); + float dx = bx - tx; + float dy = by - ty; + float dot = dx * cos(ori) + dy * sin(ori); + + if (dot > 0.0f) + { + float cross = dx * sin(ori) - dy * cos(ori); + float flankAngle = ori + (cross > 0.0f ? M_PI / 2.0f : -M_PI / 2.0f); + float flankX = tx + cos(flankAngle) * 4.0f; + float flankY = ty + sin(flankAngle) * 4.0f; + + float distFlank = bot->GetDistance(flankX, flankY, tz); + if (distFlank < sPlayerbotAIConfig.contactDistance * 3.0f) + { + return MoveTo(target->GetMapId(), behindX, behindY, tz, true); + } + return MoveTo(target->GetMapId(), flankX, flankY, tz, true); + } + else + { + return MoveTo(target->GetMapId(), behindX, behindY, tz, true); + } + } + + virtual bool isUseful() + { + Unit* target = AI_VALUE(Unit*, "current target"); + if (!target || !target->IsAlive() || !ai->HasAura("stealth", bot)) + { + return false; + } + + float tx = target->GetPositionX(); + float ty = target->GetPositionY(); + float tz = target->GetPositionZ(); + float ori = target->GetOrientation(); + + float behindX = tx - cos(ori) * 4.0f; + float behindY = ty - sin(ori) * 4.0f; + + return bot->GetDistance(behindX, behindY, tz) > sPlayerbotAIConfig.contactDistance; + } + }; + class BackOffAction : public ReachTargetAction { public: diff --git a/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp index 477c2cde6..0d81800ca 100644 --- a/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -11,6 +11,7 @@ class ChatCommandActionNodeFactoryInternal : public NamedObjectFactorypersist(3600000); } + static ActionNode* cc_on_my_target(PlayerbotAI* ai) + { + return (new ActionNode ("cc on my target", + /*P*/ NULL, + /*A*/ NULL, + /*C*/ NULL))->persist(3600000); + } }; void ChatCommandHandlerStrategy::InitTriggers(std::list &triggers) @@ -148,6 +156,10 @@ void ChatCommandHandlerStrategy::InitTriggers(std::list &triggers) "attackers", NextAction::array(0, new NextAction("tell attackers", relevance), NULL))); + triggers.push_back(new TriggerNode( + "cc", + NextAction::array(0, new NextAction("cc on my target", relevance), NULL))); + triggers.push_back(new TriggerNode( "jump", NextAction::array(0, new NextAction("jump", relevance), NULL))); diff --git a/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp b/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp index 25038924c..b8ce8f5e3 100644 --- a/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp +++ b/src/modules/Bots/playerbot/strategy/rogue/GenericRogueNonCombatStrategy.cpp @@ -19,6 +19,10 @@ void GenericRogueNonCombatStrategy::InitTriggers(std::list &trigge "sap", NextAction::array(0, new NextAction("begin sap", ACTION_HIGH + 1), NULL))); + triggers.push_back(new TriggerNode( + "cc", + NextAction::array(0, new NextAction("begin sap", ACTION_HIGH + 1), NULL))); + triggers.push_back(new TriggerNode( "stealth", NextAction::array(0, new NextAction("stealth", ACTION_NORMAL), NULL))); diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp b/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp index 890c09575..17cc44ebf 100644 --- a/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueAiObjectContext.cpp @@ -104,6 +104,7 @@ namespace ai creators["sap"] = &AiObjectContextInternal::sap; creators["begin sap"] = &AiObjectContextInternal::begin_sap; creators["end sap"] = &AiObjectContextInternal::end_sap; + creators["reach sap"] = &AiObjectContextInternal::reach_sap; creators["garrote"] = &AiObjectContextInternal::garrote; creators["cheap shot"] = &AiObjectContextInternal::cheap_shot; creators["stealth"] = &AiObjectContextInternal::stealth; @@ -129,6 +130,7 @@ namespace ai static Action* sap(PlayerbotAI* ai) { return new CastSapAction(ai); } static Action* begin_sap(PlayerbotAI* ai) { return new BeginSapAction(ai); } static Action* end_sap(PlayerbotAI* ai) { return new EndSapAction(ai); } + static Action* reach_sap(PlayerbotAI* ai) { return new ReachSapAction(ai); } static Action* garrote(PlayerbotAI* ai) { return new CastGarroteAction(ai); } static Action* cheap_shot(PlayerbotAI* ai) { return new CastCheapShotAction(ai); } static Action* stealth(PlayerbotAI* ai) { return new CastStealthAction(ai); } diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h b/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h index ac7f51d32..82a64613a 100644 --- a/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueOpeningActions.h @@ -33,6 +33,11 @@ namespace ai } return result; } + + virtual NextAction** getPrerequisites() + { + return Action::getPrerequisites(); + } }; class CastGarroteAction : public CastStealthedOpeningAction diff --git a/src/modules/Bots/playerbot/strategy/rogue/RogueSapStrategy.h b/src/modules/Bots/playerbot/strategy/rogue/RogueSapStrategy.h index 401c0600d..6d3127a31 100644 --- a/src/modules/Bots/playerbot/strategy/rogue/RogueSapStrategy.h +++ b/src/modules/Bots/playerbot/strategy/rogue/RogueSapStrategy.h @@ -19,7 +19,7 @@ namespace ai { return NextAction::array(0, new NextAction("stealth", ACTION_HIGH + 3), - new NextAction("reach melee", ACTION_HIGH + 2), + new NextAction("reach sap", ACTION_HIGH + 2), new NextAction("sap", ACTION_HIGH + 1), new NextAction("end sap", ACTION_NORMAL + 1), new NextAction("follow master", ACTION_NORMAL), diff --git a/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h b/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h index 4772640f2..77a8eb671 100644 --- a/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h +++ b/src/modules/Bots/playerbot/strategy/triggers/ChatTriggerContext.h @@ -74,11 +74,13 @@ namespace ai creators["max dps"] = &ChatTriggerContext::max_dps; creators["attackers"] = &ChatTriggerContext::attackers; creators["jump"] = &ChatTriggerContext::jump; + creators["cc"] = &ChatTriggerContext::cc_cmd; } private: static Trigger* attackers(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "attackers"); } static Trigger* jump(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "jump"); } + static Trigger* cc_cmd(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "cc"); } static Trigger* max_dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "max dps"); } static Trigger* save_mana(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "save mana"); } static Trigger* who(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "who"); } diff --git a/src/modules/Bots/playerbot/strategy/values/CcReachTargetValue.cpp b/src/modules/Bots/playerbot/strategy/values/CcReachTargetValue.cpp new file mode 100644 index 000000000..59a6b65e0 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CcReachTargetValue.cpp @@ -0,0 +1,20 @@ +#include "botpch.h" +#include "../../playerbot.h" +#include "CcReachTargetValue.h" + +using namespace ai; + +Unit* CcReachTargetValue::Get() +{ + if (selection.IsEmpty()) + { + return NULL; + } + + return sObjectAccessor.GetUnit(*bot, selection); +} + +void CcReachTargetValue::Set(Unit* unit) +{ + selection = unit ? unit->GetObjectGuid() : ObjectGuid(); +} diff --git a/src/modules/Bots/playerbot/strategy/values/CcReachTargetValue.h b/src/modules/Bots/playerbot/strategy/values/CcReachTargetValue.h new file mode 100644 index 000000000..e3ba9b573 --- /dev/null +++ b/src/modules/Bots/playerbot/strategy/values/CcReachTargetValue.h @@ -0,0 +1,17 @@ +#pragma once +#include "../Value.h" + +namespace ai +{ + class CcReachTargetValue : public UnitManualSetValue + { + public: + CcReachTargetValue(PlayerbotAI* ai) : UnitManualSetValue(ai, NULL) {} + + virtual Unit* Get(); + virtual void Set(Unit* unit); + + private: + ObjectGuid selection; + }; +} diff --git a/src/modules/Bots/playerbot/strategy/values/ValueContext.h b/src/modules/Bots/playerbot/strategy/values/ValueContext.h index 69cb868a2..db001d07d 100644 --- a/src/modules/Bots/playerbot/strategy/values/ValueContext.h +++ b/src/modules/Bots/playerbot/strategy/values/ValueContext.h @@ -60,6 +60,7 @@ #include "SpellRangeValue.h" #include "LastTargetPositionValue.h" #include "MasterBobberValue.h" +#include "CcReachTargetValue.h" namespace ai { @@ -155,6 +156,7 @@ namespace ai creators["puller target"] = &ValueContext::puller_target; creators["spell range"] = &ValueContext::spell_range; creators["last target position"] = &ValueContext::last_target_position; + creators["cc reach target"] = &ValueContext::cc_reach_target; } private: @@ -244,5 +246,6 @@ namespace ai static UntypedValue* puller_target(PlayerbotAI* ai) { return new PullerTargetValue(ai); } static UntypedValue* spell_range(PlayerbotAI* ai) { return new SpellRangeValue(ai); } static UntypedValue* last_target_position(PlayerbotAI* ai) { return new LastTargetPositionValue(ai); } + static UntypedValue* cc_reach_target(PlayerbotAI* ai) { return new CcReachTargetValue(ai); } }; };