mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-07 20:51:09 +00:00
Fix stuck on knockback, enhance movement & flee and trap weave strats (#980)
* Hunter trap weave strats * Do not allow actions to stack * Remove trap weave by default * Refactor on Engine Co-authored-by: SaW <swerkhoven@outlook.com> * Remove unused funcs in Queue * Remove ExpireActionTime config --------- Co-authored-by: SaW <swerkhoven@outlook.com>
This commit is contained in:
@@ -305,9 +305,6 @@ AiPlayerbot.DisableMoveSplinePath = 0
|
|||||||
# default: 3
|
# default: 3
|
||||||
AiPlayerbot.MaxMovementSearchTime = 3
|
AiPlayerbot.MaxMovementSearchTime = 3
|
||||||
|
|
||||||
# Action expiration time
|
|
||||||
AiPlayerbot.ExpireActionTime = 5000
|
|
||||||
|
|
||||||
# Max dispel auras duration
|
# Max dispel auras duration
|
||||||
AiPlayerbot.DispelAuraDuration = 700
|
AiPlayerbot.DispelAuraDuration = 700
|
||||||
|
|
||||||
|
|||||||
@@ -369,6 +369,10 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
case CLASS_HUNTER:
|
case CLASS_HUNTER:
|
||||||
engine->addStrategiesNoInit("dps", "aoe", "bdps", "dps assist", nullptr);
|
engine->addStrategiesNoInit("dps", "aoe", "bdps", "dps assist", nullptr);
|
||||||
engine->addStrategy("dps debuff", false);
|
engine->addStrategy("dps debuff", false);
|
||||||
|
// if (tab == HUNTER_TAB_SURVIVAL)
|
||||||
|
// {
|
||||||
|
// engine->addStrategy("trap weave", false);
|
||||||
|
// }
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION)
|
if (tab == ROGUE_TAB_ASSASSINATION)
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
|
maxWaitForMove = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxWaitForMove", 5000);
|
||||||
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
|
disableMoveSplinePath = sConfigMgr->GetOption<int32>("AiPlayerbot.DisableMoveSplinePath", 0);
|
||||||
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
|
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
|
||||||
expireActionTime = sConfigMgr->GetOption<int32>("AiPlayerbot.ExpireActionTime", 5000);
|
|
||||||
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
|
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
|
||||||
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 100);
|
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 100);
|
||||||
dynamicReactDelay = sConfigMgr->GetOption<bool>("AiPlayerbot.DynamicReactDelay", true);
|
dynamicReactDelay = sConfigMgr->GetOption<bool>("AiPlayerbot.DynamicReactDelay", true);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
bool enabled;
|
bool enabled;
|
||||||
bool allowAccountBots, allowGuildBots;
|
bool allowAccountBots, allowGuildBots;
|
||||||
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
||||||
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime,
|
||||||
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
|
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
|
||||||
bool dynamicReactDelay;
|
bool dynamicReactDelay;
|
||||||
float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance,
|
float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance,
|
||||||
|
|||||||
@@ -87,27 +87,23 @@ Engine::~Engine(void)
|
|||||||
void Engine::Reset()
|
void Engine::Reset()
|
||||||
{
|
{
|
||||||
strategyTypeMask = 0;
|
strategyTypeMask = 0;
|
||||||
|
|
||||||
ActionNode* action = nullptr;
|
ActionNode* action = nullptr;
|
||||||
do
|
|
||||||
{
|
|
||||||
action = queue.Pop();
|
|
||||||
if (!action)
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
while ((action = queue.Pop()) != nullptr)
|
||||||
|
{
|
||||||
delete action;
|
delete action;
|
||||||
} while (true);
|
}
|
||||||
|
|
||||||
for (std::vector<TriggerNode*>::iterator i = triggers.begin(); i != triggers.end(); i++)
|
for (TriggerNode* trigger : triggers)
|
||||||
{
|
{
|
||||||
TriggerNode* trigger = *i;
|
|
||||||
delete trigger;
|
delete trigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggers.clear();
|
triggers.clear();
|
||||||
|
|
||||||
for (std::vector<Multiplier*>::iterator i = multipliers.begin(); i != multipliers.end(); i++)
|
for (Multiplier* multiplier : multipliers)
|
||||||
{
|
{
|
||||||
Multiplier* multiplier = *i;
|
|
||||||
delete multiplier;
|
delete multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,8 +240,13 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal)
|
|||||||
|
|
||||||
if (!actionExecuted)
|
if (!actionExecuted)
|
||||||
LogAction("No actions executed");
|
LogAction("No actions executed");
|
||||||
|
|
||||||
|
ActionNode* action = nullptr;
|
||||||
|
while ((action = queue.Pop()) != nullptr)
|
||||||
|
{
|
||||||
|
delete action;
|
||||||
|
}
|
||||||
|
|
||||||
queue.RemoveExpired(); // Clean up expired actions in the queue
|
|
||||||
return actionExecuted;
|
return actionExecuted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,18 +48,6 @@ uint32 Queue::Size()
|
|||||||
return actions.size();
|
return actions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::RemoveExpired()
|
|
||||||
{
|
|
||||||
if (!sPlayerbotAIConfig->expireActionTime)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<ActionBasket*> expiredBaskets;
|
|
||||||
collectExpiredBaskets(expiredBaskets);
|
|
||||||
removeAndDeleteBaskets(expiredBaskets);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private helper methods
|
// Private helper methods
|
||||||
void Queue::updateExistingBasket(ActionBasket* existing, ActionBasket* newBasket)
|
void Queue::updateExistingBasket(ActionBasket* existing, ActionBasket* newBasket)
|
||||||
{
|
{
|
||||||
@@ -105,30 +93,3 @@ ActionNode* Queue::extractAndDeleteBasket(ActionBasket* basket)
|
|||||||
delete basket;
|
delete basket;
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Queue::collectExpiredBaskets(std::list<ActionBasket*>& expiredBaskets)
|
|
||||||
{
|
|
||||||
uint32 expiryTime = sPlayerbotAIConfig->expireActionTime;
|
|
||||||
for (ActionBasket* basket : actions)
|
|
||||||
{
|
|
||||||
if (basket->isExpired(expiryTime))
|
|
||||||
{
|
|
||||||
expiredBaskets.push_back(basket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Queue::removeAndDeleteBaskets(std::list<ActionBasket*>& basketsToRemove)
|
|
||||||
{
|
|
||||||
for (ActionBasket* basket : basketsToRemove)
|
|
||||||
{
|
|
||||||
actions.remove(basket);
|
|
||||||
|
|
||||||
if (ActionNode* action = basket->getAction())
|
|
||||||
{
|
|
||||||
delete action;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete basket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -53,14 +53,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
uint32 Size();
|
uint32 Size();
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Removes and deletes expired actions from the queue
|
|
||||||
*
|
|
||||||
* Uses sPlayerbotAIConfig->expireActionTime to determine if actions have expired.
|
|
||||||
* Both the ActionNode and ActionBasket are deleted for expired actions.
|
|
||||||
*/
|
|
||||||
void RemoveExpired();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Updates existing basket with new relevance and cleans up new basket
|
* @brief Updates existing basket with new relevance and cleans up new basket
|
||||||
@@ -78,11 +70,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
ActionNode* extractAndDeleteBasket(ActionBasket* basket);
|
ActionNode* extractAndDeleteBasket(ActionBasket* basket);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Collects all expired baskets into the provided list
|
|
||||||
*/
|
|
||||||
void collectExpiredBaskets(std::list<ActionBasket*>& expiredBaskets);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes and deletes all baskets in the provided list
|
* @brief Removes and deletes all baskets in the provided list
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -143,7 +143,8 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
|||||||
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
|
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
|
||||||
|
|
||||||
LastMovement& lastMovement = AI_VALUE(LastMovement&, "last movement");
|
LastMovement& lastMovement = AI_VALUE(LastMovement&, "last movement");
|
||||||
if (lastMovement.priority < MovementPriority::MOVEMENT_COMBAT && bot->isMoving())
|
bool moveControlled = bot->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE;
|
||||||
|
if (lastMovement.priority < MovementPriority::MOVEMENT_COMBAT && bot->isMoving() && !moveControlled)
|
||||||
{
|
{
|
||||||
AI_VALUE(LastMovement&, "last movement").clear();
|
AI_VALUE(LastMovement&, "last movement").clear();
|
||||||
bot->GetMotionMaster()->Clear(false);
|
bot->GetMotionMaster()->Clear(false);
|
||||||
|
|||||||
@@ -75,9 +75,6 @@ NextAction** AvoidAoeStrategy::getDefaultActions()
|
|||||||
|
|
||||||
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
// triggers.push_back(new TriggerNode(
|
|
||||||
// "has area debuff",
|
|
||||||
// NextAction::array(0, new NextAction("flee", ACTION_EMERGENCY + 5), NULL)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ void RangedCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
CombatStrategy::InitTriggers(triggers);
|
CombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("enemy too close for spell",
|
triggers.push_back(new TriggerNode("enemy too close for spell",
|
||||||
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr)));
|
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 4), nullptr)));
|
||||||
// triggers.push_back(new TriggerNode("not facing target", NextAction::array(0, new NextAction("set facing",
|
// triggers.push_back(new TriggerNode("not facing target", NextAction::array(0, new NextAction("set facing",
|
||||||
// ACTION_MOVE + 7), nullptr)));
|
// ACTION_MOVE + 7), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "GenericHunterStrategy.h"
|
#include "GenericHunterStrategy.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "Strategy.h"
|
||||||
|
|
||||||
class GenericHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
class GenericHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,7 @@ public:
|
|||||||
creators["wing clip"] = &wing_clip;
|
creators["wing clip"] = &wing_clip;
|
||||||
creators["mongoose bite"] = &mongoose_bite;
|
creators["mongoose bite"] = &mongoose_bite;
|
||||||
creators["raptor strike"] = &raptor_strike;
|
creators["raptor strike"] = &raptor_strike;
|
||||||
|
creators["explosive trap"] = &explosive_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -70,6 +72,15 @@ private:
|
|||||||
/*A*/ nullptr,
|
/*A*/ nullptr,
|
||||||
/*C*/ nullptr);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ActionNode* explosive_trap([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("explosive trap",
|
||||||
|
/*P*/ nullptr,
|
||||||
|
/*A*/ NextAction::array(0, new NextAction("immolation trap"), nullptr),
|
||||||
|
/*C*/ nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GenericHunterStrategy::GenericHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
GenericHunterStrategy::GenericHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||||
@@ -82,8 +93,11 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
CombatStrategy::InitTriggers(triggers);
|
CombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("enemy within melee",
|
triggers.push_back(new TriggerNode("enemy within melee",
|
||||||
NextAction::array(0, new NextAction("wing clip", ACTION_HIGH + 1),
|
NextAction::array(0,
|
||||||
new NextAction("mongoose bite", ACTION_HIGH), nullptr)));
|
new NextAction("explosive trap", ACTION_MOVE + 7),
|
||||||
|
new NextAction("mongoose bite", ACTION_HIGH + 2),
|
||||||
|
new NextAction("wing clip", ACTION_HIGH + 1),
|
||||||
|
nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("medium threat", NextAction::array(0, new NextAction("feign death", 35.0f), nullptr)));
|
new TriggerNode("medium threat", NextAction::array(0, new NextAction("feign death", 35.0f), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("hunters pet medium health",
|
triggers.push_back(new TriggerNode("hunters pet medium health",
|
||||||
@@ -93,7 +107,10 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("aspect of the viper",
|
triggers.push_back(new TriggerNode("aspect of the viper",
|
||||||
NextAction::array(0, new NextAction("aspect of the viper", ACTION_HIGH), NULL)));
|
NextAction::array(0, new NextAction("aspect of the viper", ACTION_HIGH), NULL)));
|
||||||
triggers.push_back(new TriggerNode("enemy too close for auto shot",
|
triggers.push_back(new TriggerNode("enemy too close for auto shot",
|
||||||
NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr)));
|
NextAction::array(0,
|
||||||
|
new NextAction("disengage", ACTION_MOVE + 5),
|
||||||
|
new NextAction("flee", ACTION_MOVE + 4),
|
||||||
|
nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("low tank threat",
|
new TriggerNode("low tank threat",
|
||||||
NextAction::array(0, new NextAction("misdirection on main tank", ACTION_HIGH + 7), NULL)));
|
NextAction::array(0, new NextAction("misdirection on main tank", ACTION_HIGH + 7), NULL)));
|
||||||
@@ -124,3 +141,14 @@ void HunterCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"freezing trap", NextAction::array(0, new NextAction("freezing trap on cc", ACTION_HIGH + 3), nullptr)));
|
"freezing trap", NextAction::array(0, new NextAction("freezing trap on cc", ACTION_HIGH + 3), nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HunterTrapWeaveStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
{
|
||||||
|
triggers.push_back(new TriggerNode(
|
||||||
|
"immolation trap no cd", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 3), nullptr)));
|
||||||
|
|
||||||
|
// triggers.push_back(new TriggerNode(
|
||||||
|
// "scare beast", NextAction::array(0, new NextAction("scare beast on cc", ACTION_HIGH + 3), nullptr)));
|
||||||
|
// triggers.push_back(new TriggerNode(
|
||||||
|
// "freezing trap", NextAction::array(0, new NextAction("freezing trap on cc", ACTION_HIGH + 3), nullptr)));
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,4 +40,14 @@ public:
|
|||||||
std::string const getName() override { return "cc"; }
|
std::string const getName() override { return "cc"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HunterTrapWeaveStrategy : public Strategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HunterTrapWeaveStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||||
|
|
||||||
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
|
std::string const getName() override { return "trap weave"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
bool CastHuntersMarkAction::isUseful() { return CastDebuffSpellAction::isUseful(); }
|
bool CastHuntersMarkAction::isUseful() { return CastDebuffSpellAction::isUseful(); }
|
||||||
@@ -46,6 +47,22 @@ bool CastAutoShotAction::isUseful()
|
|||||||
return AI_VALUE(uint32, "active spell") != AI_VALUE2(uint32, "spell id", getName());
|
return AI_VALUE(uint32, "active spell") != AI_VALUE2(uint32, "spell id", getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CastDisengageAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
// can cast spell check passed in isUseful()
|
||||||
|
bot->SetOrientation(bot->GetAngle(target));
|
||||||
|
return CastSpellAction::Execute(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastDisengageAction::isUseful()
|
||||||
|
{
|
||||||
|
return !botAI->HasStrategy("trap weave", BOT_STATE_COMBAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Value<Unit*>* CastScareBeastCcAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "scare beast"); }
|
Value<Unit*>* CastScareBeastCcAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", "scare beast"); }
|
||||||
|
|
||||||
bool CastScareBeastCcAction::Execute(Event event) { return botAI->CastSpell("scare beast", GetTarget()); }
|
bool CastScareBeastCcAction::Execute(Event event) { return botAI->CastSpell("scare beast", GetTarget()); }
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#define _PLAYERBOT_HUNTERACTIONS_H
|
#define _PLAYERBOT_HUNTERACTIONS_H
|
||||||
|
|
||||||
#include "AiObject.h"
|
#include "AiObject.h"
|
||||||
|
#include "Event.h"
|
||||||
#include "GenericSpellActions.h"
|
#include "GenericSpellActions.h"
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
@@ -84,6 +85,27 @@ END_SPELL_ACTION()
|
|||||||
BEGIN_RANGED_SPELL_ACTION(CastTranquilizingShotAction, "tranquilizing shot")
|
BEGIN_RANGED_SPELL_ACTION(CastTranquilizingShotAction, "tranquilizing shot")
|
||||||
END_SPELL_ACTION()
|
END_SPELL_ACTION()
|
||||||
|
|
||||||
|
class CastDisengageAction : public CastSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastDisengageAction(PlayerbotAI* botAI): CastSpellAction(botAI, "disengage") {}
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
bool isUseful() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CastImmolationTrapAction : public CastSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastImmolationTrapAction(PlayerbotAI* botAI): CastSpellAction(botAI, "immolation trap") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CastExplosiveTrapAction : public CastSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastExplosiveTrapAction(PlayerbotAI* botAI): CastSpellAction(botAI, "explosive trap") {}
|
||||||
|
};
|
||||||
|
|
||||||
class CastAspectOfTheHawkAction : public CastBuffSpellAction
|
class CastAspectOfTheHawkAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
creators["boost"] = &HunterStrategyFactoryInternal::boost;
|
creators["boost"] = &HunterStrategyFactoryInternal::boost;
|
||||||
creators["pet"] = &HunterStrategyFactoryInternal::pet;
|
creators["pet"] = &HunterStrategyFactoryInternal::pet;
|
||||||
creators["cc"] = &HunterStrategyFactoryInternal::cc;
|
creators["cc"] = &HunterStrategyFactoryInternal::cc;
|
||||||
|
creators["trap weave"] = &HunterStrategyFactoryInternal::trap_weave;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -35,6 +36,7 @@ private:
|
|||||||
static Strategy* boost(PlayerbotAI* botAI) { return new HunterBoostStrategy(botAI); }
|
static Strategy* boost(PlayerbotAI* botAI) { return new HunterBoostStrategy(botAI); }
|
||||||
static Strategy* pet(PlayerbotAI* botAI) { return new HunterPetStrategy(botAI); }
|
static Strategy* pet(PlayerbotAI* botAI) { return new HunterPetStrategy(botAI); }
|
||||||
static Strategy* cc(PlayerbotAI* botAI) { return new HunterCcStrategy(botAI); }
|
static Strategy* cc(PlayerbotAI* botAI) { return new HunterCcStrategy(botAI); }
|
||||||
|
static Strategy* trap_weave(PlayerbotAI* botAI) { return new HunterTrapWeaveStrategy(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class HunterBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
|
class HunterBuffStrategyFactoryInternal : public NamedObjectContext<Strategy>
|
||||||
@@ -88,6 +90,7 @@ public:
|
|||||||
creators["misdirection on main tank"] = &HunterTriggerFactoryInternal::misdirection_on_main_tank;
|
creators["misdirection on main tank"] = &HunterTriggerFactoryInternal::misdirection_on_main_tank;
|
||||||
creators["tranquilizing shot enrage"] = &HunterTriggerFactoryInternal::remove_enrage;
|
creators["tranquilizing shot enrage"] = &HunterTriggerFactoryInternal::remove_enrage;
|
||||||
creators["tranquilizing shot magic"] = &HunterTriggerFactoryInternal::remove_magic;
|
creators["tranquilizing shot magic"] = &HunterTriggerFactoryInternal::remove_magic;
|
||||||
|
creators["immolation trap no cd"] = &HunterTriggerFactoryInternal::immolation_trap_no_cd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -122,6 +125,7 @@ private:
|
|||||||
static Trigger* misdirection_on_main_tank(PlayerbotAI* ai) { return new MisdirectionOnMainTankTrigger(ai); }
|
static Trigger* misdirection_on_main_tank(PlayerbotAI* ai) { return new MisdirectionOnMainTankTrigger(ai); }
|
||||||
static Trigger* remove_enrage(PlayerbotAI* ai) { return new TargetRemoveEnrageTrigger(ai); }
|
static Trigger* remove_enrage(PlayerbotAI* ai) { return new TargetRemoveEnrageTrigger(ai); }
|
||||||
static Trigger* remove_magic(PlayerbotAI* ai) { return new TargetRemoveMagicTrigger(ai); }
|
static Trigger* remove_magic(PlayerbotAI* ai) { return new TargetRemoveMagicTrigger(ai); }
|
||||||
|
static Trigger* immolation_trap_no_cd(PlayerbotAI* ai) { return new ImmolationTrapNoCdTrigger(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class HunterAiObjectContextInternal : public NamedObjectContext<Action>
|
class HunterAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
@@ -176,6 +180,9 @@ public:
|
|||||||
creators["kill shot"] = &HunterAiObjectContextInternal::kill_shot;
|
creators["kill shot"] = &HunterAiObjectContextInternal::kill_shot;
|
||||||
creators["misdirection on main tank"] = &HunterAiObjectContextInternal::misdirection_on_main_tank;
|
creators["misdirection on main tank"] = &HunterAiObjectContextInternal::misdirection_on_main_tank;
|
||||||
creators["silencing shot"] = &HunterAiObjectContextInternal::silencing_shot;
|
creators["silencing shot"] = &HunterAiObjectContextInternal::silencing_shot;
|
||||||
|
creators["disengage"] = &HunterAiObjectContextInternal::disengage;
|
||||||
|
creators["immolation trap"] = &HunterAiObjectContextInternal::immolation_trap;
|
||||||
|
creators["explosive trap"] = &HunterAiObjectContextInternal::explosive_trap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -225,7 +232,9 @@ private:
|
|||||||
static Action* kill_shot(PlayerbotAI* ai) { return new CastKillShotAction(ai); }
|
static Action* kill_shot(PlayerbotAI* ai) { return new CastKillShotAction(ai); }
|
||||||
static Action* misdirection_on_main_tank(PlayerbotAI* ai) { return new CastMisdirectionOnMainTankAction(ai); }
|
static Action* misdirection_on_main_tank(PlayerbotAI* ai) { return new CastMisdirectionOnMainTankAction(ai); }
|
||||||
static Action* silencing_shot(PlayerbotAI* ai) { return new CastSilencingShotAction(ai); }
|
static Action* silencing_shot(PlayerbotAI* ai) { return new CastSilencingShotAction(ai); }
|
||||||
|
static Action* disengage(PlayerbotAI* ai) { return new CastDisengageAction(ai); }
|
||||||
|
static Action* immolation_trap(PlayerbotAI* ai) { return new CastImmolationTrapAction(ai); }
|
||||||
|
static Action* explosive_trap(PlayerbotAI* ai) { return new CastExplosiveTrapAction(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
||||||
|
|||||||
@@ -5,13 +5,23 @@
|
|||||||
|
|
||||||
#include "HunterTriggers.h"
|
#include "HunterTriggers.h"
|
||||||
|
|
||||||
|
#include "GenericSpellActions.h"
|
||||||
#include "GenericTriggers.h"
|
#include "GenericTriggers.h"
|
||||||
#include "HunterActions.h"
|
#include "HunterActions.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
|
bool BlackArrowTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (botAI->HasStrategy("trap weave", BOT_STATE_COMBAT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return DebuffTrigger::IsActive();
|
||||||
|
}
|
||||||
|
|
||||||
bool HunterAspectOfTheHawkTrigger::IsActive()
|
bool HunterAspectOfTheHawkTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class BlackArrowTrigger : public DebuffTrigger
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BlackArrowTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "black arrow", 1, true) {}
|
BlackArrowTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "black arrow", 1, true) {}
|
||||||
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HuntersMarkTrigger : public DebuffTrigger
|
class HuntersMarkTrigger : public DebuffTrigger
|
||||||
@@ -185,4 +186,11 @@ class TargetRemoveMagicTrigger : public TargetAuraDispelTrigger
|
|||||||
public:
|
public:
|
||||||
TargetRemoveMagicTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "tranquilizing shot", DISPEL_MAGIC) {}
|
TargetRemoveMagicTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "tranquilizing shot", DISPEL_MAGIC) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ImmolationTrapNoCdTrigger : public SpellNoCooldownTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ImmolationTrapNoCdTrigger(PlayerbotAI* ai) : SpellNoCooldownTrigger(ai, "immolation trap") {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "FireMageStrategy.h"
|
#include "FireMageStrategy.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "Strategy.h"
|
||||||
|
|
||||||
NextAction** FireMageStrategy::getDefaultActions()
|
NextAction** FireMageStrategy::getDefaultActions()
|
||||||
{
|
{
|
||||||
@@ -32,11 +33,12 @@ void FireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
|
|
||||||
void FireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void FireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
|
// higher priority to cast before move away
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("medium aoe", NextAction::array(0,
|
new TriggerNode("medium aoe", NextAction::array(0,
|
||||||
new NextAction("dragon's breath", 24.0f),
|
new NextAction("dragon's breath", ACTION_MOVE + 9),
|
||||||
new NextAction("flamestrike", 23.0f),
|
new NextAction("flamestrike", ACTION_MOVE + 8),
|
||||||
new NextAction("blast wave", 22.0f),
|
new NextAction("blast wave", ACTION_MOVE + 7),
|
||||||
new NextAction("living bomb on attackers", 21.0f),
|
new NextAction("living bomb on attackers", 21.0f),
|
||||||
new NextAction("blizzard", 20.0f), nullptr)));
|
new NextAction("blizzard", 20.0f), nullptr)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,6 +179,9 @@ void GenericMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
new TriggerNode("fire ward", NextAction::array(0, new NextAction("fire ward", ACTION_EMERGENCY), nullptr)));
|
new TriggerNode("fire ward", NextAction::array(0, new NextAction("fire ward", ACTION_EMERGENCY), nullptr)));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("frost ward", NextAction::array(0, new NextAction("frost ward", ACTION_EMERGENCY), nullptr)));
|
new TriggerNode("frost ward", NextAction::array(0, new NextAction("frost ward", ACTION_EMERGENCY), nullptr)));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("enemy too close for spell",
|
||||||
|
NextAction::array(0, new NextAction("blink back", ACTION_MOVE + 5), nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MageCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void MageCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MageActions.h"
|
#include "MageActions.h"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
@@ -17,6 +18,10 @@ bool CastFrostNovaAction::isUseful()
|
|||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
if (target && target->ToCreature() && target->ToCreature()->HasMechanicTemplateImmunity(1 << (MECHANIC_FREEZE - 1)))
|
if (target && target->ToCreature() && target->ToCreature()->HasMechanicTemplateImmunity(1 << (MECHANIC_FREEZE - 1)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (target->isFrozen())
|
||||||
|
return false;
|
||||||
|
|
||||||
return sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
|
return sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,4 +92,14 @@ Unit* CastFocusMagicOnPartyAction::GetTarget()
|
|||||||
return healer;
|
return healer;
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastBlinkBackAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
// can cast spell check passed in isUseful()
|
||||||
|
bot->SetOrientation(bot->GetAngle(target) + M_PI);
|
||||||
|
return CastSpellAction::Execute(event);
|
||||||
}
|
}
|
||||||
@@ -309,4 +309,11 @@ public:
|
|||||||
Unit* GetTarget() override;
|
Unit* GetTarget() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastBlinkBackAction : public CastSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastBlinkBackAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blink") {}
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ public:
|
|||||||
creators["frost ward"] = &MageAiObjectContextInternal::frost_ward;
|
creators["frost ward"] = &MageAiObjectContextInternal::frost_ward;
|
||||||
creators["mirror image"] = &MageAiObjectContextInternal::mirror_image;
|
creators["mirror image"] = &MageAiObjectContextInternal::mirror_image;
|
||||||
creators["focus magic on party"] = &MageAiObjectContextInternal::focus_magic_on_party;
|
creators["focus magic on party"] = &MageAiObjectContextInternal::focus_magic_on_party;
|
||||||
|
creators["blink back"] = &MageAiObjectContextInternal::blink_back;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -264,6 +265,7 @@ private:
|
|||||||
}
|
}
|
||||||
static Action* mirror_image(PlayerbotAI* botAI) { return new CastMirrorImageAction(botAI); }
|
static Action* mirror_image(PlayerbotAI* botAI) { return new CastMirrorImageAction(botAI); }
|
||||||
static Action* focus_magic_on_party(PlayerbotAI* botAI) { return new CastFocusMagicOnPartyAction(botAI); }
|
static Action* focus_magic_on_party(PlayerbotAI* botAI) { return new CastFocusMagicOnPartyAction(botAI); }
|
||||||
|
static Action* blink_back(PlayerbotAI* botAI) { return new CastBlinkBackAction(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
MageAiObjectContext::MageAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
MageAiObjectContext::MageAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
static float GetSpeedInMotion(Unit* target)
|
static float GetSpeedInMotion(Unit* target)
|
||||||
{
|
{
|
||||||
@@ -56,8 +57,19 @@ bool EnemyTooCloseForSpellTrigger::IsActive()
|
|||||||
bool EnemyTooCloseForAutoShotTrigger::IsActive()
|
bool EnemyTooCloseForAutoShotTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
return target && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) &&
|
// hunter move away after casting immolation/explosive trap
|
||||||
|
bool trapToCast = bot->getClass() == CLASS_HUNTER;
|
||||||
|
uint32 spellId = AI_VALUE2(uint32, "spell id", "immolation trap");
|
||||||
|
if (!spellId)
|
||||||
|
trapToCast = false;
|
||||||
|
|
||||||
|
if (spellId && bot->HasSpellCooldown(spellId))
|
||||||
|
trapToCast = false;
|
||||||
|
|
||||||
|
return !trapToCast && (target->GetVictim() != bot || target->isFrozen() || !target->CanFreeMove()) &&
|
||||||
bot->IsWithinMeleeRange(target);
|
bot->IsWithinMeleeRange(target);
|
||||||
|
|
||||||
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
|
// if (target->GetTarget() == bot->GetGUID() && !bot->GetGroup() && !target->HasUnitState(UNIT_STATE_ROOT) &&
|
||||||
|
|||||||
Reference in New Issue
Block a user