mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
commit
9fa03dc83f
1
.github/workflows/label_translation-pr.yml
vendored
1
.github/workflows/label_translation-pr.yml
vendored
@ -35,4 +35,5 @@ jobs:
|
|||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
gh pr edit ${{ github.event.pull_request.number }} \
|
gh pr edit ${{ github.event.pull_request.number }} \
|
||||||
|
--repo ${{ github.repository }} \
|
||||||
--add-label "Added translation"
|
--add-label "Added translation"
|
||||||
|
|||||||
@ -582,7 +582,7 @@ AiPlayerbot.AutoGearScoreLimit = 0
|
|||||||
AiPlayerbot.BotCheats = "food,taxi,raid"
|
AiPlayerbot.BotCheats = "food,taxi,raid"
|
||||||
|
|
||||||
# List of attunement quests (comma-separated list of quest IDs) that are automatically completed for all bots.
|
# List of attunement quests (comma-separated list of quest IDs) that are automatically completed for all bots.
|
||||||
# While mod-playerbots does not restore removed attunement requirements, although other mods, such as mod-individual-progression, may do so.
|
# While mod-playerbots does not restore removed attunement requirements, other mods, such as mod-individual-progression, may do so.
|
||||||
# This is meant to exclude bots from such requirements.
|
# This is meant to exclude bots from such requirements.
|
||||||
#
|
#
|
||||||
# Default:
|
# Default:
|
||||||
@ -865,34 +865,65 @@ AiPlayerbot.ExcludedHunterPetFamilies = ""
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|
||||||
|
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
# ACTIVITIES
|
# ACTIVITY
|
||||||
#
|
#
|
||||||
|
# BotActiveAlone
|
||||||
|
# - Controls how many bots are active when no real players are nearby.
|
||||||
|
# - Think of it as a rough percentage: 10 means approximately 10% of bots will be active.
|
||||||
|
# Not exact — the actual number may vary slightly per rotation cycle.
|
||||||
|
# - The active bots rotate: every <DurationSeconds> a different set of bots takes a turn.
|
||||||
|
# - The real number of active bots will always be higher than this value, because bots in
|
||||||
|
# combat, dungeons, battlegrounds, LFG queue, groups with real players, etc. are always
|
||||||
|
# forced active on top of this (see force rules below).
|
||||||
|
# - Set to 100 (with SmartScale off) = all bots always active. Maximum server load.
|
||||||
|
# - Set to 0 = only bots that match a force rule below will be active.
|
||||||
#
|
#
|
||||||
# Specify percent of active bots
|
# BotActiveAloneDurationSeconds
|
||||||
# The default is 100% but will be automatically adjusted if botActiveAloneSmartScale
|
# - How often the active roster rotates (in seconds). A different group of bots wakes up
|
||||||
# is enabled. Regardless, this value is only applied to inactive areas where no real players
|
# and the previous group may go idle.
|
||||||
# are detected. When real players are nearby, the value is always enforced to 100%
|
# - This is a minimum, not exact. If a bot is in combat or meets any force rule when the
|
||||||
AiPlayerbot.BotActiveAlone = 100
|
# rotation happens, it stays active until those conditions end — it won't be cut off
|
||||||
|
# mid-fight just because its turn expired.
|
||||||
|
#
|
||||||
|
AiPlayerbot.BotActiveAlone = 10
|
||||||
|
AiPlayerbot.BotActiveAloneDurationSeconds = 30
|
||||||
|
|
||||||
# Force botActiveAlone when bot is within the specified distance of a real player
|
#
|
||||||
|
# Force-active rules (1 = on, 0 = off)
|
||||||
|
# These override the percentage above. If any of these conditions is true, the bot stays active.
|
||||||
|
#
|
||||||
|
# InRadius - A real player is within this many yards (set to 0 to disable).
|
||||||
|
# InZone - A real player is in the same zone (e.g. Elwynn Forest).
|
||||||
|
# InMap - A real player is on the same continent (e.g. Eastern Kingdoms).
|
||||||
|
# IsFriend - A real player has this bot on their friends list.
|
||||||
|
# InGuild - This bot is in a guild that has a real player in it.
|
||||||
|
#
|
||||||
|
# Bots are also always forced active (not configurable) when:
|
||||||
|
# in combat, inside a dungeon/raid/BG, in a BG or LFG queue,
|
||||||
|
# grouped with a real player, or controlled by a real player.
|
||||||
|
#
|
||||||
AiPlayerbot.BotActiveAloneForceWhenInRadius = 150
|
AiPlayerbot.BotActiveAloneForceWhenInRadius = 150
|
||||||
AiPlayerbot.BotActiveAloneForceWhenInZone = 1
|
AiPlayerbot.BotActiveAloneForceWhenInZone = 1
|
||||||
AiPlayerbot.BotActiveAloneForceWhenInMap = 0
|
AiPlayerbot.BotActiveAloneForceWhenInMap = 0
|
||||||
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 1
|
AiPlayerbot.BotActiveAloneForceWhenIsFriend = 0
|
||||||
AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
|
AiPlayerbot.BotActiveAloneForceWhenInGuild = 1
|
||||||
|
|
||||||
# SmartScale (automatic scaling of percentage of active bots based on latency)
|
# SmartScale — automatically reduces active bots when the server is struggling.
|
||||||
# The default is 1. When enabled (smart) scales the 'BotActiveAlone' value.
|
# Monitors the server's update time (how long each server tick takes in milliseconds).
|
||||||
# (The scaling will be overruled by the BotActiveAloneForceWhen...rules)
|
# When the server slows down, fewer bots are kept active to reduce load.
|
||||||
#
|
#
|
||||||
# Limitfloor - when DIFF (latency) is above floor, activity scaling begins
|
# Floor (default 50ms) - Below this, no reduction. Server is running fine.
|
||||||
# LimitCeiling - when DIFF (latency) is above ceiling, activity is 0%
|
# Ceiling (default 200ms) - At or above this, all non-forced bots are paused.
|
||||||
|
# Between floor and ceiling, activity scales down gradually.
|
||||||
|
# Example: BotActiveAlone=10, floor=50, ceiling=200
|
||||||
|
# Server at 50ms → ~10% active (no reduction)
|
||||||
|
# Server at 125ms → ~5% active (half reduction)
|
||||||
|
# Server at 200ms → 0% active (only forced bots remain)
|
||||||
#
|
#
|
||||||
# MinLevel - only apply scaling when level is above or equal to min(bot)Level
|
# MinLevel/MaxLevel — only bots within this level range are affected by SmartScale.
|
||||||
# MaxLevel - only apply scaling when level is lower or equal of max(bot)Level
|
# Bots outside the range always use the full BotActiveAlone value.
|
||||||
|
# Force rules always win over SmartScale.
|
||||||
#
|
#
|
||||||
AiPlayerbot.botActiveAloneSmartScale = 1
|
AiPlayerbot.botActiveAloneSmartScale = 1
|
||||||
AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor = 50
|
AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor = 50
|
||||||
@ -1687,7 +1718,7 @@ AiPlayerbot.PremadeSpecLink.9.1.60 = -003203301135112530135201051
|
|||||||
AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
|
AiPlayerbot.PremadeSpecLink.9.1.70 = -003203301135112530135201051-55
|
||||||
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
|
AiPlayerbot.PremadeSpecLink.9.1.80 = -003203301135112530135221351-55000005
|
||||||
AiPlayerbot.PremadeSpecName.9.2 = destro pve
|
AiPlayerbot.PremadeSpecName.9.2 = destro pve
|
||||||
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,45785
|
AiPlayerbot.PremadeSpecGlyph.9.2 = 45785,43390,42454,43394,43393,42453
|
||||||
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
|
AiPlayerbot.PremadeSpecLink.9.2.60 = --05203215200231051305031151
|
||||||
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
|
AiPlayerbot.PremadeSpecLink.9.2.80 = 23-0302-05203215220331051335231351
|
||||||
AiPlayerbot.PremadeSpecName.9.3 = affli pvp
|
AiPlayerbot.PremadeSpecName.9.3 = affli pvp
|
||||||
|
|||||||
@ -151,7 +151,9 @@ bool CastMeleeSpellAction::isUseful()
|
|||||||
return CastSpellAction::isUseful();
|
return CastSpellAction::isUseful();
|
||||||
}
|
}
|
||||||
|
|
||||||
CastMeleeDebuffSpellAction::CastMeleeDebuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner, float needLifeTime) : CastDebuffSpellAction(botAI, spell, isOwner, needLifeTime)
|
CastMeleeDebuffSpellAction::CastMeleeDebuffSpellAction(
|
||||||
|
PlayerbotAI* botAI, std::string const spell, bool isOwner, float needLifeTime) :
|
||||||
|
CastDebuffSpellAction(botAI, spell, isOwner, needLifeTime)
|
||||||
{
|
{
|
||||||
range = ATTACK_DISTANCE;
|
range = ATTACK_DISTANCE;
|
||||||
}
|
}
|
||||||
@ -203,6 +205,35 @@ bool CastEnchantItemAction::isPossible()
|
|||||||
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
|
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CastEnchantItemMainHandAction::CastEnchantItemMainHandAction(PlayerbotAI* botAI, std::string const spell)
|
||||||
|
: CastEnchantItemAction(botAI, spell) {}
|
||||||
|
|
||||||
|
bool CastEnchantItemMainHandAction::isPossible()
|
||||||
|
{
|
||||||
|
if (!CastEnchantItemAction::isPossible())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
|
||||||
|
return item && !item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT) &&
|
||||||
|
item->GetTemplate()->Class == ITEM_CLASS_WEAPON;
|
||||||
|
}
|
||||||
|
|
||||||
|
CastEnchantItemOffHandAction::CastEnchantItemOffHandAction(PlayerbotAI* botAI, std::string const spell)
|
||||||
|
: CastEnchantItemAction(botAI, spell) {}
|
||||||
|
|
||||||
|
bool CastEnchantItemOffHandAction::isPossible()
|
||||||
|
{
|
||||||
|
if (!CastEnchantItemAction::isPossible())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
|
||||||
|
if (!item || item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 invType = item->GetTemplate()->InventoryType;
|
||||||
|
return invType == INVTYPE_WEAPON || invType == INVTYPE_WEAPONOFFHAND;
|
||||||
|
}
|
||||||
|
|
||||||
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount,
|
CastHealingSpellAction::CastHealingSpellAction(PlayerbotAI* botAI, std::string const spell, uint8 estAmount,
|
||||||
HealingManaEfficiency manaEfficiency, bool isOwner)
|
HealingManaEfficiency manaEfficiency, bool isOwner)
|
||||||
: CastAuraSpellAction(botAI, spell, isOwner), estAmount(estAmount), manaEfficiency(manaEfficiency)
|
: CastAuraSpellAction(botAI, spell, isOwner), estAmount(estAmount), manaEfficiency(manaEfficiency)
|
||||||
|
|||||||
@ -130,6 +130,20 @@ public:
|
|||||||
std::string const GetTargetName() override { return "self target"; }
|
std::string const GetTargetName() override { return "self target"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastEnchantItemMainHandAction : public CastEnchantItemAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastEnchantItemMainHandAction(PlayerbotAI* botAI, std::string const spell);
|
||||||
|
bool isPossible() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CastEnchantItemOffHandAction : public CastEnchantItemAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastEnchantItemOffHandAction(PlayerbotAI* botAI, std::string const spell);
|
||||||
|
bool isPossible() override;
|
||||||
|
};
|
||||||
|
|
||||||
class CastHealingSpellAction : public CastAuraSpellAction
|
class CastHealingSpellAction : public CastAuraSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -74,8 +74,18 @@ bool MoveToTravelTargetAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
float maxDistance = target->getDestination()->getRadiusMin();
|
float maxDistance = target->getDestination()->getRadiusMin();
|
||||||
|
|
||||||
// Evenly distribute around the target.
|
// Spread bots around the target but keep the offset stable per
|
||||||
float angle = 2 * M_PI * urand(0, 100) / 100.0;
|
// (bot, destination) pair. Previously the angle and radius were
|
||||||
|
// re-rolled every time the action re-entered (i.e. every tick the
|
||||||
|
// bot wasn't already moving), which made bots oscillate between
|
||||||
|
// two random points around the same quest POI instead of
|
||||||
|
// committing to one approach.
|
||||||
|
uint32 botLow = bot->GetGUID().GetCounter();
|
||||||
|
int32 destSeed = static_cast<int32>(location.GetPositionX()) * 73856093 ^
|
||||||
|
static_cast<int32>(location.GetPositionY()) * 19349663;
|
||||||
|
uint32 seed = botLow ^ static_cast<uint32>(destSeed);
|
||||||
|
float angle = 2.0f * static_cast<float>(M_PI) * static_cast<float>(seed % 1000) / 1000.0f;
|
||||||
|
float mod = 0.5f + static_cast<float>((seed / 1000) % 1000) / 2000.0f; // [0.5, 1.0]
|
||||||
|
|
||||||
if (target->getMaxTravelTime() > target->getTimeLeft()) // The bot is late. Speed it up.
|
if (target->getMaxTravelTime() > target->getTimeLeft()) // The bot is late. Speed it up.
|
||||||
{
|
{
|
||||||
@ -89,9 +99,6 @@ bool MoveToTravelTargetAction::Execute(Event /*event*/)
|
|||||||
float z = location.GetPositionZ();
|
float z = location.GetPositionZ();
|
||||||
float mapId = location.GetMapId();
|
float mapId = location.GetMapId();
|
||||||
|
|
||||||
// Move between 0.5 and 1.0 times the maxDistance.
|
|
||||||
float mod = frand(50.f, 100.f) / 100.0f;
|
|
||||||
|
|
||||||
x += cos(angle) * maxDistance * mod;
|
x += cos(angle) * maxDistance * mod;
|
||||||
y += sin(angle) * maxDistance * mod;
|
y += sin(angle) * maxDistance * mod;
|
||||||
|
|
||||||
|
|||||||
@ -101,6 +101,11 @@ bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPrior
|
|||||||
float x = target->GetPositionX() + cos(angle) * distance;
|
float x = target->GetPositionX() + cos(angle) * distance;
|
||||||
float y = target->GetPositionY() + sin(angle) * distance;
|
float y = target->GetPositionY() + sin(angle) * distance;
|
||||||
float z = target->GetPositionZ();
|
float z = target->GetPositionZ();
|
||||||
|
// Clamp Z to the terrain under the offset point so we don't
|
||||||
|
// hand PointMovementGenerator a Z that matches the target's
|
||||||
|
// floor but not the sampled (x,y) — avoids straight-line
|
||||||
|
// fallbacks through geometry.
|
||||||
|
bot->UpdateAllowedPositionZ(x, y, z);
|
||||||
|
|
||||||
if (!bot->IsWithinLOS(x, y, z))
|
if (!bot->IsWithinLOS(x, y, z))
|
||||||
continue;
|
continue;
|
||||||
@ -250,7 +255,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
// bot->CastStop();
|
// bot->CastStop();
|
||||||
// botAI->InterruptSpell();
|
// botAI->InterruptSpell();
|
||||||
// }
|
// }
|
||||||
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
DoMovePoint(bot, x, y, modifiedZ, generatePath, backwards);
|
||||||
float delay = 1000.0f * MoveDelay(distance, backwards);
|
float delay = 1000.0f * MoveDelay(distance, backwards);
|
||||||
if (lessDelay)
|
if (lessDelay)
|
||||||
{
|
{
|
||||||
@ -258,7 +263,8 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
}
|
}
|
||||||
delay = std::max(.0f, delay);
|
delay = std::max(.0f, delay);
|
||||||
delay = std::min((float)sPlayerbotAIConfig.maxWaitForMove, delay);
|
delay = std::min((float)sPlayerbotAIConfig.maxWaitForMove, delay);
|
||||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
AI_VALUE(LastMovement&, "last movement")
|
||||||
|
.Set(mapId, x, y, modifiedZ, bot->GetOrientation(), delay, priority);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -778,15 +784,17 @@ bool MovementAction::MoveTo(WorldObject* target, float distance, MovementPriorit
|
|||||||
|
|
||||||
float dx = cos(angle) * needToGo + bx;
|
float dx = cos(angle) * needToGo + bx;
|
||||||
float dy = sin(angle) * needToGo + by;
|
float dy = sin(angle) * needToGo + by;
|
||||||
float dz; // = std::max(bz, tz); // calc accurate z position to avoid stuck
|
// Start from a seed Z between bot and target, then clamp to the
|
||||||
|
// terrain under (dx,dy). Linear interpolation alone ignores hills
|
||||||
|
// between the two units and fed PointMovementGenerator a Z that
|
||||||
|
// could be well above/below ground, triggering straight-line
|
||||||
|
// fallbacks through walls.
|
||||||
|
float dz;
|
||||||
if (distanceToTarget > CONTACT_DISTANCE)
|
if (distanceToTarget > CONTACT_DISTANCE)
|
||||||
{
|
|
||||||
dz = bz + (tz - bz) * (needToGo / distanceToTarget);
|
dz = bz + (tz - bz) * (needToGo / distanceToTarget);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
dz = tz;
|
dz = tz;
|
||||||
}
|
bot->UpdateAllowedPositionZ(dx, dy, dz);
|
||||||
return MoveTo(target->GetMapId(), dx, dy, dz, false, false, false, false, priority);
|
return MoveTo(target->GetMapId(), dx, dy, dz, false, false, false, false, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,12 @@ WorldPosition GetBestPoint(AiObjectContext* context, Player* bot, Unit* target,
|
|||||||
float z = targetPosition.GetPositionZ() + 1.0f;
|
float z = targetPosition.GetPositionZ() + 1.0f;
|
||||||
|
|
||||||
WorldPosition point(targetPosition.GetMapId(), x, y, z);
|
WorldPosition point(targetPosition.GetMapId(), x, y, z);
|
||||||
point.setZ(point.getHeight());
|
|
||||||
|
float groundZ = bot->GetMapHeight(x, y, z);
|
||||||
|
if (groundZ == INVALID_HEIGHT || groundZ == VMAP_INVALID_HEIGHT_VALUE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
point.setZ(groundZ);
|
||||||
|
|
||||||
// Check line of sight to target
|
// Check line of sight to target
|
||||||
if (!target->IsWithinLOS(point.GetPositionX(), point.GetPositionY(),
|
if (!target->IsWithinLOS(point.GetPositionX(), point.GetPositionY(),
|
||||||
@ -88,8 +93,11 @@ bool WaitForAttackKeepSafeDistanceAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
// If our target is moving towards a stationary unit, use that unit as anchor
|
// If our target is moving towards a stationary unit, use that unit as anchor
|
||||||
if (target && !target->IsStopped())
|
if (!target->IsStopped())
|
||||||
{
|
{
|
||||||
ObjectGuid targetGuid = target->GetTarget();
|
ObjectGuid targetGuid = target->GetTarget();
|
||||||
if (targetGuid)
|
if (targetGuid)
|
||||||
@ -100,7 +108,7 @@ bool WaitForAttackKeepSafeDistanceAction::Execute(Event /*event*/)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target && target->IsAlive())
|
if (target->IsAlive())
|
||||||
{
|
{
|
||||||
float safeDistance = std::max(
|
float safeDistance = std::max(
|
||||||
target->GetCombatReach() + ATTACK_DISTANCE,
|
target->GetCombatReach() + ATTACK_DISTANCE,
|
||||||
|
|||||||
@ -481,6 +481,13 @@ bool FearCharmSleepTrigger::IsActive()
|
|||||||
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP);
|
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FearSleepSapTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
||||||
|
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP) ||
|
||||||
|
bot->HasAuraWithMechanic(1 << MECHANIC_SAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
bool HasAuraStackTrigger::IsActive()
|
bool HasAuraStackTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, stack);
|
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, stack);
|
||||||
|
|||||||
@ -762,6 +762,14 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FearSleepSapTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FearSleepSapTrigger(PlayerbotAI* botAI) : Trigger(botAI, "fear sleep sap", 1) {}
|
||||||
|
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
class IsSwimmingTrigger : public Trigger
|
class IsSwimmingTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -16,5 +16,5 @@ bool NoRtiTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* target = AI_VALUE(Unit*, "rti target");
|
Unit* target = AI_VALUE(Unit*, "rti target");
|
||||||
return target != nullptr;
|
return target == nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,6 +62,7 @@ public:
|
|||||||
creators["generic boost"] = &TriggerContext::generic_boost;
|
creators["generic boost"] = &TriggerContext::generic_boost;
|
||||||
creators["loss of control"] = &TriggerContext::loss_of_control;
|
creators["loss of control"] = &TriggerContext::loss_of_control;
|
||||||
creators["fear charm sleep"] = &TriggerContext::fear_charm_sleep;
|
creators["fear charm sleep"] = &TriggerContext::fear_charm_sleep;
|
||||||
|
creators["fear sleep sap"] = &TriggerContext::fear_sleep_sap;
|
||||||
|
|
||||||
creators["protect party member"] = &TriggerContext::protect_party_member;
|
creators["protect party member"] = &TriggerContext::protect_party_member;
|
||||||
|
|
||||||
@ -369,6 +370,7 @@ private:
|
|||||||
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
|
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
|
||||||
static Trigger* loss_of_control(PlayerbotAI* botAI) { return new LossOfControlTrigger(botAI); }
|
static Trigger* loss_of_control(PlayerbotAI* botAI) { return new LossOfControlTrigger(botAI); }
|
||||||
static Trigger* fear_charm_sleep(PlayerbotAI* botAI) { return new FearCharmSleepTrigger(botAI); }
|
static Trigger* fear_charm_sleep(PlayerbotAI* botAI) { return new FearCharmSleepTrigger(botAI); }
|
||||||
|
static Trigger* fear_sleep_sap(PlayerbotAI* botAI) { return new FearSleepSapTrigger(botAI); }
|
||||||
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
|
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new PartyMemberCriticalHealthTrigger(botAI);
|
return new PartyMemberCriticalHealthTrigger(botAI);
|
||||||
|
|||||||
64
src/Ai/Base/Value/PartyMemberSnaredTargetValue.cpp
Normal file
64
src/Ai/Base/Value/PartyMemberSnaredTargetValue.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||||
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PartyMemberSnaredTargetValue.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "PlayerbotAIAware.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
class PartyMemberSnaredTargetPredicate : public FindPlayerPredicate, public PlayerbotAIAware
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PartyMemberSnaredTargetPredicate(PlayerbotAI* botAI)
|
||||||
|
: PlayerbotAIAware(botAI)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Check(Unit* unit) override
|
||||||
|
{
|
||||||
|
if (!unit || !unit->IsAlive() || !unit->IsInWorld() || unit == botAI->GetBot())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (unit->GetMapId() != botAI->GetBot()->GetMapId())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!botAI->GetBot()->IsWithinLOSInMap(unit))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return botAI->IsMovementImpaired(unit);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Unit* PartyMemberSnaredTargetValue::Calculate()
|
||||||
|
{
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
PartyMemberSnaredTargetPredicate predicate(botAI);
|
||||||
|
Player* bestTarget = nullptr;
|
||||||
|
float closestDistanceSq = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
|
{
|
||||||
|
Player* member = gref->GetSource();
|
||||||
|
if (!member)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!predicate.Check(member))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float const distanceSq = bot->GetExactDist2dSq(member->GetPositionX(), member->GetPositionY());
|
||||||
|
if (distanceSq < closestDistanceSq)
|
||||||
|
{
|
||||||
|
closestDistanceSq = distanceSq;
|
||||||
|
bestTarget = member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestTarget;
|
||||||
|
}
|
||||||
24
src/Ai/Base/Value/PartyMemberSnaredTargetValue.h
Normal file
24
src/Ai/Base/Value/PartyMemberSnaredTargetValue.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||||
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PLAYERBOT_PARTYMEMBERSNAREDTARGETVALUE_H
|
||||||
|
#define _PLAYERBOT_PARTYMEMBERSNAREDTARGETVALUE_H
|
||||||
|
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "PartyMemberValue.h"
|
||||||
|
|
||||||
|
class PartyMemberSnaredTargetValue : public PartyMemberValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PartyMemberSnaredTargetValue(PlayerbotAI* botAI, std::string const name = "party member snared target")
|
||||||
|
: PartyMemberValue(botAI, name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Unit* Calculate() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -66,6 +66,7 @@
|
|||||||
#include "PartyMemberToDispel.h"
|
#include "PartyMemberToDispel.h"
|
||||||
#include "PartyMemberToHeal.h"
|
#include "PartyMemberToHeal.h"
|
||||||
#include "PartyMemberToResurrect.h"
|
#include "PartyMemberToResurrect.h"
|
||||||
|
#include "PartyMemberSnaredTargetValue.h"
|
||||||
#include "PartyMemberWithoutAuraValue.h"
|
#include "PartyMemberWithoutAuraValue.h"
|
||||||
#include "PartyMemberWithoutItemValue.h"
|
#include "PartyMemberWithoutItemValue.h"
|
||||||
#include "PetTargetValue.h"
|
#include "PetTargetValue.h"
|
||||||
@ -152,6 +153,7 @@ public:
|
|||||||
creators["duel target"] = &ValueContext::duel_target;
|
creators["duel target"] = &ValueContext::duel_target;
|
||||||
creators["party member to dispel"] = &ValueContext::party_member_to_dispel;
|
creators["party member to dispel"] = &ValueContext::party_member_to_dispel;
|
||||||
creators["party member to protect"] = &ValueContext::party_member_to_protect;
|
creators["party member to protect"] = &ValueContext::party_member_to_protect;
|
||||||
|
creators["party member snared target"] = &ValueContext::party_member_snared_target;
|
||||||
creators["health"] = &ValueContext::health;
|
creators["health"] = &ValueContext::health;
|
||||||
creators["rage"] = &ValueContext::rage;
|
creators["rage"] = &ValueContext::rage;
|
||||||
creators["energy"] = &ValueContext::energy;
|
creators["energy"] = &ValueContext::energy;
|
||||||
@ -450,6 +452,7 @@ private:
|
|||||||
static UntypedValue* party_member_to_resurrect(PlayerbotAI* botAI) { return new PartyMemberToResurrect(botAI); }
|
static UntypedValue* party_member_to_resurrect(PlayerbotAI* botAI) { return new PartyMemberToResurrect(botAI); }
|
||||||
static UntypedValue* party_member_to_dispel(PlayerbotAI* botAI) { return new PartyMemberToDispel(botAI); }
|
static UntypedValue* party_member_to_dispel(PlayerbotAI* botAI) { return new PartyMemberToDispel(botAI); }
|
||||||
static UntypedValue* party_member_to_protect(PlayerbotAI* botAI) { return new PartyMemberToProtect(botAI); }
|
static UntypedValue* party_member_to_protect(PlayerbotAI* botAI) { return new PartyMemberToProtect(botAI); }
|
||||||
|
static UntypedValue* party_member_snared_target(PlayerbotAI* botAI) { return new PartyMemberSnaredTargetValue(botAI); }
|
||||||
static UntypedValue* current_target(PlayerbotAI* botAI) { return new CurrentTargetValue(botAI); }
|
static UntypedValue* current_target(PlayerbotAI* botAI) { return new CurrentTargetValue(botAI); }
|
||||||
static UntypedValue* old_target(PlayerbotAI* botAI) { return new CurrentTargetValue(botAI); }
|
static UntypedValue* old_target(PlayerbotAI* botAI) { return new CurrentTargetValue(botAI); }
|
||||||
static UntypedValue* self_target(PlayerbotAI* botAI) { return new SelfTargetValue(botAI); }
|
static UntypedValue* self_target(PlayerbotAI* botAI) { return new SelfTargetValue(botAI); }
|
||||||
|
|||||||
@ -48,3 +48,55 @@ bool CastRaiseDeadAction::Execute(Event event)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Unit* CastHysteriaAction::GetTarget()
|
||||||
|
{
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
{
|
||||||
|
if (!bot->HasAura(49016))
|
||||||
|
return bot;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit* rangedDps = nullptr;
|
||||||
|
Unit* tank = nullptr;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member->GetMap() != bot->GetMap() || bot->GetDistance(member) > sPlayerbotAIConfig.spellDistance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip if already has hysteria
|
||||||
|
if (member->HasAura(49016))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Priority 1: Melee DPS
|
||||||
|
if (botAI->IsMelee(member) && botAI->IsDps(member))
|
||||||
|
return member;
|
||||||
|
|
||||||
|
// Priority 2: Ranged DPS (physical, not casters)
|
||||||
|
if (!rangedDps && botAI->IsRanged(member) && botAI->IsDps(member) && !botAI->IsCaster(member))
|
||||||
|
rangedDps = member;
|
||||||
|
|
||||||
|
// Priority 3: Tank
|
||||||
|
if (!tank && botAI->IsTank(member))
|
||||||
|
tank = member;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rangedDps)
|
||||||
|
return rangedDps;
|
||||||
|
|
||||||
|
if (tank)
|
||||||
|
return tank;
|
||||||
|
|
||||||
|
// Fallback to self if no hysteria
|
||||||
|
if (!bot->HasAura(49016))
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|||||||
@ -340,4 +340,11 @@ public:
|
|||||||
CastBloodTapAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "blood tap") {}
|
CastBloodTapAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "blood tap") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastHysteriaAction : public CastSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastHysteriaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "hysteria") {}
|
||||||
|
Unit* GetTarget() override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -100,6 +100,7 @@ public:
|
|||||||
creators["dd cd and no desolation"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_no_desolation;
|
creators["dd cd and no desolation"] = &DeathKnightTriggerFactoryInternal::dd_cd_and_no_desolation;
|
||||||
creators["death and decay cooldown"] = &DeathKnightTriggerFactoryInternal::death_and_decay_cooldown;
|
creators["death and decay cooldown"] = &DeathKnightTriggerFactoryInternal::death_and_decay_cooldown;
|
||||||
creators["army of the dead"] = &DeathKnightTriggerFactoryInternal::army_of_the_dead;
|
creators["army of the dead"] = &DeathKnightTriggerFactoryInternal::army_of_the_dead;
|
||||||
|
creators["hysteria no cd"] = &DeathKnightTriggerFactoryInternal::hysteria_no_cd;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -152,6 +153,7 @@ private:
|
|||||||
}
|
}
|
||||||
static Trigger* death_and_decay_cooldown(PlayerbotAI* botAI) { return new DeathAndDecayCooldownTrigger(botAI); }
|
static Trigger* death_and_decay_cooldown(PlayerbotAI* botAI) { return new DeathAndDecayCooldownTrigger(botAI); }
|
||||||
static Trigger* army_of_the_dead(PlayerbotAI* botAI) { return new ArmyOfTheDeadTrigger(botAI); }
|
static Trigger* army_of_the_dead(PlayerbotAI* botAI) { return new ArmyOfTheDeadTrigger(botAI); }
|
||||||
|
static Trigger* hysteria_no_cd(PlayerbotAI* botAI) { return new HysteriaNoCooldownTrigger(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeathKnightAiObjectContextInternal : public NamedObjectContext<Action>
|
class DeathKnightAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
@ -209,7 +211,7 @@ public:
|
|||||||
creators["vampiric blood"] = &DeathKnightAiObjectContextInternal::vampiric_blood;
|
creators["vampiric blood"] = &DeathKnightAiObjectContextInternal::vampiric_blood;
|
||||||
creators["death pact"] = &DeathKnightAiObjectContextInternal::death_pact;
|
creators["death pact"] = &DeathKnightAiObjectContextInternal::death_pact;
|
||||||
creators["death rune_mastery"] = &DeathKnightAiObjectContextInternal::death_rune_mastery;
|
creators["death rune_mastery"] = &DeathKnightAiObjectContextInternal::death_rune_mastery;
|
||||||
// creators["hysteria"] = &DeathKnightAiObjectContextInternal::hysteria;
|
creators["hysteria"] = &DeathKnightAiObjectContextInternal::hysteria;
|
||||||
creators["dancing rune weapon"] = &DeathKnightAiObjectContextInternal::dancing_rune_weapon;
|
creators["dancing rune weapon"] = &DeathKnightAiObjectContextInternal::dancing_rune_weapon;
|
||||||
creators["dark command"] = &DeathKnightAiObjectContextInternal::dark_command;
|
creators["dark command"] = &DeathKnightAiObjectContextInternal::dark_command;
|
||||||
}
|
}
|
||||||
@ -265,7 +267,7 @@ private:
|
|||||||
static Action* vampiric_blood(PlayerbotAI* botAI) { return new CastVampiricBloodAction(botAI); }
|
static Action* vampiric_blood(PlayerbotAI* botAI) { return new CastVampiricBloodAction(botAI); }
|
||||||
static Action* death_pact(PlayerbotAI* botAI) { return new CastDeathPactAction(botAI); }
|
static Action* death_pact(PlayerbotAI* botAI) { return new CastDeathPactAction(botAI); }
|
||||||
static Action* death_rune_mastery(PlayerbotAI* botAI) { return new CastDeathRuneMasteryAction(botAI); }
|
static Action* death_rune_mastery(PlayerbotAI* botAI) { return new CastDeathRuneMasteryAction(botAI); }
|
||||||
// static Action* hysteria(PlayerbotAI* botAI) { return new CastHysteriaAction(botAI); }
|
static Action* hysteria(PlayerbotAI* botAI) { return new CastHysteriaAction(botAI); }
|
||||||
static Action* dancing_rune_weapon(PlayerbotAI* botAI) { return new CastDancingRuneWeaponAction(botAI); }
|
static Action* dancing_rune_weapon(PlayerbotAI* botAI) { return new CastDancingRuneWeaponAction(botAI); }
|
||||||
static Action* dark_command(PlayerbotAI* botAI) { return new CastDarkCommandAction(botAI); }
|
static Action* dark_command(PlayerbotAI* botAI) { return new CastDarkCommandAction(botAI); }
|
||||||
static Action* mind_freeze_on_enemy_healer(PlayerbotAI* botAI)
|
static Action* mind_freeze_on_enemy_healer(PlayerbotAI* botAI)
|
||||||
|
|||||||
@ -50,7 +50,9 @@ private:
|
|||||||
{
|
{
|
||||||
NextAction("frost presence")
|
NextAction("frost presence")
|
||||||
},
|
},
|
||||||
/*A*/ {},
|
/*A*/ {
|
||||||
|
NextAction("blood strike")
|
||||||
|
},
|
||||||
/*C*/ {}
|
/*C*/ {}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -89,13 +91,11 @@ BloodDKStrategy::BloodDKStrategy(PlayerbotAI* botAI) : GenericDKStrategy(botAI)
|
|||||||
std::vector<NextAction> BloodDKStrategy::getDefaultActions()
|
std::vector<NextAction> BloodDKStrategy::getDefaultActions()
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
NextAction("rune strike", ACTION_DEFAULT + 0.8f),
|
NextAction("rune strike", ACTION_DEFAULT + 0.6f),
|
||||||
NextAction("icy touch", ACTION_DEFAULT + 0.7f),
|
NextAction("icy touch", ACTION_DEFAULT + 0.5f),
|
||||||
NextAction("heart strike", ACTION_DEFAULT + 0.6f),
|
NextAction("heart strike", ACTION_DEFAULT + 0.4f),
|
||||||
NextAction("blood strike", ACTION_DEFAULT + 0.5f),
|
NextAction("dancing rune weapon", ACTION_DEFAULT + 0.3f),
|
||||||
NextAction("dancing rune weapon", ACTION_DEFAULT + 0.4f),
|
NextAction("death coil", ACTION_DEFAULT + 0.2f),
|
||||||
NextAction("death coil", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("plague strike", ACTION_DEFAULT + 0.2f),
|
|
||||||
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
NextAction("melee", ACTION_DEFAULT)
|
||||||
};
|
};
|
||||||
@ -105,6 +105,14 @@ void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
GenericDKStrategy::InitTriggers(triggers);
|
GenericDKStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode(
|
||||||
|
"hysteria no cd",
|
||||||
|
{
|
||||||
|
NextAction("hysteria", ACTION_NORMAL + 4)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode(
|
new TriggerNode(
|
||||||
"rune strike",
|
"rune strike",
|
||||||
@ -162,4 +170,12 @@ void BloodDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode(
|
||||||
|
"high unholy rune",
|
||||||
|
{
|
||||||
|
NextAction("death strike", ACTION_HIGH + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,6 @@ std::vector<NextAction> FrostDKStrategy::getDefaultActions()
|
|||||||
return {
|
return {
|
||||||
NextAction("obliterate", ACTION_DEFAULT + 0.7f),
|
NextAction("obliterate", ACTION_DEFAULT + 0.7f),
|
||||||
NextAction("frost strike", ACTION_DEFAULT + 0.4f),
|
NextAction("frost strike", ACTION_DEFAULT + 0.4f),
|
||||||
NextAction("empower rune weapon", ACTION_DEFAULT + 0.3f),
|
|
||||||
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
NextAction("horn of winter", ACTION_DEFAULT + 0.1f),
|
||||||
NextAction("melee", ACTION_DEFAULT)
|
NextAction("melee", ACTION_DEFAULT)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -41,16 +41,10 @@ void GenericDKNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
{
|
{
|
||||||
NonCombatStrategy::InitTriggers(triggers);
|
NonCombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no pet", { NextAction("raise dead", ACTION_NORMAL + 1) }));
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("horn of winter", { NextAction("horn of winter", 21.0f) }));
|
new TriggerNode("horn of winter", { NextAction("horn of winter", 21.0f) }));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("bone shield", { NextAction("bone shield", 21.0f) }));
|
new TriggerNode("bone shield", { NextAction("bone shield", 21.0f) }));
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void DKBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@ -165,12 +165,6 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
MeleeCombatStrategy::InitTriggers(triggers);
|
MeleeCombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no pet", { NextAction("raise dead", ACTION_NORMAL + 5) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f) }));
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("mind freeze", { NextAction("mind freeze", ACTION_HIGH + 1) }));
|
new TriggerNode("mind freeze", { NextAction("mind freeze", ACTION_HIGH + 1) }));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
@ -179,7 +173,8 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"horn of winter", { NextAction("horn of winter", ACTION_NORMAL + 1) }));
|
"horn of winter", { NextAction("horn of winter", ACTION_NORMAL + 1) }));
|
||||||
triggers.push_back(new TriggerNode("critical health",
|
triggers.push_back(new TriggerNode("critical health",
|
||||||
{ NextAction("death pact", ACTION_HIGH + 5) }));
|
{ NextAction("raise dead", ACTION_HIGH + 6),
|
||||||
|
NextAction("death pact", ACTION_HIGH + 5) }));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("low health", { NextAction("icebound fortitude", ACTION_HIGH + 5),
|
new TriggerNode("low health", { NextAction("icebound fortitude", ACTION_HIGH + 5),
|
||||||
@ -190,4 +185,11 @@ void GenericDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
NextAction("blood boil", ACTION_NORMAL + 3) }));
|
NextAction("blood boil", ACTION_NORMAL + 3) }));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("pestilence glyph", { NextAction("pestilence", ACTION_HIGH + 9) }));
|
new TriggerNode("pestilence glyph", { NextAction("pestilence", ACTION_HIGH + 9) }));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("no rune",
|
||||||
|
{
|
||||||
|
NextAction("empower rune weapon", ACTION_HIGH + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,6 +87,13 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
GenericDKStrategy::InitTriggers(triggers);
|
GenericDKStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("no pet", { NextAction("raise dead", ACTION_NORMAL + 5) }));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f) }));
|
||||||
|
triggers.push_back(
|
||||||
|
new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode(
|
new TriggerNode(
|
||||||
"death and decay cooldown",
|
"death and decay cooldown",
|
||||||
@ -146,13 +153,6 @@ void UnholyDKStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no rune",
|
|
||||||
{
|
|
||||||
NextAction("empower rune weapon", ACTION_HIGH + 1)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode(
|
new TriggerNode(
|
||||||
"army of the dead",
|
"army of the dead",
|
||||||
|
|||||||
@ -198,4 +198,10 @@ public:
|
|||||||
ArmyOfTheDeadTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "army of the dead") {}
|
ArmyOfTheDeadTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "army of the dead") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HysteriaNoCooldownTrigger : public SpellNoCooldownTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HysteriaNoCooldownTrigger(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, "hysteria") {}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -23,6 +23,12 @@ public:
|
|||||||
CastGrowlAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "growl") {}
|
CastGrowlAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "growl") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastChallengingRoarAction : public CastMeleeDebuffSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastChallengingRoarAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "challenging roar") {}
|
||||||
|
};
|
||||||
|
|
||||||
class CastMaulAction : public CastMeleeSpellAction
|
class CastMaulAction : public CastMeleeSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -183,6 +183,7 @@ public:
|
|||||||
creators["bash"] = &DruidAiObjectContextInternal::bash;
|
creators["bash"] = &DruidAiObjectContextInternal::bash;
|
||||||
creators["swipe"] = &DruidAiObjectContextInternal::swipe;
|
creators["swipe"] = &DruidAiObjectContextInternal::swipe;
|
||||||
creators["growl"] = &DruidAiObjectContextInternal::growl;
|
creators["growl"] = &DruidAiObjectContextInternal::growl;
|
||||||
|
creators["challenging roar"] = &DruidAiObjectContextInternal::challenging_roar;
|
||||||
creators["demoralizing roar"] = &DruidAiObjectContextInternal::demoralizing_roar;
|
creators["demoralizing roar"] = &DruidAiObjectContextInternal::demoralizing_roar;
|
||||||
creators["hibernate"] = &DruidAiObjectContextInternal::hibernate;
|
creators["hibernate"] = &DruidAiObjectContextInternal::hibernate;
|
||||||
creators["entangling roots"] = &DruidAiObjectContextInternal::entangling_roots;
|
creators["entangling roots"] = &DruidAiObjectContextInternal::entangling_roots;
|
||||||
@ -277,6 +278,7 @@ private:
|
|||||||
static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); }
|
static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); }
|
||||||
static Action* swipe(PlayerbotAI* botAI) { return new CastSwipeAction(botAI); }
|
static Action* swipe(PlayerbotAI* botAI) { return new CastSwipeAction(botAI); }
|
||||||
static Action* growl(PlayerbotAI* botAI) { return new CastGrowlAction(botAI); }
|
static Action* growl(PlayerbotAI* botAI) { return new CastGrowlAction(botAI); }
|
||||||
|
static Action* challenging_roar(PlayerbotAI* botAI) { return new CastChallengingRoarAction(botAI); }
|
||||||
static Action* demoralizing_roar(PlayerbotAI* botAI) { return new CastDemoralizingRoarAction(botAI); }
|
static Action* demoralizing_roar(PlayerbotAI* botAI) { return new CastDemoralizingRoarAction(botAI); }
|
||||||
static Action* moonkin_form(PlayerbotAI* botAI) { return new CastMoonkinFormAction(botAI); }
|
static Action* moonkin_form(PlayerbotAI* botAI) { return new CastMoonkinFormAction(botAI); }
|
||||||
static Action* hibernate(PlayerbotAI* botAI) { return new CastHibernateAction(botAI); }
|
static Action* hibernate(PlayerbotAI* botAI) { return new CastHibernateAction(botAI); }
|
||||||
|
|||||||
@ -212,6 +212,7 @@ void BearTankDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
triggers.push_back(new TriggerNode("high aoe", {NextAction("challenging roar", ACTION_HIGH + 8)}));
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode(
|
new TriggerNode(
|
||||||
"lose aggro",
|
"lose aggro",
|
||||||
|
|||||||
@ -16,18 +16,15 @@ bool CastViperStingAction::isUseful()
|
|||||||
AI_VALUE2(uint8, "mana", "current target") >= 30;
|
AI_VALUE2(uint8, "mana", "current target") >= 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastAspectOfTheCheetahAction::isUseful()
|
|
||||||
{
|
|
||||||
return !botAI->HasAnyAuraOf(GetTarget(), "aspect of the cheetah", "aspect of the pack", nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CastAspectOfTheHawkAction::isUseful()
|
bool CastAspectOfTheHawkAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bot->HasSpell(61846) || bot->HasSpell(61847)) // Aspect of the Dragonhawk spell IDs
|
if (bot->HasSpell(61846) || bot->HasSpell(61847)) // Aspect of the Dragonhawk spell IDs
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +33,14 @@ bool CastArcaneShotAction::isUseful()
|
|||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
if (bot->HasSpell(53301) || bot->HasSpell(60051) || bot->HasSpell(60052) || bot->HasSpell(60053)) // Explosive Shot spell IDs
|
|
||||||
|
if (bot->HasSpell(53301) || bot->HasSpell(60051) ||
|
||||||
|
bot->HasSpell(60052) || bot->HasSpell(60053)) // Explosive Shot spell IDs
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Armor Penetration rating check - will not cast Arcane Shot above 435 ArP
|
// Armor Penetration rating check - will not cast Arcane Shot above 435 ArP
|
||||||
int32 armorPenRating = bot->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1) + bot->GetUInt32Value(CR_ARMOR_PENETRATION);
|
int32 armorPenRating =
|
||||||
|
bot->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1) + bot->GetUInt32Value(CR_ARMOR_PENETRATION);
|
||||||
if (armorPenRating > 435)
|
if (armorPenRating > 435)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -52,18 +52,26 @@ bool CastImmolationTrapAction::isUseful()
|
|||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
if (bot->HasSpell(13813) || bot->HasSpell(14316) || bot->HasSpell(14317) || bot->HasSpell(27025) || bot->HasSpell(49066) || bot->HasSpell(49067)) // Explosive Trap spell IDs
|
|
||||||
|
if (bot->HasSpell(13813) || bot->HasSpell(14316) || bot->HasSpell(14317) || bot->HasSpell(27025) ||
|
||||||
|
bot->HasSpell(49066) || bot->HasSpell(49067)) // Explosive Trap spell IDs
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value<Unit*>* CastFreezingTrap::GetTargetValue() { return context->GetValue<Unit*>("cc target", "freezing trap"); }
|
Value<Unit*>* CastFreezingTrap::GetTargetValue()
|
||||||
|
{
|
||||||
|
return context->GetValue<Unit*>("cc target", "freezing trap");
|
||||||
|
}
|
||||||
|
|
||||||
bool FeedPetAction::Execute(Event /*event*/)
|
bool FeedPetAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
if (Pet* pet = bot->GetPet())
|
if (Pet* pet = bot->GetPet(); pet && pet->getPetType() == HUNTER_PET &&
|
||||||
if (pet->getPetType() == HUNTER_PET && pet->GetHappinessState() != HAPPY)
|
pet->GetHappinessState() != HAPPY)
|
||||||
pet->SetPower(POWER_HAPPINESS, pet->GetMaxPower(Powers(POWER_HAPPINESS)));
|
{
|
||||||
|
pet->SetPower(POWER_HAPPINESS, pet->GetMaxPower(Powers(POWER_HAPPINESS)));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -79,6 +87,7 @@ bool CastAutoShotAction::isUseful()
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AI_VALUE(uint32, "active spell") != AI_VALUE2(uint32, "spell id", getName());
|
return AI_VALUE(uint32, "active spell") != AI_VALUE2(uint32, "spell id", getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +96,7 @@ bool CastDisengageAction::Execute(Event event)
|
|||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// can cast spell check passed in isUseful()
|
// can cast spell check passed in isUseful()
|
||||||
bot->SetOrientation(bot->GetAngle(target));
|
bot->SetOrientation(bot->GetAngle(target));
|
||||||
return CastSpellAction::Execute(event);
|
return CastSpellAction::Execute(event);
|
||||||
@ -97,11 +107,20 @@ bool CastDisengageAction::isUseful()
|
|||||||
return !botAI->HasStrategy("trap weave", BOT_STATE_COMBAT);
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
bool CastWingClipAction::isUseful() { return CastSpellAction::isUseful() && !botAI->HasAura(spell, GetTarget()); }
|
bool CastWingClipAction::isUseful()
|
||||||
|
{
|
||||||
|
return CastSpellAction::isUseful() && !botAI->HasAura(spell, GetTarget());
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<NextAction> CastWingClipAction::getPrerequisites()
|
std::vector<NextAction> CastWingClipAction::getPrerequisites()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -19,52 +19,58 @@ class Unit;
|
|||||||
class CastTrueshotAuraAction : public CastBuffSpellAction
|
class CastTrueshotAuraAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastTrueshotAuraAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "trueshot aura") {}
|
CastTrueshotAuraAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "trueshot aura") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CastAspectOfTheDragonhawkAction : public CastBuffSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastAspectOfTheDragonhawkAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "aspect of the dragonhawk") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAspectOfTheHawkAction : public CastBuffSpellAction
|
class CastAspectOfTheHawkAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAspectOfTheHawkAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the hawk") {}
|
CastAspectOfTheHawkAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "aspect of the hawk") {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAspectOfTheMonkeyAction : public CastBuffSpellAction
|
class CastAspectOfTheMonkeyAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAspectOfTheMonkeyAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the monkey") {}
|
CastAspectOfTheMonkeyAction(PlayerbotAI* botAI) :
|
||||||
};
|
CastBuffSpellAction(botAI, "aspect of the monkey") {}
|
||||||
|
|
||||||
class CastAspectOfTheDragonhawkAction : public CastBuffSpellAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CastAspectOfTheDragonhawkAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the dragonhawk") {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAspectOfTheWildAction : public CastBuffSpellAction
|
class CastAspectOfTheWildAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAspectOfTheWildAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the wild") {}
|
CastAspectOfTheWildAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "aspect of the wild") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAspectOfTheCheetahAction : public CastBuffSpellAction
|
class CastAspectOfTheCheetahAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAspectOfTheCheetahAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the cheetah") {}
|
CastAspectOfTheCheetahAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "aspect of the cheetah") {}
|
||||||
bool isUseful() override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAspectOfThePackAction : public CastBuffSpellAction
|
class CastAspectOfThePackAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAspectOfThePackAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the pack") {}
|
CastAspectOfThePackAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "aspect of the pack") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAspectOfTheViperAction : public CastBuffSpellAction
|
class CastAspectOfTheViperAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAspectOfTheViperAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the viper") {}
|
CastAspectOfTheViperAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "aspect of the viper") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cooldown Spells
|
// Cooldown Spells
|
||||||
@ -72,26 +78,28 @@ public:
|
|||||||
class CastRapidFireAction : public CastBuffSpellAction
|
class CastRapidFireAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRapidFireAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "rapid fire") {}
|
CastRapidFireAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "rapid fire") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastDeterrenceAction : public CastBuffSpellAction
|
class CastDeterrenceAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastDeterrenceAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "deterrence") {}
|
CastDeterrenceAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "deterrence") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastReadinessAction : public CastBuffSpellAction
|
class CastReadinessAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastReadinessAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "readiness") {}
|
CastReadinessAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "readiness") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastDisengageAction : public CastSpellAction
|
class CastDisengageAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastDisengageAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "disengage") {}
|
CastDisengageAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "disengage") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
@ -101,14 +109,15 @@ public:
|
|||||||
class CastScareBeastAction : public CastSpellAction
|
class CastScareBeastAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastScareBeastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "scare beast") {}
|
CastScareBeastAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "scare beast") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastScareBeastCcAction : public CastSpellAction
|
class CastScareBeastCcAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastScareBeastCcAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "scare beast on cc") {}
|
CastScareBeastCcAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "scare beast on cc") {}
|
||||||
Value<Unit*>* GetTargetValue() override;
|
Value<Unit*>* GetTargetValue() override;
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
@ -116,34 +125,41 @@ public:
|
|||||||
class CastFreezingTrap : public CastDebuffSpellAction
|
class CastFreezingTrap : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFreezingTrap(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "freezing trap") {}
|
CastFreezingTrap(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "freezing trap") {}
|
||||||
Value<Unit*>* GetTargetValue() override;
|
Value<Unit*>* GetTargetValue() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWyvernStingAction : public CastDebuffSpellAction
|
class CastWyvernStingAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWyvernStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "wyvern sting", true) {}
|
CastWyvernStingAction(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "wyvern sting", true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSilencingShotAction : public CastSpellAction
|
class CastSilencingShotAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastSilencingShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "silencing shot") {}
|
CastSilencingShotAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "silencing shot") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastConcussiveShotAction : public CastSnareSpellAction
|
class CastConcussiveShotAction : public CastSnareSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastConcussiveShotAction(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, "concussive shot") {}
|
CastConcussiveShotAction(PlayerbotAI* botAI) :
|
||||||
|
CastSnareSpellAction(botAI, "concussive shot") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastIntimidationAction : public CastBuffSpellAction
|
class CastIntimidationAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastIntimidationAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "intimidation", false, 5000) {}
|
CastIntimidationAction(PlayerbotAI* botAI) :
|
||||||
std::string const GetTargetName() override { return "pet target"; }
|
CastBuffSpellAction(botAI, "intimidation", false, 5000) {}
|
||||||
|
std::string const GetTargetName() override
|
||||||
|
{
|
||||||
|
return "pet target";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Threat Spells
|
// Threat Spells
|
||||||
@ -151,19 +167,22 @@ public:
|
|||||||
class CastDistractingShotAction : public CastSpellAction
|
class CastDistractingShotAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastDistractingShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "distracting shot") {}
|
CastDistractingShotAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "distracting shot") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastMisdirectionOnMainTankAction : public BuffOnMainTankAction
|
class CastMisdirectionOnMainTankAction : public BuffOnMainTankAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastMisdirectionOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "misdirection", true) {}
|
CastMisdirectionOnMainTankAction(PlayerbotAI* botAI) :
|
||||||
|
BuffOnMainTankAction(botAI, "misdirection", true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFeignDeathAction : public CastBuffSpellAction
|
class CastFeignDeathAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFeignDeathAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "feign death") {}
|
CastFeignDeathAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "feign death") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pet Spells
|
// Pet Spells
|
||||||
@ -172,7 +191,6 @@ class FeedPetAction : public Action
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FeedPetAction(PlayerbotAI* botAI) : Action(botAI, "feed pet") {}
|
FeedPetAction(PlayerbotAI* botAI) : Action(botAI, "feed pet") {}
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -186,27 +204,39 @@ class CastMendPetAction : public CastAuraSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastMendPetAction(PlayerbotAI* botAI) : CastAuraSpellAction(botAI, "mend pet") {}
|
CastMendPetAction(PlayerbotAI* botAI) : CastAuraSpellAction(botAI, "mend pet") {}
|
||||||
std::string const GetTargetName() override { return "pet target"; }
|
std::string const GetTargetName() override
|
||||||
|
{
|
||||||
|
return "pet target";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastRevivePetAction : public CastBuffSpellAction
|
class CastRevivePetAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRevivePetAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "revive pet") {}
|
CastRevivePetAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "revive pet") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastKillCommandAction : public CastBuffSpellAction
|
class CastKillCommandAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastKillCommandAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "kill command", false, 5000) {}
|
CastKillCommandAction(PlayerbotAI* botAI) :
|
||||||
std::string const GetTargetName() override { return "pet target"; }
|
CastBuffSpellAction(botAI, "kill command", false, 5000) {}
|
||||||
|
std::string const GetTargetName() override
|
||||||
|
{
|
||||||
|
return "pet target";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastBestialWrathAction : public CastBuffSpellAction
|
class CastBestialWrathAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastBestialWrathAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bestial wrath", false, 5000) {}
|
CastBestialWrathAction(PlayerbotAI* botAI) :
|
||||||
std::string const GetTargetName() override { return "pet target"; }
|
CastBuffSpellAction(botAI, "bestial wrath", false, 5000) {}
|
||||||
|
std::string const GetTargetName() override
|
||||||
|
{
|
||||||
|
return "pet target";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Direct Damage Spells
|
// Direct Damage Spells
|
||||||
@ -215,14 +245,18 @@ class CastAutoShotAction : public CastSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAutoShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "auto shot") {}
|
CastAutoShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "auto shot") {}
|
||||||
ActionThreatType getThreatType() override { return ActionThreatType::None; }
|
ActionThreatType getThreatType() override
|
||||||
|
{
|
||||||
|
return ActionThreatType::None;
|
||||||
|
}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastArcaneShotAction : public CastSpellAction
|
class CastArcaneShotAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastArcaneShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "arcane shot") {}
|
CastArcaneShotAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "arcane shot") {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -235,7 +269,8 @@ public:
|
|||||||
class CastChimeraShotAction : public CastSpellAction
|
class CastChimeraShotAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastChimeraShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chimera shot") {}
|
CastChimeraShotAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "chimera shot") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSteadyShotAction : public CastSpellAction
|
class CastSteadyShotAction : public CastSpellAction
|
||||||
@ -255,7 +290,8 @@ public:
|
|||||||
class CastHuntersMarkAction : public CastDebuffSpellAction
|
class CastHuntersMarkAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastHuntersMarkAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "hunter's mark") {}
|
CastHuntersMarkAction(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "hunter's mark") {}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
// Bypass TTL check
|
// Bypass TTL check
|
||||||
@ -266,20 +302,23 @@ public:
|
|||||||
class CastTranquilizingShotAction : public CastSpellAction
|
class CastTranquilizingShotAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastTranquilizingShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "tranquilizing shot") {}
|
CastTranquilizingShotAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "tranquilizing shot") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastViperStingAction : public CastDebuffSpellAction
|
class CastViperStingAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastViperStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "viper sting", true) {}
|
CastViperStingAction(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "viper sting", true) {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSerpentStingAction : public CastDebuffSpellAction
|
class CastSerpentStingAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastSerpentStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "serpent sting", true) {}
|
CastSerpentStingAction(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "serpent sting", true) {}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
// Bypass TTL check
|
// Bypass TTL check
|
||||||
@ -290,7 +329,8 @@ public:
|
|||||||
class CastScorpidStingAction : public CastDebuffSpellAction
|
class CastScorpidStingAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastScorpidStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "scorpid sting", true) {}
|
CastScorpidStingAction(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "scorpid sting", true) {}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
// Bypass TTL check
|
// Bypass TTL check
|
||||||
@ -301,7 +341,8 @@ public:
|
|||||||
class CastSerpentStingOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
class CastSerpentStingOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastSerpentStingOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "serpent sting", true) {}
|
CastSerpentStingOnAttackerAction(PlayerbotAI* botAI)
|
||||||
|
: CastDebuffSpellOnAttackerAction(botAI, "serpent sting", true) {}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
// Bypass TTL check
|
// Bypass TTL check
|
||||||
@ -312,20 +353,23 @@ public:
|
|||||||
class CastImmolationTrapAction : public CastSpellAction
|
class CastImmolationTrapAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastImmolationTrapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "immolation trap") {}
|
CastImmolationTrapAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "immolation trap") {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastExplosiveTrapAction : public CastSpellAction
|
class CastExplosiveTrapAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastExplosiveTrapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "explosive trap") {}
|
CastExplosiveTrapAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "explosive trap") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastBlackArrow : public CastDebuffSpellAction
|
class CastBlackArrowAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastBlackArrow(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "black arrow", true) {}
|
CastBlackArrowAction(PlayerbotAI* botAI) :
|
||||||
|
CastDebuffSpellAction(botAI, "black arrow", true) {}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
if (botAI->HasStrategy("trap weave", BOT_STATE_COMBAT))
|
if (botAI->HasStrategy("trap weave", BOT_STATE_COMBAT))
|
||||||
@ -335,77 +379,89 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastExplosiveShotAction : public CastDebuffSpellAction
|
class CastExplosiveShotBaseAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastExplosiveShotAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
CastExplosiveShotBaseAction(PlayerbotAI* botAI)
|
||||||
bool isUseful() override
|
: CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
||||||
{
|
|
||||||
// Bypass TTL check
|
|
||||||
return CastAuraSpellAction::isUseful();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rank 4
|
// Rank 4
|
||||||
class CastExplosiveShotRank4Action : public CastDebuffSpellAction
|
class CastExplosiveShotRank4Action : public CastExplosiveShotBaseAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastExplosiveShotRank4Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
CastExplosiveShotRank4Action(PlayerbotAI* botAI) :
|
||||||
|
CastExplosiveShotBaseAction(botAI) {}
|
||||||
bool Execute(Event event) override { return botAI->CastSpell(60053, GetTarget()); }
|
bool Execute(Event event) override
|
||||||
|
{
|
||||||
|
return botAI->CastSpell(60053, GetTarget());
|
||||||
|
}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !target->HasAura(60053);
|
return !target->HasAura(60053);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rank 3
|
// Rank 3
|
||||||
class CastExplosiveShotRank3Action : public CastDebuffSpellAction
|
class CastExplosiveShotRank3Action : public CastExplosiveShotBaseAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastExplosiveShotRank3Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
CastExplosiveShotRank3Action(PlayerbotAI* botAI) :
|
||||||
|
CastExplosiveShotBaseAction(botAI) {}
|
||||||
bool Execute(Event event) override { return botAI->CastSpell(60052, GetTarget()); }
|
bool Execute(Event event) override
|
||||||
|
{
|
||||||
|
return botAI->CastSpell(60052, GetTarget());
|
||||||
|
}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !target->HasAura(60052);
|
return !target->HasAura(60052);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rank 2
|
// Rank 2
|
||||||
class CastExplosiveShotRank2Action : public CastDebuffSpellAction
|
class CastExplosiveShotRank2Action : public CastExplosiveShotBaseAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastExplosiveShotRank2Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
CastExplosiveShotRank2Action(PlayerbotAI* botAI) :
|
||||||
|
CastExplosiveShotBaseAction(botAI) {}
|
||||||
bool Execute(Event event) override { return botAI->CastSpell(60051, GetTarget()); }
|
bool Execute(Event event) override
|
||||||
|
{
|
||||||
|
return botAI->CastSpell(60051, GetTarget());
|
||||||
|
}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !target->HasAura(60051);
|
return !target->HasAura(60051);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Rank 1
|
// Rank 1
|
||||||
class CastExplosiveShotRank1Action : public CastDebuffSpellAction
|
class CastExplosiveShotRank1Action : public CastExplosiveShotBaseAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastExplosiveShotRank1Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
CastExplosiveShotRank1Action(PlayerbotAI* botAI) :
|
||||||
|
CastExplosiveShotBaseAction(botAI) {}
|
||||||
bool Execute(Event event) override { return botAI->CastSpell(53301, GetTarget()); }
|
bool Execute(Event event) override
|
||||||
|
{
|
||||||
|
return botAI->CastSpell(53301, GetTarget());
|
||||||
|
}
|
||||||
bool isUseful() override
|
bool isUseful() override
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return !target->HasAura(53301);
|
return !target->HasAura(53301);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -415,8 +471,8 @@ public:
|
|||||||
class CastWingClipAction : public CastSpellAction
|
class CastWingClipAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWingClipAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "wing clip") {}
|
CastWingClipAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "wing clip") {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
std::vector<NextAction> getPrerequisites() override;
|
std::vector<NextAction> getPrerequisites() override;
|
||||||
};
|
};
|
||||||
@ -424,13 +480,15 @@ public:
|
|||||||
class CastRaptorStrikeAction : public CastSpellAction
|
class CastRaptorStrikeAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRaptorStrikeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "raptor strike") {}
|
CastRaptorStrikeAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "raptor strike") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastMongooseBiteAction : public CastSpellAction
|
class CastMongooseBiteAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastMongooseBiteAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "mongoose bite") {}
|
CastMongooseBiteAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "mongoose bite") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// AoE Spells
|
// AoE Spells
|
||||||
@ -445,7 +503,10 @@ class CastVolleyAction : public CastSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastVolleyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "volley") {}
|
CastVolleyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "volley") {}
|
||||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
ActionThreatType getThreatType() override
|
||||||
|
{
|
||||||
|
return ActionThreatType::Aoe;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -22,7 +22,6 @@ public:
|
|||||||
HunterStrategyFactoryInternal()
|
HunterStrategyFactoryInternal()
|
||||||
{
|
{
|
||||||
creators["nc"] = &HunterStrategyFactoryInternal::nc;
|
creators["nc"] = &HunterStrategyFactoryInternal::nc;
|
||||||
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;
|
creators["trap weave"] = &HunterStrategyFactoryInternal::trap_weave;
|
||||||
@ -34,7 +33,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static Strategy* nc(PlayerbotAI* botAI) { return new GenericHunterNonCombatStrategy(botAI); }
|
static Strategy* nc(PlayerbotAI* botAI) { return new GenericHunterNonCombatStrategy(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); }
|
static Strategy* trap_weave(PlayerbotAI* botAI) { return new HunterTrapWeaveStrategy(botAI); }
|
||||||
@ -51,14 +49,12 @@ public:
|
|||||||
{
|
{
|
||||||
creators["bspeed"] = &HunterBuffStrategyFactoryInternal::bspeed;
|
creators["bspeed"] = &HunterBuffStrategyFactoryInternal::bspeed;
|
||||||
creators["bdps"] = &HunterBuffStrategyFactoryInternal::bdps;
|
creators["bdps"] = &HunterBuffStrategyFactoryInternal::bdps;
|
||||||
creators["bmana"] = &HunterBuffStrategyFactoryInternal::bmana;
|
|
||||||
creators["rnature"] = &HunterBuffStrategyFactoryInternal::rnature;
|
creators["rnature"] = &HunterBuffStrategyFactoryInternal::rnature;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Strategy* bspeed(PlayerbotAI* botAI) { return new HunterBuffSpeedStrategy(botAI); }
|
static Strategy* bspeed(PlayerbotAI* botAI) { return new HunterBuffSpeedStrategy(botAI); }
|
||||||
static Strategy* bdps(PlayerbotAI* botAI) { return new HunterBuffDpsStrategy(botAI); }
|
static Strategy* bdps(PlayerbotAI* botAI) { return new HunterBuffDpsStrategy(botAI); }
|
||||||
static Strategy* bmana(PlayerbotAI* botAI) { return new HunterBuffManaStrategy(botAI); }
|
|
||||||
static Strategy* rnature(PlayerbotAI* botAI) { return new HunterNatureResistanceStrategy(botAI); }
|
static Strategy* rnature(PlayerbotAI* botAI) { return new HunterNatureResistanceStrategy(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,7 +63,6 @@ class HunterTriggerFactoryInternal : public NamedObjectContext<Trigger>
|
|||||||
public:
|
public:
|
||||||
HunterTriggerFactoryInternal()
|
HunterTriggerFactoryInternal()
|
||||||
{
|
{
|
||||||
creators["aspect of the viper"] = &HunterTriggerFactoryInternal::aspect_of_the_viper;
|
|
||||||
creators["black arrow"] = &HunterTriggerFactoryInternal::black_arrow;
|
creators["black arrow"] = &HunterTriggerFactoryInternal::black_arrow;
|
||||||
creators["no stings"] = &HunterTriggerFactoryInternal::NoStings;
|
creators["no stings"] = &HunterTriggerFactoryInternal::NoStings;
|
||||||
creators["hunters pet dead"] = &HunterTriggerFactoryInternal::hunters_pet_dead;
|
creators["hunters pet dead"] = &HunterTriggerFactoryInternal::hunters_pet_dead;
|
||||||
@ -75,10 +70,9 @@ public:
|
|||||||
creators["hunters pet medium health"] = &HunterTriggerFactoryInternal::hunters_pet_medium_health;
|
creators["hunters pet medium health"] = &HunterTriggerFactoryInternal::hunters_pet_medium_health;
|
||||||
creators["hunter's mark"] = &HunterTriggerFactoryInternal::hunters_mark;
|
creators["hunter's mark"] = &HunterTriggerFactoryInternal::hunters_mark;
|
||||||
creators["freezing trap"] = &HunterTriggerFactoryInternal::freezing_trap;
|
creators["freezing trap"] = &HunterTriggerFactoryInternal::freezing_trap;
|
||||||
creators["aspect of the pack"] = &HunterTriggerFactoryInternal::aspect_of_the_pack;
|
|
||||||
creators["rapid fire"] = &HunterTriggerFactoryInternal::rapid_fire;
|
creators["rapid fire"] = &HunterTriggerFactoryInternal::rapid_fire;
|
||||||
creators["aspect of the hawk"] = &HunterTriggerFactoryInternal::aspect_of_the_hawk;
|
creators["aspect of the pack"] = &HunterTriggerFactoryInternal::aspect_of_the_pack;
|
||||||
creators["aspect of the monkey"] = &HunterTriggerFactoryInternal::aspect_of_the_monkey;
|
creators["aspect of the dragonhawk"] = &HunterTriggerFactoryInternal::aspect_of_the_dragonhawk;
|
||||||
creators["aspect of the wild"] = &HunterTriggerFactoryInternal::aspect_of_the_wild;
|
creators["aspect of the wild"] = &HunterTriggerFactoryInternal::aspect_of_the_wild;
|
||||||
creators["aspect of the viper"] = &HunterTriggerFactoryInternal::aspect_of_the_viper;
|
creators["aspect of the viper"] = &HunterTriggerFactoryInternal::aspect_of_the_viper;
|
||||||
creators["trueshot aura"] = &HunterTriggerFactoryInternal::trueshot_aura;
|
creators["trueshot aura"] = &HunterTriggerFactoryInternal::trueshot_aura;
|
||||||
@ -107,10 +101,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
static Trigger* auto_shot(PlayerbotAI* botAI) { return new AutoShotTrigger(botAI); }
|
static Trigger* auto_shot(PlayerbotAI* botAI) { return new AutoShotTrigger(botAI); }
|
||||||
static Trigger* scare_beast(PlayerbotAI* botAI) { return new ScareBeastTrigger(botAI); }
|
static Trigger* scare_beast(PlayerbotAI* botAI) { return new ScareBeastTrigger(botAI); }
|
||||||
static Trigger* concussive_shot_on_snare_target(PlayerbotAI* botAI)
|
static Trigger* concussive_shot_on_snare_target(PlayerbotAI* botAI) {
|
||||||
{
|
return new ConcussiveShotOnSnareTargetTrigger(botAI); }
|
||||||
return new ConsussiveShotSnareTrigger(botAI);
|
|
||||||
}
|
|
||||||
static Trigger* pet_not_happy(PlayerbotAI* botAI) { return new HunterPetNotHappy(botAI); }
|
static Trigger* pet_not_happy(PlayerbotAI* botAI) { return new HunterPetNotHappy(botAI); }
|
||||||
static Trigger* serpent_sting_on_attacker(PlayerbotAI* botAI) { return new SerpentStingOnAttackerTrigger(botAI); }
|
static Trigger* serpent_sting_on_attacker(PlayerbotAI* botAI) { return new SerpentStingOnAttackerTrigger(botAI); }
|
||||||
static Trigger* trueshot_aura(PlayerbotAI* botAI) { return new TrueshotAuraTrigger(botAI); }
|
static Trigger* trueshot_aura(PlayerbotAI* botAI) { return new TrueshotAuraTrigger(botAI); }
|
||||||
@ -125,18 +117,17 @@ private:
|
|||||||
static Trigger* freezing_trap(PlayerbotAI* botAI) { return new FreezingTrapTrigger(botAI); }
|
static Trigger* freezing_trap(PlayerbotAI* botAI) { return new FreezingTrapTrigger(botAI); }
|
||||||
static Trigger* aspect_of_the_pack(PlayerbotAI* botAI) { return new HunterAspectOfThePackTrigger(botAI); }
|
static Trigger* aspect_of_the_pack(PlayerbotAI* botAI) { return new HunterAspectOfThePackTrigger(botAI); }
|
||||||
static Trigger* rapid_fire(PlayerbotAI* botAI) { return new RapidFireTrigger(botAI); }
|
static Trigger* rapid_fire(PlayerbotAI* botAI) { return new RapidFireTrigger(botAI); }
|
||||||
static Trigger* aspect_of_the_hawk(PlayerbotAI* botAI) { return new HunterAspectOfTheHawkTrigger(botAI); }
|
static Trigger* aspect_of_the_dragonhawk(PlayerbotAI* botAI) { return new HunterAspectOfTheDragonhawkTrigger(botAI); }
|
||||||
static Trigger* aspect_of_the_monkey(PlayerbotAI* botAI) { return new HunterAspectOfTheMonkeyTrigger(botAI); }
|
|
||||||
static Trigger* aspect_of_the_wild(PlayerbotAI* botAI) { return new HunterAspectOfTheWildTrigger(botAI); }
|
static Trigger* aspect_of_the_wild(PlayerbotAI* botAI) { return new HunterAspectOfTheWildTrigger(botAI); }
|
||||||
static Trigger* low_ammo(PlayerbotAI* botAI) { return new HunterLowAmmoTrigger(botAI); }
|
static Trigger* low_ammo(PlayerbotAI* botAI) { return new HunterLowAmmoTrigger(botAI); }
|
||||||
static Trigger* no_ammo(PlayerbotAI* botAI) { return new HunterNoAmmoTrigger(botAI); }
|
static Trigger* no_ammo(PlayerbotAI* botAI) { return new HunterNoAmmoTrigger(botAI); }
|
||||||
static Trigger* has_ammo(PlayerbotAI* botAI) { return new HunterHasAmmoTrigger(botAI); }
|
static Trigger* has_ammo(PlayerbotAI* botAI) { return new HunterHasAmmoTrigger(botAI); }
|
||||||
static Trigger* switch_to_melee(PlayerbotAI* botAI) { return new SwitchToMeleeTrigger(botAI); }
|
static Trigger* switch_to_melee(PlayerbotAI* botAI) { return new SwitchToMeleeTrigger(botAI); }
|
||||||
static Trigger* switch_to_ranged(PlayerbotAI* botAI) { return new SwitchToRangedTrigger(botAI); }
|
static Trigger* switch_to_ranged(PlayerbotAI* botAI) { return new SwitchToRangedTrigger(botAI); }
|
||||||
static Trigger* misdirection_on_main_tank(PlayerbotAI* ai) { return new MisdirectionOnMainTankTrigger(ai); }
|
static Trigger* misdirection_on_main_tank(PlayerbotAI* botAI) { return new MisdirectionOnMainTankTrigger(botAI); }
|
||||||
static Trigger* remove_enrage(PlayerbotAI* ai) { return new TargetRemoveEnrageTrigger(ai); }
|
static Trigger* remove_enrage(PlayerbotAI* botAI) { return new TargetRemoveEnrageTrigger(botAI); }
|
||||||
static Trigger* remove_magic(PlayerbotAI* ai) { return new TargetRemoveMagicTrigger(ai); }
|
static Trigger* remove_magic(PlayerbotAI* botAI) { return new TargetRemoveMagicTrigger(botAI); }
|
||||||
static Trigger* immolation_trap_no_cd(PlayerbotAI* ai) { return new ImmolationTrapNoCdTrigger(ai); }
|
static Trigger* immolation_trap_no_cd(PlayerbotAI* botAI) { return new ImmolationTrapNoCdTrigger(botAI); }
|
||||||
static Trigger* kill_command(PlayerbotAI* botAI) { return new KillCommandTrigger(botAI); }
|
static Trigger* kill_command(PlayerbotAI* botAI) { return new KillCommandTrigger(botAI); }
|
||||||
static Trigger* explosive_shot(PlayerbotAI* botAI) { return new ExplosiveShotTrigger(botAI); }
|
static Trigger* explosive_shot(PlayerbotAI* botAI) { return new ExplosiveShotTrigger(botAI); }
|
||||||
static Trigger* lock_and_load(PlayerbotAI* botAI) { return new LockAndLoadTrigger(botAI); }
|
static Trigger* lock_and_load(PlayerbotAI* botAI) { return new LockAndLoadTrigger(botAI); }
|
||||||
@ -153,7 +144,6 @@ public:
|
|||||||
creators["auto shot"] = &HunterAiObjectContextInternal::auto_shot;
|
creators["auto shot"] = &HunterAiObjectContextInternal::auto_shot;
|
||||||
creators["aimed shot"] = &HunterAiObjectContextInternal::aimed_shot;
|
creators["aimed shot"] = &HunterAiObjectContextInternal::aimed_shot;
|
||||||
creators["chimera shot"] = &HunterAiObjectContextInternal::chimera_shot;
|
creators["chimera shot"] = &HunterAiObjectContextInternal::chimera_shot;
|
||||||
creators["explosive shot"] = &HunterAiObjectContextInternal::explosive_shot;
|
|
||||||
creators["arcane shot"] = &HunterAiObjectContextInternal::arcane_shot;
|
creators["arcane shot"] = &HunterAiObjectContextInternal::arcane_shot;
|
||||||
creators["concussive shot"] = &HunterAiObjectContextInternal::concussive_shot;
|
creators["concussive shot"] = &HunterAiObjectContextInternal::concussive_shot;
|
||||||
creators["distracting shot"] = &HunterAiObjectContextInternal::distracting_shot;
|
creators["distracting shot"] = &HunterAiObjectContextInternal::distracting_shot;
|
||||||
@ -176,6 +166,7 @@ public:
|
|||||||
creators["deterrence"] = &HunterAiObjectContextInternal::deterrence;
|
creators["deterrence"] = &HunterAiObjectContextInternal::deterrence;
|
||||||
creators["readiness"] = &HunterAiObjectContextInternal::readiness;
|
creators["readiness"] = &HunterAiObjectContextInternal::readiness;
|
||||||
creators["aspect of the hawk"] = &HunterAiObjectContextInternal::aspect_of_the_hawk;
|
creators["aspect of the hawk"] = &HunterAiObjectContextInternal::aspect_of_the_hawk;
|
||||||
|
creators["aspect of the dragonhawk"] = &HunterAiObjectContextInternal::aspect_of_the_dragonhawk;
|
||||||
creators["aspect of the monkey"] = &HunterAiObjectContextInternal::aspect_of_the_monkey;
|
creators["aspect of the monkey"] = &HunterAiObjectContextInternal::aspect_of_the_monkey;
|
||||||
creators["aspect of the wild"] = &HunterAiObjectContextInternal::aspect_of_the_wild;
|
creators["aspect of the wild"] = &HunterAiObjectContextInternal::aspect_of_the_wild;
|
||||||
creators["aspect of the viper"] = &HunterAiObjectContextInternal::aspect_of_the_viper;
|
creators["aspect of the viper"] = &HunterAiObjectContextInternal::aspect_of_the_viper;
|
||||||
@ -191,7 +182,6 @@ public:
|
|||||||
creators["bestial wrath"] = &HunterAiObjectContextInternal::bestial_wrath;
|
creators["bestial wrath"] = &HunterAiObjectContextInternal::bestial_wrath;
|
||||||
creators["scare beast"] = &HunterAiObjectContextInternal::scare_beast;
|
creators["scare beast"] = &HunterAiObjectContextInternal::scare_beast;
|
||||||
creators["scare beast on cc"] = &HunterAiObjectContextInternal::scare_beast_on_cc;
|
creators["scare beast on cc"] = &HunterAiObjectContextInternal::scare_beast_on_cc;
|
||||||
creators["aspect of the dragonhawk"] = &HunterAiObjectContextInternal::aspect_of_the_dragonhawk;
|
|
||||||
creators["tranquilizing shot"] = &HunterAiObjectContextInternal::tranquilizing_shot;
|
creators["tranquilizing shot"] = &HunterAiObjectContextInternal::tranquilizing_shot;
|
||||||
creators["steady shot"] = &HunterAiObjectContextInternal::steady_shot;
|
creators["steady shot"] = &HunterAiObjectContextInternal::steady_shot;
|
||||||
creators["kill shot"] = &HunterAiObjectContextInternal::kill_shot;
|
creators["kill shot"] = &HunterAiObjectContextInternal::kill_shot;
|
||||||
@ -200,6 +190,7 @@ public:
|
|||||||
creators["disengage"] = &HunterAiObjectContextInternal::disengage;
|
creators["disengage"] = &HunterAiObjectContextInternal::disengage;
|
||||||
creators["immolation trap"] = &HunterAiObjectContextInternal::immolation_trap;
|
creators["immolation trap"] = &HunterAiObjectContextInternal::immolation_trap;
|
||||||
creators["explosive trap"] = &HunterAiObjectContextInternal::explosive_trap;
|
creators["explosive trap"] = &HunterAiObjectContextInternal::explosive_trap;
|
||||||
|
creators["explosive shot base"] = &HunterAiObjectContextInternal::explosive_shot_base;
|
||||||
creators["explosive shot rank 4"] = &HunterAiObjectContextInternal::explosive_shot_rank_4;
|
creators["explosive shot rank 4"] = &HunterAiObjectContextInternal::explosive_shot_rank_4;
|
||||||
creators["explosive shot rank 3"] = &HunterAiObjectContextInternal::explosive_shot_rank_3;
|
creators["explosive shot rank 3"] = &HunterAiObjectContextInternal::explosive_shot_rank_3;
|
||||||
creators["explosive shot rank 2"] = &HunterAiObjectContextInternal::explosive_shot_rank_2;
|
creators["explosive shot rank 2"] = &HunterAiObjectContextInternal::explosive_shot_rank_2;
|
||||||
@ -218,7 +209,6 @@ private:
|
|||||||
static Action* auto_shot(PlayerbotAI* botAI) { return new CastAutoShotAction(botAI); }
|
static Action* auto_shot(PlayerbotAI* botAI) { return new CastAutoShotAction(botAI); }
|
||||||
static Action* aimed_shot(PlayerbotAI* botAI) { return new CastAimedShotAction(botAI); }
|
static Action* aimed_shot(PlayerbotAI* botAI) { return new CastAimedShotAction(botAI); }
|
||||||
static Action* chimera_shot(PlayerbotAI* botAI) { return new CastChimeraShotAction(botAI); }
|
static Action* chimera_shot(PlayerbotAI* botAI) { return new CastChimeraShotAction(botAI); }
|
||||||
static Action* explosive_shot(PlayerbotAI* botAI) { return new CastExplosiveShotAction(botAI); }
|
|
||||||
static Action* arcane_shot(PlayerbotAI* botAI) { return new CastArcaneShotAction(botAI); }
|
static Action* arcane_shot(PlayerbotAI* botAI) { return new CastArcaneShotAction(botAI); }
|
||||||
static Action* concussive_shot(PlayerbotAI* botAI) { return new CastConcussiveShotAction(botAI); }
|
static Action* concussive_shot(PlayerbotAI* botAI) { return new CastConcussiveShotAction(botAI); }
|
||||||
static Action* distracting_shot(PlayerbotAI* botAI) { return new CastDistractingShotAction(botAI); }
|
static Action* distracting_shot(PlayerbotAI* botAI) { return new CastDistractingShotAction(botAI); }
|
||||||
@ -234,12 +224,13 @@ private:
|
|||||||
static Action* kill_command(PlayerbotAI* botAI) { return new CastKillCommandAction(botAI); }
|
static Action* kill_command(PlayerbotAI* botAI) { return new CastKillCommandAction(botAI); }
|
||||||
static Action* revive_pet(PlayerbotAI* botAI) { return new CastRevivePetAction(botAI); }
|
static Action* revive_pet(PlayerbotAI* botAI) { return new CastRevivePetAction(botAI); }
|
||||||
static Action* call_pet(PlayerbotAI* botAI) { return new CastCallPetAction(botAI); }
|
static Action* call_pet(PlayerbotAI* botAI) { return new CastCallPetAction(botAI); }
|
||||||
static Action* black_arrow(PlayerbotAI* botAI) { return new CastBlackArrow(botAI); }
|
static Action* black_arrow(PlayerbotAI* botAI) { return new CastBlackArrowAction(botAI); }
|
||||||
static Action* freezing_trap(PlayerbotAI* botAI) { return new CastFreezingTrap(botAI); }
|
static Action* freezing_trap(PlayerbotAI* botAI) { return new CastFreezingTrap(botAI); }
|
||||||
static Action* rapid_fire(PlayerbotAI* botAI) { return new CastRapidFireAction(botAI); }
|
static Action* rapid_fire(PlayerbotAI* botAI) { return new CastRapidFireAction(botAI); }
|
||||||
static Action* deterrence(PlayerbotAI* botAI) { return new CastDeterrenceAction(botAI); }
|
static Action* deterrence(PlayerbotAI* botAI) { return new CastDeterrenceAction(botAI); }
|
||||||
static Action* readiness(PlayerbotAI* botAI) { return new CastReadinessAction(botAI); }
|
static Action* readiness(PlayerbotAI* botAI) { return new CastReadinessAction(botAI); }
|
||||||
static Action* aspect_of_the_hawk(PlayerbotAI* botAI) { return new CastAspectOfTheHawkAction(botAI); }
|
static Action* aspect_of_the_hawk(PlayerbotAI* botAI) { return new CastAspectOfTheHawkAction(botAI); }
|
||||||
|
static Action* aspect_of_the_dragonhawk(PlayerbotAI* botAI) { return new CastAspectOfTheDragonhawkAction(botAI); }
|
||||||
static Action* aspect_of_the_monkey(PlayerbotAI* botAI) { return new CastAspectOfTheMonkeyAction(botAI); }
|
static Action* aspect_of_the_monkey(PlayerbotAI* botAI) { return new CastAspectOfTheMonkeyAction(botAI); }
|
||||||
static Action* aspect_of_the_wild(PlayerbotAI* botAI) { return new CastAspectOfTheWildAction(botAI); }
|
static Action* aspect_of_the_wild(PlayerbotAI* botAI) { return new CastAspectOfTheWildAction(botAI); }
|
||||||
static Action* aspect_of_the_viper(PlayerbotAI* botAI) { return new CastAspectOfTheViperAction(botAI); }
|
static Action* aspect_of_the_viper(PlayerbotAI* botAI) { return new CastAspectOfTheViperAction(botAI); }
|
||||||
@ -248,20 +239,20 @@ private:
|
|||||||
static Action* wing_clip(PlayerbotAI* botAI) { return new CastWingClipAction(botAI); }
|
static Action* wing_clip(PlayerbotAI* botAI) { return new CastWingClipAction(botAI); }
|
||||||
static Action* raptor_strike(PlayerbotAI* botAI) { return new CastRaptorStrikeAction(botAI); }
|
static Action* raptor_strike(PlayerbotAI* botAI) { return new CastRaptorStrikeAction(botAI); }
|
||||||
static Action* mongoose_bite(PlayerbotAI* botAI) { return new CastMongooseBiteAction(botAI); }
|
static Action* mongoose_bite(PlayerbotAI* botAI) { return new CastMongooseBiteAction(botAI); }
|
||||||
static Action* aspect_of_the_dragonhawk(PlayerbotAI* ai) { return new CastAspectOfTheDragonhawkAction(ai); }
|
static Action* tranquilizing_shot(PlayerbotAI* botAI) { return new CastTranquilizingShotAction(botAI); }
|
||||||
static Action* tranquilizing_shot(PlayerbotAI* ai) { return new CastTranquilizingShotAction(ai); }
|
static Action* steady_shot(PlayerbotAI* botAI) { return new CastSteadyShotAction(botAI); }
|
||||||
static Action* steady_shot(PlayerbotAI* ai) { return new CastSteadyShotAction(ai); }
|
static Action* kill_shot(PlayerbotAI* botAI) { return new CastKillShotAction(botAI); }
|
||||||
static Action* kill_shot(PlayerbotAI* ai) { return new CastKillShotAction(ai); }
|
static Action* misdirection_on_main_tank(PlayerbotAI* botAI) { return new CastMisdirectionOnMainTankAction(botAI); }
|
||||||
static Action* misdirection_on_main_tank(PlayerbotAI* ai) { return new CastMisdirectionOnMainTankAction(ai); }
|
static Action* silencing_shot(PlayerbotAI* botAI) { return new CastSilencingShotAction(botAI); }
|
||||||
static Action* silencing_shot(PlayerbotAI* ai) { return new CastSilencingShotAction(ai); }
|
static Action* disengage(PlayerbotAI* botAI) { return new CastDisengageAction(botAI); }
|
||||||
static Action* disengage(PlayerbotAI* ai) { return new CastDisengageAction(ai); }
|
static Action* immolation_trap(PlayerbotAI* botAI) { return new CastImmolationTrapAction(botAI); }
|
||||||
static Action* immolation_trap(PlayerbotAI* ai) { return new CastImmolationTrapAction(ai); }
|
static Action* explosive_trap(PlayerbotAI* botAI) { return new CastExplosiveTrapAction(botAI); }
|
||||||
static Action* explosive_trap(PlayerbotAI* ai) { return new CastExplosiveTrapAction(ai); }
|
static Action* explosive_shot_base(PlayerbotAI* botAI) { return new CastExplosiveShotBaseAction(botAI); }
|
||||||
static Action* explosive_shot_rank_4(PlayerbotAI* ai) { return new CastExplosiveShotRank4Action(ai); }
|
static Action* explosive_shot_rank_4(PlayerbotAI* botAI) { return new CastExplosiveShotRank4Action(botAI); }
|
||||||
static Action* explosive_shot_rank_3(PlayerbotAI* ai) { return new CastExplosiveShotRank3Action(ai); }
|
static Action* explosive_shot_rank_3(PlayerbotAI* botAI) { return new CastExplosiveShotRank3Action(botAI); }
|
||||||
static Action* explosive_shot_rank_2(PlayerbotAI* ai) { return new CastExplosiveShotRank2Action(ai); }
|
static Action* explosive_shot_rank_2(PlayerbotAI* botAI) { return new CastExplosiveShotRank2Action(botAI); }
|
||||||
static Action* explosive_shot_rank_1(PlayerbotAI* ai) { return new CastExplosiveShotRank1Action(ai); }
|
static Action* explosive_shot_rank_1(PlayerbotAI* botAI) { return new CastExplosiveShotRank1Action(botAI); }
|
||||||
static Action* intimidation(PlayerbotAI* ai) { return new CastIntimidationAction(ai); }
|
static Action* intimidation(PlayerbotAI* botAI) { return new CastIntimidationAction(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
SharedNamedObjectContextList<Strategy> HunterAiObjectContext::sharedStrategyContexts;
|
SharedNamedObjectContextList<Strategy> HunterAiObjectContext::sharedStrategyContexts;
|
||||||
|
|||||||
@ -6,41 +6,9 @@
|
|||||||
#include "BeastMasteryHunterStrategy.h"
|
#include "BeastMasteryHunterStrategy.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
|
||||||
class BeastMasteryHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BeastMasteryHunterStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["auto shot"] = &auto_shot;
|
|
||||||
creators["kill command"] = &kill_command;
|
|
||||||
creators["kill shot"] = &kill_shot;
|
|
||||||
creators["viper sting"] = &viper_sting;
|
|
||||||
creators["serpent sting"] = serpent_sting;
|
|
||||||
creators["aimed shot"] = &aimed_shot;
|
|
||||||
creators["arcane shot"] = &arcane_shot;
|
|
||||||
creators["steady shot"] = &steady_shot;
|
|
||||||
creators["multi-shot"] = &multi_shot;
|
|
||||||
creators["volley"] = &volley;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", {}, {}, {}); }
|
|
||||||
static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", {}, {}, {}); }
|
|
||||||
static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", {}, {}, {}); }
|
|
||||||
static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", {}, {}, {}); }
|
|
||||||
static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", {}, {}, {}); }
|
|
||||||
static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", {}, {}, {}); }
|
|
||||||
static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", {}, {}, {}); }
|
|
||||||
static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", {}, {}, {}); }
|
|
||||||
static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", {}, {}, {}); }
|
|
||||||
static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", {}, {}, {}); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
BeastMasteryHunterStrategy::BeastMasteryHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
BeastMasteryHunterStrategy::BeastMasteryHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new BeastMasteryHunterStrategyActionNodeFactory());
|
// No custom ActionNodeFactory needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Default Actions =====
|
// ===== Default Actions =====
|
||||||
|
|||||||
@ -4,62 +4,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "GenericHunterNonCombatStrategy.h"
|
#include "GenericHunterNonCombatStrategy.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
class GenericHunterNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GenericHunterNonCombatStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["rapid fire"] = &rapid_fire;
|
|
||||||
creators["boost"] = &rapid_fire;
|
|
||||||
creators["aspect of the pack"] = &aspect_of_the_pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* rapid_fire([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("rapid fire",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("readiness")},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("aspect of the pack",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("aspect of the cheetah")},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
GenericHunterNonCombatStrategy::GenericHunterNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
GenericHunterNonCombatStrategy::GenericHunterNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new GenericHunterNonCombatStrategyActionNodeFactory());
|
// No custom ActionNodeFactory needed
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericHunterNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void GenericHunterNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
NonCombatStrategy::InitTriggers(triggers);
|
NonCombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("trueshot aura", { NextAction("trueshot aura", 2.0f)}));
|
triggers.push_back(new TriggerNode("trueshot aura", { NextAction("trueshot aura", 2.0f) }));
|
||||||
triggers.push_back(new TriggerNode("often", {
|
triggers.push_back(new TriggerNode("often", { NextAction("apply stone", 1.0f),
|
||||||
NextAction("apply stone", 1.0f),
|
NextAction("apply oil", 1.0f) }));
|
||||||
NextAction("apply oil", 1.0f),
|
triggers.push_back(new TriggerNode("low ammo", { NextAction("say::low ammo", ACTION_NORMAL) }));
|
||||||
}));
|
triggers.push_back(new TriggerNode("no track", { NextAction("track humanoids", ACTION_NORMAL) }));
|
||||||
triggers.push_back(new TriggerNode("low ammo", { NextAction("say::low ammo", ACTION_NORMAL)}));
|
triggers.push_back(new TriggerNode("no ammo", { NextAction("equip upgrades packet action", ACTION_HIGH + 1) }));
|
||||||
triggers.push_back(new TriggerNode("no track", { NextAction("track humanoids", ACTION_NORMAL)}));
|
|
||||||
triggers.push_back(new TriggerNode("no ammo", { NextAction("equip upgrades packet action", ACTION_HIGH + 1)}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HunterPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void HunterPetStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("no pet", { NextAction("call pet", 60.0f)}));
|
triggers.push_back(new TriggerNode("no pet", { NextAction("call pet", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f)}));
|
triggers.push_back(new TriggerNode("has pet", { NextAction("toggle pet spell", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f)}));
|
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("pet not happy", { NextAction("feed pet", 60.0f)}));
|
triggers.push_back(new TriggerNode("pet not happy", { NextAction("feed pet", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("hunters pet medium health", { NextAction("mend pet", 60.0f)}));
|
triggers.push_back(new TriggerNode("hunters pet medium health", { NextAction("mend pet", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("hunters pet dead", { NextAction("revive pet", 60.0f)}));
|
triggers.push_back(new TriggerNode("hunters pet dead", { NextAction("revive pet", 60.0f) }));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,11 +11,6 @@ public:
|
|||||||
GenericHunterStrategyActionNodeFactory()
|
GenericHunterStrategyActionNodeFactory()
|
||||||
{
|
{
|
||||||
creators["rapid fire"] = &rapid_fire;
|
creators["rapid fire"] = &rapid_fire;
|
||||||
creators["boost"] = &rapid_fire;
|
|
||||||
creators["aspect of the pack"] = &aspect_of_the_pack;
|
|
||||||
creators["aspect of the dragonhawk"] = &aspect_of_the_dragonhawk;
|
|
||||||
creators["feign death"] = &feign_death;
|
|
||||||
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;
|
creators["explosive trap"] = &explosive_trap;
|
||||||
@ -29,40 +24,6 @@ private:
|
|||||||
/*A*/ { NextAction("readiness") },
|
/*A*/ { NextAction("readiness") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
|
|
||||||
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("aspect of the pack",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("aspect of the cheetah") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* aspect_of_the_dragonhawk([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("aspect of the dragonhawk",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("aspect of the hawk") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* feign_death([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("feign death",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ {},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* wing_clip([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("wing clip",
|
|
||||||
/*P*/ {},
|
|
||||||
// /*A*/ { NextAction("mongoose bite") },
|
|
||||||
{},
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
|
|
||||||
static ActionNode* mongoose_bite([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* mongoose_bite([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("mongoose bite",
|
return new ActionNode("mongoose bite",
|
||||||
@ -70,7 +31,6 @@ private:
|
|||||||
/*A*/ { NextAction("raptor strike") },
|
/*A*/ { NextAction("raptor strike") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
|
|
||||||
static ActionNode* raptor_strike([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* raptor_strike([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("raptor strike",
|
return new ActionNode("raptor strike",
|
||||||
@ -78,7 +38,6 @@ private:
|
|||||||
/*A*/ {},
|
/*A*/ {},
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
|
|
||||||
static ActionNode* explosive_trap([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* explosive_trap([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("explosive trap",
|
return new ActionNode("explosive trap",
|
||||||
@ -102,7 +61,6 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("hunter's mark", { NextAction("hunter's mark", 29.5f) }));
|
triggers.push_back(new TriggerNode("hunter's mark", { NextAction("hunter's mark", 29.5f) }));
|
||||||
triggers.push_back(new TriggerNode("rapid fire", { NextAction("rapid fire", 29.0f) }));
|
triggers.push_back(new TriggerNode("rapid fire", { NextAction("rapid fire", 29.0f) }));
|
||||||
triggers.push_back(new TriggerNode("aspect of the viper", { NextAction("aspect of the viper", 28.0f) }));
|
triggers.push_back(new TriggerNode("aspect of the viper", { NextAction("aspect of the viper", 28.0f) }));
|
||||||
triggers.push_back(new TriggerNode("aspect of the hawk", { NextAction("aspect of the dragonhawk", 27.5f) }));
|
|
||||||
|
|
||||||
// Aggro/Threat/Defensive Triggers
|
// Aggro/Threat/Defensive Triggers
|
||||||
triggers.push_back(new TriggerNode("has aggro", { NextAction("concussive shot", 20.0f) }));
|
triggers.push_back(new TriggerNode("has aggro", { NextAction("concussive shot", 20.0f) }));
|
||||||
@ -118,14 +76,12 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("tranquilizing shot magic", { NextAction("tranquilizing shot", 61.0f) }));
|
triggers.push_back(new TriggerNode("tranquilizing shot magic", { NextAction("tranquilizing shot", 61.0f) }));
|
||||||
|
|
||||||
// Ranged-based Triggers
|
// Ranged-based Triggers
|
||||||
triggers.push_back(new TriggerNode("enemy within melee", {
|
triggers.push_back(new TriggerNode("enemy within melee", { NextAction("explosive trap", 37.0f),
|
||||||
NextAction("explosive trap", 37.0f),
|
NextAction("mongoose bite", 22.0f),
|
||||||
NextAction("mongoose bite", 22.0f),
|
NextAction("wing clip", 21.0f) }));
|
||||||
NextAction("wing clip", 21.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("enemy too close for auto shot", {
|
triggers.push_back(new TriggerNode("enemy too close for auto shot", { NextAction("disengage", 35.0f),
|
||||||
NextAction("disengage", 35.0f),
|
NextAction("flee", 34.0f) }));
|
||||||
NextAction("flee", 34.0f) }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== AoE Strategy, 2/3+ enemies =====
|
// ===== AoE Strategy, 2/3+ enemies =====
|
||||||
@ -138,10 +94,6 @@ void AoEHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("light aoe", { NextAction("multi-shot", 21.0f) }));
|
triggers.push_back(new TriggerNode("light aoe", { NextAction("multi-shot", 21.0f) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void HunterBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void HunterCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void HunterCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("scare beast", { NextAction("scare beast on cc", 23.0f) }));
|
triggers.push_back(new TriggerNode("scare beast", { NextAction("scare beast on cc", 23.0f) }));
|
||||||
|
|||||||
@ -30,15 +30,6 @@ public:
|
|||||||
std::string const getName() override { return "aoe"; }
|
std::string const getName() override { return "aoe"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class HunterBoostStrategy : public Strategy
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HunterBoostStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::string const getName() override { return "boost"; }
|
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HunterCcStrategy : public Strategy
|
class HunterCcStrategy : public Strategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -10,9 +10,21 @@
|
|||||||
class BuffHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
class BuffHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BuffHunterStrategyActionNodeFactory() { creators["aspect of the hawk"] = &aspect_of_the_hawk; }
|
BuffHunterStrategyActionNodeFactory()
|
||||||
|
{
|
||||||
|
creators["aspect of the dragonhawk"] = &aspect_of_the_dragonhawk;
|
||||||
|
creators["aspect of the hawk"] = &aspect_of_the_hawk;
|
||||||
|
creators["aspect of the pack"] = &aspect_of_the_pack;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static ActionNode* aspect_of_the_dragonhawk([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("aspect of the dragonhawk",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("aspect of the hawk") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
static ActionNode* aspect_of_the_hawk([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* aspect_of_the_hawk([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("aspect of the hawk",
|
return new ActionNode("aspect of the hawk",
|
||||||
@ -20,9 +32,16 @@ private:
|
|||||||
/*A*/ { NextAction("aspect of the monkey") },
|
/*A*/ { NextAction("aspect of the monkey") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
|
static ActionNode* aspect_of_the_pack([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("aspect of the pack",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("aspect of the cheetah") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
HunterBuffDpsStrategy::HunterBuffDpsStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
HunterBuffDpsStrategy::HunterBuffDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new BuffHunterStrategyActionNodeFactory());
|
actionNodeFactories.Add(new BuffHunterStrategyActionNodeFactory());
|
||||||
}
|
}
|
||||||
@ -30,24 +49,35 @@ HunterBuffDpsStrategy::HunterBuffDpsStrategy(PlayerbotAI* botAI) : NonCombatStra
|
|||||||
void HunterBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void HunterBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("aspect of the hawk", { NextAction("aspect of the dragonhawk", 20.1f),
|
new TriggerNode(
|
||||||
NextAction("aspect of the hawk", 20.0f) }));
|
"aspect of the dragonhawk",
|
||||||
|
{
|
||||||
|
NextAction("aspect of the dragonhawk", ACTION_HIGH)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HunterNatureResistanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void HunterNatureResistanceStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("aspect of the wild",
|
triggers.push_back(
|
||||||
{ NextAction("aspect of the wild", 20.0f) }));
|
new TriggerNode(
|
||||||
|
"aspect of the wild",
|
||||||
|
{
|
||||||
|
NextAction("aspect of the wild", ACTION_HIGH)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HunterBuffSpeedStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void HunterBuffSpeedStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("aspect of the pack",
|
triggers.push_back(
|
||||||
{ NextAction("aspect of the pack", 20.0f) }));
|
new TriggerNode(
|
||||||
}
|
"aspect of the pack",
|
||||||
|
{
|
||||||
void HunterBuffManaStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
NextAction("aspect of the pack", ACTION_HIGH)
|
||||||
{
|
}
|
||||||
triggers.push_back(new TriggerNode("aspect of the viper",
|
)
|
||||||
{ NextAction("aspect of the viper", 20.0f) }));
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,44 +6,35 @@
|
|||||||
#ifndef _PLAYERBOT_HUNTERBUFFSTRATEGIES_H
|
#ifndef _PLAYERBOT_HUNTERBUFFSTRATEGIES_H
|
||||||
#define _PLAYERBOT_HUNTERBUFFSTRATEGIES_H
|
#define _PLAYERBOT_HUNTERBUFFSTRATEGIES_H
|
||||||
|
|
||||||
#include "NonCombatStrategy.h"
|
#include "Strategy.h"
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
class HunterBuffSpeedStrategy : public NonCombatStrategy
|
class HunterBuffSpeedStrategy : public Strategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HunterBuffSpeedStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
HunterBuffSpeedStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||||
|
|
||||||
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
std::string const getName() override { return "bspeed"; }
|
std::string const getName() override { return "bspeed"; }
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HunterBuffManaStrategy : public NonCombatStrategy
|
class HunterBuffDpsStrategy : public Strategy
|
||||||
{
|
|
||||||
public:
|
|
||||||
HunterBuffManaStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
|
||||||
|
|
||||||
std::string const getName() override { return "bmana"; }
|
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HunterBuffDpsStrategy : public NonCombatStrategy
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HunterBuffDpsStrategy(PlayerbotAI* botAI);
|
HunterBuffDpsStrategy(PlayerbotAI* botAI);
|
||||||
|
|
||||||
std::string const getName() override { return "bdps"; }
|
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
|
std::string const getName() override { return "bdps"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class HunterNatureResistanceStrategy : public NonCombatStrategy
|
class HunterNatureResistanceStrategy : public Strategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HunterNatureResistanceStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
HunterNatureResistanceStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||||
|
|
||||||
std::string const getName() override { return "rnature"; }
|
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
|
std::string const getName() override { return "rnature"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6,45 +6,9 @@
|
|||||||
#include "MarksmanshipHunterStrategy.h"
|
#include "MarksmanshipHunterStrategy.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
|
||||||
class MarksmanshipHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MarksmanshipHunterStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["auto shot"] = &auto_shot;
|
|
||||||
creators["silencing shot"] = &silencing_shot;
|
|
||||||
creators["kill command"] = &kill_command;
|
|
||||||
creators["kill shot"] = &kill_shot;
|
|
||||||
creators["viper sting"] = &viper_sting;
|
|
||||||
creators["serpent sting"] = serpent_sting;
|
|
||||||
creators["chimera shot"] = &chimera_shot;
|
|
||||||
creators["aimed shot"] = &aimed_shot;
|
|
||||||
creators["arcane shot"] = &arcane_shot;
|
|
||||||
creators["steady shot"] = &steady_shot;
|
|
||||||
creators["multi-shot"] = &multi_shot;
|
|
||||||
creators["volley"] = &volley;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", {}, {}, {}); }
|
|
||||||
static ActionNode* silencing_shot(PlayerbotAI*) { return new ActionNode("silencing shot", {}, {}, {}); }
|
|
||||||
static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", {}, {}, {}); }
|
|
||||||
static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", {}, {}, {}); }
|
|
||||||
static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", {}, {}, {}); }
|
|
||||||
static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", {}, {}, {}); }
|
|
||||||
static ActionNode* chimera_shot(PlayerbotAI*) { return new ActionNode("chimera shot", {}, {}, {}); }
|
|
||||||
static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", {}, {}, {}); }
|
|
||||||
static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", {}, {}, {}); }
|
|
||||||
static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", {}, {}, {}); }
|
|
||||||
static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", {}, {}, {}); }
|
|
||||||
static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", {}, {}, {}); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
MarksmanshipHunterStrategy::MarksmanshipHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
MarksmanshipHunterStrategy::MarksmanshipHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new MarksmanshipHunterStrategyActionNodeFactory());
|
// No custom ActionNodeFactory needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Default Actions =====
|
// ===== Default Actions =====
|
||||||
|
|||||||
@ -12,36 +12,35 @@ class SurvivalHunterStrategyActionNodeFactory : public NamedObjectFactory<Action
|
|||||||
public:
|
public:
|
||||||
SurvivalHunterStrategyActionNodeFactory()
|
SurvivalHunterStrategyActionNodeFactory()
|
||||||
{
|
{
|
||||||
creators["auto shot"] = &auto_shot;
|
creators["explosive shot rank 4"] = &explosive_shot_rank_4;
|
||||||
creators["kill command"] = &kill_command;
|
creators["explosive shot rank 3"] = &explosive_shot_rank_3;
|
||||||
creators["kill shot"] = &kill_shot;
|
creators["explosive shot rank 2"] = &explosive_shot_rank_2;
|
||||||
creators["explosive shot"] = &explosive_shot;
|
|
||||||
creators["black arrow"] = &black_arrow;
|
|
||||||
creators["viper sting"] = &viper_sting;
|
|
||||||
creators["serpent sting"] = serpent_sting;
|
|
||||||
creators["aimed shot"] = &aimed_shot;
|
|
||||||
creators["arcane shot"] = &arcane_shot;
|
|
||||||
creators["steady shot"] = &steady_shot;
|
|
||||||
creators["multi-shot"] = &multi_shot;
|
|
||||||
creators["volley"] = &volley;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", {}, {}, {}); }
|
static ActionNode* explosive_shot_rank_4([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", {}, {}, {}); }
|
{
|
||||||
static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", {}, {}, {}); }
|
return new ActionNode("explosive shot rank 4",
|
||||||
static ActionNode* explosive_shot(PlayerbotAI*) { return new ActionNode("explosive shot", {}, {}, {}); }
|
/*P*/ {},
|
||||||
static ActionNode* black_arrow(PlayerbotAI*) { return new ActionNode("black arrow", {}, {}, {}); }
|
/*A*/ { NextAction("explosive shot rank 3") },
|
||||||
static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", {}, {}, {}); }
|
/*C*/ {});
|
||||||
static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", {}, {}, {}); }
|
}
|
||||||
static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", {}, {}, {}); }
|
static ActionNode* explosive_shot_rank_3([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", {}, {}, {}); }
|
{
|
||||||
static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", {}, {}, {}); }
|
return new ActionNode("explosive shot rank 3",
|
||||||
static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", {}, {}, {}); }
|
/*P*/ {},
|
||||||
static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", {}, {}, {}); }
|
/*A*/ { NextAction("explosive shot rank 2") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
|
static ActionNode* explosive_shot_rank_2([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("explosive shot rank 2",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("explosive shot rank 1") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
SurvivalHunterStrategy::SurvivalHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
SurvivalHunterStrategy::SurvivalHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new SurvivalHunterStrategyActionNodeFactory());
|
actionNodeFactories.Add(new SurvivalHunterStrategyActionNodeFactory());
|
||||||
@ -76,30 +75,6 @@ void SurvivalHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 3", 27.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 2", 27.0f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode(
|
|
||||||
"lock and load",
|
|
||||||
{
|
|
||||||
NextAction("explosive shot rank 1", 26.5f)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode(
|
new TriggerNode(
|
||||||
"kill command",
|
"kill command",
|
||||||
|
|||||||
@ -16,8 +16,7 @@
|
|||||||
|
|
||||||
bool KillCommandTrigger::IsActive()
|
bool KillCommandTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
return !botAI->HasAura("kill command", GetTarget());
|
||||||
return !botAI->HasAura("kill command", target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlackArrowTrigger::IsActive()
|
bool BlackArrowTrigger::IsActive()
|
||||||
@ -26,36 +25,46 @@ bool BlackArrowTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
return DebuffTrigger::IsActive();
|
return DebuffTrigger::IsActive();
|
||||||
return BuffTrigger::IsActive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HunterAspectOfTheHawkTrigger::IsActive()
|
bool HunterAspectOfTheDragonhawkTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
return SpellTrigger::IsActive() && !botAI->HasAura("aspect of the hawk", target) &&
|
if (!target)
|
||||||
!botAI->HasAura("aspect of the dragonhawk", target) &&
|
return false;
|
||||||
(!AI_VALUE2(bool, "has mana", "self target") || AI_VALUE2(uint8, "mana", "self target") > 70);
|
|
||||||
|
if (!SpellTrigger::IsActive())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (botAI->HasAura("aspect of the hawk", target) ||
|
||||||
|
botAI->HasAura("aspect of the dragonhawk", target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (botAI->HasAura("aspect of the viper", target))
|
||||||
|
return AI_VALUE2(uint8, "mana", "self target") >= 60;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HunterNoStingsActiveTrigger::IsActive()
|
bool HunterNoStingsActiveTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
return DebuffTrigger::IsActive() && target && !botAI->HasAura("serpent sting", target, false, true) &&
|
return DebuffTrigger::IsActive() && target &&
|
||||||
!botAI->HasAura("scorpid sting", target, false, true) && !botAI->HasAura("viper sting", target, false, true);
|
!botAI->HasAura("serpent sting", target, false, true) &&
|
||||||
return BuffTrigger::IsActive();
|
!botAI->HasAura("scorpid sting", target, false, true) &&
|
||||||
|
!botAI->HasAura("viper sting", target, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HuntersPetDeadTrigger::IsActive()
|
bool HuntersPetDeadTrigger::IsActive()
|
||||||
{
|
{
|
||||||
// Unit* pet = AI_VALUE(Unit*, "pet target");
|
|
||||||
// return pet && AI_VALUE2(bool, "dead", "pet target") && !AI_VALUE2(bool, "mounted", "self target");
|
|
||||||
return AI_VALUE(bool, "pet dead") && !AI_VALUE2(bool, "mounted", "self target");
|
return AI_VALUE(bool, "pet dead") && !AI_VALUE2(bool, "mounted", "self target");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HuntersPetLowHealthTrigger::IsActive()
|
bool HuntersPetLowHealthTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* pet = AI_VALUE(Unit*, "pet target");
|
Unit* pet = AI_VALUE(Unit*, "pet target");
|
||||||
return pet && AI_VALUE2(uint8, "health", "pet target") < 40 && !AI_VALUE2(bool, "dead", "pet target") &&
|
return pet && AI_VALUE2(uint8, "health", "pet target") < 40 &&
|
||||||
|
!AI_VALUE2(bool, "dead", "pet target") &&
|
||||||
!AI_VALUE2(bool, "mounted", "self target");
|
!AI_VALUE2(bool, "mounted", "self target");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,9 +82,14 @@ bool HunterPetNotHappy::IsActive()
|
|||||||
|
|
||||||
bool HunterAspectOfTheViperTrigger::IsActive()
|
bool HunterAspectOfTheViperTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return SpellTrigger::IsActive() && !botAI->HasAura(spell, GetTarget()) &&
|
if (botAI->HasStrategy("rnature", BotState::BOT_STATE_COMBAT) ||
|
||||||
|
botAI->HasStrategy("rnature", BotState::BOT_STATE_NON_COMBAT) ||
|
||||||
|
botAI->HasStrategy("bspeed", BotState::BOT_STATE_COMBAT) ||
|
||||||
|
botAI->HasStrategy("bspeed", BotState::BOT_STATE_NON_COMBAT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return BuffTrigger::IsActive() &&
|
||||||
AI_VALUE2(uint8, "mana", "self target") < (sPlayerbotAIConfig.lowMana / 2);
|
AI_VALUE2(uint8, "mana", "self target") < (sPlayerbotAIConfig.lowMana / 2);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HunterAspectOfThePackTrigger::IsActive()
|
bool HunterAspectOfThePackTrigger::IsActive()
|
||||||
@ -85,11 +99,14 @@ bool HunterAspectOfThePackTrigger::IsActive()
|
|||||||
|
|
||||||
bool HunterLowAmmoTrigger::IsActive()
|
bool HunterLowAmmoTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return bot->GetGroup() && (AI_VALUE2(uint32, "item count", "ammo") < 100) &&
|
uint32 ammoCount = AI_VALUE2(uint32, "item count", "ammo");
|
||||||
(AI_VALUE2(uint32, "item count", "ammo") > 0);
|
return bot->GetGroup() && ammoCount > 0 && ammoCount < 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HunterHasAmmoTrigger::IsActive() { return !AmmoCountTrigger::IsActive(); }
|
bool HunterHasAmmoTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return !AmmoCountTrigger::IsActive();
|
||||||
|
}
|
||||||
|
|
||||||
bool SwitchToRangedTrigger::IsActive()
|
bool SwitchToRangedTrigger::IsActive()
|
||||||
{
|
{
|
||||||
@ -131,6 +148,7 @@ bool NoTrackTrigger::IsActive()
|
|||||||
if (botAI->HasAura(track, bot))
|
if (botAI->HasAura(track, bot))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,17 +156,17 @@ bool SerpentStingOnAttackerTrigger::IsActive()
|
|||||||
{
|
{
|
||||||
if (!DebuffOnAttackerTrigger::IsActive())
|
if (!DebuffOnAttackerTrigger::IsActive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
return !botAI->HasAura("scorpid sting", target, false, true) &&
|
return !botAI->HasAura("scorpid sting", target, false, true) &&
|
||||||
!botAI->HasAura("viper sting", target, false, true);
|
!botAI->HasAura("viper sting", target, false, true);
|
||||||
return BuffTrigger::IsActive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::set<uint32> VolleyChannelCheckTrigger::VOLLEY_SPELL_IDS = {
|
const std::set<uint32> VolleyChannelCheckTrigger::VOLLEY_SPELL_IDS =
|
||||||
|
{
|
||||||
1510, // Volley Rank 1
|
1510, // Volley Rank 1
|
||||||
14294, // Volley Rank 2
|
14294, // Volley Rank 2
|
||||||
14295, // Volley Rank 3
|
14295, // Volley Rank 3
|
||||||
@ -159,19 +177,12 @@ const std::set<uint32> VolleyChannelCheckTrigger::VOLLEY_SPELL_IDS = {
|
|||||||
|
|
||||||
bool VolleyChannelCheckTrigger::IsActive()
|
bool VolleyChannelCheckTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Player* bot = botAI->GetBot();
|
if (Spell* spell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
|
||||||
|
spell && VOLLEY_SPELL_IDS.count(spell->m_spellInfo->Id))
|
||||||
// Check if the bot is channeling a spell
|
|
||||||
if (Spell* spell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
|
||||||
{
|
{
|
||||||
// Only trigger if the spell being channeled is Volley
|
uint8 attackerCount = AI_VALUE(uint8, "attacker count");
|
||||||
if (VOLLEY_SPELL_IDS.count(spell->m_spellInfo->Id))
|
return attackerCount < minEnemies;
|
||||||
{
|
|
||||||
uint8 attackerCount = AI_VALUE(uint8, "attacker count");
|
|
||||||
return attackerCount < minEnemies;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not channeling Volley
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,16 +16,10 @@ class PlayerbotAI;
|
|||||||
|
|
||||||
// Buff and Out of Combat Triggers
|
// Buff and Out of Combat Triggers
|
||||||
|
|
||||||
class HunterAspectOfTheMonkeyTrigger : public BuffTrigger
|
class HunterAspectOfTheDragonhawkTrigger : public BuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HunterAspectOfTheMonkeyTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "aspect of the monkey") {}
|
HunterAspectOfTheDragonhawkTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "aspect of the dragonhawk") {}
|
||||||
};
|
|
||||||
|
|
||||||
class HunterAspectOfTheHawkTrigger : public BuffTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HunterAspectOfTheHawkTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "aspect of the hawk") {}
|
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,10 +124,10 @@ public:
|
|||||||
FreezingTrapTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "freezing trap") {}
|
FreezingTrapTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "freezing trap") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConsussiveShotSnareTrigger : public SnareTargetTrigger
|
class ConcussiveShotOnSnareTargetTrigger : public SnareTargetTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConsussiveShotSnareTrigger(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, "concussive shot") {}
|
ConcussiveShotOnSnareTargetTrigger(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, "concussive shot") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScareBeastTrigger : public HasCcTargetTrigger
|
class ScareBeastTrigger : public HasCcTargetTrigger
|
||||||
@ -212,25 +206,25 @@ public:
|
|||||||
class MisdirectionOnMainTankTrigger : public BuffOnMainTankTrigger
|
class MisdirectionOnMainTankTrigger : public BuffOnMainTankTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MisdirectionOnMainTankTrigger(PlayerbotAI* ai) : BuffOnMainTankTrigger(ai, "misdirection", true) {}
|
MisdirectionOnMainTankTrigger(PlayerbotAI* botAI) : BuffOnMainTankTrigger(botAI, "misdirection", true) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TargetRemoveEnrageTrigger : public TargetAuraDispelTrigger
|
class TargetRemoveEnrageTrigger : public TargetAuraDispelTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TargetRemoveEnrageTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "tranquilizing shot", DISPEL_ENRAGE) {}
|
TargetRemoveEnrageTrigger(PlayerbotAI* botAI) : TargetAuraDispelTrigger(botAI, "tranquilizing shot", DISPEL_ENRAGE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TargetRemoveMagicTrigger : public TargetAuraDispelTrigger
|
class TargetRemoveMagicTrigger : public TargetAuraDispelTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TargetRemoveMagicTrigger(PlayerbotAI* ai) : TargetAuraDispelTrigger(ai, "tranquilizing shot", DISPEL_MAGIC) {}
|
TargetRemoveMagicTrigger(PlayerbotAI* botAI) : TargetAuraDispelTrigger(botAI, "tranquilizing shot", DISPEL_MAGIC) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ImmolationTrapNoCdTrigger : public SpellNoCooldownTrigger
|
class ImmolationTrapNoCdTrigger : public SpellNoCooldownTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ImmolationTrapNoCdTrigger(PlayerbotAI* ai) : SpellNoCooldownTrigger(ai, "immolation trap") {}
|
ImmolationTrapNoCdTrigger(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, "immolation trap") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
BEGIN_TRIGGER(HuntersPetDeadTrigger, Trigger)
|
BEGIN_TRIGGER(HuntersPetDeadTrigger, Trigger)
|
||||||
|
|||||||
@ -35,7 +35,7 @@ private:
|
|||||||
static ActionNode* ice_lance(PlayerbotAI*) { return new ActionNode("ice lance", {}, {}, {}); }
|
static ActionNode* ice_lance(PlayerbotAI*) { return new ActionNode("ice lance", {}, {}, {}); }
|
||||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); }
|
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); }
|
||||||
static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", {}, {}, {}); }
|
static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", {}, {}, {}); }
|
||||||
static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", {}, {}, {}); }
|
static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", {}, { NextAction("fireball") }, {}); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
// ===== Single Target Strategy =====
|
||||||
|
|||||||
@ -237,6 +237,14 @@ void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
void MageCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void MageCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("polymorph", { NextAction("polymorph", 30.0f) }));
|
triggers.push_back(new TriggerNode("polymorph", { NextAction("polymorph", 30.0f) }));
|
||||||
|
|
||||||
|
Player* bot = botAI->GetBot();
|
||||||
|
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
if (tab == MAGE_TAB_FIRE)
|
||||||
|
{
|
||||||
|
triggers.push_back(new TriggerNode("enemy too close for spell", {NextAction("dragon's breath", ACTION_INTERRUPT + 1)}));
|
||||||
|
triggers.push_back(new TriggerNode("enemy is close", {NextAction("blast wave", ACTION_INTERRUPT)}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void MageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "Event.h"
|
#include "Event.h"
|
||||||
|
#include "PaladinHelper.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
@ -468,6 +469,39 @@ bool CastSealSpellAction::isUseful() { return AI_VALUE2(bool, "combat", "self ta
|
|||||||
|
|
||||||
Value<Unit*>* CastTurnUndeadAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); }
|
Value<Unit*>* CastTurnUndeadAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); }
|
||||||
|
|
||||||
|
Unit* CastHandOfFreedomOnPartyAction::GetTarget()
|
||||||
|
{
|
||||||
|
bool const selfImpaired = botAI->IsMovementImpaired(bot);
|
||||||
|
bool const hasSelfHand = selfImpaired && ai::paladin::HasAnyPaladinHandFromCaster(bot, bot);
|
||||||
|
|
||||||
|
if (!bot->GetGroup())
|
||||||
|
{
|
||||||
|
if (selfImpaired && !hasSelfHand)
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfImpaired && !hasSelfHand)
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
return CastBuffSpellAction::GetTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value<Unit*>* CastHandOfFreedomOnPartyAction::GetTargetValue()
|
||||||
|
{
|
||||||
|
return context->GetValue<Unit*>("party member snared target");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastHandOfFreedomOnPartyAction::isUseful()
|
||||||
|
{
|
||||||
|
Unit* target = GetTarget();
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return CastBuffSpellAction::isUseful() && !ai::paladin::HasAnyPaladinHandFromCaster(target, bot);
|
||||||
|
}
|
||||||
|
|
||||||
Unit* CastRighteousDefenseAction::GetTarget()
|
Unit* CastRighteousDefenseAction::GetTarget()
|
||||||
{
|
{
|
||||||
Unit* current_target = AI_VALUE(Unit*, "current target");
|
Unit* current_target = AI_VALUE(Unit*, "current target");
|
||||||
|
|||||||
@ -371,6 +371,19 @@ public:
|
|||||||
Value<Unit*>* GetTargetValue() override;
|
Value<Unit*>* GetTargetValue() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CastHandOfFreedomOnPartyAction : public CastBuffSpellAction, public PartyMemberActionNameSupport
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastHandOfFreedomOnPartyAction(PlayerbotAI* botAI)
|
||||||
|
: CastBuffSpellAction(botAI, "hand of freedom"), PartyMemberActionNameSupport("hand of freedom") {}
|
||||||
|
|
||||||
|
Unit* GetTarget() override;
|
||||||
|
Value<Unit*>* GetTargetValue() override;
|
||||||
|
std::string const GetTargetName() override { return "party member snared target"; }
|
||||||
|
std::string const getName() override { return PartyMemberActionNameSupport::getName(); }
|
||||||
|
bool isUseful() override;
|
||||||
|
};
|
||||||
|
|
||||||
PROTECT_ACTION(CastBlessingOfProtectionProtectAction, "blessing of protection");
|
PROTECT_ACTION(CastBlessingOfProtectionProtectAction, "blessing of protection");
|
||||||
|
|
||||||
class CastDivinePleaAction : public CastBuffSpellAction
|
class CastDivinePleaAction : public CastBuffSpellAction
|
||||||
|
|||||||
@ -134,6 +134,7 @@ public:
|
|||||||
&PaladinTriggerFactoryInternal::hammer_of_justice_on_snare_target;
|
&PaladinTriggerFactoryInternal::hammer_of_justice_on_snare_target;
|
||||||
creators["not sensing undead"] = &PaladinTriggerFactoryInternal::not_sensing_undead;
|
creators["not sensing undead"] = &PaladinTriggerFactoryInternal::not_sensing_undead;
|
||||||
creators["divine favor"] = &PaladinTriggerFactoryInternal::divine_favor;
|
creators["divine favor"] = &PaladinTriggerFactoryInternal::divine_favor;
|
||||||
|
creators["divine shield low health"] = &PaladinTriggerFactoryInternal::divine_shield_low_health;
|
||||||
creators["turn undead"] = &PaladinTriggerFactoryInternal::turn_undead;
|
creators["turn undead"] = &PaladinTriggerFactoryInternal::turn_undead;
|
||||||
creators["avenger's shield"] = &PaladinTriggerFactoryInternal::avenger_shield;
|
creators["avenger's shield"] = &PaladinTriggerFactoryInternal::avenger_shield;
|
||||||
creators["consecration"] = &PaladinTriggerFactoryInternal::consecration;
|
creators["consecration"] = &PaladinTriggerFactoryInternal::consecration;
|
||||||
@ -142,6 +143,7 @@ public:
|
|||||||
creators["repentance interrupt"] = &PaladinTriggerFactoryInternal::repentance_interrupt;
|
creators["repentance interrupt"] = &PaladinTriggerFactoryInternal::repentance_interrupt;
|
||||||
creators["beacon of light on main tank"] = &PaladinTriggerFactoryInternal::beacon_of_light_on_main_tank;
|
creators["beacon of light on main tank"] = &PaladinTriggerFactoryInternal::beacon_of_light_on_main_tank;
|
||||||
creators["sacred shield on main tank"] = &PaladinTriggerFactoryInternal::sacred_shield_on_main_tank;
|
creators["sacred shield on main tank"] = &PaladinTriggerFactoryInternal::sacred_shield_on_main_tank;
|
||||||
|
creators["hand of freedom on party"] = &PaladinTriggerFactoryInternal::hand_of_freedom_on_party;
|
||||||
|
|
||||||
creators["blessing of kings on party"] = &PaladinTriggerFactoryInternal::blessing_of_kings_on_party;
|
creators["blessing of kings on party"] = &PaladinTriggerFactoryInternal::blessing_of_kings_on_party;
|
||||||
creators["blessing of wisdom on party"] = &PaladinTriggerFactoryInternal::blessing_of_wisdom_on_party;
|
creators["blessing of wisdom on party"] = &PaladinTriggerFactoryInternal::blessing_of_wisdom_on_party;
|
||||||
@ -155,6 +157,7 @@ private:
|
|||||||
static Trigger* not_sensing_undead(PlayerbotAI* botAI) { return new NotSensingUndeadTrigger(botAI); }
|
static Trigger* not_sensing_undead(PlayerbotAI* botAI) { return new NotSensingUndeadTrigger(botAI); }
|
||||||
static Trigger* turn_undead(PlayerbotAI* botAI) { return new TurnUndeadTrigger(botAI); }
|
static Trigger* turn_undead(PlayerbotAI* botAI) { return new TurnUndeadTrigger(botAI); }
|
||||||
static Trigger* divine_favor(PlayerbotAI* botAI) { return new DivineFavorTrigger(botAI); }
|
static Trigger* divine_favor(PlayerbotAI* botAI) { return new DivineFavorTrigger(botAI); }
|
||||||
|
static Trigger* divine_shield_low_health(PlayerbotAI* botAI) { return new DivineShieldLowHealthTrigger(botAI); }
|
||||||
static Trigger* holy_shield(PlayerbotAI* botAI) { return new HolyShieldTrigger(botAI); }
|
static Trigger* holy_shield(PlayerbotAI* botAI) { return new HolyShieldTrigger(botAI); }
|
||||||
static Trigger* righteous_fury(PlayerbotAI* botAI) { return new RighteousFuryTrigger(botAI); }
|
static Trigger* righteous_fury(PlayerbotAI* botAI) { return new RighteousFuryTrigger(botAI); }
|
||||||
static Trigger* judgement(PlayerbotAI* botAI) { return new JudgementTrigger(botAI); }
|
static Trigger* judgement(PlayerbotAI* botAI) { return new JudgementTrigger(botAI); }
|
||||||
@ -207,6 +210,7 @@ private:
|
|||||||
static Trigger* repentance_interrupt(PlayerbotAI* botAI) { return new RepentanceInterruptTrigger(botAI); }
|
static Trigger* repentance_interrupt(PlayerbotAI* botAI) { return new RepentanceInterruptTrigger(botAI); }
|
||||||
static Trigger* beacon_of_light_on_main_tank(PlayerbotAI* ai) { return new BeaconOfLightOnMainTankTrigger(ai); }
|
static Trigger* beacon_of_light_on_main_tank(PlayerbotAI* ai) { return new BeaconOfLightOnMainTankTrigger(ai); }
|
||||||
static Trigger* sacred_shield_on_main_tank(PlayerbotAI* ai) { return new SacredShieldOnMainTankTrigger(ai); }
|
static Trigger* sacred_shield_on_main_tank(PlayerbotAI* ai) { return new SacredShieldOnMainTankTrigger(ai); }
|
||||||
|
static Trigger* hand_of_freedom_on_party(PlayerbotAI* botAI) { return new HandOfFreedomOnPartyTrigger(botAI); }
|
||||||
|
|
||||||
static Trigger* blessing_of_kings_on_party(PlayerbotAI* botAI) { return new BlessingOfKingsOnPartyTrigger(botAI); }
|
static Trigger* blessing_of_kings_on_party(PlayerbotAI* botAI) { return new BlessingOfKingsOnPartyTrigger(botAI); }
|
||||||
static Trigger* blessing_of_wisdom_on_party(PlayerbotAI* botAI)
|
static Trigger* blessing_of_wisdom_on_party(PlayerbotAI* botAI)
|
||||||
@ -308,6 +312,7 @@ public:
|
|||||||
creators["divine illumination"] = &PaladinAiObjectContextInternal::divine_illumination;
|
creators["divine illumination"] = &PaladinAiObjectContextInternal::divine_illumination;
|
||||||
creators["divine sacrifice"] = &PaladinAiObjectContextInternal::divine_sacrifice;
|
creators["divine sacrifice"] = &PaladinAiObjectContextInternal::divine_sacrifice;
|
||||||
creators["cancel divine sacrifice"] = &PaladinAiObjectContextInternal::cancel_divine_sacrifice;
|
creators["cancel divine sacrifice"] = &PaladinAiObjectContextInternal::cancel_divine_sacrifice;
|
||||||
|
creators["hand of freedom on party"] = &PaladinAiObjectContextInternal::hand_of_freedom_on_party;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -414,6 +419,7 @@ private:
|
|||||||
static Action* divine_illumination(PlayerbotAI* ai) { return new CastDivineIlluminationAction(ai); }
|
static Action* divine_illumination(PlayerbotAI* ai) { return new CastDivineIlluminationAction(ai); }
|
||||||
static Action* divine_sacrifice(PlayerbotAI* ai) { return new CastDivineSacrificeAction(ai); }
|
static Action* divine_sacrifice(PlayerbotAI* ai) { return new CastDivineSacrificeAction(ai); }
|
||||||
static Action* cancel_divine_sacrifice(PlayerbotAI* ai) { return new CastCancelDivineSacrificeAction(ai); }
|
static Action* cancel_divine_sacrifice(PlayerbotAI* ai) { return new CastCancelDivineSacrificeAction(ai); }
|
||||||
|
static Action* hand_of_freedom_on_party(PlayerbotAI* ai) { return new CastHandOfFreedomOnPartyAction(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
SharedNamedObjectContextList<Strategy> PaladinAiObjectContext::sharedStrategyContexts;
|
SharedNamedObjectContextList<Strategy> PaladinAiObjectContext::sharedStrategyContexts;
|
||||||
|
|||||||
@ -16,27 +16,23 @@ void GenericPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
CombatStrategy::InitTriggers(triggers);
|
CombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("critical health", { NextAction("divine shield",
|
triggers.push_back(new TriggerNode("hammer of justice interrupt",
|
||||||
ACTION_HIGH + 5) }));
|
{ NextAction("hammer of justice", ACTION_INTERRUPT) }));
|
||||||
triggers.push_back(
|
triggers.push_back(new TriggerNode("hammer of justice on enemy healer",
|
||||||
new TriggerNode("hammer of justice interrupt",
|
|
||||||
{ NextAction("hammer of justice", ACTION_INTERRUPT) }));
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"hammer of justice on enemy healer",
|
|
||||||
{ NextAction("hammer of justice on enemy healer", ACTION_INTERRUPT) }));
|
{ NextAction("hammer of justice on enemy healer", ACTION_INTERRUPT) }));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode("hammer of justice on snare target",
|
||||||
"hammer of justice on snare target",
|
|
||||||
{ NextAction("hammer of justice on snare target", ACTION_INTERRUPT) }));
|
{ NextAction("hammer of justice on snare target", ACTION_INTERRUPT) }));
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode("critical health", { NextAction("divine shield", ACTION_EMERGENCY) }));
|
||||||
"critical health", { NextAction("lay on hands", ACTION_EMERGENCY) }));
|
triggers.push_back(new TriggerNode("critical health", { NextAction("lay on hands", ACTION_EMERGENCY + 1) }));
|
||||||
triggers.push_back(
|
triggers.push_back(new TriggerNode("party member critical health",
|
||||||
new TriggerNode("party member critical health",
|
{ NextAction("lay on hands on party", ACTION_EMERGENCY + 2) }));
|
||||||
{ NextAction("lay on hands on party", ACTION_EMERGENCY + 1) }));
|
triggers.push_back(new TriggerNode("divine shield low health",
|
||||||
triggers.push_back(new TriggerNode(
|
{ NextAction("flash of light", ACTION_EMERGENCY + 3), NextAction("holy light", ACTION_EMERGENCY + 2)}));
|
||||||
"protect party member",
|
triggers.push_back(new TriggerNode("protect party member",
|
||||||
{ NextAction("blessing of protection on party", ACTION_EMERGENCY + 2) }));
|
{ NextAction("blessing of protection on party", ACTION_EMERGENCY + 3) }));
|
||||||
triggers.push_back(
|
triggers.push_back(new TriggerNode("high mana", { NextAction("divine plea", ACTION_HIGH) }));
|
||||||
new TriggerNode("high mana", { NextAction("divine plea", ACTION_HIGH) }));
|
triggers.push_back(new TriggerNode("hand of freedom on party",
|
||||||
|
{ NextAction("hand of freedom on party", ACTION_HIGH + 4) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaladinCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void PaladinCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "PaladinActions.h"
|
#include "PaladinActions.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
#include "PaladinHelper.h"
|
||||||
|
|
||||||
bool SealTrigger::IsActive()
|
bool SealTrigger::IsActive()
|
||||||
{
|
{
|
||||||
@ -31,6 +32,45 @@ bool BlessingTrigger::IsActive()
|
|||||||
"blessing of kings", "blessing of sanctuary", nullptr);
|
"blessing of kings", "blessing of sanctuary", nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DivineShieldLowHealthTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return botAI->HasAura("divine shield", bot) && AI_VALUE2(uint8, "health", "self target") < 80;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit* HandOfFreedomOnPartyTrigger::GetTarget()
|
||||||
|
{
|
||||||
|
bool const selfImpaired = botAI->IsMovementImpaired(bot);
|
||||||
|
bool const hasSelfHand = selfImpaired && ai::paladin::HasAnyPaladinHandFromCaster(bot, bot);
|
||||||
|
|
||||||
|
if (!bot->GetGroup())
|
||||||
|
{
|
||||||
|
if (selfImpaired && !hasSelfHand)
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selfImpaired && !hasSelfHand)
|
||||||
|
return bot;
|
||||||
|
|
||||||
|
return Trigger::GetTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandOfFreedomOnPartyTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* target = GetTarget();
|
||||||
|
if (!target)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (target != bot && bot->GetExactDist2dSq(target->GetPositionX(), target->GetPositionY()) > 30.0f * 30.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!botAI->CanCastSpell("hand of freedom", target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !ai::paladin::HasAnyPaladinHandFromCaster(target, bot) && botAI->IsMovementImpaired(target);
|
||||||
|
}
|
||||||
|
|
||||||
bool NotSensingUndeadTrigger::IsActive()
|
bool NotSensingUndeadTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return !botAI->HasAura("sense undead", bot);
|
return !botAI->HasAura("sense undead", bot);
|
||||||
|
|||||||
@ -185,6 +185,14 @@ public:
|
|||||||
DivineFavorTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "divine favor") {}
|
DivineFavorTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "divine favor") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DivineShieldLowHealthTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DivineShieldLowHealthTrigger(PlayerbotAI* botAI) : Trigger(botAI, "divine shield low health") {}
|
||||||
|
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
class NotSensingUndeadTrigger : public BuffTrigger
|
class NotSensingUndeadTrigger : public BuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -242,6 +250,16 @@ public:
|
|||||||
: BuffOnPartyTrigger(botAI, "blessing of sanctuary", 2 * 2000) {}
|
: BuffOnPartyTrigger(botAI, "blessing of sanctuary", 2 * 2000) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class HandOfFreedomOnPartyTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HandOfFreedomOnPartyTrigger(PlayerbotAI* botAI) : Trigger(botAI, "hand of freedom on party", 1) {}
|
||||||
|
|
||||||
|
Unit* GetTarget() override;
|
||||||
|
std::string const GetTargetName() override { return "party member snared target"; }
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
class AvengingWrathTrigger : public BoostTrigger
|
class AvengingWrathTrigger : public BoostTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
43
src/Ai/Class/Paladin/Util/PaladinHelper.h
Normal file
43
src/Ai/Class/Paladin/Util/PaladinHelper.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||||
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PLAYERBOT_PALADINHELPER_H
|
||||||
|
#define _PLAYERBOT_PALADINHELPER_H
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
|
#include "Unit.h"
|
||||||
|
|
||||||
|
class Player;
|
||||||
|
|
||||||
|
namespace ai::paladin
|
||||||
|
{
|
||||||
|
static constexpr uint32 SPELL_HAND_OF_PROTECTION = 1022;
|
||||||
|
static constexpr uint32 SPELL_HAND_OF_SALVATION = 1038;
|
||||||
|
static constexpr uint32 SPELL_HAND_OF_FREEDOM = 1044;
|
||||||
|
static constexpr uint32 SPELL_HAND_OF_SACRIFICE = 6940;
|
||||||
|
|
||||||
|
inline bool HasHandFromCaster(Unit* target, Player* caster, std::initializer_list<uint32> spellIds)
|
||||||
|
{
|
||||||
|
if (!target || !caster)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (uint32 spellId : spellIds)
|
||||||
|
{
|
||||||
|
if (target->HasAura(spellId, caster->GetGUID()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool HasAnyPaladinHandFromCaster(Unit* target, Player* caster)
|
||||||
|
{
|
||||||
|
return HasHandFromCaster(target, caster,
|
||||||
|
{ SPELL_HAND_OF_PROTECTION, SPELL_HAND_OF_SALVATION, SPELL_HAND_OF_FREEDOM, SPELL_HAND_OF_SACRIFICE });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -57,7 +57,8 @@ bool CastLavaBurstAction::isUseful()
|
|||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
static const uint32 FLAME_SHOCK_SPELL_IDS[] = {8050, 8052, 8053, 10447, 10448, 29228, 25457, 49232, 49233};
|
static const uint32 FLAME_SHOCK_SPELL_IDS[] =
|
||||||
|
{8050, 8052, 8053, 10447, 10448, 29228, 25457, 49232, 49233};
|
||||||
|
|
||||||
ObjectGuid botGuid = bot->GetGUID();
|
ObjectGuid botGuid = bot->GetGUID();
|
||||||
for (uint32 spellId : FLAME_SHOCK_SPELL_IDS)
|
for (uint32 spellId : FLAME_SHOCK_SPELL_IDS)
|
||||||
@ -65,6 +66,7 @@ bool CastLavaBurstAction::isUseful()
|
|||||||
if (target->HasAura(spellId, botGuid))
|
if (target->HasAura(spellId, botGuid))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,15 +79,13 @@ bool CastSpiritWalkAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
for (Unit* unit : bot->m_Controlled)
|
for (Unit* unit : bot->m_Controlled)
|
||||||
{
|
{
|
||||||
if (unit->GetEntry() == SPIRIT_WOLF)
|
if (unit->GetEntry() == SPIRIT_WOLF && unit->HasSpell(SPIRIT_WALK_SPELL))
|
||||||
{
|
{
|
||||||
if (unit->HasSpell(SPIRIT_WALK_SPELL))
|
unit->CastSpell(unit, SPIRIT_WALK_SPELL, false);
|
||||||
{
|
return true;
|
||||||
unit->CastSpell(unit, SPIRIT_WALK_SPELL, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,18 +105,15 @@ bool SetTotemAction::Execute(Event /*event*/)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!totemSpell)
|
if (!totemSpell)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (const ActionButton* button = bot->GetActionButton(actionButtonId);
|
||||||
|
button && button->GetType() == ACTION_BUTTON_SPELL &&
|
||||||
|
button->GetAction() == totemSpell)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const ActionButton* button = bot->GetActionButton(actionButtonId))
|
|
||||||
{
|
|
||||||
if (button->GetType() == ACTION_BUTTON_SPELL && button->GetAction() == totemSpell)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bot->addActionButton(actionButtonId, totemSpell, ACTION_BUTTON_SPELL);
|
bot->addActionButton(actionButtonId, totemSpell, ACTION_BUTTON_SPELL);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,73 +18,92 @@ class PlayerbotAI;
|
|||||||
class CastWaterShieldAction : public CastBuffSpellAction
|
class CastWaterShieldAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWaterShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water shield") {}
|
CastWaterShieldAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "water shield") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLightningShieldAction : public CastBuffSpellAction
|
class CastLightningShieldAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastLightningShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "lightning shield") {}
|
CastLightningShieldAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "lightning shield") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastEarthlivingWeaponAction : public CastEnchantItemAction
|
class CastRockbiterWeaponMainHandAction : public CastEnchantItemMainHandAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastEarthlivingWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "earthliving weapon") {}
|
CastRockbiterWeaponMainHandAction(PlayerbotAI* botAI) :
|
||||||
|
CastEnchantItemMainHandAction(botAI, "rockbiter weapon") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastRockbiterWeaponAction : public CastEnchantItemAction
|
class CastFlametongueWeaponMainHandAction : public CastEnchantItemMainHandAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRockbiterWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "rockbiter weapon") {}
|
CastFlametongueWeaponMainHandAction(PlayerbotAI* botAI) :
|
||||||
|
CastEnchantItemMainHandAction(botAI, "flametongue weapon") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFlametongueWeaponAction : public CastEnchantItemAction
|
class CastFlametongueWeaponOffHandAction : public CastEnchantItemOffHandAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFlametongueWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "flametongue weapon") {}
|
CastFlametongueWeaponOffHandAction(PlayerbotAI* botAI) :
|
||||||
|
CastEnchantItemOffHandAction(botAI, "flametongue weapon") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFrostbrandWeaponAction : public CastEnchantItemAction
|
/* class CastFrostbrandWeaponOffHandAction : public CastEnchantItemOffHandAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFrostbrandWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "frostbrand weapon") {}
|
CastFrostbrandWeaponOffHandAction(PlayerbotAI* botAI) :
|
||||||
|
CastEnchantItemOffHandAction(botAI, "frostbrand weapon") {}
|
||||||
|
}; */
|
||||||
|
|
||||||
|
class CastEarthlivingWeaponMainHandAction : public CastEnchantItemMainHandAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastEarthlivingWeaponMainHandAction(PlayerbotAI* botAI) :
|
||||||
|
CastEnchantItemMainHandAction(botAI, "earthliving weapon") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWindfuryWeaponAction : public CastEnchantItemAction
|
class CastWindfuryWeaponMainHandAction : public CastEnchantItemMainHandAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWindfuryWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "windfury weapon") {}
|
CastWindfuryWeaponMainHandAction(PlayerbotAI* botAI) :
|
||||||
|
CastEnchantItemMainHandAction(botAI, "windfury weapon") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastAncestralSpiritAction : public ResurrectPartyMemberAction
|
class CastAncestralSpiritAction : public ResurrectPartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastAncestralSpiritAction(PlayerbotAI* botAI) : ResurrectPartyMemberAction(botAI, "ancestral spirit") {}
|
CastAncestralSpiritAction(PlayerbotAI* botAI) :
|
||||||
|
ResurrectPartyMemberAction(botAI, "ancestral spirit") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWaterBreathingAction : public CastBuffSpellAction
|
class CastWaterBreathingAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWaterBreathingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water breathing") {}
|
CastWaterBreathingAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "water breathing") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWaterWalkingAction : public CastBuffSpellAction
|
class CastWaterWalkingAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWaterWalkingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water walking") {}
|
CastWaterWalkingAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "water walking") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWaterBreathingOnPartyAction : public BuffOnPartyAction
|
class CastWaterBreathingOnPartyAction : public BuffOnPartyAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWaterBreathingOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "water breathing") {}
|
CastWaterBreathingOnPartyAction(PlayerbotAI* botAI) :
|
||||||
|
BuffOnPartyAction(botAI, "water breathing") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWaterWalkingOnPartyAction : public BuffOnPartyAction
|
class CastWaterWalkingOnPartyAction : public BuffOnPartyAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWaterWalkingOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "water walking") {}
|
CastWaterWalkingOnPartyAction(PlayerbotAI* botAI) :
|
||||||
|
BuffOnPartyAction(botAI, "water walking") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Boost Actions
|
// Boost Actions
|
||||||
@ -92,31 +111,36 @@ public:
|
|||||||
class CastHeroismAction : public CastBuffSpellAction
|
class CastHeroismAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastHeroismAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "heroism") {}
|
CastHeroismAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "heroism") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastBloodlustAction : public CastBuffSpellAction
|
class CastBloodlustAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastBloodlustAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bloodlust") {}
|
CastBloodlustAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "bloodlust") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastElementalMasteryAction : public CastBuffSpellAction
|
class CastElementalMasteryAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastElementalMasteryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "elemental mastery") {}
|
CastElementalMasteryAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "elemental mastery") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastShamanisticRageAction : public CastBuffSpellAction
|
class CastShamanisticRageAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastShamanisticRageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shamanistic rage") {}
|
CastShamanisticRageAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "shamanistic rage") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFeralSpiritAction : public CastSpellAction
|
class CastFeralSpiritAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFeralSpiritAction(PlayerbotAI* ai) : CastSpellAction(ai, "feral spirit") {}
|
CastFeralSpiritAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "feral spirit") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSpiritWalkAction : public Action
|
class CastSpiritWalkAction : public Action
|
||||||
@ -138,7 +162,8 @@ public:
|
|||||||
class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction
|
class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "wind shear") {}
|
CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellOnEnemyHealerAction(botAI, "wind shear") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastPurgeAction : public CastSpellAction
|
class CastPurgeAction : public CastSpellAction
|
||||||
@ -150,16 +175,15 @@ public:
|
|||||||
class CastCleanseSpiritAction : public CastCureSpellAction
|
class CastCleanseSpiritAction : public CastCureSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCleanseSpiritAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cleanse spirit") {}
|
CastCleanseSpiritAction(PlayerbotAI* botAI) :
|
||||||
|
CastCureSpellAction(botAI, "cleanse spirit") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCleanseSpiritPoisonOnPartyAction : public CurePartyMemberAction
|
class CastCleanseSpiritPoisonOnPartyAction : public CurePartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCleanseSpiritPoisonOnPartyAction(PlayerbotAI* botAI)
|
CastCleanseSpiritPoisonOnPartyAction(PlayerbotAI* botAI) :
|
||||||
: CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_POISON)
|
CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_POISON) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const getName() override { return "cleanse spirit poison on party"; }
|
std::string const getName() override { return "cleanse spirit poison on party"; }
|
||||||
};
|
};
|
||||||
@ -167,10 +191,8 @@ public:
|
|||||||
class CastCleanseSpiritCurseOnPartyAction : public CurePartyMemberAction
|
class CastCleanseSpiritCurseOnPartyAction : public CurePartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCleanseSpiritCurseOnPartyAction(PlayerbotAI* botAI)
|
CastCleanseSpiritCurseOnPartyAction(PlayerbotAI* botAI) :
|
||||||
: CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_CURSE)
|
CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_CURSE) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const getName() override { return "cleanse spirit curse on party"; }
|
std::string const getName() override { return "cleanse spirit curse on party"; }
|
||||||
};
|
};
|
||||||
@ -178,42 +200,35 @@ public:
|
|||||||
class CastCleanseSpiritDiseaseOnPartyAction : public CurePartyMemberAction
|
class CastCleanseSpiritDiseaseOnPartyAction : public CurePartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCleanseSpiritDiseaseOnPartyAction(PlayerbotAI* botAI)
|
CastCleanseSpiritDiseaseOnPartyAction(PlayerbotAI* botAI) :
|
||||||
: CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_DISEASE)
|
CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_DISEASE) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const getName() override { return "cleanse spirit disease on party"; }
|
std::string const getName() override { return "cleanse spirit disease on party"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCurePoisonActionSham : public CastCureSpellAction
|
class CastCureToxinsActionSham : public CastCureSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCurePoisonActionSham(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure poison") {}
|
CastCureToxinsActionSham(PlayerbotAI* botAI) :
|
||||||
|
CastCureSpellAction(botAI, "cure toxins") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCurePoisonOnPartyActionSham : public CurePartyMemberAction
|
class CastCureToxinsPoisonOnPartyActionSham : public CurePartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCurePoisonOnPartyActionSham(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure poison", DISPEL_POISON) {}
|
CastCureToxinsPoisonOnPartyActionSham(PlayerbotAI* botAI) :
|
||||||
|
CurePartyMemberAction(botAI, "cure toxins", DISPEL_POISON) {}
|
||||||
|
|
||||||
std::string const getName() override { return "cure poison on party"; }
|
std::string const getName() override { return "cure toxins poison on party"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCureDiseaseActionSham : public CastCureSpellAction
|
class CastCureToxinsDiseaseOnPartyActionSham : public CurePartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCureDiseaseActionSham(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure disease") {}
|
CastCureToxinsDiseaseOnPartyActionSham(PlayerbotAI* botAI) :
|
||||||
};
|
CurePartyMemberAction(botAI, "cure toxins", DISPEL_DISEASE) {}
|
||||||
|
|
||||||
class CastCureDiseaseOnPartyActionSham : public CurePartyMemberAction
|
std::string const getName() override { return "cure toxins disease on party"; }
|
||||||
{
|
|
||||||
public:
|
|
||||||
CastCureDiseaseOnPartyActionSham(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure disease", DISPEL_DISEASE)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const getName() override { return "cure disease on party"; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Damage and Debuff Actions
|
// Damage and Debuff Actions
|
||||||
@ -221,68 +236,77 @@ public:
|
|||||||
class CastFireNovaAction : public CastMeleeSpellAction
|
class CastFireNovaAction : public CastMeleeSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFireNovaAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "fire nova") {}
|
CastFireNovaAction(PlayerbotAI* botAI) :
|
||||||
|
CastMeleeSpellAction(botAI, "fire nova") {}
|
||||||
|
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastStormstrikeAction : public CastMeleeSpellAction
|
class CastStormstrikeAction : public CastMeleeSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastStormstrikeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "stormstrike") {}
|
CastStormstrikeAction(PlayerbotAI* botAI) :
|
||||||
|
CastMeleeSpellAction(botAI, "stormstrike") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLavaLashAction : public CastMeleeSpellAction
|
class CastLavaLashAction : public CastMeleeSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastLavaLashAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "lava lash") {}
|
CastLavaLashAction(PlayerbotAI* botAI) :
|
||||||
|
CastMeleeSpellAction(botAI, "lava lash") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFlameShockAction : public CastDebuffSpellAction
|
class CastFlameShockAction : public CastDebuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true, 6.0f) {}
|
CastFlameShockAction(PlayerbotAI* botAI) :
|
||||||
bool isUseful() override
|
CastDebuffSpellAction(botAI, "flame shock", true, 6.0f) {}
|
||||||
{
|
|
||||||
// Bypass TTL check
|
bool isUseful() override { return CastAuraSpellAction::isUseful(); }
|
||||||
return CastAuraSpellAction::isUseful();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastEarthShockAction : public CastSpellAction
|
class CastEarthShockAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastEarthShockAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "earth shock") {}
|
CastEarthShockAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "earth shock") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFrostShockAction : public CastSnareSpellAction
|
class CastFrostShockAction : public CastSnareSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFrostShockAction(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, "frost shock") {}
|
CastFrostShockAction(PlayerbotAI* botAI) :
|
||||||
|
CastSnareSpellAction(botAI, "frost shock") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastChainLightningAction : public CastSpellAction
|
class CastChainLightningAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastChainLightningAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chain lightning") {}
|
CastChainLightningAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "chain lightning") {}
|
||||||
|
|
||||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLightningBoltAction : public CastSpellAction
|
class CastLightningBoltAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastLightningBoltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "lightning bolt") {}
|
CastLightningBoltAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "lightning bolt") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastThunderstormAction : public CastSpellAction
|
class CastThunderstormAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastThunderstormAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "thunderstorm") {}
|
CastThunderstormAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "thunderstorm") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLavaBurstAction : public CastSpellAction
|
class CastLavaBurstAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastLavaBurstAction(PlayerbotAI* ai) : CastSpellAction(ai, "lava burst") {}
|
CastLavaBurstAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "lava burst") {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -291,73 +315,71 @@ public:
|
|||||||
class CastLesserHealingWaveAction : public CastHealingSpellAction
|
class CastLesserHealingWaveAction : public CastHealingSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastLesserHealingWaveAction(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, "lesser healing wave") {}
|
CastLesserHealingWaveAction(PlayerbotAI* botAI) :
|
||||||
|
CastHealingSpellAction(botAI, "lesser healing wave") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLesserHealingWaveOnPartyAction : public HealPartyMemberAction
|
class CastLesserHealingWaveOnPartyAction : public HealPartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastLesserHealingWaveOnPartyAction(PlayerbotAI* botAI)
|
CastLesserHealingWaveOnPartyAction(PlayerbotAI* botAI) :
|
||||||
: HealPartyMemberAction(botAI, "lesser healing wave", 25.0f, HealingManaEfficiency::LOW)
|
HealPartyMemberAction(botAI, "lesser healing wave", 25.0f, HealingManaEfficiency::LOW) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastHealingWaveAction : public CastHealingSpellAction
|
class CastHealingWaveAction : public CastHealingSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastHealingWaveAction(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, "healing wave") {}
|
CastHealingWaveAction(PlayerbotAI* botAI) :
|
||||||
|
CastHealingSpellAction(botAI, "healing wave") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastHealingWaveOnPartyAction : public HealPartyMemberAction
|
class CastHealingWaveOnPartyAction : public HealPartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastHealingWaveOnPartyAction(PlayerbotAI* botAI)
|
CastHealingWaveOnPartyAction(PlayerbotAI* botAI) :
|
||||||
: HealPartyMemberAction(botAI, "healing wave", 50.0f, HealingManaEfficiency::MEDIUM)
|
HealPartyMemberAction(botAI, "healing wave", 50.0f, HealingManaEfficiency::MEDIUM) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastChainHealAction : public HealPartyMemberAction
|
class CastChainHealAction : public HealPartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastChainHealAction(PlayerbotAI* botAI)
|
CastChainHealAction(PlayerbotAI* botAI) :
|
||||||
: HealPartyMemberAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH)
|
HealPartyMemberAction(botAI, "chain heal", 15.0f, HealingManaEfficiency::HIGH) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastRiptideAction : public CastHealingSpellAction
|
class CastRiptideAction : public CastHealingSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRiptideAction(PlayerbotAI* botAI) : CastHealingSpellAction(botAI, "riptide") {}
|
CastRiptideAction(PlayerbotAI* botAI) :
|
||||||
|
CastHealingSpellAction(botAI, "riptide") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastRiptideOnPartyAction : public HealPartyMemberAction
|
class CastRiptideOnPartyAction : public HealPartyMemberAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastRiptideOnPartyAction(PlayerbotAI* botAI)
|
CastRiptideOnPartyAction(PlayerbotAI* botAI) :
|
||||||
: HealPartyMemberAction(botAI, "riptide", 15.0f, HealingManaEfficiency::VERY_HIGH)
|
HealPartyMemberAction(botAI, "riptide", 15.0f, HealingManaEfficiency::VERY_HIGH) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastEarthShieldAction : public CastBuffSpellAction
|
class CastEarthShieldAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastEarthShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "earth shield") {}
|
CastEarthShieldAction(PlayerbotAI* botAI) :
|
||||||
|
CastBuffSpellAction(botAI, "earth shield") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastEarthShieldOnPartyAction : public BuffOnPartyAction
|
class CastEarthShieldOnPartyAction : public BuffOnPartyAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastEarthShieldOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "earth shield") {}
|
CastEarthShieldOnPartyAction(PlayerbotAI* botAI) :
|
||||||
|
BuffOnPartyAction(botAI, "earth shield") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastEarthShieldOnMainTankAction : public BuffOnMainTankAction
|
class CastEarthShieldOnMainTankAction : public BuffOnMainTankAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastEarthShieldOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "earth shield", false) {}
|
CastEarthShieldOnMainTankAction(PlayerbotAI* botAI) :
|
||||||
|
BuffOnMainTankAction(botAI, "earth shield", false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Totem Spells
|
// Totem Spells
|
||||||
@ -365,8 +387,9 @@ public:
|
|||||||
class CastTotemAction : public CastBuffSpellAction
|
class CastTotemAction : public CastBuffSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastTotemAction(PlayerbotAI* botAI, std::string const spell, std::string const buffName = "")
|
CastTotemAction(
|
||||||
: CastBuffSpellAction(botAI, spell)
|
PlayerbotAI* botAI, std::string const spell,
|
||||||
|
std::string const buffName = "") : CastBuffSpellAction(botAI, spell)
|
||||||
{
|
{
|
||||||
buff = (buffName == "") ? spell : buffName;
|
buff = (buffName == "") ? spell : buffName;
|
||||||
}
|
}
|
||||||
@ -380,56 +403,66 @@ protected:
|
|||||||
class CastCallOfTheElementsAction : public CastSpellAction
|
class CastCallOfTheElementsAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCallOfTheElementsAction(PlayerbotAI* ai) : CastSpellAction(ai, "call of the elements") {}
|
CastCallOfTheElementsAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "call of the elements") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastTotemicRecallAction : public CastSpellAction
|
class CastTotemicRecallAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastTotemicRecallAction(PlayerbotAI* ai) : CastSpellAction(ai, "totemic recall") {}
|
CastTotemicRecallAction(PlayerbotAI* botAI) :
|
||||||
|
CastSpellAction(botAI, "totemic recall") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastStrengthOfEarthTotemAction : public CastTotemAction
|
class CastStrengthOfEarthTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastStrengthOfEarthTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "strength of earth totem", "strength of earth") {}
|
CastStrengthOfEarthTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "strength of earth totem", "strength of earth") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastStoneskinTotemAction : public CastTotemAction
|
class CastStoneskinTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastStoneskinTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "stoneskin totem", "stoneskin") {}
|
CastStoneskinTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "stoneskin totem", "stoneskin") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastTremorTotemAction : public CastTotemAction
|
class CastTremorTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastTremorTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "tremor totem", "") {}
|
CastTremorTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "tremor totem", "") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastEarthbindTotemAction : public CastTotemAction
|
class CastEarthbindTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastEarthbindTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "earthbind totem", "") {}
|
CastEarthbindTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "earthbind totem", "") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastStoneclawTotemAction : public CastTotemAction
|
class CastStoneclawTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastStoneclawTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "stoneclaw totem", "") {}
|
CastStoneclawTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "stoneclaw totem", "") {}
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastSearingTotemAction : public CastTotemAction
|
class CastSearingTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastSearingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "searing totem", "") {}
|
CastSearingTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "searing totem", "") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastMagmaTotemAction : public CastTotemAction
|
class CastMagmaTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastMagmaTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "magma totem", "") {}
|
CastMagmaTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "magma totem", "") {}
|
||||||
|
|
||||||
std::string const GetTargetName() override { return "self target"; }
|
std::string const GetTargetName() override { return "self target"; }
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
@ -437,26 +470,30 @@ public:
|
|||||||
class CastFlametongueTotemAction : public CastTotemAction
|
class CastFlametongueTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFlametongueTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "flametongue totem", "flametongue totem") {}
|
CastFlametongueTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "flametongue totem", "flametongue totem") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastTotemOfWrathAction : public CastTotemAction
|
class CastTotemOfWrathAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastTotemOfWrathAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "totem of wrath", "totem of wrath") {}
|
CastTotemOfWrathAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "totem of wrath", "totem of wrath") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFrostResistanceTotemAction : public CastTotemAction
|
class CastFrostResistanceTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFrostResistanceTotemAction(PlayerbotAI* botAI)
|
CastFrostResistanceTotemAction(PlayerbotAI* botAI) :
|
||||||
: CastTotemAction(botAI, "frost resistance totem", "frost resistance") {}
|
CastTotemAction(botAI, "frost resistance totem", "frost resistance") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFireElementalTotemAction : public CastTotemAction
|
class CastFireElementalTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFireElementalTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "") {}
|
CastFireElementalTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "fire elemental totem", "") {}
|
||||||
|
|
||||||
virtual std::string const GetTargetName() override { return "self target"; }
|
virtual std::string const GetTargetName() override { return "self target"; }
|
||||||
virtual bool isUseful() override { return CastTotemAction::isUseful(); }
|
virtual bool isUseful() override { return CastTotemAction::isUseful(); }
|
||||||
};
|
};
|
||||||
@ -464,7 +501,9 @@ public:
|
|||||||
class CastFireElementalTotemMeleeAction : public CastTotemAction
|
class CastFireElementalTotemMeleeAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFireElementalTotemMeleeAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "") {}
|
CastFireElementalTotemMeleeAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "fire elemental totem", "") {}
|
||||||
|
|
||||||
virtual std::string const GetTargetName() override { return "self target"; }
|
virtual std::string const GetTargetName() override { return "self target"; }
|
||||||
virtual bool isUseful() override
|
virtual bool isUseful() override
|
||||||
{
|
{
|
||||||
@ -478,51 +517,60 @@ public:
|
|||||||
class CastHealingStreamTotemAction : public CastTotemAction
|
class CastHealingStreamTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastHealingStreamTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "healing stream totem", "") {}
|
CastHealingStreamTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "healing stream totem", "") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastManaSpringTotemAction : public CastTotemAction
|
class CastManaSpringTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem", "mana spring") {}
|
CastManaSpringTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "mana spring totem", "mana spring") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCleansingTotemAction : public CastTotemAction
|
class CastCleansingTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCleansingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "cleansing totem", "") {}
|
CastCleansingTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "cleansing totem", "") {}
|
||||||
virtual bool isUseful();
|
virtual bool isUseful();
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastManaTideTotemAction : public CastTotemAction
|
class CastManaTideTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastManaTideTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana tide totem", "") {}
|
CastManaTideTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "mana tide totem", "") {}
|
||||||
|
|
||||||
std::string const GetTargetName() override { return "self target"; }
|
std::string const GetTargetName() override { return "self target"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastFireResistanceTotemAction : public CastTotemAction
|
class CastFireResistanceTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastFireResistanceTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "fire resistance totem", "fire resistance") {}
|
CastFireResistanceTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "fire resistance totem", "fire resistance") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWrathOfAirTotemAction : public CastTotemAction
|
class CastWrathOfAirTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWrathOfAirTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "wrath of air totem", "wrath of air totem") {}
|
CastWrathOfAirTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "wrath of air totem", "wrath of air totem") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWindfuryTotemAction : public CastTotemAction
|
class CastWindfuryTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastWindfuryTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "windfury totem", "windfury totem") {}
|
CastWindfuryTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "windfury totem", "windfury totem") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastNatureResistanceTotemAction : public CastTotemAction
|
class CastNatureResistanceTotemAction : public CastTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastNatureResistanceTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "nature resistance totem", "nature resistance") {}
|
CastNatureResistanceTotemAction(PlayerbotAI* botAI) :
|
||||||
|
CastTotemAction(botAI, "nature resistance totem", "nature resistance") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set Strategy Assigned Totems
|
// Set Strategy Assigned Totems
|
||||||
@ -532,12 +580,8 @@ class SetTotemAction : public Action
|
|||||||
public:
|
public:
|
||||||
// Template constructor: infers N (size of the id array) at compile time
|
// Template constructor: infers N (size of the id array) at compile time
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
SetTotemAction(PlayerbotAI* botAI, std::string const& totemName, const uint32 (&ids)[N], int actionButtonId)
|
SetTotemAction(PlayerbotAI* botAI, std::string const& totemName, const uint32 (&ids)[N], int actionButtonId) :
|
||||||
: Action(botAI, "set " + totemName)
|
Action(botAI, "set " + totemName), totemSpellIds(ids), totemSpellIdsCount(N), actionButtonId(actionButtonId) {}
|
||||||
, totemSpellIds(ids)
|
|
||||||
, totemSpellIdsCount(N)
|
|
||||||
, actionButtonId(actionButtonId)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
uint32 const* totemSpellIds;
|
uint32 const* totemSpellIds;
|
||||||
@ -548,120 +592,120 @@ public:
|
|||||||
class SetStrengthOfEarthTotemAction : public SetTotemAction
|
class SetStrengthOfEarthTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStrengthOfEarthTotemAction(PlayerbotAI* ai)
|
SetStrengthOfEarthTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "strength of earth totem", STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
SetTotemAction(botAI, "strength of earth totem", STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetStoneskinTotemAction : public SetTotemAction
|
class SetStoneskinTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStoneskinTotemAction(PlayerbotAI* ai)
|
SetStoneskinTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "stoneskin totem", STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
SetTotemAction(botAI, "stoneskin totem", STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTremorTotemAction : public SetTotemAction
|
class SetTremorTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetTremorTotemAction(PlayerbotAI* ai)
|
SetTremorTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "tremor totem", TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
SetTotemAction(botAI, "tremor totem", TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetEarthbindTotemAction : public SetTotemAction
|
class SetEarthbindTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetEarthbindTotemAction(PlayerbotAI* ai)
|
SetEarthbindTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "earthbind totem", EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
SetTotemAction(botAI, "earthbind totem", EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetSearingTotemAction : public SetTotemAction
|
class SetSearingTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetSearingTotemAction(PlayerbotAI* ai)
|
SetSearingTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "searing totem", SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
SetTotemAction(botAI, "searing totem", SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetMagmaTotemAction : public SetTotemAction
|
class SetMagmaTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetMagmaTotemAction(PlayerbotAI* ai)
|
SetMagmaTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "magma totem", MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
SetTotemAction(botAI, "magma totem", MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFlametongueTotemAction : public SetTotemAction
|
class SetFlametongueTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFlametongueTotemAction(PlayerbotAI* ai)
|
SetFlametongueTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "flametongue totem", FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
SetTotemAction(botAI, "flametongue totem", FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTotemOfWrathAction : public SetTotemAction
|
class SetTotemOfWrathAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetTotemOfWrathAction(PlayerbotAI* ai)
|
SetTotemOfWrathAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "totem of wrath", TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {}
|
SetTotemAction(botAI, "totem of wrath", TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFrostResistanceTotemAction : public SetTotemAction
|
class SetFrostResistanceTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFrostResistanceTotemAction(PlayerbotAI* ai)
|
SetFrostResistanceTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "frost resistance totem", FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
SetTotemAction(botAI, "frost resistance totem", FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetHealingStreamTotemAction : public SetTotemAction
|
class SetHealingStreamTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetHealingStreamTotemAction(PlayerbotAI* ai)
|
SetHealingStreamTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "healing stream totem", HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
SetTotemAction(botAI, "healing stream totem", HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetManaSpringTotemAction : public SetTotemAction
|
class SetManaSpringTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetManaSpringTotemAction(PlayerbotAI* ai)
|
SetManaSpringTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "mana spring totem", MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
SetTotemAction(botAI, "mana spring totem", MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetCleansingTotemAction : public SetTotemAction
|
class SetCleansingTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetCleansingTotemAction(PlayerbotAI* ai)
|
SetCleansingTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "cleansing totem", CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
SetTotemAction(botAI, "cleansing totem", CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFireResistanceTotemAction : public SetTotemAction
|
class SetFireResistanceTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFireResistanceTotemAction(PlayerbotAI* ai)
|
SetFireResistanceTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "fire resistance totem", FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
SetTotemAction(botAI, "fire resistance totem", FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetWrathOfAirTotemAction : public SetTotemAction
|
class SetWrathOfAirTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetWrathOfAirTotemAction(PlayerbotAI* ai)
|
SetWrathOfAirTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "wrath of air totem", WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
SetTotemAction(botAI, "wrath of air totem", WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetWindfuryTotemAction : public SetTotemAction
|
class SetWindfuryTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetWindfuryTotemAction(PlayerbotAI* ai)
|
SetWindfuryTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "windfury totem", WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
SetTotemAction(botAI, "windfury totem", WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetNatureResistanceTotemAction : public SetTotemAction
|
class SetNatureResistanceTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetNatureResistanceTotemAction(PlayerbotAI* ai)
|
SetNatureResistanceTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "nature resistance totem", NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
SetTotemAction(botAI, "nature resistance totem", NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetGroundingTotemAction : public SetTotemAction
|
class SetGroundingTotemAction : public SetTotemAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetGroundingTotemAction(PlayerbotAI* ai)
|
SetGroundingTotemAction(PlayerbotAI* botAI) :
|
||||||
: SetTotemAction(ai, "grounding totem", GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
SetTotemAction(botAI, "grounding totem", GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -158,10 +158,6 @@ public:
|
|||||||
creators["bloodlust"] = &ShamanATriggerFactoryInternal::bloodlust;
|
creators["bloodlust"] = &ShamanATriggerFactoryInternal::bloodlust;
|
||||||
creators["elemental mastery"] = &ShamanATriggerFactoryInternal::elemental_mastery;
|
creators["elemental mastery"] = &ShamanATriggerFactoryInternal::elemental_mastery;
|
||||||
creators["wind shear on enemy healer"] = &ShamanATriggerFactoryInternal::wind_shear_on_enemy_healer;
|
creators["wind shear on enemy healer"] = &ShamanATriggerFactoryInternal::wind_shear_on_enemy_healer;
|
||||||
creators["cure poison"] = &ShamanATriggerFactoryInternal::cure_poison;
|
|
||||||
creators["party member cure poison"] = &ShamanATriggerFactoryInternal::party_member_cure_poison;
|
|
||||||
creators["cure disease"] = &ShamanATriggerFactoryInternal::cure_disease;
|
|
||||||
creators["party member cure disease"] = &ShamanATriggerFactoryInternal::party_member_cure_disease;
|
|
||||||
creators["earth shield on main tank"] = &ShamanATriggerFactoryInternal::earth_shield_on_main_tank;
|
creators["earth shield on main tank"] = &ShamanATriggerFactoryInternal::earth_shield_on_main_tank;
|
||||||
creators["maelstrom weapon 3"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_3;
|
creators["maelstrom weapon 3"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_3;
|
||||||
creators["maelstrom weapon 4"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_4;
|
creators["maelstrom weapon 4"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_4;
|
||||||
@ -225,42 +221,38 @@ private:
|
|||||||
static Trigger* shock(PlayerbotAI* botAI) { return new ShockTrigger(botAI); }
|
static Trigger* shock(PlayerbotAI* botAI) { return new ShockTrigger(botAI); }
|
||||||
static Trigger* frost_shock_snare(PlayerbotAI* botAI) { return new FrostShockSnareTrigger(botAI); }
|
static Trigger* frost_shock_snare(PlayerbotAI* botAI) { return new FrostShockSnareTrigger(botAI); }
|
||||||
static Trigger* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new WindShearInterruptEnemyHealerSpellTrigger(botAI); }
|
static Trigger* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new WindShearInterruptEnemyHealerSpellTrigger(botAI); }
|
||||||
static Trigger* cure_poison(PlayerbotAI* botAI) { return new CurePoisonTrigger(botAI); }
|
static Trigger* earth_shield_on_main_tank(PlayerbotAI* botAI) { return new EarthShieldOnMainTankTrigger(botAI); }
|
||||||
static Trigger* party_member_cure_poison(PlayerbotAI* botAI) { return new PartyMemberCurePoisonTrigger(botAI); }
|
static Trigger* flame_shock(PlayerbotAI* botAI) { return new FlameShockTrigger(botAI); }
|
||||||
static Trigger* cure_disease(PlayerbotAI* botAI) { return new CureDiseaseTrigger(botAI); }
|
|
||||||
static Trigger* party_member_cure_disease(PlayerbotAI* botAI) { return new PartyMemberCureDiseaseTrigger(botAI); }
|
|
||||||
static Trigger* earth_shield_on_main_tank(PlayerbotAI* ai) { return new EarthShieldOnMainTankTrigger(ai); }
|
|
||||||
static Trigger* flame_shock(PlayerbotAI* ai) { return new FlameShockTrigger(ai); }
|
|
||||||
static Trigger* fire_elemental_totem(PlayerbotAI* botAI) { return new FireElementalTotemTrigger(botAI); }
|
static Trigger* fire_elemental_totem(PlayerbotAI* botAI) { return new FireElementalTotemTrigger(botAI); }
|
||||||
static Trigger* earth_shock_execute(PlayerbotAI* botAI) { return new EarthShockExecuteTrigger(botAI); }
|
static Trigger* earth_shock_execute(PlayerbotAI* botAI) { return new EarthShockExecuteTrigger(botAI); }
|
||||||
static Trigger* spirit_walk_ready(PlayerbotAI* ai) { return new SpiritWalkTrigger(ai); }
|
static Trigger* spirit_walk_ready(PlayerbotAI* botAI) { return new SpiritWalkTrigger(botAI); }
|
||||||
static Trigger* chain_lightning_no_cd(PlayerbotAI* ai) { return new ChainLightningNoCdTrigger(ai); }
|
static Trigger* chain_lightning_no_cd(PlayerbotAI* botAI) { return new ChainLightningNoCdTrigger(botAI); }
|
||||||
static Trigger* call_of_the_elements_and_enemy_within_melee(PlayerbotAI* ai) { return new CallOfTheElementsAndEnemyWithinMeleeTrigger(ai); }
|
static Trigger* call_of_the_elements_and_enemy_within_melee(PlayerbotAI* botAI) { return new CallOfTheElementsAndEnemyWithinMeleeTrigger(botAI); }
|
||||||
static Trigger* maelstrom_weapon_5_and_medium_aoe(PlayerbotAI* ai) { return new MaelstromWeapon5AndMediumAoeTrigger(ai); }
|
static Trigger* maelstrom_weapon_5_and_medium_aoe(PlayerbotAI* botAI) { return new MaelstromWeapon5AndMediumAoeTrigger(botAI); }
|
||||||
static Trigger* maelstrom_weapon_4_and_medium_aoe(PlayerbotAI* ai) { return new MaelstromWeapon4AndMediumAoeTrigger(ai); }
|
static Trigger* maelstrom_weapon_4_and_medium_aoe(PlayerbotAI* botAI) { return new MaelstromWeapon4AndMediumAoeTrigger(botAI); }
|
||||||
static Trigger* call_of_the_elements(PlayerbotAI* ai) { return new CallOfTheElementsTrigger(ai); }
|
static Trigger* call_of_the_elements(PlayerbotAI* botAI) { return new CallOfTheElementsTrigger(botAI); }
|
||||||
static Trigger* totemic_recall(PlayerbotAI* ai) { return new TotemicRecallTrigger(ai); }
|
static Trigger* totemic_recall(PlayerbotAI* botAI) { return new TotemicRecallTrigger(botAI); }
|
||||||
static Trigger* no_earth_totem(PlayerbotAI* ai) { return new NoEarthTotemTrigger(ai); }
|
static Trigger* no_earth_totem(PlayerbotAI* botAI) { return new NoEarthTotemTrigger(botAI); }
|
||||||
static Trigger* no_fire_totem(PlayerbotAI* ai) { return new NoFireTotemTrigger(ai); }
|
static Trigger* no_fire_totem(PlayerbotAI* botAI) { return new NoFireTotemTrigger(botAI); }
|
||||||
static Trigger* no_water_totem(PlayerbotAI* ai) { return new NoWaterTotemTrigger(ai); }
|
static Trigger* no_water_totem(PlayerbotAI* botAI) { return new NoWaterTotemTrigger(botAI); }
|
||||||
static Trigger* no_air_totem(PlayerbotAI* ai) { return new NoAirTotemTrigger(ai); }
|
static Trigger* no_air_totem(PlayerbotAI* botAI) { return new NoAirTotemTrigger(botAI); }
|
||||||
static Trigger* set_strength_of_earth_totem(PlayerbotAI* ai) { return new SetStrengthOfEarthTotemTrigger(ai); }
|
static Trigger* set_strength_of_earth_totem(PlayerbotAI* botAI) { return new SetStrengthOfEarthTotemTrigger(botAI); }
|
||||||
static Trigger* set_stoneskin_totem(PlayerbotAI* ai) { return new SetStoneskinTotemTrigger(ai); }
|
static Trigger* set_stoneskin_totem(PlayerbotAI* botAI) { return new SetStoneskinTotemTrigger(botAI); }
|
||||||
static Trigger* set_tremor_totem(PlayerbotAI* ai) { return new SetTremorTotemTrigger(ai); }
|
static Trigger* set_tremor_totem(PlayerbotAI* botAI) { return new SetTremorTotemTrigger(botAI); }
|
||||||
static Trigger* set_earthbind_totem(PlayerbotAI* ai) { return new SetEarthbindTotemTrigger(ai); }
|
static Trigger* set_earthbind_totem(PlayerbotAI* botAI) { return new SetEarthbindTotemTrigger(botAI); }
|
||||||
static Trigger* set_searing_totem(PlayerbotAI* ai) { return new SetSearingTotemTrigger(ai); }
|
static Trigger* set_searing_totem(PlayerbotAI* botAI) { return new SetSearingTotemTrigger(botAI); }
|
||||||
static Trigger* set_magma_totem(PlayerbotAI* ai) { return new SetMagmaTotemTrigger(ai); }
|
static Trigger* set_magma_totem(PlayerbotAI* botAI) { return new SetMagmaTotemTrigger(botAI); }
|
||||||
static Trigger* set_flametongue_totem(PlayerbotAI* ai) { return new SetFlametongueTotemTrigger(ai); }
|
static Trigger* set_flametongue_totem(PlayerbotAI* botAI) { return new SetFlametongueTotemTrigger(botAI); }
|
||||||
static Trigger* set_totem_of_wrath(PlayerbotAI* ai) { return new SetTotemOfWrathTrigger(ai); }
|
static Trigger* set_totem_of_wrath(PlayerbotAI* botAI) { return new SetTotemOfWrathTrigger(botAI); }
|
||||||
static Trigger* set_frost_resistance_totem(PlayerbotAI* ai) { return new SetFrostResistanceTotemTrigger(ai); }
|
static Trigger* set_frost_resistance_totem(PlayerbotAI* botAI) { return new SetFrostResistanceTotemTrigger(botAI); }
|
||||||
static Trigger* set_healing_stream_totem(PlayerbotAI* ai) { return new SetHealingStreamTotemTrigger(ai); }
|
static Trigger* set_healing_stream_totem(PlayerbotAI* botAI) { return new SetHealingStreamTotemTrigger(botAI); }
|
||||||
static Trigger* set_mana_spring_totem(PlayerbotAI* ai) { return new SetManaSpringTotemTrigger(ai); }
|
static Trigger* set_mana_spring_totem(PlayerbotAI* botAI) { return new SetManaSpringTotemTrigger(botAI); }
|
||||||
static Trigger* set_cleansing_totem(PlayerbotAI* ai) { return new SetCleansingTotemTrigger(ai); }
|
static Trigger* set_cleansing_totem(PlayerbotAI* botAI) { return new SetCleansingTotemTrigger(botAI); }
|
||||||
static Trigger* set_fire_resistance_totem(PlayerbotAI* ai) { return new SetFireResistanceTotemTrigger(ai); }
|
static Trigger* set_fire_resistance_totem(PlayerbotAI* botAI) { return new SetFireResistanceTotemTrigger(botAI); }
|
||||||
static Trigger* set_wrath_of_air_totem(PlayerbotAI* ai) { return new SetWrathOfAirTotemTrigger(ai); }
|
static Trigger* set_wrath_of_air_totem(PlayerbotAI* botAI) { return new SetWrathOfAirTotemTrigger(botAI); }
|
||||||
static Trigger* set_windfury_totem(PlayerbotAI* ai) { return new SetWindfuryTotemTrigger(ai); }
|
static Trigger* set_windfury_totem(PlayerbotAI* botAI) { return new SetWindfuryTotemTrigger(botAI); }
|
||||||
static Trigger* set_nature_resistance_totem(PlayerbotAI* ai) { return new SetNatureResistanceTotemTrigger(ai); }
|
static Trigger* set_nature_resistance_totem(PlayerbotAI* botAI) { return new SetNatureResistanceTotemTrigger(botAI); }
|
||||||
static Trigger* set_grounding_totem(PlayerbotAI* ai) { return new SetGroundingTotemTrigger(ai); }
|
static Trigger* set_grounding_totem(PlayerbotAI* botAI) { return new SetGroundingTotemTrigger(botAI); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
|
class ShamanAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
@ -272,11 +264,12 @@ public:
|
|||||||
creators["lightning shield"] = &ShamanAiObjectContextInternal::lightning_shield;
|
creators["lightning shield"] = &ShamanAiObjectContextInternal::lightning_shield;
|
||||||
creators["wind shear"] = &ShamanAiObjectContextInternal::wind_shear;
|
creators["wind shear"] = &ShamanAiObjectContextInternal::wind_shear;
|
||||||
creators["wind shear on enemy healer"] = &ShamanAiObjectContextInternal::wind_shear_on_enemy_healer;
|
creators["wind shear on enemy healer"] = &ShamanAiObjectContextInternal::wind_shear_on_enemy_healer;
|
||||||
creators["rockbiter weapon"] = &ShamanAiObjectContextInternal::rockbiter_weapon;
|
creators["rockbiter weapon main hand"] = &ShamanAiObjectContextInternal::rockbiter_weapon_main_hand;
|
||||||
creators["flametongue weapon"] = &ShamanAiObjectContextInternal::flametongue_weapon;
|
creators["flametongue weapon main hand"] = &ShamanAiObjectContextInternal::flametongue_weapon_main_hand;
|
||||||
creators["frostbrand weapon"] = &ShamanAiObjectContextInternal::frostbrand_weapon;
|
creators["flametongue weapon off hand"] = &ShamanAiObjectContextInternal::flametongue_weapon_off_hand;
|
||||||
creators["windfury weapon"] = &ShamanAiObjectContextInternal::windfury_weapon;
|
// creators["frostbrand weapon off hand"] = &ShamanAiObjectContextInternal::frostbrand_weapon_off_hand;
|
||||||
creators["earthliving weapon"] = &ShamanAiObjectContextInternal::earthliving_weapon;
|
creators["windfury weapon main hand"] = &ShamanAiObjectContextInternal::windfury_weapon_main_hand;
|
||||||
|
creators["earthliving weapon main hand"] = &ShamanAiObjectContextInternal::earthliving_weapon_main_hand;
|
||||||
creators["purge"] = &ShamanAiObjectContextInternal::purge;
|
creators["purge"] = &ShamanAiObjectContextInternal::purge;
|
||||||
creators["healing wave"] = &ShamanAiObjectContextInternal::healing_wave;
|
creators["healing wave"] = &ShamanAiObjectContextInternal::healing_wave;
|
||||||
creators["lesser healing wave"] = &ShamanAiObjectContextInternal::lesser_healing_wave;
|
creators["lesser healing wave"] = &ShamanAiObjectContextInternal::lesser_healing_wave;
|
||||||
@ -308,10 +301,9 @@ public:
|
|||||||
creators["heroism"] = &ShamanAiObjectContextInternal::heroism;
|
creators["heroism"] = &ShamanAiObjectContextInternal::heroism;
|
||||||
creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust;
|
creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust;
|
||||||
creators["elemental mastery"] = &ShamanAiObjectContextInternal::elemental_mastery;
|
creators["elemental mastery"] = &ShamanAiObjectContextInternal::elemental_mastery;
|
||||||
creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease;
|
creators["cure toxins"] = &ShamanAiObjectContextInternal::cure_toxins;
|
||||||
creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party;
|
creators["cure toxins poison on party"] = &ShamanAiObjectContextInternal::cure_toxins_poison_on_party;
|
||||||
creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison;
|
creators["cure toxins disease on party"] = &ShamanAiObjectContextInternal::cure_toxins_disease_on_party;
|
||||||
creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party;
|
|
||||||
creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst;
|
creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst;
|
||||||
creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank;
|
creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank;
|
||||||
creators["shamanistic rage"] = &ShamanAiObjectContextInternal::shamanistic_rage;
|
creators["shamanistic rage"] = &ShamanAiObjectContextInternal::shamanistic_rage;
|
||||||
@ -368,10 +360,10 @@ private:
|
|||||||
static Action* frost_shock(PlayerbotAI* botAI) { return new CastFrostShockAction(botAI); }
|
static Action* frost_shock(PlayerbotAI* botAI) { return new CastFrostShockAction(botAI); }
|
||||||
static Action* earth_shock(PlayerbotAI* botAI) { return new CastEarthShockAction(botAI); }
|
static Action* earth_shock(PlayerbotAI* botAI) { return new CastEarthShockAction(botAI); }
|
||||||
static Action* flame_shock(PlayerbotAI* botAI) { return new CastFlameShockAction(botAI); }
|
static Action* flame_shock(PlayerbotAI* botAI) { return new CastFlameShockAction(botAI); }
|
||||||
|
static Action* cleanse_spirit(PlayerbotAI* botAI) { return new CastCleanseSpiritAction(botAI); }
|
||||||
static Action* cleanse_spirit_poison_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritPoisonOnPartyAction(botAI); }
|
static Action* cleanse_spirit_poison_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritPoisonOnPartyAction(botAI); }
|
||||||
static Action* cleanse_spirit_disease_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritDiseaseOnPartyAction(botAI); }
|
static Action* cleanse_spirit_disease_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritDiseaseOnPartyAction(botAI); }
|
||||||
static Action* cleanse_spirit_curse_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritCurseOnPartyAction(botAI); }
|
static Action* cleanse_spirit_curse_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritCurseOnPartyAction(botAI); }
|
||||||
static Action* cleanse_spirit(PlayerbotAI* botAI) { return new CastCleanseSpiritAction(botAI); }
|
|
||||||
static Action* water_walking(PlayerbotAI* botAI) { return new CastWaterWalkingAction(botAI); }
|
static Action* water_walking(PlayerbotAI* botAI) { return new CastWaterWalkingAction(botAI); }
|
||||||
static Action* water_breathing(PlayerbotAI* botAI) { return new CastWaterBreathingAction(botAI); }
|
static Action* water_breathing(PlayerbotAI* botAI) { return new CastWaterBreathingAction(botAI); }
|
||||||
static Action* water_walking_on_party(PlayerbotAI* botAI) { return new CastWaterWalkingOnPartyAction(botAI); }
|
static Action* water_walking_on_party(PlayerbotAI* botAI) { return new CastWaterWalkingOnPartyAction(botAI); }
|
||||||
@ -380,11 +372,12 @@ private:
|
|||||||
static Action* lightning_shield(PlayerbotAI* botAI) { return new CastLightningShieldAction(botAI); }
|
static Action* lightning_shield(PlayerbotAI* botAI) { return new CastLightningShieldAction(botAI); }
|
||||||
static Action* fire_nova(PlayerbotAI* botAI) { return new CastFireNovaAction(botAI); }
|
static Action* fire_nova(PlayerbotAI* botAI) { return new CastFireNovaAction(botAI); }
|
||||||
static Action* wind_shear(PlayerbotAI* botAI) { return new CastWindShearAction(botAI); }
|
static Action* wind_shear(PlayerbotAI* botAI) { return new CastWindShearAction(botAI); }
|
||||||
static Action* rockbiter_weapon(PlayerbotAI* botAI) { return new CastRockbiterWeaponAction(botAI); }
|
static Action* rockbiter_weapon_main_hand(PlayerbotAI* botAI) { return new CastRockbiterWeaponMainHandAction(botAI); }
|
||||||
static Action* flametongue_weapon(PlayerbotAI* botAI) { return new CastFlametongueWeaponAction(botAI); }
|
static Action* flametongue_weapon_main_hand(PlayerbotAI* botAI) { return new CastFlametongueWeaponMainHandAction(botAI); }
|
||||||
static Action* frostbrand_weapon(PlayerbotAI* botAI) { return new CastFrostbrandWeaponAction(botAI); }
|
static Action* flametongue_weapon_off_hand(PlayerbotAI* botAI) { return new CastFlametongueWeaponOffHandAction(botAI); }
|
||||||
static Action* windfury_weapon(PlayerbotAI* botAI) { return new CastWindfuryWeaponAction(botAI); }
|
// static Action* frostbrand_weapon_off_hand(PlayerbotAI* botAI) { return new CastFrostbrandWeaponOffHandAction(botAI); }
|
||||||
static Action* earthliving_weapon(PlayerbotAI* botAI) { return new CastEarthlivingWeaponAction(botAI); }
|
static Action* earthliving_weapon_main_hand(PlayerbotAI* botAI) { return new CastEarthlivingWeaponMainHandAction(botAI); }
|
||||||
|
static Action* windfury_weapon_main_hand(PlayerbotAI* botAI) { return new CastWindfuryWeaponMainHandAction(botAI); }
|
||||||
static Action* purge(PlayerbotAI* botAI) { return new CastPurgeAction(botAI); }
|
static Action* purge(PlayerbotAI* botAI) { return new CastPurgeAction(botAI); }
|
||||||
static Action* healing_wave(PlayerbotAI* botAI) { return new CastHealingWaveAction(botAI); }
|
static Action* healing_wave(PlayerbotAI* botAI) { return new CastHealingWaveAction(botAI); }
|
||||||
static Action* lesser_healing_wave(PlayerbotAI* botAI) { return new CastLesserHealingWaveAction(botAI); }
|
static Action* lesser_healing_wave(PlayerbotAI* botAI) { return new CastLesserHealingWaveAction(botAI); }
|
||||||
@ -399,54 +392,53 @@ private:
|
|||||||
static Action* lava_lash(PlayerbotAI* botAI) { return new CastLavaLashAction(botAI); }
|
static Action* lava_lash(PlayerbotAI* botAI) { return new CastLavaLashAction(botAI); }
|
||||||
static Action* ancestral_spirit(PlayerbotAI* botAI) { return new CastAncestralSpiritAction(botAI); }
|
static Action* ancestral_spirit(PlayerbotAI* botAI) { return new CastAncestralSpiritAction(botAI); }
|
||||||
static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new CastWindShearOnEnemyHealerAction(botAI); }
|
static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new CastWindShearOnEnemyHealerAction(botAI); }
|
||||||
static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonActionSham(botAI); }
|
static Action* cure_toxins(PlayerbotAI* botAI) { return new CastCureToxinsActionSham(botAI); }
|
||||||
static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyActionSham(botAI); }
|
static Action* cure_toxins_poison_on_party(PlayerbotAI* botAI) { return new CastCureToxinsPoisonOnPartyActionSham(botAI); }
|
||||||
static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseActionSham(botAI); }
|
static Action* cure_toxins_disease_on_party(PlayerbotAI* botAI) { return new CastCureToxinsDiseaseOnPartyActionSham(botAI); }
|
||||||
static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyActionSham(botAI); }
|
static Action* lava_burst(PlayerbotAI* botAI) { return new CastLavaBurstAction(botAI); }
|
||||||
static Action* lava_burst(PlayerbotAI* ai) { return new CastLavaBurstAction(ai); }
|
static Action* earth_shield_on_main_tank(PlayerbotAI* botAI) { return new CastEarthShieldOnMainTankAction(botAI); }
|
||||||
static Action* earth_shield_on_main_tank(PlayerbotAI* ai) { return new CastEarthShieldOnMainTankAction(ai); }
|
static Action* shamanistic_rage(PlayerbotAI* botAI) { return new CastShamanisticRageAction(botAI); }
|
||||||
static Action* shamanistic_rage(PlayerbotAI* ai) { return new CastShamanisticRageAction(ai); }
|
static Action* feral_spirit(PlayerbotAI* botAI) { return new CastFeralSpiritAction(botAI); }
|
||||||
static Action* feral_spirit(PlayerbotAI* ai) { return new CastFeralSpiritAction(ai); }
|
static Action* spirit_walk(PlayerbotAI* botAI) { return new CastSpiritWalkAction(botAI); }
|
||||||
static Action* spirit_walk(PlayerbotAI* ai) { return new CastSpiritWalkAction(ai); }
|
static Action* call_of_the_elements(PlayerbotAI* botAI) { return new CastCallOfTheElementsAction(botAI); }
|
||||||
static Action* call_of_the_elements(PlayerbotAI* ai) { return new CastCallOfTheElementsAction(ai); }
|
static Action* totemic_recall(PlayerbotAI* botAI) { return new CastTotemicRecallAction(botAI); }
|
||||||
static Action* totemic_recall(PlayerbotAI* ai) { return new CastTotemicRecallAction(ai); }
|
static Action* strength_of_earth_totem(PlayerbotAI* botAI) { return new CastStrengthOfEarthTotemAction(botAI); }
|
||||||
static Action* strength_of_earth_totem(PlayerbotAI* ai) { return new CastStrengthOfEarthTotemAction(ai); }
|
static Action* stoneskin_totem(PlayerbotAI* botAI) { return new CastStoneskinTotemAction(botAI); }
|
||||||
static Action* stoneskin_totem(PlayerbotAI* ai) { return new CastStoneskinTotemAction(ai); }
|
static Action* tremor_totem(PlayerbotAI* botAI) { return new CastTremorTotemAction(botAI); }
|
||||||
static Action* tremor_totem(PlayerbotAI* ai) { return new CastTremorTotemAction(ai); }
|
static Action* earthbind_totem(PlayerbotAI* botAI) { return new CastEarthbindTotemAction(botAI); }
|
||||||
static Action* earthbind_totem(PlayerbotAI* ai) { return new CastEarthbindTotemAction(ai); }
|
static Action* stoneclaw_totem(PlayerbotAI* botAI) { return new CastStoneclawTotemAction(botAI); }
|
||||||
static Action* stoneclaw_totem(PlayerbotAI* ai) { return new CastStoneclawTotemAction(ai); }
|
static Action* searing_totem(PlayerbotAI* botAI) { return new CastSearingTotemAction(botAI); }
|
||||||
static Action* searing_totem(PlayerbotAI* ai) { return new CastSearingTotemAction(ai); }
|
static Action* magma_totem(PlayerbotAI* botAI) { return new CastMagmaTotemAction(botAI); }
|
||||||
static Action* magma_totem(PlayerbotAI* ai) { return new CastMagmaTotemAction(ai); }
|
static Action* flametongue_totem(PlayerbotAI* botAI) { return new CastFlametongueTotemAction(botAI); }
|
||||||
static Action* flametongue_totem(PlayerbotAI* ai) { return new CastFlametongueTotemAction(ai); }
|
static Action* totem_of_wrath(PlayerbotAI* botAI) { return new CastTotemOfWrathAction(botAI); }
|
||||||
static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); }
|
static Action* frost_resistance_totem(PlayerbotAI* botAI) { return new CastFrostResistanceTotemAction(botAI); }
|
||||||
static Action* frost_resistance_totem(PlayerbotAI* ai) { return new CastFrostResistanceTotemAction(ai); }
|
static Action* fire_elemental_totem(PlayerbotAI* botAI) { return new CastFireElementalTotemAction(botAI); }
|
||||||
static Action* fire_elemental_totem(PlayerbotAI* ai) { return new CastFireElementalTotemAction(ai); }
|
static Action* fire_elemental_totem_melee(PlayerbotAI* botAI) { return new CastFireElementalTotemMeleeAction(botAI); }
|
||||||
static Action* fire_elemental_totem_melee(PlayerbotAI* ai) { return new CastFireElementalTotemMeleeAction(ai); }
|
static Action* healing_stream_totem(PlayerbotAI* botAI) { return new CastHealingStreamTotemAction(botAI); }
|
||||||
static Action* healing_stream_totem(PlayerbotAI* ai) { return new CastHealingStreamTotemAction(ai); }
|
static Action* mana_spring_totem(PlayerbotAI* botAI) { return new CastManaSpringTotemAction(botAI); }
|
||||||
static Action* mana_spring_totem(PlayerbotAI* ai) { return new CastManaSpringTotemAction(ai); }
|
static Action* cleansing_totem(PlayerbotAI* botAI) { return new CastCleansingTotemAction(botAI); }
|
||||||
static Action* cleansing_totem(PlayerbotAI* ai) { return new CastCleansingTotemAction(ai); }
|
static Action* mana_tide_totem(PlayerbotAI* botAI) { return new CastManaTideTotemAction(botAI); }
|
||||||
static Action* mana_tide_totem(PlayerbotAI* ai) { return new CastManaTideTotemAction(ai); }
|
static Action* fire_resistance_totem(PlayerbotAI* botAI) { return new CastFireResistanceTotemAction(botAI); }
|
||||||
static Action* fire_resistance_totem(PlayerbotAI* ai) { return new CastFireResistanceTotemAction(ai); }
|
static Action* wrath_of_air_totem(PlayerbotAI* botAI) { return new CastWrathOfAirTotemAction(botAI); }
|
||||||
static Action* wrath_of_air_totem(PlayerbotAI* ai) { return new CastWrathOfAirTotemAction(ai); }
|
static Action* windfury_totem(PlayerbotAI* botAI) { return new CastWindfuryTotemAction(botAI); }
|
||||||
static Action* windfury_totem(PlayerbotAI* ai) { return new CastWindfuryTotemAction(ai); }
|
static Action* nature_resistance_totem(PlayerbotAI* botAI) { return new CastNatureResistanceTotemAction(botAI); }
|
||||||
static Action* nature_resistance_totem(PlayerbotAI* ai) { return new CastNatureResistanceTotemAction(ai); }
|
static Action* set_strength_of_earth_totem(PlayerbotAI* botAI) { return new SetStrengthOfEarthTotemAction(botAI); }
|
||||||
static Action* set_strength_of_earth_totem(PlayerbotAI* ai) { return new SetStrengthOfEarthTotemAction(ai); }
|
static Action* set_stoneskin_totem(PlayerbotAI* botAI) { return new SetStoneskinTotemAction(botAI); }
|
||||||
static Action* set_stoneskin_totem(PlayerbotAI* ai) { return new SetStoneskinTotemAction(ai); }
|
static Action* set_tremor_totem(PlayerbotAI* botAI) { return new SetTremorTotemAction(botAI); }
|
||||||
static Action* set_tremor_totem(PlayerbotAI* ai) { return new SetTremorTotemAction(ai); }
|
static Action* set_earthbind_totem(PlayerbotAI* botAI) { return new SetEarthbindTotemAction(botAI); }
|
||||||
static Action* set_earthbind_totem(PlayerbotAI* ai) { return new SetEarthbindTotemAction(ai); }
|
static Action* set_searing_totem(PlayerbotAI* botAI) { return new SetSearingTotemAction(botAI); }
|
||||||
static Action* set_searing_totem(PlayerbotAI* ai) { return new SetSearingTotemAction(ai); }
|
static Action* set_magma_totem(PlayerbotAI* botAI) { return new SetMagmaTotemAction(botAI); }
|
||||||
static Action* set_magma_totem(PlayerbotAI* ai) { return new SetMagmaTotemAction(ai); }
|
static Action* set_flametongue_totem(PlayerbotAI* botAI) { return new SetFlametongueTotemAction(botAI); }
|
||||||
static Action* set_flametongue_totem(PlayerbotAI* ai) { return new SetFlametongueTotemAction(ai); }
|
static Action* set_totem_of_wrath(PlayerbotAI* botAI) { return new SetTotemOfWrathAction(botAI); }
|
||||||
static Action* set_totem_of_wrath(PlayerbotAI* ai) { return new SetTotemOfWrathAction(ai); }
|
static Action* set_frost_resistance_totem(PlayerbotAI* botAI) { return new SetFrostResistanceTotemAction(botAI); }
|
||||||
static Action* set_frost_resistance_totem(PlayerbotAI* ai) { return new SetFrostResistanceTotemAction(ai); }
|
static Action* set_healing_stream_totem(PlayerbotAI* botAI) { return new SetHealingStreamTotemAction(botAI); }
|
||||||
static Action* set_healing_stream_totem(PlayerbotAI* ai) { return new SetHealingStreamTotemAction(ai); }
|
static Action* set_mana_spring_totem(PlayerbotAI* botAI) { return new SetManaSpringTotemAction(botAI); }
|
||||||
static Action* set_mana_spring_totem(PlayerbotAI* ai) { return new SetManaSpringTotemAction(ai); }
|
static Action* set_cleansing_totem(PlayerbotAI* botAI) { return new SetCleansingTotemAction(botAI); }
|
||||||
static Action* set_cleansing_totem(PlayerbotAI* ai) { return new SetCleansingTotemAction(ai); }
|
static Action* set_fire_resistance_totem(PlayerbotAI* botAI) { return new SetFireResistanceTotemAction(botAI); }
|
||||||
static Action* set_fire_resistance_totem(PlayerbotAI* ai) { return new SetFireResistanceTotemAction(ai); }
|
static Action* set_wrath_of_air_totem(PlayerbotAI* botAI) { return new SetWrathOfAirTotemAction(botAI); }
|
||||||
static Action* set_wrath_of_air_totem(PlayerbotAI* ai) { return new SetWrathOfAirTotemAction(ai); }
|
static Action* set_windfury_totem(PlayerbotAI* botAI) { return new SetWindfuryTotemAction(botAI); }
|
||||||
static Action* set_windfury_totem(PlayerbotAI* ai) { return new SetWindfuryTotemAction(ai); }
|
static Action* set_nature_resistance_totem(PlayerbotAI* botAI) { return new SetNatureResistanceTotemAction(botAI); }
|
||||||
static Action* set_nature_resistance_totem(PlayerbotAI* ai) { return new SetNatureResistanceTotemAction(ai); }
|
static Action* set_grounding_totem(PlayerbotAI* botAI) { return new SetGroundingTotemAction(botAI); }
|
||||||
static Action* set_grounding_totem(PlayerbotAI* ai) { return new SetGroundingTotemAction(ai); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
SharedNamedObjectContextList<Strategy> ShamanAiObjectContext::sharedStrategyContexts;
|
SharedNamedObjectContextList<Strategy> ShamanAiObjectContext::sharedStrategyContexts;
|
||||||
|
|||||||
@ -4,42 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ElementalShamanStrategy.h"
|
#include "ElementalShamanStrategy.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
|
||||||
class ElementalShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ElementalShamanStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["flame shock"] = &flame_shock;
|
|
||||||
creators["earth shock"] = &earth_shock;
|
|
||||||
creators["lava burst"] = &lava_burst;
|
|
||||||
creators["lightning bolt"] = &lightning_bolt;
|
|
||||||
creators["call of the elements"] = &call_of_the_elements;
|
|
||||||
creators["elemental mastery"] = &elemental_mastery;
|
|
||||||
creators["stoneclaw totem"] = &stoneclaw_totem;
|
|
||||||
creators["water shield"] = &water_shield;
|
|
||||||
creators["thunderstorm"] = &thunderstorm;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", {}, {}, {}); }
|
|
||||||
static ActionNode* earth_shock(PlayerbotAI*) { return new ActionNode("earth shock", {}, {}, {}); }
|
|
||||||
static ActionNode* lava_burst(PlayerbotAI*) { return new ActionNode("lava burst", {}, {}, {}); }
|
|
||||||
static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", {}, {}, {}); }
|
|
||||||
static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", {}, {}, {}); }
|
|
||||||
static ActionNode* elemental_mastery(PlayerbotAI*) { return new ActionNode("elemental mastery", {}, {}, {}); }
|
|
||||||
static ActionNode* stoneclaw_totem(PlayerbotAI*) { return new ActionNode("stoneclaw totem", {}, {}, {}); }
|
|
||||||
static ActionNode* water_shield(PlayerbotAI*) { return new ActionNode("water shield", {}, {}, {}); }
|
|
||||||
static ActionNode* thunderstorm(PlayerbotAI*) { return new ActionNode("thunderstorm", {}, {}, {}); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
ElementalShamanStrategy::ElementalShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI)
|
ElementalShamanStrategy::ElementalShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new ElementalShamanStrategyActionNodeFactory());
|
// No custom ActionNodeFactory needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Default Actions =====
|
// ===== Default Actions =====
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "EnhancementShamanStrategy.h"
|
#include "EnhancementShamanStrategy.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
// ===== Action Node Factory =====
|
||||||
@ -13,19 +12,10 @@ class EnhancementShamanStrategyActionNodeFactory : public NamedObjectFactory<Act
|
|||||||
public:
|
public:
|
||||||
EnhancementShamanStrategyActionNodeFactory()
|
EnhancementShamanStrategyActionNodeFactory()
|
||||||
{
|
{
|
||||||
creators["stormstrike"] = &stormstrike;
|
|
||||||
creators["lava lash"] = &lava_lash;
|
creators["lava lash"] = &lava_lash;
|
||||||
creators["feral spirit"] = &feral_spirit;
|
|
||||||
creators["lightning bolt"] = &lightning_bolt;
|
|
||||||
creators["earth shock"] = &earth_shock;
|
|
||||||
creators["flame shock"] = &flame_shock;
|
|
||||||
creators["shamanistic rage"] = &shamanistic_rage;
|
|
||||||
creators["call of the elements"] = &call_of_the_elements;
|
|
||||||
creators["lightning shield"] = &lightning_shield;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ActionNode* stormstrike(PlayerbotAI*) { return new ActionNode("stormstrike", {}, {}, {}); }
|
|
||||||
static ActionNode* lava_lash([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* lava_lash([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode(
|
return new ActionNode(
|
||||||
@ -35,13 +25,6 @@ private:
|
|||||||
/*C*/ {}
|
/*C*/ {}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
static ActionNode* feral_spirit(PlayerbotAI*) { return new ActionNode("feral spirit", {}, {}, {}); }
|
|
||||||
static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", {}, {}, {}); }
|
|
||||||
static ActionNode* earth_shock(PlayerbotAI*) { return new ActionNode("earth shock", {}, {}, {}); }
|
|
||||||
static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", {}, {}, {}); }
|
|
||||||
static ActionNode* shamanistic_rage(PlayerbotAI*) { return new ActionNode("shamanistic rage", {}, {}, {}); }
|
|
||||||
static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", {}, {}, {}); }
|
|
||||||
static ActionNode* lightning_shield(PlayerbotAI*) { return new ActionNode("lightning shield", {}, {}, {}); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
// ===== Single Target Strategy =====
|
||||||
|
|||||||
@ -16,17 +16,13 @@ public:
|
|||||||
creators["totem of wrath"] = &totem_of_wrath;
|
creators["totem of wrath"] = &totem_of_wrath;
|
||||||
creators["flametongue totem"] = &flametongue_totem;
|
creators["flametongue totem"] = &flametongue_totem;
|
||||||
creators["magma totem"] = &magma_totem;
|
creators["magma totem"] = &magma_totem;
|
||||||
creators["searing totem"] = &searing_totem;
|
|
||||||
creators["strength of earth totem"] = &strength_of_earth_totem;
|
creators["strength of earth totem"] = &strength_of_earth_totem;
|
||||||
creators["stoneskin totem"] = &stoneskin_totem;
|
|
||||||
creators["cleansing totem"] = &cleansing_totem;
|
creators["cleansing totem"] = &cleansing_totem;
|
||||||
creators["mana spring totem"] = &mana_spring_totem;
|
|
||||||
creators["healing stream totem"] = &healing_stream_totem;
|
|
||||||
creators["wrath of air totem"] = &wrath_of_air_totem;
|
creators["wrath of air totem"] = &wrath_of_air_totem;
|
||||||
creators["windfury totem"] = &windfury_totem;
|
creators["windfury totem"] = &windfury_totem;
|
||||||
creators["grounding totem"] = &grounding_totem;
|
creators["cleanse spirit"] = &cleanse_spirit;
|
||||||
creators["wind shear"] = &wind_shear;
|
creators["cleanse spirit poison on party"] = &cleanse_spirit_poison_on_party;
|
||||||
creators["purge"] = &purge;
|
creators["cleanse spirit disease on party"] = &cleanse_spirit_disease_on_party;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -58,7 +54,6 @@ private:
|
|||||||
/*A*/ { NextAction("searing totem") },
|
/*A*/ { NextAction("searing totem") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* searing_totem(PlayerbotAI*) { return new ActionNode("searing totem", {}, {}, {}); }
|
|
||||||
static ActionNode* strength_of_earth_totem([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* strength_of_earth_totem([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("strength of earth totem",
|
return new ActionNode("strength of earth totem",
|
||||||
@ -66,7 +61,6 @@ private:
|
|||||||
/*A*/ { NextAction("stoneskin totem") },
|
/*A*/ { NextAction("stoneskin totem") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* stoneskin_totem(PlayerbotAI*) { return new ActionNode("stoneskin totem", {}, {}, {}); }
|
|
||||||
static ActionNode* cleansing_totem([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* cleansing_totem([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("cleansing totem",
|
return new ActionNode("cleansing totem",
|
||||||
@ -74,8 +68,6 @@ private:
|
|||||||
/*A*/ { NextAction("mana spring totem") },
|
/*A*/ { NextAction("mana spring totem") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* mana_spring_totem(PlayerbotAI*) { return new ActionNode("mana spring totem", {}, {}, {}); }
|
|
||||||
static ActionNode* healing_stream_totem(PlayerbotAI*) { return new ActionNode("healing stream totem", {}, {}, {}); }
|
|
||||||
static ActionNode* wrath_of_air_totem([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* wrath_of_air_totem([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("wrath of air totem",
|
return new ActionNode("wrath of air totem",
|
||||||
@ -90,9 +82,27 @@ private:
|
|||||||
/*A*/ { NextAction("grounding totem") },
|
/*A*/ { NextAction("grounding totem") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* grounding_totem(PlayerbotAI*) { return new ActionNode("grounding totem", {}, {}, {}); }
|
static ActionNode* cleanse_spirit([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
static ActionNode* wind_shear(PlayerbotAI*) { return new ActionNode("wind shear", {}, {}, {}); }
|
{
|
||||||
static ActionNode* purge(PlayerbotAI*) { return new ActionNode("purge", {}, {}, {}); }
|
return new ActionNode("cleanse spirit",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("cure toxins") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
|
static ActionNode* cleanse_spirit_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("cleanse spirit poison on party",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("cure toxins poison on party") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
|
static ActionNode* cleanse_spirit_disease_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("cleanse spirit disease on party",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("cure toxins disease on party") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GenericShamanStrategy::GenericShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
GenericShamanStrategy::GenericShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||||
@ -107,18 +117,13 @@ void GenericShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("wind shear", { NextAction("wind shear", 23.0f), }));
|
triggers.push_back(new TriggerNode("wind shear", { NextAction("wind shear", 23.0f), }));
|
||||||
triggers.push_back(new TriggerNode("wind shear on enemy healer", { NextAction("wind shear on enemy healer", 23.0f), }));
|
triggers.push_back(new TriggerNode("wind shear on enemy healer", { NextAction("wind shear on enemy healer", 23.0f), }));
|
||||||
triggers.push_back(new TriggerNode("purge", { NextAction("purge", ACTION_DISPEL), }));
|
triggers.push_back(new TriggerNode("purge", { NextAction("purge", ACTION_DISPEL), }));
|
||||||
triggers.push_back(new TriggerNode("medium mana", { NextAction("mana potion", ACTION_DISPEL), }));
|
|
||||||
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 65.0f), }));
|
triggers.push_back(new TriggerNode("new pet", { NextAction("set pet stance", 65.0f), }));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShamanCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void ShamanCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("cure poison", { NextAction("cure poison", 21.0f), }));
|
|
||||||
triggers.push_back(new TriggerNode("party member cure poison", { NextAction("cure poison on party", 21.0f), }));
|
|
||||||
triggers.push_back(new TriggerNode("cleanse spirit poison", { NextAction("cleanse spirit", 24.0f), }));
|
triggers.push_back(new TriggerNode("cleanse spirit poison", { NextAction("cleanse spirit", 24.0f), }));
|
||||||
triggers.push_back(new TriggerNode("party member cleanse spirit poison", { NextAction("cleanse spirit poison on party", 23.0f), }));
|
triggers.push_back(new TriggerNode("party member cleanse spirit poison", { NextAction("cleanse spirit poison on party", 23.0f), }));
|
||||||
triggers.push_back(new TriggerNode("cure disease", { NextAction("cure disease", 31.0f), }));
|
|
||||||
triggers.push_back(new TriggerNode("party member cure disease", { NextAction("cure disease on party", 30.0f), }));
|
|
||||||
triggers.push_back(new TriggerNode("cleanse spirit disease", { NextAction("cleanse spirit", 24.0f), }));
|
triggers.push_back(new TriggerNode("cleanse spirit disease", { NextAction("cleanse spirit", 24.0f), }));
|
||||||
triggers.push_back(new TriggerNode("party member cleanse spirit disease", { NextAction("cleanse spirit disease on party", 23.0f), }));
|
triggers.push_back(new TriggerNode("party member cleanse spirit disease", { NextAction("cleanse spirit disease on party", 23.0f), }));
|
||||||
triggers.push_back(new TriggerNode("cleanse spirit curse", { NextAction("cleanse spirit", 24.0f), }));
|
triggers.push_back(new TriggerNode("cleanse spirit curse", { NextAction("cleanse spirit", 24.0f), }));
|
||||||
@ -133,11 +138,11 @@ void ShamanBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
|
||||||
if (tab == 0) // Elemental
|
if (tab == SHAMAN_TAB_ELEMENTAL)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("fire elemental totem", { NextAction("fire elemental totem", 23.0f), }));
|
triggers.push_back(new TriggerNode("fire elemental totem", { NextAction("fire elemental totem", 23.0f), }));
|
||||||
}
|
}
|
||||||
else if (tab == 1) // Enhancement
|
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("fire elemental totem", { NextAction("fire elemental totem melee", 24.0f), }));
|
triggers.push_back(new TriggerNode("fire elemental totem", { NextAction("fire elemental totem melee", 24.0f), }));
|
||||||
}
|
}
|
||||||
@ -149,23 +154,19 @@ void ShamanAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
|
||||||
if (tab == 0) // Elemental
|
if (tab == SHAMAN_TAB_ELEMENTAL)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("medium aoe",{ NextAction("fire nova", 23.0f), }));
|
triggers.push_back(new TriggerNode("medium aoe",{ NextAction("fire nova", 23.0f), }));
|
||||||
triggers.push_back(new TriggerNode("chain lightning no cd", { NextAction("chain lightning", 5.6f), }));
|
triggers.push_back(new TriggerNode("chain lightning no cd", { NextAction("chain lightning", 5.6f), }));
|
||||||
}
|
}
|
||||||
else if (tab == 1) // Enhancement
|
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("medium aoe",{
|
triggers.push_back(new TriggerNode("medium aoe",{ NextAction("magma totem", 24.0f),
|
||||||
NextAction("magma totem", 24.0f),
|
NextAction("fire nova", 23.0f), }));
|
||||||
NextAction("fire nova", 23.0f), }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("maelstrom weapon 5 and medium aoe", { NextAction("chain lightning", 22.0f), }));
|
triggers.push_back(new TriggerNode("maelstrom weapon 5 and medium aoe", { NextAction("chain lightning", 22.0f), }));
|
||||||
triggers.push_back(new TriggerNode("maelstrom weapon 4 and medium aoe", { NextAction("chain lightning", 21.0f), }));
|
triggers.push_back(new TriggerNode("maelstrom weapon 4 and medium aoe", { NextAction("chain lightning", 21.0f), }));
|
||||||
triggers.push_back(new TriggerNode("enemy within melee", { NextAction("fire nova", 5.1f), }));
|
triggers.push_back(new TriggerNode("enemy within melee", { NextAction("fire nova", 5.1f), }));
|
||||||
}
|
}
|
||||||
else if (tab == 2) // Restoration
|
// Resto AoE handled by "Healer DPS" Strategy
|
||||||
{
|
|
||||||
// Handled by "Healer DPS" Strategy
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,64 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "RestoShamanStrategy.h"
|
#include "RestoShamanStrategy.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
// ===== Action Node Factory =====
|
|
||||||
class RestoShamanStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RestoShamanStrategyActionNodeFactory()
|
|
||||||
{
|
|
||||||
creators["mana tide totem"] = &mana_tide_totem;
|
|
||||||
creators["call of the elements"] = &call_of_the_elements;
|
|
||||||
creators["stoneclaw totem"] = &stoneclaw_totem;
|
|
||||||
creators["riptide on party"] = &riptide_on_party;
|
|
||||||
creators["chain heal on party"] = &chain_heal_on_party;
|
|
||||||
creators["healing wave on party"] = &healing_wave_on_party;
|
|
||||||
creators["lesser healing wave on party"] = &lesser_healing_wave_on_party;
|
|
||||||
creators["earth shield on main tank"] = &earth_shield_on_main_tank;
|
|
||||||
creators["cleanse spirit poison on party"] = &cleanse_spirit_poison_on_party;
|
|
||||||
creators["cleanse spirit disease on party"] = &cleanse_spirit_disease_on_party;
|
|
||||||
creators["cleanse spirit curse on party"] = &cleanse_spirit_curse_on_party;
|
|
||||||
creators["cleansing totem"] = &cleansing_totem;
|
|
||||||
creators["water shield"] = &water_shield;
|
|
||||||
creators["flame shock"] = &flame_shock;
|
|
||||||
creators["lava burst"] = &lava_burst;
|
|
||||||
creators["lightning bolt"] = &lightning_bolt;
|
|
||||||
creators["chain lightning"] = &chain_lightning;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static ActionNode* mana_tide_totem([[maybe_unused]] PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return new ActionNode("mana tide totem",
|
|
||||||
/*P*/ {},
|
|
||||||
/*A*/ { NextAction("mana potion") },
|
|
||||||
/*C*/ {});
|
|
||||||
}
|
|
||||||
static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", {}, {}, {}); }
|
|
||||||
static ActionNode* stoneclaw_totem(PlayerbotAI*) { return new ActionNode("stoneclaw totem", {}, {}, {}); }
|
|
||||||
static ActionNode* riptide_on_party(PlayerbotAI*) { return new ActionNode("riptide on party", {}, {}, {}); }
|
|
||||||
static ActionNode* chain_heal_on_party(PlayerbotAI*) { return new ActionNode("chain heal on party", {}, {}, {}); }
|
|
||||||
static ActionNode* healing_wave_on_party(PlayerbotAI*) { return new ActionNode("healing wave on party", {}, {}, {}); }
|
|
||||||
static ActionNode* lesser_healing_wave_on_party(PlayerbotAI*) { return new ActionNode("lesser healing wave on party", {}, {}, {}); }
|
|
||||||
static ActionNode* earth_shield_on_main_tank(PlayerbotAI*) { return new ActionNode("earth shield on main tank", {}, {}, {}); }
|
|
||||||
static ActionNode* cleanse_spirit_poison_on_party(PlayerbotAI*) { return new ActionNode("cleanse spirit poison on party", {}, {}, {}); }
|
|
||||||
static ActionNode* cleanse_spirit_disease_on_party(PlayerbotAI*) { return new ActionNode("cleanse spirit disease on party", {}, {}, {}); }
|
|
||||||
static ActionNode* cleanse_spirit_curse_on_party(PlayerbotAI*) { return new ActionNode("cleanse spirit curse on party", {}, {}, {}); }
|
|
||||||
static ActionNode* cleansing_totem(PlayerbotAI*) { return new ActionNode("cleansing totem", {}, {}, {}); }
|
|
||||||
static ActionNode* water_shield(PlayerbotAI*) { return new ActionNode("water shield", {}, {}, {}); }
|
|
||||||
static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", {}, {}, {}); }
|
|
||||||
static ActionNode* lava_burst(PlayerbotAI*) { return new ActionNode("lava burst", {}, {}, {}); }
|
|
||||||
static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", {}, {}, {}); }
|
|
||||||
static ActionNode* chain_lightning(PlayerbotAI*) { return new ActionNode("chain lightning", {}, {}, {}); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// ===== Single Target Strategy =====
|
|
||||||
RestoShamanStrategy::RestoShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI)
|
RestoShamanStrategy::RestoShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI)
|
||||||
{
|
{
|
||||||
actionNodeFactories.Add(new RestoShamanStrategyActionNodeFactory());
|
// No custom ActionNodeFactory needed
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Trigger Initialization ===
|
// ===== Trigger Initialization ===
|
||||||
@ -75,28 +22,23 @@ void RestoShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode("medium mana", { NextAction("mana tide totem", ACTION_HIGH + 5) }));
|
triggers.push_back(new TriggerNode("medium mana", { NextAction("mana tide totem", ACTION_HIGH + 5) }));
|
||||||
|
|
||||||
// Healing Triggers
|
// Healing Triggers
|
||||||
triggers.push_back(new TriggerNode("group heal setting", {
|
triggers.push_back(new TriggerNode("group heal setting", { NextAction("riptide on party", 27.0f),
|
||||||
NextAction("riptide on party", 27.0f),
|
NextAction("chain heal on party", 26.0f) }));
|
||||||
NextAction("chain heal on party", 26.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("party member critical health", {
|
triggers.push_back(new TriggerNode("party member critical health", { NextAction("riptide on party", 25.0f),
|
||||||
NextAction("riptide on party", 25.0f),
|
NextAction("healing wave on party", 24.0f),
|
||||||
NextAction("healing wave on party", 24.0f),
|
NextAction("lesser healing wave on party", 23.0f) }));
|
||||||
NextAction("lesser healing wave on party", 23.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("party member low health", {
|
triggers.push_back(new TriggerNode("party member low health", { NextAction("riptide on party", 19.0f),
|
||||||
NextAction("riptide on party", 19.0f),
|
NextAction("healing wave on party", 18.0f),
|
||||||
NextAction("healing wave on party", 18.0f),
|
NextAction("lesser healing wave on party", 17.0f) }));
|
||||||
NextAction("lesser healing wave on party", 17.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("party member medium health", {
|
triggers.push_back(new TriggerNode("party member medium health", { NextAction("riptide on party", 16.0f),
|
||||||
NextAction("riptide on party", 16.0f),
|
NextAction("healing wave on party", 15.0f),
|
||||||
NextAction("healing wave on party", 15.0f),
|
NextAction("lesser healing wave on party", 14.0f) }));
|
||||||
NextAction("lesser healing wave on party", 14.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("party member almost full health", {
|
triggers.push_back(new TriggerNode("party member almost full health", { NextAction("riptide on party", 12.0f),
|
||||||
NextAction("riptide on party", 12.0f),
|
NextAction("lesser healing wave on party", 11.0f) }));
|
||||||
NextAction("lesser healing wave on party", 11.0f) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("earth shield on main tank", { NextAction("earth shield on main tank", ACTION_HIGH + 7) }));
|
triggers.push_back(new TriggerNode("earth shield on main tank", { NextAction("earth shield on main tank", ACTION_HIGH + 7) }));
|
||||||
|
|
||||||
@ -113,12 +55,9 @@ void RestoShamanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
|
|
||||||
void ShamanHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void ShamanHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("healer should attack",
|
triggers.push_back(new TriggerNode("healer should attack", { NextAction("flame shock", ACTION_DEFAULT + 0.2f),
|
||||||
{ NextAction("flame shock", ACTION_DEFAULT + 0.2f),
|
NextAction("lava burst", ACTION_DEFAULT + 0.1f),
|
||||||
NextAction("lava burst", ACTION_DEFAULT + 0.1f),
|
NextAction("lightning bolt", ACTION_DEFAULT) }));
|
||||||
NextAction("lightning bolt", ACTION_DEFAULT) }));
|
|
||||||
|
|
||||||
triggers.push_back(
|
triggers.push_back( new TriggerNode("medium aoe and healer should attack", { NextAction("chain lightning", ACTION_DEFAULT + 0.3f) }));
|
||||||
new TriggerNode("medium aoe and healer should attack",
|
|
||||||
{ NextAction("chain lightning", ACTION_DEFAULT + 0.3f) }));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,45 +13,65 @@ class ShamanNonCombatStrategyActionNodeFactory : public NamedObjectFactory<Actio
|
|||||||
public:
|
public:
|
||||||
ShamanNonCombatStrategyActionNodeFactory()
|
ShamanNonCombatStrategyActionNodeFactory()
|
||||||
{
|
{
|
||||||
creators["flametongue weapon"] = &flametongue_weapon;
|
creators["flametongue weapon main hand"] = &flametongue_weapon_main_hand;
|
||||||
creators["frostbrand weapon"] = &frostbrand_weapon;
|
// creators["frostbrand weapon off hand"] = &frostbrand_weapon_off_hand;
|
||||||
creators["windfury weapon"] = &windfury_weapon;
|
creators["windfury weapon main hand"] = &windfury_weapon_main_hand;
|
||||||
creators["earthliving weapon"] = &earthliving_weapon;
|
creators["earthliving weapon main hand"] = &earthliving_weapon_main_hand;
|
||||||
creators["wind shear"] = &wind_shear;
|
creators["cleanse spirit"] = &cleanse_spirit;
|
||||||
creators["purge"] = &purge;
|
creators["cleanse spirit poison on party"] = &cleanse_spirit_poison_on_party;
|
||||||
|
creators["cleanse spirit disease on party"] = &cleanse_spirit_disease_on_party;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static ActionNode* flametongue_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* flametongue_weapon_main_hand([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("flametongue weapon",
|
return new ActionNode("flametongue weapon main hand",
|
||||||
/*P*/ {},
|
/*P*/ {},
|
||||||
/*A*/ { NextAction("rockbiter weapon") },
|
/*A*/ { NextAction("rockbiter weapon main hand") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* frostbrand_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
// static ActionNode* frostbrand_weapon_off_hand([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
// {
|
||||||
|
// return new ActionNode("frostbrand weapon off hand",
|
||||||
|
// /*P*/ {},
|
||||||
|
// /*A*/ { NextAction("flametongue weapon off hand") },
|
||||||
|
// /*C*/ {});
|
||||||
|
// }
|
||||||
|
static ActionNode* earthliving_weapon_main_hand([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("frostbrand weapon",
|
return new ActionNode("earthliving weapon main hand",
|
||||||
/*P*/ {},
|
/*P*/ {},
|
||||||
/*A*/ { NextAction("flametongue weapon") },
|
/*A*/ { NextAction("flametongue weapon main hand") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* windfury_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* windfury_weapon_main_hand([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("windfury weapon",
|
return new ActionNode("windfury weapon main hand",
|
||||||
/*P*/ {},
|
/*P*/ {},
|
||||||
/*A*/ { NextAction("flametongue weapon") },
|
/*A*/ { NextAction("flametongue weapon main hand") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* earthliving_weapon([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* cleanse_spirit([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode("earthliving weapon",
|
return new ActionNode("cleanse spirit",
|
||||||
/*P*/ {},
|
/*P*/ {},
|
||||||
/*A*/ { NextAction("flametongue weapon") },
|
/*A*/ { NextAction("cure toxins") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
|
static ActionNode* cleanse_spirit_poison_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("cleanse spirit poison on party",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("cure toxins poison on party") },
|
||||||
|
/*C*/ {});
|
||||||
|
}
|
||||||
|
static ActionNode* cleanse_spirit_disease_on_party([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode("cleanse spirit disease on party",
|
||||||
|
/*P*/ {},
|
||||||
|
/*A*/ { NextAction("cure toxins disease on party") },
|
||||||
/*C*/ {});
|
/*C*/ {});
|
||||||
}
|
}
|
||||||
static ActionNode* wind_shear(PlayerbotAI*) { return new ActionNode("wind shear", {}, {}, {}); }
|
|
||||||
static ActionNode* purge(PlayerbotAI*) { return new ActionNode("purge", {}, {}, {}); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ShamanNonCombatStrategy::ShamanNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
ShamanNonCombatStrategy::ShamanNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||||
@ -64,48 +84,46 @@ void ShamanNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
NonCombatStrategy::InitTriggers(triggers);
|
NonCombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
// Totemic Recall
|
// Totemic Recall
|
||||||
triggers.push_back(new TriggerNode("totemic recall", { NextAction("totemic recall", 60.0f), }));
|
triggers.push_back(new TriggerNode("totemic recall", { NextAction("totemic recall", 60.0f) }));
|
||||||
|
|
||||||
// Healing/Resurrect Triggers
|
// Healing/Resurrect Triggers
|
||||||
triggers.push_back(new TriggerNode("party member dead", { NextAction("ancestral spirit", ACTION_CRITICAL_HEAL + 10), }));
|
triggers.push_back(new TriggerNode("party member dead", { NextAction("ancestral spirit", ACTION_CRITICAL_HEAL + 10) }));
|
||||||
triggers.push_back(new TriggerNode("party member critical health", {
|
triggers.push_back(new TriggerNode("party member critical health", { NextAction("riptide on party", 31.0f),
|
||||||
NextAction("riptide on party", 31.0f),
|
NextAction("healing wave on party", 30.0f) }));
|
||||||
NextAction("healing wave on party", 30.0f) }));
|
triggers.push_back(new TriggerNode("party member low health", { NextAction("riptide on party", 29.0f),
|
||||||
triggers.push_back(new TriggerNode("party member low health",{
|
NextAction("healing wave on party", 28.0f) }));
|
||||||
NextAction("riptide on party", 29.0f),
|
triggers.push_back(new TriggerNode("party member medium health", { NextAction("riptide on party", 27.0f),
|
||||||
NextAction("healing wave on party", 28.0f) }));
|
NextAction("healing wave on party", 26.0f) }));
|
||||||
triggers.push_back(new TriggerNode("party member medium health",{
|
triggers.push_back(new TriggerNode("party member almost full health", { NextAction("riptide on party", 25.0f),
|
||||||
NextAction("riptide on party", 27.0f),
|
NextAction("lesser healing wave on party", 24.0f) }));
|
||||||
NextAction("healing wave on party", 26.0f) }));
|
triggers.push_back(new TriggerNode("group heal setting", { NextAction("chain heal on party", 27.0f) }));
|
||||||
triggers.push_back(new TriggerNode("party member almost full health",{
|
|
||||||
NextAction("riptide on party", 25.0f),
|
|
||||||
NextAction("lesser healing wave on party", 24.0f) }));
|
|
||||||
triggers.push_back(new TriggerNode("group heal setting",{ NextAction("chain heal on party", 27.0f) }));
|
|
||||||
|
|
||||||
// Cure Triggers
|
// Cure Triggers
|
||||||
triggers.push_back(new TriggerNode("cure poison", { NextAction("cure poison", 21.0f), }));
|
triggers.push_back(new TriggerNode("cleanse spirit poison", { NextAction("cleanse spirit", 24.0f) }));
|
||||||
triggers.push_back(new TriggerNode("party member cure poison", { NextAction("cure poison on party", 21.0f), }));
|
triggers.push_back(new TriggerNode("party member cleanse spirit poison", { NextAction("cleanse spirit poison on party", 23.0f) }));
|
||||||
triggers.push_back(new TriggerNode("cure disease", { NextAction("cure disease", 31.0f), }));
|
triggers.push_back(new TriggerNode("cleanse spirit disease", { NextAction("cleanse spirit", 24.0f) }));
|
||||||
triggers.push_back(new TriggerNode("party member cure disease", { NextAction("cure disease on party", 30.0f), }));
|
triggers.push_back(new TriggerNode("party member cleanse spirit disease", { NextAction("cleanse spirit disease on party", 23.0f) }));
|
||||||
|
triggers.push_back(new TriggerNode("cleanse spirit curse", { NextAction("cleanse spirit", 24.0f) }));
|
||||||
|
triggers.push_back(new TriggerNode("party member cleanse spirit curse", { NextAction("cleanse spirit curse on party", 23.0f) }));
|
||||||
|
|
||||||
// Out of Combat Buff Triggers
|
// Out of Combat Buff Triggers
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||||
|
|
||||||
if (tab == 0) // Elemental
|
if (tab == SHAMAN_TAB_ELEMENTAL)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("flametongue weapon", 22.0f), }));
|
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("flametongue weapon main hand", 22.0f), }));
|
||||||
triggers.push_back(new TriggerNode("water shield", { NextAction("water shield", 21.0f), }));
|
triggers.push_back(new TriggerNode("water shield", { NextAction("water shield", 21.0f), }));
|
||||||
}
|
}
|
||||||
else if (tab == 1) // Enhancement
|
else if (tab == SHAMAN_TAB_ENHANCEMENT)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("windfury weapon", 22.0f), }));
|
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("windfury weapon main hand", 22.0f), }));
|
||||||
triggers.push_back(new TriggerNode("off hand weapon no imbue", { NextAction("flametongue weapon", 21.0f), }));
|
triggers.push_back(new TriggerNode("off hand weapon no imbue", { NextAction("flametongue weapon off hand", 21.0f), }));
|
||||||
triggers.push_back(new TriggerNode("lightning shield", { NextAction("lightning shield", 20.0f), }));
|
triggers.push_back(new TriggerNode("lightning shield", { NextAction("lightning shield", 20.0f), }));
|
||||||
}
|
}
|
||||||
else if (tab == 2) // Restoration
|
else if (tab == SHAMAN_TAB_RESTORATION)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("main hand weapon no imbue",{ NextAction("earthliving weapon", 22.0f), }));
|
triggers.push_back(new TriggerNode("main hand weapon no imbue", { NextAction("earthliving weapon main hand", 22.0f), }));
|
||||||
triggers.push_back(new TriggerNode("water shield", { NextAction("water shield", 20.0f), }));
|
triggers.push_back(new TriggerNode("water shield", { NextAction("water shield", 20.0f), }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,13 +75,9 @@ void TotemOfWrathStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// If the bot hasn't learned Totem of Wrath yet, set Flametongue Totem instead.
|
// If the bot hasn't learned Totem of Wrath yet, set Flametongue Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(30706))
|
if (bot->HasSpell(30706))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set totem of wrath", { NextAction("set totem of wrath", 60.0f) }));
|
triggers.push_back(new TriggerNode("set totem of wrath", { NextAction("set totem of wrath", 60.0f) }));
|
||||||
}
|
|
||||||
else if (bot->HasSpell(8227))
|
else if (bot->HasSpell(8227))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set flametongue totem", { NextAction("set flametongue totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set flametongue totem", { NextAction("set flametongue totem", 60.0f) }));
|
||||||
}
|
|
||||||
triggers.push_back(new TriggerNode("no fire totem", { NextAction("totem of wrath", 55.0f) }));
|
triggers.push_back(new TriggerNode("no fire totem", { NextAction("totem of wrath", 55.0f) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,13 +113,9 @@ void CleansingTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// If the bot hasn't learned Cleansing Totem yet, set Mana Spring Totem instead.
|
// If the bot hasn't learned Cleansing Totem yet, set Mana Spring Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(8170))
|
if (bot->HasSpell(8170))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set cleansing totem", { NextAction("set cleansing totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set cleansing totem", { NextAction("set cleansing totem", 60.0f) }));
|
||||||
}
|
|
||||||
else if (bot->HasSpell(5675))
|
else if (bot->HasSpell(5675))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set mana spring totem", { NextAction("set mana spring totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set mana spring totem", { NextAction("set mana spring totem", 60.0f) }));
|
||||||
}
|
|
||||||
triggers.push_back(new TriggerNode("no water totem", { NextAction("cleansing totem", 55.0f) }));
|
triggers.push_back(new TriggerNode("no water totem", { NextAction("cleansing totem", 55.0f) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,15 +135,10 @@ void WrathOfAirTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// If the bot hasn't learned Wrath of Air Totem yet, set Grounding Totem instead.
|
// If the bot hasn't learned Wrath of Air Totem yet, set Grounding Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(3738))
|
if (bot->HasSpell(3738))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set wrath of air totem", { NextAction("set wrath of air totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set wrath of air totem", { NextAction("set wrath of air totem", 60.0f) }));
|
||||||
}
|
|
||||||
else if (bot->HasSpell(8177))
|
else if (bot->HasSpell(8177))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
||||||
}
|
triggers.push_back( new TriggerNode("no air totem", { NextAction("wrath of air totem", 55.0f) }));
|
||||||
triggers.push_back(
|
|
||||||
new TriggerNode("no air totem", { NextAction("wrath of air totem", 55.0f) }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WindfuryTotemStrategy::WindfuryTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {}
|
WindfuryTotemStrategy::WindfuryTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {}
|
||||||
@ -161,13 +148,9 @@ void WindfuryTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
// If the bot hasn't learned Windfury Totem yet, set Grounding Totem instead.
|
// If the bot hasn't learned Windfury Totem yet, set Grounding Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(8512))
|
if (bot->HasSpell(8512))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set windfury totem", { NextAction("set windfury totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set windfury totem", { NextAction("set windfury totem", 60.0f) }));
|
||||||
}
|
|
||||||
else if (bot->HasSpell(8177))
|
else if (bot->HasSpell(8177))
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
||||||
}
|
|
||||||
triggers.push_back(new TriggerNode("no air totem", { NextAction("windfury totem", 55.0f) }));
|
triggers.push_back(new TriggerNode("no air totem", { NextAction("windfury totem", 55.0f) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -261,13 +261,13 @@ bool TotemicRecallTrigger::IsActive()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the active totem strategy for this slot, and return the highest-rank spellId the bot knows for it
|
// Find the active totem strategy for this slot, and return the highest-rank spellId the bot knows for it
|
||||||
static uint32 GetRequiredTotemSpellId(PlayerbotAI* ai, const char* strategies[],
|
static uint32 GetRequiredTotemSpellId(PlayerbotAI* botAI, const char* strategies[],
|
||||||
const uint32* spellList[], const size_t spellCounts[], size_t numStrategies)
|
const uint32* spellList[], const size_t spellCounts[], size_t numStrategies)
|
||||||
{
|
{
|
||||||
Player* bot = ai->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
for (size_t i = 0; i < numStrategies; ++i)
|
for (size_t i = 0; i < numStrategies; ++i)
|
||||||
{
|
{
|
||||||
if (ai->HasStrategy(strategies[i], BOT_STATE_COMBAT))
|
if (botAI->HasStrategy(strategies[i], BOT_STATE_COMBAT))
|
||||||
{
|
{
|
||||||
// Find the highest-rank spell the bot knows
|
// Find the highest-rank spell the bot knows
|
||||||
for (size_t j = 0; j < spellCounts[i]; ++j)
|
for (size_t j = 0; j < spellCounts[i]; ++j)
|
||||||
|
|||||||
@ -41,14 +41,14 @@ const uint32 SPELL_CALL_OF_THE_ELEMENTS = 66842;
|
|||||||
class MainHandWeaponNoImbueTrigger : public BuffTrigger
|
class MainHandWeaponNoImbueTrigger : public BuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MainHandWeaponNoImbueTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "main hand", 1) {}
|
MainHandWeaponNoImbueTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "main hand", 1) {}
|
||||||
virtual bool IsActive();
|
virtual bool IsActive();
|
||||||
};
|
};
|
||||||
|
|
||||||
class OffHandWeaponNoImbueTrigger : public BuffTrigger
|
class OffHandWeaponNoImbueTrigger : public BuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OffHandWeaponNoImbueTrigger(PlayerbotAI* ai) : BuffTrigger(ai, "off hand", 1) {}
|
OffHandWeaponNoImbueTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "off hand", 1) {}
|
||||||
virtual bool IsActive();
|
virtual bool IsActive();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ public:
|
|||||||
class SpiritWalkTrigger : public Trigger
|
class SpiritWalkTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SpiritWalkTrigger(PlayerbotAI* ai) : Trigger(ai, "spirit walk ready") {}
|
SpiritWalkTrigger(PlayerbotAI* botAI) : Trigger(botAI, "spirit walk ready") {}
|
||||||
|
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
|
|
||||||
@ -165,9 +165,7 @@ class PartyMemberCleanseSpiritPoisonTrigger : public PartyMemberNeedCureTrigger
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PartyMemberCleanseSpiritPoisonTrigger(PlayerbotAI* botAI)
|
PartyMemberCleanseSpiritPoisonTrigger(PlayerbotAI* botAI)
|
||||||
: PartyMemberNeedCureTrigger(botAI, "cleanse spirit", DISPEL_POISON)
|
: PartyMemberNeedCureTrigger(botAI, "cleanse spirit", DISPEL_POISON) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CleanseSpiritCurseTrigger : public NeedCureTrigger
|
class CleanseSpiritCurseTrigger : public NeedCureTrigger
|
||||||
@ -180,9 +178,7 @@ class PartyMemberCleanseSpiritCurseTrigger : public PartyMemberNeedCureTrigger
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PartyMemberCleanseSpiritCurseTrigger(PlayerbotAI* botAI)
|
PartyMemberCleanseSpiritCurseTrigger(PlayerbotAI* botAI)
|
||||||
: PartyMemberNeedCureTrigger(botAI, "cleanse spirit", DISPEL_CURSE)
|
: PartyMemberNeedCureTrigger(botAI, "cleanse spirit", DISPEL_CURSE) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CleanseSpiritDiseaseTrigger : public NeedCureTrigger
|
class CleanseSpiritDiseaseTrigger : public NeedCureTrigger
|
||||||
@ -195,34 +191,7 @@ class PartyMemberCleanseSpiritDiseaseTrigger : public PartyMemberNeedCureTrigger
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PartyMemberCleanseSpiritDiseaseTrigger(PlayerbotAI* botAI)
|
PartyMemberCleanseSpiritDiseaseTrigger(PlayerbotAI* botAI)
|
||||||
: PartyMemberNeedCureTrigger(botAI, "cleanse spirit", DISPEL_DISEASE)
|
: PartyMemberNeedCureTrigger(botAI, "cleanse spirit", DISPEL_DISEASE) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CurePoisonTrigger : public NeedCureTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CurePoisonTrigger(PlayerbotAI* botAI) : NeedCureTrigger(botAI, "cure poison", DISPEL_POISON) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PartyMemberCurePoisonTrigger : public PartyMemberNeedCureTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PartyMemberCurePoisonTrigger(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, "cure poison", DISPEL_POISON) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CureDiseaseTrigger : public NeedCureTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CureDiseaseTrigger(PlayerbotAI* botAI) : NeedCureTrigger(botAI, "cure disease", DISPEL_DISEASE) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class PartyMemberCureDiseaseTrigger : public PartyMemberNeedCureTrigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PartyMemberCureDiseaseTrigger(PlayerbotAI* botAI)
|
|
||||||
: PartyMemberNeedCureTrigger(botAI, "cure disease", DISPEL_DISEASE) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Damage and Debuff Triggers
|
// Damage and Debuff Triggers
|
||||||
@ -250,7 +219,7 @@ public:
|
|||||||
class FlameShockTrigger : public DebuffTrigger
|
class FlameShockTrigger : public DebuffTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FlameShockTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "flame shock", 1, true, 6.0f) {}
|
FlameShockTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "flame shock", 1, true, 6.0f) {}
|
||||||
bool IsActive() override { return BuffTrigger::IsActive(); }
|
bool IsActive() override { return BuffTrigger::IsActive(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -265,19 +234,19 @@ public:
|
|||||||
class MaelstromWeapon5AndMediumAoeTrigger : public TwoTriggers
|
class MaelstromWeapon5AndMediumAoeTrigger : public TwoTriggers
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MaelstromWeapon5AndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "maelstrom weapon 5", "medium aoe") {}
|
MaelstromWeapon5AndMediumAoeTrigger(PlayerbotAI* botAI) : TwoTriggers(botAI, "maelstrom weapon 5", "medium aoe") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MaelstromWeapon4AndMediumAoeTrigger : public TwoTriggers
|
class MaelstromWeapon4AndMediumAoeTrigger : public TwoTriggers
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MaelstromWeapon4AndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "maelstrom weapon 4", "medium aoe") {}
|
MaelstromWeapon4AndMediumAoeTrigger(PlayerbotAI* botAI) : TwoTriggers(botAI, "maelstrom weapon 4", "medium aoe") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChainLightningNoCdTrigger : public SpellNoCooldownTrigger
|
class ChainLightningNoCdTrigger : public SpellNoCooldownTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ChainLightningNoCdTrigger(PlayerbotAI* ai) : SpellNoCooldownTrigger(ai, "chain lightning") {}
|
ChainLightningNoCdTrigger(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, "chain lightning") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Healing Triggers
|
// Healing Triggers
|
||||||
@ -307,49 +276,49 @@ protected:
|
|||||||
class CallOfTheElementsTrigger : public Trigger
|
class CallOfTheElementsTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CallOfTheElementsTrigger(PlayerbotAI* ai) : Trigger(ai, "call of the elements") {}
|
CallOfTheElementsTrigger(PlayerbotAI* botAI) : Trigger(botAI, "call of the elements") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TotemicRecallTrigger : public Trigger
|
class TotemicRecallTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TotemicRecallTrigger(PlayerbotAI* ai) : Trigger(ai, "totemic recall") {}
|
TotemicRecallTrigger(PlayerbotAI* botAI) : Trigger(botAI, "totemic recall") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoEarthTotemTrigger : public Trigger
|
class NoEarthTotemTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NoEarthTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no earth totem") {}
|
NoEarthTotemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no earth totem") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoFireTotemTrigger : public Trigger
|
class NoFireTotemTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NoFireTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no fire totem") {}
|
NoFireTotemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no fire totem") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoWaterTotemTrigger : public Trigger
|
class NoWaterTotemTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NoWaterTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no water totem") {}
|
NoWaterTotemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no water totem") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoAirTotemTrigger : public Trigger
|
class NoAirTotemTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NoAirTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no air totem") {}
|
NoAirTotemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no air totem") {}
|
||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CallOfTheElementsAndEnemyWithinMeleeTrigger : public TwoTriggers
|
class CallOfTheElementsAndEnemyWithinMeleeTrigger : public TwoTriggers
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CallOfTheElementsAndEnemyWithinMeleeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "call of the elements", "enemy within melee") {}
|
CallOfTheElementsAndEnemyWithinMeleeTrigger(PlayerbotAI* botAI) : TwoTriggers(botAI, "call of the elements", "enemy within melee") {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set Strategy Assigned Totems
|
// Set Strategy Assigned Totems
|
||||||
@ -359,8 +328,8 @@ class SetTotemTrigger : public Trigger
|
|||||||
public:
|
public:
|
||||||
// Template constructor: infers N (size of the id array) at compile time
|
// Template constructor: infers N (size of the id array) at compile time
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
SetTotemTrigger(PlayerbotAI* ai, std::string const& spellName, const uint32 (&ids)[N], int actionButtonId)
|
SetTotemTrigger(PlayerbotAI* botAI, std::string const& spellName, const uint32 (&ids)[N], int actionButtonId)
|
||||||
: Trigger(ai, "set " + spellName)
|
: Trigger(botAI, "set " + spellName)
|
||||||
, totemSpellIds(ids)
|
, totemSpellIds(ids)
|
||||||
, totemSpellIdsCount(N)
|
, totemSpellIdsCount(N)
|
||||||
, actionButtonId(actionButtonId)
|
, actionButtonId(actionButtonId)
|
||||||
@ -376,120 +345,120 @@ private:
|
|||||||
class SetStrengthOfEarthTotemTrigger : public SetTotemTrigger
|
class SetStrengthOfEarthTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStrengthOfEarthTotemTrigger(PlayerbotAI* ai)
|
SetStrengthOfEarthTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "strength of earth totem", STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(botAI, "strength of earth totem", STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetStoneskinTotemTrigger : public SetTotemTrigger
|
class SetStoneskinTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStoneskinTotemTrigger(PlayerbotAI* ai)
|
SetStoneskinTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "stoneskin totem", STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(botAI, "stoneskin totem", STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTremorTotemTrigger : public SetTotemTrigger
|
class SetTremorTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetTremorTotemTrigger(PlayerbotAI* ai)
|
SetTremorTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "tremor totem", TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(botAI, "tremor totem", TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetEarthbindTotemTrigger : public SetTotemTrigger
|
class SetEarthbindTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetEarthbindTotemTrigger(PlayerbotAI* ai)
|
SetEarthbindTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "earthbind totem", EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(botAI, "earthbind totem", EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetSearingTotemTrigger : public SetTotemTrigger
|
class SetSearingTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetSearingTotemTrigger(PlayerbotAI* ai)
|
SetSearingTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "searing totem", SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(botAI, "searing totem", SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetMagmaTotemTrigger : public SetTotemTrigger
|
class SetMagmaTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetMagmaTotemTrigger(PlayerbotAI* ai)
|
SetMagmaTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "magma totem", MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(botAI, "magma totem", MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFlametongueTotemTrigger : public SetTotemTrigger
|
class SetFlametongueTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFlametongueTotemTrigger(PlayerbotAI* ai)
|
SetFlametongueTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "flametongue totem", FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(botAI, "flametongue totem", FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTotemOfWrathTrigger : public SetTotemTrigger
|
class SetTotemOfWrathTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetTotemOfWrathTrigger(PlayerbotAI* ai)
|
SetTotemOfWrathTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "totem of wrath", TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(botAI, "totem of wrath", TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFrostResistanceTotemTrigger : public SetTotemTrigger
|
class SetFrostResistanceTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFrostResistanceTotemTrigger(PlayerbotAI* ai)
|
SetFrostResistanceTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "frost resistance totem", FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(botAI, "frost resistance totem", FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetHealingStreamTotemTrigger : public SetTotemTrigger
|
class SetHealingStreamTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetHealingStreamTotemTrigger(PlayerbotAI* ai)
|
SetHealingStreamTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "healing stream totem", HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(botAI, "healing stream totem", HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetManaSpringTotemTrigger : public SetTotemTrigger
|
class SetManaSpringTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetManaSpringTotemTrigger(PlayerbotAI* ai)
|
SetManaSpringTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "mana spring totem", MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(botAI, "mana spring totem", MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetCleansingTotemTrigger : public SetTotemTrigger
|
class SetCleansingTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetCleansingTotemTrigger(PlayerbotAI* ai)
|
SetCleansingTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "cleansing totem", CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(botAI, "cleansing totem", CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFireResistanceTotemTrigger : public SetTotemTrigger
|
class SetFireResistanceTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFireResistanceTotemTrigger(PlayerbotAI* ai)
|
SetFireResistanceTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "fire resistance totem", FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(botAI, "fire resistance totem", FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetWrathOfAirTotemTrigger : public SetTotemTrigger
|
class SetWrathOfAirTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetWrathOfAirTotemTrigger(PlayerbotAI* ai)
|
SetWrathOfAirTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "wrath of air totem", WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(botAI, "wrath of air totem", WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetWindfuryTotemTrigger : public SetTotemTrigger
|
class SetWindfuryTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetWindfuryTotemTrigger(PlayerbotAI* ai)
|
SetWindfuryTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "windfury totem", WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(botAI, "windfury totem", WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetNatureResistanceTotemTrigger : public SetTotemTrigger
|
class SetNatureResistanceTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetNatureResistanceTotemTrigger(PlayerbotAI* ai)
|
SetNatureResistanceTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "nature resistance totem", NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(botAI, "nature resistance totem", NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetGroundingTotemTrigger : public SetTotemTrigger
|
class SetGroundingTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetGroundingTotemTrigger(PlayerbotAI* ai)
|
SetGroundingTotemTrigger(PlayerbotAI* botAI)
|
||||||
: SetTotemTrigger(ai, "grounding totem", GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(botAI, "grounding totem", GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -7,6 +7,33 @@
|
|||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
bool CastBerserkerRageAction::isPossible()
|
||||||
|
{
|
||||||
|
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
|
||||||
|
if (!spellId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!bot->HasSpell(spellId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (bot->HasSpellCooldown(spellId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CastBerserkerRageAction::isUseful()
|
||||||
|
{
|
||||||
|
return (bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
||||||
|
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP) ||
|
||||||
|
bot->HasAuraWithMechanic(1 << MECHANIC_SAPPED))
|
||||||
|
&& !botAI->HasAura("berserker rage", bot)
|
||||||
|
&& CastSpellAction::isUseful();
|
||||||
|
}
|
||||||
|
|
||||||
bool CastSunderArmorAction::isUseful()
|
bool CastSunderArmorAction::isUseful()
|
||||||
{
|
{
|
||||||
Aura* aura = botAI->GetAura("sunder armor", GetTarget(), false, true);
|
Aura* aura = botAI->GetAura("sunder armor", GetTarget(), false, true);
|
||||||
|
|||||||
@ -78,7 +78,15 @@ REACH_ACTION(CastInterceptAction, "intercept", 8.0f);
|
|||||||
ENEMY_HEALER_ACTION(CastInterceptOnEnemyHealerAction, "intercept");
|
ENEMY_HEALER_ACTION(CastInterceptOnEnemyHealerAction, "intercept");
|
||||||
SNARE_ACTION(CastInterceptOnSnareTargetAction, "intercept");
|
SNARE_ACTION(CastInterceptOnSnareTargetAction, "intercept");
|
||||||
MELEE_ACTION(CastSlamAction, "slam");
|
MELEE_ACTION(CastSlamAction, "slam");
|
||||||
BUFF_ACTION(CastBerserkerRageAction, "berserker rage");
|
class CastBerserkerRageAction : public CastSpellAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastBerserkerRageAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "berserker rage") {}
|
||||||
|
|
||||||
|
std::string const GetTargetName() override { return "self target"; }
|
||||||
|
bool isPossible() override;
|
||||||
|
bool isUseful() override;
|
||||||
|
};
|
||||||
MELEE_ACTION(CastWhirlwindAction, "whirlwind");
|
MELEE_ACTION(CastWhirlwindAction, "whirlwind");
|
||||||
MELEE_ACTION(CastPummelAction, "pummel");
|
MELEE_ACTION(CastPummelAction, "pummel");
|
||||||
ENEMY_HEALER_ACTION(CastPummelOnEnemyHealerAction, "pummel");
|
ENEMY_HEALER_ACTION(CastPummelOnEnemyHealerAction, "pummel");
|
||||||
|
|||||||
@ -7,9 +7,33 @@
|
|||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
class GenericWarriorNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericWarriorNonCombatStrategyActionNodeFactory() { creators["berserker rage"] = &berserker_rage; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ActionNode* berserker_rage([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode(
|
||||||
|
"berserker rage",
|
||||||
|
/*P*/ { NextAction("berserker stance") },
|
||||||
|
/*A*/ {},
|
||||||
|
/*C*/ {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericWarriorNonCombatStrategy::GenericWarriorNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI)
|
||||||
|
{
|
||||||
|
actionNodeFactories.Add(new GenericWarriorNonCombatStrategyActionNodeFactory());
|
||||||
|
}
|
||||||
|
|
||||||
void GenericWarriorNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void GenericWarriorNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
NonCombatStrategy::InitTriggers(triggers);
|
NonCombatStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("often", { NextAction("apply stone", 1.0f) }));
|
triggers.push_back(new TriggerNode("often", { NextAction("apply stone", 1.0f) }));
|
||||||
|
triggers.push_back(new TriggerNode(
|
||||||
|
"fear sleep sap", { NextAction("berserker rage", ACTION_EMERGENCY + 1) }));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ class PlayerbotAI;
|
|||||||
class GenericWarriorNonCombatStrategy : public NonCombatStrategy
|
class GenericWarriorNonCombatStrategy : public NonCombatStrategy
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GenericWarriorNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {}
|
GenericWarriorNonCombatStrategy(PlayerbotAI* botAI);
|
||||||
|
|
||||||
std::string const getName() override { return "nc"; }
|
std::string const getName() override { return "nc"; }
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
|
|||||||
@ -7,9 +7,26 @@
|
|||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
class GenericWarriorStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GenericWarriorStrategyActionNodeFactory() { creators["berserker rage"] = &berserker_rage; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ActionNode* berserker_rage([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode(
|
||||||
|
"berserker rage",
|
||||||
|
/*P*/ { NextAction("berserker stance") },
|
||||||
|
/*A*/ {},
|
||||||
|
/*C*/ {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
GenericWarriorStrategy::GenericWarriorStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
GenericWarriorStrategy::GenericWarriorStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)
|
||||||
{
|
{
|
||||||
|
actionNodeFactories.Add(new GenericWarriorStrategyActionNodeFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void GenericWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
@ -17,6 +34,8 @@ void GenericWarriorStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
CombatStrategy::InitTriggers(triggers);
|
CombatStrategy::InitTriggers(triggers);
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"enemy out of melee", { NextAction("reach melee", ACTION_HIGH + 1) }));
|
"enemy out of melee", { NextAction("reach melee", ACTION_HIGH + 1) }));
|
||||||
|
triggers.push_back(new TriggerNode(
|
||||||
|
"fear sleep sap", { NextAction("berserker rage", ACTION_EMERGENCY + 1) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
class WarrirorAoeStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
class WarrirorAoeStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "WarriorTriggers.h"
|
#include "WarriorTriggers.h"
|
||||||
|
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
bool BloodrageBuffTrigger::IsActive()
|
bool BloodrageBuffTrigger::IsActive()
|
||||||
@ -16,15 +15,11 @@ bool BloodrageBuffTrigger::IsActive()
|
|||||||
bool VigilanceTrigger::IsActive()
|
bool VigilanceTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!bot->HasSpell(50720))
|
if (!bot->HasSpell(50720))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Player* currentVigilanceTarget = nullptr;
|
Player* currentVigilanceTarget = nullptr;
|
||||||
Player* mainTank = nullptr;
|
Player* mainTank = nullptr;
|
||||||
@ -33,37 +28,23 @@ bool VigilanceTrigger::IsActive()
|
|||||||
Player* highestGearScorePlayer = nullptr;
|
Player* highestGearScorePlayer = nullptr;
|
||||||
uint32 highestGearScore = 0;
|
uint32 highestGearScore = 0;
|
||||||
|
|
||||||
// Iterate once through the group to gather all necessary information
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member || member == bot || !member->IsAlive())
|
if (!member || member == bot || !member->IsAlive())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if member has Vigilance applied by the bot
|
|
||||||
if (!currentVigilanceTarget && botAI->HasAura("vigilance", member, false, true))
|
if (!currentVigilanceTarget && botAI->HasAura("vigilance", member, false, true))
|
||||||
{
|
|
||||||
currentVigilanceTarget = member;
|
currentVigilanceTarget = member;
|
||||||
}
|
|
||||||
|
|
||||||
// Identify Main Tank
|
|
||||||
if (!mainTank && botAI->IsMainTank(member))
|
if (!mainTank && botAI->IsMainTank(member))
|
||||||
{
|
|
||||||
mainTank = member;
|
mainTank = member;
|
||||||
}
|
else if (!assistTank1 && botAI->IsAssistTankOfIndex(member, 0))
|
||||||
|
|
||||||
// Identify Assist Tanks
|
|
||||||
if (assistTank1 == nullptr && botAI->IsAssistTankOfIndex(member, 0))
|
|
||||||
{
|
|
||||||
assistTank1 = member;
|
assistTank1 = member;
|
||||||
}
|
else if (!assistTank2 && botAI->IsAssistTankOfIndex(member, 1))
|
||||||
else if (assistTank2 == nullptr && botAI->IsAssistTankOfIndex(member, 1))
|
|
||||||
{
|
|
||||||
assistTank2 = member;
|
assistTank2 = member;
|
||||||
}
|
|
||||||
|
|
||||||
// Determine Highest Gear Score
|
uint32 gearScore = botAI->GetEquipGearScore(member);
|
||||||
uint32 gearScore = botAI->GetEquipGearScore(member/*, false, false*/);
|
|
||||||
if (gearScore > highestGearScore)
|
if (gearScore > highestGearScore)
|
||||||
{
|
{
|
||||||
highestGearScore = gearScore;
|
highestGearScore = gearScore;
|
||||||
@ -71,33 +52,20 @@ bool VigilanceTrigger::IsActive()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the highest-priority target
|
|
||||||
Player* highestPriorityTarget = mainTank ? mainTank :
|
Player* highestPriorityTarget = mainTank ? mainTank :
|
||||||
(assistTank1 ? assistTank1 :
|
(assistTank1 ? assistTank1 :
|
||||||
(assistTank2 ? assistTank2 : highestGearScorePlayer));
|
(assistTank2 ? assistTank2 : highestGearScorePlayer));
|
||||||
|
|
||||||
// Trigger if no Vigilance is active or the current target is not the highest-priority target
|
|
||||||
if (!currentVigilanceTarget || currentVigilanceTarget != highestPriorityTarget)
|
if (!currentVigilanceTarget || currentVigilanceTarget != highestPriorityTarget)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false; // No need to reassign Vigilance
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShatteringThrowTrigger::IsActive()
|
bool ShatteringThrowTrigger::IsActive()
|
||||||
{
|
{
|
||||||
// Spell cooldown check
|
if (!bot->HasSpell(64382) || bot->HasSpellCooldown(64382))
|
||||||
if (!bot->HasSpell(64382))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Spell cooldown check
|
|
||||||
if (bot->HasSpellCooldown(64382))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
|
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
|
||||||
|
|
||||||
@ -107,7 +75,6 @@ bool ShatteringThrowTrigger::IsActive()
|
|||||||
if (!enemy || !enemy->IsAlive() || enemy->IsFriendlyTo(bot))
|
if (!enemy || !enemy->IsAlive() || enemy->IsFriendlyTo(bot))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if the enemy is within 25 yards and has the specific auras
|
|
||||||
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
||||||
(enemy->HasAura(642) || // Divine Shield
|
(enemy->HasAura(642) || // Divine Shield
|
||||||
enemy->HasAura(45438) || // Ice Block
|
enemy->HasAura(45438) || // Ice Block
|
||||||
@ -117,5 +84,74 @@ bool ShatteringThrowTrigger::IsActive()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // No valid targets within range
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BattleShoutTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!BuffTrigger::IsActive())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 battleShoutSpellId = AI_VALUE2(uint32, "spell id", "battle shout");
|
||||||
|
if (!battleShoutSpellId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SpellInfo const* bsInfo = sSpellMgr->GetSpellInfo(battleShoutSpellId);
|
||||||
|
if (!bsInfo)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int32 bsApValue = 0;
|
||||||
|
for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
|
||||||
|
{
|
||||||
|
if (bsInfo->Effects[eff].ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER)
|
||||||
|
{
|
||||||
|
bsApValue = bsInfo->Effects[eff].BasePoints + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bsApValue)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
static const uint32 commandingPresenceSpells[] = {
|
||||||
|
12318, 12857, 12858, 12860, 12861 };
|
||||||
|
static const float commandingPresenceBonus[] = {
|
||||||
|
0.05f, 0.10f, 0.15f, 0.20f, 0.25f };
|
||||||
|
|
||||||
|
float cpBonus = 0.0f;
|
||||||
|
for (int rank = 4; rank >= 0; --rank)
|
||||||
|
{
|
||||||
|
if (bot->HasAura(commandingPresenceSpells[rank]))
|
||||||
|
{
|
||||||
|
cpBonus = commandingPresenceBonus[rank];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int32 effectiveBsAp = int32(bsApValue * (1.0f + cpBonus));
|
||||||
|
|
||||||
|
static const char* blessingNames[] = {
|
||||||
|
"blessing of might", "greater blessing of might", nullptr
|
||||||
|
};
|
||||||
|
for (int i = 0; blessingNames[i] != nullptr; ++i)
|
||||||
|
{
|
||||||
|
Aura* bom = botAI->GetAura(blessingNames[i], bot);
|
||||||
|
if (!bom)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SpellInfo const* bomInfo = bom->GetSpellInfo();
|
||||||
|
if (!bomInfo)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint8 eff = 0; eff < MAX_SPELL_EFFECTS; ++eff)
|
||||||
|
{
|
||||||
|
if (bomInfo->Effects[eff].ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER)
|
||||||
|
{
|
||||||
|
int32 bomApValue = bomInfo->Effects[eff].BasePoints + 1;
|
||||||
|
if (bomApValue >= effectiveBsAp)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,13 @@
|
|||||||
#include "GenericTriggers.h"
|
#include "GenericTriggers.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
|
||||||
BUFF_TRIGGER(BattleShoutTrigger, "battle shout");
|
class BattleShoutTrigger : public BuffTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BattleShoutTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "battle shout") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
BUFF_TRIGGER(BattleStanceTrigger, "battle stance");
|
BUFF_TRIGGER(BattleStanceTrigger, "battle stance");
|
||||||
BUFF_TRIGGER(DefensiveStanceTrigger, "defensive stance");
|
BUFF_TRIGGER(DefensiveStanceTrigger, "defensive stance");
|
||||||
BUFF_TRIGGER(BerserkerStanceTrigger, "berserker stance");
|
BUFF_TRIGGER(BerserkerStanceTrigger, "berserker stance");
|
||||||
@ -85,4 +91,5 @@ public:
|
|||||||
// public:
|
// public:
|
||||||
// SlamTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "slam!") {}
|
// SlamTrigger(PlayerbotAI* ai) : HasAuraTrigger(ai, "slam!") {}
|
||||||
// };
|
// };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -647,7 +647,7 @@ float IccSindragosaMultiplier::GetValue(Action* action)
|
|||||||
dynamic_cast<CastWhirlwindAction*>(action) || dynamic_cast<CastMindSearAction*>(action) ||
|
dynamic_cast<CastWhirlwindAction*>(action) || dynamic_cast<CastMindSearAction*>(action) ||
|
||||||
dynamic_cast<CastMagmaTotemAction*>(action) || dynamic_cast<CastConsecrationAction*>(action) ||
|
dynamic_cast<CastMagmaTotemAction*>(action) || dynamic_cast<CastConsecrationAction*>(action) ||
|
||||||
dynamic_cast<CastFlamestrikeAction*>(action) || dynamic_cast<CastExplosiveTrapAction*>(action) ||
|
dynamic_cast<CastFlamestrikeAction*>(action) || dynamic_cast<CastExplosiveTrapAction*>(action) ||
|
||||||
dynamic_cast<CastExplosiveShotAction*>(action))
|
dynamic_cast<CastExplosiveShotBaseAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,7 +774,7 @@ float IccLichKingAddsMultiplier::GetValue(Action* action)
|
|||||||
dynamic_cast<CastStarfallAction*>(action) || dynamic_cast<FanOfKnivesAction*>(action) ||
|
dynamic_cast<CastStarfallAction*>(action) || dynamic_cast<FanOfKnivesAction*>(action) ||
|
||||||
dynamic_cast<CastWhirlwindAction*>(action) || dynamic_cast<CastMindSearAction*>(action) ||
|
dynamic_cast<CastWhirlwindAction*>(action) || dynamic_cast<CastMindSearAction*>(action) ||
|
||||||
dynamic_cast<CastMagmaTotemAction*>(action) || dynamic_cast<CastFlamestrikeAction*>(action) ||
|
dynamic_cast<CastMagmaTotemAction*>(action) || dynamic_cast<CastFlamestrikeAction*>(action) ||
|
||||||
dynamic_cast<CastExplosiveTrapAction*>(action) || dynamic_cast<CastExplosiveShotAction*>(action))
|
dynamic_cast<CastExplosiveTrapAction*>(action) || dynamic_cast<CastExplosiveShotBaseAction*>(action))
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -151,7 +151,14 @@ bool NewRpgGoGrindAction::Execute(Event /*event*/)
|
|||||||
if (SearchQuestGiverAndAcceptOrReward())
|
if (SearchQuestGiverAndAcceptOrReward())
|
||||||
return true;
|
return true;
|
||||||
if (auto* data = std::get_if<NewRpgInfo::GoGrind>(&botAI->rpgInfo.data))
|
if (auto* data = std::get_if<NewRpgInfo::GoGrind>(&botAI->rpgInfo.data))
|
||||||
return MoveFarTo(data->pos);
|
{
|
||||||
|
if (MoveFarTo(data->pos))
|
||||||
|
return true;
|
||||||
|
// Small nudge so the next tick's MoveFarTo starts from a
|
||||||
|
// slightly different position. Kept small so it doesn't look
|
||||||
|
// like the bot is abandoning its destination.
|
||||||
|
return MoveRandomNear(10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -162,7 +169,11 @@ bool NewRpgGoCampAction::Execute(Event /*event*/)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (auto* data = std::get_if<NewRpgInfo::GoCamp>(&botAI->rpgInfo.data))
|
if (auto* data = std::get_if<NewRpgInfo::GoCamp>(&botAI->rpgInfo.data))
|
||||||
return MoveFarTo(data->pos);
|
{
|
||||||
|
if (MoveFarTo(data->pos))
|
||||||
|
return true;
|
||||||
|
return MoveRandomNear(10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -215,7 +226,14 @@ bool NewRpgWanderNpcAction::Execute(Event /*event*/)
|
|||||||
data.lastReach = 0;
|
data.lastReach = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return MoveWorldObjectTo(data.npcOrGo);
|
{
|
||||||
|
if (MoveWorldObjectTo(data.npcOrGo))
|
||||||
|
return true;
|
||||||
|
// NPC pathing failed (random offset in a wall, mmap hiccup, etc).
|
||||||
|
// Take a small random step so the next tick retries from a
|
||||||
|
// different spot instead of staring at the NPC from afar.
|
||||||
|
return MoveRandomNear(15.0f);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -305,7 +323,12 @@ bool NewRpgDoQuestAction::DoIncompleteQuest(NewRpgInfo::DoQuest& data)
|
|||||||
|
|
||||||
if (bot->GetDistance(data.pos) > 10.0f && !data.lastReachPOI)
|
if (bot->GetDistance(data.pos) > 10.0f && !data.lastReachPOI)
|
||||||
{
|
{
|
||||||
return MoveFarTo(data.pos);
|
if (MoveFarTo(data.pos))
|
||||||
|
return true;
|
||||||
|
// Long-range sampler couldn't land a candidate — nudge the
|
||||||
|
// bot a short distance so the next tick retries from a
|
||||||
|
// different position instead of sitting idle.
|
||||||
|
return MoveRandomNear(10.0f);
|
||||||
}
|
}
|
||||||
// Now we are near the quest objective
|
// Now we are near the quest objective
|
||||||
// kill mobs and looting quest should be done automatically by grind strategy
|
// kill mobs and looting quest should be done automatically by grind strategy
|
||||||
@ -352,7 +375,11 @@ bool NewRpgDoQuestAction::DoIncompleteQuest(NewRpgInfo::DoQuest& data)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MoveRandomNear(20.0f);
|
// At the POI: keep the bot actively placed but avoid large
|
||||||
|
// random 20yd hops that look like pacing back and forth. A small
|
||||||
|
// ~8yd wander reads as the bot looking around while grind/loot
|
||||||
|
// strategies do their work.
|
||||||
|
return MoveRandomNear(8.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgDoQuestAction::DoCompletedQuest(NewRpgInfo::DoQuest& data)
|
bool NewRpgDoQuestAction::DoCompletedQuest(NewRpgInfo::DoQuest& data)
|
||||||
@ -392,7 +419,11 @@ bool NewRpgDoQuestAction::DoCompletedQuest(NewRpgInfo::DoQuest& data)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bot->GetDistance(data.pos) > 10.0f && !data.lastReachPOI)
|
if (bot->GetDistance(data.pos) > 10.0f && !data.lastReachPOI)
|
||||||
return MoveFarTo(data.pos);
|
{
|
||||||
|
if (MoveFarTo(data.pos))
|
||||||
|
return true;
|
||||||
|
return MoveRandomNear(10.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// Now we are near the qoi of reward
|
// Now we are near the qoi of reward
|
||||||
// the quest should be rewarded by SearchQuestGiverAndAcceptOrReward
|
// the quest should be rewarded by SearchQuestGiverAndAcceptOrReward
|
||||||
|
|||||||
@ -46,17 +46,51 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let previously committed movement finish before recomputing.
|
||||||
|
//
|
||||||
|
// MoveTo internally caps its stored delay at maxWaitForMove
|
||||||
|
// (default 5s), but a long path (200+ yd routed around a
|
||||||
|
// mountain) takes 30+ seconds to walk. After 5s
|
||||||
|
// IsWaitingForLastMove returns false and MoveFarTo re-enters.
|
||||||
|
// Without this gate, DoMovePoint would call mm->Clear() and
|
||||||
|
// reissue MovePoint from the new bot position — and from a new
|
||||||
|
// position mmap's partial-path endpoint often differs, so the
|
||||||
|
// bot gets clobbered mid-walk and ends up oscillating (e.g.
|
||||||
|
// cave entrance -> inside cave -> cave entrance -> mountain
|
||||||
|
// base -> cave entrance...) around an unreachable destination.
|
||||||
|
//
|
||||||
|
// If the bot is still actively walking toward its last
|
||||||
|
// committed point on the same map, just let the current spline
|
||||||
|
// finish. The stuck counter below continues to track real
|
||||||
|
// progress toward dest and triggers teleport recovery if the
|
||||||
|
// committed paths genuinely aren't closing the gap.
|
||||||
|
{
|
||||||
|
LastMovement& lastMove = AI_VALUE(LastMovement&, "last movement");
|
||||||
|
if (bot->isMoving() && lastMove.lastMoveToMapId == bot->GetMapId())
|
||||||
|
{
|
||||||
|
float remaining = bot->GetExactDist(lastMove.lastMoveToX, lastMove.lastMoveToY, lastMove.lastMoveToZ);
|
||||||
|
if (remaining > 10.0f)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// stuck check
|
// stuck check
|
||||||
float disToDest = bot->GetDistance(dest);
|
float disToDest = bot->GetDistance(dest);
|
||||||
if (disToDest + 1.0f < botAI->rpgInfo.nearestMoveFarDis)
|
// Require a meaningful improvement (5yd) to reset the stuck counter.
|
||||||
|
// The old 1yd threshold was small enough that bots oscillating back
|
||||||
|
// and forth around an obstacle would keep "making progress" forever
|
||||||
|
// and never trigger the teleport recovery below.
|
||||||
|
if (disToDest + 5.0f < botAI->rpgInfo.nearestMoveFarDis)
|
||||||
{
|
{
|
||||||
botAI->rpgInfo.nearestMoveFarDis = disToDest;
|
botAI->rpgInfo.nearestMoveFarDis = disToDest;
|
||||||
botAI->rpgInfo.stuckTs = getMSTime();
|
botAI->rpgInfo.stuckTs = getMSTime();
|
||||||
botAI->rpgInfo.stuckAttempts = 0;
|
botAI->rpgInfo.stuckAttempts = 0;
|
||||||
}
|
}
|
||||||
else if (++botAI->rpgInfo.stuckAttempts >= 10 && GetMSTimeDiffToNow(botAI->rpgInfo.stuckTs) >= stuckTime)
|
else if (++botAI->rpgInfo.stuckAttempts >= 5 && GetMSTimeDiffToNow(botAI->rpgInfo.stuckTs) >= stuckTime)
|
||||||
{
|
{
|
||||||
// Unfortunately we've been stuck here for over 5 mins, fallback to teleporting directly to the destination
|
// No meaningful progress toward dest for `stuckTime`: fall
|
||||||
|
// back to teleporting directly so the bot can get on with
|
||||||
|
// its RPG objective instead of oscillating indefinitely.
|
||||||
botAI->rpgInfo.stuckTs = getMSTime();
|
botAI->rpgInfo.stuckTs = getMSTime();
|
||||||
botAI->rpgInfo.stuckAttempts = 0;
|
botAI->rpgInfo.stuckAttempts = 0;
|
||||||
const AreaTableEntry* entry = sAreaTableStore.LookupEntry(bot->GetZoneId());
|
const AreaTableEntry* entry = sAreaTableStore.LookupEntry(bot->GetZoneId());
|
||||||
@ -78,26 +112,62 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
|||||||
false, true);
|
false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uint32 typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY;
|
||||||
|
|
||||||
|
// Primary strategy: ask mmap for a route to the TRUE destination.
|
||||||
|
// If mmap can reach it directly (PATHFIND_NORMAL) or partially
|
||||||
|
// (PATHFIND_INCOMPLETE — destinations beyond the smooth-path cap
|
||||||
|
// of ~296 yards, or where local geometry blocks the final step),
|
||||||
|
// walk to the furthest reachable waypoint mmap computed. This
|
||||||
|
// lets bots follow the real route around obstacles (mountains,
|
||||||
|
// cave walls, cliffs) instead of trying to cut straight through.
|
||||||
|
// The spline system walks the whole returned path smoothly, so
|
||||||
|
// subsequent ticks early-out via IsWaitingForLastMove and no
|
||||||
|
// further PathGenerator calls fire until the bot arrives.
|
||||||
|
{
|
||||||
|
PathGenerator path(bot);
|
||||||
|
path.CalculatePath(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||||
|
PathType type = path.GetPathType();
|
||||||
|
bool canReach = !(type & (~typeOk));
|
||||||
|
if (canReach)
|
||||||
|
{
|
||||||
|
const G3D::Vector3& endPos = path.GetActualEndPosition();
|
||||||
|
// Only commit if the mmap endpoint actually makes progress
|
||||||
|
// toward the destination. For pathological INCOMPLETE
|
||||||
|
// results (e.g. disconnected polys that still report
|
||||||
|
// INCOMPLETE) the endpoint can land right under the bot;
|
||||||
|
// fall through to cone sampling in that case.
|
||||||
|
float endDistToDest = dest.GetExactDist(endPos.x, endPos.y, endPos.z);
|
||||||
|
if (endDistToDest + 5.0f < disToDest)
|
||||||
|
{
|
||||||
|
return MoveTo(bot->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: mmap couldn't route to the destination. Sample the
|
||||||
|
// forward cone for a reachable stepping stone so the bot keeps
|
||||||
|
// moving and can try again from a new vantage point. Cap at 2
|
||||||
|
// samples — we already spent one PathGenerator call above and at
|
||||||
|
// 3000 bots every extra CalculatePath matters.
|
||||||
float minDelta = M_PI;
|
float minDelta = M_PI;
|
||||||
const float x = bot->GetPositionX();
|
const float x = bot->GetPositionX();
|
||||||
const float y = bot->GetPositionY();
|
const float y = bot->GetPositionY();
|
||||||
const float z = bot->GetPositionZ();
|
const float z = bot->GetPositionZ();
|
||||||
|
const float baseAngle = bot->GetAngle(&dest);
|
||||||
float rx, ry, rz;
|
float rx, ry, rz;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
int attempt = 3;
|
for (int attempt = 0; attempt < 2; ++attempt)
|
||||||
while (attempt--)
|
|
||||||
{
|
{
|
||||||
float angle = bot->GetAngle(&dest);
|
float delta = (rand_norm() - 0.5f) * static_cast<float>(M_PI); // ±π/2, forward cone
|
||||||
float delta = urand(1, 100) <= 75 ? (rand_norm() - 0.5) * M_PI * 0.5 : (rand_norm() - 0.5) * M_PI * 2;
|
float sampleDis = (0.5f + rand_norm() * 0.5f) * pathFinderDis;
|
||||||
angle += delta;
|
float angle = baseAngle + delta;
|
||||||
float dis = rand_norm() * pathFinderDis;
|
float dx = x + cos(angle) * sampleDis;
|
||||||
float dx = x + cos(angle) * dis;
|
float dy = y + sin(angle) * sampleDis;
|
||||||
float dy = y + sin(angle) * dis;
|
|
||||||
float dz = z + 0.5f;
|
float dz = z + 0.5f;
|
||||||
PathGenerator path(bot);
|
PathGenerator path(bot);
|
||||||
path.CalculatePath(dx, dy, dz);
|
path.CalculatePath(dx, dy, dz);
|
||||||
PathType type = path.GetPathType();
|
PathType type = path.GetPathType();
|
||||||
uint32 typeOk = PATHFIND_NORMAL | PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY;
|
|
||||||
bool canReach = !(type & (~typeOk));
|
bool canReach = !(type & (~typeOk));
|
||||||
|
|
||||||
if (canReach && fabs(delta) <= minDelta)
|
if (canReach && fabs(delta) <= minDelta)
|
||||||
@ -159,14 +229,18 @@ bool NewRpgBaseAction::MoveRandomNear(float moveStep, MovementPriority priority)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float distance = rand_norm() * moveStep;
|
|
||||||
Map* map = bot->GetMap();
|
Map* map = bot->GetMap();
|
||||||
const float x = bot->GetPositionX();
|
const float x = bot->GetPositionX();
|
||||||
const float y = bot->GetPositionY();
|
const float y = bot->GetPositionY();
|
||||||
const float z = bot->GetPositionZ();
|
const float z = bot->GetPositionZ();
|
||||||
int attempts = 1;
|
// Previously: attempts = 1. A single random sample often landed in
|
||||||
while (attempts--)
|
// water / blocked geometry / unreachable poly, the function returned
|
||||||
|
// false, and the caller had no fallback — bot stood still. Retry a
|
||||||
|
// handful of times with a fresh distance each loop so a bad roll
|
||||||
|
// doesn't lock the bot in place.
|
||||||
|
for (int attempt = 0; attempt < 8; ++attempt)
|
||||||
{
|
{
|
||||||
|
float distance = (0.4f + rand_norm() * 0.6f) * moveStep;
|
||||||
float angle = (float)rand_norm() * 2 * static_cast<float>(M_PI);
|
float angle = (float)rand_norm() * 2 * static_cast<float>(M_PI);
|
||||||
float dx = x + distance * cos(angle);
|
float dx = x + distance * cos(angle);
|
||||||
float dy = y + distance * sin(angle);
|
float dy = y + distance * sin(angle);
|
||||||
|
|||||||
@ -61,7 +61,14 @@ protected:
|
|||||||
protected:
|
protected:
|
||||||
/* FOR MOVE FAR */
|
/* FOR MOVE FAR */
|
||||||
const float pathFinderDis = 70.0f;
|
const float pathFinderDis = 70.0f;
|
||||||
const uint32 stuckTime = 5 * 60 * 1000;
|
// Time without real progress toward dest before MoveFarTo
|
||||||
|
// falls back to teleport recovery. Kept short enough that a
|
||||||
|
// bot truly oscillating around an unreachable destination
|
||||||
|
// (mmap returning non-progressing partial paths, or NOPATH +
|
||||||
|
// cone fallback wandering) doesn't spin for 5 minutes before
|
||||||
|
// the teleport fires, but long enough that a genuine long
|
||||||
|
// walk that is slowly making progress never triggers it.
|
||||||
|
const uint32 stuckTime = 90 * 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -25,7 +25,7 @@ void PlayerbotAIBase::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
UpdateAIInternal(elapsed, minimal);
|
UpdateAIInternal(elapsed, minimal);
|
||||||
YieldThread();
|
YieldThread(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerbotAIBase::SetNextCheckDelay(uint32 const delay)
|
void PlayerbotAIBase::SetNextCheckDelay(uint32 const delay)
|
||||||
@ -49,10 +49,14 @@ void PlayerbotAIBase::IncreaseNextCheckDelay(uint32 delay)
|
|||||||
|
|
||||||
bool PlayerbotAIBase::CanUpdateAI() { return nextAICheckDelay == 0; }
|
bool PlayerbotAIBase::CanUpdateAI() { return nextAICheckDelay == 0; }
|
||||||
|
|
||||||
void PlayerbotAIBase::YieldThread(uint32 delay)
|
void PlayerbotAIBase::YieldThread(Player* bot, uint32 delay)
|
||||||
{
|
{
|
||||||
if (nextAICheckDelay < delay)
|
if (nextAICheckDelay < delay)
|
||||||
nextAICheckDelay = delay;
|
{
|
||||||
|
// Adding a deterministic per-bot slight offset (0–200 ms) to stagger updates and prevent cpu spikes.
|
||||||
|
uint32 offset = bot ? (bot->GetGUID().GetCounter() % 201) : 0;
|
||||||
|
nextAICheckDelay = delay + offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAIBase::IsActive() { return nextAICheckDelay < sPlayerbotAIConfig.maxWaitForMove; }
|
bool PlayerbotAIBase::IsActive() { return nextAICheckDelay < sPlayerbotAIConfig.maxWaitForMove; }
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "Define.h"
|
#include "Define.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
class PlayerbotAIBase
|
class PlayerbotAIBase
|
||||||
{
|
{
|
||||||
@ -17,7 +18,7 @@ public:
|
|||||||
bool CanUpdateAI();
|
bool CanUpdateAI();
|
||||||
void SetNextCheckDelay(uint32 const delay);
|
void SetNextCheckDelay(uint32 const delay);
|
||||||
void IncreaseNextCheckDelay(uint32 delay);
|
void IncreaseNextCheckDelay(uint32 delay);
|
||||||
void YieldThread(uint32 delay = sPlayerbotAIConfig.reactDelay);
|
void YieldThread(Player* bot, uint32 delay = sPlayerbotAIConfig.reactDelay);
|
||||||
virtual void UpdateAI(uint32 elapsed, bool minimal = false);
|
virtual void UpdateAI(uint32 elapsed, bool minimal = false);
|
||||||
virtual void UpdateAIInternal(uint32 elapsed, bool minimal = false) = 0;
|
virtual void UpdateAIInternal(uint32 elapsed, bool minimal = false) = 0;
|
||||||
bool IsActive();
|
bool IsActive();
|
||||||
|
|||||||
@ -311,7 +311,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("frost", nullptr);
|
engine->addStrategiesNoInit("frost", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr);
|
engine->addStrategiesNoInit("dps", "dps assist", "cure", "cc", "aoe", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == WARRIOR_TAB_PROTECTION)
|
if (tab == WARRIOR_TAB_PROTECTION)
|
||||||
@ -363,7 +363,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("surv", nullptr);
|
engine->addStrategiesNoInit("surv", nullptr);
|
||||||
|
|
||||||
engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr);
|
engine->addStrategiesNoInit("cc", "dps assist", "aoe", "bdps", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY)
|
||||||
|
|||||||
@ -3032,6 +3032,17 @@ void PlayerbotFactory::InitMounts()
|
|||||||
slow = {33660, 35020, 35022, 35018};
|
slow = {33660, 35020, 35022, 35018};
|
||||||
fast = {35025, 35025, 35027};
|
fast = {35025, 35025, 35027};
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
if (bot->GetTeamId() == TEAM_HORDE)
|
||||||
|
{ // Orc mounts
|
||||||
|
slow = {470, 6648, 458, 472};
|
||||||
|
fast = {23228, 23227, 23229};
|
||||||
|
}
|
||||||
|
else // Human mounts
|
||||||
|
{
|
||||||
|
slow = {6654, 6653, 580};
|
||||||
|
fast = {23250, 23252, 23251};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bot->GetTeamId())
|
switch (bot->GetTeamId())
|
||||||
@ -3307,7 +3318,7 @@ void PlayerbotFactory::InitReagents()
|
|||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
if (level >= 52)
|
if (level >= 52)
|
||||||
items.push_back({21177, 80}); // Symbol of Kings
|
items.push_back({21177, 100}); // Symbol of Kings
|
||||||
break;
|
break;
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
if (level >= 48 && level < 56)
|
if (level >= 48 && level < 56)
|
||||||
|
|||||||
@ -119,7 +119,7 @@ PlayerbotAI::PlayerbotAI()
|
|||||||
|
|
||||||
for (uint8 i = 0; i < MAX_ACTIVITY_TYPE; i++)
|
for (uint8 i = 0; i < MAX_ACTIVITY_TYPE; i++)
|
||||||
{
|
{
|
||||||
allowActiveCheckTimer[i] = time(nullptr);
|
allowActiveCheckTimer[i] = 0;
|
||||||
allowActive[i] = false;
|
allowActive[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,19 +137,20 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
|||||||
|
|
||||||
for (uint8 i = 0; i < MAX_ACTIVITY_TYPE; i++)
|
for (uint8 i = 0; i < MAX_ACTIVITY_TYPE; i++)
|
||||||
{
|
{
|
||||||
allowActiveCheckTimer[i] = time(nullptr);
|
allowActiveCheckTimer[i] = 0;
|
||||||
allowActive[i] = false;
|
allowActive[i] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
accountId = bot->GetSession()->GetAccountId();
|
accountId = bot->GetSession()->GetAccountId();
|
||||||
|
|
||||||
aiObjectContext = AiFactory::createAiObjectContext(bot, this);
|
aiObjectContext = AiFactory::createAiObjectContext(bot, this);
|
||||||
|
|
||||||
engines[BOT_STATE_COMBAT] = AiFactory::createCombatEngine(bot, this, aiObjectContext);
|
engines[BOT_STATE_COMBAT] = AiFactory::createCombatEngine(bot, this, aiObjectContext);
|
||||||
engines[BOT_STATE_NON_COMBAT] = AiFactory::createNonCombatEngine(bot, this, aiObjectContext);
|
engines[BOT_STATE_NON_COMBAT] = AiFactory::createNonCombatEngine(bot, this, aiObjectContext);
|
||||||
engines[BOT_STATE_DEAD] = AiFactory::createDeadEngine(bot, this, aiObjectContext);
|
engines[BOT_STATE_DEAD] = AiFactory::createDeadEngine(bot, this, aiObjectContext);
|
||||||
|
|
||||||
if (sPlayerbotAIConfig.applyInstanceStrategies)
|
if (sPlayerbotAIConfig.applyInstanceStrategies)
|
||||||
ApplyInstanceStrategies(bot->GetMapId());
|
ApplyInstanceStrategies(bot->GetMapId());
|
||||||
|
|
||||||
currentEngine = engines[BOT_STATE_NON_COMBAT];
|
currentEngine = engines[BOT_STATE_NON_COMBAT];
|
||||||
currentState = BOT_STATE_NON_COMBAT;
|
currentState = BOT_STATE_NON_COMBAT;
|
||||||
|
|
||||||
@ -279,7 +280,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
if (spellTarget && !spellTarget->IsAlive() && !spellInfo->IsAllowingDeadTarget())
|
if (spellTarget && !spellTarget->IsAlive() && !spellInfo->IsAllowingDeadTarget())
|
||||||
{
|
{
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(bot, GetReactDelay());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +289,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
if (goSpellTarget && !goSpellTarget->isSpawned())
|
if (goSpellTarget && !goSpellTarget->isSpawned())
|
||||||
{
|
{
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(bot, GetReactDelay());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +321,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
if (isHeal && isSingleTarget && spellTarget && spellTarget->IsFullHealth())
|
if (isHeal && isSingleTarget && spellTarget && spellTarget->IsFullHealth())
|
||||||
{
|
{
|
||||||
InterruptSpell();
|
InterruptSpell();
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(bot, GetReactDelay());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +333,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for spell cast
|
// Wait for spell cast
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(bot, GetReactDelay());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,7 +369,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
|||||||
|
|
||||||
// Update internal AI
|
// Update internal AI
|
||||||
UpdateAIInternal(elapsed, minimal);
|
UpdateAIInternal(elapsed, minimal);
|
||||||
YieldThread(GetReactDelay());
|
YieldThread(bot, GetReactDelay());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for UpdateAI to check group membership and handle removal if necessary
|
// Helper function for UpdateAI to check group membership and handle removal if necessary
|
||||||
@ -445,9 +446,11 @@ void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal
|
|||||||
if (!bot->GetMap())
|
if (!bot->GetMap())
|
||||||
return; // instances are created and destroyed on demand
|
return; // instances are created and destroyed on demand
|
||||||
|
|
||||||
|
// kinda expensive call to make on every single updateAI, do we really need this information?
|
||||||
std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I";
|
std::string const mapString = WorldPosition(bot).isOverworld() ? std::to_string(bot->GetMapId()) : "I";
|
||||||
PerfMonitorOperation* pmo =
|
PerfMonitorOperation* pmo =
|
||||||
sPerfMonitor.start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString);
|
sPerfMonitor.start(PERF_MON_TOTAL, "PlayerbotAI::UpdateAIInternal " + mapString);
|
||||||
|
|
||||||
ExternalEventHelper helper(aiObjectContext);
|
ExternalEventHelper helper(aiObjectContext);
|
||||||
|
|
||||||
// chat replies
|
// chat replies
|
||||||
@ -1202,23 +1205,18 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
|||||||
if (HasRealPlayerMaster() && guid1 != GetMaster()->GetGUID())
|
if (HasRealPlayerMaster() && guid1 != GetMaster()->GetGUID())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto itemIds = GetChatHelper()->ExtractAllItemIds(message);
|
||||||
if (message.starts_with(sPlayerbotAIConfig.toxicLinksPrefix) &&
|
if (message.starts_with(sPlayerbotAIConfig.toxicLinksPrefix) &&
|
||||||
(GetChatHelper()->ExtractAllItemIds(message).size() > 0 ||
|
(itemIds.size() > 0 || GetChatHelper()->ExtractAllQuestIds(message).size() > 0) &&
|
||||||
GetChatHelper()->ExtractAllQuestIds(message).size() > 0) &&
|
|
||||||
sPlayerbotAIConfig.toxicLinksRepliesChance)
|
sPlayerbotAIConfig.toxicLinksRepliesChance)
|
||||||
{
|
{
|
||||||
if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig.toxicLinksRepliesChance)
|
if (urand(0, 50) > 0 || urand(1, 100) > sPlayerbotAIConfig.toxicLinksRepliesChance)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ((GetChatHelper()->ExtractAllItemIds(message).count(19019) &&
|
else if (itemIds.count(19019) && sPlayerbotAIConfig.thunderfuryRepliesChance)
|
||||||
sPlayerbotAIConfig.thunderfuryRepliesChance))
|
|
||||||
{
|
{
|
||||||
if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig.thunderfuryRepliesChance)
|
if (urand(0, 60) > 0 || urand(1, 100) > sPlayerbotAIConfig.thunderfuryRepliesChance)
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1962,6 +1960,11 @@ bool PlayerbotAI::HasAggro(Unit* unit)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlayerbotAI::IsMovementImpaired(Unit* unit)
|
||||||
|
{
|
||||||
|
return unit && (unit->HasAuraType(SPELL_AURA_MOD_ROOT) || unit->IsRooted() || unit->GetSpeedRate(MOVE_RUN) < 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
int32 PlayerbotAI::GetAssistTankIndex(Player* player)
|
int32 PlayerbotAI::GetAssistTankIndex(Player* player)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
@ -4372,21 +4375,27 @@ Player* PlayerbotAI::GetGroupLeader()
|
|||||||
return master;
|
return master;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 PlayerbotAI::GetFixedBotNumer(uint32 maxNum, float cyclePerMin)
|
uint32 PlayerbotAI::GetFixedBotNumber(uint32 maxNum)
|
||||||
{
|
{
|
||||||
uint32 randseed = rand32(); // Seed random number
|
if (maxNum == 0)
|
||||||
uint32 randnum = bot->GetGUID().GetCounter() + randseed; // Semi-random but fixed number for each bot.
|
return 0;
|
||||||
|
|
||||||
if (cyclePerMin > 0)
|
// Deterministic pseudo-random hash based on the bot GUID evenly distributed across active slots
|
||||||
{
|
uint32 id = bot->GetGUID().GetCounter();
|
||||||
uint32 cycle = floor(getMSTime() / (1000)); // Semi-random number adds 1 each second.
|
uint32 h = id;
|
||||||
cycle = cycle * cyclePerMin / 60; // Cycles cyclePerMin per minute.
|
h ^= h >> 16;
|
||||||
randnum += cycle; // Make the random number cylce.
|
h *= 0x7feb352d;
|
||||||
}
|
h ^= h >> 15;
|
||||||
|
h *= 0x846ca68b;
|
||||||
|
h ^= h >> 16;
|
||||||
|
|
||||||
randnum =
|
// Current time slot
|
||||||
(randnum % (maxNum + 1)); // Loops the randomnumber at maxNum. Bassically removes all the numbers above 99.
|
uint32 timeSlot = (getMSTime() / 1000) / sPlayerbotAIConfig.BotActiveAloneDurationSeconds;
|
||||||
return randnum; // Now we have a number unique for each bot between 0 and maxNum that increases by cyclePerMin.
|
|
||||||
|
// Mix timeSlot into the hash to reshuffle every rotation window
|
||||||
|
uint32 mixed = h ^ (timeSlot * 0x9e3779b9); // with multiplicative constant
|
||||||
|
|
||||||
|
return mixed % maxNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4403,7 +4412,7 @@ enum GrouperType
|
|||||||
|
|
||||||
GrouperType PlayerbotAI::GetGrouperType()
|
GrouperType PlayerbotAI::GetGrouperType()
|
||||||
{
|
{
|
||||||
uint32 grouperNumber = GetFixedBotNumer(100, 0);
|
uint32 grouperNumber = GetFixedBotNumber(100);
|
||||||
|
|
||||||
if (grouperNumber < 20 && !HasRealPlayerMaster())
|
if (grouperNumber < 20 && !HasRealPlayerMaster())
|
||||||
return GrouperType::SOLO;
|
return GrouperType::SOLO;
|
||||||
@ -4425,7 +4434,7 @@ GrouperType PlayerbotAI::GetGrouperType()
|
|||||||
|
|
||||||
GuilderType PlayerbotAI::GetGuilderType()
|
GuilderType PlayerbotAI::GetGuilderType()
|
||||||
{
|
{
|
||||||
uint32 grouperNumber = GetFixedBotNumer(100, 0);
|
uint32 grouperNumber = GetFixedBotNumber(100);
|
||||||
|
|
||||||
if (grouperNumber < 20 && !HasRealPlayerMaster())
|
if (grouperNumber < 20 && !HasRealPlayerMaster())
|
||||||
return GuilderType::SOLO;
|
return GuilderType::SOLO;
|
||||||
@ -4448,7 +4457,6 @@ GuilderType PlayerbotAI::GetGuilderType()
|
|||||||
bool PlayerbotAI::HasPlayerNearby(WorldPosition* pos, float range)
|
bool PlayerbotAI::HasPlayerNearby(WorldPosition* pos, float range)
|
||||||
{
|
{
|
||||||
float sqRange = range * range;
|
float sqRange = range * range;
|
||||||
bool nearPlayer = false;
|
|
||||||
for (auto& player : sRandomPlayerbotMgr.GetPlayers())
|
for (auto& player : sRandomPlayerbotMgr.GetPlayers())
|
||||||
{
|
{
|
||||||
if (!player->IsGameMaster() || player->isGMVisible())
|
if (!player->IsGameMaster() || player->isGMVisible())
|
||||||
@ -4457,19 +4465,18 @@ bool PlayerbotAI::HasPlayerNearby(WorldPosition* pos, float range)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pos->sqDistance(WorldPosition(player)) < sqRange)
|
if (pos->sqDistance(WorldPosition(player)) < sqRange)
|
||||||
nearPlayer = true;
|
return true;
|
||||||
|
|
||||||
// if player is far check farsight/cinematic camera
|
|
||||||
WorldObject* viewObj = player->GetViewpoint();
|
WorldObject* viewObj = player->GetViewpoint();
|
||||||
if (viewObj && viewObj != player)
|
if (viewObj && viewObj != player)
|
||||||
{
|
{
|
||||||
if (pos->sqDistance(WorldPosition(viewObj)) < sqRange)
|
if (pos->sqDistance(WorldPosition(viewObj)) < sqRange)
|
||||||
nearPlayer = true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nearPlayer;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::HasPlayerNearby(float range)
|
bool PlayerbotAI::HasPlayerNearby(float range)
|
||||||
@ -4478,173 +4485,97 @@ bool PlayerbotAI::HasPlayerNearby(float range)
|
|||||||
return HasPlayerNearby(&botPos, range);
|
return HasPlayerNearby(&botPos, range);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool PlayerbotAI::HasManyPlayersNearby(uint32 trigerrValue, float range)
|
|
||||||
{
|
|
||||||
float sqRange = range * range;
|
|
||||||
uint32 found = 0;
|
|
||||||
|
|
||||||
for (auto& player : sRandomPlayerbotMgr.GetPlayers())
|
|
||||||
{
|
|
||||||
if ((!player->IsGameMaster() || player->isGMVisible()) && ServerFacade::instance().GetDistance2d(player, bot) < sqRange)
|
|
||||||
{
|
|
||||||
found++;
|
|
||||||
|
|
||||||
if (found >= trigerrValue)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool HasRealPlayers(Map* map)
|
|
||||||
{
|
|
||||||
Map::PlayerList const& players = map->GetPlayers();
|
|
||||||
if (players.IsEmpty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto const& itr : players)
|
|
||||||
{
|
|
||||||
Player* player = itr.GetSource();
|
|
||||||
if (!player || !player->IsVisible())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
|
||||||
if (!botAI || botAI->IsRealPlayer() || botAI->HasRealPlayerMaster())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool ZoneHasRealPlayers(Player* bot)
|
|
||||||
{
|
|
||||||
Map* map = bot->GetMap();
|
|
||||||
if (!bot || !map)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Player* player : sRandomPlayerbotMgr.GetPlayers())
|
|
||||||
{
|
|
||||||
if (player->GetMapId() != bot->GetMapId())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (player->IsGameMaster() && !player->IsVisible())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player->GetZoneId() == bot->GetZoneId())
|
|
||||||
{
|
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
|
||||||
if (!botAI || botAI->IsRealPlayer() || botAI->HasRealPlayerMaster())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PlayerbotAI::AllowActive(ActivityType activityType)
|
bool PlayerbotAI::AllowActive(ActivityType activityType)
|
||||||
{
|
{
|
||||||
// Early return if bot is in invalid state
|
// bot is in an invalid state, not safe to process
|
||||||
if (!bot || !bot->GetSession() || !bot->IsInWorld() || bot->IsBeingTeleported() ||
|
if (!bot || !bot->GetSession() || !bot->IsInWorld() || bot->IsBeingTeleported() ||
|
||||||
bot->GetSession()->isLogingOut() || bot->IsDuringRemoveFromWorld())
|
bot->GetSession()->isLogingOut() || bot->IsDuringRemoveFromWorld())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// when botActiveAlone is 100% and smartScale disabled
|
// always allow packet handling (e.g. group invites, trade, loot, friend requests etc)
|
||||||
if (sPlayerbotAIConfig.botActiveAlone >= 100 && !sPlayerbotAIConfig.botActiveAloneSmartScale)
|
if (activityType == PACKET_ACTIVITY)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// Is in combat. Always defend yourself.
|
// all bots forced active, no rotation or scaling needed
|
||||||
|
if (sPlayerbotAIConfig.botActiveAlone >= 100 && !sPlayerbotAIConfig.botActiveAloneSmartScale)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// bot is in combat, always defend yourself
|
||||||
if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY)
|
if (activityType != OUT_OF_PARTY_ACTIVITY && activityType != PACKET_ACTIVITY)
|
||||||
{
|
{
|
||||||
if (bot->IsInCombat())
|
if (bot->IsInCombat())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// only keep updating till initializing time has completed,
|
// bot is inside a BG, dungeon, or raid — always active
|
||||||
// which prevents unneeded expensive GameTime calls.
|
|
||||||
if (_isBotInitializing)
|
|
||||||
{
|
|
||||||
_isBotInitializing = GameTime::GetUptime().count() < sPlayerbotAIConfig.maxRandomBots * 0.11;
|
|
||||||
|
|
||||||
// no activity allowed during bot initialization
|
|
||||||
if (_isBotInitializing)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// General exceptions
|
|
||||||
if (activityType == PACKET_ACTIVITY)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bg, raid, dungeon
|
|
||||||
if (!WorldPosition(bot).isOverworld())
|
if (!WorldPosition(bot).isOverworld())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// bot map has active players.
|
// bot is waiting in a BG queue — stay active to speed up join
|
||||||
if (sPlayerbotAIConfig.BotActiveAloneForceWhenInMap)
|
if (bot->InBattlegroundQueue())
|
||||||
{
|
return true;
|
||||||
if (HasRealPlayers(bot->GetMap()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// bot zone has active players.
|
// bot is in a guild that contains a real player
|
||||||
if (sPlayerbotAIConfig.BotActiveAloneForceWhenInZone)
|
|
||||||
{
|
|
||||||
if (ZoneHasRealPlayers(bot))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// when in real guild
|
|
||||||
if (sPlayerbotAIConfig.BotActiveAloneForceWhenInGuild)
|
if (sPlayerbotAIConfig.BotActiveAloneForceWhenInGuild)
|
||||||
{
|
{
|
||||||
if (IsInRealGuild())
|
if (IsInRealGuild()) // checks cache list
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a real player is in the same zone (e.g. Elwynn Forest), same continent or within configured yard radius
|
||||||
|
// combined into a single loop to multiple iterations since this function is called so often
|
||||||
|
bool checkMap = sPlayerbotAIConfig.BotActiveAloneForceWhenInMap;
|
||||||
|
bool checkZone = sPlayerbotAIConfig.BotActiveAloneForceWhenInZone;
|
||||||
|
bool checkRadius = sPlayerbotAIConfig.BotActiveAloneForceWhenInRadius > 0;
|
||||||
|
if (checkMap || checkZone || checkRadius)
|
||||||
|
{
|
||||||
|
uint32 botMapId = bot->GetMapId();
|
||||||
|
uint32 botZoneId = checkZone ? bot->GetZoneId() : 0;
|
||||||
|
float sqRange = 0.0f;
|
||||||
|
WorldPosition botPos(bot);
|
||||||
|
if (checkRadius)
|
||||||
|
{
|
||||||
|
float range = static_cast<float>(sPlayerbotAIConfig.BotActiveAloneForceWhenInRadius);
|
||||||
|
sqRange = range * range;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& player : sRandomPlayerbotMgr.GetPlayers())
|
||||||
|
{
|
||||||
|
if (!player || player->GetMapId() != botMapId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool isGM = player->IsGameMaster();
|
||||||
|
|
||||||
|
// map check
|
||||||
|
if (checkMap && !(isGM && !player->IsVisible()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// zone check
|
||||||
|
if (checkZone && !(isGM && !player->IsVisible()) && player->GetZoneId() == botZoneId)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// radius check
|
||||||
|
if (checkRadius && (!isGM || player->isGMVisible()))
|
||||||
|
{
|
||||||
|
if (botPos.sqDistance(WorldPosition(player)) < sqRange)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
WorldObject* viewObj = player->GetViewpoint();
|
||||||
|
if (viewObj && viewObj != player && botPos.sqDistance(WorldPosition(viewObj)) < sqRange)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player is near. Always active.
|
// bot has a real player master (not another bot)
|
||||||
if (HasPlayerNearby(sPlayerbotAIConfig.BotActiveAloneForceWhenInRadius))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has player master. Always active.
|
|
||||||
if (GetMaster())
|
if (GetMaster())
|
||||||
{
|
{
|
||||||
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(GetMaster());
|
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(GetMaster());
|
||||||
if (!masterBotAI || masterBotAI->IsRealPlayer())
|
if (!masterBotAI || masterBotAI->IsRealPlayer())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if grouped up
|
// bot is grouped with a real player (or a bot owned by one)
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (group)
|
if (group)
|
||||||
{
|
{
|
||||||
@ -4655,52 +4586,37 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (member == bot)
|
if (member == bot)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member);
|
PlayerbotAI* memberBotAI = GET_PLAYERBOT_AI(member);
|
||||||
{
|
|
||||||
if (!memberBotAI || memberBotAI->HasRealPlayerMaster())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// group member is a real player or owned by one — stay active
|
||||||
|
if (!memberBotAI || memberBotAI->HasRealPlayerMaster())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// if group leader (bot) is inactive, follow suit
|
||||||
if (group->IsLeader(member->GetGUID()))
|
if (group->IsLeader(member->GetGUID()))
|
||||||
{
|
{
|
||||||
if (!memberBotAI->AllowActivity(PARTY_ACTIVITY))
|
if (!memberBotAI->AllowActivity(PARTY_ACTIVITY))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In bg queue. Speed up bg queue/join.
|
// bot is in LFG queue — stay active
|
||||||
if (bot->InBattlegroundQueue())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLFG = false;
|
bool isLFG = false;
|
||||||
if (group)
|
if (group)
|
||||||
{
|
{
|
||||||
if (sLFGMgr->GetState(group->GetGUID()) != lfg::LFG_STATE_NONE)
|
if (sLFGMgr->GetState(group->GetGUID()) != lfg::LFG_STATE_NONE)
|
||||||
{
|
|
||||||
isLFG = true;
|
isLFG = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
|
if (sLFGMgr->GetState(bot->GetGUID()) != lfg::LFG_STATE_NONE)
|
||||||
{
|
|
||||||
isLFG = true;
|
isLFG = true;
|
||||||
}
|
|
||||||
if (isLFG)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasFriend
|
if (isLFG)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// a real player has this bot on their friends list
|
||||||
if (sPlayerbotAIConfig.BotActiveAloneForceWhenIsFriend)
|
if (sPlayerbotAIConfig.BotActiveAloneForceWhenIsFriend)
|
||||||
{
|
{
|
||||||
// shouldnt be needed analyse in future
|
// shouldnt be needed analyse in future
|
||||||
@ -4717,41 +4633,27 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
|||||||
if (!playerAI || !playerAI->IsRealPlayer())
|
if (!playerAI || !playerAI->IsRealPlayer())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// if a real player has the bot as a friend
|
|
||||||
PlayerSocial* social = player->GetSocial();
|
PlayerSocial* social = player->GetSocial();
|
||||||
if (social && social->HasFriend(bot->GetGUID()))
|
if (social && social->HasFriend(bot->GetGUID()))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force the bots to spread
|
// pathfinding only runs for bots forced active by the rules above —
|
||||||
if (activityType == OUT_OF_PARTY_ACTIVITY || activityType == GRIND_ACTIVITY)
|
// skip it for bots that would only be active via random rotation
|
||||||
{
|
|
||||||
if (HasManyPlayersNearby(10, 40))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bots don't need react to PathGenerator activities
|
|
||||||
if (activityType == DETAILED_MOVE_ACTIVITY)
|
if (activityType == DETAILED_MOVE_ACTIVITY)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
|
// #######################################################################################
|
||||||
|
// Acitivity throttling logic
|
||||||
|
// #######################################################################################
|
||||||
if (sPlayerbotAIConfig.botActiveAlone <= 0)
|
if (sPlayerbotAIConfig.botActiveAlone <= 0)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// #######################################################################################
|
// base threshold capped at 100
|
||||||
// All mandatory conditations are checked to be active or not, from here the remaining
|
|
||||||
// situations are usable for scaling when enabled.
|
|
||||||
// #######################################################################################
|
|
||||||
|
|
||||||
// Below is code to have a specified % of bots active at all times.
|
|
||||||
// The default is 100%. With 1% of all bots going active or inactive each minute.
|
|
||||||
uint32 mod = sPlayerbotAIConfig.botActiveAlone > 100 ? 100 : sPlayerbotAIConfig.botActiveAlone;
|
uint32 mod = sPlayerbotAIConfig.botActiveAlone > 100 ? 100 : sPlayerbotAIConfig.botActiveAlone;
|
||||||
|
|
||||||
|
// reduce threshold based on server tick time when SmartScale is enabled
|
||||||
if (sPlayerbotAIConfig.botActiveAloneSmartScale &&
|
if (sPlayerbotAIConfig.botActiveAloneSmartScale &&
|
||||||
bot->GetLevel() >= sPlayerbotAIConfig.botActiveAloneSmartScaleWhenMinLevel &&
|
bot->GetLevel() >= sPlayerbotAIConfig.botActiveAloneSmartScaleWhenMinLevel &&
|
||||||
bot->GetLevel() <= sPlayerbotAIConfig.botActiveAloneSmartScaleWhenMaxLevel)
|
bot->GetLevel() <= sPlayerbotAIConfig.botActiveAloneSmartScaleWhenMaxLevel)
|
||||||
@ -4759,34 +4661,27 @@ bool PlayerbotAI::AllowActive(ActivityType activityType)
|
|||||||
mod = AutoScaleActivity(mod);
|
mod = AutoScaleActivity(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ActivityNumber =
|
// deterministic rotation — bot is active if its hash falls below the threshold
|
||||||
GetFixedBotNumer(100, sPlayerbotAIConfig.botActiveAlone * static_cast<float>(mod) / 100 * 0.01f);
|
uint32 ActivityNumber = GetFixedBotNumber(100);
|
||||||
|
return ActivityNumber < mod;
|
||||||
return ActivityNumber <=
|
|
||||||
(sPlayerbotAIConfig.botActiveAlone * mod) /
|
|
||||||
100; // The given percentage of bots should be active and rotate 1% of those active bots each minute.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
|
bool PlayerbotAI::AllowActivity(ActivityType activityType, bool checkNow)
|
||||||
{
|
{
|
||||||
const int activityIndex = static_cast<int>(activityType);
|
const int activityIndex = static_cast<int>(activityType);
|
||||||
|
|
||||||
// Unknown/out-of-range avoid blocking, added logging for further analysing should not happen in the first place.
|
|
||||||
if (activityIndex <= 0 || activityIndex >= MAX_ACTIVITY_TYPE)
|
|
||||||
{
|
|
||||||
LOG_ERROR("playerbots", "AllowActivity received invalid activity type value: {}", activityIndex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowActiveCheckTimer[activityIndex])
|
if (!allowActiveCheckTimer[activityIndex])
|
||||||
allowActiveCheckTimer[activityIndex] = time(nullptr);
|
allowActiveCheckTimer[activityIndex] = getMSTime();
|
||||||
|
|
||||||
if (!checkNow && time(nullptr) < (allowActiveCheckTimer[activityIndex] + 5))
|
// 4500ms base + 0–499ms per-bot offset = 4500–4999ms, capping at just under 5 seconds
|
||||||
|
uint32 offset = bot->GetGUID().GetCounter() % 500;
|
||||||
|
|
||||||
|
if (!checkNow && getMSTime() < (allowActiveCheckTimer[activityIndex] + 4500 + offset))
|
||||||
return allowActive[activityIndex];
|
return allowActive[activityIndex];
|
||||||
|
|
||||||
const bool allowed = AllowActive(activityType);
|
const bool allowed = AllowActive(activityType);
|
||||||
allowActive[activityIndex] = allowed;
|
allowActive[activityIndex] = allowed;
|
||||||
allowActiveCheckTimer[activityIndex] = time(nullptr);
|
allowActiveCheckTimer[activityIndex] = getMSTime();
|
||||||
|
|
||||||
return allowed;
|
return allowed;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -430,6 +430,7 @@ public:
|
|||||||
static bool IsAssistHealOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
static bool IsAssistHealOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
||||||
static bool IsAssistRangedDpsOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
static bool IsAssistRangedDpsOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
||||||
bool HasAggro(Unit* unit);
|
bool HasAggro(Unit* unit);
|
||||||
|
bool IsMovementImpaired(Unit* unit);
|
||||||
static int32 GetAssistTankIndex(Player* player);
|
static int32 GetAssistTankIndex(Player* player);
|
||||||
int32 GetGroupSlotIndex(Player* player);
|
int32 GetGroupSlotIndex(Player* player);
|
||||||
int32 GetRangedIndex(Player* player);
|
int32 GetRangedIndex(Player* player);
|
||||||
@ -540,13 +541,11 @@ public:
|
|||||||
// Checks if the bot is summoned as alt of a player
|
// Checks if the bot is summoned as alt of a player
|
||||||
bool IsAlt();
|
bool IsAlt();
|
||||||
Player* GetGroupLeader();
|
Player* GetGroupLeader();
|
||||||
// Returns a semi-random (cycling) number that is fixed for each bot.
|
uint32 GetFixedBotNumber(uint32 maxNum = 100);
|
||||||
uint32 GetFixedBotNumer(uint32 maxNum = 100, float cyclePerMin = 1);
|
|
||||||
GrouperType GetGrouperType();
|
GrouperType GetGrouperType();
|
||||||
GuilderType GetGuilderType();
|
GuilderType GetGuilderType();
|
||||||
bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig.reactDistance);
|
bool HasPlayerNearby(WorldPosition* pos, float range = sPlayerbotAIConfig.reactDistance);
|
||||||
bool HasPlayerNearby(float range = sPlayerbotAIConfig.reactDistance);
|
bool HasPlayerNearby(float range = sPlayerbotAIConfig.reactDistance);
|
||||||
bool HasManyPlayersNearby(uint32 trigerrValue = 20, float range = sPlayerbotAIConfig.sightDistance);
|
|
||||||
bool AllowActive(ActivityType activityType);
|
bool AllowActive(ActivityType activityType);
|
||||||
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
|
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
|
||||||
uint32 AutoScaleActivity(uint32 mod);
|
uint32 AutoScaleActivity(uint32 mod);
|
||||||
@ -614,7 +613,6 @@ private:
|
|||||||
Item* FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const;
|
Item* FindItemInInventory(std::function<bool(ItemTemplate const*)> checkItem) const;
|
||||||
void HandleCommands();
|
void HandleCommands();
|
||||||
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
void HandleCommand(uint32 type, const std::string& text, Player& fromPlayer, const uint32 lang = LANG_UNIVERSAL);
|
||||||
bool _isBotInitializing = false;
|
|
||||||
inline bool IsValidUnit(const Unit* unit) const
|
inline bool IsValidUnit(const Unit* unit) const
|
||||||
{
|
{
|
||||||
return unit && unit->IsInWorld() && !unit->IsDuringRemoveFromWorld();
|
return unit && unit->IsInWorld() && !unit->IsDuringRemoveFromWorld();
|
||||||
|
|||||||
@ -1768,13 +1768,16 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot)
|
|||||||
if (bot->InBattleground())
|
if (bot->InBattleground())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<WorldLocation> locs = sTravelMgr.GetCityLocations(bot);
|
if (bot->GetLevel() >= 10 && urand(0, 100) < sPlayerbotAIConfig.probTeleToBankers * 100)
|
||||||
if (!locs.empty())
|
|
||||||
{
|
{
|
||||||
RandomTeleport(bot, locs, true);
|
std::vector<WorldLocation> locs = sTravelMgr.GetCityLocations(bot);
|
||||||
return;
|
if (!locs.empty())
|
||||||
|
{
|
||||||
|
RandomTeleport(bot, locs, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
locs = sTravelMgr.GetTeleportLocations(bot);
|
std::vector<WorldLocation> locs = sTravelMgr.GetTeleportLocations(bot);
|
||||||
if (!locs.empty())
|
if (!locs.empty())
|
||||||
{
|
{
|
||||||
RandomTeleport(bot, locs, false);
|
RandomTeleport(bot, locs, false);
|
||||||
|
|||||||
@ -4419,6 +4419,7 @@ std::vector<std::vector<uint32>> TravelMgr::GetOptimalFlightDestinations(Player*
|
|||||||
bot->GetTeamId());
|
bot->GetTeamId());
|
||||||
if (!fromNode)
|
if (!fromNode)
|
||||||
return validDestinations;
|
return validDestinations;
|
||||||
|
|
||||||
std::vector<WorldLocation> candidateLocations;
|
std::vector<WorldLocation> candidateLocations;
|
||||||
if (bot->GetLevel() >= 10 && urand(0, 100) < sPlayerbotAIConfig.probTeleToBankers * 100)
|
if (bot->GetLevel() >= 10 && urand(0, 100) < sPlayerbotAIConfig.probTeleToBankers * 100)
|
||||||
candidateLocations = GetCityLocations(bot);
|
candidateLocations = GetCityLocations(bot);
|
||||||
@ -4673,6 +4674,31 @@ void TravelMgr::PrepareDestinationCache()
|
|||||||
if (forAlliance)
|
if (forAlliance)
|
||||||
allianceFlightMasterCache[guid] = pos;
|
allianceFlightMasterCache[guid] = pos;
|
||||||
flightMastersCount++;
|
flightMastersCount++;
|
||||||
|
|
||||||
|
// Zones that have flight masters but no innkeepers — use flight master as hub
|
||||||
|
static const std::set<uint32> zonesWithoutInnkeeper = {
|
||||||
|
4, // Blasted Lands (52-57)
|
||||||
|
16, // Azshara (45-52)
|
||||||
|
28, // Western Plaguelands (50-60)
|
||||||
|
46, // Burning Steppes (51-60)
|
||||||
|
51, // Searing Gorge (45-51)
|
||||||
|
361, // Felwood (47-57)
|
||||||
|
490, // Un'Goro Crater (49-56)
|
||||||
|
2817, // Crystalsong Forest (77-80)
|
||||||
|
4197 // Wintergrasp (79-80)
|
||||||
|
};
|
||||||
|
if (zonesWithoutInnkeeper.count(areaId))
|
||||||
|
{
|
||||||
|
LevelBracket bracket = zone2LevelBracket[areaId];
|
||||||
|
WorldPosition loc(mapId, x + cos(orient) * 5.0f, y + sin(orient) * 5.0f, z + 0.5f, orient + M_PI);
|
||||||
|
for (int i = bracket.low; i <= bracket.high; i++)
|
||||||
|
{
|
||||||
|
if (forHorde)
|
||||||
|
hordeHubsPerLevelCache[i].push_back(loc);
|
||||||
|
if (forAlliance)
|
||||||
|
allianceHubsPerLevelCache[i].push_back(loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (creatureTemplate->npcflag & UNIT_NPC_FLAG_INNKEEPER)
|
else if (creatureTemplate->npcflag & UNIT_NPC_FLAG_INNKEEPER)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -595,11 +595,12 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
randomBotHordeRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotHordeRatio", 50);
|
randomBotHordeRatio = sConfigMgr->GetOption<int32>("AiPlayerbot.RandomBotHordeRatio", 50);
|
||||||
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
disableDeathKnightLogin = sConfigMgr->GetOption<bool>("AiPlayerbot.DisableDeathKnightLogin", 0);
|
||||||
limitTalentsExpansion = sConfigMgr->GetOption<bool>("AiPlayerbot.LimitTalentsExpansion", 0);
|
limitTalentsExpansion = sConfigMgr->GetOption<bool>("AiPlayerbot.LimitTalentsExpansion", 0);
|
||||||
botActiveAlone = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAlone", 100);
|
botActiveAlone = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAlone", 10);
|
||||||
|
BotActiveAloneDurationSeconds = sConfigMgr->GetOption<int32>("AiPlayerbot.BotActiveAloneDurationSeconds", 30);
|
||||||
BotActiveAloneForceWhenInRadius = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotActiveAloneForceWhenInRadius", 150);
|
BotActiveAloneForceWhenInRadius = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotActiveAloneForceWhenInRadius", 150);
|
||||||
BotActiveAloneForceWhenInZone = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInZone", 1);
|
BotActiveAloneForceWhenInZone = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInZone", 1);
|
||||||
BotActiveAloneForceWhenInMap = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInMap", 0);
|
BotActiveAloneForceWhenInMap = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInMap", 0);
|
||||||
BotActiveAloneForceWhenIsFriend = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenIsFriend", 1);
|
BotActiveAloneForceWhenIsFriend = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenIsFriend", 0);
|
||||||
BotActiveAloneForceWhenInGuild = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInGuild", 1);
|
BotActiveAloneForceWhenInGuild = sConfigMgr->GetOption<bool>("AiPlayerbot.BotActiveAloneForceWhenInGuild", 1);
|
||||||
botActiveAloneSmartScale = sConfigMgr->GetOption<bool>("AiPlayerbot.botActiveAloneSmartScale", 1);
|
botActiveAloneSmartScale = sConfigMgr->GetOption<bool>("AiPlayerbot.botActiveAloneSmartScale", 1);
|
||||||
botActiveAloneSmartScaleDiffLimitfloor = sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor", 50);
|
botActiveAloneSmartScaleDiffLimitfloor = sConfigMgr->GetOption<uint32>("AiPlayerbot.botActiveAloneSmartScaleDiffLimitfloor", 50);
|
||||||
|
|||||||
@ -334,6 +334,7 @@ public:
|
|||||||
bool disableDeathKnightLogin;
|
bool disableDeathKnightLogin;
|
||||||
bool limitTalentsExpansion;
|
bool limitTalentsExpansion;
|
||||||
uint32 botActiveAlone;
|
uint32 botActiveAlone;
|
||||||
|
uint32 BotActiveAloneDurationSeconds;
|
||||||
uint32 BotActiveAloneForceWhenInRadius;
|
uint32 BotActiveAloneForceWhenInRadius;
|
||||||
bool BotActiveAloneForceWhenInZone;
|
bool BotActiveAloneForceWhenInZone;
|
||||||
bool BotActiveAloneForceWhenInMap;
|
bool BotActiveAloneForceWhenInMap;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user