Compare commits

..

No commits in common. "8cb847db5d3043e59a7a3e4571068ffd48599f9c" and "38caa1daa7399f272267cd6ffc9d2d4f154b7f3e" have entirely different histories.

33 changed files with 126 additions and 4021 deletions

View File

@ -2240,14 +2240,6 @@ AiPlayerbot.CommandPrefix = ""
# Separator for bot chat commands
AiPlayerbot.CommandSeparator = "\\\\"
# Enable automatic item count/trade trigger when a chat message contains
# item-related keywords. When enabled (1), mentioning items in chat
# (e.g. "food", "potion", "ammo") will automatically show inventory and
# open a trade window with the bot. Explicit "c" and "t" commands still
# work regardless of this setting.
# Default: 1 (enabled)
AiPlayerbot.EnableAutoTradeOnItemMention = 1
# Enable bots talking (say / yell / general chatting / lfg)
AiPlayerbot.RandomBotTalk = 1
# Enable bots emoting

View File

@ -143,17 +143,14 @@ bool CastCustomSpellAction::Execute(Event event)
std::ostringstream spellName;
spellName << ChatHelper::FormatSpell(spellInfo) << " on ";
bool const hasItemTarget = itemTarget &&
(spellInfo->Targets & TARGET_FLAG_ITEM || spellInfo->Targets & TARGET_FLAG_GAMEOBJECT_ITEM);
if (bot->GetTrader())
spellName << "trade item";
else if (hasItemTarget)
else if (itemTarget)
spellName << chat->FormatItem(itemTarget->GetTemplate());
else if (target != bot)
spellName << target->GetName();
else
else if (target == bot)
spellName << "self";
else
spellName << target->GetName();
if (!bot->GetTrader() && !botAI->CanCastSpell(spell, target, true, itemTarget))
{

View File

@ -9,36 +9,28 @@
#include "PlayerbotRepository.h"
#include "Playerbots.h"
// Helper function for prefixes used by combat and non-combat strategy commands.
static void HandleStrategyCommon(PlayerbotAI* botAI, std::string const& text, BotState state)
{
std::vector<std::string> splitted = split(text, ',');
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
{
const char* name = i->c_str();
switch (name[0])
{
case '+':
case '-':
case '~':
PlayerbotRepository::instance().Save(botAI);
break;
case '!':
botAI->SelectiveResetStrategies(state);
PlayerbotRepository::instance().Save(botAI);
break;
case '?':
break;
}
}
}
bool ChangeCombatStrategyAction::Execute(Event event)
{
std::string const text = event.getParam();
botAI->ChangeStrategy(text.empty() ? getName() : text, BOT_STATE_COMBAT);
if (event.GetSource() == "co")
HandleStrategyCommon(botAI, text, BOT_STATE_COMBAT);
{
std::vector<std::string> splitted = split(text, ',');
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
{
const char* name = i->c_str();
switch (name[0])
{
case '+':
case '-':
case '~':
PlayerbotRepository::instance().Save(botAI);
break;
case '?':
break;
}
}
}
return true;
}
@ -60,7 +52,23 @@ bool ChangeNonCombatStrategyAction::Execute(Event event)
botAI->ChangeStrategy(text, BOT_STATE_NON_COMBAT);
if (event.GetSource() == "nc")
HandleStrategyCommon(botAI, text, BOT_STATE_NON_COMBAT);
{
std::vector<std::string> splitted = split(text, ',');
for (std::vector<std::string>::iterator i = splitted.begin(); i != splitted.end(); i++)
{
const char* name = i->c_str();
switch (name[0])
{
case '+':
case '-':
case '~':
PlayerbotRepository::instance().Save(botAI);
break;
case '?':
break;
}
}
}
return true;
}

View File

