mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
commit
652c7a1996
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="icon.png" alt="Playerbots Icon" width="700px">
|
<img src="banner.png" alt="Playerbots Banner" width="700px">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|||||||
BIN
banner.png
Normal file
BIN
banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 204 KiB |
File diff suppressed because it is too large
Load Diff
@ -4,15 +4,19 @@
|
|||||||
-- zhTW, esES, esMX, ruRU)
|
-- zhTW, esES, esMX, ruRU)
|
||||||
-- #########################################################
|
-- #########################################################
|
||||||
|
|
||||||
|
DELETE FROM ai_playerbot_texts WHERE name IN ('pvp_currency', 'pvp_arena_team', 'pvp_no_arena_team');
|
||||||
|
DELETE FROM ai_playerbot_texts_chance WHERE name IN ('pvp_currency', 'pvp_arena_team', 'pvp_no_arena_team');
|
||||||
|
|
||||||
-- ---------------------------------------------------------
|
-- ---------------------------------------------------------
|
||||||
-- pvp_currency
|
-- pvp_currency
|
||||||
-- [PVP] Arena points: %arena_points | Honor Points: %honor_points
|
-- [PVP] Arena points: %arena_points | Honor Points: %honor_points
|
||||||
-- ---------------------------------------------------------
|
-- ---------------------------------------------------------
|
||||||
INSERT INTO `ai_playerbot_texts`
|
INSERT INTO `ai_playerbot_texts`
|
||||||
(`name`, `text`, `say_type`, `reply_type`,
|
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
||||||
SELECT
|
VALUES (
|
||||||
|
1737,
|
||||||
'pvp_currency',
|
'pvp_currency',
|
||||||
'[PVP] Arena points: %arena_points | Honor Points: %honor_points',
|
'[PVP] Arena points: %arena_points | Honor Points: %honor_points',
|
||||||
0, 0,
|
0, 0,
|
||||||
@ -31,20 +35,20 @@ SELECT
|
|||||||
-- esMX
|
-- esMX
|
||||||
'[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points',
|
'[PVP] Puntos de arena: %arena_points | Puntos de honor: %honor_points',
|
||||||
-- ruRU
|
-- ruRU
|
||||||
'[PVP] Очки арены: %arena_points | Очки чести: %honor_points'
|
'[PVP] Очки арены: %arena_points | Очки чести: %honor_points');
|
||||||
WHERE NOT EXISTS (
|
|
||||||
SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_currency'
|
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pvp_currency', 100);
|
||||||
);
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------
|
-- ---------------------------------------------------------
|
||||||
-- pvp_arena_team
|
-- pvp_arena_team
|
||||||
-- [PVP] %bracket: <%team_name> (rating %team_rating)
|
-- [PVP] %bracket: <%team_name> (rating %team_rating)
|
||||||
-- ---------------------------------------------------------
|
-- ---------------------------------------------------------
|
||||||
INSERT INTO `ai_playerbot_texts`
|
INSERT INTO `ai_playerbot_texts`
|
||||||
(`name`, `text`, `say_type`, `reply_type`,
|
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
||||||
SELECT
|
VALUES (
|
||||||
|
1738,
|
||||||
'pvp_arena_team',
|
'pvp_arena_team',
|
||||||
'[PVP] %bracket: <%team_name> (rating %team_rating)',
|
'[PVP] %bracket: <%team_name> (rating %team_rating)',
|
||||||
0, 0,
|
0, 0,
|
||||||
@ -63,20 +67,20 @@ SELECT
|
|||||||
-- esMX
|
-- esMX
|
||||||
'[PVP] %bracket: <%team_name> (índice %team_rating)',
|
'[PVP] %bracket: <%team_name> (índice %team_rating)',
|
||||||
-- ruRU
|
-- ruRU
|
||||||
'[PVP] %bracket: <%team_name> (рейтинг %team_rating)'
|
'[PVP] %bracket: <%team_name> (рейтинг %team_rating)');
|
||||||
WHERE NOT EXISTS (
|
|
||||||
SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_arena_team'
|
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pvp_arena_team', 100);
|
||||||
);
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------
|
-- ---------------------------------------------------------
|
||||||
-- pvp_no_arena_team
|
-- pvp_no_arena_team
|
||||||
-- [PVP] I have no Arena Team.
|
-- [PVP] I have no Arena Team.
|
||||||
-- ---------------------------------------------------------
|
-- ---------------------------------------------------------
|
||||||
INSERT INTO `ai_playerbot_texts`
|
INSERT INTO `ai_playerbot_texts`
|
||||||
(`name`, `text`, `say_type`, `reply_type`,
|
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
||||||
SELECT
|
VALUES (
|
||||||
|
1739,
|
||||||
'pvp_no_arena_team',
|
'pvp_no_arena_team',
|
||||||
'[PVP] I have no Arena Team.',
|
'[PVP] I have no Arena Team.',
|
||||||
0, 0,
|
0, 0,
|
||||||
@ -95,7 +99,6 @@ SELECT
|
|||||||
-- esMX
|
-- esMX
|
||||||
'[PVP] No tengo equipo de arena.',
|
'[PVP] No tengo equipo de arena.',
|
||||||
-- ruRU
|
-- ruRU
|
||||||
'[PVP] У меня нет команды арены.'
|
'[PVP] У меня нет команды арены.');
|
||||||
WHERE NOT EXISTS (
|
|
||||||
SELECT 1 FROM `ai_playerbot_texts` WHERE `name` = 'pvp_no_arena_team'
|
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('pvp_no_arena_team', 100);
|
||||||
);
|
|
||||||
|
|||||||
BIN
icon.png
BIN
icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 125 KiB |
@ -24,8 +24,6 @@ bool BGJoinAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
BattlegroundQueueTypeId queueTypeId = (BattlegroundQueueTypeId)bgList[urand(0, bgList.size() - 1)];
|
BattlegroundQueueTypeId queueTypeId = (BattlegroundQueueTypeId)bgList[urand(0, bgList.size() - 1)];
|
||||||
BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(queueTypeId);
|
BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(queueTypeId);
|
||||||
BattlegroundBracketId bracketId;
|
|
||||||
bool isArena = false;
|
|
||||||
bool isRated = false;
|
bool isRated = false;
|
||||||
|
|
||||||
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
|
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId);
|
||||||
@ -37,12 +35,8 @@ bool BGJoinAction::Execute(Event /*event*/)
|
|||||||
if (!pvpDiff)
|
if (!pvpDiff)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bracketId = pvpDiff->GetBracketId();
|
|
||||||
|
|
||||||
if (ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)))
|
if (ArenaType type = ArenaType(BattlegroundMgr::BGArenaType(queueTypeId)))
|
||||||
{
|
{
|
||||||
isArena = true;
|
|
||||||
|
|
||||||
std::vector<uint32>::iterator i = find(ratedList.begin(), ratedList.end(), queueTypeId);
|
std::vector<uint32>::iterator i = find(ratedList.begin(), ratedList.end(), queueTypeId);
|
||||||
if (i != ratedList.end())
|
if (i != ratedList.end())
|
||||||
isRated = true;
|
isRated = true;
|
||||||
@ -408,8 +402,6 @@ bool BGJoinAction::JoinQueue(uint32 type)
|
|||||||
|
|
||||||
bracketId = pvpDiff->GetBracketId();
|
bracketId = pvpDiff->GetBracketId();
|
||||||
|
|
||||||
uint32 BracketSize = bg->GetMaxPlayersPerTeam() * 2;
|
|
||||||
uint32 TeamSize = bg->GetMaxPlayersPerTeam();
|
|
||||||
TeamId teamId = bot->GetTeamId();
|
TeamId teamId = bot->GetTeamId();
|
||||||
|
|
||||||
// check if already in queue
|
// check if already in queue
|
||||||
@ -486,8 +478,6 @@ bool BGJoinAction::JoinQueue(uint32 type)
|
|||||||
if (isArena)
|
if (isArena)
|
||||||
{
|
{
|
||||||
isArena = true;
|
isArena = true;
|
||||||
BracketSize = type * 2;
|
|
||||||
TeamSize = type;
|
|
||||||
isRated = botAI->GetAiObjectContext()->GetValue<uint32>("arena type")->Get();
|
isRated = botAI->GetAiObjectContext()->GetValue<uint32>("arena type")->Get();
|
||||||
|
|
||||||
if (joinAsGroup)
|
if (joinAsGroup)
|
||||||
|
|||||||
@ -2497,7 +2497,6 @@ bool BGTactics::selectObjective(bool reset)
|
|||||||
EYBotStrategy strategyHorde = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
|
EYBotStrategy strategyHorde = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_HORDE));
|
||||||
EYBotStrategy strategyAlliance = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
|
EYBotStrategy strategyAlliance = static_cast<EYBotStrategy>(GetBotStrategyForTeam(bg, TEAM_ALLIANCE));
|
||||||
EYBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
|
EYBotStrategy strategy = (team == TEAM_ALLIANCE) ? strategyAlliance : strategyHorde;
|
||||||
EYBotStrategy enemyStrategy = (team == TEAM_ALLIANCE) ? strategyHorde : strategyAlliance;
|
|
||||||
|
|
||||||
auto IsOwned = [&](uint32 nodeId) -> bool
|
auto IsOwned = [&](uint32 nodeId) -> bool
|
||||||
{ return eyeOfTheStormBG->GetCapturePointInfo(nodeId)._ownerTeamId == team; };
|
{ return eyeOfTheStormBG->GetCapturePointInfo(nodeId)._ownerTeamId == team; };
|
||||||
@ -3231,7 +3230,6 @@ bool BGTactics::selectObjectiveWp(std::vector<BattleBotPath*> const& vPaths)
|
|||||||
if (bgType == BATTLEGROUND_RB)
|
if (bgType == BATTLEGROUND_RB)
|
||||||
bgType = bg->GetBgTypeID(true);
|
bgType = bg->GetBgTypeID(true);
|
||||||
|
|
||||||
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
||||||
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
PositionInfo pos = context->GetValue<PositionMap&>("position")->Get()["bg objective"];
|
||||||
if (!pos.isSet())
|
if (!pos.isSet())
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -68,9 +68,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
|
|||||||
std::string const target = formation->GetTargetName();
|
std::string const target = formation->GetTargetName();
|
||||||
bool moved = false;
|
bool moved = false;
|
||||||
if (!target.empty())
|
if (!target.empty())
|
||||||
{
|
|
||||||
moved = Follow(AI_VALUE(Unit*, target));
|
moved = Follow(AI_VALUE(Unit*, target));
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WorldLocation loc = formation->GetLocation();
|
WorldLocation loc = formation->GetLocation();
|
||||||
@ -83,9 +81,7 @@ bool FollowChatShortcutAction::Execute(Event /*event*/)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Pet* pet = bot->GetPet())
|
if (Pet* pet = bot->GetPet())
|
||||||
{
|
|
||||||
botAI->PetFollow();
|
botAI->PetFollow();
|
||||||
}
|
|
||||||
|
|
||||||
if (moved)
|
if (moved)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -112,7 +112,6 @@ float ChooseRpgTargetAction::getMaxRelevance(GuidPosition guidP)
|
|||||||
|
|
||||||
bool ChooseRpgTargetAction::Execute(Event /*event*/)
|
bool ChooseRpgTargetAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
//TravelTarget* travelTarget = AI_VALUE(TravelTarget*, "travel target"); //not used, line marked for removal.
|
|
||||||
Player* master = botAI->GetMaster();
|
Player* master = botAI->GetMaster();
|
||||||
GuidPosition masterRpgTarget;
|
GuidPosition masterRpgTarget;
|
||||||
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
|
if (master && master != bot && GET_PLAYERBOT_AI(master) && master->GetMapId() == bot->GetMapId() && !master->IsBeingTeleported())
|
||||||
@ -124,7 +123,6 @@ bool ChooseRpgTargetAction::Execute(Event /*event*/)
|
|||||||
master = nullptr;
|
master = nullptr;
|
||||||
|
|
||||||
std::unordered_map<ObjectGuid, uint32> targets;
|
std::unordered_map<ObjectGuid, uint32> targets;
|
||||||
// uint32 num = 0; //not used, line marked for removal.
|
|
||||||
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
GuidVector possibleTargets = AI_VALUE(GuidVector, "possible rpg targets");
|
||||||
GuidVector possibleObjects = AI_VALUE(GuidVector, "nearest game objects no los");
|
GuidVector possibleObjects = AI_VALUE(GuidVector, "nearest game objects no los");
|
||||||
GuidVector possiblePlayers = AI_VALUE(GuidVector, "nearest friendly players");
|
GuidVector possiblePlayers = AI_VALUE(GuidVector, "nearest friendly players");
|
||||||
|
|||||||
@ -232,15 +232,6 @@ void ChooseTravelTargetAction::ReportTravelTarget(TravelTarget* newTarget, Trave
|
|||||||
QuestTravelDestination* QuestDestination = (QuestTravelDestination*)destination;
|
QuestTravelDestination* QuestDestination = (QuestTravelDestination*)destination;
|
||||||
Quest const* quest = QuestDestination->GetQuestTemplate();
|
Quest const* quest = QuestDestination->GetQuestTemplate();
|
||||||
WorldPosition botLocation(bot);
|
WorldPosition botLocation(bot);
|
||||||
|
|
||||||
CreatureTemplate const* cInfo = nullptr;
|
|
||||||
GameObjectTemplate const* gInfo = nullptr;
|
|
||||||
|
|
||||||
if (destination->getEntry() > 0)
|
|
||||||
cInfo = sObjectMgr->GetCreatureTemplate(destination->getEntry());
|
|
||||||
else
|
|
||||||
gInfo = sObjectMgr->GetGameObjectTemplate(destination->getEntry() * -1);
|
|
||||||
|
|
||||||
std::string Sub;
|
std::string Sub;
|
||||||
|
|
||||||
if (newTarget->isGroupCopy())
|
if (newTarget->isGroupCopy())
|
||||||
@ -823,10 +814,6 @@ char* strstri(char const* haystack, char const* needle);
|
|||||||
|
|
||||||
TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name, bool zones, bool npcs, bool quests, bool mobs, bool bosses)
|
TravelDestination* ChooseTravelTargetAction::FindDestination(Player* bot, std::string const name, bool zones, bool npcs, bool quests, bool mobs, bool bosses)
|
||||||
{
|
{
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
||||||
|
|
||||||
// AiObjectContext* context = botAI->GetAiObjectContext(); //not used, line marked for removal.
|
|
||||||
|
|
||||||
std::vector<TravelDestination*> dests;
|
std::vector<TravelDestination*> dests;
|
||||||
|
|
||||||
//Quests
|
//Quests
|
||||||
|
|||||||
@ -520,8 +520,8 @@ bool DebugAction::Execute(Event event)
|
|||||||
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
|
botPos.setY(botPos.GetPositionY() + (dy - 5) * 5);
|
||||||
botPos.setZ(botPos.getHeight());
|
botPos.setZ(botPos.getHeight());
|
||||||
|
|
||||||
Creature* wpCreature = bot->SummonCreature(effect, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
|
bot->SummonCreature(effect, botPos.GetPositionX(), botPos.GetPositionY(), botPos.GetPositionZ(), 0,
|
||||||
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
|
TEMPSUMMON_TIMED_DESPAWN, 10000.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -85,8 +85,8 @@ void EquipAction::EquipItem(Item* item)
|
|||||||
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
if (itemProto->Class == ITEM_CLASS_CONTAINER)
|
||||||
{
|
{
|
||||||
// Attempt to equip as a bag
|
// Attempt to equip as a bag
|
||||||
Bag* pBag = reinterpret_cast<Bag*>(item);
|
|
||||||
uint8 newBagSlot = GetSmallestBagSlot();
|
uint8 newBagSlot = GetSmallestBagSlot();
|
||||||
|
|
||||||
if (newBagSlot > 0)
|
if (newBagSlot > 0)
|
||||||
{
|
{
|
||||||
uint16 src = ((bagIndex << 8) | slot);
|
uint16 src = ((bagIndex << 8) | slot);
|
||||||
|
|||||||
@ -262,7 +262,7 @@ bool MoveNearWaterAction::isUseful()
|
|||||||
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
|
FishingSpotValue* fishingSpotValueObject = (FishingSpotValue*)context->GetValue<WorldPosition>("fishing spot");
|
||||||
WorldPosition pos = fishingSpotValueObject->Get();
|
WorldPosition pos = fishingSpotValueObject->Get();
|
||||||
return !pos.IsValid() || fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT) ||
|
return !pos.IsValid() || fishingSpotValueObject->IsStale(FISHING_LOCATION_TIMEOUT) ||
|
||||||
bot->GetExactDist(&pos) < 0.1f;
|
bot->GetExactDist(&pos) > 0.1f;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +292,6 @@ bool MoveNearWaterAction::isPossible()
|
|||||||
// Water spot is out of range, lets look for a spot to move to for the fishing hole.
|
// Water spot is out of range, lets look for a spot to move to for the fishing hole.
|
||||||
if (distance > MAX_DISTANCE_TO_WATER || distance < MIN_DISTANCE_TO_WATER)
|
if (distance > MAX_DISTANCE_TO_WATER || distance < MIN_DISTANCE_TO_WATER)
|
||||||
{
|
{
|
||||||
float angle = bot->GetAngle(fishingHole.GetPositionX(), fishingHole.GetPositionY());
|
|
||||||
WorldPosition landSpot = FindLandRadialFromPosition(botAI, fishingHole, MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, fishingSearchWindow, 32);
|
WorldPosition landSpot = FindLandRadialFromPosition(botAI, fishingHole, MIN_DISTANCE_TO_WATER, MAX_DISTANCE_TO_WATER, SEARCH_INCREMENT, fishingSearchWindow, 32);
|
||||||
if (landSpot.IsValid())
|
if (landSpot.IsValid())
|
||||||
{
|
{
|
||||||
@ -323,7 +322,6 @@ bool MoveNearWaterAction::isPossible()
|
|||||||
if (!water.IsValid())
|
if (!water.IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool hasLOS = bot->IsWithinLOS(water.GetPositionX(), water.GetPositionY(), water.GetPositionZ());
|
|
||||||
float angle = bot->GetAngle(water.GetPositionX(), water.GetPositionY());
|
float angle = bot->GetAngle(water.GetPositionX(), water.GetPositionY());
|
||||||
WorldPosition landSpot =
|
WorldPosition landSpot =
|
||||||
FindLandFromPosition(botAI, 0.0f, MAX_DISTANCE_TO_WATER, 1.0f, angle, water, fishingSearchWindow, false);
|
FindLandFromPosition(botAI, 0.0f, MAX_DISTANCE_TO_WATER, 1.0f, angle, water, fishingSearchWindow, false);
|
||||||
|
|||||||
@ -28,7 +28,6 @@ bool GiveItemAction::Execute(Event /*event*/)
|
|||||||
if (receiverAi->GetAiObjectContext()->GetValue<uint32>("item count", item)->Get())
|
if (receiverAi->GetAiObjectContext()->GetValue<uint32>("item count", item)->Get())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
bool moved = false;
|
|
||||||
std::vector<Item*> items = InventoryAction::parseItems(item, ITERATE_ITEMS_IN_BAGS);
|
std::vector<Item*> items = InventoryAction::parseItems(item, ITERATE_ITEMS_IN_BAGS);
|
||||||
for (Item* item : items)
|
for (Item* item : items)
|
||||||
{
|
{
|
||||||
@ -42,7 +41,6 @@ bool GiveItemAction::Execute(Event /*event*/)
|
|||||||
bot->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
|
bot->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
|
||||||
item->SetOwnerGUID(target->GetGUID());
|
item->SetOwnerGUID(target->GetGUID());
|
||||||
receiver->MoveItemToInventory(dest, item, true);
|
receiver->MoveItemToInventory(dest, item, true);
|
||||||
moved = true;
|
|
||||||
|
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "Got " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " << bot->GetName();
|
out << "Got " << chat->FormatItem(item->GetTemplate(), item->GetCount()) << " from " << bot->GetName();
|
||||||
|
|||||||
@ -17,7 +17,6 @@
|
|||||||
bool BuyPetitionAction::Execute(Event /*event*/)
|
bool BuyPetitionAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||||
bool vendored = false, result = false;
|
|
||||||
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
|
for (GuidVector::iterator i = vendors.begin(); i != vendors.end(); ++i)
|
||||||
{
|
{
|
||||||
ObjectGuid vendorguid = *i;
|
ObjectGuid vendorguid = *i;
|
||||||
@ -97,7 +96,6 @@ bool BuyPetitionAction::canBuyPetition(Player* bot)
|
|||||||
|
|
||||||
bool PetitionOfferAction::Execute(Event event)
|
bool PetitionOfferAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
uint32 petitionEntry = 5863; // GUILD_CHARTER
|
|
||||||
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
|
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
|
||||||
|
|
||||||
if (petitions.empty())
|
if (petitions.empty())
|
||||||
@ -212,7 +210,6 @@ bool PetitionOfferNearbyAction::isUseful()
|
|||||||
bool PetitionTurnInAction::Execute(Event /*event*/)
|
bool PetitionTurnInAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
GuidVector vendors = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||||
bool vendored = false, result = false;
|
|
||||||
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
|
std::vector<Item*> petitions = AI_VALUE2(std::vector<Item*>, "inventory items", chat->FormatQItem(5863));
|
||||||
|
|
||||||
if (petitions.empty())
|
if (petitions.empty())
|
||||||
|
|||||||
@ -167,8 +167,6 @@ std::vector<Player*> InviteGuildToGroupAction::getGuildMembers()
|
|||||||
|
|
||||||
bool InviteGuildToGroupAction::Execute(Event /*event*/)
|
bool InviteGuildToGroupAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
Guild* guild = sGuildMgr->GetGuildById(bot->GetGuildId());
|
|
||||||
|
|
||||||
for (auto& member : getGuildMembers())
|
for (auto& member : getGuildMembers())
|
||||||
{
|
{
|
||||||
Player* player = member;
|
Player* player = member;
|
||||||
|
|||||||
@ -27,7 +27,6 @@ bool LootRollAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ObjectGuid guid = roll->itemGUID;
|
ObjectGuid guid = roll->itemGUID;
|
||||||
uint32 slot = roll->itemSlot;
|
|
||||||
uint32 itemId = roll->itemid;
|
uint32 itemId = roll->itemid;
|
||||||
int32 randomProperty = 0;
|
int32 randomProperty = 0;
|
||||||
if (roll->itemRandomPropId)
|
if (roll->itemRandomPropId)
|
||||||
@ -184,7 +183,6 @@ bool MasterLootRollAction::Execute(Event event)
|
|||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RollVote vote = CalculateRollVote(proto);
|
|
||||||
group->CountRollVote(bot->GetGUID(), creatureGuid, CalculateRollVote(proto));
|
group->CountRollVote(bot->GetGUID(), creatureGuid, CalculateRollVote(proto));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -16,7 +16,6 @@ bool LootStrategyAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
std::string const strategy = event.getParam();
|
std::string const strategy = event.getParam();
|
||||||
|
|
||||||
LootObjectStack* lootItems = AI_VALUE(LootObjectStack*, "available loot");
|
|
||||||
std::set<uint32>& alwaysLootItems = AI_VALUE(std::set<uint32>&, "always loot list");
|
std::set<uint32>& alwaysLootItems = AI_VALUE(std::set<uint32>&, "always loot list");
|
||||||
Value<LootStrategy*>* lootStrategy = context->GetValue<LootStrategy*>("loot strategy");
|
Value<LootStrategy*>* lootStrategy = context->GetValue<LootStrategy*>("loot strategy");
|
||||||
|
|
||||||
|
|||||||
@ -134,7 +134,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool CheckBagSpace(Player* bot)
|
bool CheckBagSpace(Player* bot)
|
||||||
{
|
{
|
||||||
uint32 totalused = 0, total = 16;
|
uint32 totalused = 0;
|
||||||
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++)
|
for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; slot++)
|
||||||
if (bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
if (bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||||
++totalused;
|
++totalused;
|
||||||
|
|||||||
@ -93,9 +93,6 @@ bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPrior
|
|||||||
|
|
||||||
distance += target->GetCombatReach();
|
distance += target->GetCombatReach();
|
||||||
|
|
||||||
float x = target->GetPositionX();
|
|
||||||
float y = target->GetPositionY();
|
|
||||||
float z = target->GetPositionZ();
|
|
||||||
float followAngle = GetFollowAngle();
|
float followAngle = GetFollowAngle();
|
||||||
|
|
||||||
for (float angle = followAngle; angle <= followAngle + static_cast<float>(2 * M_PI);
|
for (float angle = followAngle; angle <= followAngle + static_cast<float>(2 * M_PI);
|
||||||
@ -113,7 +110,6 @@ bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPrior
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// botAI->TellError("All paths not in LOS");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,9 +118,6 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
|
|||||||
if (!target)
|
if (!target)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// std::ostringstream out; out << "Moving to LOS!";
|
|
||||||
// bot->Say(out.str(), LANG_UNIVERSAL);
|
|
||||||
|
|
||||||
float x = target->GetPositionX();
|
float x = target->GetPositionX();
|
||||||
float y = target->GetPositionY();
|
float y = target->GetPositionY();
|
||||||
float z = target->GetPositionZ();
|
float z = target->GetPositionZ();
|
||||||
@ -257,7 +250,6 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
|||||||
// bot->CastStop();
|
// bot->CastStop();
|
||||||
// botAI->InterruptSpell();
|
// botAI->InterruptSpell();
|
||||||
// }
|
// }
|
||||||
G3D::Vector3 endP = path.back();
|
|
||||||
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
DoMovePoint(bot, x, y, z, generatePath, backwards);
|
||||||
float delay = 1000.0f * MoveDelay(distance, backwards);
|
float delay = 1000.0f * MoveDelay(distance, backwards);
|
||||||
if (lessDelay)
|
if (lessDelay)
|
||||||
@ -772,8 +764,6 @@ bool MovementAction::MoveTo(WorldObject* target, float distance, MovementPriorit
|
|||||||
float by = bot->GetPositionY();
|
float by = bot->GetPositionY();
|
||||||
float bz = bot->GetPositionZ();
|
float bz = bot->GetPositionZ();
|
||||||
|
|
||||||
float tx = target->GetPositionX();
|
|
||||||
float ty = target->GetPositionY();
|
|
||||||
float tz = target->GetPositionZ();
|
float tz = target->GetPositionZ();
|
||||||
|
|
||||||
float distanceToTarget = bot->GetDistance(target);
|
float distanceToTarget = bot->GetDistance(target);
|
||||||
@ -805,10 +795,6 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
|||||||
if (!IsMovingAllowed(target))
|
if (!IsMovingAllowed(target))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float bx = bot->GetPositionX();
|
|
||||||
float by = bot->GetPositionY();
|
|
||||||
float bz = bot->GetPositionZ();
|
|
||||||
|
|
||||||
float tx = target->GetPositionX();
|
float tx = target->GetPositionX();
|
||||||
float ty = target->GetPositionY();
|
float ty = target->GetPositionY();
|
||||||
float tz = target->GetPositionZ();
|
float tz = target->GetPositionZ();
|
||||||
@ -1413,7 +1399,6 @@ bool MovementAction::Flee(Unit* target)
|
|||||||
if (botAI->IsTank(player))
|
if (botAI->IsTank(player))
|
||||||
{
|
{
|
||||||
float distanceToTank = ServerFacade::instance().GetDistance2d(bot, player);
|
float distanceToTank = ServerFacade::instance().GetDistance2d(bot, player);
|
||||||
float distanceToTarget = ServerFacade::instance().GetDistance2d(bot, target);
|
|
||||||
if (distanceToTank < fleeDistance)
|
if (distanceToTank < fleeDistance)
|
||||||
{
|
{
|
||||||
fleeTarget = player;
|
fleeTarget = player;
|
||||||
@ -1434,8 +1419,6 @@ bool MovementAction::Flee(Unit* target)
|
|||||||
else // bot is not targeted, try to flee dps/healers
|
else // bot is not targeted, try to flee dps/healers
|
||||||
{
|
{
|
||||||
bool isHealer = botAI->IsHeal(bot);
|
bool isHealer = botAI->IsHeal(bot);
|
||||||
bool isDps = !isHealer && !botAI->IsTank(bot);
|
|
||||||
bool isTank = botAI->IsTank(bot);
|
|
||||||
bool needHealer = !isHealer && AI_VALUE2(uint8, "health", "self target") < 50;
|
bool needHealer = !isHealer && AI_VALUE2(uint8, "health", "self target") < 50;
|
||||||
bool isRanged = botAI->IsRanged(bot);
|
bool isRanged = botAI->IsRanged(bot);
|
||||||
|
|
||||||
@ -2771,9 +2754,7 @@ bool MoveRandomAction::Execute(Event /*event*/)
|
|||||||
float angle = (float)rand_norm() * static_cast<float>(M_PI);
|
float angle = (float)rand_norm() * static_cast<float>(M_PI);
|
||||||
x += urand(0, distance) * cos(angle);
|
x += urand(0, distance) * cos(angle);
|
||||||
y += urand(0, distance) * sin(angle);
|
y += urand(0, distance) * sin(angle);
|
||||||
float ox = x;
|
|
||||||
float oy = y;
|
|
||||||
float oz = z;
|
|
||||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||||
bot->GetPositionZ(), x, y, z))
|
bot->GetPositionZ(), x, y, z))
|
||||||
continue;
|
continue;
|
||||||
@ -2894,10 +2875,8 @@ bool MoveAwayFromCreatureAction::isPossible() { return bot->CanFreeMove(); }
|
|||||||
|
|
||||||
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event /*event*/)
|
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
Player* closestPlayer = nullptr;
|
Group* const group = bot->GetGroup();
|
||||||
float minDistance = 0.0f;
|
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@ -332,7 +332,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
uint32 spellId;
|
uint32 spellId;
|
||||||
float range;
|
float range;
|
||||||
bool alive;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -20,7 +20,6 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool warningEnabled = true;
|
|
||||||
std::string defaultCmd;
|
std::string defaultCmd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,6 @@ void QueryQuestAction::TellObjective(std::string const name, uint32 available, u
|
|||||||
|
|
||||||
bool QueryQuestAction::Execute(Event event)
|
bool QueryQuestAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
WorldPosition botPos(bot);
|
WorldPosition botPos(bot);
|
||||||
WorldPosition* ptr_botpos = &botPos;
|
WorldPosition* ptr_botpos = &botPos;
|
||||||
|
|||||||
@ -352,7 +352,6 @@ bool QuestUpdateAddItemAction::Execute(Event event)
|
|||||||
uint32 itemId, count;
|
uint32 itemId, count;
|
||||||
p >> itemId >> count;
|
p >> itemId >> count;
|
||||||
|
|
||||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
|
||||||
auto const* itemPrototype = sObjectMgr->GetItemTemplate(itemId);
|
auto const* itemPrototype = sObjectMgr->GetItemTemplate(itemId);
|
||||||
if (itemPrototype)
|
if (itemPrototype)
|
||||||
{
|
{
|
||||||
@ -407,8 +406,6 @@ bool QuestItemPushResultAction::Execute(Event event)
|
|||||||
if (!quest)
|
if (!quest)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const QuestStatusData& q_status = bot->getQuestStatusMap().at(questId);
|
|
||||||
|
|
||||||
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
|
for (int i = 0; i < QUEST_ITEM_OBJECTIVES_COUNT; i++)
|
||||||
{
|
{
|
||||||
uint32 itemId = quest->RequiredItemId[i];
|
uint32 itemId = quest->RequiredItemId[i];
|
||||||
@ -448,8 +445,6 @@ bool QuestUpdateFailedTimerAction::Execute(Event event)
|
|||||||
uint32 questId;
|
uint32 questId;
|
||||||
p >> questId;
|
p >> questId;
|
||||||
|
|
||||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
|
||||||
|
|
||||||
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
|
Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
|
||||||
|
|
||||||
if (qInfo)
|
if (qInfo)
|
||||||
|
|||||||
@ -28,7 +28,7 @@ bool RememberTaxiAction::Execute(Event event)
|
|||||||
case CMSG_ACTIVATETAXIEXPRESS:
|
case CMSG_ACTIVATETAXIEXPRESS:
|
||||||
{
|
{
|
||||||
ObjectGuid guid;
|
ObjectGuid guid;
|
||||||
uint32 node_count, totalcost;
|
uint32 node_count;
|
||||||
p >> guid >> node_count;
|
p >> guid >> node_count;
|
||||||
|
|
||||||
LastMovement& movement = context->GetValue<LastMovement&>("last taxi")->Get();
|
LastMovement& movement = context->GetValue<LastMovement&>("last taxi")->Get();
|
||||||
|
|||||||
@ -156,7 +156,6 @@ bool SayAction::isUseful()
|
|||||||
|
|
||||||
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name)
|
void ChatReplyAction::ChatReplyDo(Player* bot, uint32& type, uint32& guid1, uint32& guid2, std::string& msg, std::string& chanName, std::string& name)
|
||||||
{
|
{
|
||||||
ChatReplyType replyType = REPLY_NOT_UNDERSTAND; // default not understand
|
|
||||||
std::string respondsText = "";
|
std::string respondsText = "";
|
||||||
|
|
||||||
// if we're just commanding bots around, don't respond...
|
// if we're just commanding bots around, don't respond...
|
||||||
|
|||||||
@ -10,8 +10,10 @@
|
|||||||
|
|
||||||
bool SecurityCheckAction::isUseful()
|
bool SecurityCheckAction::isUseful()
|
||||||
{
|
{
|
||||||
return sRandomPlayerbotMgr.IsRandomBot(bot) && botAI->GetMaster() &&
|
return RandomPlayerbotMgr::instance().IsRandomBot(bot)
|
||||||
botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER && !GET_PLAYERBOT_AI(botAI->GetMaster());
|
&& botAI->GetMaster()
|
||||||
|
&& botAI->GetMaster()->GetSession()->GetSecurity() < SEC_GAMEMASTER
|
||||||
|
&& !GET_PLAYERBOT_AI(botAI->GetMaster());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SecurityCheckAction::Execute(Event /*event*/)
|
bool SecurityCheckAction::Execute(Event /*event*/)
|
||||||
|
|||||||
@ -66,7 +66,8 @@ bool SetCraftAction::Execute(Event event)
|
|||||||
if (!spellInfo)
|
if (!spellInfo)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (SkillLineAbilityEntry const* skillLine = skillSpells[spellId])
|
SkillLineAbilityEntry const* skillLine = skillSpells[spellId];
|
||||||
|
if (skillLine != nullptr)
|
||||||
{
|
{
|
||||||
for (uint8 i = 0; i < 3; ++i)
|
for (uint8 i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -26,20 +26,10 @@ bool SetHomeAction::Execute(Event /*event*/)
|
|||||||
if (Unit* unit = botAI->GetUnit(selection))
|
if (Unit* unit = botAI->GetUnit(selection))
|
||||||
if (unit->HasNpcFlag(UNIT_NPC_FLAG_INNKEEPER))
|
if (unit->HasNpcFlag(UNIT_NPC_FLAG_INNKEEPER))
|
||||||
{
|
{
|
||||||
if (isRpgAction)
|
Creature* creature = botAI->GetCreature(selection);
|
||||||
{
|
bot->GetSession()->SendBindPoint(creature);
|
||||||
Creature* creature = botAI->GetCreature(selection);
|
botAI->TellMaster("This inn is my new home");
|
||||||
bot->GetSession()->SendBindPoint(creature);
|
return true;
|
||||||
botAI->TellMaster("This inn is my new home");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Creature* creature = botAI->GetCreature(selection);
|
|
||||||
bot->GetSession()->SendBindPoint(creature);
|
|
||||||
botAI->TellMaster("This inn is my new home");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||||
|
|||||||
@ -40,9 +40,8 @@ bool ShareQuestAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AutoShareQuestAction::Execute(Event event)
|
bool AutoShareQuestAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
Player* requester = event.getOwner() ? event.getOwner() : GetMaster();
|
|
||||||
bool shared = false;
|
bool shared = false;
|
||||||
|
|
||||||
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
|
||||||
|
|||||||
@ -47,7 +47,6 @@ bool StayAction::isUseful()
|
|||||||
PositionInfo stayPosition = AI_VALUE(PositionMap&, "position")["stay"];
|
PositionInfo stayPosition = AI_VALUE(PositionMap&, "position")["stay"];
|
||||||
if (stayPosition.isSet())
|
if (stayPosition.isSet())
|
||||||
{
|
{
|
||||||
const float distance = bot->GetDistance(stayPosition.x, stayPosition.y, stayPosition.z);
|
|
||||||
if (sPlayerbotAIConfig.followDistance)
|
if (sPlayerbotAIConfig.followDistance)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,7 +63,6 @@ bool SuggestWhatToDoAction::Execute(Event /*event*/)
|
|||||||
fnct_ptr();
|
fnct_ptr();
|
||||||
|
|
||||||
std::string const qualifier = "suggest what to do";
|
std::string const qualifier = "suggest what to do";
|
||||||
time_t lastSaid = AI_VALUE2(time_t, "last said", qualifier);
|
|
||||||
botAI->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(time(nullptr) + urand(1, 60));
|
botAI->GetAiObjectContext()->GetValue<time_t>("last said", qualifier)->Set(time(nullptr) + urand(1, 60));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -221,7 +220,7 @@ void SuggestWhatToDoAction::thunderfury()
|
|||||||
class FindTradeItemsVisitor : public IterateItemsVisitor
|
class FindTradeItemsVisitor : public IterateItemsVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FindTradeItemsVisitor(uint32 quality) : quality(quality), IterateItemsVisitor() {}
|
FindTradeItemsVisitor(uint32 quality) : IterateItemsVisitor(), quality(quality) {}
|
||||||
|
|
||||||
bool Visit(Item* item) override
|
bool Visit(Item* item) override
|
||||||
{
|
{
|
||||||
|
|||||||
@ -231,7 +231,6 @@ void TalkToQuestGiverAction::AskToSelectReward(Quest const* quest, std::ostrings
|
|||||||
for (uint8 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
|
for (uint8 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
|
||||||
{
|
{
|
||||||
ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i]);
|
ItemTemplate const* item = sObjectMgr->GetItemTemplate(quest->RewardChoiceItemId[i]);
|
||||||
ItemUsage usage = AI_VALUE2(ItemUsage, "item usage", quest->RewardChoiceItemId[i]);
|
|
||||||
|
|
||||||
if (!forEquip || BestRewards(quest).count(i) > 0)
|
if (!forEquip || BestRewards(quest).count(i) > 0)
|
||||||
{
|
{
|
||||||
@ -248,7 +247,6 @@ bool TurnInQueryQuestAction::Execute(Event event)
|
|||||||
WorldPacket pakcet = event.getPacket();
|
WorldPacket pakcet = event.getPacket();
|
||||||
ObjectGuid guid;
|
ObjectGuid guid;
|
||||||
uint32 questId;
|
uint32 questId;
|
||||||
ObjectGuid unk1;
|
|
||||||
pakcet >> guid >> questId;
|
pakcet >> guid >> questId;
|
||||||
Object* object =
|
Object* object =
|
||||||
ObjectAccessor::GetObjectByTypeMask(*bot, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM);
|
ObjectAccessor::GetObjectByTypeMask(*bot, guid, TYPEMASK_UNIT | TYPEMASK_GAMEOBJECT | TYPEMASK_ITEM);
|
||||||
|
|||||||
@ -51,7 +51,6 @@ bool TameAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
std::set<std::string> normalFamilies;
|
std::set<std::string> normalFamilies;
|
||||||
std::set<std::string> exoticFamilies;
|
std::set<std::string> exoticFamilies;
|
||||||
Player* bot = botAI->GetBot();
|
|
||||||
|
|
||||||
// Loop over all creature templates and collect tameable families
|
// Loop over all creature templates and collect tameable families
|
||||||
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
|
CreatureTemplateContainer const* creatures = sObjectMgr->GetCreatureTemplates();
|
||||||
|
|||||||
@ -31,8 +31,14 @@ bool TaxiAction::Execute(Event event)
|
|||||||
GuidVector units = *context->GetValue<GuidVector>("nearest npcs");
|
GuidVector units = *context->GetValue<GuidVector>("nearest npcs");
|
||||||
for (ObjectGuid const guid : units)
|
for (ObjectGuid const guid : units)
|
||||||
{
|
{
|
||||||
Creature* npc = bot->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_FLIGHTMASTER);
|
Creature* npc = ObjectAccessor::GetCreature(*bot, guid);
|
||||||
if (!npc)
|
if (!npc || !npc->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(npc->GetNpcFlags() & UNIT_NPC_FLAG_FLIGHTMASTER))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bot->GetDistance(npc) > sPlayerbotAIConfig.farDistance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32 curloc = sObjectMgr->GetNearestTaxiNode(npc->GetPositionX(), npc->GetPositionY(), npc->GetPositionZ(),
|
uint32 curloc = sObjectMgr->GetNearestTaxiNode(npc->GetPositionX(), npc->GetPositionY(), npc->GetPositionZ(),
|
||||||
@ -50,21 +56,17 @@ bool TaxiAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stagger bot takeoff
|
|
||||||
uint32 delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u, false);
|
|
||||||
uint32 delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u, false);
|
|
||||||
uint32 gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u, false);
|
|
||||||
uint32 gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u, false);
|
|
||||||
|
|
||||||
// Only for follower bots
|
// Only for follower bots
|
||||||
if (botAI->HasRealPlayerMaster())
|
if (botAI->HasRealPlayerMaster())
|
||||||
{
|
{
|
||||||
uint32 index = botAI->GetGroupSlotIndex(bot);
|
uint32 index = botAI->GetGroupSlotIndex(bot);
|
||||||
uint32 delay = delayMin + index * gapMs + urand(0, gapJitterMs);
|
uint32 delay = sPlayerbotAIConfig.botTaxiDelayMin +
|
||||||
|
index * sPlayerbotAIConfig.botTaxiGapMs +
|
||||||
|
urand(0, sPlayerbotAIConfig.botTaxiGapJitterMs);
|
||||||
|
|
||||||
delay = std::min(delay, delayMax);
|
delay = std::min(delay, sPlayerbotAIConfig.botTaxiDelayMax);
|
||||||
|
|
||||||
// Store the npc’s GUID so we can re-acquire the pointer later
|
// Store the NPC's GUID so we can re-acquire the pointer later
|
||||||
ObjectGuid npcGuid = npc->GetGUID();
|
ObjectGuid npcGuid = npc->GetGUID();
|
||||||
|
|
||||||
// schedule the take-off
|
// schedule the take-off
|
||||||
|
|||||||
@ -95,7 +95,6 @@ bool TellAuraAction::Execute(Event /*event*/)
|
|||||||
std::string caster_name = caster ? caster->GetName() : "unknown";
|
std::string caster_name = caster ? caster->GetName() : "unknown";
|
||||||
bool is_area = aura->IsArea();
|
bool is_area = aura->IsArea();
|
||||||
int32 duration = aura->GetDuration();
|
int32 duration = aura->GetDuration();
|
||||||
const SpellInfo* spellInfo = aura->GetSpellInfo();
|
|
||||||
int32 spellId = aura->GetSpellInfo()->Id;
|
int32 spellId = aura->GetSpellInfo()->Id;
|
||||||
bool isPositive = aura->GetSpellInfo()->IsPositive();
|
bool isPositive = aura->GetSpellInfo()->IsPositive();
|
||||||
sLog->outMessage("playerbot", LOG_LEVEL_DEBUG,
|
sLog->outMessage("playerbot", LOG_LEVEL_DEBUG,
|
||||||
|
|||||||
@ -64,8 +64,6 @@ bool TradeStatusAction::Execute(Event event)
|
|||||||
uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot, trader);
|
uint32 discount = sRandomPlayerbotMgr.GetTradeDiscount(bot, trader);
|
||||||
if (CheckTrade())
|
if (CheckTrade())
|
||||||
{
|
{
|
||||||
int32 botMoney = CalculateCost(bot, true);
|
|
||||||
|
|
||||||
std::map<uint32, uint32> givenItemIds, takenItemIds;
|
std::map<uint32, uint32> givenItemIds, takenItemIds;
|
||||||
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
||||||
{
|
{
|
||||||
@ -161,15 +159,11 @@ bool TradeStatusAction::CheckTrade()
|
|||||||
|
|
||||||
if (!botAI->HasActivePlayerMaster() && GET_PLAYERBOT_AI(bot->GetTrader()))
|
if (!botAI->HasActivePlayerMaster() && GET_PLAYERBOT_AI(bot->GetTrader()))
|
||||||
{
|
{
|
||||||
bool isGivingItem = false;
|
|
||||||
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
||||||
{
|
{
|
||||||
Item* item = bot->GetTradeData()->GetItem((TradeSlots)slot);
|
Item* item = bot->GetTradeData()->GetItem((TradeSlots)slot);
|
||||||
if (item)
|
if (item)
|
||||||
{
|
|
||||||
isGivingItem = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool isGettingItem = false;
|
bool isGettingItem = false;
|
||||||
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
for (uint32 slot = 0; slot < TRADE_SLOT_TRADED_COUNT; ++slot)
|
||||||
|
|||||||
@ -134,8 +134,6 @@ bool MoveFromDarkPortalAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
if (bot->GetTeamId() == TEAM_ALLIANCE)
|
||||||
return MoveTo(530, -319.261f, 1027.213, 54.172638f, false, true);
|
return MoveTo(530, -319.261f, 1027.213, 54.172638f, false, true);
|
||||||
else
|
|
||||||
return MoveTo(530, -180.444f, 1027.947, 54.181538f, false, true);
|
|
||||||
|
|
||||||
return false;
|
return MoveTo(530, -180.444f, 1027.947, 54.181538f, false, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,7 +69,6 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni
|
|||||||
|
|
||||||
uint8 bagIndex = item->GetBagSlot();
|
uint8 bagIndex = item->GetBagSlot();
|
||||||
uint8 slot = item->GetSlot();
|
uint8 slot = item->GetSlot();
|
||||||
uint8 spell_index = 0;
|
|
||||||
uint8 cast_count = 1;
|
uint8 cast_count = 1;
|
||||||
ObjectGuid item_guid = item->GetGUID();
|
ObjectGuid item_guid = item->GetGUID();
|
||||||
uint32 glyphIndex = 0;
|
uint32 glyphIndex = 0;
|
||||||
|
|||||||
@ -108,7 +108,7 @@ std::string const WhoAction::QuerySkill(std::string const text)
|
|||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string const WhoAction::QuerySpec(std::string const text)
|
std::string const WhoAction::QuerySpec(std::string const /*text*/)
|
||||||
{
|
{
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
|
|
||||||
|
|||||||
@ -8,11 +8,13 @@
|
|||||||
|
|
||||||
bool WipeAction::Execute(Event event)
|
bool WipeAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Player* master = event.getOwner();
|
Player* const owner = event.getOwner();
|
||||||
|
Player* const master = this->botAI->GetMaster();
|
||||||
|
|
||||||
if (botAI->GetMaster()->GetGUID() != event.getOwner()->GetGUID())
|
if (owner != nullptr && master != nullptr && master->GetGUID() != owner->GetGUID())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bot->Kill(bot, bot);
|
bot->Kill(bot, bot);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "LootValues.h"
|
#include "LootValues.h"
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "Playerbots.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "PvpValues.h"
|
#include "PvpValues.h"
|
||||||
#include "QuestValues.h"
|
#include "QuestValues.h"
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,6 @@
|
|||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
static float GetSpeedInMotion(Unit* target)
|
|
||||||
{
|
|
||||||
return target->GetSpeed(Movement::SelectSpeedType(target->GetUnitMovementFlags()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EnemyTooCloseForSpellTrigger::IsActive()
|
bool EnemyTooCloseForSpellTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
|
|||||||
@ -144,8 +144,6 @@ UnitPosition MultiLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint3
|
|||||||
uint32 lineNo = index / 6;
|
uint32 lineNo = index / 6;
|
||||||
uint32 indexInLine = index % 6;
|
uint32 indexInLine = index % 6;
|
||||||
uint32 lineSize = std::max(count - lineNo * 6, uint32(6));
|
uint32 lineSize = std::max(count - lineNo * 6, uint32(6));
|
||||||
float x = cos(orientation) * sPlayerbotAIConfig.followDistance * lineNo;
|
|
||||||
float y = sin(orientation) * sPlayerbotAIConfig.followDistance * lineNo;
|
|
||||||
return placer.Place(unit, indexInLine, lineSize);
|
return placer.Place(unit, indexInLine, lineSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,17 +158,13 @@ UnitPosition SingleLineUnitPlacer::Place(FormationUnit* unit, uint32 index, uint
|
|||||||
void FormationSlot::Move(float dx, float dy)
|
void FormationSlot::Move(float dx, float dy)
|
||||||
{
|
{
|
||||||
for (FormationUnit* unit : units)
|
for (FormationUnit* unit : units)
|
||||||
{
|
|
||||||
unit->SetLocation(unit->GetX() + dx, unit->GetY() + dy);
|
unit->SetLocation(unit->GetX() + dx, unit->GetY() + dy);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FormationSlot::~FormationSlot()
|
FormationSlot::~FormationSlot()
|
||||||
{
|
{
|
||||||
for (FormationUnit* unit : units)
|
for (FormationUnit* unit : units)
|
||||||
{
|
|
||||||
delete unit;
|
delete unit;
|
||||||
}
|
|
||||||
|
|
||||||
units.clear();
|
units.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,6 @@ Unit* GrindTargetValue::Calculate()
|
|||||||
|
|
||||||
Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
||||||
{
|
{
|
||||||
uint32 memberCount = 1;
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
Player* master = GetMaster();
|
Player* master = GetMaster();
|
||||||
|
|
||||||
@ -65,7 +64,6 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount)
|
|||||||
if (!unit->IsInWorld() || unit->IsDuringRemoveFromWorld())
|
if (!unit->IsInWorld() || unit->IsDuringRemoveFromWorld())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto& rep = bot->ToPlayer()->GetReputationMgr();
|
|
||||||
if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid &&
|
if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid &&
|
||||||
bot->GetReactionTo(unit) >= REP_NEUTRAL)
|
bot->GetReactionTo(unit) >= REP_NEUTRAL)
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -69,8 +69,10 @@ ItemUsage ItemUsageValue::Calculate()
|
|||||||
if (proto->Class == ITEM_CLASS_KEY)
|
if (proto->Class == ITEM_CLASS_KEY)
|
||||||
return ITEM_USAGE_USE;
|
return ITEM_USAGE_USE;
|
||||||
|
|
||||||
|
const uint32_t maxCount = proto->MaxCount;
|
||||||
|
|
||||||
if (proto->Class == ITEM_CLASS_CONSUMABLE &&
|
if (proto->Class == ITEM_CLASS_CONSUMABLE &&
|
||||||
(proto->MaxCount == 0 || bot->GetItemCount(itemId, false) < proto->MaxCount))
|
(maxCount == 0 || bot->GetItemCount(itemId, false) < maxCount))
|
||||||
{
|
{
|
||||||
std::string const foodType = GetConsumableType(proto, bot->GetPower(POWER_MANA));
|
std::string const foodType = GetConsumableType(proto, bot->GetPower(POWER_MANA));
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include "LeastHpTargetValue.h"
|
#include "LeastHpTargetValue.h"
|
||||||
|
|
||||||
#include "AttackersValue.h"
|
#include "AttackersValue.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
class FindLeastHpTargetStrategy : public FindNonCcTargetStrategy
|
class FindLeastHpTargetStrategy : public FindNonCcTargetStrategy
|
||||||
{
|
{
|
||||||
@ -15,7 +15,6 @@ public:
|
|||||||
|
|
||||||
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
|
void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override
|
||||||
{
|
{
|
||||||
Player* bot = botAI->GetBot();
|
|
||||||
if (IsCcTarget(attacker))
|
if (IsCcTarget(attacker))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -30,5 +29,6 @@ protected:
|
|||||||
Unit* LeastHpTargetValue::Calculate()
|
Unit* LeastHpTargetValue::Calculate()
|
||||||
{
|
{
|
||||||
FindLeastHpTargetStrategy strategy(botAI);
|
FindLeastHpTargetStrategy strategy(botAI);
|
||||||
|
|
||||||
return FindTarget(&strategy);
|
return FindTarget(&strategy);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "NamedObjectContext.h"
|
#include "NamedObjectContext.h"
|
||||||
#include "PartyMemberValue.h"
|
#include "PartyMemberValue.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
class Unit;
|
class Unit;
|
||||||
@ -16,8 +15,7 @@ class Unit;
|
|||||||
class PartyMemberWithoutAuraValue : public PartyMemberValue, public Qualified
|
class PartyMemberWithoutAuraValue : public PartyMemberValue, public Qualified
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PartyMemberWithoutAuraValue(PlayerbotAI* botAI, std::string const name = "party member without aura",
|
PartyMemberWithoutAuraValue(PlayerbotAI* botAI, std::string const name = "party member without aura")
|
||||||
float range = sPlayerbotAIConfig.sightDistance)
|
|
||||||
: PartyMemberValue(botAI, name)
|
: PartyMemberValue(botAI, name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,15 +5,14 @@
|
|||||||
|
|
||||||
#include "PossibleRpgTargetsValue.h"
|
#include "PossibleRpgTargetsValue.h"
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
#include "CellImpl.h"
|
||||||
|
#include "GridNotifiers.h"
|
||||||
|
#include "GridNotifiersImpl.h"
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "NearestGameObjects.h"
|
#include "NearestGameObjects.h"
|
||||||
#include "GridNotifiers.h"
|
|
||||||
#include "GridNotifiersImpl.h"
|
|
||||||
#include "CellImpl.h"
|
|
||||||
#include "TravelMgr.h"
|
|
||||||
|
|
||||||
std::vector<uint32> PossibleRpgTargetsValue::allowedNpcFlags;
|
std::vector<uint32> PossibleRpgTargetsValue::allowedNpcFlags;
|
||||||
|
|
||||||
@ -74,15 +73,9 @@ bool PossibleRpgTargetsValue::AcceptUnit(Unit* unit)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TravelTarget* travelTarget = context->GetValue<TravelTarget*>("travel target")->Get();
|
TravelTarget* travelTarget = context->GetValue<TravelTarget*>("travel target")->Get();
|
||||||
|
if (travelTarget && travelTarget->getDestination() &&
|
||||||
if (
|
travelTarget->getDestination()->getEntry() == unit->GetEntry())
|
||||||
travelTarget != nullptr
|
|
||||||
&& travelTarget->getDestination()
|
|
||||||
&& (uint32_t)travelTarget->getDestination()->getEntry() == unit->GetEntry()
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (urand(1, 100) < 25 && unit->IsFriendlyTo(bot))
|
if (urand(1, 100) < 25 && unit->IsFriendlyTo(bot))
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -14,7 +14,6 @@ Unit* SnareTargetValue::Calculate()
|
|||||||
std::string const spell = qualifier;
|
std::string const spell = qualifier;
|
||||||
|
|
||||||
GuidVector attackers = botAI->GetAiObjectContext()->GetValue<GuidVector>("attackers")->Get();
|
GuidVector attackers = botAI->GetAiObjectContext()->GetValue<GuidVector>("attackers")->Get();
|
||||||
Unit* target = botAI->GetAiObjectContext()->GetValue<Unit*>("current target")->Get();
|
|
||||||
for (ObjectGuid const guid : attackers)
|
for (ObjectGuid const guid : attackers)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(guid);
|
Unit* unit = botAI->GetUnit(guid);
|
||||||
|
|||||||
@ -208,7 +208,6 @@ uint8 BagSpaceValue::Calculate()
|
|||||||
++totalused;
|
++totalused;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 totalfree = 16 - totalused;
|
|
||||||
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
for (uint8 bag = INVENTORY_SLOT_BAG_START; bag < INVENTORY_SLOT_BAG_END; ++bag)
|
||||||
{
|
{
|
||||||
const Bag* const pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag);
|
const Bag* const pBag = (Bag*)bot->GetItemByPos(INVENTORY_SLOT_BAG_0, bag);
|
||||||
@ -218,7 +217,6 @@ uint8 BagSpaceValue::Calculate()
|
|||||||
if (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER)
|
if (pBagProto->Class == ITEM_CLASS_CONTAINER && pBagProto->SubClass == ITEM_SUBCLASS_CONTAINER)
|
||||||
{
|
{
|
||||||
total += pBag->GetBagSize();
|
total += pBag->GetBagSize();
|
||||||
totalfree += pBag->GetFreeSlots();
|
|
||||||
totalused += pBag->GetBagSize() - pBag->GetFreeSlots();
|
totalused += pBag->GetBagSize() - pBag->GetFreeSlots();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
#include "ObjectAccessor.h"
|
#include "ObjectAccessor.h"
|
||||||
|
|
||||||
using ai::buff::MakeAuraQualifierForBuff;
|
using ai::buff::MakeAuraQualifierForBuff;
|
||||||
using ai::buff::UpgradeToGroupIfAppropriate;
|
|
||||||
|
|
||||||
// Helper : detect tank role on the target (player bot or not) return true if spec is tank or if the bot have tank strategies (bear/tank/tank face).
|
// Helper : detect tank role on the target (player bot or not) return true if spec is tank or if the bot have tank strategies (bear/tank/tank face).
|
||||||
static inline bool IsTankRole(Player* p)
|
static inline bool IsTankRole(Player* p)
|
||||||
@ -53,11 +52,6 @@ static inline bool IsOnlyPaladinInGroup(Player* bot)
|
|||||||
return pals == 1u;
|
return pals == 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool GroupHasTankOfClass(Group* g, uint8 classId)
|
|
||||||
{
|
|
||||||
return GroupHasTankOfClass(g, static_cast<Classes>(classId));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string const GetActualBlessingOfMight(Unit* target)
|
inline std::string const GetActualBlessingOfMight(Unit* target)
|
||||||
{
|
{
|
||||||
if (!target->ToPlayer())
|
if (!target->ToPlayer())
|
||||||
|
|||||||
@ -283,20 +283,6 @@ static uint32 GetRequiredTotemSpellId(PlayerbotAI* ai, const char* strategies[],
|
|||||||
return 0; // No relevant strategy active, or bot doesn't know any rank
|
return 0; // No relevant strategy active, or bot doesn't know any rank
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the spellId of the currently summoned totem in the slot
|
|
||||||
static uint32 GetSummonedTotemSpellId(Player* bot, uint8 slot)
|
|
||||||
{
|
|
||||||
ObjectGuid guid = bot->m_SummonSlot[slot];
|
|
||||||
if (guid.IsEmpty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Creature* totem = bot->GetMap()->GetCreature(guid);
|
|
||||||
if (!totem)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return totem->GetUInt32Value(UNIT_CREATED_BY_SPELL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NoEarthTotemTrigger::IsActive()
|
bool NoEarthTotemTrigger::IsActive()
|
||||||
{
|
{
|
||||||
// Check if the bot has Stoneskin Totem (required level 4) and prevents the trigger firing if it doesn't
|
// Check if the bot has Stoneskin Totem (required level 4) and prevents the trigger firing if it doesn't
|
||||||
|
|||||||
@ -359,10 +359,8 @@ class SetTotemTrigger : public Trigger
|
|||||||
public:
|
public:
|
||||||
// Template constructor: infers N (size of the id array) at compile time
|
// Template constructor: infers N (size of the id array) at compile time
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
SetTotemTrigger(PlayerbotAI* ai, std::string const& spellName, uint32 requiredSpellId,
|
SetTotemTrigger(PlayerbotAI* ai, std::string const& spellName, const uint32 (&ids)[N], int actionButtonId)
|
||||||
const uint32 (&ids)[N], int actionButtonId)
|
|
||||||
: Trigger(ai, "set " + spellName)
|
: Trigger(ai, "set " + spellName)
|
||||||
, requiredSpellId(requiredSpellId)
|
|
||||||
, totemSpellIds(ids)
|
, totemSpellIds(ids)
|
||||||
, totemSpellIdsCount(N)
|
, totemSpellIdsCount(N)
|
||||||
, actionButtonId(actionButtonId)
|
, actionButtonId(actionButtonId)
|
||||||
@ -370,7 +368,6 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32 requiredSpellId;
|
|
||||||
uint32 const* totemSpellIds;
|
uint32 const* totemSpellIds;
|
||||||
size_t totemSpellIdsCount;
|
size_t totemSpellIdsCount;
|
||||||
int actionButtonId;
|
int actionButtonId;
|
||||||
@ -380,119 +377,119 @@ class SetStrengthOfEarthTotemTrigger : public SetTotemTrigger
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStrengthOfEarthTotemTrigger(PlayerbotAI* ai)
|
SetStrengthOfEarthTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "strength of earth totem", SPELL_STRENGTH_OF_EARTH_TOTEM_RANK_1, STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(ai, "strength of earth totem", STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetStoneskinTotemTrigger : public SetTotemTrigger
|
class SetStoneskinTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetStoneskinTotemTrigger(PlayerbotAI* ai)
|
SetStoneskinTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "stoneskin totem", SPELL_STONESKIN_TOTEM_RANK_1, STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(ai, "stoneskin totem", STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTremorTotemTrigger : public SetTotemTrigger
|
class SetTremorTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetTremorTotemTrigger(PlayerbotAI* ai)
|
SetTremorTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "tremor totem", SPELL_TREMOR_TOTEM_RANK_1, TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(ai, "tremor totem", TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetEarthbindTotemTrigger : public SetTotemTrigger
|
class SetEarthbindTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetEarthbindTotemTrigger(PlayerbotAI* ai)
|
SetEarthbindTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "earthbind totem", SPELL_EARTHBIND_TOTEM_RANK_1, EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
: SetTotemTrigger(ai, "earthbind totem", EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetSearingTotemTrigger : public SetTotemTrigger
|
class SetSearingTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetSearingTotemTrigger(PlayerbotAI* ai)
|
SetSearingTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "searing totem", SPELL_SEARING_TOTEM_RANK_1, SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(ai, "searing totem", SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetMagmaTotemTrigger : public SetTotemTrigger
|
class SetMagmaTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetMagmaTotemTrigger(PlayerbotAI* ai)
|
SetMagmaTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "magma totem", SPELL_MAGMA_TOTEM_RANK_1, MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(ai, "magma totem", MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFlametongueTotemTrigger : public SetTotemTrigger
|
class SetFlametongueTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFlametongueTotemTrigger(PlayerbotAI* ai)
|
SetFlametongueTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "flametongue totem", SPELL_FLAMETONGUE_TOTEM_RANK_1, FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(ai, "flametongue totem", FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetTotemOfWrathTrigger : public SetTotemTrigger
|
class SetTotemOfWrathTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetTotemOfWrathTrigger(PlayerbotAI* ai)
|
SetTotemOfWrathTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "totem of wrath", SPELL_TOTEM_OF_WRATH_RANK_1, TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(ai, "totem of wrath", TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFrostResistanceTotemTrigger : public SetTotemTrigger
|
class SetFrostResistanceTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFrostResistanceTotemTrigger(PlayerbotAI* ai)
|
SetFrostResistanceTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "frost resistance totem", SPELL_FROST_RESISTANCE_TOTEM_RANK_1, FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
: SetTotemTrigger(ai, "frost resistance totem", FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetHealingStreamTotemTrigger : public SetTotemTrigger
|
class SetHealingStreamTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetHealingStreamTotemTrigger(PlayerbotAI* ai)
|
SetHealingStreamTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "healing stream totem", SPELL_HEALING_STREAM_TOTEM_RANK_1, HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(ai, "healing stream totem", HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetManaSpringTotemTrigger : public SetTotemTrigger
|
class SetManaSpringTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetManaSpringTotemTrigger(PlayerbotAI* ai)
|
SetManaSpringTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "mana spring totem", SPELL_MANA_SPRING_TOTEM_RANK_1, MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(ai, "mana spring totem", MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetCleansingTotemTrigger : public SetTotemTrigger
|
class SetCleansingTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetCleansingTotemTrigger(PlayerbotAI* ai)
|
SetCleansingTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "cleansing totem", SPELL_CLEANSING_TOTEM_RANK_1, CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(ai, "cleansing totem", CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetFireResistanceTotemTrigger : public SetTotemTrigger
|
class SetFireResistanceTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetFireResistanceTotemTrigger(PlayerbotAI* ai)
|
SetFireResistanceTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "fire resistance totem", SPELL_FIRE_RESISTANCE_TOTEM_RANK_1, FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
: SetTotemTrigger(ai, "fire resistance totem", FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetWrathOfAirTotemTrigger : public SetTotemTrigger
|
class SetWrathOfAirTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetWrathOfAirTotemTrigger(PlayerbotAI* ai)
|
SetWrathOfAirTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "wrath of air totem", SPELL_WRATH_OF_AIR_TOTEM_RANK_1, WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(ai, "wrath of air totem", WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetWindfuryTotemTrigger : public SetTotemTrigger
|
class SetWindfuryTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetWindfuryTotemTrigger(PlayerbotAI* ai)
|
SetWindfuryTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "windfury totem", SPELL_WINDFURY_TOTEM_RANK_1, WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(ai, "windfury totem", WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetNatureResistanceTotemTrigger : public SetTotemTrigger
|
class SetNatureResistanceTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetNatureResistanceTotemTrigger(PlayerbotAI* ai)
|
SetNatureResistanceTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "nature resistance totem", SPELL_NATURE_RESISTANCE_TOTEM_RANK_1, NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(ai, "nature resistance totem", NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetGroundingTotemTrigger : public SetTotemTrigger
|
class SetGroundingTotemTrigger : public SetTotemTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SetGroundingTotemTrigger(PlayerbotAI* ai)
|
SetGroundingTotemTrigger(PlayerbotAI* ai)
|
||||||
: SetTotemTrigger(ai, "grounding totem", SPELL_GROUNDING_TOTEM_RANK_1, GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
: SetTotemTrigger(ai, "grounding totem", GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -17,11 +17,9 @@ bool MoveFromBronjahmAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
bool AttackCorruptedSoulFragmentAction::Execute(Event /*event*/)
|
bool AttackCorruptedSoulFragmentAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||||
|
|
||||||
// If no valid skull target, search for corrupted soul fragment
|
// If no valid skull target, search for corrupted soul fragment
|
||||||
Unit* empoweredPrince = nullptr;
|
|
||||||
for (auto i = targets.begin(); i != targets.end(); ++i)
|
for (auto i = targets.begin(); i != targets.end(); ++i)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(*i);
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
@ -30,8 +28,6 @@ bool AttackCorruptedSoulFragmentAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
if (unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT)
|
if (unit->GetEntry() == NPC_CORRUPTED_SOUL_FRAGMENT)
|
||||||
{
|
{
|
||||||
empoweredPrince = unit;
|
|
||||||
|
|
||||||
// Mark corrupted soul fragment with skull if in group and not already marked
|
// Mark corrupted soul fragment with skull if in group and not already marked
|
||||||
if (Group* group = bot->GetGroup())
|
if (Group* group = bot->GetGroup())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -23,7 +23,6 @@ bool AttackSnakeWrapAction::Execute(Event /*event*/)
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
Unit* snakeWrap = nullptr;
|
|
||||||
// Target is not findable from threat table using AI_VALUE2(),
|
// Target is not findable from threat table using AI_VALUE2(),
|
||||||
// therefore need to search manually for the unit name
|
// therefore need to search manually for the unit name
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||||
|
|||||||
@ -55,10 +55,6 @@ bool ToCLanceAction::Execute(Event /*event*/)
|
|||||||
// If we found the lance, equip it
|
// If we found the lance, equip it
|
||||||
if (lanceItem)
|
if (lanceItem)
|
||||||
{
|
{
|
||||||
// Store the lance's current position
|
|
||||||
uint8 srcBag = lanceItem->GetBagSlot();
|
|
||||||
uint8 srcSlot = lanceItem->GetSlot();
|
|
||||||
|
|
||||||
// First unequip current weapon if it exists
|
// First unequip current weapon if it exists
|
||||||
if (oldWeapon)
|
if (oldWeapon)
|
||||||
bot->SwapItem(oldWeapon->GetPos(), lanceItem->GetPos());
|
bot->SwapItem(oldWeapon->GetPos(), lanceItem->GetPos());
|
||||||
|
|||||||
@ -399,7 +399,9 @@ bool HighKingMaulgarBanishFelstalkerAction::Execute(Event /*event*/)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (warlockIndex >= 0 && warlockIndex < felStalkers.size())
|
const int64_t felStalkersSize = felStalkers.size();
|
||||||
|
|
||||||
|
if (warlockIndex >= 0 && warlockIndex < felStalkersSize)
|
||||||
{
|
{
|
||||||
Unit* assignedFelStalker = felStalkers[warlockIndex];
|
Unit* assignedFelStalker = felStalkers[warlockIndex];
|
||||||
if (!botAI->HasAura("banish", assignedFelStalker) && botAI->CanCastSpell("banish", assignedFelStalker))
|
if (!botAI->HasAura("banish", assignedFelStalker) && botAI->CanCastSpell("banish", assignedFelStalker))
|
||||||
@ -511,7 +513,6 @@ bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
if (distanceToTankPosition > maxDistance)
|
if (distanceToTankPosition > maxDistance)
|
||||||
{
|
{
|
||||||
float step = std::min(maxDistance, distanceToTankPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance;
|
float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance;
|
||||||
float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance;
|
float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance;
|
||||||
const float moveZ = position.GetPositionZ();
|
const float moveZ = position.GetPositionZ();
|
||||||
|
|||||||
@ -1034,8 +1034,6 @@ bool IccDbsTankPositionAction::CrowdControlBloodBeasts()
|
|||||||
NPC_BLOOD_BEAST4};
|
NPC_BLOOD_BEAST4};
|
||||||
const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
|
|
||||||
bool appliedCC = false;
|
|
||||||
|
|
||||||
for (auto const& npc : npcs)
|
for (auto const& npc : npcs)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(npc);
|
Unit* unit = botAI->GetUnit(npc);
|
||||||
@ -1054,73 +1052,43 @@ bool IccDbsTankPositionAction::CrowdControlBloodBeasts()
|
|||||||
{
|
{
|
||||||
case CLASS_MAGE:
|
case CLASS_MAGE:
|
||||||
if (!botAI->HasAura("Frost Nova", unit))
|
if (!botAI->HasAura("Frost Nova", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Frost Nova", unit);
|
botAI->CastSpell("Frost Nova", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (!botAI->HasAura("Entangling Roots", unit))
|
if (!botAI->HasAura("Entangling Roots", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Entangling Roots", unit);
|
botAI->CastSpell("Entangling Roots", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_PALADIN:
|
case CLASS_PALADIN:
|
||||||
if (!botAI->HasAura("Hammer of Justice", unit))
|
if (!botAI->HasAura("Hammer of Justice", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Hammer of Justice", unit);
|
botAI->CastSpell("Hammer of Justice", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (!botAI->HasAura("Hamstring", unit))
|
if (!botAI->HasAura("Hamstring", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Hamstring", unit);
|
botAI->CastSpell("Hamstring", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_HUNTER:
|
case CLASS_HUNTER:
|
||||||
if (!botAI->HasAura("Concussive Shot", unit))
|
if (!botAI->HasAura("Concussive Shot", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Concussive Shot", unit);
|
botAI->CastSpell("Concussive Shot", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (!botAI->HasAura("Kidney Shot", unit))
|
if (!botAI->HasAura("Kidney Shot", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Kidney Shot", unit);
|
botAI->CastSpell("Kidney Shot", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (!botAI->HasAura("Frost Shock", unit))
|
if (!botAI->HasAura("Frost Shock", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Frost Shock", unit);
|
botAI->CastSpell("Frost Shock", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (!botAI->HasAura("Chains of Ice", unit))
|
if (!botAI->HasAura("Chains of Ice", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Chains of Ice", unit);
|
botAI->CastSpell("Chains of Ice", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
if (!botAI->HasAura("Psychic Scream", unit))
|
if (!botAI->HasAura("Psychic Scream", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Psychic Scream", unit);
|
botAI->CastSpell("Psychic Scream", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
if (!botAI->HasAura("Fear", unit))
|
if (!botAI->HasAura("Fear", unit))
|
||||||
{
|
|
||||||
botAI->CastSpell("Fear", unit);
|
botAI->CastSpell("Fear", unit);
|
||||||
appliedCC = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1464,7 +1432,6 @@ int IccFestergutGroupPositionAction::CalculatePositionIndex(Group* group)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Fill remaining spots in second row
|
// Fill remaining spots in second row
|
||||||
int spotsInFirstRow = 6;
|
|
||||||
int spotsInSecondRow = healerSpotsUsed - 6;
|
int spotsInSecondRow = healerSpotsUsed - 6;
|
||||||
int remainingInSecondRow = 6 - spotsInSecondRow;
|
int remainingInSecondRow = 6 - spotsInSecondRow;
|
||||||
|
|
||||||
@ -1511,7 +1478,6 @@ int IccFestergutGroupPositionAction::CalculatePositionIndex(Group* group)
|
|||||||
bool IccFestergutSporeAction::Execute(Event /*event*/)
|
bool IccFestergutSporeAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
constexpr float POSITION_TOLERANCE = 4.0f;
|
constexpr float POSITION_TOLERANCE = 4.0f;
|
||||||
constexpr float SPREAD_RADIUS = 2.0f;
|
|
||||||
|
|
||||||
// Check if bot has spore
|
// Check if bot has spore
|
||||||
bool hasSpore = bot->HasAura(SPELL_GAS_SPORE); // gas spore
|
bool hasSpore = bot->HasAura(SPELL_GAS_SPORE); // gas spore
|
||||||
@ -1661,7 +1627,7 @@ bool IccRotfaceTankPositionAction::PositionMainTankAndMelee(Unit* boss)
|
|||||||
{
|
{
|
||||||
bool isBossCasting = false;
|
bool isBossCasting = false;
|
||||||
if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->GetCurrentSpell(SPELL_SLIME_SPRAY))
|
if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->GetCurrentSpell(SPELL_SLIME_SPRAY))
|
||||||
bool isBossCasting = true;
|
isBossCasting = true;
|
||||||
|
|
||||||
if (bot->GetExactDist2d(ICC_ROTFACE_CENTER_POSITION) > 7.0f && botAI->HasAggro(boss) && botAI->IsMainTank(bot))
|
if (bot->GetExactDist2d(ICC_ROTFACE_CENTER_POSITION) > 7.0f && botAI->HasAggro(boss) && botAI->IsMainTank(bot))
|
||||||
MoveTo(bot->GetMapId(), ICC_ROTFACE_CENTER_POSITION.GetPositionX(),
|
MoveTo(bot->GetMapId(), ICC_ROTFACE_CENTER_POSITION.GetPositionX(),
|
||||||
@ -1829,21 +1795,7 @@ bool IccRotfaceGroupPositionAction::Execute(Event /*event*/)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
const GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
bool floodPresent = false;
|
|
||||||
|
|
||||||
for (auto const& npc : npcs)
|
|
||||||
{
|
|
||||||
Unit* unit = botAI->GetUnit(npc);
|
|
||||||
if (!unit || !botAI->HasAura("Ooze Flood", unit))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float puddleDistance = bot->GetExactDist2d(unit);
|
|
||||||
|
|
||||||
if (puddleDistance < 30.0f)
|
|
||||||
floodPresent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unit* bigOoze = AI_VALUE2(Unit*, "find target", "big ooze");
|
|
||||||
bool hasOozeFlood = botAI->HasAura("Ooze Flood", bot);
|
bool hasOozeFlood = botAI->HasAura("Ooze Flood", bot);
|
||||||
Unit* smallOoze = AI_VALUE2(Unit*, "find target", "little ooze");
|
Unit* smallOoze = AI_VALUE2(Unit*, "find target", "little ooze");
|
||||||
bool hasMutatedInfection = botAI->HasAura("Mutated Infection", bot);
|
bool hasMutatedInfection = botAI->HasAura("Mutated Infection", bot);
|
||||||
@ -2014,7 +1966,7 @@ bool IccRotfaceGroupPositionAction::PositionRangedAndHealers(Unit* boss,Unit *sm
|
|||||||
Difficulty diff = bot->GetRaidDifficulty();
|
Difficulty diff = bot->GetRaidDifficulty();
|
||||||
bool isBossCasting = false;
|
bool isBossCasting = false;
|
||||||
if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->GetCurrentSpell(SPELL_SLIME_SPRAY))
|
if (boss && boss->HasUnitState(UNIT_STATE_CASTING) && boss->GetCurrentSpell(SPELL_SLIME_SPRAY))
|
||||||
bool isBossCasting = true;
|
isBossCasting = true;
|
||||||
|
|
||||||
bool isHeroic = (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC);
|
bool isHeroic = (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC);
|
||||||
|
|
||||||
@ -2070,7 +2022,6 @@ bool IccRotfaceGroupPositionAction::FindAndMoveFromClosestMember(Unit* boss, Uni
|
|||||||
const float maxMoveDistance = 12.0f; // Limit maximum movement distance
|
const float maxMoveDistance = 12.0f; // Limit maximum movement distance
|
||||||
const float puddleSafeDistance = 30.0f; // Minimum distance to stay away from puddle
|
const float puddleSafeDistance = 30.0f; // Minimum distance to stay away from puddle
|
||||||
const float minCenterDistance = 20.0f; // Minimum distance from center position
|
const float minCenterDistance = 20.0f; // Minimum distance from center position
|
||||||
const bool isRanged = botAI->IsRanged(bot) || botAI->IsHeal(bot);
|
|
||||||
|
|
||||||
// Ranged: spread from other members
|
// Ranged: spread from other members
|
||||||
const GuidVector members = AI_VALUE(GuidVector, "group members");
|
const GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||||
@ -2233,7 +2184,6 @@ bool IccRotfaceMoveAwayFromExplosionAction::MoveToRandomSafeLocation()
|
|||||||
// Move in increments of 5.0f towards the calculated position
|
// Move in increments of 5.0f towards the calculated position
|
||||||
float currentX = bot->GetPositionX();
|
float currentX = bot->GetPositionX();
|
||||||
float currentY = bot->GetPositionY();
|
float currentY = bot->GetPositionY();
|
||||||
float currentZ = bot->GetPositionZ();
|
|
||||||
|
|
||||||
float directionX = moveX - currentX;
|
float directionX = moveX - currentX;
|
||||||
float directionY = moveY - currentY;
|
float directionY = moveY - currentY;
|
||||||
@ -2276,7 +2226,6 @@ Unit* IccPutricideGrowingOozePuddleAction::FindClosestThreateningPuddle()
|
|||||||
|
|
||||||
Unit* closestPuddle = nullptr;
|
Unit* closestPuddle = nullptr;
|
||||||
float closestDistance = FLT_MAX;
|
float closestDistance = FLT_MAX;
|
||||||
float closestSafeDistance = BASE_RADIUS;
|
|
||||||
|
|
||||||
for (auto const& npc : npcs)
|
for (auto const& npc : npcs)
|
||||||
{
|
{
|
||||||
@ -2293,7 +2242,6 @@ Unit* IccPutricideGrowingOozePuddleAction::FindClosestThreateningPuddle()
|
|||||||
if (currentDistance < safeDistance && currentDistance < closestDistance)
|
if (currentDistance < safeDistance && currentDistance < closestDistance)
|
||||||
{
|
{
|
||||||
closestDistance = currentDistance;
|
closestDistance = currentDistance;
|
||||||
closestSafeDistance = safeDistance;
|
|
||||||
closestPuddle = unit;
|
closestPuddle = unit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3648,7 +3596,6 @@ bool IccBpcKineticBombAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
Unit* IccBpcKineticBombAction::FindOptimalKineticBomb()
|
Unit* IccBpcKineticBombAction::FindOptimalKineticBomb()
|
||||||
{
|
{
|
||||||
static constexpr float MAX_HEIGHT_DIFF = 20.0f;
|
|
||||||
static constexpr std::array<uint32_t, 4> KINETIC_BOMB_ENTRIES = {NPC_KINETIC_BOMB1, NPC_KINETIC_BOMB2,
|
static constexpr std::array<uint32_t, 4> KINETIC_BOMB_ENTRIES = {NPC_KINETIC_BOMB1, NPC_KINETIC_BOMB2,
|
||||||
NPC_KINETIC_BOMB3, NPC_KINETIC_BOMB4};
|
NPC_KINETIC_BOMB3, NPC_KINETIC_BOMB4};
|
||||||
|
|
||||||
@ -4012,7 +3959,6 @@ bool IccBqlGroupPositionAction::HandleShadowsMovement()
|
|||||||
|
|
||||||
// Find closest safe point by searching in both directions from closest point
|
// Find closest safe point by searching in both directions from closest point
|
||||||
Position safeMoveTarget = closestPoint;
|
Position safeMoveTarget = closestPoint;
|
||||||
float safeMoveTargetDist = FLT_MAX;
|
|
||||||
bool foundSafe = closestIsSafe;
|
bool foundSafe = closestIsSafe;
|
||||||
|
|
||||||
// Only search for safe spots if the closest point isn't already safe
|
// Only search for safe spots if the closest point isn't already safe
|
||||||
@ -4083,7 +4029,6 @@ bool IccBqlGroupPositionAction::HandleShadowsMovement()
|
|||||||
if (foundSafe)
|
if (foundSafe)
|
||||||
{
|
{
|
||||||
// If we found a safe point, penalize based on travel distance along the curve to reach it
|
// If we found a safe point, penalize based on travel distance along the curve to reach it
|
||||||
float stepsToCurve = minDist / 2.0f; // Approximate steps to reach the curve
|
|
||||||
float safeDist = bot->GetExactDist2d(safeMoveTarget);
|
float safeDist = bot->GetExactDist2d(safeMoveTarget);
|
||||||
|
|
||||||
// Add distance penalty based on how far we need to move along the curve
|
// Add distance penalty based on how far we need to move along the curve
|
||||||
@ -4364,7 +4309,6 @@ bool IccBqlGroupPositionAction::HandleGroupPosition(Unit* boss, Aura* frenzyAura
|
|||||||
rangedBots.erase(std::remove(rangedBots.begin(), rangedBots.end(), h), rangedBots.end());
|
rangedBots.erase(std::remove(rangedBots.begin(), rangedBots.end(), h), rangedBots.end());
|
||||||
|
|
||||||
// Distribute remaining ranged evenly
|
// Distribute remaining ranged evenly
|
||||||
size_t totalRanged = leftSide.size() + rightSide.size() + rangedBots.size();
|
|
||||||
size_t leftCount = leftSide.size();
|
size_t leftCount = leftSide.size();
|
||||||
size_t rightCount = rightSide.size();
|
size_t rightCount = rightSide.size();
|
||||||
for (Player* p : rangedBots)
|
for (Player* p : rangedBots)
|
||||||
@ -5562,7 +5506,6 @@ bool IccValithriaDreamCloudAction::Execute(Event /*event*/)
|
|||||||
auto it = std::find(dreamBots.begin(), dreamBots.end(), bot);
|
auto it = std::find(dreamBots.begin(), dreamBots.end(), bot);
|
||||||
if (it == dreamBots.end())
|
if (it == dreamBots.end())
|
||||||
return false;
|
return false;
|
||||||
size_t myIndex = std::distance(dreamBots.begin(), it);
|
|
||||||
|
|
||||||
// Check if all dream bots are stacked within 3f of the current leader (lowest guid)
|
// Check if all dream bots are stacked within 3f of the current leader (lowest guid)
|
||||||
constexpr float STACK_RADIUS = 2.0f;
|
constexpr float STACK_RADIUS = 2.0f;
|
||||||
@ -6699,7 +6642,6 @@ bool IccSindragosaFrostBombAction::Execute(Event /*event*/)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Unit* losTomb = myTombs[bestIdx];
|
Unit* losTomb = myTombs[bestIdx];
|
||||||
ObjectGuid losTombGuid = myTombGuids[bestIdx];
|
|
||||||
|
|
||||||
// Calculate position for LOS (stand at least 6.5f behind the tomb from the bomb)
|
// Calculate position for LOS (stand at least 6.5f behind the tomb from the bomb)
|
||||||
float angle = marker->GetAngle(losTomb);
|
float angle = marker->GetAngle(losTomb);
|
||||||
@ -6782,7 +6724,6 @@ bool IccSindragosaFrostBombAction::Execute(Event /*event*/)
|
|||||||
// Clear the marker for our group's icon
|
// Clear the marker for our group's icon
|
||||||
group->SetTargetIcon(iconIndex, bot->GetGUID(), ObjectGuid::Empty);
|
group->SetTargetIcon(iconIndex, bot->GetGUID(), ObjectGuid::Empty);
|
||||||
}
|
}
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sindragosa");
|
|
||||||
bot->AttackStop();
|
bot->AttackStop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -7021,10 +6962,7 @@ bool IccLichKingWinterAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
const ObjectGuid currentSkullTarget = group->GetTargetIcon(7);
|
const ObjectGuid currentSkullTarget = group->GetTargetIcon(7);
|
||||||
if (!currentSkullTarget.IsEmpty())
|
if (!currentSkullTarget.IsEmpty())
|
||||||
{
|
|
||||||
Unit* skullTarget = ObjectAccessor::GetUnit(*bot, currentSkullTarget);
|
|
||||||
group->SetTargetIcon(7, bot->GetGUID(), ObjectGuid::Empty);
|
group->SetTargetIcon(7, bot->GetGUID(), ObjectGuid::Empty);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVictim)
|
if (isVictim)
|
||||||
@ -7802,7 +7740,6 @@ bool IccLichKingAddsAction::Execute(Event /*event*/)
|
|||||||
//------CHEAT-------
|
//------CHEAT-------
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit* spiritWarden = AI_VALUE2(Unit*, "find target", "spirit warden");
|
|
||||||
bool hasPlague = botAI->HasAura("Necrotic Plague", bot);
|
bool hasPlague = botAI->HasAura("Necrotic Plague", bot);
|
||||||
Unit* terenasMenethilHC = bot->FindNearestCreature(NPC_TERENAS_MENETHIL_HC, 55.0f);
|
Unit* terenasMenethilHC = bot->FindNearestCreature(NPC_TERENAS_MENETHIL_HC, 55.0f);
|
||||||
|
|
||||||
@ -8475,8 +8412,6 @@ bool IccLichKingAddsAction::HandleAssistTankAddManagement(Unit* boss, Difficulty
|
|||||||
// In heroic mode, stay at melee position
|
// In heroic mode, stay at melee position
|
||||||
if (diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC))
|
if (diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC))
|
||||||
{
|
{
|
||||||
Unit* mainTank = AI_VALUE(Unit*, "main tank");
|
|
||||||
|
|
||||||
if (bot->GetExactDist2d(ICC_LICH_KING_ASSISTHC_POSITION.GetPositionX(),
|
if (bot->GetExactDist2d(ICC_LICH_KING_ASSISTHC_POSITION.GetPositionX(),
|
||||||
ICC_LICH_KING_ASSISTHC_POSITION.GetPositionY()) > 2.0f)
|
ICC_LICH_KING_ASSISTHC_POSITION.GetPositionY()) > 2.0f)
|
||||||
{
|
{
|
||||||
@ -8713,7 +8648,6 @@ void IccLichKingAddsAction::HandleDefileMechanics(Unit* boss, Difficulty diff)
|
|||||||
|
|
||||||
// Gather all defile units
|
// Gather all defile units
|
||||||
std::vector<Unit*> defiles;
|
std::vector<Unit*> defiles;
|
||||||
Unit* closestDefile = nullptr;
|
|
||||||
float closestDistance = std::numeric_limits<float>::max();
|
float closestDistance = std::numeric_limits<float>::max();
|
||||||
|
|
||||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
@ -8725,10 +8659,7 @@ void IccLichKingAddsAction::HandleDefileMechanics(Unit* boss, Difficulty diff)
|
|||||||
defiles.push_back(unit);
|
defiles.push_back(unit);
|
||||||
float dist = bot->GetDistance(unit);
|
float dist = bot->GetDistance(unit);
|
||||||
if (dist < closestDistance)
|
if (dist < closestDistance)
|
||||||
{
|
|
||||||
closestDistance = dist;
|
closestDistance = dist;
|
||||||
closestDefile = unit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9068,7 +8999,6 @@ void IccLichKingAddsAction::HandleValkyrMarking(const std::vector<Unit*>& grabbi
|
|||||||
std::sort(sortedValkyrs.begin(), sortedValkyrs.end(), [](Unit* a, Unit* b) { return a->GetGUID() < b->GetGUID(); });
|
std::sort(sortedValkyrs.begin(), sortedValkyrs.end(), [](Unit* a, Unit* b) { return a->GetGUID() < b->GetGUID(); });
|
||||||
|
|
||||||
static constexpr uint8_t ICON_INDICES[] = {7, 6, 0}; // Skull, Cross, Star
|
static constexpr uint8_t ICON_INDICES[] = {7, 6, 0}; // Skull, Cross, Star
|
||||||
static constexpr const char* ICON_NAMES[] = {"skull", "cross", "star"};
|
|
||||||
|
|
||||||
// In heroic mode, clean up invalid markers for all possible icons
|
// In heroic mode, clean up invalid markers for all possible icons
|
||||||
if (diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC))
|
if (diff && (diff == RAID_DIFFICULTY_10MAN_HEROIC || diff == RAID_DIFFICULTY_25MAN_HEROIC))
|
||||||
|
|||||||
@ -24,8 +24,6 @@
|
|||||||
// LK global variables
|
// LK global variables
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
uint32 g_lastPlagueTime = 0;
|
|
||||||
bool g_plagueAllowedToCure = false;
|
|
||||||
std::map<ObjectGuid, uint32> g_plagueTimes;
|
std::map<ObjectGuid, uint32> g_plagueTimes;
|
||||||
std::map<ObjectGuid, bool> g_allowCure;
|
std::map<ObjectGuid, bool> g_allowCure;
|
||||||
std::mutex g_plagueMutex; // Lock before accessing shared variables
|
std::mutex g_plagueMutex; // Lock before accessing shared variables
|
||||||
|
|||||||
@ -1102,7 +1102,6 @@ bool IccLichKingShadowTrapTrigger::IsActive()
|
|||||||
// search for all nearby traps
|
// search for all nearby traps
|
||||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
std::vector<Unit*> nearbyTraps;
|
std::vector<Unit*> nearbyTraps;
|
||||||
bool needToMove = false;
|
|
||||||
|
|
||||||
for (auto& npc : npcs)
|
for (auto& npc : npcs)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -870,7 +870,6 @@ bool NetherspiteAvoidBeamAndVoidZoneAction::Execute(Event /*event*/)
|
|||||||
if (!netherspite)
|
if (!netherspite)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto [redBlocker, greenBlocker, blueBlocker] = GetCurrentBeamBlockers(botAI, bot);
|
|
||||||
std::vector<Unit*> voidZones = GetAllVoidZones(botAI, bot);
|
std::vector<Unit*> voidZones = GetAllVoidZones(botAI, bot);
|
||||||
|
|
||||||
bool nearVoidZone = !IsSafePosition(bot->GetPositionX(), bot->GetPositionY(),
|
bool nearVoidZone = !IsSafePosition(bot->GetPositionX(), bot->GetPositionY(),
|
||||||
|
|||||||
@ -8,9 +8,6 @@ bool SartharionTankPositionAction::Execute(Event /*event*/)
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "sartharion");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
// Unit* shadron = AI_VALUE2(Unit*, "find target", "shadron");
|
|
||||||
// Unit* tenebron = AI_VALUE2(Unit*, "find target", "tenebron");
|
|
||||||
// Unit* vesperon = AI_VALUE2(Unit*, "find target", "vesperon");
|
|
||||||
Unit* shadron = nullptr;
|
Unit* shadron = nullptr;
|
||||||
Unit* tenebron = nullptr;
|
Unit* tenebron = nullptr;
|
||||||
Unit* vesperon = nullptr;
|
Unit* vesperon = nullptr;
|
||||||
@ -96,9 +93,7 @@ bool AvoidTwilightFissureAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
float currentDistance = bot->GetDistance2d(unit);
|
float currentDistance = bot->GetDistance2d(unit);
|
||||||
if (currentDistance < radius)
|
if (currentDistance < radius)
|
||||||
{
|
|
||||||
return MoveAway(unit, radius - currentDistance);
|
return MoveAway(unit, radius - currentDistance);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -127,39 +122,29 @@ bool AvoidFlameTsunamiAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
bool wavePassed = currentPos.GetPositionX() > unit->GetPositionX();
|
bool wavePassed = currentPos.GetPositionX() > unit->GetPositionX();
|
||||||
if (wavePassed)
|
if (wavePassed)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL) > looseDistance)
|
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL) > looseDistance)
|
||||||
{
|
|
||||||
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL, currentPos.GetPositionZ(),
|
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_RIGHT_SAFE_ALL, currentPos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else // LEFT WAVE
|
else // LEFT WAVE
|
||||||
{
|
{
|
||||||
bool wavePassed = currentPos.GetPositionX() < unit->GetPositionX();
|
bool wavePassed = currentPos.GetPositionX() < unit->GetPositionX();
|
||||||
if (wavePassed)
|
if (wavePassed)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMelee(bot))
|
if (botAI->IsMelee(bot))
|
||||||
{
|
{
|
||||||
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE) > looseDistance)
|
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE) > looseDistance)
|
||||||
{
|
|
||||||
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE, currentPos.GetPositionZ(),
|
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_MELEE, currentPos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else // Ranged/healers
|
else // Ranged/healers
|
||||||
{
|
{
|
||||||
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED) > looseDistance)
|
if (bot->GetExactDist2d(currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED) > looseDistance)
|
||||||
{
|
|
||||||
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED, currentPos.GetPositionZ(),
|
return MoveTo(OS_MAP_ID, currentPos.GetPositionX(), TSUNAMI_LEFT_SAFE_RANGED, currentPos.GetPositionZ(),
|
||||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,30 +163,18 @@ bool SartharionAttackPriorityAction::Execute(Event /*event*/)
|
|||||||
Unit* target = nullptr;
|
Unit* target = nullptr;
|
||||||
|
|
||||||
if (acolyte)
|
if (acolyte)
|
||||||
{
|
|
||||||
target = acolyte;
|
target = acolyte;
|
||||||
}
|
|
||||||
else if (vesperon)
|
else if (vesperon)
|
||||||
{
|
|
||||||
target = vesperon;
|
target = vesperon;
|
||||||
}
|
|
||||||
else if (tenebron)
|
else if (tenebron)
|
||||||
{
|
|
||||||
target = tenebron;
|
target = tenebron;
|
||||||
}
|
|
||||||
else if (shadron)
|
else if (shadron)
|
||||||
{
|
|
||||||
target = shadron;
|
target = shadron;
|
||||||
}
|
|
||||||
else if (sartharion)
|
else if (sartharion)
|
||||||
{
|
|
||||||
target = sartharion;
|
target = sartharion;
|
||||||
}
|
|
||||||
|
|
||||||
if (target && AI_VALUE(Unit*, "current target") != target)
|
if (target && AI_VALUE(Unit*, "current target") != target)
|
||||||
{
|
|
||||||
return Attack(target);
|
return Attack(target);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -215,9 +188,7 @@ bool EnterTwilightPortalAction::Execute(Event /*event*/)
|
|||||||
if (!portal) { return false; }
|
if (!portal) { return false; }
|
||||||
|
|
||||||
if (!portal->IsAtInteractDistance(bot))
|
if (!portal->IsAtInteractDistance(bot))
|
||||||
{
|
|
||||||
return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f));
|
return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f));
|
||||||
}
|
|
||||||
|
|
||||||
// Go through portal
|
// Go through portal
|
||||||
WorldPacket data1(CMSG_GAMEOBJ_USE);
|
WorldPacket data1(CMSG_GAMEOBJ_USE);
|
||||||
@ -230,12 +201,11 @@ bool EnterTwilightPortalAction::Execute(Event /*event*/)
|
|||||||
bool ExitTwilightPortalAction::Execute(Event /*event*/)
|
bool ExitTwilightPortalAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
GameObject* portal = bot->FindNearestGameObject(GO_NORMAL_PORTAL, 100.0f);
|
GameObject* portal = bot->FindNearestGameObject(GO_NORMAL_PORTAL, 100.0f);
|
||||||
if (!portal) { return false; }
|
if (!portal)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!portal->IsAtInteractDistance(bot))
|
if (!portal->IsAtInteractDistance(bot))
|
||||||
{
|
|
||||||
return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f));
|
return MoveTo(portal, fmaxf(portal->GetInteractionDistance() - 1.0f, 0.0f));
|
||||||
}
|
|
||||||
|
|
||||||
// Go through portal
|
// Go through portal
|
||||||
WorldPacket data1(CMSG_GAMEOBJ_USE);
|
WorldPacket data1(CMSG_GAMEOBJ_USE);
|
||||||
|
|||||||
@ -77,39 +77,101 @@ void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target)
|
|||||||
// Intended for purposes of storing and erasing timers and trackers in associative containers
|
// Intended for purposes of storing and erasing timers and trackers in associative containers
|
||||||
bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude)
|
bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude)
|
||||||
{
|
{
|
||||||
if (Group* group = bot->GetGroup())
|
if (!botAI->IsDps(bot) || !bot->IsAlive() || bot->GetMapId() != mapId)
|
||||||
{
|
return false;
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member || !member->IsAlive() || member->GetMapId() != mapId ||
|
|
||||||
!GET_PLAYERBOT_AI(member) || !botAI->IsDps(member))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (member != exclude)
|
Group* group = bot->GetGroup();
|
||||||
return member == bot;
|
if (!group)
|
||||||
}
|
return false;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member->GetMapId() != mapId || member == exclude)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PlayerbotAI* memberAI = GET_PLAYERBOT_AI(member);
|
||||||
|
if (!memberAI || !memberAI->IsDps(member))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return member == bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the first matching alive unit from a cell search of nearby npcs
|
// Requires the main tank to be alive
|
||||||
// More responsive than "find target," but performance cost is much higher
|
// Note that IsMainTank() will return the player with the main tank flag, even if dead
|
||||||
// Re: using the third parameter (false by default), some units are never considered
|
Player* GetGroupMainTank(PlayerbotAI* botAI, Player* bot)
|
||||||
// to be in combat (e.g., totems)
|
{
|
||||||
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry, bool requireInCombat)
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (botAI->IsMainTank(member))
|
||||||
|
return member;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the alive assist tank of the specified index (0 = first, 1 = second, etc.)
|
||||||
|
// Priority: Assistants first, then Non-Assistants.
|
||||||
|
Player* GetGroupAssistTank(PlayerbotAI* botAI, Player* bot, uint8 index)
|
||||||
|
{
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
uint8 assistantCount = 0;
|
||||||
|
std::vector<Player*> nonAssistantTanks;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (botAI->IsAssistTank(member))
|
||||||
|
{
|
||||||
|
if (group->IsAssistant(member->GetGUID()))
|
||||||
|
{
|
||||||
|
if (assistantCount == index)
|
||||||
|
return member;
|
||||||
|
|
||||||
|
assistantCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nonAssistantTanks.push_back(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the index wasn't found among assistants, check the non-assistants that were saved
|
||||||
|
uint8 nonAssistantIndex = index - assistantCount;
|
||||||
|
if (nonAssistantIndex < nonAssistantTanks.size())
|
||||||
|
return nonAssistantTanks[nonAssistantIndex];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first matching alive unit from PossibleTargetsValue within sightDistance from config
|
||||||
|
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry)
|
||||||
{
|
{
|
||||||
auto const& npcs =
|
auto const& npcs =
|
||||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los")->Get();
|
||||||
for (auto const& npcGuid : npcs)
|
for (auto const& npcGuid : npcs)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(npcGuid);
|
Unit* unit = botAI->GetUnit(npcGuid);
|
||||||
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
|
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
|
||||||
{
|
return unit;
|
||||||
if (!requireInCombat || unit->IsInCombat())
|
|
||||||
return unit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|||||||
@ -15,7 +15,10 @@ void MarkTargetWithCross(Player* bot, Unit* target);
|
|||||||
void MarkTargetWithMoon(Player* bot, Unit* target);
|
void MarkTargetWithMoon(Player* bot, Unit* target);
|
||||||
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target);
|
||||||
bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude = nullptr);
|
bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude = nullptr);
|
||||||
Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry, bool requireInCombat = false);
|
Player* GetGroupMainTank(PlayerbotAI* botAI, Player* bot);
|
||||||
|
Player* GetGroupAssistTank(PlayerbotAI* botAI, Player* bot, uint8 index);
|
||||||
|
Unit* GetFirstAliveUnitByEntry(
|
||||||
|
PlayerbotAI* botAI, uint32 entry);
|
||||||
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
|
Unit* GetNearestPlayerInRadius(Player* bot, float radius);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6,9 +6,10 @@
|
|||||||
#include "RaidMcStrategy.h"
|
#include "RaidMcStrategy.h"
|
||||||
#include "RaidBwlStrategy.h"
|
#include "RaidBwlStrategy.h"
|
||||||
#include "RaidKarazhanStrategy.h"
|
#include "RaidKarazhanStrategy.h"
|
||||||
#include "RaidMagtheridonStrategy.h"
|
|
||||||
#include "RaidGruulsLairStrategy.h"
|
#include "RaidGruulsLairStrategy.h"
|
||||||
|
#include "RaidMagtheridonStrategy.h"
|
||||||
#include "RaidSSCStrategy.h"
|
#include "RaidSSCStrategy.h"
|
||||||
|
#include "RaidTempestKeepStrategy.h"
|
||||||
#include "RaidOsStrategy.h"
|
#include "RaidOsStrategy.h"
|
||||||
#include "RaidEoEStrategy.h"
|
#include "RaidEoEStrategy.h"
|
||||||
#include "RaidVoAStrategy.h"
|
#include "RaidVoAStrategy.h"
|
||||||
@ -25,9 +26,10 @@ public:
|
|||||||
creators["moltencore"] = &RaidStrategyContext::moltencore;
|
creators["moltencore"] = &RaidStrategyContext::moltencore;
|
||||||
creators["bwl"] = &RaidStrategyContext::bwl;
|
creators["bwl"] = &RaidStrategyContext::bwl;
|
||||||
creators["karazhan"] = &RaidStrategyContext::karazhan;
|
creators["karazhan"] = &RaidStrategyContext::karazhan;
|
||||||
creators["magtheridon"] = &RaidStrategyContext::magtheridon;
|
|
||||||
creators["gruulslair"] = &RaidStrategyContext::gruulslair;
|
creators["gruulslair"] = &RaidStrategyContext::gruulslair;
|
||||||
|
creators["magtheridon"] = &RaidStrategyContext::magtheridon;
|
||||||
creators["ssc"] = &RaidStrategyContext::ssc;
|
creators["ssc"] = &RaidStrategyContext::ssc;
|
||||||
|
creators["tempestkeep"] = &RaidStrategyContext::tempestkeep;
|
||||||
creators["wotlk-os"] = &RaidStrategyContext::wotlk_os;
|
creators["wotlk-os"] = &RaidStrategyContext::wotlk_os;
|
||||||
creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe;
|
creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe;
|
||||||
creators["voa"] = &RaidStrategyContext::voa;
|
creators["voa"] = &RaidStrategyContext::voa;
|
||||||
@ -41,9 +43,10 @@ private:
|
|||||||
static Strategy* moltencore(PlayerbotAI* botAI) { return new RaidMcStrategy(botAI); }
|
static Strategy* moltencore(PlayerbotAI* botAI) { return new RaidMcStrategy(botAI); }
|
||||||
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
|
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
|
||||||
static Strategy* karazhan(PlayerbotAI* botAI) { return new RaidKarazhanStrategy(botAI); }
|
static Strategy* karazhan(PlayerbotAI* botAI) { return new RaidKarazhanStrategy(botAI); }
|
||||||
static Strategy* magtheridon(PlayerbotAI* botAI) { return new RaidMagtheridonStrategy(botAI); }
|
|
||||||
static Strategy* gruulslair(PlayerbotAI* botAI) { return new RaidGruulsLairStrategy(botAI); }
|
static Strategy* gruulslair(PlayerbotAI* botAI) { return new RaidGruulsLairStrategy(botAI); }
|
||||||
|
static Strategy* magtheridon(PlayerbotAI* botAI) { return new RaidMagtheridonStrategy(botAI); }
|
||||||
static Strategy* ssc(PlayerbotAI* botAI) { return new RaidSSCStrategy(botAI); }
|
static Strategy* ssc(PlayerbotAI* botAI) { return new RaidSSCStrategy(botAI); }
|
||||||
|
static Strategy* tempestkeep(PlayerbotAI* botAI) { return new RaidTempestKeepStrategy(botAI); }
|
||||||
static Strategy* wotlk_os(PlayerbotAI* botAI) { return new RaidOsStrategy(botAI); }
|
static Strategy* wotlk_os(PlayerbotAI* botAI) { return new RaidOsStrategy(botAI); }
|
||||||
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }
|
static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); }
|
||||||
static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); }
|
static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); }
|
||||||
|
|||||||
2050
src/Ai/Raid/TempestKeep/Action/RaidTempestKeepActions.cpp
Normal file
2050
src/Ai/Raid/TempestKeep/Action/RaidTempestKeepActions.cpp
Normal file
File diff suppressed because it is too large
Load Diff
413
src/Ai/Raid/TempestKeep/Action/RaidTempestKeepActions.h
Normal file
413
src/Ai/Raid/TempestKeep/Action/RaidTempestKeepActions.h
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPACTIONS_H
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPACTIONS_H
|
||||||
|
|
||||||
|
#include "RaidTempestKeepHelpers.h"
|
||||||
|
#include "RaidTempestKeepKaelthasBossAI.h"
|
||||||
|
#include "Action.h"
|
||||||
|
#include "AttackAction.h"
|
||||||
|
#include "MovementActions.h"
|
||||||
|
|
||||||
|
using namespace TempestKeepHelpers;
|
||||||
|
|
||||||
|
// Trash
|
||||||
|
|
||||||
|
class CrimsonHandCenturionCastPolymorphAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CrimsonHandCenturionCastPolymorphAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "crimson hand centurion cast polymorph") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
|
||||||
|
class AlarMisdirectBossToMainTankAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarMisdirectBossToMainTankAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar misdirect boss to main tank") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarBossTanksMoveBetweenPlatformsAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarBossTanksMoveBetweenPlatformsAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar boss tanks move between platforms") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool PositionMainTank(Unit* alar, int8 locationIndex);
|
||||||
|
bool PositionAssistTank(Unit* alar, int8 locationIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarMeleeDpsMoveBetweenPlatformsAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarMeleeDpsMoveBetweenPlatformsAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar melee dps move between platforms") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarRangedAndEmberTankMoveUnderPlatformsAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarRangedAndEmberTankMoveUnderPlatformsAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar ranged and ember tank move under platforms") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarAssistTanksPickUpEmbersAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarAssistTanksPickUpEmbersAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar assist tanks pick up embers") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool HandlePhase1Embers(Unit* alar);
|
||||||
|
bool HandlePhase2Embers(Unit* alar);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarRangedDpsPrioritizeEmbersAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarRangedDpsPrioritizeEmbersAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar ranged dps prioritize embers") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarJumpFromPlatformAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarJumpFromPlatformAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar jump from platform") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarMoveAwayFromRebirthAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarMoveAwayFromRebirthAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar move away from rebirth") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarSwapTanksOnBossAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarSwapTanksOnBossAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar swap tanks on boss") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarAvoidFlamePatchesAndDiveBombsAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarAvoidFlamePatchesAndDiveBombsAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar avoid flame patches and dive bombs") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool AvoidFlamePatch();
|
||||||
|
bool HandleDiveBomb(Unit* alar);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarReturnToRoomCenterAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarReturnToRoomCenterAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar return to room center") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarManagePhaseTrackerAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarManagePhaseTrackerAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "al'ar manage phase tracker") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
|
||||||
|
class VoidReaverTanksPositionBossAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverTanksPositionBossAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "void reaver tanks position boss") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverUseAggroDumpAbilityAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverUseAggroDumpAbilityAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "void reaver use aggro dump ability") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverSpreadRangedAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverSpreadRangedAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "void reaver spread ranged") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int GetHealerIndex(Group* group, int& healerCount);
|
||||||
|
int GetRangedDpsIndex(Group* group, int& rangedDpsCount);
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverAvoidArcaneOrbAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverAvoidArcaneOrbAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "void reaver avoid arcane orb") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverEraseTrackersAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverEraseTrackersAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "void reaver erase trackers") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
|
||||||
|
class HighAstromancerSolarianRangedLeaveSpaceForMeleeAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianRangedLeaveSpaceForMeleeAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "high astromancer solarian ranged leave space for melee") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianMoveAwayFromGroupAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianMoveAwayFromGroupAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "high astromancer solarian move away from group") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianStackForAoeAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianStackForAoeAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "high astromancer solarian stack for aoe") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianTargetSolariumPriestsAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianTargetSolariumPriestsAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "high astromancer solarian target solarium priests") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::pair<Unit*, Unit*> GetSolariumPriests(PlayerbotAI* botAI);
|
||||||
|
std::vector<Player*> GetMeleeBots(Group* group);
|
||||||
|
Unit* AssignSolariumPriestsToBots(const std::pair<Unit*, Unit*>& priestsPair, const std::vector<Player*>& meleeMembers);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianCastFearWardOnMainTankAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianCastFearWardOnMainTankAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "high astromancer solarian cast fear ward on main tank") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
|
||||||
|
class KaelthasSunstriderKiteThaladredAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderKiteThaladredAction(
|
||||||
|
PlayerbotAI* botAI) : MovementAction(botAI, "kael'thas sunstrider kite thaladred") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderMisdirectAdvisorsToTanksAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderMisdirectAdvisorsToTanksAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider misdirect advisors to tanks") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderMainTankPositionSanguinarAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderMainTankPositionSanguinarAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider main tank position sanguinar") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderCastFearWardOnSanguinarTankAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderCastFearWardOnSanguinarTankAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider cast fear ward on sanguinar tank") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderWarlockTankPositionCapernianAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderWarlockTankPositionCapernianAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider warlock tank position capernian") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderSpreadAndMoveAwayFromCapernianAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderSpreadAndMoveAwayFromCapernianAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider spread and move away from capernian") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool RangedBotsDisperse(boss_kaelthas* kaelAI, Unit* capernian);
|
||||||
|
bool MeleeStayBackFromCapernian(Unit* capernian);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderFirstAssistTankPositionTelonicusAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderFirstAssistTankPositionTelonicusAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider first assist tank position telonicus") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderHandleAdvisorRolesInPhase3Action : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderHandleAdvisorRolesInPhase3Action(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider handle advisor roles in phase 3") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderAssignAdvisorDpsPriorityAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderAssignAdvisorDpsPriorityAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider assign advisor dps priority") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderManageAdvisorDpsTimerAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderManageAdvisorDpsTimerAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider manage advisor dps timer") : Action(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderAssignLegendaryWeaponDpsPriorityAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderAssignLegendaryWeaponDpsPriorityAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider assign legendary weapon dps priority") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderMoveDevastationAwayAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderMoveDevastationAwayAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider move devastation away") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderLootLegendaryWeaponsAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderLootLegendaryWeaponsAction(
|
||||||
|
PlayerbotAI* botAI) : MovementAction(botAI, "kael'thas sunstrider loot legendary weapons") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool ShouldBotLootWeapon(uint32 weaponEntry);
|
||||||
|
bool LootWeapon(uint32 weaponEntry, uint32 itemId);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderUseLegendaryWeaponsAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderUseLegendaryWeaponsAction(
|
||||||
|
PlayerbotAI* botAI) : Action(botAI, "kael'thas sunstrider use legendary weapons") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool UsePhaseshiftBulwark();
|
||||||
|
bool UseStaffOfDisintegration();
|
||||||
|
bool UseNetherstrandLongbow();
|
||||||
|
bool UseEquippedItemWithPacket(Item* item);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderReequipGearAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderReequipGearAction(
|
||||||
|
PlayerbotAI* botAI) : Action(botAI, "kael'thas sunstrider reequip gear") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderMainTankPositionBossAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderMainTankPositionBossAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider main tank position boss") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderAvoidFlameStrikeAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderAvoidFlameStrikeAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider avoid flame strike") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderHandlePhoenixesAndEggsAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderHandlePhoenixesAndEggsAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider handle phoenixes and eggs") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool AssistTanksPickUpPhoenixes();
|
||||||
|
bool NonTanksDestroyEggsAndAvoidPhoenixes();
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderBreakMindControlAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderBreakMindControlAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider break mind control") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderBreakThroughShockBarrierAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderBreakThroughShockBarrierAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider break through shock barrier") : AttackAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderSpreadOutInMidairAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderSpreadOutInMidairAction(
|
||||||
|
PlayerbotAI* botAI, std::string const name = "kael'thas sunstrider spread out in midair") : MovementAction(botAI, name) {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,422 @@
|
|||||||
|
#include "RaidTempestKeepMultipliers.h"
|
||||||
|
#include "RaidTempestKeepActions.h"
|
||||||
|
#include "RaidTempestKeepHelpers.h"
|
||||||
|
#include "RaidTempestKeepKaelthasBossAI.h"
|
||||||
|
#include "ChooseTargetActions.h"
|
||||||
|
#include "DKActions.h"
|
||||||
|
#include "DruidActions.h"
|
||||||
|
#include "DruidBearActions.h"
|
||||||
|
#include "EquipAction.h"
|
||||||
|
#include "FollowActions.h"
|
||||||
|
#include "HunterActions.h"
|
||||||
|
#include "MageActions.h"
|
||||||
|
#include "PaladinActions.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "RogueActions.h"
|
||||||
|
#include "ShamanActions.h"
|
||||||
|
#include "WarlockActions.h"
|
||||||
|
#include "WarriorActions.h"
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
|
||||||
|
float AlarMoveBetweenPlatformsMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (isAlarInPhase2[alar->GetMap()->GetInstanceId()])
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<ReachTargetAction*>(action) ||
|
||||||
|
dynamic_cast<TankFaceAction*>(action) ||
|
||||||
|
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
||||||
|
dynamic_cast<CastDisengageAction*>(action) ||
|
||||||
|
dynamic_cast<CastBlinkBackAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
if (botAI->IsDps(bot) &&
|
||||||
|
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AlarDisableDisperseMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "al'ar"))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
|
||||||
|
!dynamic_cast<TankFaceAction*>(action) &&
|
||||||
|
!dynamic_cast<SetBehindTargetAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<FollowAction*>(action) ||
|
||||||
|
dynamic_cast<FleeAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AlarDisableTankAssistMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (bot->GetVictim() == nullptr)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (!botAI->IsTank(bot))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "al'ar"))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<TankAssistAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AlarStayAwayFromRebirthMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Creature* alarCreature = alar->ToCreature();
|
||||||
|
if (!alarCreature || alarCreature->GetReactState() != REACT_PASSIVE)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<MovementAction*>(action) &&
|
||||||
|
!dynamic_cast<AlarMoveAwayFromRebirthAction*>(action) &&
|
||||||
|
!dynamic_cast<AlarAvoidFlamePatchesAndDiveBombsAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AlarPhase2NoTankingIfArmorMeltedMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (!bot->HasAura(SPELL_MELT_ARMOR))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar || bot->GetTarget() != alar->GetGUID())
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<CastTauntAction*>(action) ||
|
||||||
|
dynamic_cast<CastGrowlAction*>(action) ||
|
||||||
|
dynamic_cast<CastHandOfReckoningAction*>(action) ||
|
||||||
|
dynamic_cast<CastDarkCommandAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
|
||||||
|
float VoidReaverMaintainPositionsMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "void reaver"))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
|
||||||
|
!dynamic_cast<SetBehindTargetAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
|
||||||
|
float HighAstromancerSolarianMaintainPositionMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* astromancer = AI_VALUE2(Unit*, "find target", "high astromancer solarian");
|
||||||
|
if (!astromancer || astromancer->HasAura(SPELL_SOLARIAN_TRANSFORM))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (botAI->IsRanged(bot) &&
|
||||||
|
(dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||||
|
dynamic_cast<FleeAction*>(action) ||
|
||||||
|
dynamic_cast<CastBlinkBackAction*>(action) ||
|
||||||
|
dynamic_cast<CastDisengageAction*>(action)))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
if (!bot->HasAura(SPELL_WRATH_OF_THE_ASTROMANCER))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
||||||
|
(dynamic_cast<MovementAction*>(action) &&
|
||||||
|
!dynamic_cast<HighAstromancerSolarianMoveAwayFromGroupAction*>(action)))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float HighAstromancerSolarianDisableTankAssistMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (bot->GetVictim() == nullptr)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (!botAI->IsTank(bot))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "solarium priest"))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<TankAssistAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
|
||||||
|
float KaelthasSunstriderWaitForDpsMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI || kaelAI->GetPhase() != PHASE_SINGLE_ADVISOR)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<KaelthasSunstriderMisdirectAdvisorsToTanksAction*>(action))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
const time_t now = std::time(nullptr);
|
||||||
|
constexpr uint8 dpsWaitSeconds = 10;
|
||||||
|
|
||||||
|
auto it = advisorDpsWaitTimer.find(kaelthas->GetMap()->GetInstanceId());
|
||||||
|
if (it == advisorDpsWaitTimer.end() || (now - it->second) < dpsWaitSeconds)
|
||||||
|
{
|
||||||
|
Unit* sanguinar = AI_VALUE2(Unit*, "find target", "lord sanguinar");
|
||||||
|
Unit* capernian = AI_VALUE2(Unit*, "find target", "grand astromancer capernian");
|
||||||
|
Unit* telonicus = AI_VALUE2(Unit*, "find target", "master engineer telonicus");
|
||||||
|
|
||||||
|
auto isAdvisorActive = [](Unit* advisor)
|
||||||
|
{
|
||||||
|
return advisor && !advisor->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) &&
|
||||||
|
!advisor->HasAura(SPELL_PERMANENT_FEIGN_DEATH);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((isAdvisorActive(sanguinar) && botAI->IsMainTank(bot)) ||
|
||||||
|
(isAdvisorActive(telonicus) && botAI->IsAssistTankOfIndex(bot, 0, true)) ||
|
||||||
|
(isAdvisorActive(capernian) && (botAI->IsMainTank(bot) || GetCapernianTank(bot) == bot)))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
bool shouldHoldDps =
|
||||||
|
(isAdvisorActive(sanguinar) && !botAI->IsMainTank(bot)) ||
|
||||||
|
(isAdvisorActive(telonicus) && !botAI->IsAssistTankOfIndex(bot, 0, true)) ||
|
||||||
|
(isAdvisorActive(capernian) && !botAI->IsMainTank(bot) && GetCapernianTank(bot) != bot);
|
||||||
|
|
||||||
|
if (shouldHoldDps &&
|
||||||
|
(dynamic_cast<AttackAction*>(action) ||
|
||||||
|
(dynamic_cast<CastSpellAction*>(action) &&
|
||||||
|
!dynamic_cast<CastHealingSpellAction*>(action))))
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderKiteThaladredMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (botAI->IsTank(bot) && kaelAI->GetPhase() == PHASE_ALL_ADVISORS)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Unit* thaladred = AI_VALUE2(Unit*, "find target", "thaladred the darkener");
|
||||||
|
if (!thaladred || thaladred->GetVictim() != bot ||
|
||||||
|
thaladred->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<MovementAction*>(action) &&
|
||||||
|
!dynamic_cast<KaelthasSunstriderKiteThaladredAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderControlMisdirectionMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_HUNTER)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI || kaelAI->GetPhase() == PHASE_FINAL)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<CastMisdirectionOnMainTankAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderKeepDistanceFromCapernianMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI || kaelAI->GetPhase() != PHASE_SINGLE_ADVISOR)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Unit* capernian = AI_VALUE2(Unit*, "find target", "grand astromancer capernian");
|
||||||
|
if (!capernian || capernian->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) ||
|
||||||
|
capernian->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<MovementAction*>(action) &&
|
||||||
|
!dynamic_cast<AttackAction*>(action) &&
|
||||||
|
!dynamic_cast<KaelthasSunstriderSpreadAndMoveAwayFromCapernianAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderManageWeaponTankingMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (!botAI->IsTank(bot))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (kaelAI->GetPhase() != PHASE_WEAPONS &&
|
||||||
|
dynamic_cast<TankFaceAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
if (!botAI->IsMainTank(bot))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
// Try to keep main tank from grabbing aggro on any weapon other than the axe
|
||||||
|
if (kaelAI->GetPhase() == PHASE_WEAPONS &&
|
||||||
|
(dynamic_cast<TankAssistAction*>(action) ||
|
||||||
|
dynamic_cast<CastTauntAction*>(action) ||
|
||||||
|
dynamic_cast<CastChallengingShoutAction*>(action) ||
|
||||||
|
dynamic_cast<CastThunderClapAction*>(action) ||
|
||||||
|
dynamic_cast<CastShockwaveAction*>(action) ||
|
||||||
|
dynamic_cast<CastCleaveAction*>(action) ||
|
||||||
|
dynamic_cast<CastGrowlAction*>(action) ||
|
||||||
|
dynamic_cast<CastSwipeAction*>(action) ||
|
||||||
|
dynamic_cast<CastHandOfReckoningAction*>(action) ||
|
||||||
|
dynamic_cast<CastAvengersShieldAction*>(action) ||
|
||||||
|
dynamic_cast<CastConsecrationAction*>(action) ||
|
||||||
|
dynamic_cast<CastDarkCommandAction*>(action) ||
|
||||||
|
dynamic_cast<CastDeathAndDecayAction*>(action) ||
|
||||||
|
dynamic_cast<CastPestilenceAction*>(action) ||
|
||||||
|
dynamic_cast<CastBloodBoilAction*>(action)))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderDisableAdvisorTankAssistMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (bot->GetVictim() == nullptr || !botAI->IsTank(bot))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (kaelAI->GetPhase() != PHASE_SINGLE_ADVISOR &&
|
||||||
|
kaelAI->GetPhase() != PHASE_ALL_ADVISORS)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<TankAssistAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderDisableDisperseMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "kael'thas sunstrider"))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
|
||||||
|
!dynamic_cast<TankFaceAction*>(action) &&
|
||||||
|
!dynamic_cast<SetBehindTargetAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bloodlust/Heroism and other major cooldowns should be used at the start of Phase 3
|
||||||
|
float KaelthasSunstriderDelayCooldownsMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI || kaelAI->GetPhase() == PHASE_ALL_ADVISORS ||
|
||||||
|
kaelAI->GetPhase() == PHASE_FINAL)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (bot->getClass() == CLASS_SHAMAN &&
|
||||||
|
(dynamic_cast<CastBloodlustAction*>(action) ||
|
||||||
|
dynamic_cast<CastHeroismAction*>(action)))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
if (botAI->IsDps(bot) &&
|
||||||
|
(dynamic_cast<CastMetamorphosisAction*>(action) ||
|
||||||
|
dynamic_cast<CastAdrenalineRushAction*>(action) ||
|
||||||
|
dynamic_cast<CastBladeFlurryAction*>(action) ||
|
||||||
|
dynamic_cast<CastIcyVeinsAction*>(action) ||
|
||||||
|
dynamic_cast<CastColdSnapAction*>(action) ||
|
||||||
|
dynamic_cast<CastArcanePowerAction*>(action) ||
|
||||||
|
dynamic_cast<CastPresenceOfMindAction*>(action) ||
|
||||||
|
dynamic_cast<CastCombustionAction*>(action) ||
|
||||||
|
dynamic_cast<CastRapidFireAction*>(action) ||
|
||||||
|
dynamic_cast<CastReadinessAction*>(action) ||
|
||||||
|
dynamic_cast<CastAvengingWrathAction*>(action) ||
|
||||||
|
dynamic_cast<CastElementalMasteryAction*>(action) ||
|
||||||
|
dynamic_cast<CastFeralSpiritAction*>(action) ||
|
||||||
|
dynamic_cast<CastFireElementalTotemAction*>(action) ||
|
||||||
|
dynamic_cast<CastFireElementalTotemMeleeAction*>(action) ||
|
||||||
|
dynamic_cast<CastForceOfNatureAction*>(action) ||
|
||||||
|
dynamic_cast<CastArmyOfTheDeadAction*>(action) ||
|
||||||
|
dynamic_cast<CastSummonGargoyleAction*>(action) ||
|
||||||
|
dynamic_cast<CastBerserkingAction*>(action) ||
|
||||||
|
dynamic_cast<CastBloodFuryAction*>(action) ||
|
||||||
|
dynamic_cast<UseTrinketAction*>(action)))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float KaelthasSunstriderStaySpreadDuringGravityLapseMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
if (!bot->HasAura(SPELL_GRAVITY_LAPSE))
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
if (dynamic_cast<MovementAction*>(action) &&
|
||||||
|
!dynamic_cast<KaelthasSunstriderSpreadOutInMidairAction*>(action))
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
150
src/Ai/Raid/TempestKeep/Multiplier/RaidTempestKeepMultipliers.h
Normal file
150
src/Ai/Raid/TempestKeep/Multiplier/RaidTempestKeepMultipliers.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPMULTIPLIERS_H
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPMULTIPLIERS_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
|
||||||
|
class AlarMoveBetweenPlatformsMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarMoveBetweenPlatformsMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "al'ar move between platforms multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarDisableDisperseMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarDisableDisperseMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "al'ar disable disperse multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarDisableTankAssistMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarDisableTankAssistMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "al'ar disable tank assist multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarStayAwayFromRebirthMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarStayAwayFromRebirthMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "al'ar stay away from rebirth multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarPhase2NoTankingIfArmorMeltedMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarPhase2NoTankingIfArmorMeltedMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "al'ar phase 2 no tanking if armor melted multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
|
||||||
|
class VoidReaverMaintainPositionsMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverMaintainPositionsMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "void reaver maintain positions multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
|
||||||
|
class HighAstromancerSolarianDisableTankAssistMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianDisableTankAssistMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "high astromancer solarian disable tank assist multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianMaintainPositionMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianMaintainPositionMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "high astromancer solarian maintain position multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
|
||||||
|
class KaelthasSunstriderWaitForDpsMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderWaitForDpsMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider wait for dps multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderKiteThaladredMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderKiteThaladredMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider kite thaladred multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderControlMisdirectionMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderControlMisdirectionMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider control misdirection multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderKeepDistanceFromCapernianMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderKeepDistanceFromCapernianMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider keep distance from capernian multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderManageWeaponTankingMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderManageWeaponTankingMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider manage weapon tanking multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderDisableAdvisorTankAssistMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderDisableAdvisorTankAssistMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider disable advisor tank assist multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderDisableDisperseMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderDisableDisperseMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider disable disperse multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderDelayCooldownsMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderDelayCooldownsMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider delay cooldowns multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderStaySpreadDuringGravityLapseMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderStaySpreadDuringGravityLapseMultiplier(
|
||||||
|
PlayerbotAI* botAI) : Multiplier(botAI, "kael'thas sunstrider stay spread during gravity lapse multiplier") {}
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
289
src/Ai/Raid/TempestKeep/RaidTempestKeepActionContext.h
Normal file
289
src/Ai/Raid/TempestKeep/RaidTempestKeepActionContext.h
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPACTIONCONTEXT_H
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPACTIONCONTEXT_H
|
||||||
|
|
||||||
|
#include "RaidTempestKeepActions.h"
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
|
||||||
|
class RaidTempestKeepActionContext : public NamedObjectContext<Action>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RaidTempestKeepActionContext()
|
||||||
|
{
|
||||||
|
// Trash
|
||||||
|
creators["crimson hand centurion cast polymorph"] =
|
||||||
|
&RaidTempestKeepActionContext::crimson_hand_centurion_cast_polymorph;
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
creators["al'ar misdirect boss to main tank"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_misdirect_boss_to_main_tank;
|
||||||
|
|
||||||
|
creators["al'ar boss tanks move between platforms"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_boss_tanks_move_between_platforms;
|
||||||
|
|
||||||
|
creators["al'ar melee dps move between platforms"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_melee_dps_move_between_platforms;
|
||||||
|
|
||||||
|
creators["al'ar ranged and ember tank move under platforms"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_ranged_and_ember_tank_move_under_platforms;
|
||||||
|
|
||||||
|
creators["al'ar assist tanks pick up embers"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_assist_tanks_pick_up_embers;
|
||||||
|
|
||||||
|
creators["al'ar ranged dps prioritize embers"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_ranged_dps_prioritize_embers;
|
||||||
|
|
||||||
|
creators["al'ar jump from platform"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_jump_from_platform;
|
||||||
|
|
||||||
|
creators["al'ar move away from rebirth"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_move_away_from_rebirth;
|
||||||
|
|
||||||
|
creators["al'ar swap tanks on boss"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_swap_tanks_on_boss;
|
||||||
|
|
||||||
|
creators["al'ar avoid flame patches and dive bombs"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_avoid_flame_patches_and_dive_bombs;
|
||||||
|
|
||||||
|
creators["al'ar return to room center"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_return_to_room_center;
|
||||||
|
|
||||||
|
creators["al'ar manage phase tracker"] =
|
||||||
|
&RaidTempestKeepActionContext::alar_manage_phase_tracker;
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
creators["void reaver tanks position boss"] =
|
||||||
|
&RaidTempestKeepActionContext::void_reaver_tanks_position_boss;
|
||||||
|
|
||||||
|
creators["void reaver use aggro dump ability"] =
|
||||||
|
&RaidTempestKeepActionContext::void_reaver_use_aggro_dump_ability;
|
||||||
|
|
||||||
|
creators["void reaver spread ranged"] =
|
||||||
|
&RaidTempestKeepActionContext::void_reaver_spread_ranged;
|
||||||
|
|
||||||
|
creators["void reaver avoid arcane orb"] =
|
||||||
|
&RaidTempestKeepActionContext::void_reaver_avoid_arcane_orb;
|
||||||
|
|
||||||
|
creators["void reaver erase trackers"] =
|
||||||
|
&RaidTempestKeepActionContext::void_reaver_erase_trackers;
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
creators["high astromancer solarian ranged leave space for melee"] =
|
||||||
|
&RaidTempestKeepActionContext::high_astromancer_solarian_ranged_leave_space_for_melee;
|
||||||
|
|
||||||
|
creators["high astromancer solarian move away from group"] =
|
||||||
|
&RaidTempestKeepActionContext::high_astromancer_solarian_move_away_from_group;
|
||||||
|
|
||||||
|
creators["high astromancer solarian stack for aoe"] =
|
||||||
|
&RaidTempestKeepActionContext::high_astromancer_solarian_stack_for_aoe;
|
||||||
|
|
||||||
|
creators["high astromancer solarian target solarium priests"] =
|
||||||
|
&RaidTempestKeepActionContext::high_astromancer_solarian_target_solarium_priests;
|
||||||
|
|
||||||
|
creators["high astromancer solarian cast fear ward on main tank"] =
|
||||||
|
&RaidTempestKeepActionContext::high_astromancer_solarian_cast_fear_ward_on_main_tank;
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
creators["kael'thas sunstrider kite thaladred"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_kite_thaladred;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider misdirect advisors to tanks"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_misdirect_advisors_to_tanks;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider main tank position sanguinar"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_main_tank_position_sanguinar;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider cast fear ward on sanguinar tank"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_cast_fear_ward_on_sanguinar_tank;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider warlock tank position capernian"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_warlock_tank_position_capernian;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider spread and move away from capernian"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_spread_and_move_away_from_capernian;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider first assist tank position telonicus"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_first_assist_tank_position_telonicus;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider handle advisor roles in phase 3"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_handle_advisor_roles_in_phase_3;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider assign advisor dps priority"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_assign_advisor_dps_priority;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider manage advisor dps timer"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_manage_advisor_dps_timer;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider assign legendary weapon dps priority"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_assign_legendary_weapon_dps_priority;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider main tank move devastation away"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_main_tank_move_devastation_away;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider loot legendary weapons"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_loot_legendary_weapons;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider use legendary weapons"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_use_legendary_weapons;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider reequip gear"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_reequip_gear;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider main tank position boss"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_main_tank_position_boss;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider avoid flame strike"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_avoid_flame_strike;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider handle phoenixes and eggs"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_handle_phoenixes_and_eggs;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider break mind control"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_break_mind_control;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider break through shock barrier"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_break_through_shock_barrier;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider spread out in midair"] =
|
||||||
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_spread_out_in_midair;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Trash
|
||||||
|
static Action* crimson_hand_centurion_cast_polymorph(
|
||||||
|
PlayerbotAI* botAI) { return new CrimsonHandCenturionCastPolymorphAction(botAI); }
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
static Action* alar_misdirect_boss_to_main_tank(
|
||||||
|
PlayerbotAI* botAI) { return new AlarMisdirectBossToMainTankAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_boss_tanks_move_between_platforms(
|
||||||
|
PlayerbotAI* botAI) { return new AlarBossTanksMoveBetweenPlatformsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_melee_dps_move_between_platforms(
|
||||||
|
PlayerbotAI* botAI) { return new AlarMeleeDpsMoveBetweenPlatformsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_ranged_and_ember_tank_move_under_platforms(
|
||||||
|
PlayerbotAI* botAI) { return new AlarRangedAndEmberTankMoveUnderPlatformsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_assist_tanks_pick_up_embers(
|
||||||
|
PlayerbotAI* botAI) { return new AlarAssistTanksPickUpEmbersAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_ranged_dps_prioritize_embers(
|
||||||
|
PlayerbotAI* botAI) { return new AlarRangedDpsPrioritizeEmbersAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_jump_from_platform(
|
||||||
|
PlayerbotAI* botAI) { return new AlarJumpFromPlatformAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_move_away_from_rebirth(
|
||||||
|
PlayerbotAI* botAI) { return new AlarMoveAwayFromRebirthAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_swap_tanks_on_boss(
|
||||||
|
PlayerbotAI* botAI) { return new AlarSwapTanksOnBossAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_avoid_flame_patches_and_dive_bombs(
|
||||||
|
PlayerbotAI* botAI) { return new AlarAvoidFlamePatchesAndDiveBombsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_return_to_room_center(
|
||||||
|
PlayerbotAI* botAI) { return new AlarReturnToRoomCenterAction(botAI); }
|
||||||
|
|
||||||
|
static Action* alar_manage_phase_tracker(
|
||||||
|
PlayerbotAI* botAI) { return new AlarManagePhaseTrackerAction(botAI); }
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
static Action* void_reaver_tanks_position_boss(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverTanksPositionBossAction(botAI); }
|
||||||
|
|
||||||
|
static Action* void_reaver_use_aggro_dump_ability(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverUseAggroDumpAbilityAction(botAI); }
|
||||||
|
|
||||||
|
static Action* void_reaver_spread_ranged(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverSpreadRangedAction(botAI); }
|
||||||
|
|
||||||
|
static Action* void_reaver_avoid_arcane_orb(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverAvoidArcaneOrbAction(botAI); }
|
||||||
|
|
||||||
|
static Action* void_reaver_erase_trackers(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverEraseTrackersAction(botAI); }
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
static Action* high_astromancer_solarian_ranged_leave_space_for_melee(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianRangedLeaveSpaceForMeleeAction(botAI); }
|
||||||
|
|
||||||
|
static Action* high_astromancer_solarian_move_away_from_group(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianMoveAwayFromGroupAction(botAI); }
|
||||||
|
|
||||||
|
static Action* high_astromancer_solarian_stack_for_aoe(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianStackForAoeAction(botAI); }
|
||||||
|
|
||||||
|
static Action* high_astromancer_solarian_target_solarium_priests(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianTargetSolariumPriestsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* high_astromancer_solarian_cast_fear_ward_on_main_tank(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianCastFearWardOnMainTankAction(botAI); }
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
static Action* kaelthas_sunstrider_kite_thaladred(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderKiteThaladredAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_misdirect_advisors_to_tanks(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderMisdirectAdvisorsToTanksAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_main_tank_position_sanguinar(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderMainTankPositionSanguinarAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_cast_fear_ward_on_sanguinar_tank(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderCastFearWardOnSanguinarTankAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_warlock_tank_position_capernian(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderWarlockTankPositionCapernianAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_spread_and_move_away_from_capernian(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderSpreadAndMoveAwayFromCapernianAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_first_assist_tank_position_telonicus(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderFirstAssistTankPositionTelonicusAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_handle_advisor_roles_in_phase_3(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderHandleAdvisorRolesInPhase3Action(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_assign_advisor_dps_priority(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderAssignAdvisorDpsPriorityAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_manage_advisor_dps_timer(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderManageAdvisorDpsTimerAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_assign_legendary_weapon_dps_priority(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderAssignLegendaryWeaponDpsPriorityAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_main_tank_move_devastation_away(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderMoveDevastationAwayAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_loot_legendary_weapons(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderLootLegendaryWeaponsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_use_legendary_weapons(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderUseLegendaryWeaponsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_reequip_gear(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderReequipGearAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_main_tank_position_boss(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderMainTankPositionBossAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_avoid_flame_strike(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderAvoidFlameStrikeAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_handle_phoenixes_and_eggs(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderHandlePhoenixesAndEggsAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_break_mind_control(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderBreakMindControlAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_break_through_shock_barrier(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderBreakThroughShockBarrierAction(botAI); }
|
||||||
|
|
||||||
|
static Action* kaelthas_sunstrider_spread_out_in_midair(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderSpreadOutInMidairAction(botAI); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
265
src/Ai/Raid/TempestKeep/RaidTempestKeepTriggerContext.h
Normal file
265
src/Ai/Raid/TempestKeep/RaidTempestKeepTriggerContext.h
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPTRIGGERCONTEXT_H
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPTRIGGERCONTEXT_H
|
||||||
|
|
||||||
|
#include "RaidTempestKeepTriggers.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
|
class RaidTempestKeepTriggerContext : public NamedObjectContext<Trigger>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RaidTempestKeepTriggerContext()
|
||||||
|
{
|
||||||
|
// Trash
|
||||||
|
creators["crimson hand centurion casts arcane volley"] =
|
||||||
|
&RaidTempestKeepTriggerContext::crimson_hand_centurion_casts_arcane_volley;
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
creators["al'ar pulling boss"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_pulling_boss;
|
||||||
|
|
||||||
|
creators["al'ar boss is flying between platforms"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_boss_is_flying_between_platforms;
|
||||||
|
|
||||||
|
creators["al'ar embers of al'ar explode upon death"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_embers_of_alar_explode_upon_death;
|
||||||
|
|
||||||
|
creators["al'ar killing embers of al'ar damages boss"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_killing_embers_of_alar_damages_boss;
|
||||||
|
|
||||||
|
creators["al'ar incoming flame quills"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_incoming_flame_quills;
|
||||||
|
|
||||||
|
creators["al'ar rising from the ashes"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_rising_from_the_ashes;
|
||||||
|
|
||||||
|
creators["al'ar everything is on fire in phase 2"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_everything_is_on_fire_in_phase_2;
|
||||||
|
|
||||||
|
creators["al'ar phase 2 encounter is at room center"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_phase_2_encounter_is_at_room_center;
|
||||||
|
|
||||||
|
creators["al'ar strategy changes between phases"] =
|
||||||
|
&RaidTempestKeepTriggerContext::alar_strategy_changes_between_phases;
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
creators["void reaver boss casts pounding"] =
|
||||||
|
&RaidTempestKeepTriggerContext::void_reaver_boss_casts_pounding;
|
||||||
|
|
||||||
|
creators["void reaver knock away reduces tank aggro"] =
|
||||||
|
&RaidTempestKeepTriggerContext::void_reaver_knock_away_reduces_tank_aggro;
|
||||||
|
|
||||||
|
creators["void reaver boss launches arcane orbs"] =
|
||||||
|
&RaidTempestKeepTriggerContext::void_reaver_boss_launches_arcane_orbs;
|
||||||
|
|
||||||
|
creators["void reaver arcane orb is incoming"] =
|
||||||
|
&RaidTempestKeepTriggerContext::void_reaver_arcane_orb_is_incoming;
|
||||||
|
|
||||||
|
creators["void reaver bot is not in combat"] =
|
||||||
|
&RaidTempestKeepTriggerContext::void_reaver_bot_is_not_in_combat;
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
creators["high astromancer solarian boss casts wrath of the astromancer"] =
|
||||||
|
&RaidTempestKeepTriggerContext::high_astromancer_solarian_boss_casts_wrath_of_the_astromancer;
|
||||||
|
|
||||||
|
creators["high astromancer solarian bot has wrath of the astromancer"] =
|
||||||
|
&RaidTempestKeepTriggerContext::high_astromancer_solarian_bot_has_wrath_of_the_astromancer;
|
||||||
|
|
||||||
|
creators["high astromancer solarian boss has vanished"] =
|
||||||
|
&RaidTempestKeepTriggerContext::high_astromancer_solarian_boss_has_vanished;
|
||||||
|
|
||||||
|
creators["high astromancer solarian solarium priests spawned"] =
|
||||||
|
&RaidTempestKeepTriggerContext::high_astromancer_solarian_solarium_priests_spawned;
|
||||||
|
|
||||||
|
creators["high astromancer solarian boss casts psychic scream"] =
|
||||||
|
&RaidTempestKeepTriggerContext::high_astromancer_solarian_boss_casts_psychic_scream;
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
creators["kael'thas sunstrider thaladred is fixated on bot"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_thaladred_is_fixated_on_bot;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider pulling tankable advisors"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_pulling_tankable_advisors;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider sanguinar engaged by main tank"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_sanguinar_engaged_by_main_tank;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider sanguinar casts bellowing roar"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_sanguinar_casts_bellowing_roar;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider capernian should be tanked by a warlock"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_capernian_should_be_tanked_by_a_warlock;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider capernian casts arcane burst and conflagration"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_capernian_casts_arcane_burst_and_conflagration;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider telonicus engaged by first assist tank"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_telonicus_engaged_by_first_assist_tank;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider bots have specific roles in phase 3"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_bots_have_specific_roles_in_phase_3;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider determining advisor kill order"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_determining_advisor_kill_order;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider waiting for tanks to get aggro on advisors"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_waiting_for_tanks_to_get_aggro_on_advisors;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider legendary weapons are alive"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_legendary_weapons_are_alive;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider legendary axe casts whirlwind"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_legendary_axe_casts_whirlwind;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider legendary weapons are dead and lootable"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_legendary_weapons_are_dead_and_lootable;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider legendary weapons are equipped"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_legendary_weapons_are_equipped;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider legendary weapons were lost"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_legendary_weapons_were_lost;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider boss has entered the fight"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_boss_has_entered_the_fight;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider raid member is mind controlled"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_raid_member_is_mind_controlled;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider phoenixes and eggs are spawning"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_phoenixes_and_eggs_are_spawning;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider boss is casting pyroblast"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_boss_is_casting_pyroblast;
|
||||||
|
|
||||||
|
creators["kael'thas sunstrider boss is manipulating gravity"] =
|
||||||
|
&RaidTempestKeepTriggerContext::kaelthas_sunstrider_boss_is_manipulating_gravity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Trash
|
||||||
|
static Trigger* crimson_hand_centurion_casts_arcane_volley(
|
||||||
|
PlayerbotAI* botAI) { return new CrimsonHandCenturionCastsArcaneVolleyTrigger(botAI); }
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
static Trigger* alar_pulling_boss(
|
||||||
|
PlayerbotAI* botAI) { return new AlarPullingBossTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_boss_is_flying_between_platforms(
|
||||||
|
PlayerbotAI* botAI) { return new AlarBossIsFlyingBetweenPlatformsTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_embers_of_alar_explode_upon_death(
|
||||||
|
PlayerbotAI* botAI) { return new AlarEmbersOfAlarExplodeUponDeathTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_killing_embers_of_alar_damages_boss(
|
||||||
|
PlayerbotAI* botAI) { return new AlarKillingEmbersOfAlarDamagesBossTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_incoming_flame_quills(
|
||||||
|
PlayerbotAI* botAI) { return new AlarIncomingFlameQuillsTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_rising_from_the_ashes(
|
||||||
|
PlayerbotAI* botAI) { return new AlarRisingFromTheAshesTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_everything_is_on_fire_in_phase_2(
|
||||||
|
PlayerbotAI* botAI) { return new AlarEverythingIsOnFireInPhase2Trigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_phase_2_encounter_is_at_room_center(
|
||||||
|
PlayerbotAI* botAI) { return new AlarPhase2EncounterIsAtRoomCenterTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* alar_strategy_changes_between_phases(
|
||||||
|
PlayerbotAI* botAI) { return new AlarStrategyChangesBetweenPhasesTrigger(botAI); }
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
static Trigger* void_reaver_boss_casts_pounding(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverBossCastsPoundingTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* void_reaver_knock_away_reduces_tank_aggro(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverKnockAwayReducesTankAggroTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* void_reaver_boss_launches_arcane_orbs(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverBossLaunchesArcaneOrbsTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* void_reaver_arcane_orb_is_incoming(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverArcaneOrbIsIncomingTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* void_reaver_bot_is_not_in_combat(
|
||||||
|
PlayerbotAI* botAI) { return new VoidReaverBotIsNotInCombatTrigger(botAI); }
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
static Trigger* high_astromancer_solarian_boss_casts_wrath_of_the_astromancer(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianBossCastsWrathOfTheAstromancerTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* high_astromancer_solarian_bot_has_wrath_of_the_astromancer(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianBotHasWrathOfTheAstromancerTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* high_astromancer_solarian_boss_has_vanished(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianBossHasVanishedTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* high_astromancer_solarian_solarium_priests_spawned(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianSolariumPriestsSpawnedTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* high_astromancer_solarian_boss_casts_psychic_scream(
|
||||||
|
PlayerbotAI* botAI) { return new HighAstromancerSolarianBossCastsPsychicScreamTrigger(botAI); }
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
static Trigger* kaelthas_sunstrider_thaladred_is_fixated_on_bot(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderThaladredIsFixatedOnBotTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_pulling_tankable_advisors(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderPullingTankableAdvisorsTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_sanguinar_engaged_by_main_tank(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderSanguinarEngagedByMainTankTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_sanguinar_casts_bellowing_roar(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderSanguinarCastsBellowingRoarTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_capernian_should_be_tanked_by_a_warlock(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderCapernianShouldBeTankedByAWarlockTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_capernian_casts_arcane_burst_and_conflagration(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderCapernianCastsArcaneBurstAndConflagrationTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_telonicus_engaged_by_first_assist_tank(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderTelonicusEngagedByFirstAssistTankTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_bots_have_specific_roles_in_phase_3(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderBotsHaveSpecificRolesInPhase3Trigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_determining_advisor_kill_order(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderDeterminingAdvisorKillOrderTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_waiting_for_tanks_to_get_aggro_on_advisors(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderWaitingForTanksToGetAggroOnAdvisorsTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_legendary_weapons_are_alive(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderLegendaryWeaponsAreAliveTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_legendary_axe_casts_whirlwind(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderLegendaryAxeCastsWhirlwindTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_legendary_weapons_are_dead_and_lootable(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderLegendaryWeaponsAreDeadAndLootableTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_legendary_weapons_are_equipped(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderLegendaryWeaponsAreEquippedTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_legendary_weapons_were_lost(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderLegendaryWeaponsWereLostTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_boss_has_entered_the_fight(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderBossHasEnteredTheFightTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_raid_member_is_mind_controlled(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderRaidMemberIsMindControlledTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_phoenixes_and_eggs_are_spawning(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderPhoenixesAndEggsAreSpawningTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_boss_is_casting_pyroblast(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderBossIsCastingPyroblastTrigger(botAI); }
|
||||||
|
|
||||||
|
static Trigger* kaelthas_sunstrider_boss_is_manipulating_gravity(
|
||||||
|
PlayerbotAI* botAI) { return new KaelthasSunstriderBossIsManipulatingGravityTrigger(botAI); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
162
src/Ai/Raid/TempestKeep/Strategy/RaidTempestKeepStrategy.cpp
Normal file
162
src/Ai/Raid/TempestKeep/Strategy/RaidTempestKeepStrategy.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#include "RaidTempestKeepStrategy.h"
|
||||||
|
#include "RaidTempestKeepMultipliers.h"
|
||||||
|
|
||||||
|
void RaidTempestKeepStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
|
{
|
||||||
|
// Trash
|
||||||
|
triggers.push_back(new TriggerNode("crimson hand centurion casts arcane volley", {
|
||||||
|
NextAction("crimson hand centurion cast polymorph", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
triggers.push_back(new TriggerNode("al'ar pulling boss", {
|
||||||
|
NextAction("al'ar misdirect boss to main tank", ACTION_EMERGENCY + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar boss is flying between platforms", {
|
||||||
|
NextAction("al'ar boss tanks move between platforms", ACTION_RAID + 1),
|
||||||
|
NextAction("al'ar melee dps move between platforms", ACTION_RAID + 1),
|
||||||
|
NextAction("al'ar ranged and ember tank move under platforms", ACTION_RAID + 4) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar embers of al'ar explode upon death", {
|
||||||
|
NextAction("al'ar assist tanks pick up embers", ACTION_RAID + 3) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar killing embers of al'ar damages boss", {
|
||||||
|
NextAction("al'ar ranged dps prioritize embers", ACTION_RAID + 2) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar incoming flame quills", {
|
||||||
|
NextAction("al'ar jump from platform", ACTION_EMERGENCY + 7) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar rising from the ashes", {
|
||||||
|
NextAction("al'ar move away from rebirth", ACTION_EMERGENCY + 7) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar everything is on fire in phase 2", {
|
||||||
|
NextAction("al'ar swap tanks on boss", ACTION_EMERGENCY + 2),
|
||||||
|
NextAction("al'ar avoid flame patches and dive bombs", ACTION_EMERGENCY + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar phase 2 encounter is at room center", {
|
||||||
|
NextAction("al'ar return to room center", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("al'ar strategy changes between phases", {
|
||||||
|
NextAction("al'ar manage phase tracker", ACTION_EMERGENCY + 10) }));
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
triggers.push_back(new TriggerNode("void reaver boss casts pounding", {
|
||||||
|
NextAction("void reaver tanks position boss", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("void reaver knock away reduces tank aggro", {
|
||||||
|
NextAction("void reaver use aggro dump ability", ACTION_EMERGENCY + 6) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("void reaver boss launches arcane orbs", {
|
||||||
|
NextAction("void reaver spread ranged", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("void reaver arcane orb is incoming", {
|
||||||
|
NextAction("void reaver avoid arcane orb", ACTION_EMERGENCY + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("void reaver bot is not in combat", {
|
||||||
|
NextAction("void reaver erase trackers", ACTION_EMERGENCY + 11) }));
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
triggers.push_back(new TriggerNode("high astromancer solarian boss casts wrath of the astromancer", {
|
||||||
|
NextAction("high astromancer solarian ranged leave space for melee", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("high astromancer solarian bot has wrath of the astromancer", {
|
||||||
|
NextAction("high astromancer solarian move away from group", ACTION_EMERGENCY + 6) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("high astromancer solarian boss has vanished", {
|
||||||
|
NextAction("high astromancer solarian stack for aoe", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("high astromancer solarian solarium priests spawned", {
|
||||||
|
NextAction("high astromancer solarian target solarium priests", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("high astromancer solarian boss casts psychic scream", {
|
||||||
|
NextAction("high astromancer solarian cast fear ward on main tank", ACTION_RAID + 2) }));
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider thaladred is fixated on bot", {
|
||||||
|
NextAction("kael'thas sunstrider kite thaladred", ACTION_EMERGENCY + 6) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider pulling tankable advisors", {
|
||||||
|
NextAction("kael'thas sunstrider misdirect advisors to tanks", ACTION_EMERGENCY + 2) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider sanguinar engaged by main tank", {
|
||||||
|
NextAction("kael'thas sunstrider main tank position sanguinar", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider sanguinar casts bellowing roar", {
|
||||||
|
NextAction("kael'thas sunstrider cast fear ward on sanguinar tank", ACTION_RAID + 2) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider capernian should be tanked by a warlock", {
|
||||||
|
NextAction("kael'thas sunstrider warlock tank position capernian", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider capernian casts arcane burst and conflagration", {
|
||||||
|
NextAction("kael'thas sunstrider spread and move away from capernian", ACTION_RAID + 3) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider telonicus engaged by first assist tank", {
|
||||||
|
NextAction("kael'thas sunstrider first assist tank position telonicus", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider bots have specific roles in phase 3", {
|
||||||
|
NextAction("kael'thas sunstrider handle advisor roles in phase 3", ACTION_RAID + 2) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider determining advisor kill order", {
|
||||||
|
NextAction("kael'thas sunstrider assign advisor dps priority", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider waiting for tanks to get aggro on advisors", {
|
||||||
|
NextAction("kael'thas sunstrider manage advisor dps timer", ACTION_EMERGENCY + 10) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary weapons are alive", {
|
||||||
|
NextAction("kael'thas sunstrider assign legendary weapon dps priority", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary axe casts whirlwind", {
|
||||||
|
NextAction("kael'thas sunstrider main tank move devastation away", ACTION_EMERGENCY + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary weapons are dead and lootable", {
|
||||||
|
NextAction("kael'thas sunstrider loot legendary weapons", ACTION_RAID) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary weapons are equipped", {
|
||||||
|
NextAction("kael'thas sunstrider use legendary weapons", ACTION_EMERGENCY + 6) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary weapons were lost", {
|
||||||
|
NextAction("kael'thas sunstrider reequip gear", ACTION_EMERGENCY + 11) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider boss has entered the fight", {
|
||||||
|
NextAction("kael'thas sunstrider main tank position boss", ACTION_RAID + 1),
|
||||||
|
NextAction("kael'thas sunstrider avoid flame strike", ACTION_EMERGENCY + 8) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider phoenixes and eggs are spawning", {
|
||||||
|
NextAction("kael'thas sunstrider handle phoenixes and eggs", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider raid member is mind controlled", {
|
||||||
|
NextAction("kael'thas sunstrider break mind control", ACTION_EMERGENCY + 1) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider boss is casting pyroblast", {
|
||||||
|
NextAction("kael'thas sunstrider break through shock barrier", ACTION_EMERGENCY + 7) }));
|
||||||
|
|
||||||
|
triggers.push_back(new TriggerNode("kael'thas sunstrider boss is manipulating gravity", {
|
||||||
|
NextAction("kael'thas sunstrider spread out in midair", ACTION_EMERGENCY + 1) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaidTempestKeepStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||||
|
{
|
||||||
|
// Alar <Phoenix God>
|
||||||
|
multipliers.push_back(new AlarMoveBetweenPlatformsMultiplier(botAI));
|
||||||
|
multipliers.push_back(new AlarDisableDisperseMultiplier(botAI));
|
||||||
|
multipliers.push_back(new AlarDisableTankAssistMultiplier(botAI));
|
||||||
|
multipliers.push_back(new AlarStayAwayFromRebirthMultiplier(botAI));
|
||||||
|
multipliers.push_back(new AlarPhase2NoTankingIfArmorMeltedMultiplier(botAI));
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
multipliers.push_back(new VoidReaverMaintainPositionsMultiplier(botAI));
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
multipliers.push_back(new HighAstromancerSolarianDisableTankAssistMultiplier(botAI));
|
||||||
|
multipliers.push_back(new HighAstromancerSolarianMaintainPositionMultiplier(botAI));
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
multipliers.push_back(new KaelthasSunstriderWaitForDpsMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderKiteThaladredMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderControlMisdirectionMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderKeepDistanceFromCapernianMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderManageWeaponTankingMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderDisableAdvisorTankAssistMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderDisableDisperseMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderDelayCooldownsMultiplier(botAI));
|
||||||
|
multipliers.push_back(new KaelthasSunstriderStaySpreadDuringGravityLapseMultiplier(botAI));
|
||||||
|
}
|
||||||
18
src/Ai/Raid/TempestKeep/Strategy/RaidTempestKeepStrategy.h
Normal file
18
src/Ai/Raid/TempestKeep/Strategy/RaidTempestKeepStrategy.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPSTRATEGY_H_
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPSTRATEGY_H_
|
||||||
|
|
||||||
|
#include "Strategy.h"
|
||||||
|
#include "Multiplier.h"
|
||||||
|
|
||||||
|
class RaidTempestKeepStrategy : public Strategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RaidTempestKeepStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||||
|
|
||||||
|
std::string const getName() override { return "tempestkeep"; }
|
||||||
|
|
||||||
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
|
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
527
src/Ai/Raid/TempestKeep/Trigger/RaidTempestKeepTriggers.cpp
Normal file
527
src/Ai/Raid/TempestKeep/Trigger/RaidTempestKeepTriggers.cpp
Normal file
@ -0,0 +1,527 @@
|
|||||||
|
#include "RaidTempestKeepTriggers.h"
|
||||||
|
#include "RaidTempestKeepHelpers.h"
|
||||||
|
#include "RaidTempestKeepActions.h"
|
||||||
|
#include "RaidTempestKeepKaelthasBossAI.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
|
|
||||||
|
using namespace TempestKeepHelpers;
|
||||||
|
|
||||||
|
// Trash
|
||||||
|
|
||||||
|
bool CrimsonHandCenturionCastsArcaneVolleyTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return bot->getClass() == CLASS_MAGE &&
|
||||||
|
AI_VALUE2(Unit*, "find target", "crimson hand centurion");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
|
||||||
|
bool AlarPullingBossTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_HUNTER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
return alar && alar->GetHealthPct() > 98.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarBossIsFlyingBetweenPlatformsTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar || !alar->IsVisible())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isAlarInPhase2[alar->GetMap()->GetInstanceId()])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int8 locationIndex = GetAlarCurrentLocationIndex(alar);
|
||||||
|
if (locationIndex == LOCATION_NONE)
|
||||||
|
{
|
||||||
|
Position dest;
|
||||||
|
locationIndex = GetAlarDestinationLocationIndex(alar, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return locationIndex != POINT_QUILL_OR_DIVE_IDX &&
|
||||||
|
locationIndex != POINT_MIDDLE_IDX;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarEmbersOfAlarExplodeUponDeathTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return botAI->IsTank(bot) && AI_VALUE2(Unit*, "find target", "ember of al'ar");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarKillingEmbersOfAlarDamagesBossTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return botAI->IsRangedDps(bot) &&
|
||||||
|
AI_VALUE2(Unit*, "find target", "ember of al'ar");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarIncomingFlameQuillsTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar || isAlarInPhase2[alar->GetMap()->GetInstanceId()])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Position dest;
|
||||||
|
return GetAlarCurrentLocationIndex(alar) == POINT_QUILL_OR_DIVE_IDX ||
|
||||||
|
GetAlarDestinationLocationIndex(alar, dest) == POINT_QUILL_OR_DIVE_IDX;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarRisingFromTheAshesTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isAlarInPhase2[alar->GetMap()->GetInstanceId()])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Creature* alarCreature = alar->ToCreature();
|
||||||
|
return alarCreature && alarCreature->GetReactState() == REACT_PASSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarEverythingIsOnFireInPhase2Trigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
return alar && isAlarInPhase2[alar->GetMap()->GetInstanceId()];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarPhase2EncounterIsAtRoomCenterTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->GetVictim())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* alar = AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
if (!alar || !isAlarInPhase2[alar->GetMap()->GetInstanceId()])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Creature* alarCreature = alar->ToCreature();
|
||||||
|
if (alarCreature && alarCreature->GetReactState() == REACT_PASSIVE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Position dest;
|
||||||
|
return GetAlarCurrentLocationIndex(alar) != POINT_QUILL_OR_DIVE_IDX &&
|
||||||
|
GetAlarDestinationLocationIndex(alar, dest) != POINT_QUILL_OR_DIVE_IDX;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AlarStrategyChangesBetweenPhasesTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return botAI->IsDps(bot) && IsMechanicTrackerBot(botAI, bot, TEMPEST_KEEP_MAP_ID) &&
|
||||||
|
AI_VALUE2(Unit*, "find target", "al'ar");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
|
||||||
|
bool VoidReaverBossCastsPoundingTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsTank(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* voidReaver = AI_VALUE2(Unit*, "find target", "void reaver");
|
||||||
|
return voidReaver && voidReaver->GetVictim() == bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VoidReaverKnockAwayReducesTankAggroTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (botAI->IsTank(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (bot->getClass() == CLASS_DEATH_KNIGHT ||
|
||||||
|
bot->getClass() == CLASS_DRUID ||
|
||||||
|
bot->getClass() == CLASS_SHAMAN ||
|
||||||
|
bot->getClass() == CLASS_WARRIOR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* voidReaver = AI_VALUE2(Unit*, "find target", "void reaver");
|
||||||
|
return voidReaver && voidReaver->GetVictim() == bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VoidReaverBossLaunchesArcaneOrbsTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsRanged(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* voidReaver = AI_VALUE2(Unit*, "find target", "void reaver");
|
||||||
|
return voidReaver && voidReaver->GetVictim() != bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VoidReaverArcaneOrbIsIncomingTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (botAI->IsTank(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* voidReaver = AI_VALUE2(Unit*, "find target", "void reaver");
|
||||||
|
if (!voidReaver || voidReaver->GetVictim() == bot)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto it = voidReaverArcaneOrbs.find(bot->GetMap()->GetInstanceId());
|
||||||
|
if (it == voidReaverArcaneOrbs.end() || it->second.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32 currentTime = getMSTime();
|
||||||
|
constexpr uint32 orbDuration = 7000;
|
||||||
|
constexpr float safeDistance = 22.0f;
|
||||||
|
|
||||||
|
for (auto const& orb : it->second)
|
||||||
|
{
|
||||||
|
if (getMSTimeDiff(orb.castTime, currentTime) <= orbDuration &&
|
||||||
|
bot->GetExactDist2d(orb.destination.GetPositionX(),
|
||||||
|
orb.destination.GetPositionY()) < safeDistance)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VoidReaverBotIsNotInCombatTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return !bot->IsInCombat();
|
||||||
|
}
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
|
||||||
|
bool HighAstromancerSolarianBossCastsWrathOfTheAstromancerTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->HasAura(SPELL_WRATH_OF_THE_ASTROMANCER))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!botAI->IsRanged(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* astromancer = AI_VALUE2(Unit*, "find target", "high astromancer solarian");
|
||||||
|
return astromancer && !astromancer->HasAura(SPELL_SOLARIAN_TRANSFORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HighAstromancerSolarianBotHasWrathOfTheAstromancerTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return bot->HasAura(SPELL_WRATH_OF_THE_ASTROMANCER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HighAstromancerSolarianBossHasVanishedTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->HasAura(SPELL_WRATH_OF_THE_ASTROMANCER))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* astromancer = AI_VALUE2(Unit*, "find target", "high astromancer solarian");
|
||||||
|
if (!astromancer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Creature* astromancerCreature = astromancer->ToCreature();
|
||||||
|
return astromancerCreature &&
|
||||||
|
astromancerCreature->GetReactState() == REACT_PASSIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HighAstromancerSolarianSolariumPriestsSpawnedTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return botAI->IsMelee(bot) && AI_VALUE2(Unit*, "find target", "solarium priest");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HighAstromancerSolarianBossCastsPsychicScreamTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_PRIEST)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* astromancer = AI_VALUE2(Unit*, "find target", "high astromancer solarian");
|
||||||
|
return astromancer && astromancer->HasAura(SPELL_SOLARIAN_TRANSFORM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
|
||||||
|
bool KaelthasSunstriderThaladredIsFixatedOnBotTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* thaladred = AI_VALUE2(Unit*, "find target", "thaladred the darkener");
|
||||||
|
if (!thaladred || thaladred->GetVictim() != bot)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !(botAI->IsTank(bot) && kaelAI->GetPhase() == PHASE_ALL_ADVISORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderPullingTankableAdvisorsTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_HUNTER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
return kaelAI && (kaelAI->GetPhase() == PHASE_SINGLE_ADVISOR ||
|
||||||
|
kaelAI->GetPhase() == PHASE_ALL_ADVISORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderSanguinarEngagedByMainTankTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsMainTank(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* sanguinar = AI_VALUE2(Unit*, "find target", "lord sanguinar");
|
||||||
|
return sanguinar && !sanguinar->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) &&
|
||||||
|
!sanguinar->HasAura(SPELL_PERMANENT_FEIGN_DEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderSanguinarCastsBellowingRoarTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_PRIEST)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (kaelAI->GetPhase() != PHASE_SINGLE_ADVISOR &&
|
||||||
|
kaelAI->GetPhase() != PHASE_TRANSITION &&
|
||||||
|
kaelAI->GetPhase() != PHASE_ALL_ADVISORS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Player* mainTank = GetGroupMainTank(botAI, bot);
|
||||||
|
if (!mainTank || mainTank->HasAura(SPELL_FEAR_WARD))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return botAI->CanCastSpell("fear ward", mainTank);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderCapernianShouldBeTankedByAWarlockTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_WARLOCK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* capernian = AI_VALUE2(Unit*, "find target", "grand astromancer capernian");
|
||||||
|
if (!capernian || capernian->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) ||
|
||||||
|
capernian->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return GetCapernianTank(bot) == bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderCapernianCastsArcaneBurstAndConflagrationTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* capernian = AI_VALUE2(Unit*, "find target", "grand astromancer capernian");
|
||||||
|
if (!capernian || capernian->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) ||
|
||||||
|
capernian->HasAura(SPELL_PERMANENT_FEIGN_DEATH))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return GetCapernianTank(bot) != bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderTelonicusEngagedByFirstAssistTankTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsAssistTankOfIndex(bot, 0, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* telonicus = AI_VALUE2(Unit*, "find target", "master engineer telonicus");
|
||||||
|
return telonicus && !telonicus->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE) &&
|
||||||
|
!telonicus->HasAura(SPELL_PERMANENT_FEIGN_DEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderBotsHaveSpecificRolesInPhase3Trigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "master engineer telonicus") &&
|
||||||
|
!AI_VALUE2(Unit*, "find target", "lord sanguinar"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI || kaelAI->GetPhase() != PHASE_ALL_ADVISORS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return botAI->IsAssistHealOfIndex(bot, 0, true) ||
|
||||||
|
botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0, true) ||
|
||||||
|
(bot->getClass() == CLASS_WARLOCK && GetCapernianTank(bot) == bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderDeterminingAdvisorKillOrderTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (botAI->IsHeal(bot) ||
|
||||||
|
botAI->IsMainTank(bot) ||
|
||||||
|
botAI->IsAssistTankOfIndex(bot, 0, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
return kaelAI && (kaelAI->GetPhase() == PHASE_SINGLE_ADVISOR ||
|
||||||
|
kaelAI->GetPhase() == PHASE_ALL_ADVISORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderWaitingForTanksToGetAggroOnAdvisorsTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsDps(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI || kaelAI->GetPhase() != PHASE_SINGLE_ADVISOR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return IsMechanicTrackerBot(botAI, bot, TEMPEST_KEEP_MAP_ID, GetCapernianTank(bot));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderLegendaryWeaponsAreAliveTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (botAI->IsMainTank(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
return kaelAI && kaelAI->GetPhase() == PHASE_WEAPONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderLegendaryAxeCastsWhirlwindTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return botAI->IsMainTank(bot) &&
|
||||||
|
AI_VALUE2(Unit*, "find target", "devastation");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderLegendaryWeaponsAreDeadAndLootableTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
if (!kaelAI ||
|
||||||
|
(kaelAI->GetPhase() != PHASE_WEAPONS && kaelAI->GetPhase() != PHASE_ALL_ADVISORS))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* axe = AI_VALUE2(Unit*, "find target", "devastation");
|
||||||
|
if (axe && axe->GetVictim() == bot)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return IsAnyLegendaryWeaponDead(bot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderLegendaryWeaponsAreEquippedTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!AI_VALUE2(Unit*, "find target", "kael'thas sunstrider"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bot->HasItemCount(ITEM_STAFF_OF_DISINTEGRATION, 1, false) ||
|
||||||
|
bot->HasItemCount(ITEM_NETHERSTRAND_LONGBOW, 1, false) ||
|
||||||
|
bot->HasItemCount(ITEM_PHASESHIFT_BULWARK, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderLegendaryWeaponsWereLostTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (bot->GetMapId() != TEMPEST_KEEP_MAP_ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Map* map = bot->GetMap();
|
||||||
|
if (!map)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
constexpr uint32 KAELTHAS_DB_GUID = 158218;
|
||||||
|
auto const& creatureStore = map->GetCreatureBySpawnIdStore();
|
||||||
|
auto it = creatureStore.find(KAELTHAS_DB_GUID);
|
||||||
|
if (it == creatureStore.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Creature* kaelthas = it->second;
|
||||||
|
if (!kaelthas || bot->GetExactDist2d(kaelthas) > 150.0f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const std::array<uint8, 3> weaponSlots =
|
||||||
|
{
|
||||||
|
EQUIPMENT_SLOT_MAINHAND,
|
||||||
|
EQUIPMENT_SLOT_OFFHAND,
|
||||||
|
EQUIPMENT_SLOT_RANGED
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint8 slot : weaponSlots)
|
||||||
|
{
|
||||||
|
if (!bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot) &&
|
||||||
|
HasEquippableItemForSlot(bot, slot))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderBossHasEnteredTheFightTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boss_kaelthas* kaelAI = dynamic_cast<boss_kaelthas*>(kaelthas->GetAI());
|
||||||
|
return kaelAI && kaelAI->GetPhase() == PHASE_FINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderPhoenixesAndEggsAreSpawningTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (botAI->IsTank(bot) && kaelthas->GetVictim() == bot)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return AI_VALUE2(Unit*, "find target", "phoenix") ||
|
||||||
|
AI_VALUE2(Unit*, "find target", "phoenix egg");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderRaidMemberIsMindControlledTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
if (!kaelthas)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (botAI->IsTank(bot) && kaelthas->GetVictim() == bot)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!bot->HasItemCount(ITEM_INFINITY_BLADE, 1, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Group* group = bot->GetGroup())
|
||||||
|
{
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (member->HasAura(SPELL_KAELTHAS_MIND_CONTROL))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderBossIsCastingPyroblastTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsDps(bot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* kaelthas = AI_VALUE2(Unit*, "find target", "kael'thas sunstrider");
|
||||||
|
return kaelthas && kaelthas->HasAura(SPELL_SHOCK_BARRIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KaelthasSunstriderBossIsManipulatingGravityTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return bot->HasAura(SPELL_GRAVITY_LAPSE);
|
||||||
|
}
|
||||||
338
src/Ai/Raid/TempestKeep/Trigger/RaidTempestKeepTriggers.h
Normal file
338
src/Ai/Raid/TempestKeep/Trigger/RaidTempestKeepTriggers.h
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPTRIGGERS_H
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPTRIGGERS_H
|
||||||
|
|
||||||
|
#include "Trigger.h"
|
||||||
|
|
||||||
|
// General
|
||||||
|
|
||||||
|
// Trash
|
||||||
|
|
||||||
|
class CrimsonHandCenturionCastsArcaneVolleyTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CrimsonHandCenturionCastsArcaneVolleyTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "crimson hand centurion casts arcane volley") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
|
||||||
|
class AlarPullingBossTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarPullingBossTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar pulling boss") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarBossIsFlyingBetweenPlatformsTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarBossIsFlyingBetweenPlatformsTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar boss is flying between platforms") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarEmbersOfAlarExplodeUponDeathTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarEmbersOfAlarExplodeUponDeathTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar embers of al'ar explode upon death") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarKillingEmbersOfAlarDamagesBossTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarKillingEmbersOfAlarDamagesBossTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar killing embers of al'ar damages boss") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarIncomingFlameQuillsTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarIncomingFlameQuillsTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar incoming flame quills") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarRisingFromTheAshesTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarRisingFromTheAshesTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar rising from the ashes") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarEverythingIsOnFireInPhase2Trigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarEverythingIsOnFireInPhase2Trigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar everything is on fire in phase 2") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarPhase2EncounterIsAtRoomCenterTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarPhase2EncounterIsAtRoomCenterTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar phase 2 encounter is at room center") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AlarStrategyChangesBetweenPhasesTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AlarStrategyChangesBetweenPhasesTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "al'ar strategy changes between phases") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
|
||||||
|
class VoidReaverBossCastsPoundingTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverBossCastsPoundingTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "void reaver boss casts pounding") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverKnockAwayReducesTankAggroTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverKnockAwayReducesTankAggroTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "void reaver knock away reduces tank aggro") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverBossLaunchesArcaneOrbsTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverBossLaunchesArcaneOrbsTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "void reaver boss launches arcane orbs") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverArcaneOrbIsIncomingTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverArcaneOrbIsIncomingTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "void reaver arcane orb is incoming") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoidReaverBotIsNotInCombatTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VoidReaverBotIsNotInCombatTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "void reaver bot is not in combat") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
|
||||||
|
class HighAstromancerSolarianBossCastsWrathOfTheAstromancerTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianBossCastsWrathOfTheAstromancerTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "high astromancer solarian boss casts wrath of the astromancer") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianBotHasWrathOfTheAstromancerTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianBotHasWrathOfTheAstromancerTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "high astromancer solarian bot has wrath of the astromancer") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianBossHasVanishedTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianBossHasVanishedTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "high astromancer solarian boss has vanished") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianSolariumPriestsSpawnedTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianSolariumPriestsSpawnedTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "high astromancer solarian solarium priests spawned") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighAstromancerSolarianBossCastsPsychicScreamTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HighAstromancerSolarianBossCastsPsychicScreamTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "high astromancer boss casts psychic scream") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
|
||||||
|
class KaelthasSunstriderThaladredIsFixatedOnBotTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderThaladredIsFixatedOnBotTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider thaladred is fixated on bot") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderPullingTankableAdvisorsTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderPullingTankableAdvisorsTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider pulling tankable advisors") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderSanguinarEngagedByMainTankTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderSanguinarEngagedByMainTankTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider sanguinar engaged by main tank") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderSanguinarCastsBellowingRoarTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderSanguinarCastsBellowingRoarTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider sanguinar casts bellowing roar") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderCapernianShouldBeTankedByAWarlockTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderCapernianShouldBeTankedByAWarlockTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider capernian should be tanked by a warlock") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderCapernianCastsArcaneBurstAndConflagrationTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderCapernianCastsArcaneBurstAndConflagrationTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider capernian casts arcane burst and conflagration") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderTelonicusEngagedByFirstAssistTankTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderTelonicusEngagedByFirstAssistTankTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider telonicus engaged by first assist tank") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderBotsHaveSpecificRolesInPhase3Trigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderBotsHaveSpecificRolesInPhase3Trigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider bots have specific roles in phase 3") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderDeterminingAdvisorKillOrderTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderDeterminingAdvisorKillOrderTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider determining advisor kill order") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderWaitingForTanksToGetAggroOnAdvisorsTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderWaitingForTanksToGetAggroOnAdvisorsTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider waiting for tanks to get aggro on advisors") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderLegendaryWeaponsAreAliveTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderLegendaryWeaponsAreAliveTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider legendary weapons are alive") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderLegendaryAxeCastsWhirlwindTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderLegendaryAxeCastsWhirlwindTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider legendary axe casts whirlwind") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderLegendaryWeaponsAreDeadAndLootableTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderLegendaryWeaponsAreDeadAndLootableTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider legendary weapons are dead and lootable") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderLegendaryWeaponsAreEquippedTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderLegendaryWeaponsAreEquippedTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider legendary weapons are equipped") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderLegendaryWeaponsWereLostTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderLegendaryWeaponsWereLostTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider legendary weapons were lost") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderBossHasEnteredTheFightTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderBossHasEnteredTheFightTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider boss has entered the fight") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderPhoenixesAndEggsAreSpawningTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderPhoenixesAndEggsAreSpawningTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider phoenixes and eggs are spawning") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderRaidMemberIsMindControlledTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderRaidMemberIsMindControlledTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider raid member is mind controlled") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderBossIsCastingPyroblastTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderBossIsCastingPyroblastTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider boss is casting pyroblast") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class KaelthasSunstriderBossIsManipulatingGravityTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KaelthasSunstriderBossIsManipulatingGravityTrigger(
|
||||||
|
PlayerbotAI* botAI) : Trigger(botAI, "kael'thas sunstrider boss is manipulating gravity") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
425
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepHelpers.cpp
Normal file
425
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepHelpers.cpp
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
#include "RaidTempestKeepHelpers.h"
|
||||||
|
#include "RaidTempestKeepActions.h"
|
||||||
|
#include "LootObjectStack.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "RaidBossHelpers.h"
|
||||||
|
|
||||||
|
namespace TempestKeepHelpers
|
||||||
|
{
|
||||||
|
// General
|
||||||
|
|
||||||
|
Unit* GetNearestNonTankPlayerInRadius(PlayerbotAI* botAI, Player* bot, float radius)
|
||||||
|
{
|
||||||
|
Unit* nearestPlayer = nullptr;
|
||||||
|
float nearestDistance = radius;
|
||||||
|
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member == bot || botAI->IsTank(member))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float distance = bot->GetExactDist2d(member);
|
||||||
|
if (distance < nearestDistance)
|
||||||
|
{
|
||||||
|
nearestDistance = distance;
|
||||||
|
nearestPlayer = member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearestPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Unit*> GetAllHazardTriggers(Player* bot, uint32 npcEntry, float searchRadius)
|
||||||
|
{
|
||||||
|
std::vector<Unit*> hazardTriggers;
|
||||||
|
|
||||||
|
std::list<Creature*> creatureList;
|
||||||
|
bot->GetCreatureListWithEntryInGrid(creatureList, npcEntry, searchRadius);
|
||||||
|
|
||||||
|
for (Creature* creature : creatureList)
|
||||||
|
{
|
||||||
|
if (creature && creature->IsAlive())
|
||||||
|
hazardTriggers.push_back(creature);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hazardTriggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position FindSafestNearbyPosition(Player* bot, const std::vector<Unit*>& hazards,
|
||||||
|
float hazardRadius, const Position* center)
|
||||||
|
{
|
||||||
|
constexpr float searchStep = M_PI / 8.0f;
|
||||||
|
constexpr float minDistance = 2.0f;
|
||||||
|
constexpr float maxDistance = 30.0f;
|
||||||
|
constexpr float distanceStep = 1.0f;
|
||||||
|
|
||||||
|
Position bestPos;
|
||||||
|
float minMoveDistance = std::numeric_limits<float>::max();
|
||||||
|
bool foundSafe = false;
|
||||||
|
|
||||||
|
for (float distance = minDistance; distance <= maxDistance; distance += distanceStep)
|
||||||
|
{
|
||||||
|
for (float angle = 0.0f; angle < 2 * M_PI; angle += searchStep)
|
||||||
|
{
|
||||||
|
const Position& searchCenter = center ? *center : bot->GetPosition();
|
||||||
|
float x = searchCenter.GetPositionX() + distance * std::cos(angle);
|
||||||
|
float y = searchCenter.GetPositionY() + distance * std::sin(angle);
|
||||||
|
|
||||||
|
bool isSafe = true;
|
||||||
|
for (Unit* hazard : hazards)
|
||||||
|
{
|
||||||
|
if (hazard->GetExactDist2d(x, y) < hazardRadius)
|
||||||
|
{
|
||||||
|
isSafe = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSafe)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Position testPos(x, y, bot->GetPositionZ());
|
||||||
|
|
||||||
|
bool pathSafe = IsPathSafeFromHazards(bot->GetPosition(), testPos, hazards, hazardRadius);
|
||||||
|
if (pathSafe || !foundSafe)
|
||||||
|
{
|
||||||
|
float moveDistance = bot->GetExactDist2d(x, y);
|
||||||
|
|
||||||
|
if (pathSafe && (!foundSafe || moveDistance < minMoveDistance))
|
||||||
|
{
|
||||||
|
bestPos = testPos;
|
||||||
|
minMoveDistance = moveDistance;
|
||||||
|
foundSafe = true;
|
||||||
|
}
|
||||||
|
else if (!foundSafe && moveDistance < minMoveDistance)
|
||||||
|
{
|
||||||
|
bestPos = testPos;
|
||||||
|
minMoveDistance = moveDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundSafe)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPathSafeFromHazards(
|
||||||
|
const Position& start, const Position& end, const std::vector<Unit*>& hazards, float hazardRadius)
|
||||||
|
{
|
||||||
|
constexpr uint8 numChecks = 10;
|
||||||
|
float dx = end.GetPositionX() - start.GetPositionX();
|
||||||
|
float dy = end.GetPositionY() - start.GetPositionY();
|
||||||
|
|
||||||
|
for (uint8 i = 1; i <= numChecks; ++i)
|
||||||
|
{
|
||||||
|
float ratio = static_cast<float>(i) / numChecks;
|
||||||
|
float checkX = start.GetPositionX() + dx * ratio;
|
||||||
|
float checkY = start.GetPositionY() + dy * ratio;
|
||||||
|
|
||||||
|
for (Unit* hazard : hazards)
|
||||||
|
{
|
||||||
|
float distToHazard = hazard->GetExactDist2d(checkX, checkY);
|
||||||
|
if (distToHazard < hazardRadius)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
|
||||||
|
const Position ALAR_PLATFORM_0 = { 335.638f, 59.4879f, 17.9319f }; // West Platform
|
||||||
|
const Position ALAR_PLATFORM_1 = { 388.751f, 31.7312f, 20.2636f }; // Northwest Platform
|
||||||
|
const Position ALAR_PLATFORM_2 = { 388.791f, -33.1059f, 20.2636f }; // Northeast Platform
|
||||||
|
const Position ALAR_PLATFORM_3 = { 332.723f, -61.159f, 17.9791f }; // East Platform
|
||||||
|
const std::array<Position, 4> PLATFORM_POSITIONS =
|
||||||
|
{
|
||||||
|
ALAR_PLATFORM_0,
|
||||||
|
ALAR_PLATFORM_1,
|
||||||
|
ALAR_PLATFORM_2,
|
||||||
|
ALAR_PLATFORM_3
|
||||||
|
};
|
||||||
|
const Position ALAR_GROUND_0 = { 336.439f, 48.181f, -2.389f }; // Ground counterpart to West Platform
|
||||||
|
const Position ALAR_GROUND_1 = { 379.122f, 25.146f, -2.385f }; // Ground counterpart to Northwest Platform
|
||||||
|
const Position ALAR_GROUND_2 = { 378.583f, -27.481f, -2.385f }; // Ground counterpart to Northeast Platform
|
||||||
|
const Position ALAR_GROUND_3 = { 331.631f, -49.716f, -2.389f }; // Ground counterpart to East Platform
|
||||||
|
const std::array<Position, 4> GROUND_POSITIONS =
|
||||||
|
{
|
||||||
|
ALAR_GROUND_0,
|
||||||
|
ALAR_GROUND_1,
|
||||||
|
ALAR_GROUND_2,
|
||||||
|
ALAR_GROUND_3
|
||||||
|
};
|
||||||
|
const Position ALAR_ROOM_CENTER = { 330.611f, -2.540f, -2.389f };
|
||||||
|
const Position ALAR_POINT_QUILL_OR_DIVE = { 332.000f, 0.010f, 43.000f };
|
||||||
|
const Position ALAR_POINT_MIDDLE = { 331.000f, 0.010f, -2.380f };
|
||||||
|
const Position ALAR_SE_RAMP_BASE = { 281.064f, -36.590f, -2.389f };
|
||||||
|
const Position ALAR_SW_RAMP_BASE = { 281.064f, 36.590f, -2.389f };
|
||||||
|
const Position ALAR_ROOM_S_CENTER = { 281.064f, 0.000f, -2.389f };
|
||||||
|
|
||||||
|
std::unordered_map<uint32, bool> lastRebirthState;
|
||||||
|
std::unordered_map<uint32, bool> isAlarInPhase2;
|
||||||
|
|
||||||
|
int8 GetAlarDestinationLocationIndex(Unit* alar, Position& dest)
|
||||||
|
{
|
||||||
|
if (!alar)
|
||||||
|
return LOCATION_NONE;
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
if (!alar->GetMotionMaster()->GetDestination(x, y, z))
|
||||||
|
return LOCATION_NONE;
|
||||||
|
|
||||||
|
dest.Relocate(x, y, z);
|
||||||
|
|
||||||
|
const std::array<Position, 6> locations =
|
||||||
|
{
|
||||||
|
ALAR_PLATFORM_0,
|
||||||
|
ALAR_PLATFORM_1,
|
||||||
|
ALAR_PLATFORM_2,
|
||||||
|
ALAR_PLATFORM_3,
|
||||||
|
ALAR_POINT_QUILL_OR_DIVE,
|
||||||
|
ALAR_POINT_MIDDLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
float minDist = std::numeric_limits<float>::max();
|
||||||
|
int8 locationIndex = LOCATION_NONE;
|
||||||
|
for (int8 i = 0; i < TOTAL_ALAR_LOCATIONS; ++i)
|
||||||
|
{
|
||||||
|
float dist = dest.GetExactDist2d(&locations[i]);
|
||||||
|
if (dist < minDist)
|
||||||
|
{
|
||||||
|
minDist = dist;
|
||||||
|
locationIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minDist > 0.1f)
|
||||||
|
return LOCATION_NONE;
|
||||||
|
|
||||||
|
return locationIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8 GetAlarCurrentLocationIndex(Unit* alar)
|
||||||
|
{
|
||||||
|
if (!alar)
|
||||||
|
return LOCATION_NONE;
|
||||||
|
|
||||||
|
const std::array<Position, 6> locations =
|
||||||
|
{
|
||||||
|
ALAR_PLATFORM_0,
|
||||||
|
ALAR_PLATFORM_1,
|
||||||
|
ALAR_PLATFORM_2,
|
||||||
|
ALAR_PLATFORM_3,
|
||||||
|
ALAR_POINT_QUILL_OR_DIVE,
|
||||||
|
ALAR_POINT_MIDDLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
float minDist = std::numeric_limits<float>::max();
|
||||||
|
int8 locationIndex = LOCATION_NONE;
|
||||||
|
for (int8 i = 0; i < TOTAL_ALAR_LOCATIONS; ++i)
|
||||||
|
{
|
||||||
|
float dist = alar->GetPosition().GetExactDist2d(&locations[i]);
|
||||||
|
if (dist < minDist)
|
||||||
|
{
|
||||||
|
minDist = dist;
|
||||||
|
locationIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minDist > 0.1f)
|
||||||
|
return LOCATION_NONE;
|
||||||
|
|
||||||
|
return locationIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetClosestPlatformAndGround(const Position& botPos, int8& closestPlatform, Position& ground)
|
||||||
|
{
|
||||||
|
float minDist = std::numeric_limits<float>::max();
|
||||||
|
closestPlatform = -1;
|
||||||
|
for (int8 i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
float dist = botPos.GetExactDist2d(&PLATFORM_POSITIONS[i]);
|
||||||
|
if (dist < minDist)
|
||||||
|
{
|
||||||
|
minDist = dist;
|
||||||
|
closestPlatform = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ground = GROUND_POSITIONS[closestPlatform];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Unit*, Unit*> GetFirstTwoEmbersOfAlar(PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
Unit* firstEmber = nullptr;
|
||||||
|
Unit* secondEmber = nullptr;
|
||||||
|
|
||||||
|
for (auto const& guid :
|
||||||
|
botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los")->Get())
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(guid);
|
||||||
|
if (unit && unit->IsAlive() && unit->GetEntry() == NPC_EMBER_OF_ALAR)
|
||||||
|
{
|
||||||
|
if (!firstEmber)
|
||||||
|
{
|
||||||
|
firstEmber = unit;
|
||||||
|
}
|
||||||
|
else if (!secondEmber)
|
||||||
|
{
|
||||||
|
secondEmber = unit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { firstEmber, secondEmber };
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* GetSecondEmberTank(PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
Player* mainTank = GetGroupMainTank(botAI, botAI->GetBot());
|
||||||
|
Player* assistTank = GetGroupAssistTank(botAI, botAI->GetBot(), 0);
|
||||||
|
|
||||||
|
bool mainTankHasMelt = mainTank && mainTank->HasAura(SPELL_MELT_ARMOR);
|
||||||
|
bool assistTankHasMelt = assistTank && assistTank->HasAura(SPELL_MELT_ARMOR);
|
||||||
|
|
||||||
|
if (mainTankHasMelt)
|
||||||
|
return mainTank;
|
||||||
|
|
||||||
|
if (assistTankHasMelt || (!mainTankHasMelt && !assistTankHasMelt))
|
||||||
|
return assistTank;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
|
||||||
|
const Position VOID_REAVER_TANK_POSITION = { 423.845f, 371.733f, 14.897f };
|
||||||
|
|
||||||
|
std::unordered_map<ObjectGuid, bool> hasReachedVoidReaverPosition;
|
||||||
|
std::unordered_map<uint32, std::vector<ArcaneOrbData>> voidReaverArcaneOrbs;
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
|
||||||
|
const Position SANGUINAR_TANK_POSITION = { 775.478f, 39.888f, 46.780f };
|
||||||
|
const Position SANGUINAR_WAITING_POSITION = { 761.850f, 27.459f, 46.779f };
|
||||||
|
const Position TELONICUS_TANK_POSITION = { 773.717f, 44.091f, 46.780f };
|
||||||
|
const Position TELONICUS_WAITING_POSITION = { 754.347f, 31.739f, 46.796f };
|
||||||
|
const Position ADVISOR_HEAL_POSITION = { 752.171f, 19.494f, 46.779f };
|
||||||
|
const Position CAPERNIAN_WAITING_POSITION = { 743.897f, -11.575f, 46.779f };
|
||||||
|
const Position KAELTHAS_TANK_POSITION = { 799.390f, -0.837f, 48.729f };
|
||||||
|
|
||||||
|
std::unordered_map<uint32, time_t> advisorDpsWaitTimer;
|
||||||
|
|
||||||
|
// (1) First priority is an assistant Warlock (real player or bot)
|
||||||
|
// (2) If no assistant Warlock, then look for any Warlock bot
|
||||||
|
Player* GetCapernianTank(Player* bot)
|
||||||
|
{
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
Player* fallbackWarlock = nullptr;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member->getClass() != CLASS_WARLOCK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (group->IsAssistant(member->GetGUID()))
|
||||||
|
return member;
|
||||||
|
|
||||||
|
if (!fallbackWarlock && GET_PLAYERBOT_AI(member))
|
||||||
|
fallbackWarlock = member;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackWarlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One Hunter will start on Sanguinar in Phase 3 with Melee to apply Armor Disruption
|
||||||
|
// (1) First priority is an assistant Hunter (real player or bot)
|
||||||
|
// (2) If no assistant Hunter, then look for any Hunter bot
|
||||||
|
bool IsDebuffHunter(Player* bot)
|
||||||
|
{
|
||||||
|
if (bot->getClass() != CLASS_HUNTER || !bot->IsAlive())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Player* fallbackHunter = nullptr;
|
||||||
|
|
||||||
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
|
{
|
||||||
|
Player* member = ref->GetSource();
|
||||||
|
if (!member || !member->IsAlive() || member->getClass() != CLASS_HUNTER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (group->IsAssistant(member->GetGUID()))
|
||||||
|
return member == bot;
|
||||||
|
|
||||||
|
if (!fallbackHunter && GET_PLAYERBOT_AI(member))
|
||||||
|
fallbackHunter = member;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackHunter == bot;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAnyLegendaryWeaponDead(Player* bot)
|
||||||
|
{
|
||||||
|
static const std::array<uint32, 7> weaponEntries =
|
||||||
|
{
|
||||||
|
NPC_STAFF_OF_DISINTEGRATION,
|
||||||
|
NPC_COSMIC_INFUSER,
|
||||||
|
NPC_INFINITY_BLADES,
|
||||||
|
NPC_WARP_SLICER,
|
||||||
|
NPC_PHASESHIFT_BULWARK,
|
||||||
|
NPC_NETHERSTRAND_LONGBOW,
|
||||||
|
NPC_DEVASTATION
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr float searchRadius = 100.0f;
|
||||||
|
|
||||||
|
for (uint32 entry : weaponEntries)
|
||||||
|
{
|
||||||
|
Creature* weapon = bot->FindNearestCreature(entry, searchRadius, false);
|
||||||
|
|
||||||
|
if (weapon && !weapon->IsAlive())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasEquippableItemForSlot(Player* bot, uint8 slot)
|
||||||
|
{
|
||||||
|
for (uint8 i = 0; i < 5; ++i)
|
||||||
|
{
|
||||||
|
uint8 bag = (i == 0) ? INVENTORY_SLOT_BAG_0 : (INVENTORY_SLOT_BAG_START + i - 1);
|
||||||
|
uint8 startSlot = (bag == INVENTORY_SLOT_BAG_0) ? INVENTORY_SLOT_ITEM_START : 0;
|
||||||
|
uint8 endSlot = (bag == INVENTORY_SLOT_BAG_0) ? INVENTORY_SLOT_ITEM_END :
|
||||||
|
(bot->GetBagByPos(bag) ? bot->GetBagByPos(bag)->GetBagSize() : 0);
|
||||||
|
|
||||||
|
for (uint8 bagSlot = startSlot; bagSlot < endSlot; ++bagSlot)
|
||||||
|
{
|
||||||
|
Item* item = bot->GetItemByPos(bag, bagSlot);
|
||||||
|
if (!item || !item->GetTemplate())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint16 dest = 0;
|
||||||
|
if (bot->CanEquipItem(slot, dest, item, false) == EQUIP_ERR_OK)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
158
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepHelpers.h
Normal file
158
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepHelpers.h
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPHELPERS_H_
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPHELPERS_H_
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "AiObject.h"
|
||||||
|
#include "Position.h"
|
||||||
|
#include "Unit.h"
|
||||||
|
|
||||||
|
namespace TempestKeepHelpers
|
||||||
|
{
|
||||||
|
enum TempestKeepSpells
|
||||||
|
{
|
||||||
|
// Trash
|
||||||
|
SPELL_ARCANE_FLURRY = 37268,
|
||||||
|
|
||||||
|
// Al'ar
|
||||||
|
SPELL_REBIRTH_PHASE2 = 34342,
|
||||||
|
SPELL_REBIRTH_DIVE = 35369,
|
||||||
|
SPELL_MELT_ARMOR = 35410,
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
SPELL_ARCANE_ORB = 34172,
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
SPELL_SOLARIAN_TRANSFORM = 39117,
|
||||||
|
SPELL_WRATH_OF_THE_ASTROMANCER = 42783,
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider
|
||||||
|
SPELL_PERMANENT_FEIGN_DEATH = 29266,
|
||||||
|
SPELL_GRAVITY_LAPSE = 39432,
|
||||||
|
SPELL_KAEL_FULL_POWER = 36187,
|
||||||
|
SPELL_MENTAL_PROTECTION_FIELD = 36480, // Staff of Disintegration
|
||||||
|
SPELL_ARCANE_BARRIER = 36481, // Phaseshift Bulwark
|
||||||
|
SPELL_KAELTHAS_MIND_CONTROL = 36797,
|
||||||
|
SPELL_SHOCK_BARRIER = 36815,
|
||||||
|
SPELL_STAFF_FROSTBOLT = 36990,
|
||||||
|
|
||||||
|
// Hunter
|
||||||
|
SPELL_MISDIRECTION = 35079,
|
||||||
|
|
||||||
|
// Priest
|
||||||
|
SPELL_FEAR_WARD = 6346,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TempestKeepNPCs
|
||||||
|
{
|
||||||
|
// Al'ar
|
||||||
|
NPC_EMBER_OF_ALAR = 19551,
|
||||||
|
NPC_FLAME_PATCH = 20602,
|
||||||
|
|
||||||
|
// High Astromancer Solarian
|
||||||
|
NPC_SOLARIUM_PRIEST = 18806,
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider
|
||||||
|
NPC_KAELTHAS_SUNSTRIDER = 19622,
|
||||||
|
NPC_NETHERSTRAND_LONGBOW = 21268,
|
||||||
|
NPC_DEVASTATION = 21269,
|
||||||
|
NPC_COSMIC_INFUSER = 21270,
|
||||||
|
NPC_INFINITY_BLADES = 21271, // Item is singular, but NPC is plural
|
||||||
|
NPC_WARP_SLICER = 21272,
|
||||||
|
NPC_PHASESHIFT_BULWARK = 21273,
|
||||||
|
NPC_STAFF_OF_DISINTEGRATION = 21274,
|
||||||
|
// NPC_NETHER_VAPOR = 21002, // Unimplemented in AC; method needed if fixed
|
||||||
|
NPC_PHOENIX = 21362,
|
||||||
|
NPC_PHOENIX_EGG = 21364,
|
||||||
|
NPC_FLAME_STRIKE_TRIGGER = 21369,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TempestKeepItems
|
||||||
|
{
|
||||||
|
// Kael'thas Sunstrider
|
||||||
|
ITEM_WARP_SLICER = 30311,
|
||||||
|
ITEM_INFINITY_BLADE = 30312,
|
||||||
|
ITEM_STAFF_OF_DISINTEGRATION = 30313,
|
||||||
|
ITEM_PHASESHIFT_BULWARK = 30314,
|
||||||
|
ITEM_DEVASTATION = 30316,
|
||||||
|
ITEM_COSMIC_INFUSER = 30317,
|
||||||
|
ITEM_NETHERSTRAND_LONGBOW = 30318,
|
||||||
|
ITEM_NETHER_SPIKES = 30319,
|
||||||
|
};
|
||||||
|
|
||||||
|
// General
|
||||||
|
constexpr uint32 TEMPEST_KEEP_MAP_ID = 550;
|
||||||
|
Unit* GetNearestNonTankPlayerInRadius(PlayerbotAI* botAI, Player* bot, float radius);
|
||||||
|
std::vector<Unit*> GetAllHazardTriggers(Player* bot, uint32 npcEntry, float searchRadius);
|
||||||
|
Position FindSafestNearbyPosition(Player* bot, const std::vector<Unit*>& hazards,
|
||||||
|
float hazardRadius, const Position* center = nullptr);
|
||||||
|
bool IsPathSafeFromHazards(
|
||||||
|
const Position& start, const Position& end, const std::vector<Unit*>& hazards,
|
||||||
|
float hazardRadius);
|
||||||
|
|
||||||
|
// Al'ar <Phoenix God>
|
||||||
|
enum AlarLocationIndex
|
||||||
|
{
|
||||||
|
PLATFORM_0_IDX,
|
||||||
|
PLATFORM_1_IDX,
|
||||||
|
PLATFORM_2_IDX,
|
||||||
|
PLATFORM_3_IDX,
|
||||||
|
POINT_QUILL_OR_DIVE_IDX,
|
||||||
|
POINT_MIDDLE_IDX,
|
||||||
|
LOCATION_NONE = -1
|
||||||
|
};
|
||||||
|
constexpr float ALAR_BALCONY_Z = 17.0f;
|
||||||
|
extern const Position ALAR_PLATFORM_0;
|
||||||
|
extern const Position ALAR_PLATFORM_1;
|
||||||
|
extern const Position ALAR_PLATFORM_2;
|
||||||
|
extern const Position ALAR_PLATFORM_3;
|
||||||
|
extern const std::array<Position, 4> PLATFORM_POSITIONS;
|
||||||
|
extern const Position ALAR_GROUND_0;
|
||||||
|
extern const Position ALAR_GROUND_1;
|
||||||
|
extern const Position ALAR_GROUND_2;
|
||||||
|
extern const Position ALAR_GROUND_3;
|
||||||
|
extern const std::array<Position, 4> GROUND_POSITIONS;
|
||||||
|
extern const Position ALAR_ROOM_CENTER;
|
||||||
|
extern const Position ALAR_POINT_QUILL_OR_DIVE;
|
||||||
|
extern const Position ALAR_POINT_MIDDLE;
|
||||||
|
extern const Position ALAR_SE_RAMP_BASE;
|
||||||
|
extern const Position ALAR_SW_RAMP_BASE;
|
||||||
|
extern const Position ALAR_ROOM_S_CENTER;
|
||||||
|
constexpr uint8 TOTAL_ALAR_LOCATIONS = 6;
|
||||||
|
extern std::unordered_map<uint32, bool> lastRebirthState;
|
||||||
|
extern std::unordered_map<uint32, bool> isAlarInPhase2;
|
||||||
|
int8 GetAlarDestinationLocationIndex(Unit* alar, Position& dest);
|
||||||
|
int8 GetAlarCurrentLocationIndex(Unit* alar);
|
||||||
|
void GetClosestPlatformAndGround(
|
||||||
|
const Position& botPos, int8& closestPlatform, Position& ground);
|
||||||
|
std::pair<Unit*, Unit*> GetFirstTwoEmbersOfAlar(PlayerbotAI* botAI);
|
||||||
|
Player* GetSecondEmberTank(PlayerbotAI* botAI);
|
||||||
|
|
||||||
|
// Void Reaver
|
||||||
|
extern const Position VOID_REAVER_TANK_POSITION;
|
||||||
|
extern std::unordered_map<ObjectGuid, bool> hasReachedVoidReaverPosition;
|
||||||
|
struct ArcaneOrbData
|
||||||
|
{
|
||||||
|
Position destination;
|
||||||
|
uint32 castTime;
|
||||||
|
};
|
||||||
|
extern std::unordered_map<uint32, std::vector<ArcaneOrbData>> voidReaverArcaneOrbs;
|
||||||
|
|
||||||
|
// Kael'thas Sunstrider <Lord of the Blood Elves>
|
||||||
|
extern const Position SANGUINAR_TANK_POSITION;
|
||||||
|
extern const Position SANGUINAR_WAITING_POSITION;
|
||||||
|
extern const Position TELONICUS_TANK_POSITION;
|
||||||
|
extern const Position TELONICUS_WAITING_POSITION;
|
||||||
|
extern const Position CAPERNIAN_WAITING_POSITION;
|
||||||
|
extern const Position ADVISOR_HEAL_POSITION;
|
||||||
|
extern const Position KAELTHAS_TANK_POSITION;
|
||||||
|
extern std::unordered_map<uint32, time_t> advisorDpsWaitTimer;
|
||||||
|
Player* GetCapernianTank(Player* bot);
|
||||||
|
bool IsDebuffHunter(Player* bot);
|
||||||
|
bool IsAnyLegendaryWeaponDead(Player* bot);
|
||||||
|
bool HasEquippableItemForSlot(Player* bot, uint8 slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
54
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepKaelthasBossAI.h
Normal file
54
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepKaelthasBossAI.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef _PLAYERBOT_RAIDTEMPESTKEEPKAELTHASBOSSAI_H_
|
||||||
|
#define _PLAYERBOT_RAIDTEMPESTKEEPKAELTHASBOSSAI_H_
|
||||||
|
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
|
||||||
|
enum KTYells
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KTPhases
|
||||||
|
{
|
||||||
|
PHASE_NONE = 0,
|
||||||
|
PHASE_SINGLE_ADVISOR = 1,
|
||||||
|
PHASE_WEAPONS = 2,
|
||||||
|
PHASE_TRANSITION = 3,
|
||||||
|
PHASE_ALL_ADVISORS = 4,
|
||||||
|
PHASE_FINAL = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum KTActions
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct boss_kaelthas : public BossAI
|
||||||
|
{
|
||||||
|
boss_kaelthas(Creature* creature);
|
||||||
|
|
||||||
|
void PrepareAdvisors();
|
||||||
|
void SetRoomState(GOState state);
|
||||||
|
void Reset() override;
|
||||||
|
void AttackStart(Unit* who) override;
|
||||||
|
void MoveInLineOfSight(Unit* who) override;
|
||||||
|
void KilledUnit(Unit* victim) override;
|
||||||
|
void JustSummoned(Creature* summon) override;
|
||||||
|
void SpellHit(Unit* caster, SpellInfo const* spell) override;
|
||||||
|
void MovementInform(uint32 type, uint32 point) override;
|
||||||
|
void ExecuteMiddleEvent();
|
||||||
|
void IntroduceNewAdvisor(KTYells talkIntroduction, KTActions kaelAction);
|
||||||
|
void PhaseEnchantedWeaponsExecute();
|
||||||
|
void PhaseAllAdvisorsExecute();
|
||||||
|
void PhaseKaelExecute();
|
||||||
|
void UpdateAI(uint32 diff) override;
|
||||||
|
bool CheckEvadeIfOutOfCombatArea() const override;
|
||||||
|
void JustDied(Unit* killer) override;
|
||||||
|
|
||||||
|
uint32 GetPhase() const { return _phase; } // This is the only addition to the existing class
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 _phase;
|
||||||
|
uint8 _advisorsAlive;
|
||||||
|
bool _transitionSceneReached = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
47
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepScripts.cpp
Normal file
47
src/Ai/Raid/TempestKeep/Util/RaidTempestKeepScripts.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "RaidTempestKeepHelpers.h"
|
||||||
|
#include "ObjectAccessor.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "Spell.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
using namespace TempestKeepHelpers;
|
||||||
|
|
||||||
|
class BossListenerScript : public AllSpellScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BossListenerScript() : AllSpellScript("BossListenerScript") { }
|
||||||
|
|
||||||
|
void OnSpellCast(Spell* spell, Unit* caster, SpellInfo const* spellInfo, bool /*skipCheck*/) override
|
||||||
|
{
|
||||||
|
if (spellInfo->Id != SPELL_ARCANE_ORB)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::list<TargetInfo> const& targets = *spell->GetUniqueTargetInfo();
|
||||||
|
if (targets.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Player* target = ObjectAccessor::GetPlayer(*caster, targets.front().targetGUID);
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& orbs = voidReaverArcaneOrbs[caster->GetMap()->GetInstanceId()];
|
||||||
|
uint32 currentTime = getMSTime();
|
||||||
|
|
||||||
|
ArcaneOrbData orbData;
|
||||||
|
orbData.destination = target->GetPosition();
|
||||||
|
orbData.castTime = currentTime;
|
||||||
|
|
||||||
|
orbs.push_back(orbData);
|
||||||
|
|
||||||
|
orbs.erase(std::remove_if(orbs.begin(), orbs.end(),
|
||||||
|
[currentTime](const ArcaneOrbData& orb) {
|
||||||
|
return getMSTimeDiff(orb.castTime, currentTime) > 5000;
|
||||||
|
}), orbs.end());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_TempestKeepBotScripts()
|
||||||
|
{
|
||||||
|
new BossListenerScript();
|
||||||
|
}
|
||||||
@ -72,9 +72,7 @@ bool FlameLeviathanVehicleAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!target || bot->GetExactDist(target) > bot->GetExactDist(unit))
|
if (!target || bot->GetExactDist(target) > bot->GetExactDist(unit))
|
||||||
{
|
|
||||||
target = unit;
|
target = unit;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Flame Leviathan is chasing me
|
// Flame Leviathan is chasing me
|
||||||
if (flame && flame->GetVictim() == vehicleBase_)
|
if (flame && flame->GetVictim() == vehicleBase_)
|
||||||
@ -419,9 +417,7 @@ bool RazorscaleAvoidDevouringFlameAction::Execute(Event /*event*/)
|
|||||||
RazorscaleBossHelper razorscaleHelper(botAI);
|
RazorscaleBossHelper razorscaleHelper(botAI);
|
||||||
|
|
||||||
if (!razorscaleHelper.UpdateBossAI())
|
if (!razorscaleHelper.UpdateBossAI())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
bool isMainTank = botAI->IsMainTank(bot);
|
bool isMainTank = botAI->IsMainTank(bot);
|
||||||
const float flameRadius = 3.5f;
|
const float flameRadius = 3.5f;
|
||||||
@ -433,9 +429,7 @@ bool RazorscaleAvoidDevouringFlameAction::Execute(Event /*event*/)
|
|||||||
// Get the boss
|
// Get the boss
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "razorscale");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "razorscale");
|
||||||
if (!boss)
|
if (!boss)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
Unit* closestFlame = nullptr;
|
Unit* closestFlame = nullptr;
|
||||||
@ -458,15 +452,12 @@ bool RazorscaleAvoidDevouringFlameAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
// Off tanks are following the main tank during grounded and should prioritise stacking
|
// Off tanks are following the main tank during grounded and should prioritise stacking
|
||||||
if (razorscaleHelper.IsGroundPhase() && (botAI->IsTank(bot) && !botAI->IsMainTank(bot)))
|
if (razorscaleHelper.IsGroundPhase() && (botAI->IsTank(bot) && !botAI->IsMainTank(bot)))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Handle movement from flames
|
// Handle movement from flames
|
||||||
if (closestDistance < safeDistance)
|
if (closestDistance < safeDistance)
|
||||||
{
|
|
||||||
return MoveAway(closestFlame, safeDistance);
|
return MoveAway(closestFlame, safeDistance);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,9 +477,7 @@ bool RazorscaleAvoidDevouringFlameAction::isUseful()
|
|||||||
{
|
{
|
||||||
float distance = bot->GetDistance2d(unit);
|
float distance = bot->GetDistance2d(unit);
|
||||||
if (distance < safeDistance)
|
if (distance < safeDistance)
|
||||||
{
|
|
||||||
return true; // Bot is within the danger distance
|
return true; // Bot is within the danger distance
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,9 +511,7 @@ bool RazorscaleAvoidSentinelAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
// Move away if ranged and too close
|
// Move away if ranged and too close
|
||||||
if (isRanged && bot->GetDistance2d(unit) < radius)
|
if (isRanged && bot->GetDistance2d(unit) < radius)
|
||||||
{
|
|
||||||
movedAway = MoveAway(unit, radius) || movedAway;
|
movedAway = MoveAway(unit, radius) || movedAway;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,9 +534,7 @@ bool RazorscaleAvoidSentinelAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
// If there's no skull set yet, or the skull is on a different target, set the sentinel
|
// If there's no skull set yet, or the skull is on a different target, set the sentinel
|
||||||
if (!currentSkullTarget || (lowestHealthSentinel->GetGUID() != currentSkullTarget))
|
if (!currentSkullTarget || (lowestHealthSentinel->GetGUID() != currentSkullTarget))
|
||||||
{
|
|
||||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), lowestHealthSentinel->GetGUID());
|
group->SetTargetIcon(skullIndex, bot->GetGUID(), lowestHealthSentinel->GetGUID());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break; // Stop after finding the first valid bot tank
|
break; // Stop after finding the first valid bot tank
|
||||||
}
|
}
|
||||||
@ -565,9 +550,7 @@ bool RazorscaleAvoidSentinelAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
// If there's no skull set yet, or the skull is on a different target, set the sentinel
|
// If there's no skull set yet, or the skull is on a different target, set the sentinel
|
||||||
if (!currentSkullTarget || (lowestHealthSentinel->GetGUID() != currentSkullTarget))
|
if (!currentSkullTarget || (lowestHealthSentinel->GetGUID() != currentSkullTarget))
|
||||||
{
|
|
||||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), lowestHealthSentinel->GetGUID());
|
group->SetTargetIcon(skullIndex, bot->GetGUID(), lowestHealthSentinel->GetGUID());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,9 +565,7 @@ bool RazorscaleAvoidSentinelAction::isUseful()
|
|||||||
|
|
||||||
// If this bot is the main tank, it should always try to mark
|
// If this bot is the main tank, it should always try to mark
|
||||||
if (isMainTank)
|
if (isMainTank)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// If the main tank is a human, check if this bot is one of the first three valid bot tanks
|
// If the main tank is a human, check if this bot is one of the first three valid bot tanks
|
||||||
if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player
|
if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player
|
||||||
@ -592,9 +573,7 @@ bool RazorscaleAvoidSentinelAction::isUseful()
|
|||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank
|
if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank
|
||||||
{
|
|
||||||
return true; // This bot should assist with marking
|
return true; // This bot should assist with marking
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,9 +587,7 @@ bool RazorscaleAvoidSentinelAction::isUseful()
|
|||||||
if (unit && unit->GetEntry() == RazorscaleBossHelper::UNIT_DARK_RUNE_SENTINEL)
|
if (unit && unit->GetEntry() == RazorscaleBossHelper::UNIT_DARK_RUNE_SENTINEL)
|
||||||
{
|
{
|
||||||
if (isRanged && bot->GetDistance2d(unit) < radius)
|
if (isRanged && bot->GetDistance2d(unit) < radius)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,9 +610,7 @@ bool RazorscaleAvoidWhirlwindAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
float currentDistance = bot->GetDistance2d(unit);
|
float currentDistance = bot->GetDistance2d(unit);
|
||||||
if (currentDistance < radius)
|
if (currentDistance < radius)
|
||||||
{
|
|
||||||
return MoveAway(unit, radius);
|
return MoveAway(unit, radius);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -690,23 +665,17 @@ bool RazorscaleIgnoreBossAction::isUseful()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!botAI->IsTank(bot))
|
if (!botAI->IsTank(bot))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the boss is already set as the moon marker
|
// Check if the boss is already set as the moon marker
|
||||||
int8 moonIndex = 4; // Moon marker index
|
int8 moonIndex = 4; // Moon marker index
|
||||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex);
|
ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex);
|
||||||
if (currentMoonTarget == boss->GetGUID())
|
if (currentMoonTarget == boss->GetGUID())
|
||||||
{
|
|
||||||
return false; // Moon marker is already correctly set, no further action needed
|
return false; // Moon marker is already correctly set, no further action needed
|
||||||
}
|
|
||||||
|
|
||||||
// Proceed to tank-specific logic
|
// Proceed to tank-specific logic
|
||||||
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
|
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
|
||||||
@ -714,9 +683,7 @@ bool RazorscaleIgnoreBossAction::isUseful()
|
|||||||
|
|
||||||
// If this bot is the main tank, it needs to set the moon marker
|
// If this bot is the main tank, it needs to set the moon marker
|
||||||
if (mainTankUnit == bot)
|
if (mainTankUnit == bot)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// If the main tank is a human, check if this bot is the lowest-indexed bot tank
|
// If the main tank is a human, check if this bot is the lowest-indexed bot tank
|
||||||
if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player
|
if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a human player
|
||||||
@ -724,9 +691,7 @@ bool RazorscaleIgnoreBossAction::isUseful()
|
|||||||
for (int i = 0; i < 3; ++i) // Only iterate through the first 3 indexes
|
for (int i = 0; i < 3; ++i) // Only iterate through the first 3 indexes
|
||||||
{
|
{
|
||||||
if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Valid bot tank
|
if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Valid bot tank
|
||||||
{
|
|
||||||
return true; // This bot should assign the marker
|
return true; // This bot should assign the marker
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1156,9 +1121,7 @@ bool IronAssemblyLightningTendrilsAction::Execute(Event /*event*/)
|
|||||||
float currentDistance = bot->GetDistance2d(boss);
|
float currentDistance = bot->GetDistance2d(boss);
|
||||||
|
|
||||||
if (currentDistance < radius)
|
if (currentDistance < radius)
|
||||||
{
|
|
||||||
return MoveAway(boss, radius - currentDistance);
|
return MoveAway(boss, radius - currentDistance);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1180,9 +1143,7 @@ bool IronAssemblyOverloadAction::Execute(Event /*event*/)
|
|||||||
float currentDistance = bot->GetDistance2d(boss);
|
float currentDistance = bot->GetDistance2d(boss);
|
||||||
|
|
||||||
if (currentDistance < radius)
|
if (currentDistance < radius)
|
||||||
{
|
|
||||||
return MoveAway(boss, radius - currentDistance);
|
return MoveAway(boss, radius - currentDistance);
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1230,7 +1191,6 @@ bool KologarnMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
if (!target)
|
if (!target)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32 creatureId = target->GetEntry();
|
|
||||||
if (target->GetEntry() == NPC_RUBBLE && target->IsAlive())
|
if (target->GetEntry() == NPC_RUBBLE && target->IsAlive())
|
||||||
{
|
{
|
||||||
targetToMark = target;
|
targetToMark = target;
|
||||||
@ -1252,21 +1212,15 @@ bool KologarnMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn");
|
||||||
if (boss && boss->IsAlive())
|
if (boss && boss->IsAlive())
|
||||||
{
|
|
||||||
targetToMark = boss;
|
targetToMark = boss;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!targetToMark)
|
if (!targetToMark)
|
||||||
{
|
|
||||||
return false; // No target to mark
|
return false; // No target to mark
|
||||||
}
|
|
||||||
|
|
||||||
Unit* leftArm = AI_VALUE2(Unit*, "find target", "left arm");
|
Unit* leftArm = AI_VALUE2(Unit*, "find target", "left arm");
|
||||||
if (leftArm && leftArm->IsAlive())
|
if (leftArm && leftArm->IsAlive())
|
||||||
{
|
|
||||||
targetToCcMark = leftArm;
|
targetToCcMark = leftArm;
|
||||||
}
|
|
||||||
|
|
||||||
bool isMainTank = botAI->IsMainTank(bot);
|
bool isMainTank = botAI->IsMainTank(bot);
|
||||||
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
|
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
|
||||||
@ -1284,13 +1238,10 @@ bool KologarnMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||||
if (targetToCcMark)
|
if (targetToCcMark)
|
||||||
{
|
|
||||||
group->SetTargetIcon(moonIndex, bot->GetGUID(), targetToCcMark->GetGUID());
|
group->SetTargetIcon(moonIndex, bot->GetGUID(), targetToCcMark->GetGUID());
|
||||||
}
|
|
||||||
if (additionalTargetToMark)
|
if (additionalTargetToMark)
|
||||||
{
|
|
||||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), additionalTargetToMark->GetGUID());
|
group->SetTargetIcon(crossIndex, bot->GetGUID(), additionalTargetToMark->GetGUID());
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1305,13 +1256,11 @@ bool KologarnMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||||
if (targetToCcMark)
|
if (targetToCcMark)
|
||||||
{
|
|
||||||
group->SetTargetIcon(moonIndex, bot->GetGUID(), targetToCcMark->GetGUID());
|
group->SetTargetIcon(moonIndex, bot->GetGUID(), targetToCcMark->GetGUID());
|
||||||
}
|
|
||||||
if (additionalTargetToMark)
|
if (additionalTargetToMark)
|
||||||
{
|
|
||||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), additionalTargetToMark->GetGUID());
|
group->SetTargetIcon(crossIndex, bot->GetGUID(), additionalTargetToMark->GetGUID());
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1326,13 +1275,11 @@ bool KologarnMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||||
if (targetToCcMark)
|
if (targetToCcMark)
|
||||||
{
|
|
||||||
group->SetTargetIcon(moonIndex, bot->GetGUID(), targetToCcMark->GetGUID());
|
group->SetTargetIcon(moonIndex, bot->GetGUID(), targetToCcMark->GetGUID());
|
||||||
}
|
|
||||||
if (additionalTargetToMark)
|
if (additionalTargetToMark)
|
||||||
{
|
|
||||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), additionalTargetToMark->GetGUID());
|
group->SetTargetIcon(crossIndex, bot->GetGUID(), additionalTargetToMark->GetGUID());
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break; // Stop after finding the first valid bot tank
|
break; // Stop after finding the first valid bot tank
|
||||||
@ -1379,17 +1326,11 @@ bool KologarnEyebeamAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
bool runToLeftSide;
|
bool runToLeftSide;
|
||||||
if (!distanceToLeftPoint)
|
if (!distanceToLeftPoint)
|
||||||
{
|
|
||||||
runToLeftSide = true;
|
runToLeftSide = true;
|
||||||
}
|
|
||||||
else if (!distanceToRightPoint)
|
else if (!distanceToRightPoint)
|
||||||
{
|
|
||||||
runToLeftSide = false;
|
runToLeftSide = false;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
runToLeftSide = distanceToRightPoint > distanceToLeftPoint;
|
runToLeftSide = distanceToRightPoint > distanceToLeftPoint;
|
||||||
}
|
|
||||||
|
|
||||||
bool teleportedToPoint;
|
bool teleportedToPoint;
|
||||||
KologarnEyebeamTrigger kologarnEyebeamTrigger(botAI);
|
KologarnEyebeamTrigger kologarnEyebeamTrigger(botAI);
|
||||||
@ -1418,9 +1359,7 @@ bool KologarnEyebeamAction::isUseful()
|
|||||||
{
|
{
|
||||||
KologarnEyebeamTrigger kologarnEyebeamTrigger(botAI);
|
KologarnEyebeamTrigger kologarnEyebeamTrigger(botAI);
|
||||||
if (!kologarnEyebeamTrigger.IsActive())
|
if (!kologarnEyebeamTrigger.IsActive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return botAI->HasCheat(BotCheatMask::raid);
|
return botAI->HasCheat(BotCheatMask::raid);
|
||||||
}
|
}
|
||||||
@ -1447,9 +1386,7 @@ bool KologarnCrunchArmorAction::isUseful()
|
|||||||
{
|
{
|
||||||
KologarnCrunchArmorTrigger kologarnCrunchArmorTrigger(botAI);
|
KologarnCrunchArmorTrigger kologarnCrunchArmorTrigger(botAI);
|
||||||
if (!kologarnCrunchArmorTrigger.IsActive())
|
if (!kologarnCrunchArmorTrigger.IsActive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return botAI->HasCheat(BotCheatMask::raid);
|
return botAI->HasCheat(BotCheatMask::raid);
|
||||||
}
|
}
|
||||||
@ -1482,15 +1419,11 @@ bool HodirMoveSnowpackedIcicleAction::isUseful()
|
|||||||
// Check boss and it is alive
|
// Check boss and it is alive
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "hodir");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "hodir");
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Check if boss is casting Flash Freeze
|
// Check if boss is casting Flash Freeze
|
||||||
if (!boss->HasUnitState(UNIT_STATE_CASTING) || !boss->FindCurrentSpellBySpellId(SPELL_FLASH_FREEZE))
|
if (!boss->HasUnitState(UNIT_STATE_CASTING) || !boss->FindCurrentSpellBySpellId(SPELL_FLASH_FREEZE))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Find the nearest Snowpacked Icicle Target
|
// Find the nearest Snowpacked Icicle Target
|
||||||
Creature* target = bot->FindNearestCreature(NPC_SNOWPACKED_ICICLE, 100.0f);
|
Creature* target = bot->FindNearestCreature(NPC_SNOWPACKED_ICICLE, 100.0f);
|
||||||
@ -1499,9 +1432,7 @@ bool HodirMoveSnowpackedIcicleAction::isUseful()
|
|||||||
|
|
||||||
// Check that bot is stacked on Snowpacked Icicle
|
// Check that bot is stacked on Snowpacked Icicle
|
||||||
if (bot->GetDistance2d(target->GetPositionX(), target->GetPositionY()) <= 5.0f)
|
if (bot->GetDistance2d(target->GetPositionX(), target->GetPositionY()) <= 5.0f)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1612,42 +1543,26 @@ bool FreyaMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_EONARS_GIFT)
|
if (target->GetEntry() == NPC_EONARS_GIFT)
|
||||||
{
|
|
||||||
eonarsGift = target;
|
eonarsGift = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_ANCIENT_CONSERVATOR)
|
else if (target->GetEntry() == NPC_ANCIENT_CONSERVATOR)
|
||||||
{
|
|
||||||
ancientConservator = target;
|
ancientConservator = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_SNAPLASHER)
|
else if (target->GetEntry() == NPC_SNAPLASHER)
|
||||||
{
|
|
||||||
snaplasher = target;
|
snaplasher = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_ANCIENT_WATER_SPIRIT)
|
else if (target->GetEntry() == NPC_ANCIENT_WATER_SPIRIT)
|
||||||
{
|
|
||||||
ancientWaterSpirit = target;
|
ancientWaterSpirit = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_STORM_LASHER)
|
else if (target->GetEntry() == NPC_STORM_LASHER)
|
||||||
{
|
|
||||||
stormLasher = target;
|
stormLasher = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_DETONATING_LASHER && !firstDetonatingLasher)
|
else if (target->GetEntry() == NPC_DETONATING_LASHER && !firstDetonatingLasher)
|
||||||
{
|
|
||||||
firstDetonatingLasher = target;
|
firstDetonatingLasher = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that eonars gift is need to be mark
|
// Check that eonars gift is need to be mark
|
||||||
if (eonarsGift)
|
if (eonarsGift)
|
||||||
{
|
|
||||||
targetToMark = eonarsGift;
|
targetToMark = eonarsGift;
|
||||||
}
|
|
||||||
|
|
||||||
// Check that ancient conservator is need to be mark
|
// Check that ancient conservator is need to be mark
|
||||||
if (ancientConservator && !targetToMark)
|
if (ancientConservator && !targetToMark)
|
||||||
{
|
|
||||||
targetToMark = ancientConservator;
|
targetToMark = ancientConservator;
|
||||||
}
|
|
||||||
|
|
||||||
// Check that trio of adds is need to be mark
|
// Check that trio of adds is need to be mark
|
||||||
if ((snaplasher || ancientWaterSpirit || stormLasher) && !targetToMark)
|
if ((snaplasher || ancientWaterSpirit || stormLasher) && !targetToMark)
|
||||||
@ -1679,14 +1594,10 @@ bool FreyaMarkDpsTargetAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
// Check that detonating lasher is need to be mark
|
// Check that detonating lasher is need to be mark
|
||||||
if (firstDetonatingLasher && !targetToMark)
|
if (firstDetonatingLasher && !targetToMark)
|
||||||
{
|
|
||||||
targetToMark = firstDetonatingLasher;
|
targetToMark = firstDetonatingLasher;
|
||||||
}
|
|
||||||
|
|
||||||
if (!targetToMark)
|
if (!targetToMark)
|
||||||
{
|
|
||||||
return false; // No target to mark
|
return false; // No target to mark
|
||||||
}
|
|
||||||
|
|
||||||
bool isMainTank = botAI->IsMainTank(bot);
|
bool isMainTank = botAI->IsMainTank(bot);
|
||||||
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
|
Unit* mainTankUnit = AI_VALUE(Unit*, "main tank");
|
||||||
@ -1778,9 +1689,7 @@ bool ThorimUnbalancingStrikeAction::isUseful()
|
|||||||
{
|
{
|
||||||
ThorimUnbalancingStrikeTrigger thorimUnbalancingStrikeTrigger(botAI);
|
ThorimUnbalancingStrikeTrigger thorimUnbalancingStrikeTrigger(botAI);
|
||||||
if (!thorimUnbalancingStrikeTrigger.IsActive())
|
if (!thorimUnbalancingStrikeTrigger.IsActive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return botAI->HasCheat(BotCheatMask::raid);
|
return botAI->HasCheat(BotCheatMask::raid);
|
||||||
}
|
}
|
||||||
@ -2188,23 +2097,15 @@ bool MimironShockBlastAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
{
|
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
{
|
|
||||||
vx001 = target;
|
vx001 = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
{
|
|
||||||
aerialCommandUnit = target;
|
aerialCommandUnit = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leviathanMkII)
|
if (!leviathanMkII)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!vx001 && !aerialCommandUnit)
|
if (!vx001 && !aerialCommandUnit)
|
||||||
{
|
{
|
||||||
@ -2213,9 +2114,8 @@ bool MimironShockBlastAction::Execute(Event /*event*/)
|
|||||||
MoveAway(leviathanMkII, radius - currentDistance);
|
MoveAway(leviathanMkII, radius - currentDistance);
|
||||||
|
|
||||||
if (botAI->IsMelee(bot))
|
if (botAI->IsMelee(bot))
|
||||||
{
|
|
||||||
botAI->SetNextCheckDelay(100);
|
botAI->SetNextCheckDelay(100);
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2261,15 +2161,11 @@ bool MimironP3Wx2LaserBarrageAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
auto master = botAI->GetMaster();
|
auto master = botAI->GetMaster();
|
||||||
if (!master || !master->IsAlive())
|
if (!master || !master->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (bot->GetDistance2d(master) > 15.0f)
|
if (bot->GetDistance2d(master) > 15.0f)
|
||||||
{
|
|
||||||
return bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(),
|
return bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(),
|
||||||
master->GetPositionZ(), master->GetOrientation());
|
master->GetPositionZ(), master->GetOrientation());
|
||||||
}
|
|
||||||
|
|
||||||
return MoveTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), false,
|
return MoveTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(), false,
|
||||||
false, false, true, MovementPriority::MOVEMENT_COMBAT, true);
|
false, false, true, MovementPriority::MOVEMENT_COMBAT, true);
|
||||||
@ -2294,18 +2190,14 @@ bool MimironRapidBurstAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
{
|
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Position targetPosition;
|
Position targetPosition;
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
uint32 memberSpotNumber = 0;
|
uint32 memberSpotNumber = 0;
|
||||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
@ -2359,28 +2251,21 @@ bool MimironRapidBurstAction::Execute(Event /*event*/)
|
|||||||
memberSpotNumber++;
|
memberSpotNumber++;
|
||||||
|
|
||||||
if (memberSpotNumber == 3)
|
if (memberSpotNumber == 3)
|
||||||
{
|
|
||||||
memberSpotNumber = 0;
|
memberSpotNumber = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveTo(bot->GetMapId(), targetPosition.GetPositionX(), targetPosition.GetPositionY(), targetPosition.GetPositionZ(),
|
MoveTo(bot->GetMapId(), targetPosition.GetPositionX(), targetPosition.GetPositionY(), targetPosition.GetPositionZ(),
|
||||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED, true, false);
|
false, false, false, true, MovementPriority::MOVEMENT_FORCED, true, false);
|
||||||
|
|
||||||
if (AI_VALUE(float, "disperse distance") != 0.0f)
|
if (AI_VALUE(float, "disperse distance") != 0.0f)
|
||||||
{
|
|
||||||
SET_AI_VALUE(float, "disperse distance", 0.0f);
|
SET_AI_VALUE(float, "disperse distance", 0.0f);
|
||||||
}
|
|
||||||
|
|
||||||
TankFaceStrategy tankFaceStrategy(botAI);
|
TankFaceStrategy tankFaceStrategy(botAI);
|
||||||
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
||||||
{
|
|
||||||
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||||
}
|
|
||||||
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
||||||
{
|
|
||||||
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
||||||
}
|
|
||||||
|
|
||||||
if (bot->GetDistance(targetPosition) > 1.0f)
|
if (bot->GetDistance(targetPosition) > 1.0f)
|
||||||
return false;
|
return false;
|
||||||
@ -2403,53 +2288,38 @@ bool MimironAerialCommandUnitAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
{
|
|
||||||
boss = target;
|
boss = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_BOMB_BOT)
|
else if (target->GetEntry() == NPC_BOMB_BOT)
|
||||||
{
|
|
||||||
bombBot = target;
|
bombBot = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_ASSAULT_BOT)
|
else if (target->GetEntry() == NPC_ASSAULT_BOT)
|
||||||
{
|
|
||||||
assaultBot = target;
|
assaultBot = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0))
|
if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0))
|
||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (bombBot)
|
if (bombBot)
|
||||||
{
|
|
||||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), bombBot->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), bombBot->GetGUID());
|
||||||
}
|
|
||||||
else if (boss)
|
else if (boss)
|
||||||
{
|
|
||||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), boss->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), boss->GetGUID());
|
||||||
}
|
|
||||||
|
|
||||||
if (assaultBot)
|
if (assaultBot)
|
||||||
{
|
{
|
||||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||||
Unit* skullUnit = botAI->GetUnit(skullTarget);
|
Unit* skullUnit = botAI->GetUnit(skullTarget);
|
||||||
if (!skullTarget || !skullUnit || !skullUnit->IsAlive())
|
if (!skullTarget || !skullUnit || !skullUnit->IsAlive())
|
||||||
{
|
|
||||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), assaultBot->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), assaultBot->GetGUID());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AI_VALUE(float, "disperse distance") != 5.0f)
|
if (AI_VALUE(float, "disperse distance") != 5.0f)
|
||||||
{
|
|
||||||
SET_AI_VALUE(float, "disperse distance", 5.0f);
|
SET_AI_VALUE(float, "disperse distance", 5.0f);
|
||||||
}
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2476,10 +2346,8 @@ bool MimironRocketStrikeAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
vx001 = target;
|
vx001 = target;
|
||||||
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
aerialCommandUnit = target;
|
aerialCommandUnit = target;
|
||||||
}
|
}
|
||||||
@ -2536,23 +2404,15 @@ bool MimironPhase4MarkDpsAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
{
|
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
{
|
|
||||||
vx001 = target;
|
vx001 = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
{
|
|
||||||
aerialCommandUnit = target;
|
aerialCommandUnit = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leviathanMkII || !vx001 || !aerialCommandUnit)
|
if (!leviathanMkII || !vx001 || !aerialCommandUnit)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot))
|
if (botAI->IsMainTank(bot))
|
||||||
{
|
{
|
||||||
@ -2563,31 +2423,27 @@ bool MimironPhase4MarkDpsAction::Execute(Event /*event*/)
|
|||||||
highestHealth = leviathanMkII->GetHealth();
|
highestHealth = leviathanMkII->GetHealth();
|
||||||
highestHealthUnit = leviathanMkII;
|
highestHealthUnit = leviathanMkII;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vx001 && vx001->GetHealth() > highestHealth)
|
if (vx001 && vx001->GetHealth() > highestHealth)
|
||||||
{
|
{
|
||||||
highestHealth = vx001->GetHealth();
|
highestHealth = vx001->GetHealth();
|
||||||
highestHealthUnit = vx001;
|
highestHealthUnit = vx001;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aerialCommandUnit && aerialCommandUnit->GetHealth() > highestHealth)
|
if (aerialCommandUnit && aerialCommandUnit->GetHealth() > highestHealth)
|
||||||
{
|
|
||||||
highestHealthUnit = aerialCommandUnit;
|
highestHealthUnit = aerialCommandUnit;
|
||||||
}
|
|
||||||
|
|
||||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), highestHealthUnit->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), highestHealthUnit->GetGUID());
|
||||||
if (highestHealthUnit == leviathanMkII)
|
if (highestHealthUnit == leviathanMkII)
|
||||||
{
|
{
|
||||||
if (AI_VALUE(std::string, "rti") == "skull")
|
if (AI_VALUE(std::string, "rti") == "skull")
|
||||||
{
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("skull");
|
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("skull");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), leviathanMkII->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), leviathanMkII->GetGUID());
|
||||||
if (AI_VALUE(std::string, "rti") != "cross")
|
if (AI_VALUE(std::string, "rti") != "cross")
|
||||||
{
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
botAI->DoSpecificAction("attack rti target");
|
botAI->DoSpecificAction("attack rti target");
|
||||||
@ -2614,13 +2470,9 @@ bool MimironCheatAction::Execute(Event /*event*/)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (unit->GetEntry() == NPC_PROXIMITY_MINE)
|
if (unit->GetEntry() == NPC_PROXIMITY_MINE)
|
||||||
{
|
|
||||||
unit->Kill(bot, unit);
|
unit->Kill(bot, unit);
|
||||||
}
|
|
||||||
else if (unit->GetEntry() == NPC_BOMB_BOT)
|
else if (unit->GetEntry() == NPC_BOMB_BOT)
|
||||||
{
|
|
||||||
unit->Kill(bot, unit);
|
unit->Kill(bot, unit);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2631,9 +2483,7 @@ bool VezaxCheatAction::Execute(Event /*event*/)
|
|||||||
// Restore bot's mana to full
|
// Restore bot's mana to full
|
||||||
uint32 maxMana = bot->GetMaxPower(POWER_MANA);
|
uint32 maxMana = bot->GetMaxPower(POWER_MANA);
|
||||||
if (maxMana > 0)
|
if (maxMana > 0)
|
||||||
{
|
|
||||||
bot->SetPower(POWER_MANA, maxMana);
|
bot->SetPower(POWER_MANA, maxMana);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2643,9 +2493,7 @@ bool VezaxShadowCrashAction::Execute(Event /*event*/)
|
|||||||
// Find General Vezax boss
|
// Find General Vezax boss
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax");
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Get bot's current position relative to boss
|
// Get bot's current position relative to boss
|
||||||
float bossX = boss->GetPositionX();
|
float bossX = boss->GetPositionX();
|
||||||
@ -2664,9 +2512,7 @@ bool VezaxShadowCrashAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
// If too close or too far, adjust distance first
|
// If too close or too far, adjust distance first
|
||||||
if (currentDistance < desiredDistance - 2.0f || currentDistance > desiredDistance + 2.0f)
|
if (currentDistance < desiredDistance - 2.0f || currentDistance > desiredDistance + 2.0f)
|
||||||
{
|
|
||||||
currentDistance = desiredDistance;
|
currentDistance = desiredDistance;
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate movement increment - move in increments around the boss
|
// Calculate movement increment - move in increments around the boss
|
||||||
float angleIncrement = M_PI / 10;
|
float angleIncrement = M_PI / 10;
|
||||||
@ -2696,15 +2542,11 @@ bool YoggSaronOminousCloudCheatAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
Unit* boss = yoggSaronTrigger.GetSaraIfAlive();
|
Unit* boss = yoggSaronTrigger.GetSaraIfAlive();
|
||||||
if (!boss)
|
if (!boss)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Creature* target = boss->FindNearestCreature(NPC_OMINOUS_CLOUD, 25.0f);
|
Creature* target = boss->FindNearestCreature(NPC_OMINOUS_CLOUD, 25.0f);
|
||||||
if (!target || !target->IsAlive())
|
if (!target || !target->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
target->Kill(bot, target);
|
target->Kill(bot, target);
|
||||||
return true;
|
return true;
|
||||||
@ -2730,9 +2572,7 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
YoggSaronTrigger yoggSaronTrigger(botAI);
|
YoggSaronTrigger yoggSaronTrigger(botAI);
|
||||||
if (yoggSaronTrigger.IsPhase2())
|
if (yoggSaronTrigger.IsPhase2())
|
||||||
@ -2741,9 +2581,7 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Unit* crusherTentacle = bot->FindNearestCreature(NPC_CRUSHER_TENTACLE, 200.0f, true);
|
Unit* crusherTentacle = bot->FindNearestCreature(NPC_CRUSHER_TENTACLE, 200.0f, true);
|
||||||
if (crusherTentacle)
|
if (crusherTentacle)
|
||||||
{
|
|
||||||
crusherTentacle->Kill(bot, crusherTentacle);
|
crusherTentacle->Kill(bot, crusherTentacle);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
||||||
@ -2761,9 +2599,7 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
nextPossibleTarget = bot->FindNearestCreature(NPC_CORRUPTOR_TENTACLE, 200.0f, true);
|
nextPossibleTarget = bot->FindNearestCreature(NPC_CORRUPTOR_TENTACLE, 200.0f, true);
|
||||||
if (!nextPossibleTarget)
|
if (!nextPossibleTarget)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSkullTarget)
|
if (currentSkullTarget)
|
||||||
@ -2772,9 +2608,7 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
if (currentSkullUnit && currentSkullUnit->IsAlive() &&
|
if (currentSkullUnit && currentSkullUnit->IsAlive() &&
|
||||||
currentSkullUnit->GetGUID() == nextPossibleTarget->GetGUID())
|
currentSkullUnit->GetGUID() == nextPossibleTarget->GetGUID())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), nextPossibleTarget->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), nextPossibleTarget->GetGUID());
|
||||||
@ -2783,15 +2617,11 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
TankFaceStrategy tankFaceStrategy(botAI);
|
TankFaceStrategy tankFaceStrategy(botAI);
|
||||||
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
||||||
{
|
|
||||||
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||||
}
|
|
||||||
|
|
||||||
TankAssistStrategy tankAssistStrategy(botAI);
|
TankAssistStrategy tankAssistStrategy(botAI);
|
||||||
if (!botAI->HasStrategy(tankAssistStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
if (!botAI->HasStrategy(tankAssistStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
||||||
{
|
|
||||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + tankAssistStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + tankAssistStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||||
}
|
|
||||||
|
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||||
|
|
||||||
@ -2801,9 +2631,7 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(guid);
|
Unit* unit = botAI->GetUnit(guid);
|
||||||
if (!unit || !unit->IsAlive())
|
if (!unit || !unit->IsAlive())
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if ((unit->GetEntry() == NPC_IMMORTAL_GUARDIAN || unit->GetEntry() == NPC_MARKED_IMMORTAL_GUARDIAN) &&
|
if ((unit->GetEntry() == NPC_IMMORTAL_GUARDIAN || unit->GetEntry() == NPC_MARKED_IMMORTAL_GUARDIAN) &&
|
||||||
unit->GetHealthPct() > 10)
|
unit->GetHealthPct() > 10)
|
||||||
@ -2821,13 +2649,9 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
// Added because lunatic gaze freeze all bots and they can't attack
|
// Added because lunatic gaze freeze all bots and they can't attack
|
||||||
// If someone fix it then this cheat can be removed
|
// If someone fix it then this cheat can be removed
|
||||||
if (botAI->HasCheat(BotCheatMask::raid))
|
if (botAI->HasCheat(BotCheatMask::raid))
|
||||||
{
|
|
||||||
lowestHealthUnit->Kill(bot, lowestHealthUnit);
|
lowestHealthUnit->Kill(bot, lowestHealthUnit);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), lowestHealthUnit->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), lowestHealthUnit->GetGUID());
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2835,9 +2659,7 @@ bool YoggSaronMarkTargetAction::Execute(Event /*event*/)
|
|||||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||||
Unit* currentSkullUnit = nullptr;
|
Unit* currentSkullUnit = nullptr;
|
||||||
if (currentSkullTarget)
|
if (currentSkullTarget)
|
||||||
{
|
|
||||||
currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||||
}
|
|
||||||
|
|
||||||
if (!currentSkullUnit || currentSkullUnit->GetEntry() != NPC_YOGG_SARON)
|
if (!currentSkullUnit || currentSkullUnit->GetEntry() != NPC_YOGG_SARON)
|
||||||
{
|
{
|
||||||
@ -2859,17 +2681,13 @@ bool YoggSaronBrainLinkAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
{
|
{
|
||||||
Player* player = gref->GetSource();
|
Player* player = gref->GetSource();
|
||||||
if (player && player->IsAlive() && player->HasAura(SPELL_BRAIN_LINK) && player->GetGUID() != bot->GetGUID())
|
if (player && player->IsAlive() && player->HasAura(SPELL_BRAIN_LINK) && player->GetGUID() != bot->GetGUID())
|
||||||
{
|
|
||||||
return MoveNear(player, 10.0f, MovementPriority::MOVEMENT_FORCED);
|
return MoveNear(player, 10.0f, MovementPriority::MOVEMENT_FORCED);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -2879,17 +2697,13 @@ bool YoggSaronMoveToEnterPortalAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
bool isInBrainRoomTeam = false;
|
bool isInBrainRoomTeam = false;
|
||||||
int portalNumber = 0;
|
int portalNumber = 0;
|
||||||
int brainRoomTeamCount = 10;
|
int brainRoomTeamCount = 10;
|
||||||
if (bot->GetRaidDifficulty() == Difficulty::RAID_DIFFICULTY_10MAN_NORMAL)
|
if (bot->GetRaidDifficulty() == Difficulty::RAID_DIFFICULTY_10MAN_NORMAL)
|
||||||
{
|
|
||||||
brainRoomTeamCount = 4;
|
brainRoomTeamCount = 4;
|
||||||
}
|
|
||||||
|
|
||||||
Player* master = botAI->GetMaster();
|
Player* master = botAI->GetMaster();
|
||||||
if (master && !botAI->IsTank(master))
|
if (master && !botAI->IsTank(master))
|
||||||
@ -2902,9 +2716,7 @@ bool YoggSaronMoveToEnterPortalAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
Player* member = gref->GetSource();
|
Player* member = gref->GetSource();
|
||||||
if (!member || !member->IsAlive() || botAI->IsTank(member) || botAI->GetMaster()->GetGUID() == member->GetGUID())
|
if (!member || !member->IsAlive() || botAI->IsTank(member) || botAI->GetMaster()->GetGUID() == member->GetGUID())
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
portalNumber++;
|
portalNumber++;
|
||||||
if (member->GetGUID() == bot->GetGUID())
|
if (member->GetGUID() == bot->GetGUID())
|
||||||
@ -2915,15 +2727,11 @@ bool YoggSaronMoveToEnterPortalAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
brainRoomTeamCount--;
|
brainRoomTeamCount--;
|
||||||
if (brainRoomTeamCount == 0)
|
if (brainRoomTeamCount == 0)
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isInBrainRoomTeam)
|
if (!isInBrainRoomTeam)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Position assignedPortalPosition = yoggPortalLoc[portalNumber - 1];
|
Position assignedPortalPosition = yoggPortalLoc[portalNumber - 1];
|
||||||
|
|
||||||
@ -2980,33 +2788,24 @@ bool YoggSaronBossRoomMovementCheatAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
FollowMasterStrategy followMasterStrategy(botAI);
|
FollowMasterStrategy followMasterStrategy(botAI);
|
||||||
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
||||||
{
|
|
||||||
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
||||||
}
|
|
||||||
|
|
||||||
if (!botAI->HasCheat(BotCheatMask::raid))
|
if (!botAI->HasCheat(BotCheatMask::raid))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||||
|
|
||||||
if (!currentSkullTarget)
|
if (!currentSkullTarget)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||||
|
|
||||||
if (!currentSkullUnit || !currentSkullUnit->IsAlive())
|
if (!currentSkullUnit || !currentSkullUnit->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return bot->TeleportTo(bot->GetMapId(), currentSkullUnit->GetPositionX(), currentSkullUnit->GetPositionY(),
|
return bot->TeleportTo(bot->GetMapId(), currentSkullUnit->GetPositionX(), currentSkullUnit->GetPositionY(),
|
||||||
currentSkullUnit->GetPositionZ(), bot->GetOrientation());
|
currentSkullUnit->GetPositionZ(), bot->GetOrientation());
|
||||||
@ -3014,19 +2813,15 @@ bool YoggSaronBossRoomMovementCheatAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
bool YoggSaronUsePortalAction::Execute(Event /*event*/)
|
bool YoggSaronUsePortalAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
Creature* assignedPortal = bot->FindNearestCreature(NPC_DESCEND_INTO_MADNESS, 2.0f, true);
|
Creature* assignedPortal = bot->FindNearestCreature(NPC_DESCEND_INTO_MADNESS, 2.0f, true);
|
||||||
if (!assignedPortal)
|
if (!assignedPortal)
|
||||||
{
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FollowMasterStrategy followMasterStrategy(botAI);
|
FollowMasterStrategy followMasterStrategy(botAI);
|
||||||
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
||||||
{
|
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
||||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return assignedPortal->HandleSpellClick(bot);
|
return assignedPortal->HandleSpellClick(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool YoggSaronIllusionRoomAction::Execute(Event /*event*/)
|
bool YoggSaronIllusionRoomAction::Execute(Event /*event*/)
|
||||||
@ -3067,15 +2862,11 @@ bool YoggSaronIllusionRoomAction::SetIllusionRtiTarget(YoggSaronTrigger yoggSaro
|
|||||||
{
|
{
|
||||||
Unit* currentRtiTarget = yoggSaronTrigger.GetIllusionRoomRtiTarget();
|
Unit* currentRtiTarget = yoggSaronTrigger.GetIllusionRoomRtiTarget();
|
||||||
if (currentRtiTarget)
|
if (currentRtiTarget)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Unit* nextRtiTarget = yoggSaronTrigger.GetNextIllusionRoomRtiTarget();
|
Unit* nextRtiTarget = yoggSaronTrigger.GetNextIllusionRoomRtiTarget();
|
||||||
if (!nextRtiTarget)
|
if (!nextRtiTarget)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// If proper adds handling in illusion room will be implemented, then this can be removed
|
// If proper adds handling in illusion room will be implemented, then this can be removed
|
||||||
if (botAI->HasCheat(BotCheatMask::raid))
|
if (botAI->HasCheat(BotCheatMask::raid))
|
||||||
@ -3090,9 +2881,7 @@ bool YoggSaronIllusionRoomAction::SetIllusionRtiTarget(YoggSaronTrigger yoggSaro
|
|||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
uint8 rtiIndex = RtiTargetValue::GetRtiIndex(AI_VALUE(std::string, "rti"));
|
uint8 rtiIndex = RtiTargetValue::GetRtiIndex(AI_VALUE(std::string, "rti"));
|
||||||
group->SetTargetIcon(rtiIndex, bot->GetGUID(), nextRtiTarget->GetGUID());
|
group->SetTargetIcon(rtiIndex, bot->GetGUID(), nextRtiTarget->GetGUID());
|
||||||
@ -3104,23 +2893,17 @@ bool YoggSaronIllusionRoomAction::SetIllusionRtiTarget(YoggSaronTrigger yoggSaro
|
|||||||
bool YoggSaronIllusionRoomAction::SetBrainRtiTarget(YoggSaronTrigger yoggSaronTrigger)
|
bool YoggSaronIllusionRoomAction::SetBrainRtiTarget(YoggSaronTrigger yoggSaronTrigger)
|
||||||
{
|
{
|
||||||
if (AI_VALUE(std::string, "rti") == "square" || !yoggSaronTrigger.IsMasterIsInBrainRoom())
|
if (AI_VALUE(std::string, "rti") == "square" || !yoggSaronTrigger.IsMasterIsInBrainRoom())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("square");
|
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("square");
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Creature* brain = bot->FindNearestCreature(NPC_BRAIN, 200.0f, true);
|
Creature* brain = bot->FindNearestCreature(NPC_BRAIN, 200.0f, true);
|
||||||
if (!brain)
|
if (!brain)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
group->SetTargetIcon(RtiTargetValue::squareIndex, bot->GetGUID(), brain->GetGUID());
|
group->SetTargetIcon(RtiTargetValue::squareIndex, bot->GetGUID(), brain->GetGUID());
|
||||||
|
|
||||||
@ -3160,7 +2943,6 @@ bool YoggSaronMoveToExitPortalAction::Execute(Event /*event*/)
|
|||||||
if (botAI->HasCheat(BotCheatMask::raid))
|
if (botAI->HasCheat(BotCheatMask::raid))
|
||||||
bot->TeleportTo(bot->GetMapId(), portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(),
|
bot->TeleportTo(bot->GetMapId(), portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(),
|
||||||
bot->GetOrientation());
|
bot->GetOrientation());
|
||||||
|
|
||||||
else
|
else
|
||||||
MoveTo(bot->GetMapId(), portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), false,
|
MoveTo(bot->GetMapId(), portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), false,
|
||||||
false, false, true, MovementPriority::MOVEMENT_FORCED,
|
false, false, true, MovementPriority::MOVEMENT_FORCED,
|
||||||
@ -3189,9 +2971,7 @@ bool YoggSaronLunaticGazeAction::Execute(Event /*event*/)
|
|||||||
{
|
{
|
||||||
if (AI_VALUE(std::string, "rti") != "cross")
|
if (AI_VALUE(std::string, "rti") != "cross")
|
||||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -852,8 +852,6 @@ bool ThorimMarkDpsTargetTrigger::IsActive()
|
|||||||
|
|
||||||
Unit* runicColossus = AI_VALUE2(Unit*, "find target", "runic colossus");
|
Unit* runicColossus = AI_VALUE2(Unit*, "find target", "runic colossus");
|
||||||
Unit* ancientRuneGiant = AI_VALUE2(Unit*, "find target", "ancient rune giant");
|
Unit* ancientRuneGiant = AI_VALUE2(Unit*, "find target", "ancient rune giant");
|
||||||
Unit* ironHonorGuard = AI_VALUE2(Unit*, "find target", "iron ring guard");
|
|
||||||
Unit* ironRingGuard = AI_VALUE2(Unit*, "find target", "iron honor guard");
|
|
||||||
|
|
||||||
if (acolyte && acolyte->IsAlive() && (!currentCrossUnit || currentCrossUnit->GetEntry() != acolyte->GetEntry()))
|
if (acolyte && acolyte->IsAlive() && (!currentCrossUnit || currentCrossUnit->GetEntry() != acolyte->GetEntry()))
|
||||||
return true;
|
return true;
|
||||||
@ -1179,8 +1177,6 @@ bool MimironPhase1PositioningTrigger::IsActive()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Unit* leviathanMkII = nullptr;
|
Unit* leviathanMkII = nullptr;
|
||||||
Unit* vx001 = nullptr;
|
|
||||||
Unit* aerialCommandUnit = nullptr;
|
|
||||||
|
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||||
Unit* target = nullptr;
|
Unit* target = nullptr;
|
||||||
@ -1192,19 +1188,14 @@ bool MimironPhase1PositioningTrigger::IsActive()
|
|||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leviathanMkII || !leviathanMkII->IsAlive())
|
if (!leviathanMkII || !leviathanMkII->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return AI_VALUE(float, "disperse distance") != 6.0f;
|
return AI_VALUE(float, "disperse distance") != 6.0f;
|
||||||
}
|
}
|
||||||
@ -1215,9 +1206,7 @@ bool MimironP3Wx2LaserBarrageTrigger::IsActive()
|
|||||||
|
|
||||||
// Check boss and it is alive
|
// Check boss and it is alive
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
bool isCasting = boss->HasUnitState(UNIT_STATE_CASTING);
|
bool isCasting = boss->HasUnitState(UNIT_STATE_CASTING);
|
||||||
bool isP3WX2LaserBarrage = boss->FindCurrentSpellBySpellId(SPELL_SPINNING_UP) ||
|
bool isP3WX2LaserBarrage = boss->FindCurrentSpellBySpellId(SPELL_SPINNING_UP) ||
|
||||||
@ -1230,9 +1219,7 @@ bool MimironP3Wx2LaserBarrageTrigger::IsActive()
|
|||||||
boss->HasAura(SPELL_P3WX2_LASER_BARRAGE_AURA_1) || boss->HasAura(SPELL_P3WX2_LASER_BARRAGE_AURA_2);
|
boss->HasAura(SPELL_P3WX2_LASER_BARRAGE_AURA_1) || boss->HasAura(SPELL_P3WX2_LASER_BARRAGE_AURA_2);
|
||||||
|
|
||||||
if ((!isCasting && !hasP3WX2LaserBarrageAura) || !isP3WX2LaserBarrage)
|
if ((!isCasting && !hasP3WX2LaserBarrageAura) || !isP3WX2LaserBarrage)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1252,51 +1239,33 @@ bool MimironRapidBurstTrigger::IsActive()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
{
|
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
{
|
|
||||||
vx001 = target;
|
vx001 = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
{
|
|
||||||
aerialCommandUnit = target;
|
aerialCommandUnit = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vx001 || !vx001->IsAlive())
|
if (!vx001 || !vx001->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (leviathanMkII && leviathanMkII->HasUnitState(UNIT_STATE_CASTING) &&
|
if (leviathanMkII && leviathanMkII->HasUnitState(UNIT_STATE_CASTING) &&
|
||||||
leviathanMkII->FindCurrentSpellBySpellId(SPELL_SHOCK_BLAST))
|
leviathanMkII->FindCurrentSpellBySpellId(SPELL_SHOCK_BLAST))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot) && leviathanMkII && leviathanMkII->IsAlive() && leviathanMkII->GetVictim() != bot)
|
if (botAI->IsMainTank(bot) && leviathanMkII && leviathanMkII->IsAlive() && leviathanMkII->GetVictim() != bot)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMelee(bot) && !botAI->IsMainTank(bot) && leviathanMkII && aerialCommandUnit)
|
if (botAI->IsMelee(bot) && !botAI->IsMainTank(bot) && leviathanMkII && aerialCommandUnit)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
MimironP3Wx2LaserBarrageTrigger mimironP3Wx2LaserBarrageTrigger(botAI);
|
MimironP3Wx2LaserBarrageTrigger mimironP3Wx2LaserBarrageTrigger(botAI);
|
||||||
if (mimironP3Wx2LaserBarrageTrigger.IsActive())
|
if (mimironP3Wx2LaserBarrageTrigger.IsActive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
uint32 memberSpotNumber = 0;
|
uint32 memberSpotNumber = 0;
|
||||||
Position memberPosition;
|
Position memberPosition;
|
||||||
@ -1355,9 +1324,7 @@ bool MimironRapidBurstTrigger::IsActive()
|
|||||||
memberSpotNumber++;
|
memberSpotNumber++;
|
||||||
|
|
||||||
if (memberSpotNumber == 3)
|
if (memberSpotNumber == 3)
|
||||||
{
|
|
||||||
memberSpotNumber = 0;
|
memberSpotNumber = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||||
@ -1390,7 +1357,6 @@ bool MimironAerialCommandUnitTrigger::IsActive()
|
|||||||
Unit* leviathanMkII = nullptr;
|
Unit* leviathanMkII = nullptr;
|
||||||
Unit* vx001 = nullptr;
|
Unit* vx001 = nullptr;
|
||||||
Unit* aerialCommandUnit = nullptr;
|
Unit* aerialCommandUnit = nullptr;
|
||||||
//Unit* bombBot = nullptr;
|
|
||||||
Unit* assaultBot = nullptr;
|
Unit* assaultBot = nullptr;
|
||||||
|
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||||
@ -1402,69 +1368,41 @@ bool MimironAerialCommandUnitTrigger::IsActive()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
{
|
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
{
|
|
||||||
vx001 = target;
|
vx001 = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
{
|
|
||||||
aerialCommandUnit = target;
|
aerialCommandUnit = target;
|
||||||
}
|
|
||||||
//else if (target->GetEntry() == NPC_BOMB_BOT)
|
|
||||||
//{
|
|
||||||
// bombBot = target;
|
|
||||||
//}
|
|
||||||
else if (target->GetEntry() == NPC_ASSAULT_BOT)
|
else if (target->GetEntry() == NPC_ASSAULT_BOT)
|
||||||
{
|
|
||||||
assaultBot = target;
|
assaultBot = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!aerialCommandUnit || !aerialCommandUnit->IsAlive() || leviathanMkII || vx001)
|
if (!aerialCommandUnit || !aerialCommandUnit->IsAlive() || leviathanMkII || vx001)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!botAI->IsRanged(bot) && !botAI->IsMainTank(bot) && !botAI->IsAssistTankOfIndex(bot, 0))
|
if (!botAI->IsRanged(bot) && !botAI->IsMainTank(bot) && !botAI->IsAssistTankOfIndex(bot, 0))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0))
|
if (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0))
|
||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||||
ObjectGuid crossTarget = group->GetTargetIcon(RtiTargetValue::crossIndex);
|
ObjectGuid crossTarget = group->GetTargetIcon(RtiTargetValue::crossIndex);
|
||||||
|
|
||||||
//if (bombBot && bombBot->GetGUID() != crossTarget)
|
|
||||||
//{
|
|
||||||
// return true;
|
|
||||||
//}
|
|
||||||
if (!crossTarget || aerialCommandUnit->GetGUID() != crossTarget)
|
if (!crossTarget || aerialCommandUnit->GetGUID() != crossTarget)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
else if (assaultBot && (!skullTarget || assaultBot->GetGUID() != skullTarget))
|
else if (assaultBot && (!skullTarget || assaultBot->GetGUID() != skullTarget))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rtiMark = AI_VALUE(std::string, "rti");
|
std::string rtiMark = AI_VALUE(std::string, "rti");
|
||||||
if (rtiMark != "cross")
|
if (rtiMark != "cross")
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1475,16 +1413,12 @@ bool MimironRocketStrikeTrigger::IsActive()
|
|||||||
|
|
||||||
// Check boss and it is alive
|
// Check boss and it is alive
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Creature* rocketStrikeN = bot->FindNearestCreature(NPC_ROCKET_STRIKE_N, 100.0f);
|
Creature* rocketStrikeN = bot->FindNearestCreature(NPC_ROCKET_STRIKE_N, 100.0f);
|
||||||
|
|
||||||
if (!rocketStrikeN)
|
if (!rocketStrikeN)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return bot->GetDistance2d(rocketStrikeN->GetPositionX(), rocketStrikeN->GetPositionY()) <= 10.0f;
|
return bot->GetDistance2d(rocketStrikeN->GetPositionX(), rocketStrikeN->GetPositionY()) <= 10.0f;
|
||||||
}
|
}
|
||||||
@ -1497,9 +1431,7 @@ bool MimironPhase4MarkDpsTrigger::IsActive()
|
|||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||||
Unit* target = nullptr;
|
Unit* target = nullptr;
|
||||||
@ -1510,23 +1442,15 @@ bool MimironPhase4MarkDpsTrigger::IsActive()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
if (target->GetEntry() == NPC_LEVIATHAN_MKII)
|
||||||
{
|
|
||||||
leviathanMkII = target;
|
leviathanMkII = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_VX001)
|
else if (target->GetEntry() == NPC_VX001)
|
||||||
{
|
|
||||||
vx001 = target;
|
vx001 = target;
|
||||||
}
|
|
||||||
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
else if (target->GetEntry() == NPC_AERIAL_COMMAND_UNIT)
|
||||||
{
|
|
||||||
aerialCommandUnit = target;
|
aerialCommandUnit = target;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!leviathanMkII || !vx001 || !aerialCommandUnit)
|
if (!leviathanMkII || !vx001 || !aerialCommandUnit)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot))
|
if (botAI->IsMainTank(bot))
|
||||||
{
|
{
|
||||||
@ -1544,22 +1468,16 @@ bool MimironPhase4MarkDpsTrigger::IsActive()
|
|||||||
highestHealthUnit = vx001;
|
highestHealthUnit = vx001;
|
||||||
}
|
}
|
||||||
if (aerialCommandUnit && aerialCommandUnit->GetHealth() > highestHealth)
|
if (aerialCommandUnit && aerialCommandUnit->GetHealth() > highestHealth)
|
||||||
{
|
|
||||||
highestHealthUnit = aerialCommandUnit;
|
highestHealthUnit = aerialCommandUnit;
|
||||||
}
|
|
||||||
|
|
||||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||||
if (!skullTarget)
|
if (!skullTarget)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return highestHealthUnit->GetGUID() != skullTarget;
|
return highestHealthUnit->GetGUID() != skullTarget;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return AI_VALUE(std::string, "rti") != "skull";
|
return AI_VALUE(std::string, "rti") != "skull";
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1567,14 +1485,10 @@ bool MimironPhase4MarkDpsTrigger::IsActive()
|
|||||||
bool MimironCheatTrigger::IsActive()
|
bool MimironCheatTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!botAI->HasCheat(BotCheatMask::raid))
|
if (!botAI->HasCheat(BotCheatMask::raid))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!botAI->IsMainTank(bot))
|
if (!botAI->IsMainTank(bot))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||||
for (const ObjectGuid& guid : targets)
|
for (const ObjectGuid& guid : targets)
|
||||||
@ -1584,13 +1498,9 @@ bool MimironCheatTrigger::IsActive()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (unit->GetEntry() == NPC_PROXIMITY_MINE)
|
if (unit->GetEntry() == NPC_PROXIMITY_MINE)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
else if (unit->GetEntry() == NPC_BOMB_BOT)
|
else if (unit->GetEntry() == NPC_BOMB_BOT)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -1599,22 +1509,16 @@ bool MimironCheatTrigger::IsActive()
|
|||||||
bool VezaxCheatTrigger::IsActive()
|
bool VezaxCheatTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!botAI->HasCheat(BotCheatMask::raid))
|
if (!botAI->HasCheat(BotCheatMask::raid))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "general vezax");
|
||||||
|
|
||||||
// Check boss and it is alive
|
// Check boss and it is alive
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!AI_VALUE2(bool, "has mana", "self target"))
|
if (!AI_VALUE2(bool, "has mana", "self target"))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana;
|
return AI_VALUE2(uint8, "mana", "self target") < sPlayerbotAIConfig.lowMana;
|
||||||
}
|
}
|
||||||
@ -1625,9 +1529,7 @@ bool VezaxShadowCrashTrigger::IsActive()
|
|||||||
|
|
||||||
// Check boss and it is alive
|
// Check boss and it is alive
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
|
return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
|
||||||
}
|
}
|
||||||
@ -1638,14 +1540,10 @@ bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
|||||||
|
|
||||||
// Check boss and it is alive
|
// Check boss and it is alive
|
||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (!botAI->HasAura(SPELL_MARK_OF_THE_FACELESS, bot))
|
if (!botAI->HasAura(SPELL_MARK_OF_THE_FACELESS, bot))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
float distance = bot->GetDistance2d(ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(),
|
float distance = bot->GetDistance2d(ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(),
|
||||||
ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionY());
|
ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionY());
|
||||||
@ -1657,9 +1555,8 @@ Unit* YoggSaronTrigger::GetSaraIfAlive()
|
|||||||
{
|
{
|
||||||
Unit* sara = AI_VALUE2(Unit*, "find target", "sara");
|
Unit* sara = AI_VALUE2(Unit*, "find target", "sara");
|
||||||
if (!sara || !sara->IsAlive())
|
if (!sara || !sara->IsAlive())
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
return sara;
|
return sara;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1689,9 +1586,7 @@ bool YoggSaronTrigger::IsYoggSaronFight()
|
|||||||
Unit* yoggsaron = AI_VALUE2(Unit*, "find target", "yogg-saron");
|
Unit* yoggsaron = AI_VALUE2(Unit*, "find target", "yogg-saron");
|
||||||
|
|
||||||
if ((sara && sara->IsAlive()) || (yoggsaron && yoggsaron->IsAlive()))
|
if ((sara && sara->IsAlive()) || (yoggsaron && yoggsaron->IsAlive()))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1699,24 +1594,16 @@ bool YoggSaronTrigger::IsYoggSaronFight()
|
|||||||
bool YoggSaronTrigger::IsInIllusionRoom()
|
bool YoggSaronTrigger::IsInIllusionRoom()
|
||||||
{
|
{
|
||||||
if (!IsInBrainLevel())
|
if (!IsInBrainLevel())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInStormwindKeeperIllusion())
|
if (IsInStormwindKeeperIllusion())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInIcecrownKeeperIllusion())
|
if (IsInIcecrownKeeperIllusion())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInChamberOfTheAspectsIllusion())
|
if (IsInChamberOfTheAspectsIllusion())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1753,9 +1640,7 @@ bool YoggSaronTrigger::IsMasterIsInBrainRoom()
|
|||||||
Player* master = botAI->GetMaster();
|
Player* master = botAI->GetMaster();
|
||||||
|
|
||||||
if (!master)
|
if (!master)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return master->GetDistance2d(ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE.GetPositionX(),
|
return master->GetDistance2d(ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE.GetPositionX(),
|
||||||
ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE.GetPositionY()) <
|
ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE.GetPositionY()) <
|
||||||
@ -1766,43 +1651,29 @@ bool YoggSaronTrigger::IsMasterIsInBrainRoom()
|
|||||||
Position YoggSaronTrigger::GetIllusionRoomEntrancePosition()
|
Position YoggSaronTrigger::GetIllusionRoomEntrancePosition()
|
||||||
{
|
{
|
||||||
if (IsInChamberOfTheAspectsIllusion())
|
if (IsInChamberOfTheAspectsIllusion())
|
||||||
{
|
|
||||||
return ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE;
|
return ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE;
|
||||||
}
|
|
||||||
else if (IsInIcecrownKeeperIllusion())
|
else if (IsInIcecrownKeeperIllusion())
|
||||||
{
|
|
||||||
return ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE;
|
return ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE;
|
||||||
}
|
|
||||||
else if (IsInStormwindKeeperIllusion())
|
else if (IsInStormwindKeeperIllusion())
|
||||||
{
|
|
||||||
return ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE;
|
return ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
return Position();
|
return Position();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit* YoggSaronTrigger::GetIllusionRoomRtiTarget()
|
Unit* YoggSaronTrigger::GetIllusionRoomRtiTarget()
|
||||||
{
|
{
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
int32_t rtiIndex = RtiTargetValue::GetRtiIndex(AI_VALUE(std::string, "rti"));
|
int32_t rtiIndex = RtiTargetValue::GetRtiIndex(AI_VALUE(std::string, "rti"));
|
||||||
if (rtiIndex == -1)
|
if (rtiIndex == -1)
|
||||||
{
|
|
||||||
return nullptr; // Invalid RTI mark
|
return nullptr; // Invalid RTI mark
|
||||||
}
|
|
||||||
|
|
||||||
ObjectGuid currentRtiTarget = group->GetTargetIcon(rtiIndex);
|
ObjectGuid currentRtiTarget = group->GetTargetIcon(rtiIndex);
|
||||||
Unit* currentRtiTargetUnit = botAI->GetUnit(currentRtiTarget);
|
Unit* currentRtiTargetUnit = botAI->GetUnit(currentRtiTarget);
|
||||||
if (!currentRtiTargetUnit || !currentRtiTargetUnit->IsAlive())
|
if (!currentRtiTargetUnit || !currentRtiTargetUnit->IsAlive())
|
||||||
{
|
|
||||||
currentRtiTargetUnit = nullptr;
|
currentRtiTargetUnit = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
return currentRtiTargetUnit;
|
return currentRtiTargetUnit;
|
||||||
}
|
}
|
||||||
@ -1812,13 +1683,10 @@ Unit* YoggSaronTrigger::GetNextIllusionRoomRtiTarget()
|
|||||||
float detectionRadius = 0.0f;
|
float detectionRadius = 0.0f;
|
||||||
if (IsInStormwindKeeperIllusion())
|
if (IsInStormwindKeeperIllusion())
|
||||||
detectionRadius = ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS;
|
detectionRadius = ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS;
|
||||||
|
|
||||||
else if (IsInIcecrownKeeperIllusion())
|
else if (IsInIcecrownKeeperIllusion())
|
||||||
detectionRadius = ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS;
|
detectionRadius = ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS;
|
||||||
|
|
||||||
else if (IsInChamberOfTheAspectsIllusion())
|
else if (IsInChamberOfTheAspectsIllusion())
|
||||||
detectionRadius = ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS;
|
detectionRadius = ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS;
|
||||||
|
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -1855,9 +1723,7 @@ Unit* YoggSaronTrigger::GetNextIllusionRoomRtiTarget()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nextIllusionRoomRtiTarget)
|
if (nextIllusionRoomRtiTarget)
|
||||||
{
|
|
||||||
return nextIllusionRoomRtiTarget;
|
return nextIllusionRoomRtiTarget;
|
||||||
}
|
|
||||||
|
|
||||||
if (IsInStormwindKeeperIllusion())
|
if (IsInStormwindKeeperIllusion())
|
||||||
{
|
{
|
||||||
@ -1969,9 +1835,7 @@ bool YoggSaronMarkTargetTrigger::IsActive()
|
|||||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
||||||
Creature* yogg_saron = bot->FindNearestCreature(NPC_YOGG_SARON, 200.0f, true);
|
Creature* yogg_saron = bot->FindNearestCreature(NPC_YOGG_SARON, 200.0f, true);
|
||||||
if (!currentMoonTarget || currentMoonTarget != yogg_saron->GetGUID())
|
if (!currentMoonTarget || currentMoonTarget != yogg_saron->GetGUID())
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||||
|
|
||||||
@ -2234,9 +2098,7 @@ bool YoggSaronPhase3PositioningTrigger::IsActive()
|
|||||||
|
|
||||||
if (botAI->IsRanged(bot) && bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionX(),
|
if (botAI->IsRanged(bot) && bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionX(),
|
||||||
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionY()) > 15.0f)
|
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionY()) > 15.0f)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (botAI->IsMelee(bot) && !botAI->IsTank(bot) &&
|
if (botAI->IsMelee(bot) && !botAI->IsTank(bot) &&
|
||||||
bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||||
|
|||||||
@ -435,7 +435,6 @@ bool NewRpgTravelFlightAction::Execute(Event /*event*/)
|
|||||||
botAI->rpgInfo.ChangeToIdle();
|
botAI->rpgInfo.ChangeToIdle();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const TaxiNodesEntry* entry = sTaxiNodesStore.LookupEntry(data.toNode);
|
|
||||||
if (bot->GetDistance(flightMaster) > INTERACTION_DISTANCE)
|
if (bot->GetDistance(flightMaster) > INTERACTION_DISTANCE)
|
||||||
return MoveFarTo(flightMaster);
|
return MoveFarTo(flightMaster);
|
||||||
|
|
||||||
|
|||||||
@ -360,7 +360,6 @@ bool NewRpgBaseAction::IsWithinInteractionDist(Object* questGiver)
|
|||||||
case TYPEID_GAMEOBJECT:
|
case TYPEID_GAMEOBJECT:
|
||||||
{
|
{
|
||||||
ObjectGuid guid = questGiver->GetGUID();
|
ObjectGuid guid = questGiver->GetGUID();
|
||||||
GameobjectTypes type = GAMEOBJECT_TYPE_QUESTGIVER;
|
|
||||||
if (GameObject* go = bot->GetMap()->GetGameObject(guid))
|
if (GameObject* go = bot->GetMap()->GetGameObject(guid))
|
||||||
{
|
{
|
||||||
if (go->IsWithinDistInMap(bot))
|
if (go->IsWithinDistInMap(bot))
|
||||||
@ -546,7 +545,9 @@ bool NewRpgBaseAction::OrganizeQuestLog()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
const Quest* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||||
if (quest->GetZoneOrSort() < 0 || (quest->GetZoneOrSort() > 0 && quest->GetZoneOrSort() != bot->GetZoneId()))
|
const int64_t botZoneId = this->bot->GetZoneId();
|
||||||
|
|
||||||
|
if (quest->GetZoneOrSort() < 0 || (quest->GetZoneOrSort() > 0 && quest->GetZoneOrSort() != botZoneId))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
LOG_DEBUG("playerbots", "[New RPG] {} drop quest {}", bot->GetName(), questId);
|
||||||
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
WorldPacket packet(CMSG_QUESTLOG_REMOVE_QUEST);
|
||||||
|
|||||||
@ -60,7 +60,10 @@ void NewRpgInfo::ChangeToIdle()
|
|||||||
data = Idle{};
|
data = Idle{};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NewRpgInfo::CanChangeTo(NewRpgStatus status) { return true; }
|
bool NewRpgInfo::CanChangeTo(NewRpgStatus)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void NewRpgInfo::Reset()
|
void NewRpgInfo::Reset()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -37,12 +37,14 @@
|
|||||||
#include "Ai/Raid/BlackwingLair/RaidBwlTriggerContext.h"
|
#include "Ai/Raid/BlackwingLair/RaidBwlTriggerContext.h"
|
||||||
#include "Ai/Raid/Karazhan/RaidKarazhanActionContext.h"
|
#include "Ai/Raid/Karazhan/RaidKarazhanActionContext.h"
|
||||||
#include "Ai/Raid/Karazhan/RaidKarazhanTriggerContext.h"
|
#include "Ai/Raid/Karazhan/RaidKarazhanTriggerContext.h"
|
||||||
#include "Ai/Raid/Magtheridon/RaidMagtheridonActionContext.h"
|
|
||||||
#include "Ai/Raid/Magtheridon/RaidMagtheridonTriggerContext.h"
|
|
||||||
#include "Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h"
|
#include "Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h"
|
||||||
#include "Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h"
|
#include "Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h"
|
||||||
|
#include "Ai/Raid/Magtheridon/RaidMagtheridonActionContext.h"
|
||||||
|
#include "Ai/Raid/Magtheridon/RaidMagtheridonTriggerContext.h"
|
||||||
#include "Ai/Raid/SerpentshrineCavern/RaidSSCActionContext.h"
|
#include "Ai/Raid/SerpentshrineCavern/RaidSSCActionContext.h"
|
||||||
#include "Ai/Raid/SerpentshrineCavern/RaidSSCTriggerContext.h"
|
#include "Ai/Raid/SerpentshrineCavern/RaidSSCTriggerContext.h"
|
||||||
|
#include "Ai/Raid/TempestKeep/RaidTempestKeepActionContext.h"
|
||||||
|
#include "Ai/Raid/TempestKeep/RaidTempestKeepTriggerContext.h"
|
||||||
#include "Ai/Raid/EyeOfEternity/RaidEoEActionContext.h"
|
#include "Ai/Raid/EyeOfEternity/RaidEoEActionContext.h"
|
||||||
#include "Ai/Raid/EyeOfEternity/RaidEoETriggerContext.h"
|
#include "Ai/Raid/EyeOfEternity/RaidEoETriggerContext.h"
|
||||||
#include "Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h"
|
#include "Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h"
|
||||||
@ -115,9 +117,10 @@ void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList<Act
|
|||||||
actionContexts.Add(new RaidMcActionContext());
|
actionContexts.Add(new RaidMcActionContext());
|
||||||
actionContexts.Add(new RaidBwlActionContext());
|
actionContexts.Add(new RaidBwlActionContext());
|
||||||
actionContexts.Add(new RaidKarazhanActionContext());
|
actionContexts.Add(new RaidKarazhanActionContext());
|
||||||
actionContexts.Add(new RaidMagtheridonActionContext());
|
|
||||||
actionContexts.Add(new RaidGruulsLairActionContext());
|
actionContexts.Add(new RaidGruulsLairActionContext());
|
||||||
|
actionContexts.Add(new RaidMagtheridonActionContext());
|
||||||
actionContexts.Add(new RaidSSCActionContext());
|
actionContexts.Add(new RaidSSCActionContext());
|
||||||
|
actionContexts.Add(new RaidTempestKeepActionContext());
|
||||||
actionContexts.Add(new RaidOsActionContext());
|
actionContexts.Add(new RaidOsActionContext());
|
||||||
actionContexts.Add(new RaidEoEActionContext());
|
actionContexts.Add(new RaidEoEActionContext());
|
||||||
actionContexts.Add(new RaidVoAActionContext());
|
actionContexts.Add(new RaidVoAActionContext());
|
||||||
@ -150,9 +153,10 @@ void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList<Tr
|
|||||||
triggerContexts.Add(new RaidMcTriggerContext());
|
triggerContexts.Add(new RaidMcTriggerContext());
|
||||||
triggerContexts.Add(new RaidBwlTriggerContext());
|
triggerContexts.Add(new RaidBwlTriggerContext());
|
||||||
triggerContexts.Add(new RaidKarazhanTriggerContext());
|
triggerContexts.Add(new RaidKarazhanTriggerContext());
|
||||||
triggerContexts.Add(new RaidMagtheridonTriggerContext());
|
|
||||||
triggerContexts.Add(new RaidGruulsLairTriggerContext());
|
triggerContexts.Add(new RaidGruulsLairTriggerContext());
|
||||||
|
triggerContexts.Add(new RaidMagtheridonTriggerContext());
|
||||||
triggerContexts.Add(new RaidSSCTriggerContext());
|
triggerContexts.Add(new RaidSSCTriggerContext());
|
||||||
|
triggerContexts.Add(new RaidTempestKeepTriggerContext());
|
||||||
triggerContexts.Add(new RaidOsTriggerContext());
|
triggerContexts.Add(new RaidOsTriggerContext());
|
||||||
triggerContexts.Add(new RaidEoETriggerContext());
|
triggerContexts.Add(new RaidEoETriggerContext());
|
||||||
triggerContexts.Add(new RaidVoATriggerContext());
|
triggerContexts.Add(new RaidVoATriggerContext());
|
||||||
|
|||||||
@ -948,8 +948,6 @@ void PlayerbotFactory::InitPet()
|
|||||||
continue;
|
continue;
|
||||||
if (co->Name.size() > 21)
|
if (co->Name.size() > 21)
|
||||||
continue;
|
continue;
|
||||||
uint32 guid = map->GenerateLowGuid<HighGuid::Pet>();
|
|
||||||
uint32 pet_number = sObjectMgr->GeneratePetNumber();
|
|
||||||
if (bot->GetPetStable() && bot->GetPetStable()->CurrentPet)
|
if (bot->GetPetStable() && bot->GetPetStable()->CurrentPet)
|
||||||
{
|
{
|
||||||
auto petGuid = bot->GetPetStable()->CurrentPet.value(); // To correct the build warnin in VS
|
auto petGuid = bot->GetPetStable()->CurrentPet.value(); // To correct the build warnin in VS
|
||||||
@ -1905,7 +1903,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
if (oldItem)
|
if (oldItem)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Item* newItem = bot->EquipNewItem(dest, bestItemForSlot, true);
|
bot->EquipNewItem(dest, bestItemForSlot, true);
|
||||||
bot->AutoUnequipOffhandIfNeed();
|
bot->AutoUnequipOffhandIfNeed();
|
||||||
// if (newItem)
|
// if (newItem)
|
||||||
// {
|
// {
|
||||||
@ -1936,7 +1934,7 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
(slot != EQUIPMENT_SLOT_RANGED))
|
(slot != EQUIPMENT_SLOT_RANGED))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Item* oldItem = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
if (bot->GetItemByPos(INVENTORY_SLOT_BAG_0, slot) != nullptr)
|
||||||
bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
|
bot->DestroyItem(INVENTORY_SLOT_BAG_0, slot, true);
|
||||||
|
|
||||||
std::vector<uint32>& ids = items[slot];
|
std::vector<uint32>& ids = items[slot];
|
||||||
@ -1973,12 +1971,9 @@ void PlayerbotFactory::InitEquipment(bool incremental, bool second_chance)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Item* newItem = bot->EquipNewItem(dest, bestItemForSlot, true);
|
Item* newItem = bot->EquipNewItem(dest, bestItemForSlot, true);
|
||||||
|
|
||||||
|
bot->EquipNewItem(dest, bestItemForSlot, true);
|
||||||
bot->AutoUnequipOffhandIfNeed();
|
bot->AutoUnequipOffhandIfNeed();
|
||||||
// if (newItem)
|
|
||||||
// {
|
|
||||||
// newItem->AddToWorld();
|
|
||||||
// newItem->AddToUpdateQueueOf(bot);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1991,16 +1986,10 @@ bool PlayerbotFactory::IsDesiredReplacement(Item* item)
|
|||||||
ItemTemplate const* proto = item->GetTemplate();
|
ItemTemplate const* proto = item->GetTemplate();
|
||||||
uint32 requiredLevel = proto->RequiredLevel;
|
uint32 requiredLevel = proto->RequiredLevel;
|
||||||
if (!requiredLevel)
|
if (!requiredLevel)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
// if (!requiredLevel)
|
|
||||||
// {
|
|
||||||
// requiredLevel = sRandomItemMgr.GetMinLevelFromCache(proto->ItemId);
|
|
||||||
// }
|
|
||||||
|
|
||||||
uint32 delta = 1 + (80 - bot->GetLevel()) / 10;
|
uint32 delta = 1 + (80 - bot->GetLevel()) / 10;
|
||||||
return proto->Quality < ITEM_QUALITY_RARE || int32(bot->GetLevel() - requiredLevel) > delta;
|
return proto->Quality < ITEM_QUALITY_RARE || (bot->GetLevel() - requiredLevel) > delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Item* StoreNewItemInInventorySlot(Player* player, uint32 newItemId, uint32 count)
|
inline Item* StoreNewItemInInventorySlot(Player* player, uint32 newItemId, uint32 count)
|
||||||
@ -2010,9 +1999,7 @@ inline Item* StoreNewItemInInventorySlot(Player* player, uint32 newItemId, uint3
|
|||||||
if (msg == EQUIP_ERR_OK)
|
if (msg == EQUIP_ERR_OK)
|
||||||
{
|
{
|
||||||
if (Item* newItem = player->StoreNewItem(vDest, newItemId, true, Item::GenerateItemRandomPropertyId(newItemId)))
|
if (Item* newItem = player->StoreNewItem(vDest, newItemId, true, Item::GenerateItemRandomPropertyId(newItemId)))
|
||||||
{
|
|
||||||
return newItem;
|
return newItem;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -2875,7 +2862,6 @@ void PlayerbotFactory::AddPrevQuests(uint32 questId, std::list<uint32>& questIds
|
|||||||
|
|
||||||
void PlayerbotFactory::InitQuests(std::list<uint32>& questMap, bool withRewardItem)
|
void PlayerbotFactory::InitQuests(std::list<uint32>& questMap, bool withRewardItem)
|
||||||
{
|
{
|
||||||
uint32 count = 0;
|
|
||||||
for (std::list<uint32>::iterator i = questMap.begin(); i != questMap.end(); ++i)
|
for (std::list<uint32>::iterator i = questMap.begin(); i != questMap.end(); ++i)
|
||||||
{
|
{
|
||||||
uint32 questId = *i;
|
uint32 questId = *i;
|
||||||
@ -3280,7 +3266,6 @@ void PlayerbotFactory::InitFood()
|
|||||||
|
|
||||||
void PlayerbotFactory::InitReagents()
|
void PlayerbotFactory::InitReagents()
|
||||||
{
|
{
|
||||||
int specTab = AiFactory::GetPlayerSpecTab(bot);
|
|
||||||
std::vector<std::pair<uint32, uint32>> items;
|
std::vector<std::pair<uint32, uint32>> items;
|
||||||
switch (bot->getClass())
|
switch (bot->getClass())
|
||||||
{
|
{
|
||||||
@ -4336,15 +4321,11 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!item->IsFitToSpellRequirements(spellInfo))
|
if (!item->IsFitToSpellRequirements(spellInfo))
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
uint32 requiredLevel = spellInfo->BaseLevel;
|
uint32 requiredLevel = spellInfo->BaseLevel;
|
||||||
if (requiredLevel > bot->GetLevel())
|
if (requiredLevel > bot->GetLevel())
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// disable next expansion enchantments
|
// disable next expansion enchantments
|
||||||
if (sPlayerbotAIConfig.limitEnchantExpansion && bot->GetLevel() <= 60 && enchantSpell >= 27899)
|
if (sPlayerbotAIConfig.limitEnchantExpansion && bot->GetLevel() <= 60 && enchantSpell >= 27899)
|
||||||
@ -4364,9 +4345,8 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld)
|
|||||||
|
|
||||||
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
|
||||||
if (!enchant || (enchant->slot != PERM_ENCHANTMENT_SLOT && enchant->slot != TEMP_ENCHANTMENT_SLOT))
|
if (!enchant || (enchant->slot != PERM_ENCHANTMENT_SLOT && enchant->slot != TEMP_ENCHANTMENT_SLOT))
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (enchant->requiredSkill &&
|
if (enchant->requiredSkill &&
|
||||||
(!bot->HasSkill(enchant->requiredSkill) ||
|
(!bot->HasSkill(enchant->requiredSkill) ||
|
||||||
(bot->GetSkillValue(enchant->requiredSkill) < enchant->requiredSkillValue)))
|
(bot->GetSkillValue(enchant->requiredSkill) < enchant->requiredSkillValue)))
|
||||||
@ -4374,9 +4354,8 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (enchant->requiredLevel > bot->GetLevel())
|
if (enchant->requiredLevel > bot->GetLevel())
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
float score = calculator.CalculateEnchant(enchant_id);
|
float score = calculator.CalculateEnchant(enchant_id);
|
||||||
if (score >= bestScore)
|
if (score >= bestScore)
|
||||||
{
|
{
|
||||||
@ -4399,11 +4378,9 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld)
|
|||||||
{
|
{
|
||||||
uint8 socketColor = item->GetTemplate()->Socket[enchant_slot - SOCK_ENCHANTMENT_SLOT].Color;
|
uint8 socketColor = item->GetTemplate()->Socket[enchant_slot - SOCK_ENCHANTMENT_SLOT].Color;
|
||||||
if (!socketColor)
|
if (!socketColor)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
int32 enchantIdChosen = -1;
|
int32 enchantIdChosen = -1;
|
||||||
int32 colorChosen;
|
|
||||||
bool jewelersGemChosen;
|
bool jewelersGemChosen;
|
||||||
float bestGemScore = -1;
|
float bestGemScore = -1;
|
||||||
for (uint32& enchantGem : availableGems)
|
for (uint32& enchantGem : availableGems)
|
||||||
@ -4448,7 +4425,6 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destroyOld)
|
|||||||
if (score > bestGemScore)
|
if (score > bestGemScore)
|
||||||
{
|
{
|
||||||
enchantIdChosen = enchant_id;
|
enchantIdChosen = enchant_id;
|
||||||
colorChosen = gemProperties->color;
|
|
||||||
bestGemScore = score;
|
bestGemScore = score;
|
||||||
jewelersGemChosen = isJewelersGem;
|
jewelersGemChosen = isJewelersGem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1556,6 +1556,9 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
case 548:
|
case 548:
|
||||||
strategyName = "ssc"; // Serpentshrine Cavern
|
strategyName = "ssc"; // Serpentshrine Cavern
|
||||||
break;
|
break;
|
||||||
|
case 550:
|
||||||
|
strategyName = "tempestkeep"; // Tempest Keep
|
||||||
|
break;
|
||||||
case 565:
|
case 565:
|
||||||
strategyName = "gruulslair"; // Gruul's Lair
|
strategyName = "gruulslair"; // Gruul's Lair
|
||||||
break;
|
break;
|
||||||
@ -1797,98 +1800,104 @@ bool PlayerbotAI::IsCombo(Player* player)
|
|||||||
|
|
||||||
bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(player, bySpec) && IsDps(player, bySpec); }
|
bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(player, bySpec) && IsDps(player, bySpec); }
|
||||||
|
|
||||||
bool PlayerbotAI::IsAssistHealOfIndex(Player* player, int index, bool ignoreDeadPlayers)
|
bool PlayerbotAI::IsAssistHealOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers)
|
||||||
{
|
{
|
||||||
|
if (!IsHeal(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ignoreDeadPlayers && !player->IsAlive())
|
||||||
|
return false;
|
||||||
|
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int counter = 0;
|
uint8 totalAssistants = 0;
|
||||||
|
uint8 assistantsBeforePlayer = 0;
|
||||||
|
uint8 nonAssistantsBeforePlayer = 0;
|
||||||
|
bool playerFound = false;
|
||||||
|
|
||||||
// First, assistants
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member)
|
if (!member || (ignoreDeadPlayers && !member->IsAlive()) || !IsHeal(member))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ignoreDeadPlayers && !member->IsAlive())
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
continue;
|
|
||||||
|
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsHeal(member))
|
if (isAssistant)
|
||||||
|
totalAssistants++;
|
||||||
|
|
||||||
|
if (member == player)
|
||||||
|
playerFound = true;
|
||||||
|
else if (!playerFound)
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (isAssistant)
|
||||||
return player == member;
|
assistantsBeforePlayer++;
|
||||||
counter++;
|
else
|
||||||
|
nonAssistantsBeforePlayer++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not enough assistants, get non-assistants
|
if (!playerFound)
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
return false;
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ignoreDeadPlayers && !member->IsAlive())
|
// If the player is an assistant, their index is just the number of assistants before them.
|
||||||
continue;
|
// If they are a non-assistant, their index is shifted by the total number of assistants.
|
||||||
|
uint8 playerIndex = group->IsAssistant(player->GetGUID())
|
||||||
|
? assistantsBeforePlayer : (totalAssistants + nonAssistantsBeforePlayer);
|
||||||
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsHeal(member))
|
return playerIndex == index;
|
||||||
{
|
|
||||||
if (index == counter)
|
|
||||||
return player == member;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::IsAssistRangedDpsOfIndex(Player* player, int index, bool ignoreDeadPlayers)
|
bool PlayerbotAI::IsAssistRangedDpsOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers)
|
||||||
{
|
{
|
||||||
|
if (!IsRangedDps(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ignoreDeadPlayers && !player->IsAlive())
|
||||||
|
return false;
|
||||||
|
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int counter = 0;
|
uint8 totalAssistants = 0;
|
||||||
|
uint8 assistantsBeforePlayer = 0;
|
||||||
|
uint8 nonAssistantsBeforePlayer = 0;
|
||||||
|
bool playerFound = false;
|
||||||
|
|
||||||
// First, assistants
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member)
|
if (!member || (ignoreDeadPlayers && !member->IsAlive()) || !IsRangedDps(member))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ignoreDeadPlayers && !member->IsAlive())
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
continue;
|
|
||||||
|
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsRangedDps(member))
|
if (isAssistant)
|
||||||
|
totalAssistants++;
|
||||||
|
|
||||||
|
if (member == player)
|
||||||
|
playerFound = true;
|
||||||
|
else if (!playerFound)
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (isAssistant)
|
||||||
return player == member;
|
assistantsBeforePlayer++;
|
||||||
counter++;
|
else
|
||||||
|
nonAssistantsBeforePlayer++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not enough assistants, get non-assistants
|
if (!playerFound)
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
return false;
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ignoreDeadPlayers && !member->IsAlive())
|
// If the player is an assistant, their index is just the number of assistants before them.
|
||||||
continue;
|
// If they are a non-assistant, their index is shifted by the total number of assistants.
|
||||||
|
uint8 playerIndex = group->IsAssistant(player->GetGUID())
|
||||||
|
? assistantsBeforePlayer : (totalAssistants + nonAssistantsBeforePlayer);
|
||||||
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsRangedDps(member))
|
return playerIndex == index;
|
||||||
{
|
|
||||||
if (index == counter)
|
|
||||||
return player == member;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::HasAggro(Unit* unit)
|
bool PlayerbotAI::HasAggro(Unit* unit)
|
||||||
@ -2226,43 +2235,44 @@ bool PlayerbotAI::IsDps(Player* player, bool bySpec)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::IsMainTank(Player* player)
|
bool PlayerbotAI::IsMainTank(Player* player, bool ignoreMemberFlag)
|
||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return IsTank(player);
|
return IsTank(player);
|
||||||
}
|
|
||||||
|
|
||||||
ObjectGuid mainTank = ObjectGuid();
|
ObjectGuid mainTank = ObjectGuid();
|
||||||
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
|
||||||
|
|
||||||
for (Group::member_citerator itr = slots.begin(); itr != slots.end(); ++itr)
|
// (1) Check for main tank flag (any class or spec)
|
||||||
|
if (!ignoreMemberFlag)
|
||||||
{
|
{
|
||||||
if (itr->flags & MEMBER_FLAG_MAINTANK)
|
Group::MemberSlotList const& slots = group->GetMemberSlots();
|
||||||
|
|
||||||
|
for (Group::member_citerator itr = slots.begin(); itr != slots.end(); ++itr)
|
||||||
{
|
{
|
||||||
mainTank = itr->guid;
|
if (itr->flags & MEMBER_FLAG_MAINTANK)
|
||||||
break;
|
{
|
||||||
|
mainTank = itr->guid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mainTank != ObjectGuid::Empty)
|
||||||
|
return player->GetGUID() == mainTank;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mainTank != ObjectGuid::Empty)
|
// (2) If no main tank flag, return the first tank
|
||||||
{
|
if (!IsTank(player) || !player->IsAlive())
|
||||||
return player->GetGUID() == mainTank;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member)
|
if (!member)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (IsTank(member) && member->IsAlive())
|
if (IsTank(member) && member->IsAlive())
|
||||||
{
|
|
||||||
return player->GetGUID() == member->GetGUID();
|
return player->GetGUID() == member->GetGUID();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -2281,47 +2291,31 @@ bool PlayerbotAI::IsBotMainTank(Player* player)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsMainTank(player))
|
if (IsMainTank(player))
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
return true;
|
||||||
return true; // If no group, consider the bot as main tank
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 botAssistTankIndex = GetAssistTankIndex(player);
|
int32 botAssistTankIndex = GetAssistTankIndex(player);
|
||||||
if (botAssistTankIndex == -1)
|
if (botAssistTankIndex == -1)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||||
{
|
{
|
||||||
Player* member = gref->GetSource();
|
Player* member = gref->GetSource();
|
||||||
if (!member)
|
if (!member)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
int32 memberAssistTankIndex = GetAssistTankIndex(member);
|
int32 memberAssistTankIndex = GetAssistTankIndex(member);
|
||||||
if (memberAssistTankIndex == -1)
|
if (memberAssistTankIndex == -1)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (memberAssistTankIndex == botAssistTankIndex && player == member)
|
if (memberAssistTankIndex == botAssistTankIndex && player == member)
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
if (memberAssistTankIndex < botAssistTankIndex && member->GetSession()->IsBot())
|
if (memberAssistTankIndex < botAssistTankIndex && member->GetSession()->IsBot())
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -2331,73 +2325,76 @@ uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
|||||||
{
|
{
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
uint32 result = 0;
|
uint32 result = 0;
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
|
|
||||||
if (!member)
|
if (!member)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (IsTank(member) && member->IsAlive())
|
if (IsTank(member) && member->IsAlive())
|
||||||
{
|
|
||||||
result++;
|
result++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::IsAssistTank(Player* player) { return IsTank(player) && !IsMainTank(player); }
|
bool PlayerbotAI::IsAssistTank(Player* player)
|
||||||
|
|
||||||
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers)
|
|
||||||
{
|
{
|
||||||
|
return IsTank(player) && !IsMainTank(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers)
|
||||||
|
{
|
||||||
|
if (!IsAssistTank(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ignoreDeadPlayers && !player->IsAlive())
|
||||||
|
return false;
|
||||||
|
|
||||||
Group* group = player->GetGroup();
|
Group* group = player->GetGroup();
|
||||||
if (!group)
|
if (!group)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int counter = 0;
|
uint8 totalAssistants = 0;
|
||||||
|
uint8 assistantsBeforePlayer = 0;
|
||||||
|
uint8 nonAssistantsBeforePlayer = 0;
|
||||||
|
bool playerFound = false;
|
||||||
|
|
||||||
// First, assistants
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (!member)
|
if (!member || (ignoreDeadPlayers && !member->IsAlive()) || !IsAssistTank(member))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (ignoreDeadPlayers && !member->IsAlive())
|
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||||
continue;
|
|
||||||
|
|
||||||
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
if (isAssistant)
|
||||||
|
totalAssistants++;
|
||||||
|
|
||||||
|
if (member == player)
|
||||||
|
playerFound = true;
|
||||||
|
else if (!playerFound)
|
||||||
{
|
{
|
||||||
if (index == counter)
|
if (isAssistant)
|
||||||
return player == member;
|
assistantsBeforePlayer++;
|
||||||
counter++;
|
else
|
||||||
|
nonAssistantsBeforePlayer++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not enough assistants, get non-assistants
|
if (!playerFound)
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
return false;
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (ignoreDeadPlayers && !member->IsAlive())
|
// If the player is an assistant, their index is just the number of assistants before them.
|
||||||
continue;
|
// If they are a non-assistant, their index is shifted by the total number of assistants.
|
||||||
|
uint8 playerIndex = group->IsAssistant(player->GetGUID())
|
||||||
|
? assistantsBeforePlayer : (totalAssistants + nonAssistantsBeforePlayer);
|
||||||
|
|
||||||
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
return playerIndex == index;
|
||||||
{
|
|
||||||
if (index == counter)
|
|
||||||
return player == member;
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace acore
|
namespace acore
|
||||||
|
|||||||
@ -423,12 +423,12 @@ public:
|
|||||||
static bool IsRangedDps(Player* player, bool bySpec = false);
|
static bool IsRangedDps(Player* player, bool bySpec = false);
|
||||||
static bool IsCombo(Player* player);
|
static bool IsCombo(Player* player);
|
||||||
static bool IsBotMainTank(Player* player);
|
static bool IsBotMainTank(Player* player);
|
||||||
static bool IsMainTank(Player* player);
|
static bool IsMainTank(Player* player, bool ignoreMemberFlag = false);
|
||||||
static uint32 GetGroupTankNum(Player* player);
|
static uint32 GetGroupTankNum(Player* player);
|
||||||
static bool IsAssistTank(Player* player);
|
static bool IsAssistTank(Player* player);
|
||||||
static bool IsAssistTankOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
static bool IsAssistTankOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
||||||
static bool IsAssistHealOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
static bool IsAssistHealOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
||||||
static bool IsAssistRangedDpsOfIndex(Player* player, int index, bool ignoreDeadPlayers = false);
|
static bool IsAssistRangedDpsOfIndex(Player* player, uint8 index, bool ignoreDeadPlayers = false);
|
||||||
bool HasAggro(Unit* unit);
|
bool HasAggro(Unit* unit);
|
||||||
static int32 GetAssistTankIndex(Player* player);
|
static int32 GetAssistTankIndex(Player* player);
|
||||||
int32 GetGroupSlotIndex(Player* player);
|
int32 GetGroupSlotIndex(Player* player);
|
||||||
|
|||||||
@ -71,7 +71,6 @@ class PlayerbotLoginQueryHolder : public LoginQueryHolder
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint32 masterAccountId;
|
uint32 masterAccountId;
|
||||||
PlayerbotHolder* playerbotHolder;
|
|
||||||
public:
|
public:
|
||||||
PlayerbotLoginQueryHolder(uint32 masterAccount, uint32 accountId, ObjectGuid guid)
|
PlayerbotLoginQueryHolder(uint32 masterAccount, uint32 accountId, ObjectGuid guid)
|
||||||
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount)
|
: LoginQueryHolder(accountId, guid), masterAccountId(masterAccount)
|
||||||
|
|||||||
@ -994,7 +994,7 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
|
|
||||||
// Arena logic
|
// Arena logic
|
||||||
bool isRated = false;
|
bool isRated = false;
|
||||||
if (uint8 arenaType = BattlegroundMgr::BGArenaType(queueTypeId))
|
if (BattlegroundMgr::BGArenaType(queueTypeId))
|
||||||
{
|
{
|
||||||
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(queueTypeId);
|
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(queueTypeId);
|
||||||
GroupQueueInfo ginfo;
|
GroupQueueInfo ginfo;
|
||||||
@ -1081,7 +1081,7 @@ void RandomPlayerbotMgr::CheckBgQueue()
|
|||||||
BattlegroundData[queueTypeId][bracketId].minLevel = pvpDiff->minLevel;
|
BattlegroundData[queueTypeId][bracketId].minLevel = pvpDiff->minLevel;
|
||||||
BattlegroundData[queueTypeId][bracketId].maxLevel = pvpDiff->maxLevel;
|
BattlegroundData[queueTypeId][bracketId].maxLevel = pvpDiff->maxLevel;
|
||||||
|
|
||||||
if (uint8 arenaType = BattlegroundMgr::BGArenaType(queueTypeId))
|
if (BattlegroundMgr::BGArenaType(queueTypeId))
|
||||||
{
|
{
|
||||||
bool isRated = false;
|
bool isRated = false;
|
||||||
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(queueTypeId);
|
BattlegroundQueue& bgQueue = sBattlegroundMgr->GetBattlegroundQueue(queueTypeId);
|
||||||
@ -1986,13 +1986,9 @@ void RandomPlayerbotMgr::PrepareTeleportCache()
|
|||||||
for (int i = bracket.low; i <= bracket.high; i++)
|
for (int i = bracket.low; i <= bracket.high; i++)
|
||||||
{
|
{
|
||||||
if (forHorde)
|
if (forHorde)
|
||||||
{
|
|
||||||
hordeStarterPerLevelCache[i].push_back(loc);
|
hordeStarterPerLevelCache[i].push_back(loc);
|
||||||
}
|
|
||||||
if (forAlliance)
|
if (forAlliance)
|
||||||
{
|
|
||||||
allianceStarterPerLevelCache[i].push_back(loc);
|
allianceStarterPerLevelCache[i].push_back(loc);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (results->NextRow());
|
} while (results->NextRow());
|
||||||
@ -3146,10 +3142,10 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
uint32 heal = 0;
|
uint32 heal = 0;
|
||||||
uint32 tank = 0;
|
uint32 tank = 0;
|
||||||
uint32 active = 0;
|
uint32 active = 0;
|
||||||
uint32 update = 0;
|
/* uint32 update = 0;
|
||||||
uint32 randomize = 0;
|
uint32 randomize = 0;
|
||||||
uint32 teleport = 0;
|
uint32 teleport = 0;
|
||||||
uint32 changeStrategy = 0;
|
uint32 changeStrategy = 0;*/
|
||||||
uint32 dead = 0;
|
uint32 dead = 0;
|
||||||
uint32 combat = 0;
|
uint32 combat = 0;
|
||||||
// uint32 revive = 0; //not used, line marked for removal.
|
// uint32 revive = 0; //not used, line marked for removal.
|
||||||
@ -3189,7 +3185,7 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
|
|
||||||
if (botAI->AllowActivity())
|
if (botAI->AllowActivity())
|
||||||
++active;
|
++active;
|
||||||
|
/* TODO: Review statistics on rpg merge
|
||||||
if (botAI->GetAiObjectContext()->GetValue<bool>("random bot update")->Get())
|
if (botAI->GetAiObjectContext()->GetValue<bool>("random bot update")->Get())
|
||||||
++update;
|
++update;
|
||||||
|
|
||||||
@ -3202,7 +3198,7 @@ void RandomPlayerbotMgr::PrintStats()
|
|||||||
|
|
||||||
if (!GetEventValue(botId, "change_strategy"))
|
if (!GetEventValue(botId, "change_strategy"))
|
||||||
++changeStrategy;
|
++changeStrategy;
|
||||||
|
*/
|
||||||
if (bot->isDead())
|
if (bot->isDead())
|
||||||
{
|
{
|
||||||
++dead;
|
++dead;
|
||||||
|
|||||||
@ -1832,7 +1832,6 @@ std::vector<uint32> RandomItemMgr::GetUpgradeList(Player* player, std::string sp
|
|||||||
// get old item statWeight
|
// get old item statWeight
|
||||||
uint32 oldStatWeight = 0;
|
uint32 oldStatWeight = 0;
|
||||||
uint32 specId = 0;
|
uint32 specId = 0;
|
||||||
uint32 closestUpgrade = 0;
|
|
||||||
uint32 closestUpgradeWeight = 0;
|
uint32 closestUpgradeWeight = 0;
|
||||||
std::vector<uint32> classspecs;
|
std::vector<uint32> classspecs;
|
||||||
|
|
||||||
@ -1933,7 +1932,6 @@ std::vector<uint32> RandomItemMgr::GetUpgradeList(Player* player, std::string sp
|
|||||||
// pick closest upgrade
|
// pick closest upgrade
|
||||||
if (info.weights[specId] > closestUpgradeWeight)
|
if (info.weights[specId] > closestUpgradeWeight)
|
||||||
{
|
{
|
||||||
closestUpgrade = info.itemId;
|
|
||||||
closestUpgradeWeight = info.weights[specId];
|
closestUpgradeWeight = info.weights[specId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -415,10 +415,10 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
|
useFastFlyMountAtMinLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.UseFastFlyMountAtMinLevel", 70);
|
||||||
|
|
||||||
// stagger bot flightpath takeoff
|
// stagger bot flightpath takeoff
|
||||||
delayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350u);
|
botTaxiDelayMin = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMinMs", 350);
|
||||||
delayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000u);
|
botTaxiDelayMax = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiDelayMaxMs", 5000);
|
||||||
gapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200u);
|
botTaxiGapMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapMs", 200);
|
||||||
gapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100u);
|
botTaxiGapJitterMs = sConfigMgr->GetOption<uint32>("AiPlayerbot.BotTaxiGapJitterMs", 100);
|
||||||
|
|
||||||
LOG_INFO("server.loading", "Loading TalentSpecs...");
|
LOG_INFO("server.loading", "Loading TalentSpecs...");
|
||||||
|
|
||||||
|
|||||||
@ -424,10 +424,10 @@ public:
|
|||||||
uint32 useFastFlyMountAtMinLevel;
|
uint32 useFastFlyMountAtMinLevel;
|
||||||
|
|
||||||
// stagger flightpath takeoff
|
// stagger flightpath takeoff
|
||||||
uint32 delayMin;
|
uint32 botTaxiDelayMin;
|
||||||
uint32 delayMax;
|
uint32 botTaxiDelayMax;
|
||||||
uint32 gapMs;
|
uint32 botTaxiGapMs;
|
||||||
uint32 gapJitterMs;
|
uint32 botTaxiGapJitterMs;
|
||||||
|
|
||||||
std::string const GetTimestampStr();
|
std::string const GetTimestampStr();
|
||||||
bool hasLog(std::string const fileName)
|
bool hasLog(std::string const fileName)
|
||||||
|
|||||||
@ -520,6 +520,8 @@ public:
|
|||||||
|
|
||||||
void AddPlayerbotsSecureLoginScripts();
|
void AddPlayerbotsSecureLoginScripts();
|
||||||
|
|
||||||
|
void AddSC_TempestKeepBotScripts();
|
||||||
|
|
||||||
void AddPlayerbotsScripts()
|
void AddPlayerbotsScripts()
|
||||||
{
|
{
|
||||||
new PlayerbotsDatabaseScript();
|
new PlayerbotsDatabaseScript();
|
||||||
@ -532,4 +534,5 @@ void AddPlayerbotsScripts()
|
|||||||
AddPlayerbotsSecureLoginScripts();
|
AddPlayerbotsSecureLoginScripts();
|
||||||
AddPlayerbotsCommandscripts();
|
AddPlayerbotsCommandscripts();
|
||||||
PlayerBotsGuildValidationScript();
|
PlayerBotsGuildValidationScript();
|
||||||
|
AddSC_TempestKeepBotScripts();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user