@ -4,11 +4,9 @@
*/
#include "CheckMountStateAction.h"
#include "AreaDefines.h"
#include "BattleGroundTactics.h"
#include "BattlegroundEY.h"
#include "BattlegroundWS.h"
#include "DBCStores.h"
#include "Event.h"
#include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
@ -16,8 +14,6 @@
#include "ServerFacade.h"
#include "SpellAuraEffects.h"
static constexpr uint32 SPELL_COLD_WEATHER_FLYING = 54197;
// Define the static map / init bool for caching bot preferred mount data globally
std::unordered_map<uint32, PreferredMountCache> CheckMountStateAction::mountCache;
bool CheckMountStateAction::preferredMountTableChecked = false;
@ -98,10 +94,9 @@ bool CheckMountStateAction::Execute(Event /*event*/)
}
bool inBattleground = bot->InBattleground();
bool const noRealMaster = (!master || master == bot);
// If there is a master and bot not in BG, follow master's mount state regardless of group leader
if (!noRealMaster && !inBattleground)
if (master && !inBattleground)
{
if (ShouldFollowMasterMountState(master, noAttackers, shouldMount))
return Mount();
@ -115,8 +110,8 @@ bool CheckMountStateAction::Execute(Event /*event*/)
return false;
}
// No real master (random bot or self-bot) OR bot in BG
if ((noRealMaster || inBattleground) && !bot->IsMounted() &&
// If there is no master or bot in BG
if ((!master || inBattleground) && !bot->IsMounted() &&
noAttackers && shouldMount && !bot->IsInCombat())
return Mount();
@ -233,39 +228,6 @@ void CheckMountStateAction::Dismount()
WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
bool const wantsFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
bool const isWaterWalking = bot->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
bool const isFlying = bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
bool const hasGravityDisabled = bot->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
if (!wantsFly && !isWaterWalking && (isFlying || hasGravityDisabled))
{
bot->RemoveUnitMovementFlag(
MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY);
if (!bot->IsRooted())
bot->SendMovementFlagUpdate();
}
}
void CheckMountStateAction::CompleteDismount(Player* bot)
{
if (!bot || !bot->IsInWorld())
return;
float const x = bot->GetPositionX();
float const y = bot->GetPositionY();
float const startZ = bot->GetPositionZ();
float groundZ = startZ;
bot->UpdateAllowedPositionZ(x, y, groundZ);
bot->GetMotionMaster()->MoveFall();
MovementInfo fallInfo = bot->m_movementInfo;
// Need to set the start of the fall, otherwise the fall may start from too high of a Z and kill the bot.
bot->SetFallInformation(0, startZ);
fallInfo.pos.Relocate(x, y, groundZ);
bot->HandleFall(fallInfo);
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING | MOVEMENTFLAG_FALLING_FAR);
}
bool CheckMountStateAction::TryForms(Player* master, int32 masterMountType, int32 masterSpeed) const
@ -472,24 +434,6 @@ bool CheckMountStateAction::ShouldDismountForMaster(Player* master) const
return !isMasterMounted && bot->IsMounted();
}
static bool BotCanUseFlyingMount(Player const* bot)
{
if (bot->GetPureSkillValue(SKILL_RIDING) < 225)
return false;
AreaTableEntry const* area = sAreaTableStore.LookupEntry(bot->GetAreaId());
if (!area || !area->IsFlyable())
return false;
if (area->flags & AREA_FLAG_NO_FLY_ZONE)
return false;
uint32 const vmap = GetVirtualMapForMapAndZone(bot->GetMapId(), bot->GetZoneId());
if (vmap == MAP_NORTHREND && !bot->HasSpell(SPELL_COLD_WEATHER_FLYING))
return false;
return true;
}
int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const MountData& mountData) const
{
// Check riding skill and level requirements
@ -499,10 +443,8 @@ int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const Mou
if (ridingSkill <= 75 && botLevel < static_cast<int32>(sPlayerbotAIConfig.useFastGroundMountAtMinLevel))
return 59;
// check if bot has master and if master is self
bool const noRealMaster = (!master || master == bot);
if (!noRealMaster && !bot->InBattleground())
// If there is a master and bot not in BG, use master's aura effects.
if (master && !bot->InBattleground())
{
auto auraEffects = master->GetAuraEffectsByType(SPELL_AURA_MOUNTED);
if (!auraEffects.empty())
@ -516,27 +458,27 @@ int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const Mou
return 279;
else if (masterInShapeshiftForm == FORM_FLIGHT)
return 149;
return 59; // walk pace
}
else
{
// Bots on their own.
int32 speed = mountData.maxSpeed;
if (bot->InBattleground() && speed > 99)
return 99;
return speed;
}
// No real master OR battleground: pick speed by skill tier.
if (!bot->InBattleground() && BotCanUseFlyingMount(bot))
return (ridingSkill >= 300) ? 279 : 149;
int32 maxGround = (ridingSkill >= 150) ? 99 : 59;
if (bot->InBattleground() && maxGround > 99)
maxGround = 99;
return maxGround;
return 59;
}
uint32 CheckMountStateAction::GetMountType(Player* master) const
{
bool const noRealMaster = (!master || master == bot);
if (noRealMaster)
return (!bot->InBattleground() && BotCanUseFlyingMount(bot)) ? 1 : 0;
if (!master)
return 0;
auto auraEffects = master->GetAuraEffectsByType(SPELL_AURA_MOUNTED);
if (!auraEffects.empty())
{
SpellInfo const* masterSpell = auraEffects.front()->GetSpellInfo();

View File

@ -42,8 +42,6 @@ public:
bool isPossible() override { return true; }
bool Mount();
static void CompleteDismount(Player* bot);
private:
Player* master;
ShapeshiftForm masterInShapeshiftForm;

View File

@ -17,7 +17,7 @@
#include "WorldPacket.h"
#include "Group.h"
#include "Chat.h"
#include "GenericBuffUtils.h"
#include "Ai/Base/Util/GenericBuffUtils.h"
#include "PlayerbotAI.h"
using ai::buff::MakeAuraQualifierForBuff;
@ -134,8 +134,7 @@ bool CastSpellAction::isPossible()
return botAI->CanCastSpell(spell, GetTarget());
}
CastMeleeSpellAction::CastMeleeSpellAction(
PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
{
range = ATTACK_DISTANCE;
}
@ -183,47 +182,56 @@ bool CastAuraSpellAction::isUseful()
return false;
}
CastEnchantItemMainHandAction::CastEnchantItemMainHandAction(
PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell) {}
bool CastEnchantItemMainHandAction::Execute(Event /*event*/)
CastEnchantItemAction::CastEnchantItemAction(PlayerbotAI* botAI, std::string const spell)
: CastSpellAction(botAI, spell)
{
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
return item && botAI->CastSpell(spell, bot, item);
range = botAI->GetRange("spell");
}
bool CastEnchantItemAction::isPossible()
{
// if (!CastSpellAction::isPossible())
// {
// botAI->TellMasterNoFacing("Impossible: " + spell);
// return false;
// }
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
// bool ok = AI_VALUE2(Item*, "item for spell", spellId);
// Item* item = AI_VALUE2(Item*, "item for spell", spellId);
// botAI->TellMasterNoFacing("spell: " + spell + ", spell id: " + std::to_string(spellId) + " item for spell: " +
// std::to_string(ok));
return spellId && AI_VALUE2(Item*, "item for spell", spellId);
}
CastEnchantItemMainHandAction::CastEnchantItemMainHandAction(PlayerbotAI* botAI, std::string const spell)
: CastEnchantItemAction(botAI, spell) {}
bool CastEnchantItemMainHandAction::isPossible()
{
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
if (!item || item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_MISC ||
item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE ||
item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
{
if (!CastEnchantItemAction::isPossible())
return false;
}
return botAI->CanCastSpell(spell, bot, item);
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) : CastSpellAction(botAI, spell) {}
bool CastEnchantItemOffHandAction::Execute(Event /*event*/)
{
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
return item && botAI->CastSpell(spell, bot, item);
}
CastEnchantItemOffHandAction::CastEnchantItemOffHandAction(PlayerbotAI* botAI, std::string const spell)
: CastEnchantItemAction(botAI, spell) {}
bool CastEnchantItemOffHandAction::isPossible()
{
Item* item = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
if (!item || item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_MISC ||
item->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT))
{
if (!CastEnchantItemAction::isPossible())
return false;
}
return botAI->CanCastSpell(spell, bot, item);
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,
@ -237,8 +245,7 @@ bool CastHealingSpellAction::isUseful() { return CastAuraSpellAction::isUseful()
bool CastAoeHealSpellAction::isUseful() { return CastSpellAction::isUseful(); }
CastCureSpellAction::CastCureSpellAction(
PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
CastCureSpellAction::CastCureSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
{
range = botAI->GetRange("heal");
}
@ -260,15 +267,13 @@ bool BuffOnPartyAction::Execute(Event /*event*/)
std::string castName = spell; // default = mono
auto SendGroupRP = ai::chat::MakeGroupAnnouncer(bot);
castName = ai::buff::UpgradeToGroupIfAppropriate(
bot, botAI, castName, /*announceOnMissing=*/true, SendGroupRP);
castName = ai::buff::UpgradeToGroupIfAppropriate(bot, botAI, castName, /*announceOnMissing=*/true, SendGroupRP);
return botAI->CastSpell(castName, GetTarget());
}
// End greater buff fix
CastShootAction::CastShootAction(
PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot"), shootSpellId(0)
CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "shoot"), shootSpellId(0)
{
if (Item* const pItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
{
@ -322,8 +327,7 @@ Value<Unit*>* CastDebuffSpellOnMeleeAttackerAction::GetTargetValue()
return context->GetValue<Unit*>("melee attacker without aura", spell);
}
CastBuffSpellAction::CastBuffSpellAction(
PlayerbotAI* botAI, std::string const spell, bool checkIsOwner, uint32 beforeDuration)
CastBuffSpellAction::CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner, uint32 beforeDuration)
: CastAuraSpellAction(botAI, spell, checkIsOwner, false, beforeDuration)
{
range = botAI->GetRange("spell");
@ -444,8 +448,7 @@ bool UseTrinketAction::UseTrinket(Item* item)
uint32 spellId = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (item->GetTemplate()->Spells[i].SpellId > 0 &&
item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
if (item->GetTemplate()->Spells[i].SpellId > 0 && item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
{
spellId = item->GetTemplate()->Spells[i].SpellId;
const SpellInfo* spellInfo = sSpellMgr->GetSpellInfo(spellId);

View File

@ -121,21 +121,26 @@ public:
std::string const GetTargetName() override { return "self target"; }
};
class CastEnchantItemMainHandAction : public CastSpellAction
class CastEnchantItemAction : public CastSpellAction
{
public:
CastEnchantItemAction(PlayerbotAI* botAI, std::string const spell);
bool isPossible() override;
std::string const GetTargetName() override { return "self target"; }
};
class CastEnchantItemMainHandAction : public CastEnchantItemAction
{
public:
CastEnchantItemMainHandAction(PlayerbotAI* botAI, std::string const spell);
std::string const GetTargetName() override { return "self target"; }
bool Execute(Event event) override;
bool isPossible() override;
};
class CastEnchantItemOffHandAction : public CastSpellAction
class CastEnchantItemOffHandAction : public CastEnchantItemAction
{
public:
CastEnchantItemOffHandAction(PlayerbotAI* botAI, std::string const spell);
std::string const GetTargetName() override { return "self target"; }
bool Execute(Event event) override;
bool isPossible() override;
};

View File

@ -10,31 +10,6 @@
#include "ItemVisitors.h"
#include "Playerbots.h"
namespace
{
bool isReservedQualifier(std::string const& text)
{
static std::array<std::string_view, 13> const exactQualifiers = {
"ammo",
"conjured drink",
"conjured food",
"conjured water",
"drink",
"food",
"healing potion",
"mount",
"mana potion",
"pet",
"quest",
"recipe",
"water"
};
return std::find(exactQualifiers.begin(), exactQualifiers.end(), text) != exactQualifiers.end() ||
text.rfind("usage ", 0) == 0;
}
}
void InventoryAction::IterateItems(IterateItemsVisitor* visitor, IterateItemsMask mask)
{
if (mask & ITERATE_ITEMS_IN_BAGS)
@ -317,12 +292,9 @@ std::vector<Item*> InventoryAction::parseItems(std::string const text, IterateIt
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
}
if (!isReservedQualifier(text))
{
FindNamedItemVisitor visitor(bot, text);
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
}
FindNamedItemVisitor visitor(bot, text);
IterateItems(&visitor, ITERATE_ITEMS_IN_BAGS);
found.insert(visitor.GetResult().begin(), visitor.GetResult().end());
uint32 quality = chat->parseItemQuality(text);
if (quality != MAX_ITEM_QUALITY)

View File

@ -39,8 +39,11 @@ bool LeaveLargeGuildTrigger::IsActive()
Player* leader = ObjectAccessor::FindPlayer(guild->GetLeaderGUID());
// Only leave the guild if the leader is an online bot (not a real player).
PlayerbotAI* leaderBotAI = leader ? GET_PLAYERBOT_AI(leader) : nullptr;
// Only leave the guild if we know the leader is not a real player.
if (!leader || !GET_PLAYERBOT_AI(leader) || !GET_PLAYERBOT_AI(leader)->IsRealPlayer())
return false;
PlayerbotAI* leaderBotAI = GET_PLAYERBOT_AI(leader);
if (!leaderBotAI || leaderBotAI->IsRealPlayer())
return false;

File diff suppressed because it is too large Load Diff

View File

@ -1,277 +0,0 @@
/*
* 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_RAIDHYJALSUMMITACTIONS_H
#define _PLAYERBOT_RAIDHYJALSUMMITACTIONS_H
#include "Action.h"
#include "AttackAction.h"
#include "MovementActions.h"
// General
class HyjalSummitEraseTrackersAction : public Action
{
public:
HyjalSummitEraseTrackersAction(
PlayerbotAI* botAI) : Action(botAI, "hyjal summit erase trackers") {}
bool Execute(Event event) override;
};
// Rage Winterchill
class RageWinterchillMisdirectBossToMainTankAction : public AttackAction
{
public:
RageWinterchillMisdirectBossToMainTankAction(
PlayerbotAI* botAI) : AttackAction(botAI, "rage winterchill misdirect boss to main tank") {}
bool Execute(Event event) override;
};
class RageWinterchillMainTankPositionBossAction : public AttackAction
{
public:
RageWinterchillMainTankPositionBossAction(
PlayerbotAI* botAI) : AttackAction(botAI, "rage winterchill main tank position boss") {}
bool Execute(Event event) override;
};
class RageWinterchillSpreadRangedInCircleAction : public MovementAction
{
public:
RageWinterchillSpreadRangedInCircleAction(
PlayerbotAI* botAI) : MovementAction(botAI, "rage winterchill spread ranged in circle") {}
bool Execute(Event event) override;
};
class RageWinterchillMeleeGetOutOfDeathAndDecayAction : public AttackAction
{
public:
RageWinterchillMeleeGetOutOfDeathAndDecayAction(
PlayerbotAI* botAI) : AttackAction(botAI, "rage winterchill melee get out of death and decay") {}
bool Execute(Event event) override;
};
// Anetheron
class AnetheronMisdirectBossAndInfernalsToTanksAction : public AttackAction
{
public:
AnetheronMisdirectBossAndInfernalsToTanksAction(
PlayerbotAI* botAI) : AttackAction(botAI, "anetheron misdirect boss and infernals to tanks") {}
bool Execute(Event event) override;
};
class AnetheronMainTankPositionBossAction : public AttackAction
{
public:
AnetheronMainTankPositionBossAction(
PlayerbotAI* botAI) : AttackAction(botAI, "anetheron main tank position boss") {}
bool Execute(Event event) override;
};
class AnetheronSpreadRangedInCircleAction : public MovementAction
{
public:
AnetheronSpreadRangedInCircleAction(
PlayerbotAI* botAI) : MovementAction(botAI, "anetheron spread ranged in circle") {}
bool Execute(Event event) override;
};
class AnetheronBringInfernalToInfernalTankAction : public MovementAction
{
public:
AnetheronBringInfernalToInfernalTankAction(
PlayerbotAI* botAI) : MovementAction(botAI, "anetheron bring infernal to infernal tank") {}
bool Execute(Event event) override;
};
class AnetheronFirstAssistTankPickUpInfernalsAction : public AttackAction
{
public:
AnetheronFirstAssistTankPickUpInfernalsAction(
PlayerbotAI* botAI) : AttackAction(botAI, "anetheron first assist tank pick up infernals") {}
bool Execute(Event event) override;
};
class AnetheronAssignDpsPriorityAction : public AttackAction
{
public:
AnetheronAssignDpsPriorityAction(
PlayerbotAI* botAI) : AttackAction(botAI, "anetheron assign dps priority") {}
bool Execute(Event event) override;
};
// Kaz'rogal
class KazrogalMisdirectBossToMainTankAction : public AttackAction
{
public:
KazrogalMisdirectBossToMainTankAction(
PlayerbotAI* botAI) : AttackAction(botAI, "kaz'rogal misdirect boss to main tank") {}
bool Execute(Event event) override;
};
class KazrogalMainTankPositionBossAction : public AttackAction
{
public:
KazrogalMainTankPositionBossAction(
PlayerbotAI* botAI) : AttackAction(botAI, "kaz'rogal main tank position boss") {}
bool Execute(Event event) override;
};
class KazrogalAssistTanksMoveInFrontOfBossAction : public AttackAction
{
public:
KazrogalAssistTanksMoveInFrontOfBossAction(
PlayerbotAI* botAI) : AttackAction(botAI, "kaz'rogal assist tanks move in front of boss") {}
bool Execute(Event event) override;
};
class KazrogalSpreadRangedInArcAction : public MovementAction
{
public:
KazrogalSpreadRangedInArcAction(
PlayerbotAI* botAI) : MovementAction(botAI, "kaz'rogal spread ranged in arc") {}
bool Execute(Event event) override;
};
class KazrogalLowManaBotTakeDefensiveMeasuresAction : public MovementAction
{
public:
KazrogalLowManaBotTakeDefensiveMeasuresAction(
PlayerbotAI* botAI) : MovementAction(botAI, "kaz'rogal low mana bot take defensive measures") {}
bool Execute(Event event) override;
};
class KazrogalCastShadowProtectionSpellAction : public Action
{
public:
KazrogalCastShadowProtectionSpellAction(
PlayerbotAI* botAI) : Action(botAI, "kaz'rogal cast shadow protection spell") {}
bool Execute(Event event) override;
};
// Azgalor
class AzgalorMisdirectBossToMainTankAction : public AttackAction
{
public:
AzgalorMisdirectBossToMainTankAction(
PlayerbotAI* botAI) : AttackAction(botAI, "azgalor misdirect boss to main tank") {}
bool Execute(Event event) override;
};
class AzgalorMainTankPositionBossAction : public AttackAction
{
public:
AzgalorMainTankPositionBossAction(
PlayerbotAI* botAI) : AttackAction(botAI, "azgalor main tank position boss") {}
bool Execute(Event event) override;
};
class AzgalorWaitAtSafePositionAction : public MovementAction
{
public:
AzgalorWaitAtSafePositionAction(
PlayerbotAI* botAI) : MovementAction(botAI, "azgalor wait at safe position") {}
bool Execute(Event event) override;
};
class AzgalorDisperseRangedAction : public MovementAction
{
public:
AzgalorDisperseRangedAction(
PlayerbotAI* botAI) : MovementAction(botAI, "azgalor disperse ranged") {}
bool Execute(Event event) override;
};
class AzgalorMeleeGetOutOfFireAndSwapTargetsAction : public AttackAction
{
public:
AzgalorMeleeGetOutOfFireAndSwapTargetsAction(
PlayerbotAI* botAI) : AttackAction(botAI, "azgalor melee get out of fire and swap targets") {}
bool Execute(Event event) override;
};
class AzgalorMoveToDoomguardTankAction : public MovementAction
{
public:
AzgalorMoveToDoomguardTankAction(
PlayerbotAI* botAI) : MovementAction(botAI, "azgalor move to doomguard tank") {}
bool Execute(Event event) override;
};
class AzgalorFirstAssistTankPositionDoomguardAction : public AttackAction
{
public:
AzgalorFirstAssistTankPositionDoomguardAction(
PlayerbotAI* botAI) : AttackAction(botAI, "azgalor first assist tank position doomguard") {}
bool Execute(Event event) override;
};
class AzgalorRangedDpsPrioritizeDoomguardsAction : public AttackAction
{
public:
AzgalorRangedDpsPrioritizeDoomguardsAction(
PlayerbotAI* botAI) : AttackAction(botAI, "azgalor ranged dps prioritize doomguards") {}
bool Execute(Event event) override;
};
// Archimonde
class ArchimondeMisdirectBossToMainTankAction : public AttackAction
{
public:
ArchimondeMisdirectBossToMainTankAction(
PlayerbotAI* botAI) : AttackAction(botAI, "archimonde misdirect boss to main tank") {}
bool Execute(Event event) override;
};
class ArchimondeMoveBossToInitialPositionAction : public AttackAction
{
public:
ArchimondeMoveBossToInitialPositionAction(
PlayerbotAI* botAI) : AttackAction(botAI, "archimonde move boss to initial position") {}
bool Execute(Event event) override;
};
class ArchimondeCastFearImmunitySpellAction : public Action
{
public:
ArchimondeCastFearImmunitySpellAction(
PlayerbotAI* botAI) : Action(botAI, "archimonde cast fear immunity spell") {}
bool Execute(Event event) override;
private:
bool CastFearWardOnMainTank();
bool UseTremorTotemStrategy();
};
class ArchimondeSpreadToAvoidAirBurstAction : public MovementAction
{
public:
ArchimondeSpreadToAvoidAirBurstAction(
PlayerbotAI* botAI) : MovementAction(botAI, "archimonde spread to avoid air burst") {}
bool Execute(Event event) override;
};
class ArchimondeAvoidDoomfireAction : public MovementAction
{
public:
ArchimondeAvoidDoomfireAction(
PlayerbotAI* botAI) : MovementAction(botAI, "archimonde avoid doomfire") {}
bool Execute(Event event) override;
};
class ArchimondeRemoveDoomfireDotAction : public Action
{
public:
ArchimondeRemoveDoomfireDotAction(
PlayerbotAI* botAI) : Action(botAI, "archimonde remove doomfire dot") {}
bool Execute(Event event) override;
};
#endif

View File

@ -1,295 +0,0 @@
/*
* 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 "RaidHyjalSummitMultipliers.h"
#include "RaidHyjalSummitActions.h"
#include "RaidHyjalSummitHelpers.h"
#include "AiFactory.h"
#include "ChooseTargetActions.h"
#include "DKActions.h"
#include "DruidBearActions.h"
#include "HunterActions.h"
#include "PaladinActions.h"
#include "RaidBossHelpers.h"
#include "ReachTargetActions.h"
#include "ShamanActions.h"
#include "WarriorActions.h"
using namespace HyjalSummitHelpers;
// Without this multiplier, Bloodlust/Heroism will not be available for
// bosses because it will be used on cooldown during trash waves
float HyjalSummitTimeBloodlustAndHeroismMultiplier::GetValue(Action* action)
{
if (bot->getClass() != CLASS_SHAMAN)
return 1.0f;
if (dynamic_cast<CastBloodlustAction*>(action) ||
dynamic_cast<CastHeroismAction*>(action))
{
Unit* archimonde = AI_VALUE2(Unit*, "find target", "archimonde");
if (archimonde && archimonde->GetHealthPct() < 90.0f)
return 1.0f;
Unit* azgalor = AI_VALUE2(Unit*, "find target", "azgalor");
if (azgalor && azgalor->GetHealthPct() < 90.0f)
return 1.0f;
Unit* kazrogal = AI_VALUE2(Unit*, "find target", "kaz'rogal");
if (kazrogal && kazrogal->GetHealthPct() < 90.0f)
return 1.0f;
Unit* anetheron = AI_VALUE2(Unit*, "find target", "anetheron");
if (anetheron && anetheron->GetHealthPct() < 85.0f)
return 1.0f;
Unit* winterchill = AI_VALUE2(Unit*, "find target", "rage winterchill");
if (winterchill && winterchill->GetHealthPct() < 90.0f)
return 1.0f;
return 0.0f;
}
return 1.0f;
}
// Rage Winterchill
float RageWinterchillDisableCombatFormationMoveMultiplier::GetValue(Action* action)
{
if (!AI_VALUE2(Unit*, "find target", "rage winterchill"))
return 1.0f;
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
!dynamic_cast<SetBehindTargetAction*>(action))
return 0.0f;
return 1.0f;
}
float RageWinterchillMeleeControlAvoidanceMultiplier::GetValue(Action* action)
{
if (botAI->IsRanged(bot))
return 1.0f;
Unit* winterchill = AI_VALUE2(Unit*, "find target", "rage winterchill");
if (!winterchill)
return 1.0f;
if (IsInDeathAndDecay(bot, DEATH_AND_DECAY_SAFE_RADIUS + 2.0f))
{
if (dynamic_cast<AvoidAoeAction*>(action))
return 0.0f;
if (botAI->IsMainTank(bot) || winterchill->GetVictim() == bot)
return 1.0f;
if (dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<RageWinterchillMeleeGetOutOfDeathAndDecayAction*>(action))
return 0.0f;
if (dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
}
return 1.0f;
}
// Anetheron
float AnetheronDisableTankActionsMultiplier::GetValue(Action* action)
{
if (!botAI->IsTank(bot) || !AI_VALUE2(Unit*, "find target", "anetheron"))
return 1.0f;
if (dynamic_cast<AvoidAoeAction*>(action))
return 0.0f;
if (bot->GetVictim() != nullptr &&
dynamic_cast<TankAssistAction*>(action))
return 0.0f;
return 1.0f;
}
float AnetheronDisableCombatFormationMoveMultiplier::GetValue(Action* action)
{
if (!AI_VALUE2(Unit*, "find target", "anetheron"))
return 1.0f;
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
!dynamic_cast<SetBehindTargetAction*>(action))
return 0.0f;
return 1.0f;
}
float AnetheronControlMisdirectionMultiplier::GetValue(Action* action)
{
if (bot->getClass() != CLASS_HUNTER ||
!AI_VALUE2(Unit*, "find target", "anetheron"))
return 1.0f;
if (dynamic_cast<CastMisdirectionOnMainTankAction*>(action))
return 0.0f;
return 1.0f;
}
// Kaz'rogal
float KazrogalLowManaBotStayAwayFromGroupMultiplier::GetValue(Action* action)
{
if (bot->getClass() == CLASS_WARRIOR || bot->getClass() == CLASS_ROGUE ||
bot->getClass() == CLASS_DEATH_KNIGHT || bot->getClass() == CLASS_HUNTER)
return 1.0f;
uint8 tab = AiFactory::GetPlayerSpecTab(bot);
if (bot->getClass() == CLASS_DRUID && tab == DRUID_TAB_FERAL)
return 1.0f;
if (!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return 1.0f;
if (!isBelowManaThreshold.count(bot->GetGUID()))
return 1.0f;
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
(dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<AttackAction*>(action) &&
!dynamic_cast<KazrogalLowManaBotTakeDefensiveMeasuresAction*>(action)))
return 0.0f;
return 1.0f;
}
float KazrogalKeepAspectOfTheViperActiveMultiplier::GetValue(Action* action)
{
if (bot->getClass() != CLASS_HUNTER || bot->GetPower(POWER_MANA) > 4000 ||
!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return 1.0f;
if (dynamic_cast<CastAspectOfTheHawkAction*>(action) ||
dynamic_cast<CastAspectOfTheWildAction*>(action) ||
dynamic_cast<CastAspectOfTheDragonhawkAction*>(action) ||
dynamic_cast<CastAspectOfTheCheetahAction*>(action) ||
dynamic_cast<CastAspectOfThePackAction*>(action) ||
dynamic_cast<CastAspectOfTheMonkeyAction*>(action))
return 0.0f;
return 1.0f;
}
float KazrogalControlMovementMultiplier::GetValue(Action* action)
{
if (!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return 1.0f;
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
!dynamic_cast<SetBehindTargetAction*>(action))
return 0.0f;
if (dynamic_cast<FleeAction*>(action))
return 0.0f;
if (botAI->IsRanged(bot) && dynamic_cast<ReachTargetAction*>(action))
return 0.0f;
return 1.0f;
}
// Azgalor
float AzgalorDisableTankActionsMultiplier::GetValue(Action* action)
{
if (bot->GetVictim() == nullptr)
return 1.0f;
if (!botAI->IsTank(bot) || !AI_VALUE2(Unit*, "find target", "azgalor"))
return 1.0f;
if (dynamic_cast<TankFaceAction*>(action))
return 0.0f;
if (dynamic_cast<TankAssistAction*>(action) || dynamic_cast<AvoidAoeAction*>(action))
{
if (botAI->IsMainTank(bot))
{
return 0.0f;
}
else if (botAI->IsAssistTank(bot) && (AnyGroupMemberHasDoom(bot) ||
AI_VALUE2(Unit*, "find target", "lesser doomguard")))
{
return 0.0f;
}
}
return 1.0f;
}
float AzgalorDoomedBotPrioritizePositioningMultiplier::GetValue(Action* action)
{
if (!bot->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOM)))
return 1.0f;
if (dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<AttackAction*>(action) &&
!dynamic_cast<AvoidAoeAction*>(action) &&
!dynamic_cast<AzgalorMoveToDoomguardTankAction*>(action))
return 0.0f;
return 1.0f;
}
float AzgalorMeleeDpsControlAvoidanceMultiplier::GetValue(Action* action)
{
if (botAI->IsRanged(bot) || botAI->IsTank(bot))
return 1.0f;
Unit* azgalor = AI_VALUE2(Unit*, "find target", "azgalor");
if (!azgalor)
return 1.0f;
constexpr float singleTickMoveAwayDist = 6.0f;
if (IsInRainOfFire(bot, RAIN_OF_FIRE_RADIUS + singleTickMoveAwayDist))
{
if (dynamic_cast<AvoidAoeAction*>(action) ||
dynamic_cast<CastReachTargetSpellAction*>(action))
return 0.0f;
if (dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<AzgalorMeleeGetOutOfFireAndSwapTargetsAction*>(action))
return 0.0f;
}
Player* mainTank = GetGroupMainTank(botAI, bot);
if (!mainTank || !GET_PLAYERBOT_AI(mainTank))
return 1.0f;
TankPositionState tankState = GetAzgalorTankPositionState(botAI, bot);
if ((tankState == TankPositionState::Unknown ||
tankState == TankPositionState::MovingToTransition) &&
dynamic_cast<MovementAction*>(action) &&
!dynamic_cast<AzgalorWaitAtSafePositionAction*>(action))
{
return 0.0f;
}
return 1.0f;
}
// Archimonde
float ArchimondeDisableCombatFormationMoveMultiplier::GetValue(Action* action)
{
if (!AI_VALUE2(Unit*, "find target", "archimonde"))
return 1.0f;
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
!dynamic_cast<SetBehindTargetAction*>(action))
return 0.0f;
return 1.0f;
}

View File

@ -1,125 +0,0 @@
/*
* 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_RAIDHYJALSUMMITMULTIPLIERS_H
#define _PLAYERBOT_RAIDHYJALSUMMITMULTIPLIERS_H
#include "Multiplier.h"
class HyjalSummitTimeBloodlustAndHeroismMultiplier : public Multiplier
{
public:
HyjalSummitTimeBloodlustAndHeroismMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "hyjal summit time bloodlust and heroism multiplier") {}
virtual float GetValue(Action* action);
};
// Rage Winterchill
class RageWinterchillDisableCombatFormationMoveMultiplier : public Multiplier
{
public:
RageWinterchillDisableCombatFormationMoveMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "rage winterchill disable combat formation move multiplier") {}
virtual float GetValue(Action* action);
};
class RageWinterchillMeleeControlAvoidanceMultiplier : public Multiplier
{
public:
RageWinterchillMeleeControlAvoidanceMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "rage winterchill melee control avoidance multiplier") {}
virtual float GetValue(Action* action);
};
// Anetheron
class AnetheronDisableTankActionsMultiplier : public Multiplier
{
public:
AnetheronDisableTankActionsMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "anetheron disable tank actions multiplier") {}
virtual float GetValue(Action* action);
};
class AnetheronDisableCombatFormationMoveMultiplier : public Multiplier
{
public:
AnetheronDisableCombatFormationMoveMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "anetheron disable combat formation move multiplier") {}
virtual float GetValue(Action* action);
};
class AnetheronControlMisdirectionMultiplier : public Multiplier
{
public:
AnetheronControlMisdirectionMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "anetheron control misdirection multiplier") {}
virtual float GetValue(Action* action);
};
// Kaz'rogal
class KazrogalLowManaBotStayAwayFromGroupMultiplier : public Multiplier
{
public:
KazrogalLowManaBotStayAwayFromGroupMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "kaz'rogal low mana bot stay away from group multiplier") {}
virtual float GetValue(Action* action);
};
class KazrogalKeepAspectOfTheViperActiveMultiplier : public Multiplier
{
public:
KazrogalKeepAspectOfTheViperActiveMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "kaz'rogal keep aspect of the viper active multiplier") {}
virtual float GetValue(Action* action);
};
class KazrogalControlMovementMultiplier : public Multiplier
{
public:
KazrogalControlMovementMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "kaz'rogal control movement multiplier") {}
virtual float GetValue(Action* action);
};
// Azgalor
class AzgalorDisableTankActionsMultiplier : public Multiplier
{
public:
AzgalorDisableTankActionsMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "azgalor disable tank actions multiplier") {}
virtual float GetValue(Action* action);
};
class AzgalorDoomedBotPrioritizePositioningMultiplier : public Multiplier
{
public:
AzgalorDoomedBotPrioritizePositioningMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "azgalor doomed bot prioritize positioning multiplier") {}
virtual float GetValue(Action* action);
};
class AzgalorMeleeDpsControlAvoidanceMultiplier : public Multiplier
{
public:
AzgalorMeleeDpsControlAvoidanceMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "azgalor melee dps control avoidance multiplier") {}
virtual float GetValue(Action* action);
};
// Archimonde
class ArchimondeDisableCombatFormationMoveMultiplier : public Multiplier
{
public:
ArchimondeDisableCombatFormationMoveMultiplier(
PlayerbotAI* botAI) : Multiplier(botAI, "archimonde disable combat formation move multiplier") {}
virtual float GetValue(Action* action);
};
#endif

View File

@ -1,218 +0,0 @@
/*
* 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_RAIDHYJALSUMMITACTIONCONTEXT_H
#define _PLAYERBOT_RAIDHYJALSUMMITACTIONCONTEXT_H
#include "RaidHyjalSummitActions.h"
#include "NamedObjectContext.h"
class RaidHyjalSummitActionContext : public NamedObjectContext<Action>
{
public:
RaidHyjalSummitActionContext()
{
// General
creators["hyjal summit erase trackers"] =
&RaidHyjalSummitActionContext::hyjal_summit_erase_trackers;
// Rage Winterchill
creators["rage winterchill misdirect boss to main tank"] =
&RaidHyjalSummitActionContext::rage_winterchill_misdirect_boss_to_main_tank;
creators["rage winterchill main tank position boss"] =
&RaidHyjalSummitActionContext::rage_winterchill_main_tank_position_boss;
creators["rage winterchill spread ranged in circle"] =
&RaidHyjalSummitActionContext::rage_winterchill_spread_ranged_in_circle;
creators["rage winterchill melee get out of death and decay"] =
&RaidHyjalSummitActionContext::rage_winterchill_melee_get_out_of_death_and_decay;
// Anetheron
creators["anetheron misdirect boss and infernals to tanks"] =
&RaidHyjalSummitActionContext::anetheron_misdirect_boss_and_infernals_to_tanks;
creators["anetheron main tank position boss"] =
&RaidHyjalSummitActionContext::anetheron_main_tank_position_boss;
creators["anetheron spread ranged in circle"] =
&RaidHyjalSummitActionContext::anetheron_spread_ranged_in_circle;
creators["anetheron bring infernal to infernal tank"] =
&RaidHyjalSummitActionContext::anetheron_bring_infernal_to_infernal_tank;
creators["anetheron first assist tank pick up infernals"] =
&RaidHyjalSummitActionContext::anetheron_first_assist_tank_pick_up_infernals;
creators["anetheron assign dps priority"] =
&RaidHyjalSummitActionContext::anetheron_assign_dps_priority;
// Kaz'rogal
creators["kaz'rogal misdirect boss to main tank"] =
&RaidHyjalSummitActionContext::kazrogal_misdirect_boss_to_main_tank;
creators["kaz'rogal main tank position boss"] =
&RaidHyjalSummitActionContext::kazrogal_main_tank_position_boss;
creators["kaz'rogal assist tanks move in front of boss"] =
&RaidHyjalSummitActionContext::kazrogal_assist_tanks_move_in_front_of_boss;
creators["kaz'rogal spread ranged in arc"] =
&RaidHyjalSummitActionContext::kazrogal_spread_ranged_in_arc;
creators["kaz'rogal low mana bot take defensive measures"] =
&RaidHyjalSummitActionContext::kazrogal_low_mana_bot_take_defensive_measures;
creators["kaz'rogal cast shadow protection spell"] =
&RaidHyjalSummitActionContext::kazrogal_cast_shadow_protection_spell;
// Azgalor
creators["azgalor misdirect boss to main tank"] =
&RaidHyjalSummitActionContext::azgalor_misdirect_boss_to_main_tank;
creators["azgalor main tank position boss"] =
&RaidHyjalSummitActionContext::azgalor_main_tank_position_boss;
creators["azgalor wait at safe position"] =
&RaidHyjalSummitActionContext::azgalor_wait_at_safe_position;
creators["azgalor disperse ranged"] =
&RaidHyjalSummitActionContext::azgalor_disperse_ranged;
creators["azgalor melee get out of fire and swap targets"] =
&RaidHyjalSummitActionContext::azgalor_melee_get_out_of_fire_and_swap_targets;
creators["azgalor move to doomguard tank"] =
&RaidHyjalSummitActionContext::azgalor_move_to_doomguard_tank;
creators["azgalor first assist tank position doomguard"] =
&RaidHyjalSummitActionContext::azgalor_first_assist_tank_position_doomguard;
creators["azgalor ranged dps prioritize doomguards"] =
&RaidHyjalSummitActionContext::azgalor_ranged_dps_prioritize_doomguards;
// Archimonde
creators["archimonde misdirect boss to main tank"] =
&RaidHyjalSummitActionContext::archimonde_misdirect_boss_to_main_tank;
creators["archimonde move boss to initial position"] =
&RaidHyjalSummitActionContext::archimonde_move_boss_to_initial_position;
creators["archimonde cast fear immunity spell"] =
&RaidHyjalSummitActionContext::archimonde_cast_fear_immunity_spell;
creators["archimonde spread to avoid air burst"] =
&RaidHyjalSummitActionContext::archimonde_spread_to_avoid_air_burst;
creators["archimonde avoid doomfire"] =
&RaidHyjalSummitActionContext::archimonde_avoid_doomfire;
creators["archimonde remove doomfire dot"] =
&RaidHyjalSummitActionContext::archimonde_remove_doomfire_dot;
}
private:
// General
static Action* hyjal_summit_erase_trackers(
PlayerbotAI* botAI) { return new HyjalSummitEraseTrackersAction(botAI); }
// Rage Winterchill
static Action* rage_winterchill_misdirect_boss_to_main_tank(
PlayerbotAI* botAI) { return new RageWinterchillMisdirectBossToMainTankAction(botAI); }
static Action* rage_winterchill_main_tank_position_boss(
PlayerbotAI* botAI) { return new RageWinterchillMainTankPositionBossAction(botAI); }
static Action* rage_winterchill_spread_ranged_in_circle(
PlayerbotAI* botAI) { return new RageWinterchillSpreadRangedInCircleAction(botAI); }
static Action* rage_winterchill_melee_get_out_of_death_and_decay(
PlayerbotAI* botAI) { return new RageWinterchillMeleeGetOutOfDeathAndDecayAction(botAI); }
// Anetheron
static Action* anetheron_misdirect_boss_and_infernals_to_tanks(
PlayerbotAI* botAI) { return new AnetheronMisdirectBossAndInfernalsToTanksAction(botAI); }
static Action* anetheron_main_tank_position_boss(
PlayerbotAI* botAI) { return new AnetheronMainTankPositionBossAction(botAI); }
static Action* anetheron_spread_ranged_in_circle(
PlayerbotAI* botAI) { return new AnetheronSpreadRangedInCircleAction(botAI); }
static Action* anetheron_bring_infernal_to_infernal_tank(
PlayerbotAI* botAI) { return new AnetheronBringInfernalToInfernalTankAction(botAI); }
static Action* anetheron_first_assist_tank_pick_up_infernals(
PlayerbotAI* botAI) { return new AnetheronFirstAssistTankPickUpInfernalsAction(botAI); }
static Action* anetheron_assign_dps_priority(
PlayerbotAI* botAI) { return new AnetheronAssignDpsPriorityAction(botAI); }
// Kaz'rogal
static Action* kazrogal_misdirect_boss_to_main_tank(
PlayerbotAI* botAI) { return new KazrogalMisdirectBossToMainTankAction(botAI); }
static Action* kazrogal_main_tank_position_boss(
PlayerbotAI* botAI) { return new KazrogalMainTankPositionBossAction(botAI); }
static Action* kazrogal_assist_tanks_move_in_front_of_boss(
PlayerbotAI* botAI) { return new KazrogalAssistTanksMoveInFrontOfBossAction(botAI); }
static Action* kazrogal_spread_ranged_in_arc(
PlayerbotAI* botAI) { return new KazrogalSpreadRangedInArcAction(botAI); }
static Action* kazrogal_low_mana_bot_take_defensive_measures(
PlayerbotAI* botAI) { return new KazrogalLowManaBotTakeDefensiveMeasuresAction(botAI); }
static Action* kazrogal_cast_shadow_protection_spell(
PlayerbotAI* botAI) { return new KazrogalCastShadowProtectionSpellAction(botAI); }
// Azgalor
static Action* azgalor_misdirect_boss_to_main_tank(
PlayerbotAI* botAI) { return new AzgalorMisdirectBossToMainTankAction(botAI); }
static Action* azgalor_main_tank_position_boss(
PlayerbotAI* botAI) { return new AzgalorMainTankPositionBossAction(botAI); }
static Action* azgalor_wait_at_safe_position(
PlayerbotAI* botAI) { return new AzgalorWaitAtSafePositionAction(botAI); }
static Action* azgalor_disperse_ranged(
PlayerbotAI* botAI) { return new AzgalorDisperseRangedAction(botAI); }
static Action* azgalor_melee_get_out_of_fire_and_swap_targets(
PlayerbotAI* botAI) { return new AzgalorMeleeGetOutOfFireAndSwapTargetsAction(botAI); }
static Action* azgalor_move_to_doomguard_tank(
PlayerbotAI* botAI) { return new AzgalorMoveToDoomguardTankAction(botAI); }
static Action* azgalor_first_assist_tank_position_doomguard(
PlayerbotAI* botAI) { return new AzgalorFirstAssistTankPositionDoomguardAction(botAI); }
static Action* azgalor_ranged_dps_prioritize_doomguards(
PlayerbotAI* botAI) { return new AzgalorRangedDpsPrioritizeDoomguardsAction(botAI); }
// Archimonde
static Action* archimonde_misdirect_boss_to_main_tank(
PlayerbotAI* botAI) { return new ArchimondeMisdirectBossToMainTankAction(botAI); }
static Action* archimonde_move_boss_to_initial_position(
PlayerbotAI* botAI) { return new ArchimondeMoveBossToInitialPositionAction(botAI); }
static Action* archimonde_cast_fear_immunity_spell(
PlayerbotAI* botAI) { return new ArchimondeCastFearImmunitySpellAction(botAI); }
static Action* archimonde_spread_to_avoid_air_burst(
PlayerbotAI* botAI) { return new ArchimondeSpreadToAvoidAirBurstAction(botAI); }
static Action* archimonde_avoid_doomfire(
PlayerbotAI* botAI) { return new ArchimondeAvoidDoomfireAction(botAI); }
static Action* archimonde_remove_doomfire_dot(
PlayerbotAI* botAI) { return new ArchimondeRemoveDoomfireDotAction(botAI); }
};
#endif

View File

@ -1,218 +0,0 @@
/*
* 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_RAIDHYJALSUMMITTRIGGERCONTEXT_H
#define _PLAYERBOT_RAIDHYJALSUMMITTRIGGERCONTEXT_H
#include "RaidHyjalSummitTriggers.h"
#include "NamedObjectContext.h"
class RaidHyjalSummitTriggerContext : public NamedObjectContext<Trigger>
{
public:
RaidHyjalSummitTriggerContext()
{
// General
creators["hyjal summit bot is not in combat"] =
&RaidHyjalSummitTriggerContext::hyjal_summit_bot_is_not_in_combat;
// Rage Winterchill
creators["rage winterchill pulling boss"] =
&RaidHyjalSummitTriggerContext::rage_winterchill_pulling_boss;
creators["rage winterchill boss engaged by main tank"] =
&RaidHyjalSummitTriggerContext::rage_winterchill_boss_engaged_by_main_tank;
creators["rage winterchill boss casts death and decay on ranged"] =
&RaidHyjalSummitTriggerContext::rage_winterchill_boss_casts_death_and_decay_on_ranged;
creators["rage winterchill melee is standing in death and decay"] =
&RaidHyjalSummitTriggerContext::rage_winterchill_melee_is_standing_in_death_and_decay;
// Anetheron
creators["anetheron pulling boss or infernal"] =
&RaidHyjalSummitTriggerContext::anetheron_pulling_boss_or_infernal;
creators["anetheron boss engaged by main tank"] =
&RaidHyjalSummitTriggerContext::anetheron_boss_engaged_by_main_tank;
creators["anetheron boss casts carrion swarm"] =
&RaidHyjalSummitTriggerContext::anetheron_boss_casts_carrion_swarm;
creators["anetheron bot is targeted by infernal"] =
&RaidHyjalSummitTriggerContext::anetheron_bot_is_targeted_by_infernal;
creators["anetheron infernals need to be kept away from raid"] =
&RaidHyjalSummitTriggerContext::anetheron_infernals_need_to_be_kept_away_from_raid;
creators["anetheron infernals continue to spawn"] =
&RaidHyjalSummitTriggerContext::anetheron_infernals_continue_to_spawn;
// Kaz'rogal
creators["kaz'rogal pulling boss"] =
&RaidHyjalSummitTriggerContext::kazrogal_pulling_boss;
creators["kaz'rogal boss engaged by main tank"] =
&RaidHyjalSummitTriggerContext::kazrogal_boss_engaged_by_main_tank;
creators["kaz'rogal boss engaged by assist tanks"] =
&RaidHyjalSummitTriggerContext::kazrogal_boss_engaged_by_assist_tanks;
creators["kaz'rogal bot is low on mana"] =
&RaidHyjalSummitTriggerContext::kazrogal_bot_is_low_on_mana;
creators["kaz'rogal low mana bots need escape path"] =
&RaidHyjalSummitTriggerContext::kazrogal_low_mana_bots_need_escape_path;
creators["kaz'rogal mark deals shadow damage"] =
&RaidHyjalSummitTriggerContext::kazrogal_mark_deals_shadow_damage;
// Azgalor
creators["azgalor pulling boss"] =
&RaidHyjalSummitTriggerContext::azgalor_pulling_boss;
creators["azgalor boss engaged by main tank"] =
&RaidHyjalSummitTriggerContext::azgalor_boss_engaged_by_main_tank;
creators["azgalor main tank is positioning boss"] =
&RaidHyjalSummitTriggerContext::azgalor_main_tank_is_positioning_boss;
creators["azgalor boss engaged by ranged"] =
&RaidHyjalSummitTriggerContext::azgalor_boss_engaged_by_ranged;
creators["azgalor boss casts rain of fire on melee"] =
&RaidHyjalSummitTriggerContext::azgalor_boss_casts_rain_of_fire_on_melee;
creators["azgalor bot is doomed"] =
&RaidHyjalSummitTriggerContext::azgalor_bot_is_doomed;
creators["azgalor doomguards must be controlled"] =
&RaidHyjalSummitTriggerContext::azgalor_doomguards_must_be_controlled;
creators["azgalor doomguards must die"] =
&RaidHyjalSummitTriggerContext::azgalor_doomguards_must_die;
// Archimonde
creators["archimonde pulling boss"] =
&RaidHyjalSummitTriggerContext::archimonde_pulling_boss;
creators["archimonde boss engaged by main tank"] =
&RaidHyjalSummitTriggerContext::archimonde_boss_engaged_by_main_tank;
creators["archimonde boss casts fear"] =
&RaidHyjalSummitTriggerContext::archimonde_boss_casts_fear;
creators["archimonde boss casts air burst"] =
&RaidHyjalSummitTriggerContext::archimonde_boss_casts_air_burst;
creators["archimonde boss summoned doomfire"] =
&RaidHyjalSummitTriggerContext::archimonde_boss_summoned_doomfire;
creators["archimonde bot stood in doomfire"] =
&RaidHyjalSummitTriggerContext::archimonde_bot_stood_in_doomfire;
}
private:
// General
static Trigger* hyjal_summit_bot_is_not_in_combat(
PlayerbotAI* botAI) { return new HyjalSummitBotIsNotInCombatTrigger(botAI); }
// Rage Winterchill
static Trigger* rage_winterchill_pulling_boss(
PlayerbotAI* botAI) { return new RageWinterchillPullingBossTrigger(botAI); }
static Trigger* rage_winterchill_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new RageWinterchillBossEngagedByMainTankTrigger(botAI); }
static Trigger* rage_winterchill_boss_casts_death_and_decay_on_ranged(
PlayerbotAI* botAI) { return new RageWinterchillBossCastsDeathAndDecayOnRangedTrigger(botAI); }
static Trigger* rage_winterchill_melee_is_standing_in_death_and_decay(
PlayerbotAI* botAI) { return new RageWinterchillMeleeIsStandingInDeathAndDecayTrigger(botAI); }
// Anetheron
static Trigger* anetheron_pulling_boss_or_infernal(
PlayerbotAI* botAI) { return new AnetheronPullingBossOrInfernalTrigger(botAI); }
static Trigger* anetheron_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new AnetheronBossEngagedByMainTankTrigger(botAI); }
static Trigger* anetheron_boss_casts_carrion_swarm(
PlayerbotAI* botAI) { return new AnetheronBossCastsCarrionSwarmTrigger(botAI); }
static Trigger* anetheron_bot_is_targeted_by_infernal(
PlayerbotAI* botAI) { return new AnetheronBotIsTargetedByInfernalTrigger(botAI); }
static Trigger* anetheron_infernals_need_to_be_kept_away_from_raid(
PlayerbotAI* botAI) { return new AnetheronInfernalsNeedToBeKeptAwayFromRaidTrigger(botAI); }
static Trigger* anetheron_infernals_continue_to_spawn(
PlayerbotAI* botAI) { return new AnetheronInfernalsContinueToSpawnTrigger(botAI); }
// Kaz'rogal
static Trigger* kazrogal_pulling_boss(
PlayerbotAI* botAI) { return new KazrogalPullingBossTrigger(botAI); }
static Trigger* kazrogal_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new KazrogalBossEngagedByMainTankTrigger(botAI); }
static Trigger* kazrogal_boss_engaged_by_assist_tanks(
PlayerbotAI* botAI) { return new KazrogalBossEngagedByAssistTanksTrigger(botAI); }
static Trigger* kazrogal_low_mana_bots_need_escape_path(
PlayerbotAI* botAI) { return new KazrogalLowManaBotsNeedEscapePathTrigger(botAI); }
static Trigger* kazrogal_bot_is_low_on_mana(
PlayerbotAI* botAI) { return new KazrogalBotIsLowOnManaTrigger(botAI); }
static Trigger* kazrogal_mark_deals_shadow_damage(
PlayerbotAI* botAI) { return new KazrogalMarkDealsShadowDamageTrigger(botAI); }
// Azgalor
static Trigger* azgalor_pulling_boss(
PlayerbotAI* botAI) { return new AzgalorPullingBossTrigger(botAI); }
static Trigger* azgalor_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new AzgalorBossEngagedByMainTankTrigger(botAI); }
static Trigger* azgalor_main_tank_is_positioning_boss(
PlayerbotAI* botAI) { return new AzgalorMainTankIsPositioningBossTrigger(botAI); }
static Trigger* azgalor_boss_engaged_by_ranged(
PlayerbotAI* botAI) { return new AzgalorBossEngagedByRangedTrigger(botAI); }
static Trigger* azgalor_boss_casts_rain_of_fire_on_melee(
PlayerbotAI* botAI) { return new AzgalorBossCastsRainOfFireOnMeleeTrigger(botAI); }
static Trigger* azgalor_bot_is_doomed(
PlayerbotAI* botAI) { return new AzgalorBotIsDoomedTrigger(botAI); }
static Trigger* azgalor_doomguards_must_be_controlled(
PlayerbotAI* botAI) { return new AzgalorDoomguardsMustBeControlledTrigger(botAI); }
static Trigger* azgalor_doomguards_must_die(
PlayerbotAI* botAI) { return new AzgalorDoomguardsMustDieTrigger(botAI); }
// Archimonde
static Trigger* archimonde_pulling_boss(
PlayerbotAI* botAI) { return new ArchimondePullingBossTrigger(botAI); }
static Trigger* archimonde_boss_engaged_by_main_tank(
PlayerbotAI* botAI) { return new ArchimondeBossEngagedByMainTankTrigger(botAI); }
static Trigger* archimonde_boss_casts_fear(
PlayerbotAI* botAI) { return new ArchimondeBossCastsFearTrigger(botAI); }
static Trigger* archimonde_boss_casts_air_burst(
PlayerbotAI* botAI) { return new ArchimondeBossCastsAirBurstTrigger(botAI); }
static Trigger* archimonde_boss_summoned_doomfire(
PlayerbotAI* botAI) { return new ArchimondeBossSummonedDoomfireTrigger(botAI); }
static Trigger* archimonde_bot_stood_in_doomfire(
PlayerbotAI* botAI) { return new ArchimondeBotStoodInDoomfireTrigger(botAI); }
};
#endif

View File

@ -1,137 +0,0 @@
/*
* 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 "RaidHyjalSummitStrategy.h"
#include "RaidHyjalSummitMultipliers.h"
void RaidHyjalSummitStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
// General
triggers.push_back(new TriggerNode("hyjal summit bot is not in combat", {
NextAction("hyjal summit erase trackers", ACTION_EMERGENCY + 11) }));
// Rage Winterchill
triggers.push_back(new TriggerNode("rage winterchill pulling boss", {
NextAction("rage winterchill misdirect boss to main tank", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("rage winterchill boss engaged by main tank", {
NextAction("rage winterchill main tank position boss", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("rage winterchill boss casts death and decay on ranged", {
NextAction("rage winterchill spread ranged in circle", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("rage winterchill melee is standing in death and decay", {
NextAction("rage winterchill melee get out of death and decay", ACTION_EMERGENCY + 1) }));
// Anetheron
triggers.push_back(new TriggerNode("anetheron pulling boss or infernal", {
NextAction("anetheron misdirect boss and infernals to tanks", ACTION_RAID + 3) }));
triggers.push_back(new TriggerNode("anetheron boss engaged by main tank", {
NextAction("anetheron main tank position boss", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("anetheron boss casts carrion swarm", {
NextAction("anetheron spread ranged in circle", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("anetheron bot is targeted by infernal", {
NextAction("anetheron bring infernal to infernal tank", ACTION_EMERGENCY + 2) }));
triggers.push_back(new TriggerNode("anetheron infernals need to be kept away from raid", {
NextAction("anetheron first assist tank pick up infernals", ACTION_EMERGENCY + 1) }));
triggers.push_back(new TriggerNode("anetheron infernals continue to spawn", {
NextAction("anetheron assign dps priority", ACTION_RAID + 1) }));
// Kaz'rogal
triggers.push_back(new TriggerNode("kaz'rogal pulling boss", {
NextAction("kaz'rogal misdirect boss to main tank", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("kaz'rogal boss engaged by main tank", {
NextAction("kaz'rogal main tank position boss", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("kaz'rogal boss engaged by assist tanks", {
NextAction("kaz'rogal assist tanks move in front of boss", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("kaz'rogal low mana bots need escape path", {
NextAction("kaz'rogal spread ranged in arc", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("kaz'rogal bot is low on mana", {
NextAction("kaz'rogal low mana bot take defensive measures", ACTION_EMERGENCY + 1) }));
triggers.push_back(new TriggerNode("kaz'rogal mark deals shadow damage", {
NextAction("kaz'rogal cast shadow protection spell", ACTION_EMERGENCY + 6) }));
// Azgalor
triggers.push_back(new TriggerNode("azgalor pulling boss", {
NextAction("azgalor misdirect boss to main tank", ACTION_RAID + 3) }));
triggers.push_back(new TriggerNode("azgalor boss engaged by main tank", {
NextAction("azgalor main tank position boss", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("azgalor main tank is positioning boss", {
NextAction("azgalor wait at safe position", ACTION_EMERGENCY + 1) }));
triggers.push_back(new TriggerNode("azgalor boss engaged by ranged", {
NextAction("azgalor disperse ranged", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("azgalor boss casts rain of fire on melee", {
NextAction("azgalor melee get out of fire and swap targets", ACTION_EMERGENCY + 2) }));
triggers.push_back(new TriggerNode("azgalor bot is doomed", {
NextAction("azgalor move to doomguard tank", ACTION_EMERGENCY + 3) }));
triggers.push_back(new TriggerNode("azgalor doomguards must be controlled", {
NextAction("azgalor first assist tank position doomguard", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("azgalor doomguards must die", {
NextAction("azgalor ranged dps prioritize doomguards", ACTION_RAID + 1) }));
// Archimonde
triggers.push_back(new TriggerNode("archimonde pulling boss", {
NextAction("archimonde misdirect boss to main tank", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("archimonde boss engaged by main tank", {
NextAction("archimonde move boss to initial position", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("archimonde boss casts fear", {
NextAction("archimonde cast fear immunity spell", ACTION_RAID + 2) }));
triggers.push_back(new TriggerNode("archimonde boss casts air burst", {
NextAction("archimonde spread to avoid air burst", ACTION_RAID + 1) }));
triggers.push_back(new TriggerNode("archimonde boss summoned doomfire", {
NextAction("archimonde avoid doomfire", ACTION_EMERGENCY + 6) }));
triggers.push_back(new TriggerNode("archimonde bot stood in doomfire", {
NextAction("archimonde remove doomfire dot", ACTION_EMERGENCY + 7) }));
}
void RaidHyjalSummitStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
{
// Trash
multipliers.push_back(new HyjalSummitTimeBloodlustAndHeroismMultiplier(botAI));
// Rage Winterchill
multipliers.push_back(new RageWinterchillDisableCombatFormationMoveMultiplier(botAI));
multipliers.push_back(new RageWinterchillMeleeControlAvoidanceMultiplier(botAI));
// Anetheron
multipliers.push_back(new AnetheronDisableTankActionsMultiplier(botAI));
multipliers.push_back(new AnetheronDisableCombatFormationMoveMultiplier(botAI));
multipliers.push_back(new AnetheronControlMisdirectionMultiplier(botAI));
// Kaz'rogal
multipliers.push_back(new KazrogalLowManaBotStayAwayFromGroupMultiplier(botAI));
multipliers.push_back(new KazrogalKeepAspectOfTheViperActiveMultiplier(botAI));
multipliers.push_back(new KazrogalControlMovementMultiplier(botAI));
// Azgalor
multipliers.push_back(new AzgalorDisableTankActionsMultiplier(botAI));
multipliers.push_back(new AzgalorDoomedBotPrioritizePositioningMultiplier(botAI));
multipliers.push_back(new AzgalorMeleeDpsControlAvoidanceMultiplier(botAI));
// Archimonde
multipliers.push_back(new ArchimondeDisableCombatFormationMoveMultiplier(botAI));
}

View File

@ -1,22 +0,0 @@
/*
* 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_RAIDHYJALSUMMITSTRATEGY_H_
#define _PLAYERBOT_RAIDHYJALSUMMITSTRATEGY_H_
#include "Strategy.h"
class RaidHyjalSummitStrategy : public Strategy
{
public:
RaidHyjalSummitStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
std::string const getName() override { return "hyjal"; }
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
};
#endif

View File

@ -1,357 +0,0 @@
/*
* 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 "RaidHyjalSummitTriggers.h"
#include "RaidHyjalSummitHelpers.h"
#include "RaidHyjalSummitActions.h"
#include "AiFactory.h"
#include "Playerbots.h"
#include "RaidBossHelpers.h"
using namespace HyjalSummitHelpers;
// General
bool HyjalSummitBotIsNotInCombatTrigger::IsActive()
{
return !bot->IsInCombat() && bot->GetMapId() == HYJAL_SUMMIT_MAP_ID;
}
// Rage Winterchill
bool RageWinterchillPullingBossTrigger::IsActive()
{
if (bot->getClass() != CLASS_HUNTER)
return false;
Unit* winterchill = AI_VALUE2(Unit*, "find target", "rage winterchill");
return winterchill && winterchill->GetHealthPct() > 95.0f;
}
bool RageWinterchillBossEngagedByMainTankTrigger::IsActive()
{
return botAI->IsMainTank(bot) &&
AI_VALUE2(Unit*, "find target", "rage winterchill");
}
bool RageWinterchillBossCastsDeathAndDecayOnRangedTrigger::IsActive()
{
return botAI->IsRanged(bot) &&
AI_VALUE2(Unit*, "find target", "rage winterchill");
}
bool RageWinterchillMeleeIsStandingInDeathAndDecayTrigger::IsActive()
{
if (botAI->IsRanged(bot))
return false;
Unit* winterchill = AI_VALUE2(Unit*, "find target", "rage winterchill");
if (!winterchill || winterchill->GetVictim() == bot)
return false;
if (botAI->IsMainTank(bot))
return false;
return IsInDeathAndDecay(bot, DEATH_AND_DECAY_SAFE_RADIUS);
}
// Anetheron
bool AnetheronPullingBossOrInfernalTrigger::IsActive()
{
return bot->getClass() == CLASS_HUNTER &&
AI_VALUE2(Unit*, "find target", "anetheron");
}
bool AnetheronBossEngagedByMainTankTrigger::IsActive()
{
return botAI->IsMainTank(bot) && AI_VALUE2(Unit*, "find target", "anetheron");
}
bool AnetheronBossCastsCarrionSwarmTrigger::IsActive()
{
if (botAI->IsMelee(bot))
return false;
Unit* anetheron = AI_VALUE2(Unit*, "find target", "anetheron");
if (!anetheron)
return false;
return GetInfernoTarget(anetheron) != bot;
}
bool AnetheronBotIsTargetedByInfernalTrigger::IsActive()
{
Unit* anetheron = AI_VALUE2(Unit*, "find target", "anetheron");
if (!anetheron || botAI->IsMainTank(bot))
return false;
return GetInfernoTarget(anetheron) == bot;
}
bool AnetheronInfernalsNeedToBeKeptAwayFromRaidTrigger::IsActive()
{
return botAI->IsAssistTankOfIndex(bot, 0, true) &&
AI_VALUE2(Unit*, "find target", "towering infernal");
}
bool AnetheronInfernalsContinueToSpawnTrigger::IsActive()
{
return !botAI->IsTank(bot) && AI_VALUE2(Unit*, "find target", "anetheron");
}
// Kaz'rogal
bool KazrogalPullingBossTrigger::IsActive()
{
if (bot->getClass() != CLASS_HUNTER)
return false;
Unit* kazrogal = AI_VALUE2(Unit*, "find target", "kaz'rogal");
return kazrogal && kazrogal->GetHealthPct() > 95.0f;
}
bool KazrogalBossEngagedByMainTankTrigger::IsActive()
{
return botAI->IsMainTank(bot) && AI_VALUE2(Unit*, "find target", "kaz'rogal");
}
bool KazrogalBossEngagedByAssistTanksTrigger::IsActive()
{
if (!botAI->IsAssistTank(bot))
return false;
if (!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return false;
return bot->GetPower(POWER_MANA) > 3000;
}
bool KazrogalLowManaBotsNeedEscapePathTrigger::IsActive()
{
if (bot->getClass() == CLASS_WARRIOR || bot->getClass() == CLASS_ROGUE ||
bot->getClass() == CLASS_DEATH_KNIGHT)
return false;
uint8 tab = AiFactory::GetPlayerSpecTab(bot);
if (bot->getClass() == CLASS_DRUID && tab == DRUID_TAB_FERAL)
return false;
if (!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return false;
if (bot->getClass() == CLASS_HUNTER)
{
return true;
}
else if (bot->GetPower(POWER_MANA) > 4000)
{
isBelowManaThreshold.erase(bot->GetGUID());
if (botAI->IsMelee(bot))
return false;
else
return true;
}
return false;
}
bool KazrogalBotIsLowOnManaTrigger::IsActive()
{
if (bot->getClass() == CLASS_WARRIOR || bot->getClass() == CLASS_ROGUE ||
bot->getClass() == CLASS_DEATH_KNIGHT)
return false;
uint8 tab = AiFactory::GetPlayerSpecTab(bot);
if (bot->getClass() == CLASS_DRUID && tab == DRUID_TAB_FERAL)
return false;
if (!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return false;
if (botAI->HasAnyAuraOf(bot, "ice block", "divine shield", nullptr))
return false;
if (isBelowManaThreshold.count(bot->GetGUID()) ||
bot->GetPower(POWER_MANA) <= 3200)
return true;
return false;
}
bool KazrogalMarkDealsShadowDamageTrigger::IsActive()
{
if (bot->getClass() != CLASS_PALADIN && bot->getClass() != CLASS_WARLOCK)
return false;
if (!AI_VALUE2(Unit*, "find target", "kaz'rogal"))
return false;
if (bot->getClass() == CLASS_PALADIN &&
(botAI->HasAura("shadow resistance aura", bot) ||
botAI->HasAura("prayer of shadow protection", bot) ||
botAI->HasAura("shadow protection", bot)))
return false;
return bot->HasAura(
static_cast<uint32>(HyjalSummitSpells::SPELL_MARK_OF_KAZROGAL));
}
// Azgalor
bool AzgalorPullingBossTrigger::IsActive()
{
if (bot->getClass() != CLASS_HUNTER)
return false;
Unit* azgalor = AI_VALUE2(Unit*, "find target", "azgalor");
return azgalor && azgalor->GetHealthPct() > 95.0f;
}
bool AzgalorBossEngagedByMainTankTrigger::IsActive()
{
return botAI->IsMainTank(bot) && AI_VALUE2(Unit*, "find target", "azgalor");
}
bool AzgalorMainTankIsPositioningBossTrigger::IsActive()
{
if (botAI->IsRanged(bot))
return false;
Unit* azgalor = AI_VALUE2(Unit*, "find target", "azgalor");
if (!azgalor || azgalor->GetVictim() == bot)
return false;
Player* mainTank = GetGroupMainTank(botAI, bot);
if (!mainTank || !GET_PLAYERBOT_AI(mainTank) || botAI->IsMainTank(bot))
return false;
TankPositionState tankState = GetAzgalorTankPositionState(botAI, bot);
return tankState == TankPositionState::Unknown ||
tankState == TankPositionState::MovingToTransition;
}
bool AzgalorBossEngagedByRangedTrigger::IsActive()
{
if (botAI->IsMelee(bot))
return false;
Unit* azgalor = AI_VALUE2(Unit*, "find target", "azgalor");
return azgalor && azgalor->GetVictim() != bot &&
!bot->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOM));
}
bool AzgalorBossCastsRainOfFireOnMeleeTrigger::IsActive()
{
if (botAI->IsRanged(bot) || botAI->IsTank(bot))
return false;
Unit* azgalor = AI_VALUE2(Unit*, "find target", "azgalor");
if (!azgalor || azgalor->GetVictim() == bot ||
bot->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOM)))
return false;
return IsInRainOfFire(bot, RAIN_OF_FIRE_RADIUS);
}
bool AzgalorBotIsDoomedTrigger::IsActive()
{
return bot->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOM));
}
bool AzgalorDoomguardsMustBeControlledTrigger::IsActive()
{
if (!botAI->IsAssistTank(bot) ||
!AI_VALUE2(Unit*, "find target", "azgalor"))
return false;
if (botAI->IsAssistTankOfIndex(bot, 0, true))
{
return AI_VALUE2(Unit*, "find target", "lesser doomguard") ||
AnyGroupMemberHasDoom(bot);
}
if (botAI->IsAssistTankOfIndex(bot, 1, true))
{
// Trigger for second assist tank only if first assist tank has Doom
Player* firstAssistTank = GetGroupAssistTank(botAI, bot, 0);
if (firstAssistTank &&
!firstAssistTank->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOM)))
return false;
return AI_VALUE2(Unit*, "find target", "lesser doomguard") ||
AnyGroupMemberHasDoom(bot);
}
return false;
}
bool AzgalorDoomguardsMustDieTrigger::IsActive()
{
return botAI->IsRangedDps(bot) && AI_VALUE2(Unit*, "find target", "azgalor");
}
// Archimonde
bool ArchimondePullingBossTrigger::IsActive()
{
if (bot->getClass() != CLASS_HUNTER)
return false;
Unit* archimonde = AI_VALUE2(Unit*, "find target", "archimonde");
return archimonde && archimonde->GetHealthPct() > 95.0f;
}
bool ArchimondeBossEngagedByMainTankTrigger::IsActive()
{
if (!botAI->IsMainTank(bot))
return false;
Unit* archimonde = AI_VALUE2(Unit*, "find target", "archimonde");
return archimonde && archimonde->GetHealthPct() > 95.0f;
}
bool ArchimondeBossCastsFearTrigger::IsActive()
{
if (bot->getClass() != CLASS_PRIEST &&
bot->getClass() != CLASS_SHAMAN)
return false;
Unit* archimonde = AI_VALUE2(Unit*, "find target", "archimonde");
return archimonde && archimonde->GetHealthPct() > 10.0f;
}
bool ArchimondeBossCastsAirBurstTrigger::IsActive()
{
Unit* archimonde = AI_VALUE2(Unit*, "find target", "archimonde");
if (!archimonde || archimonde->GetHealthPct() <= 10.0f ||
archimonde->GetVictim() == bot)
return false;
return !botAI->IsMainTank(bot);
}
bool ArchimondeBossSummonedDoomfireTrigger::IsActive()
{
Unit* archimonde = AI_VALUE2(Unit*, "find target", "archimonde");
if (!archimonde || archimonde->GetHealthPct() <= 10.0f)
return false;
// If I don't make an exception, bots actually refuse to enter the
// Doomfire even when feared
return !bot->HasAura(
static_cast<uint32>(HyjalSummitSpells::SPELL_ARCHIMONDE_FEAR));
}
bool ArchimondeBotStoodInDoomfireTrigger::IsActive()
{
if (bot->getClass() != CLASS_MAGE && bot->getClass() != CLASS_ROGUE &&
bot->getClass() != CLASS_PALADIN)
return false;
return bot->GetHealthPct() < 40.0f &&
(bot->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOMFIRE)) ||
bot->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOMFIRE_DOT)));
}

View File

@ -1,271 +0,0 @@
/*
* 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_RAIDHYJALSUMMITTRIGGERS_H
#define _PLAYERBOT_RAIDHYJALSUMMITTRIGGERS_H
#include "Trigger.h"
// General
class HyjalSummitBotIsNotInCombatTrigger : public Trigger
{
public:
HyjalSummitBotIsNotInCombatTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "hyjal summit bot is not in combat") {}
bool IsActive() override;
};
// Rage Winterchill
class RageWinterchillPullingBossTrigger : public Trigger
{
public:
RageWinterchillPullingBossTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "rage winterchill pulling boss") {}
bool IsActive() override;
};
class RageWinterchillBossEngagedByMainTankTrigger : public Trigger
{
public:
RageWinterchillBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "rage winterchill boss engaged by main tank") {}
bool IsActive() override;
};
class RageWinterchillBossCastsDeathAndDecayOnRangedTrigger : public Trigger
{
public:
RageWinterchillBossCastsDeathAndDecayOnRangedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "rage winterchill boss casts death and decay on ranged") {}
bool IsActive() override;
};
class RageWinterchillMeleeIsStandingInDeathAndDecayTrigger : public Trigger
{
public:
RageWinterchillMeleeIsStandingInDeathAndDecayTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "rage winterchill melee is standing in death and decay") {}
bool IsActive() override;
};
// Anetheron
class AnetheronPullingBossOrInfernalTrigger : public Trigger
{
public:
AnetheronPullingBossOrInfernalTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "anetheron pulling boss or infernal") {}
bool IsActive() override;
};
class AnetheronBossEngagedByMainTankTrigger : public Trigger
{
public:
AnetheronBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "anetheron boss engaged by main tank") {}
bool IsActive() override;
};
class AnetheronBossCastsCarrionSwarmTrigger : public Trigger
{
public:
AnetheronBossCastsCarrionSwarmTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "anetheron boss casts carrion swarm") {}
bool IsActive() override;
};
class AnetheronBotIsTargetedByInfernalTrigger : public Trigger
{
public:
AnetheronBotIsTargetedByInfernalTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "anetheron bot is targeted by infernal") {}
bool IsActive() override;
};
class AnetheronInfernalsNeedToBeKeptAwayFromRaidTrigger : public Trigger
{
public:
AnetheronInfernalsNeedToBeKeptAwayFromRaidTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "anetheron infernals need to be kept away from raid") {}
bool IsActive() override;
};
class AnetheronInfernalsContinueToSpawnTrigger : public Trigger
{
public:
AnetheronInfernalsContinueToSpawnTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "anetheron infernals continue to spawn") {}
bool IsActive() override;
};
// Kaz'rogal
class KazrogalPullingBossTrigger : public Trigger
{
public:
KazrogalPullingBossTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "kaz'rogal pulling boss") {}
bool IsActive() override;
};
class KazrogalBossEngagedByMainTankTrigger : public Trigger
{
public:
KazrogalBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "kaz'rogal boss engaged by main tank") {}
bool IsActive() override;
};
class KazrogalBossEngagedByAssistTanksTrigger : public Trigger
{
public:
KazrogalBossEngagedByAssistTanksTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "kaz'rogal boss engaged by assist tanks") {}
bool IsActive() override;
};
class KazrogalLowManaBotsNeedEscapePathTrigger : public Trigger
{
public:
KazrogalLowManaBotsNeedEscapePathTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "kaz'rogal low mana bots need escape path") {}
bool IsActive() override;
};
class KazrogalBotIsLowOnManaTrigger : public Trigger
{
public:
KazrogalBotIsLowOnManaTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "kaz'rogal bot is low on mana") {}
bool IsActive() override;
};
class KazrogalMarkDealsShadowDamageTrigger : public Trigger
{
public:
KazrogalMarkDealsShadowDamageTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "kaz'rogal mark deals shadow damage") {}
bool IsActive() override;
};
// Azgalor
class AzgalorPullingBossTrigger : public Trigger
{
public:
AzgalorPullingBossTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor pulling boss") {}
bool IsActive() override;
};
class AzgalorBossEngagedByMainTankTrigger : public Trigger
{
public:
AzgalorBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor boss engaged by main tank") {}
bool IsActive() override;
};
class AzgalorMainTankIsPositioningBossTrigger : public Trigger
{
public:
AzgalorMainTankIsPositioningBossTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor main tank is positioning boss") {}
bool IsActive() override;
};
class AzgalorBossEngagedByRangedTrigger : public Trigger
{
public:
AzgalorBossEngagedByRangedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor boss engaged by ranged") {}
bool IsActive() override;
};
class AzgalorBossCastsRainOfFireOnMeleeTrigger : public Trigger
{
public:
AzgalorBossCastsRainOfFireOnMeleeTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor boss casts rain of fire on melee") {}
bool IsActive() override;
};
class AzgalorBotIsDoomedTrigger : public Trigger
{
public:
AzgalorBotIsDoomedTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor bot is doomed") {}
bool IsActive() override;
};
class AzgalorDoomguardsMustBeControlledTrigger : public Trigger
{
public:
AzgalorDoomguardsMustBeControlledTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor doomguards must be controlled") {}
bool IsActive() override;
};
class AzgalorDoomguardsMustDieTrigger : public Trigger
{
public:
AzgalorDoomguardsMustDieTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "azgalor doomguards must die") {}
bool IsActive() override;
};
// Archimonde
class ArchimondePullingBossTrigger : public Trigger
{
public:
ArchimondePullingBossTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "archimonde pulling boss") {}
bool IsActive() override;
};
class ArchimondeBossEngagedByMainTankTrigger : public Trigger
{
public:
ArchimondeBossEngagedByMainTankTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "archimonde boss engaged by main tank") {}
bool IsActive() override;
};
class ArchimondeBossCastsFearTrigger : public Trigger
{
public:
ArchimondeBossCastsFearTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "archimonde boss casts fear") {}
bool IsActive() override;
};
class ArchimondeBossCastsAirBurstTrigger : public Trigger
{
public:
ArchimondeBossCastsAirBurstTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "archimonde boss casts air burst") {}
bool IsActive() override;
};
class ArchimondeBossSummonedDoomfireTrigger : public Trigger
{
public:
ArchimondeBossSummonedDoomfireTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "archimonde boss summoned doomfire") {}
bool IsActive() override;
};
class ArchimondeBotStoodInDoomfireTrigger : public Trigger
{
public:
ArchimondeBotStoodInDoomfireTrigger(
PlayerbotAI* botAI) : Trigger(botAI, "archimonde bot stood in doomfire") {}
bool IsActive() override;
};
#endif

View File

@ -1,268 +0,0 @@
/*
* 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 "RaidHyjalSummitHelpers.h"
#include <algorithm>
#include "Playerbots.h"
#include "RaidBossHelpers.h"
#include "Timer.h"
namespace HyjalSummitHelpers
{
// General
bool GetGroundedStepPosition(
Player* bot, float destinationX, float destinationY, float moveDist,
float& stepX, float& stepY, float& stepZ)
{
const float distance = bot->GetExactDist2d(destinationX, destinationY);
if (distance <= 0.0f)
return false;
const float stepDistance = std::min(moveDist, distance);
const float deltaX = destinationX - bot->GetPositionX();
const float deltaY = destinationY - bot->GetPositionY();
stepX = bot->GetPositionX() + (deltaX / distance) * stepDistance;
stepY = bot->GetPositionY() + (deltaY / distance) * stepDistance;
stepZ = bot->GetMapWaterOrGroundLevel(stepX, stepY, bot->GetPositionZ());
if (stepZ <= INVALID_HEIGHT)
stepZ = bot->GetPositionZ();
bot->GetMap()->CheckCollisionAndGetValidCoords(
bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(),
stepX, stepY, stepZ, false);
return true;
}
RangedGroups GetRangedGroups(PlayerbotAI* botAI, Player* bot)
{
RangedGroups result;
Group* group = bot->GetGroup();
if (!group)
return result;
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (!member || !botAI->IsRanged(member))
continue;
if (botAI->IsHeal(member))
result.healers.push_back(member);
else
result.rangedDps.push_back(member);
}
return result;
}
std::pair<size_t, size_t> GetBotCircleIndexAndCount(PlayerbotAI* botAI, Player* bot,
const RangedGroups& groups)
{
const std::vector<Player*>& vec = botAI->IsHeal(bot) ? groups.healers : groups.rangedDps;
auto it = std::find(vec.begin(), vec.end(), bot);
size_t index = (it != vec.end()) ? std::distance(vec.begin(), it) : 0;
return {index, vec.size()};
}
// Rage Winterchill
const Position WINTERCHILL_TANK_POSITION = { 5031.061f, -1784.521f, 1321.626f };
std::unordered_map<ObjectGuid, bool> hasReachedWinterchillPosition;
std::unordered_map<uint32, DeathAndDecayData> deathAndDecayPosition;
DeathAndDecayData* GetActiveWinterchillDeathAndDecay(uint32 instanceId)
{
auto instanceIt = deathAndDecayPosition.find(instanceId);
if (instanceIt == deathAndDecayPosition.end())
return nullptr;
const uint32 now = getMSTime();
const uint32 elapsed = getMSTimeDiff(instanceIt->second.spawnTime, now);
if (elapsed >= DEATH_AND_DECAY_REACQUIRE_DELAY)
{
deathAndDecayPosition.erase(instanceIt);
return nullptr;
}
if (elapsed >= DEATH_AND_DECAY_DURATION)
return nullptr;
return &instanceIt->second;
}
bool IsInDeathAndDecay(Player* bot, float radius)
{
const uint32 instanceId = bot->GetMap()->GetInstanceId();
Aura* aura = bot->GetAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DEATH_AND_DECAY));
if (aura)
{
DynamicObject* dynObj = aura->GetDynobjOwner();
if (dynObj && dynObj->IsInWorld())
{
const uint32 now = getMSTime();
auto instanceIt = deathAndDecayPosition.find(instanceId);
if (instanceIt == deathAndDecayPosition.end() ||
getMSTimeDiff(instanceIt->second.spawnTime, now) >= DEATH_AND_DECAY_REACQUIRE_DELAY)
{
deathAndDecayPosition[instanceId] =
DeathAndDecayData{ dynObj->GetPosition(), now };
}
}
}
DeathAndDecayData* data = GetActiveWinterchillDeathAndDecay(instanceId);
if (!data)
return false;
return bot->GetExactDist2d(data->position) < radius;
}
// Anetheron
const Position ANETHERON_TANK_POSITION = { 5033.177f, -1765.996f, 1324.195f };
const Position ANETHERON_E_INFERNAL_POSITION = { 5016.578f, -1800.233f, 1323.070f };
const Position ANETHERON_W_INFERNAL_POSITION = { 5048.911f, -1722.164f, 1321.408f };
std::unordered_map<ObjectGuid, bool> hasReachedAnetheronPosition;
Player* GetInfernoTarget(Unit* anetheron)
{
if (!anetheron)
return nullptr;
Spell* spell = anetheron->GetCurrentSpell(CURRENT_GENERIC_SPELL);
if (spell && spell->m_spellInfo->Id ==
static_cast<uint32>(HyjalSummitSpells::SPELL_INFERNO))
{
Unit* spellTarget = spell->m_targets.GetUnitTarget();
if (spellTarget && spellTarget->IsPlayer())
return spellTarget->ToPlayer();
}
return nullptr;
}
const Position& GetClosestInfernalTankPosition(Player* bot)
{
const Position& east = ANETHERON_E_INFERNAL_POSITION;
const Position& west = ANETHERON_W_INFERNAL_POSITION;
return (bot->GetExactDist2d(east.GetPositionX(), east.GetPositionY()) <=
bot->GetExactDist2d(west.GetPositionX(), west.GetPositionY())) ? east : west;
}
// Kaz'rogal
const Position KAZROGAL_TANK_TRANSITION_POSITION = { 5528.792f, -2636.486f, 1481.293f };
const Position KAZROGAL_TANK_FINAL_POSITION = { 5511.514f, -2662.466f, 1480.288f };
std::unordered_map<ObjectGuid, TankPositionState> kazrogalTankStep;
std::unordered_map<ObjectGuid, bool> isBelowManaThreshold;
TankPositionState GetKazrogalTankPositionState(PlayerbotAI* botAI, Player* bot)
{
Player* mainTank = GetGroupMainTank(botAI, bot);
if (!mainTank)
return TankPositionState::Unknown;
auto it = kazrogalTankStep.find(mainTank->GetGUID());
if (it != kazrogalTankStep.end())
return it->second;
return TankPositionState::Unknown;
}
// Azgalor
const Position AZGALOR_TANK_TRANSITION_POSITION = { 5486.787f, -2696.215f, 1482.007f };
const Position AZGALOR_TANK_FINAL_POSITION = { 5496.379f, -2675.265f, 1481.053f };
const Position AZGALOR_DOOMGUARD_POSITION = { 5485.555f, -2731.659f, 1485.555f };
std::unordered_map<ObjectGuid, TankPositionState> azgalorTankStep;
std::unordered_map<uint32, RainOfFireData> rainOfFirePosition;
RainOfFireData* GetActiveAzgalorRainOfFire(uint32 instanceId)
{
auto instanceIt = rainOfFirePosition.find(instanceId);
if (instanceIt == rainOfFirePosition.end())
return nullptr;
const uint32 now = getMSTime();
const uint32 elapsed = getMSTimeDiff(instanceIt->second.spawnTime, now);
if (elapsed >= RAIN_OF_FIRE_REACQUIRE_DELAY)
{
rainOfFirePosition.erase(instanceIt);
return nullptr;
}
if (elapsed >= RAIN_OF_FIRE_DURATION)
return nullptr;
return &instanceIt->second;
}
TankPositionState GetAzgalorTankPositionState(PlayerbotAI* botAI, Player* bot)
{
Player* mainTank = GetGroupMainTank(botAI, bot);
if (!mainTank)
return TankPositionState::Unknown;
auto it = azgalorTankStep.find(mainTank->GetGUID());
if (it != azgalorTankStep.end())
return it->second;
return TankPositionState::Unknown;
}
bool IsInRainOfFire(Player* bot, float radius)
{
RainOfFireData* data = GetActiveAzgalorRainOfFire(bot->GetMap()->GetInstanceId());
if (!data)
return false;
return bot->GetExactDist2d(data->position) < radius;
}
bool AnyGroupMemberHasDoom(Player* bot)
{
if (Group* group = bot->GetGroup())
{
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
Player* member = ref->GetSource();
if (member &&
member->HasAura(static_cast<uint32>(HyjalSummitSpells::SPELL_DOOM)))
return true;
}
}
return false;
}
// Archimonde
const Position ARCHIMONDE_INITIAL_POSITION = { 5640.502f, -3421.238f, 1587.453f };
std::unordered_map<uint32, AirBurstData> archimondeAirBurstTargets;
std::unordered_map<uint32, std::vector<DoomfireTrailData>> doomfireTrails;
std::unordered_map<ObjectGuid, uint32> doomfireLastSampleTime;
AirBurstData* GetRecentArchimondeAirBurst(uint32 instanceId)
{
auto instanceIt = archimondeAirBurstTargets.find(instanceId);
if (instanceIt == archimondeAirBurstTargets.end())
return nullptr;
constexpr uint32 airBurstReactionWindow = 2000;
const uint32 now = getMSTime();
if (getMSTimeDiff(instanceIt->second.castTime, now) >= airBurstReactionWindow)
{
archimondeAirBurstTargets.erase(instanceIt);
return nullptr;
}
return &instanceIt->second;
}
}

View File

@ -1,143 +0,0 @@
/*
* 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_RAIDHYJALSUMMITHELPERS_H_
#define _PLAYERBOT_RAIDHYJALSUMMITHELPERS_H_
#include <unordered_map>
#include <utility>
#include <vector>
#include "AiObject.h"
#include "Position.h"
#include "Unit.h"
namespace HyjalSummitHelpers
{
enum class HyjalSummitSpells : uint32
{
// Rage Winterchill
SPELL_DEATH_AND_DECAY = 31258,
// Anetheron
SPELL_INFERNO = 31299,
// Kaz'rogal
SPELL_MARK_OF_KAZROGAL = 31447,
// Azgalor
SPELL_RAIN_OF_FIRE = 31340,
SPELL_DOOM = 31347,
// Archimonde
SPELL_DOOMFIRE = 31944, // Damaging part of trail
SPELL_DOOMFIRE_DOT = 31969, // DoT after exiting trail
SPELL_ARCHIMONDE_FEAR = 31970,
SPELL_AIR_BURST = 32014,
// Hunter
SPELL_MISDIRECTION = 35079,
// Priest
SPELL_FEAR_WARD = 6346,
};
enum class HyjalSummitNpcs : uint32
{
// Archimonde
NPC_DOOMFIRE = 18095,
};
enum class TankPositionState : uint8
{
MovingToTransition = 0,
MovingToFinal = 1,
Positioned = 2,
Unknown = 255,
};
// General
constexpr uint32 HYJAL_SUMMIT_MAP_ID = 534;
struct RangedGroups
{
std::vector<Player*> healers;
std::vector<Player*> rangedDps;
};
bool GetGroundedStepPosition(
Player* bot, float destinationX, float destinationY, float moveDist,
float& stepX, float& stepY, float& stepZ);
RangedGroups GetRangedGroups(PlayerbotAI* botAI, Player* bot);
std::pair<size_t, size_t> GetBotCircleIndexAndCount(PlayerbotAI* botAI, Player* bot,
const RangedGroups& groups);
// Rage Winterchill
extern const Position WINTERCHILL_TANK_POSITION;
extern std::unordered_map<ObjectGuid, bool> hasReachedWinterchillPosition;
constexpr uint32 DEATH_AND_DECAY_DURATION = 15000;
constexpr uint32 DEATH_AND_DECAY_REACQUIRE_DELAY = 20000;
constexpr float DEATH_AND_DECAY_SAFE_RADIUS = 22.0f; // 20y radius + 1.5y player hitbox + 0.5y buffer
struct DeathAndDecayData
{
Position position;
uint32 spawnTime;
};
extern std::unordered_map<uint32, DeathAndDecayData> deathAndDecayPosition;
DeathAndDecayData* GetActiveWinterchillDeathAndDecay(uint32 instanceId);
bool IsInDeathAndDecay(Player* bot, float radius);
// Anetheron
extern const Position ANETHERON_TANK_POSITION;
extern const Position ANETHERON_E_INFERNAL_POSITION;
extern const Position ANETHERON_W_INFERNAL_POSITION;
extern std::unordered_map<ObjectGuid, bool> hasReachedAnetheronPosition;
Player* GetInfernoTarget(Unit* anetheron);
const Position& GetClosestInfernalTankPosition(Player* bot);
// Kaz'rogal
extern const Position KAZROGAL_TANK_TRANSITION_POSITION;
extern const Position KAZROGAL_TANK_FINAL_POSITION;
extern std::unordered_map<ObjectGuid, TankPositionState> kazrogalTankStep;
extern std::unordered_map<ObjectGuid, bool> isBelowManaThreshold;
TankPositionState GetKazrogalTankPositionState(PlayerbotAI* botAI, Player* bot);
// Azgalor
extern const Position AZGALOR_TANK_TRANSITION_POSITION;
extern const Position AZGALOR_TANK_FINAL_POSITION;
extern const Position AZGALOR_DOOMGUARD_POSITION;
extern std::unordered_map<ObjectGuid, TankPositionState> azgalorTankStep;
constexpr uint32 RAIN_OF_FIRE_DURATION = 10000;
constexpr uint32 RAIN_OF_FIRE_REACQUIRE_DELAY = 15000;
constexpr float RAIN_OF_FIRE_RADIUS = 17.0f; // 15y radius + 1.5y player hitbox + 0.5y buffer
struct RainOfFireData
{
Position position;
uint32 spawnTime;
};
extern std::unordered_map<uint32, RainOfFireData> rainOfFirePosition;
TankPositionState GetAzgalorTankPositionState(PlayerbotAI* botAI, Player* bot);
RainOfFireData* GetActiveAzgalorRainOfFire(uint32 instanceId);
bool IsInRainOfFire(Player* bot, float radius);
bool AnyGroupMemberHasDoom(Player* bot);
// Archimonde
constexpr float AIR_BURST_SAFE_DISTANCE = 15.0f;
struct AirBurstData
{
ObjectGuid targetGuid;
uint32 castTime;
};
struct DoomfireTrailData
{
Position position;
uint32 recordTime;
};
extern const Position ARCHIMONDE_INITIAL_POSITION;
extern std::unordered_map<uint32, AirBurstData> archimondeAirBurstTargets;
extern std::unordered_map<uint32, std::vector<DoomfireTrailData>> doomfireTrails;
extern std::unordered_map<ObjectGuid, uint32> doomfireLastSampleTime;
AirBurstData* GetRecentArchimondeAirBurst(uint32 instanceId);
}
#endif

View File

@ -1,211 +0,0 @@
/*
* 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 "RaidHyjalSummitHelpers.h"
#include "AllCreatureScript.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "RaidBossHelpers.h"
#include "DynamicObjectScript.h"
#include "Playerbots.h"
#include "ScriptMgr.h"
#include "Spell.h"
#include "Timer.h"
using namespace HyjalSummitHelpers;
static Player* GetFirstPlayerSpellTarget(Spell* spell, Unit* caster)
{
if (!spell || !caster)
return nullptr;
if (Unit* unitTarget = spell->m_targets.GetUnitTarget())
return unitTarget->ToPlayer();
std::list<TargetInfo> const& targets = *spell->GetUniqueTargetInfo();
for (TargetInfo const& targetInfo : targets)
{
if (Player* target = ObjectAccessor::GetPlayer(*caster, targetInfo.targetGUID))
return target;
}
return nullptr;
}
static bool ShouldInterruptForArchimondeAirBurst(PlayerbotAI* botAI, Player* bot, Player* target)
{
if (!target)
return false;
Player* mainTank = GetGroupMainTank(botAI, bot);
if (!mainTank || bot == mainTank)
return false;
float distanceToMainTank = bot->GetExactDist2d(mainTank);
return (target == mainTank || target == bot) &&
distanceToMainTank < AIR_BURST_SAFE_DISTANCE;
}
// Records the active Rain of Fire dynamic object so that melee bots can avoid it by running
// away from Azgalor or swapping to a Doomguard; the standard FleePosition() logic to avoid aoe
// can take melee in front of Azgalor, resulting in them getting cleaved
class AzgalorRainOfFireScript : public DynamicObjectScript
{
public:
AzgalorRainOfFireScript() : DynamicObjectScript("AzgalorRainOfFireScript") {}
void OnUpdate(DynamicObject* dynobj, uint32 /*diff*/) override
{
if (dynobj->GetSpellId() != static_cast<uint32>(HyjalSummitSpells::SPELL_RAIN_OF_FIRE))
return;
uint32 instanceId = dynobj->GetMap()->GetInstanceId();
if (GetActiveAzgalorRainOfFire(instanceId))
return;
uint32 now = getMSTime();
auto instanceIt = rainOfFirePosition.find(instanceId);
if (instanceIt != rainOfFirePosition.end() &&
getMSTimeDiff(instanceIt->second.spawnTime, now) < RAIN_OF_FIRE_REACQUIRE_DELAY)
{
return;
}
bool shouldTrackRainOfFire = false;
Map::PlayerList const& players = dynobj->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
{
Player* player = it->GetSource();
if (!player || !player->IsAlive())
continue;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
if (!botAI || !botAI->HasStrategy("hyjal", BOT_STATE_COMBAT))
continue;
shouldTrackRainOfFire = true;
break;
}
if (!shouldTrackRainOfFire)
return;
rainOfFirePosition[instanceId] = RainOfFireData{ dynobj->GetPosition(), now };
}
};
// Records the position of each Doomfire NPC at regular intervals so that bots can avoid
// the persistent fire trail it leaves behind. Each sample is tagged with a timestamp and
// expires after TRAIL_DURATION ms, matching the lifetime of a Doomfire DynamicObject (18s)
class ArchimondeDoomfireTrailScript : public AllCreatureScript
{
public:
ArchimondeDoomfireTrailScript() : AllCreatureScript("ArchimondeDoomfireTrailScript") {}
void OnAllCreatureUpdate(Creature* creature, uint32 /*diff*/) override
{
if (creature->GetEntry() != static_cast<uint32>(HyjalSummitNpcs::NPC_DOOMFIRE))
return;
uint32 now = getMSTime();
ObjectGuid guid = creature->GetGUID();
auto& lastSample = doomfireLastSampleTime[guid];
if (getMSTimeDiff(lastSample, now) < 500)
return;
lastSample = now;
uint32 instanceId = creature->GetMap()->GetInstanceId();
auto& trail = doomfireTrails[instanceId];
DoomfireTrailData data;
data.position = creature->GetPosition();
data.recordTime = now;
trail.push_back(data);
constexpr uint32 TRAIL_DURATION = 18000;
trail.erase(std::remove_if(trail.begin(), trail.end(),
[now](const DoomfireTrailData& d)
{
return getMSTimeDiff(d.recordTime, now) > TRAIL_DURATION;
}), trail.end());
constexpr float DOOMFIRE_DANGER_RANGE = 10.0f;
Map::PlayerList const& players = creature->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
{
Player* player = it->GetSource();
if (!player || !player->IsAlive())
continue;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
if (!botAI || !botAI->HasStrategy("hyjal", BOT_STATE_COMBAT) ||
creature->GetDistance(player) > DOOMFIRE_DANGER_RANGE)
{
continue;
}
botAI->RequestSpellInterrupt();
}
}
void OnCreatureRemoveWorld(Creature* creature) override
{
if (creature->GetEntry() != static_cast<uint32>(HyjalSummitNpcs::NPC_DOOMFIRE))
return;
doomfireLastSampleTime.erase(creature->GetGUID());
}
};
class ArchimondeAirBurstSpellListenerScript : public AllSpellScript
{
public:
ArchimondeAirBurstSpellListenerScript() :
AllSpellScript("ArchimondeAirBurstSpellListenerScript") {}
void OnSpellCast(
Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool /*skipCheck*/) override
{
if (!spell || !caster || !spellInfo)
return;
if (spellInfo->Id != static_cast<uint32>(HyjalSummitSpells::SPELL_AIR_BURST))
return;
Player* target = GetFirstPlayerSpellTarget(spell, caster);
if (!target)
return;
archimondeAirBurstTargets[caster->GetMap()->GetInstanceId()] =
AirBurstData{ target->GetGUID(), getMSTime() };
Map::PlayerList const& players = caster->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
{
Player* player = it->GetSource();
if (!player || !player->IsAlive())
continue;
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
if (!botAI || !botAI->HasStrategy("hyjal", BOT_STATE_COMBAT) ||
!ShouldInterruptForArchimondeAirBurst(botAI, player, target))
{
continue;
}
botAI->RequestSpellInterrupt();
}
}
};
void AddSC_HyjalSummitBotScripts()
{
new AzgalorRainOfFireScript();
new ArchimondeDoomfireTrailScript();
new ArchimondeAirBurstSpellListenerScript();
}

View File

@ -11,7 +11,6 @@
#include "RaidNaxxStrategy.h"
#include "RaidSSCStrategy.h"
#include "RaidTempestKeepStrategy.h"
#include "RaidHyjalSummitStrategy.h"
#include "RaidZulAmanStrategy.h"
#include "RaidOsStrategy.h"
#include "RaidEoEStrategy.h"
@ -34,7 +33,6 @@ public:
creators["naxx"] = &RaidStrategyContext::naxx;
creators["ssc"] = &RaidStrategyContext::ssc;
creators["tempestkeep"] = &RaidStrategyContext::tempestkeep;
creators["hyjal"] = &RaidStrategyContext::hyjal;
creators["zulaman"] = &RaidStrategyContext::zulaman;
creators["wotlk-os"] = &RaidStrategyContext::wotlk_os;
creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe;
@ -54,7 +52,6 @@ private:
static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); }
static Strategy* ssc(PlayerbotAI* botAI) { return new RaidSSCStrategy(botAI); }
static Strategy* tempestkeep(PlayerbotAI* botAI) { return new RaidTempestKeepStrategy(botAI); }
static Strategy* hyjal(PlayerbotAI* botAI) { return new RaidHyjalSummitStrategy(botAI); }
static Strategy* zulaman(PlayerbotAI* botAI) { return new RaidZulAmanStrategy(botAI); }
static Strategy* wotlk_os(PlayerbotAI* botAI) { return new RaidOsStrategy(botAI); }
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }

View File

@ -11,7 +11,6 @@
#include "Ai/Raid/Magtheridon/RaidMagtheridonActionContext.h"
#include "Ai/Raid/SerpentshrineCavern/RaidSSCActionContext.h"
#include "Ai/Raid/TempestKeep/RaidTempestKeepActionContext.h"
#include "Ai/Raid/HyjalSummit/RaidHyjalSummitActionContext.h"
#include "Ai/Raid/ZulAman/RaidZulAmanActionContext.h"
#include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.h"
#include "Ai/Raid/EyeOfEternity/RaidEoEActionContext.h"
@ -35,7 +34,6 @@ void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList<Act
actionContexts.Add(new RaidMagtheridonActionContext());
actionContexts.Add(new RaidSSCActionContext());
actionContexts.Add(new RaidTempestKeepActionContext());
actionContexts.Add(new RaidHyjalSummitActionContext());
actionContexts.Add(new RaidZulAmanActionContext());
actionContexts.Add(new RaidNaxxActionContext());
actionContexts.Add(new RaidOsActionContext());

View File

@ -11,7 +11,6 @@
#include "Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h"
#include "Ai/Raid/SerpentshrineCavern/RaidSSCTriggerContext.h"
#include "Ai/Raid/TempestKeep/RaidTempestKeepTriggerContext.h"
#include "Ai/Raid/HyjalSummit/RaidHyjalSummitTriggerContext.h"
#include "Ai/Raid/ZulAman/RaidZulAmanTriggerContext.h"
#include "Ai/Raid/ObsidianSanctum/RaidOsTriggerContext.h"
#include "Ai/Raid/EyeOfEternity/RaidEoETriggerContext.h"
@ -36,7 +35,6 @@ void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList<Tr
triggerContexts.Add(new RaidNaxxTriggerContext());
triggerContexts.Add(new RaidSSCTriggerContext());
triggerContexts.Add(new RaidTempestKeepTriggerContext());
triggerContexts.Add(new RaidHyjalSummitTriggerContext());
triggerContexts.Add(new RaidZulAmanTriggerContext());
triggerContexts.Add(new RaidOsTriggerContext());
triggerContexts.Add(new RaidEoETriggerContext());

View File

@ -33,11 +33,8 @@ bool ExternalEventHelper::ParseChatCommand(std::string const command, Player* ow
if (!ChatHelper::parseableItem(command))
return false;
if (sPlayerbotAIConfig.enableAutoTradeOnItemMention)
{
HandleCommand("c", command, owner);
HandleCommand("t", command, owner);
}
HandleCommand("c", command, owner);
HandleCommand("t", command, owner);
return true;
}

View File

@ -15,7 +15,6 @@
#include "ChannelMgr.h"
#include "CharacterPackets.h"
#include "ChatHelper.h"
#include "CheckMountStateAction.h"
#include "Common.h"
#include "CreatureData.h"
#include "EmoteAction.h"
@ -1366,17 +1365,6 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
// */
return;
}
case SMSG_DISMOUNT:
{
WorldPacket p(packet);
p.rpos(0);
ObjectGuid guid;
p >> guid.ReadAsPacked();
if (guid != bot->GetGUID())
return;
CheckMountStateAction::CompleteDismount(bot);
return;
}
default:
botOutgoingPacketHandlers.AddPacket(packet);
}
@ -1585,27 +1573,6 @@ void PlayerbotAI::ClearStrategies(BotState type)
e->removeAllStrategies();
}
// Resets only the combat or non-combat engine: wipe strategies, repopulate with class/spec defaults,
// re-apply current map's instance strategy (if any), and call Init() to rebuild trigger/action lists.
void PlayerbotAI::SelectiveResetStrategies(BotState type)
{
Engine* e = engines[type];
if (!e)
return;
e->removeAllStrategies();
if (type == BOT_STATE_COMBAT)
AiFactory::AddDefaultCombatStrategies(bot, this, e);
else if (type == BOT_STATE_NON_COMBAT)
AiFactory::AddDefaultNonCombatStrategies(bot, this, e);
if (sPlayerbotAIConfig.applyInstanceStrategies)
ApplyInstanceStrategies(bot->GetMapId());
e->Init();
}
std::vector<std::string> PlayerbotAI::GetStrategies(BotState type)
{
Engine* e = engines[type];
@ -1619,12 +1586,11 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
{
static const std::vector<std::string> allInstanceStrategies =
{
"aq20", "bwl", "karazhan", "gruulslair", "hyjal", "icc", "magtheridon",
"moltencore", "naxx", "onyxia", "ssc", "tbc-ac", "tempestkeep", "ulduar",
"voa", "wotlk-an", "wotlk-cos", "wotlk-dtk", "wotlk-eoe", "wotlk-fos",
"wotlk-gd", "wotlk-hol", "wotlk-hor", "wotlk-hos", "wotlk-nex", "wotlk-occ",
"wotlk-ok", "wotlk-os", "wotlk-pos", "wotlk-toc", "wotlk-uk", "wotlk-up",
"wotlk-vh", "zulaman"
"aq20", "bwl", "karazhan", "gruulslair", "icc", "magtheridon", "moltencore",
"naxx", "onyxia", "ssc", "tbc-ac", "tempestkeep", "ulduar", "voa", "wotlk-an", "wotlk-cos",
"wotlk-dtk", "wotlk-eoe", "wotlk-fos", "wotlk-gd", "wotlk-hol", "wotlk-hor",
"wotlk-hos", "wotlk-nex", "wotlk-occ", "wotlk-ok", "wotlk-os", "wotlk-pos",
"wotlk-toc", "wotlk-uk", "wotlk-up", "wotlk-vh", "zulaman"
};
for (const std::string& strat : allInstanceStrategies)
@ -1654,9 +1620,6 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
case 533:
strategyName = "naxx"; // Naxxramas
break;
case 534:
strategyName = "hyjal"; // The Battle for Mount Hyjal (Hyjal Summit)
break;
case 544:
strategyName = "magtheridon"; // Magtheridon's Lair
break;

View File

@ -404,7 +404,6 @@ public:
std::string const qualifier = "");
void ChangeStrategy(std::string const name, BotState type);
void ClearStrategies(BotState type);
void SelectiveResetStrategies(BotState type);
std::vector<std::string> GetStrategies(BotState type);
Strategy* GetStrategy(std::string const name, BotState type);
void ApplyInstanceStrategies(uint32 mapId, bool tellMaster = false);

View File

@ -1542,24 +1542,6 @@ void PlayerbotMgr::HandleMasterIncomingPacket(WorldPacket const& packet)
// if master is logging out, log out all bots
case CMSG_LOGOUT_REQUEST:
{
Player* master = GetMaster();
if (master)
{
// Replicate the AFK logout prevention checks from WorldSession::HandleLogoutRequestOpcode
// so bots are not logged out when the master's own logout is going to be prevented.
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(master->GetAreaId());
bool preventAfkSanctuaryLogout = sWorld->getIntConfig(CONFIG_AFK_PREVENT_LOGOUT) == 1
&& master->isAFK() && areaEntry && areaEntry->IsSanctuary();
bool preventAfkLogout = sWorld->getIntConfig(CONFIG_AFK_PREVENT_LOGOUT) == 2
&& master->isAFK();
if (preventAfkSanctuaryLogout || preventAfkLogout)
{
break;
}
}
LogoutAllBots();
break;
}

View File

@ -4821,10 +4821,7 @@ void TravelMgr::PrepareDestinationCache()
if (l < 1 || l > maxLevel)
continue;
locsPerLevelCache[(uint8)l].push_back(WorldLocation(std::get<0>(gridTuple),
static_cast<float>(std::get<1>(gridTuple)) * 50.0f,
static_cast<float>(std::get<2>(gridTuple)) * 50.0f,
static_cast<float>(std::get<3>(gridTuple)) * 50.0f));
locsPerLevelCache[(uint8)l].push_back(WorldLocation(std::get<0>(gridTuple)));
}
}
}

View File

@ -519,7 +519,6 @@ bool PlayerbotAIConfig::Initialize()
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.AllowedLogFiles", ""),
allowedLogFiles);
enableAutoTradeOnItemMention = sConfigMgr->GetOption<bool>("AiPlayerbot.EnableAutoTradeOnItemMention", true);
LoadListString<std::vector<std::string>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.TradeActionExcludedPrefixes", ""),
tradeActionExcludedPrefixes);

View File

@ -306,7 +306,6 @@ public:
uint32 iterationsPerTick;
std::mutex m_logMtx;
bool enableAutoTradeOnItemMention;
std::vector<std::string> tradeActionExcludedPrefixes;
std::vector<std::string> allowedLogFiles;
std::unordered_map<std::string, std::pair<FILE*, bool>> logFiles;

View File

@ -526,7 +526,6 @@ public:
void AddPlayerbotsSecureLoginScripts();
void AddSC_TempestKeepBotScripts();
void AddSC_HyjalSummitBotScripts();
void AddPlayerbotsScripts()
{
@ -542,5 +541,4 @@ void AddPlayerbotsScripts()
AddPlayerbotsCommandscripts();
PlayerBotsGuildValidationScript();
AddSC_TempestKeepBotScripts();
AddSC_HyjalSummitBotScripts();
}