mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-21 07:59:25 +02:00
Compare commits
No commits in common. "6db44b5296b259de52618f05cb0b4adc2866d955" and "f00fe15ff120b373edce0cb5d5a7d71d9963cfb5" have entirely different histories.
6db44b5296
...
f00fe15ff1
@ -61,12 +61,27 @@ any impact on performance, you may skip these question. If necessary, a maintain
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Messages to Translate
|
||||||
|
<!--
|
||||||
|
Bot messages have to be translatable, but you don't need to do the translations here. You only need to make sure
|
||||||
|
the message is in a translatable format, and list in the table the message_key and the default English message.
|
||||||
|
Search for GetBotTextOrDefault in the codebase for examples.
|
||||||
|
-->
|
||||||
|
- Does this change add bot messages to translate?
|
||||||
|
- - [ ] No
|
||||||
|
- - [ ] Yes (**list messages in the table**)
|
||||||
|
|
||||||
|
| Message key | Default message |
|
||||||
|
| --------------- | ------------------ |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
|
||||||
## AI Assistance
|
## AI Assistance
|
||||||
<!--
|
<!--
|
||||||
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
|
AI assistance is allowed, but all submitted code must be fully understood, reviewed, and owned by the contributor.
|
||||||
We expect contributors to be honest about what they do and do not understand.
|
We expect contributors to be honest about what they do and do not understand.
|
||||||
-->
|
-->
|
||||||
Was AI assistance used while working on this change?
|
- Was AI assistance used while working on this change?
|
||||||
- - [ ] No
|
- - [ ] No
|
||||||
- - [ ] Yes (**explain below**)
|
- - [ ] Yes (**explain below**)
|
||||||
<!--
|
<!--
|
||||||
@ -77,25 +92,12 @@ If yes, please specify:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
TRANSLATIONS:
|
|
||||||
Anything new that the bots say in chat must be in a translatable format. This is done using GetBotTextOrDefault,
|
|
||||||
which you can search for in the codebase to find examples. Your code needs to have English as the default fallback,
|
|
||||||
while the full translations need to be in an SQL update file. The languages in the file are the nine language
|
|
||||||
options supported by AzerothCore: English, Korean, French, German, Chinese, Taiwanese, Spanish, Spanish Mexico, and
|
|
||||||
Russian. See data/sql/playerbots/updates/2025_12_27_ai_playerbot_fishing_text.sql as an example of a translation SQL
|
|
||||||
update, whose content are called within the codebase at src/strategy/actions/FishingAction.cpp
|
|
||||||
-->
|
|
||||||
|
|
||||||
## Final Checklist
|
## Final Checklist
|
||||||
|
|
||||||
- - [ ] Stability is not compromised.
|
- - [ ] Stability is not compromised.
|
||||||
- - [ ] Performance impact is understood, tested, and acceptable.
|
- - [ ] Performance impact is understood, tested, and acceptable.
|
||||||
- - [ ] Added logic complexity is justified and explained.
|
- - [ ] Added logic complexity is justified and explained.
|
||||||
- - [ ] Any new bot dialogue lines are translated.
|
|
||||||
- - [ ] Documentation updated if needed (Conf comments, WiKi commands).
|
- - [ ] Documentation updated if needed (Conf comments, WiKi commands).
|
||||||
|
|
||||||
## Notes for Reviewers
|
## Notes for Reviewers
|
||||||
<!-- Anything else that's helpful to review or test your pull request. -->
|
<!-- Anything else that's helpful to review or test your pull request. -->
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,104 +0,0 @@
|
|||||||
-- #########################################################
|
|
||||||
-- Playerbots - Add texts for SetWaitForAttackTimeAction
|
|
||||||
-- Localized for all WotLK locales (koKR, frFR, deDE, zhCN,
|
|
||||||
-- zhTW, esES, esMX, ruRU)
|
|
||||||
-- #########################################################
|
|
||||||
|
|
||||||
DELETE FROM ai_playerbot_texts WHERE name IN ('wait_for_attack_provide_time', 'wait_for_attack_invalid_time', 'wait_for_attack_time_set');
|
|
||||||
DELETE FROM ai_playerbot_texts_chance WHERE name IN ('wait_for_attack_provide_time', 'wait_for_attack_invalid_time', 'wait_for_attack_time_set');
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------
|
|
||||||
-- wait_for_attack_provide_time
|
|
||||||
-- Please provide a time to set (in seconds)
|
|
||||||
-- ---------------------------------------------------------
|
|
||||||
INSERT INTO `ai_playerbot_texts`
|
|
||||||
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
|
||||||
VALUES (
|
|
||||||
1740,
|
|
||||||
'wait_for_attack_provide_time',
|
|
||||||
'Please provide a time to set (in seconds)',
|
|
||||||
0, 0,
|
|
||||||
-- koKR
|
|
||||||
'설정할 시간을 입력해 주세요 (초 단위)',
|
|
||||||
-- frFR
|
|
||||||
'Veuillez indiquer un temps à définir (en secondes)',
|
|
||||||
-- deDE
|
|
||||||
'Bitte gib eine Zeit an (in Sekunden)',
|
|
||||||
-- zhCN
|
|
||||||
'请提供要设置的时间(以秒为单位)',
|
|
||||||
-- zhTW
|
|
||||||
'請提供要設定的時間(以秒為單位)',
|
|
||||||
-- esES
|
|
||||||
'Por favor, indica un tiempo a establecer (en segundos)',
|
|
||||||
-- esMX
|
|
||||||
'Por favor, indica un tiempo a establecer (en segundos)',
|
|
||||||
-- ruRU
|
|
||||||
'Пожалуйста, укажите время (в секундах)');
|
|
||||||
|
|
||||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('wait_for_attack_provide_time', 100);
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------
|
|
||||||
-- wait_for_attack_invalid_time
|
|
||||||
-- Please provide valid time to set (in seconds) between 0 and 99
|
|
||||||
-- ---------------------------------------------------------
|
|
||||||
INSERT INTO `ai_playerbot_texts`
|
|
||||||
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
|
||||||
VALUES (
|
|
||||||
1741,
|
|
||||||
'wait_for_attack_invalid_time',
|
|
||||||
'Please provide valid time to set (in seconds) between 0 and 99',
|
|
||||||
0, 0,
|
|
||||||
-- koKR
|
|
||||||
'0에서 99 사이의 유효한 시간을 입력해 주세요 (초 단위)',
|
|
||||||
-- frFR
|
|
||||||
'Veuillez indiquer un temps valide (en secondes) entre 0 et 99',
|
|
||||||
-- deDE
|
|
||||||
'Bitte gib eine gültige Zeit an (in Sekunden) zwischen 0 und 99',
|
|
||||||
-- zhCN
|
|
||||||
'请提供有效的时间(以秒为单位),范围为 0 到 99',
|
|
||||||
-- zhTW
|
|
||||||
'請提供有效的時間(以秒為單位),範圍為 0 到 99',
|
|
||||||
-- esES
|
|
||||||
'Por favor, indica un tiempo válido (en segundos) entre 0 y 99',
|
|
||||||
-- esMX
|
|
||||||
'Por favor, indica un tiempo válido (en segundos) entre 0 y 99',
|
|
||||||
-- ruRU
|
|
||||||
'Пожалуйста, укажите допустимое время (в секундах) от 0 до 99');
|
|
||||||
|
|
||||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('wait_for_attack_invalid_time', 100);
|
|
||||||
|
|
||||||
-- ---------------------------------------------------------
|
|
||||||
-- wait_for_attack_time_set
|
|
||||||
-- Wait for attack time set to %new_time seconds
|
|
||||||
-- ---------------------------------------------------------
|
|
||||||
INSERT INTO `ai_playerbot_texts`
|
|
||||||
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
|
||||||
VALUES (
|
|
||||||
1742,
|
|
||||||
'wait_for_attack_time_set',
|
|
||||||
'Wait for attack time set to %new_time seconds',
|
|
||||||
0, 0,
|
|
||||||
-- koKR
|
|
||||||
'공격 대기 시간이 %new_time초로 설정되었습니다',
|
|
||||||
-- frFR
|
|
||||||
'Temps d''attente avant l''attaque défini à %new_time secondes',
|
|
||||||
-- deDE
|
|
||||||
'Wartezeit vor dem Angriff auf %new_time Sekunden gesetzt',
|
|
||||||
-- zhCN
|
|
||||||
'等待攻击时间已设置为 %new_time 秒',
|
|
||||||
-- zhTW
|
|
||||||
'等待攻擊時間已設定為 %new_time 秒',
|
|
||||||
-- esES
|
|
||||||
'Tiempo de espera para atacar establecido en %new_time segundos',
|
|
||||||
-- esMX
|
|
||||||
'Tiempo de espera para atacar establecido en %new_time segundos',
|
|
||||||
-- ruRU
|
|
||||||
'Время ожидания атаки установлено на %new_time секунд');
|
|
||||||
|
|
||||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('wait_for_attack_time_set', 100);
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
-- Translations for additional logout related messages
|
|
||||||
DELETE FROM ai_playerbot_texts WHERE name IN ('bot_not_your_master', 'bot_rndbot_no_logout');
|
|
||||||
DELETE FROM ai_playerbot_texts_chance WHERE name IN ('bot_not_your_master', 'bot_rndbot_no_logout');
|
|
||||||
|
|
||||||
INSERT INTO `ai_playerbot_texts`
|
|
||||||
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
|
||||||
VALUES (
|
|
||||||
1740,
|
|
||||||
'bot_not_your_master',
|
|
||||||
"You are not my master!",
|
|
||||||
0, 0,
|
|
||||||
-- koKR
|
|
||||||
"당신은 내 주인이 아닙니다!",
|
|
||||||
-- frFR
|
|
||||||
"Tu n'es pas mon maître !",
|
|
||||||
-- deDE
|
|
||||||
"Du bist nicht mein Meister!",
|
|
||||||
-- zhCN
|
|
||||||
"你不是我的主人!",
|
|
||||||
-- zhTW
|
|
||||||
"你不是我的主人!",
|
|
||||||
-- esES
|
|
||||||
"¡No eres mi amo!",
|
|
||||||
-- esMX
|
|
||||||
"¡No eres mi amo!",
|
|
||||||
-- ruRU
|
|
||||||
"Ты не мой хозяин!");
|
|
||||||
|
|
||||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('bot_not_your_master', 100);
|
|
||||||
|
|
||||||
INSERT INTO `ai_playerbot_texts`
|
|
||||||
(`id`, `name`, `text`, `say_type`, `reply_type`,
|
|
||||||
`text_loc1`, `text_loc2`, `text_loc3`, `text_loc4`,
|
|
||||||
`text_loc5`, `text_loc6`, `text_loc7`, `text_loc8`)
|
|
||||||
VALUES (
|
|
||||||
1741,
|
|
||||||
'bot_rndbot_no_logout',
|
|
||||||
"You can't command me to logout!",
|
|
||||||
0, 0,
|
|
||||||
-- koKR
|
|
||||||
"당신은 나에게 로그아웃을 명령할 수 없습니다!",
|
|
||||||
-- frFR
|
|
||||||
"Tu ne peux pas m'ordonner de me déconnecter !",
|
|
||||||
-- deDE
|
|
||||||
"Du kannst mir nicht befehlen, mich auszuloggen!",
|
|
||||||
-- zhCN
|
|
||||||
"你不能命令我下线!",
|
|
||||||
-- zhTW
|
|
||||||
"你不能命令我登出!",
|
|
||||||
-- esES
|
|
||||||
"¡No puedes ordenarme que cierre sesión!",
|
|
||||||
-- esMX
|
|
||||||
"¡No puedes ordenarme que cierre sesión!",
|
|
||||||
-- ruRU
|
|
||||||
"Ты не можешь приказать мне выйти из игры!");
|
|
||||||
|
|
||||||
INSERT INTO ai_playerbot_texts_chance (name, probability) VALUES ('bot_rndbot_no_logout', 100);
|
|
||||||
@ -65,7 +65,6 @@
|
|||||||
#include "NewRpgAction.h"
|
#include "NewRpgAction.h"
|
||||||
#include "FishingAction.h"
|
#include "FishingAction.h"
|
||||||
#include "CancelChannelAction.h"
|
#include "CancelChannelAction.h"
|
||||||
#include "WaitForAttackAction.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
@ -165,7 +164,6 @@ public:
|
|||||||
creators["blood fury"] = &ActionContext::blood_fury;
|
creators["blood fury"] = &ActionContext::blood_fury;
|
||||||
creators["berserking"] = &ActionContext::berserking;
|
creators["berserking"] = &ActionContext::berserking;
|
||||||
creators["every man for himself"] = &ActionContext::every_man_for_himself;
|
creators["every man for himself"] = &ActionContext::every_man_for_himself;
|
||||||
creators["will of the forsaken"] = &ActionContext::will_of_the_forsaken;
|
|
||||||
creators["use trinket"] = &ActionContext::use_trinket;
|
creators["use trinket"] = &ActionContext::use_trinket;
|
||||||
creators["auto talents"] = &ActionContext::auto_talents;
|
creators["auto talents"] = &ActionContext::auto_talents;
|
||||||
creators["auto share quest"] = &ActionContext::auto_share_quest;
|
creators["auto share quest"] = &ActionContext::auto_share_quest;
|
||||||
@ -265,7 +263,6 @@ public:
|
|||||||
creators["new rpg wander npc"] = &ActionContext::new_rpg_wander_npc;
|
creators["new rpg wander npc"] = &ActionContext::new_rpg_wander_npc;
|
||||||
creators["new rpg do quest"] = &ActionContext::new_rpg_do_quest;
|
creators["new rpg do quest"] = &ActionContext::new_rpg_do_quest;
|
||||||
creators["new rpg travel flight"] = &ActionContext::new_rpg_travel_flight;
|
creators["new rpg travel flight"] = &ActionContext::new_rpg_travel_flight;
|
||||||
creators["wait for attack keep safe distance"] = &ActionContext::wait_for_attack_keep_safe_distance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -362,7 +359,6 @@ private:
|
|||||||
static Action* blood_fury(PlayerbotAI* botAI) { return new CastBloodFuryAction(botAI); }
|
static Action* blood_fury(PlayerbotAI* botAI) { return new CastBloodFuryAction(botAI); }
|
||||||
static Action* berserking(PlayerbotAI* botAI) { return new CastBerserkingAction(botAI); }
|
static Action* berserking(PlayerbotAI* botAI) { return new CastBerserkingAction(botAI); }
|
||||||
static Action* every_man_for_himself(PlayerbotAI* botAI) { return new CastEveryManForHimselfAction(botAI); }
|
static Action* every_man_for_himself(PlayerbotAI* botAI) { return new CastEveryManForHimselfAction(botAI); }
|
||||||
static Action* will_of_the_forsaken(PlayerbotAI* botAI) { return new CastWillOfTheForsakenAction(botAI); }
|
|
||||||
static Action* use_trinket(PlayerbotAI* botAI) { return new UseTrinketAction(botAI); }
|
static Action* use_trinket(PlayerbotAI* botAI) { return new UseTrinketAction(botAI); }
|
||||||
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
|
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
|
||||||
static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); }
|
static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); }
|
||||||
@ -462,7 +458,6 @@ private:
|
|||||||
static Action* new_rpg_wander_npc(PlayerbotAI* ai) { return new NewRpgWanderNpcAction(ai); }
|
static Action* new_rpg_wander_npc(PlayerbotAI* ai) { return new NewRpgWanderNpcAction(ai); }
|
||||||
static Action* new_rpg_do_quest(PlayerbotAI* ai) { return new NewRpgDoQuestAction(ai); }
|
static Action* new_rpg_do_quest(PlayerbotAI* ai) { return new NewRpgDoQuestAction(ai); }
|
||||||
static Action* new_rpg_travel_flight(PlayerbotAI* ai) { return new NewRpgTravelFlightAction(ai); }
|
static Action* new_rpg_travel_flight(PlayerbotAI* ai) { return new NewRpgTravelFlightAction(ai); }
|
||||||
static Action* wait_for_attack_keep_safe_distance(PlayerbotAI* ai) { return new WaitForAttackKeepSafeDistanceAction(ai); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -14,7 +14,6 @@
|
|||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "WaitForAttackStrategy.h"
|
|
||||||
|
|
||||||
bool AttackAction::Execute(Event /*event*/)
|
bool AttackAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
@ -165,7 +164,6 @@ bool AttackAction::Attack(Unit* target, bool /*with_pet*/ /*true*/)
|
|||||||
|
|
||||||
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
||||||
|
|
||||||
if (!WaitForAttackStrategy::ShouldWait(botAI))
|
|
||||||
bot->Attack(target, shouldMelee);
|
bot->Attack(target, shouldMelee);
|
||||||
/* prevent pet dead immediately in group */
|
/* prevent pet dead immediately in group */
|
||||||
// if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat())
|
// if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat())
|
||||||
|
|||||||
@ -143,28 +143,3 @@ namespace ai::buff
|
|||||||
return castName;
|
return castName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ai::spell
|
|
||||||
{
|
|
||||||
bool HasSpellOrCategoryCooldown(Player* bot, uint32 spellId)
|
|
||||||
{
|
|
||||||
if (bot->HasSpellCooldown(spellId))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
|
||||||
if (!spellInfo)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32 category = spellInfo->GetCategory();
|
|
||||||
if (!category)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (auto const& [cooldownSpellId, cooldown] : bot->GetSpellCooldownMap())
|
|
||||||
{
|
|
||||||
if (cooldown.category == category && bot->GetSpellCooldownDelay(cooldownSpellId) > 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
63
src/Ai/Base/Actions/GenericBuffUtils.h
Normal file
63
src/Ai/Base/Actions/GenericBuffUtils.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
||||||
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Group.h"
|
||||||
|
#include "Chat.h"
|
||||||
|
#include "Language.h"
|
||||||
|
|
||||||
|
class Player;
|
||||||
|
class PlayerbotAI;
|
||||||
|
|
||||||
|
namespace ai::buff
|
||||||
|
{
|
||||||
|
|
||||||
|
// Build an aura qualifier "single + greater" to avoid double-buffing
|
||||||
|
std::string MakeAuraQualifierForBuff(std::string const& name);
|
||||||
|
|
||||||
|
// Returns the group spell name for a given single-target buff.
|
||||||
|
// If no group equivalent exists, returns "".
|
||||||
|
std::string GroupVariantFor(std::string const& name);
|
||||||
|
|
||||||
|
// Checks if the bot has the required reagents to cast a spell (by its spellId).
|
||||||
|
// Returns false if the spellId is invalid.
|
||||||
|
bool HasRequiredReagents(Player* bot, uint32 spellId);
|
||||||
|
|
||||||
|
// Applies the "switch to group buff" policy if: the bot is in a group of size x+,
|
||||||
|
// the group variant is known/useful, and reagents are available. Otherwise, returns baseName.
|
||||||
|
// If announceOnMissing == true and reagents are missing, calls the 'announce' callback
|
||||||
|
// (if provided) to notify the party/raid.
|
||||||
|
std::string UpgradeToGroupIfAppropriate(
|
||||||
|
Player* bot,
|
||||||
|
PlayerbotAI* botAI,
|
||||||
|
std::string const& baseName,
|
||||||
|
bool announceOnMissing = false,
|
||||||
|
std::function<void(std::string const&)> announce = {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ai::chat {
|
||||||
|
inline std::function<void(std::string const&)> MakeGroupAnnouncer(Player* me)
|
||||||
|
{
|
||||||
|
return [me](std::string const& msg)
|
||||||
|
{
|
||||||
|
if (Group* g = me->GetGroup())
|
||||||
|
{
|
||||||
|
WorldPacket data;
|
||||||
|
ChatMsg type = g->isRaidGroup() ? CHAT_MSG_RAID : CHAT_MSG_PARTY;
|
||||||
|
ChatHandler::BuildChatPacket(data, type, LANG_UNIVERSAL, me, /*receiver=*/nullptr, msg.c_str());
|
||||||
|
g->BroadcastPacket(&data, true, -1, me->GetGUID());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me->Say(msg, LANG_UNIVERSAL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,11 +17,10 @@
|
|||||||
#include "WorldPacket.h"
|
#include "WorldPacket.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "Chat.h"
|
#include "Chat.h"
|
||||||
#include "Ai/Base/Util/GenericBuffUtils.h"
|
#include "GenericBuffUtils.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
|
||||||
using ai::buff::MakeAuraQualifierForBuff;
|
using ai::buff::MakeAuraQualifierForBuff;
|
||||||
using ai::spell::HasSpellOrCategoryCooldown;
|
|
||||||
|
|
||||||
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
|
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
|
||||||
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell)
|
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell)
|
||||||
@ -321,7 +320,7 @@ bool CastEveryManForHimselfAction::isPossible()
|
|||||||
if (!bot->HasSpell(spellId))
|
if (!bot->HasSpell(spellId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (HasSpellOrCategoryCooldown(bot, spellId))
|
if (bot->HasSpellCooldown(spellId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -329,36 +328,11 @@ bool CastEveryManForHimselfAction::isPossible()
|
|||||||
|
|
||||||
bool CastEveryManForHimselfAction::isUseful()
|
bool CastEveryManForHimselfAction::isUseful()
|
||||||
{
|
{
|
||||||
return (bot->HasAuraType(SPELL_AURA_MOD_STUN) ||
|
return bot->HasAuraType(SPELL_AURA_MOD_STUN) ||
|
||||||
bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
||||||
bot->HasAuraType(SPELL_AURA_MOD_ROOT) ||
|
bot->HasAuraType(SPELL_AURA_MOD_ROOT) ||
|
||||||
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) ||
|
bot->HasAuraType(SPELL_AURA_MOD_CONFUSE) ||
|
||||||
bot->HasAuraType(SPELL_AURA_MOD_CHARM))
|
bot->HasAuraType(SPELL_AURA_MOD_CHARM);
|
||||||
&& CastSpellAction::isUseful();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CastWillOfTheForsakenAction::isPossible()
|
|
||||||
{
|
|
||||||
uint32 spellId = AI_VALUE2(uint32, "spell id", spell);
|
|
||||||
if (!spellId)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!bot->HasSpell(spellId))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (HasSpellOrCategoryCooldown(bot, spellId))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CastWillOfTheForsakenAction::isUseful()
|
|
||||||
{
|
|
||||||
return (bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
|
||||||
bot->HasAuraType(SPELL_AURA_MOD_CHARM) ||
|
|
||||||
bot->HasAuraType(SPELL_AURA_AOE_CHARM) ||
|
|
||||||
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP))
|
|
||||||
&& CastSpellAction::isUseful();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UseTrinketAction::Execute(Event /*event*/)
|
bool UseTrinketAction::Execute(Event /*event*/)
|
||||||
|
|||||||
@ -294,16 +294,6 @@ public:
|
|||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastWillOfTheForsakenAction : public CastSpellAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CastWillOfTheForsakenAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "will of the forsaken") {}
|
|
||||||
|
|
||||||
std::string const GetTargetName() override { return "self target"; }
|
|
||||||
bool isPossible() override;
|
|
||||||
bool isUseful() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UseTrinketAction : public Action
|
class UseTrinketAction : public Action
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -1,166 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WaitForAttackAction.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cctype>
|
|
||||||
|
|
||||||
#include "ObjectAccessor.h"
|
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
#include "PlayerbotTextMgr.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "ServerFacade.h"
|
|
||||||
#include "TravelMgr.h"
|
|
||||||
#include "WaitForAttackStrategy.h"
|
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
WorldPosition GetBestPoint(AiObjectContext* context, Player* bot, Unit* target,
|
|
||||||
float minDistance, float maxDistance)
|
|
||||||
{
|
|
||||||
WorldPosition botPosition(bot);
|
|
||||||
WorldPosition targetPosition(target);
|
|
||||||
|
|
||||||
int8 startDir = urand(0, 1) * 2 - 1;
|
|
||||||
float const radiansIncrement = (5.0f / 180.0f) * static_cast<float>(M_PI);
|
|
||||||
float startAngle = targetPosition.getAngleTo(botPosition) +
|
|
||||||
frand(0.0f, radiansIncrement) * startDir;
|
|
||||||
float distance = frand(minDistance, maxDistance);
|
|
||||||
|
|
||||||
GuidVector enemies = AI_VALUE(GuidVector, "possible targets no los");
|
|
||||||
|
|
||||||
for (float tryAngle = 0.0f; tryAngle < static_cast<float>(M_PI); tryAngle += radiansIncrement)
|
|
||||||
{
|
|
||||||
for (int8 tryDir = -1; tryAngle && tryDir < 1; tryDir += 2)
|
|
||||||
{
|
|
||||||
float pointAngle = startAngle + tryAngle * startDir * tryDir;
|
|
||||||
|
|
||||||
float x = targetPosition.GetPositionX() + distance * cos(pointAngle);
|
|
||||||
float y = targetPosition.GetPositionY() + distance * sin(pointAngle);
|
|
||||||
float z = targetPosition.GetPositionZ() + 1.0f;
|
|
||||||
|
|
||||||
WorldPosition point(targetPosition.GetMapId(), x, y, z);
|
|
||||||
point.setZ(point.getHeight());
|
|
||||||
|
|
||||||
// Check line of sight to target
|
|
||||||
if (!target->IsWithinLOS(point.GetPositionX(), point.GetPositionY(),
|
|
||||||
point.GetPositionZ() + bot->GetCollisionHeight()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check if enemies are close to this point
|
|
||||||
bool enemyClose = false;
|
|
||||||
for (ObjectGuid const& enemyGUID : enemies)
|
|
||||||
{
|
|
||||||
Unit* enemy = ObjectAccessor::GetUnit(*bot, enemyGUID);
|
|
||||||
if (enemy && enemy->IsWithinLOSInMap(bot) && enemy->IsHostileTo(bot))
|
|
||||||
{
|
|
||||||
float enemyAttackRange = enemy->GetCombatReach() + ATTACK_DISTANCE;
|
|
||||||
WorldPosition enemyPos(enemy);
|
|
||||||
if (enemyPos.sqDistance(point) <= (enemyAttackRange * enemyAttackRange))
|
|
||||||
{
|
|
||||||
enemyClose = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enemyClose)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check if bot can path to this point
|
|
||||||
if (!botPosition.canPathTo(point, bot))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return point;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return botPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool WaitForAttackKeepSafeDistanceAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
|
||||||
|
|
||||||
// If our target is moving towards a stationary unit, use that unit as anchor
|
|
||||||
if (target && !target->IsStopped())
|
|
||||||
{
|
|
||||||
ObjectGuid targetGuid = target->GetTarget();
|
|
||||||
if (targetGuid)
|
|
||||||
{
|
|
||||||
Unit* targetsTarget = ObjectAccessor::GetUnit(*target, targetGuid);
|
|
||||||
if (targetsTarget && targetsTarget->IsStopped())
|
|
||||||
target = targetsTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target && target->IsAlive())
|
|
||||||
{
|
|
||||||
float safeDistance = std::max(
|
|
||||||
target->GetCombatReach() + ATTACK_DISTANCE,
|
|
||||||
WaitForAttackStrategy::GetSafeDistance());
|
|
||||||
float safeDistanceThreshold = WaitForAttackStrategy::GetSafeDistanceThreshold();
|
|
||||||
|
|
||||||
WorldPosition bestPoint = GetBestPoint(context, bot, target,
|
|
||||||
safeDistance - safeDistanceThreshold, safeDistance);
|
|
||||||
|
|
||||||
if (bestPoint)
|
|
||||||
return MoveTo(bestPoint.GetMapId(), bestPoint.GetPositionX(),
|
|
||||||
bestPoint.GetPositionY(), bestPoint.GetPositionZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SetWaitForAttackTimeAction::Execute(Event event)
|
|
||||||
{
|
|
||||||
std::string newTimeStr = event.getParam();
|
|
||||||
|
|
||||||
if (newTimeStr.empty())
|
|
||||||
{
|
|
||||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"wait_for_attack_provide_time",
|
|
||||||
"Please provide a time to set (in seconds)",
|
|
||||||
std::map<std::string, std::string>());
|
|
||||||
botAI->TellMaster(text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!std::all_of(newTimeStr.begin(), newTimeStr.end(), ::isdigit))
|
|
||||||
{
|
|
||||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"wait_for_attack_invalid_time",
|
|
||||||
"Please provide valid time to set (in seconds) between 0 and 99",
|
|
||||||
std::map<std::string, std::string>());
|
|
||||||
botAI->TellMaster(text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int newTime = std::stoi(newTimeStr);
|
|
||||||
if (newTime < 0 || newTime > 99)
|
|
||||||
{
|
|
||||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"wait_for_attack_invalid_time",
|
|
||||||
"Please provide valid time to set (in seconds) between 0 and 99",
|
|
||||||
std::map<std::string, std::string>());
|
|
||||||
botAI->TellMaster(text);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->GetValue<uint8>("wait for attack time")->Set(static_cast<uint8>(newTime));
|
|
||||||
|
|
||||||
std::map<std::string, std::string> placeholders;
|
|
||||||
placeholders["%new_time"] = std::to_string(newTime);
|
|
||||||
std::string const text = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"wait_for_attack_time_set",
|
|
||||||
"Wait for attack time set to %new_time seconds",
|
|
||||||
placeholders);
|
|
||||||
botAI->TellMaster(text);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_WAITFORATTACKACTION_H
|
|
||||||
#define _PLAYERBOT_WAITFORATTACKACTION_H
|
|
||||||
|
|
||||||
#include "MovementActions.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
class WaitForAttackKeepSafeDistanceAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WaitForAttackKeepSafeDistanceAction(PlayerbotAI* botAI)
|
|
||||||
: MovementAction(botAI, "wait for attack keep safe distance") {}
|
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SetWaitForAttackTimeAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SetWaitForAttackTimeAction(PlayerbotAI* botAI)
|
|
||||||
: Action(botAI, "wait for attack time") {}
|
|
||||||
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -84,7 +84,6 @@
|
|||||||
#include "TellGlyphsAction.h"
|
#include "TellGlyphsAction.h"
|
||||||
#include "EquipGlyphsAction.h"
|
#include "EquipGlyphsAction.h"
|
||||||
#include "PetsAction.h"
|
#include "PetsAction.h"
|
||||||
#include "WaitForAttackAction.h"
|
|
||||||
|
|
||||||
class ChatActionContext : public NamedObjectContext<Action>
|
class ChatActionContext : public NamedObjectContext<Action>
|
||||||
{
|
{
|
||||||
@ -200,7 +199,6 @@ public:
|
|||||||
creators["pet"] = &ChatActionContext::pet;
|
creators["pet"] = &ChatActionContext::pet;
|
||||||
creators["pet attack"] = &ChatActionContext::pet_attack;
|
creators["pet attack"] = &ChatActionContext::pet_attack;
|
||||||
creators["roll"] = &ChatActionContext::roll_action;
|
creators["roll"] = &ChatActionContext::roll_action;
|
||||||
creators["wait for attack time"] = &ChatActionContext::wait_for_attack_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -313,7 +311,6 @@ private:
|
|||||||
static Action* pet(PlayerbotAI* botAI) { return new PetsAction(botAI); }
|
static Action* pet(PlayerbotAI* botAI) { return new PetsAction(botAI); }
|
||||||
static Action* pet_attack(PlayerbotAI* botAI) { return new PetsAction(botAI, "attack"); }
|
static Action* pet_attack(PlayerbotAI* botAI) { return new PetsAction(botAI, "attack"); }
|
||||||
static Action* roll_action(PlayerbotAI* botAI) { return new RollAction(botAI); }
|
static Action* roll_action(PlayerbotAI* botAI) { return new RollAction(botAI); }
|
||||||
static Action* wait_for_attack_time(PlayerbotAI* botAI) { return new SetWaitForAttackTimeAction(botAI); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -145,7 +145,6 @@ public:
|
|||||||
creators["pet"] = &ChatTriggerContext::pet;
|
creators["pet"] = &ChatTriggerContext::pet;
|
||||||
creators["pet attack"] = &ChatTriggerContext::pet_attack;
|
creators["pet attack"] = &ChatTriggerContext::pet_attack;
|
||||||
creators["roll"] = &ChatTriggerContext::roll_action;
|
creators["roll"] = &ChatTriggerContext::roll_action;
|
||||||
creators["wait for attack time"] = &ChatTriggerContext::wait_for_attack_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -270,7 +269,6 @@ private:
|
|||||||
static Trigger* pet(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pet"); }
|
static Trigger* pet(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pet"); }
|
||||||
static Trigger* pet_attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pet attack"); }
|
static Trigger* pet_attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "pet attack"); }
|
||||||
static Trigger* roll_action(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "roll"); }
|
static Trigger* roll_action(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "roll"); }
|
||||||
static Trigger* wait_for_attack_time(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "wait for attack time"); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -199,5 +199,4 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
|
|||||||
supported.push_back("glyph equip"); // Added for custom Glyphs
|
supported.push_back("glyph equip"); // Added for custom Glyphs
|
||||||
supported.push_back("pet");
|
supported.push_back("pet");
|
||||||
supported.push_back("pet attack");
|
supported.push_back("pet attack");
|
||||||
supported.push_back("wait for attack time");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,9 +37,6 @@ void RacialsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"loss of control", { NextAction("every man for himself", ACTION_EMERGENCY + 1) }));
|
"loss of control", { NextAction("every man for himself", ACTION_EMERGENCY + 1) }));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"fear charm sleep", { NextAction("will of the forsaken", ACTION_EMERGENCY + 1) }));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RacialsStrategy::RacialsStrategy(PlayerbotAI* botAI) : Strategy(botAI)
|
RacialsStrategy::RacialsStrategy(PlayerbotAI* botAI) : Strategy(botAI)
|
||||||
|
|||||||
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WaitForAttackStrategy.h"
|
|
||||||
|
|
||||||
#include "Action.h"
|
|
||||||
#include "PlayerbotAI.h"
|
|
||||||
#include "PlayerbotAIConfig.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "Strategy.h"
|
|
||||||
|
|
||||||
void WaitForAttackStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
triggers.push_back(new TriggerNode(
|
|
||||||
"wait for attack safe distance",
|
|
||||||
{
|
|
||||||
NextAction("wait for attack keep safe distance", ACTION_RAID)
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitForAttackStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|
||||||
{
|
|
||||||
multipliers.push_back(new WaitForAttackMultiplier(botAI));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WaitForAttackStrategy::ShouldWait(PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
if (botAI->HasStrategy("wait for attack", BOT_STATE_COMBAT))
|
|
||||||
{
|
|
||||||
Player* bot = botAI->GetBot();
|
|
||||||
if (bot->GetGroup() && botAI->HasRealPlayerMaster())
|
|
||||||
{
|
|
||||||
// Don't wait if the current target is an enemy player
|
|
||||||
Unit* target = botAI->GetAiObjectContext()->GetValue<Unit*>("current target")->Get();
|
|
||||||
if (target && target->IsPlayer())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
AiObjectContext* context = botAI->GetAiObjectContext();
|
|
||||||
time_t combatStartTime = context->GetValue<time_t>("combat start time")->Get();
|
|
||||||
|
|
||||||
if (bot->IsInCombat())
|
|
||||||
{
|
|
||||||
if (combatStartTime == 0)
|
|
||||||
{
|
|
||||||
combatStartTime = time(nullptr);
|
|
||||||
context->GetValue<time_t>("combat start time")->Set(combatStartTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t elapsedTime = time(nullptr) - combatStartTime;
|
|
||||||
return elapsedTime < GetWaitTime(botAI);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (combatStartTime != 0)
|
|
||||||
context->GetValue<time_t>("combat start time")->Set(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 WaitForAttackStrategy::GetWaitTime(PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
return botAI->GetAiObjectContext()->GetValue<uint8>("wait for attack time")->Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
float WaitForAttackStrategy::GetSafeDistance()
|
|
||||||
{
|
|
||||||
return sPlayerbotAIConfig.spellDistance;
|
|
||||||
}
|
|
||||||
|
|
||||||
float WaitForAttackMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
std::string const& actionName = action->getName();
|
|
||||||
|
|
||||||
if (actionName != "wait for attack keep safe distance" &&
|
|
||||||
actionName != "dps assist" &&
|
|
||||||
actionName != "set facing" &&
|
|
||||||
actionName != "pull my target" &&
|
|
||||||
actionName != "pull rti target" &&
|
|
||||||
actionName != "pull start" &&
|
|
||||||
actionName != "pull action" &&
|
|
||||||
actionName != "pull end")
|
|
||||||
{
|
|
||||||
return WaitForAttackStrategy::ShouldWait(botAI) ? 0.0f : 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_WAITFORATTACKSTRATEGY_H
|
|
||||||
#define _PLAYERBOT_WAITFORATTACKSTRATEGY_H
|
|
||||||
|
|
||||||
#include "Multiplier.h"
|
|
||||||
#include "Strategy.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
class WaitForAttackStrategy : public Strategy
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WaitForAttackStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::string const getName() override { return "wait for attack"; }
|
|
||||||
|
|
||||||
static bool ShouldWait(PlayerbotAI* botAI);
|
|
||||||
static uint8 GetWaitTime(PlayerbotAI* botAI);
|
|
||||||
static float GetSafeDistance();
|
|
||||||
static float GetSafeDistanceThreshold() { return 2.5f; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
|
||||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WaitForAttackMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WaitForAttackMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "wait for attack") {}
|
|
||||||
|
|
||||||
float GetValue(Action* action) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -50,7 +50,6 @@
|
|||||||
#include "TravelStrategy.h"
|
#include "TravelStrategy.h"
|
||||||
#include "UseFoodStrategy.h"
|
#include "UseFoodStrategy.h"
|
||||||
#include "UsePotionsStrategy.h"
|
#include "UsePotionsStrategy.h"
|
||||||
#include "WaitForAttackStrategy.h"
|
|
||||||
#include "WorldPacketHandlerStrategy.h"
|
#include "WorldPacketHandlerStrategy.h"
|
||||||
|
|
||||||
class StrategyContext : public NamedObjectContext<Strategy>
|
class StrategyContext : public NamedObjectContext<Strategy>
|
||||||
@ -125,7 +124,6 @@ public:
|
|||||||
creators["worldbuff"] = &StrategyContext::world_buff;
|
creators["worldbuff"] = &StrategyContext::world_buff;
|
||||||
creators["use bobber"] = &StrategyContext::bobber_strategy;
|
creators["use bobber"] = &StrategyContext::bobber_strategy;
|
||||||
creators["master fishing"] = &StrategyContext::master_fishing;
|
creators["master fishing"] = &StrategyContext::master_fishing;
|
||||||
creators["wait for attack"] = &StrategyContext::wait_for_attack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -197,7 +195,6 @@ private:
|
|||||||
static Strategy* world_buff(PlayerbotAI* botAI) { return new WorldBuffStrategy(botAI); }
|
static Strategy* world_buff(PlayerbotAI* botAI) { return new WorldBuffStrategy(botAI); }
|
||||||
static Strategy* bobber_strategy(PlayerbotAI* botAI) { return new UseBobberStrategy(botAI); }
|
static Strategy* bobber_strategy(PlayerbotAI* botAI) { return new UseBobberStrategy(botAI); }
|
||||||
static Strategy* master_fishing(PlayerbotAI* botAI) { return new MasterFishingStrategy(botAI); }
|
static Strategy* master_fishing(PlayerbotAI* botAI) { return new MasterFishingStrategy(botAI); }
|
||||||
static Strategy* wait_for_attack(PlayerbotAI* botAI) { return new WaitForAttackStrategy(botAI); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MovementStrategyContext : public NamedObjectContext<Strategy>
|
class MovementStrategyContext : public NamedObjectContext<Strategy>
|
||||||
|
|||||||
@ -473,14 +473,6 @@ bool LossOfControlTrigger::IsActive()
|
|||||||
bot->HasAuraType(SPELL_AURA_MOD_CHARM);
|
bot->HasAuraType(SPELL_AURA_MOD_CHARM);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FearCharmSleepTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return bot->HasAuraType(SPELL_AURA_MOD_FEAR) ||
|
|
||||||
bot->HasAuraType(SPELL_AURA_MOD_CHARM) ||
|
|
||||||
bot->HasAuraType(SPELL_AURA_AOE_CHARM) ||
|
|
||||||
bot->HasAuraWithMechanic(1 << MECHANIC_SLEEP);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasAuraStackTrigger::IsActive()
|
bool HasAuraStackTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, stack);
|
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, stack);
|
||||||
|
|||||||
@ -754,14 +754,6 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FearCharmSleepTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FearCharmSleepTrigger(PlayerbotAI* botAI) : Trigger(botAI, "fear charm sleep", 1) {}
|
|
||||||
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IsSwimmingTrigger : public Trigger
|
class IsSwimmingTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_WAITFORATTACKTRIGGERS_H
|
|
||||||
#define _PLAYERBOT_WAITFORATTACKTRIGGERS_H
|
|
||||||
|
|
||||||
#include "PlayerbotAIConfig.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "ServerFacade.h"
|
|
||||||
#include "Trigger.h"
|
|
||||||
#include "WaitForAttackStrategy.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
class WaitForAttackSafeDistanceTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WaitForAttackSafeDistanceTrigger(PlayerbotAI* botAI)
|
|
||||||
: Trigger(botAI, "wait for attack safe distance") {}
|
|
||||||
|
|
||||||
bool IsActive() override
|
|
||||||
{
|
|
||||||
if (!WaitForAttackStrategy::ShouldWait(botAI))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Do not move if stay strategy is set
|
|
||||||
if (botAI->HasStrategy("stay", botAI->GetState()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Do not move if currently being targeted
|
|
||||||
if (!bot->getAttackers().empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
|
||||||
if (!target)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float safeDistance = WaitForAttackStrategy::GetSafeDistance();
|
|
||||||
float safeDistanceThreshold = WaitForAttackStrategy::GetSafeDistanceThreshold();
|
|
||||||
float distanceToTarget = ServerFacade::instance().GetDistance2d(bot, target);
|
|
||||||
|
|
||||||
return (distanceToTarget > (safeDistance + safeDistanceThreshold)) ||
|
|
||||||
(distanceToTarget < (safeDistance - safeDistanceThreshold));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -20,7 +20,6 @@
|
|||||||
#include "RtiTriggers.h"
|
#include "RtiTriggers.h"
|
||||||
#include "StuckTriggers.h"
|
#include "StuckTriggers.h"
|
||||||
#include "TravelTriggers.h"
|
#include "TravelTriggers.h"
|
||||||
#include "WaitForAttackTriggers.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
@ -61,7 +60,6 @@ public:
|
|||||||
|
|
||||||
creators["generic boost"] = &TriggerContext::generic_boost;
|
creators["generic boost"] = &TriggerContext::generic_boost;
|
||||||
creators["loss of control"] = &TriggerContext::loss_of_control;
|
creators["loss of control"] = &TriggerContext::loss_of_control;
|
||||||
creators["fear charm sleep"] = &TriggerContext::fear_charm_sleep;
|
|
||||||
|
|
||||||
creators["protect party member"] = &TriggerContext::protect_party_member;
|
creators["protect party member"] = &TriggerContext::protect_party_member;
|
||||||
|
|
||||||
@ -233,7 +231,6 @@ public:
|
|||||||
creators["can fish"] = &TriggerContext::can_fish;
|
creators["can fish"] = &TriggerContext::can_fish;
|
||||||
creators["can use fishing bobber"] = &TriggerContext::can_use_fishing_bobber;
|
creators["can use fishing bobber"] = &TriggerContext::can_use_fishing_bobber;
|
||||||
creators["new pet"] = &TriggerContext::new_pet;
|
creators["new pet"] = &TriggerContext::new_pet;
|
||||||
creators["wait for attack safe distance"] = &TriggerContext::wait_for_attack_safe_distance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -368,7 +365,6 @@ private:
|
|||||||
}
|
}
|
||||||
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
|
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
|
||||||
static Trigger* loss_of_control(PlayerbotAI* botAI) { return new LossOfControlTrigger(botAI); }
|
static Trigger* loss_of_control(PlayerbotAI* botAI) { return new LossOfControlTrigger(botAI); }
|
||||||
static Trigger* fear_charm_sleep(PlayerbotAI* botAI) { return new FearCharmSleepTrigger(botAI); }
|
|
||||||
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
|
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new PartyMemberCriticalHealthTrigger(botAI);
|
return new PartyMemberCriticalHealthTrigger(botAI);
|
||||||
@ -438,7 +434,6 @@ private:
|
|||||||
static Trigger* can_fish(PlayerbotAI* ai) { return new CanFishTrigger(ai); }
|
static Trigger* can_fish(PlayerbotAI* ai) { return new CanFishTrigger(ai); }
|
||||||
static Trigger* can_use_fishing_bobber(PlayerbotAI* ai) { return new CanUseFishingBobberTrigger(ai); }
|
static Trigger* can_use_fishing_bobber(PlayerbotAI* ai) { return new CanUseFishingBobberTrigger(ai); }
|
||||||
static Trigger* new_pet(PlayerbotAI* ai) { return new NewPetTrigger(ai); }
|
static Trigger* new_pet(PlayerbotAI* ai) { return new NewPetTrigger(ai); }
|
||||||
static Trigger* wait_for_attack_safe_distance(PlayerbotAI* ai) { return new WaitForAttackSafeDistanceTrigger(ai); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <functional>
|
|
||||||
#include "Common.h"
|
|
||||||
#include "Group.h"
|
|
||||||
#include "Chat.h"
|
|
||||||
#include "Language.h"
|
|
||||||
|
|
||||||
class Player;
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
namespace ai::buff
|
|
||||||
{
|
|
||||||
|
|
||||||
// Build an aura qualifier "single + greater" to avoid double-buffing
|
|
||||||
std::string MakeAuraQualifierForBuff(std::string const& name);
|
|
||||||
|
|
||||||
// Returns the group spell name for a given single-target buff.
|
|
||||||
// If no group equivalent exists, returns "".
|
|
||||||
std::string GroupVariantFor(std::string const& name);
|
|
||||||
|
|
||||||
// Checks if the bot has the required reagents to cast a spell (by its spellId).
|
|
||||||
// Returns false if the spellId is invalid.
|
|
||||||
bool HasRequiredReagents(Player* bot, uint32 spellId);
|
|
||||||
|
|
||||||
// Applies the "switch to group buff" policy if: the bot is in a group of size x+,
|
|
||||||
// the group variant is known/useful, and reagents are available. Otherwise, returns baseName.
|
|
||||||
// If announceOnMissing == true and reagents are missing, calls the 'announce' callback
|
|
||||||
// (if provided) to notify the party/raid.
|
|
||||||
std::string UpgradeToGroupIfAppropriate(
|
|
||||||
Player* bot,
|
|
||||||
PlayerbotAI* botAI,
|
|
||||||
std::string const& baseName,
|
|
||||||
bool announceOnMissing = false,
|
|
||||||
std::function<void(std::string const&)> announce = {}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ai::spell
|
|
||||||
{
|
|
||||||
bool HasSpellOrCategoryCooldown(Player* bot, uint32 spellId);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ai::chat {
|
|
||||||
inline std::function<void(std::string const&)> MakeGroupAnnouncer(Player* me)
|
|
||||||
{
|
|
||||||
return [me](std::string const& msg)
|
|
||||||
{
|
|
||||||
if (Group* g = me->GetGroup())
|
|
||||||
{
|
|
||||||
WorldPacket data;
|
|
||||||
ChatMsg type = g->isRaidGroup() ? CHAT_MSG_RAID : CHAT_MSG_PARTY;
|
|
||||||
ChatHandler::BuildChatPacket(data, type, LANG_UNIVERSAL, me, /*receiver=*/nullptr, msg.c_str());
|
|
||||||
g->BroadcastPacket(&data, true, -1, me->GetGUID());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
me->Say(msg, LANG_UNIVERSAL);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_WAITFORATTACKTIMEVALUE_H
|
|
||||||
#define _PLAYERBOT_WAITFORATTACKTIMEVALUE_H
|
|
||||||
|
|
||||||
#include "Value.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
|
||||||
|
|
||||||
class WaitForAttackTimeValue : public ManualSetValue<uint8>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WaitForAttackTimeValue(PlayerbotAI* botAI) : ManualSetValue<uint8>(botAI, 10, "wait for attack time") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CombatStartTimeValue : public ManualSetValue<time_t>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CombatStartTimeValue(PlayerbotAI* botAI) : ManualSetValue<time_t>(botAI, 0, "combat start time") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -91,7 +91,6 @@
|
|||||||
#include "ThreatValues.h"
|
#include "ThreatValues.h"
|
||||||
#include "TradeValues.h"
|
#include "TradeValues.h"
|
||||||
#include "Value.h"
|
#include "Value.h"
|
||||||
#include "WaitForAttackTimeValue.h"
|
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
@ -323,8 +322,6 @@ public:
|
|||||||
creators["can fish"] = &ValueContext::can_fish;
|
creators["can fish"] = &ValueContext::can_fish;
|
||||||
creators["can use fishing bobber"] = &ValueContext::can_use_fishing_bobber;
|
creators["can use fishing bobber"] = &ValueContext::can_use_fishing_bobber;
|
||||||
creators["fishing spot"] = &ValueContext::fishing_spot;
|
creators["fishing spot"] = &ValueContext::fishing_spot;
|
||||||
creators["wait for attack time"] = &ValueContext::wait_for_attack_time;
|
|
||||||
creators["combat start time"] = &ValueContext::combat_start_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -581,8 +578,6 @@ private:
|
|||||||
{
|
{
|
||||||
return new ManualSetValue<bool>(ai, false, "custom_glyphs");
|
return new ManualSetValue<bool>(ai, false, "custom_glyphs");
|
||||||
}
|
}
|
||||||
static UntypedValue* wait_for_attack_time(PlayerbotAI* ai) { return new WaitForAttackTimeValue(ai); }
|
|
||||||
static UntypedValue* combat_start_time(PlayerbotAI* ai) { return new CombatStartTimeValue(ai); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -112,7 +112,6 @@ public:
|
|||||||
creators["mangle (cat)"] = &DruidTriggerFactoryInternal::mangle_cat;
|
creators["mangle (cat)"] = &DruidTriggerFactoryInternal::mangle_cat;
|
||||||
creators["ferocious bite time"] = &DruidTriggerFactoryInternal::ferocious_bite_time;
|
creators["ferocious bite time"] = &DruidTriggerFactoryInternal::ferocious_bite_time;
|
||||||
creators["hurricane channel check"] = &DruidTriggerFactoryInternal::hurricane_channel_check;
|
creators["hurricane channel check"] = &DruidTriggerFactoryInternal::hurricane_channel_check;
|
||||||
creators["no healer dps strategy"] = &DruidTriggerFactoryInternal::no_healer_dps_strategy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -150,7 +149,6 @@ private:
|
|||||||
static Trigger* mangle_cat(PlayerbotAI* ai) { return new MangleCatTrigger(ai); }
|
static Trigger* mangle_cat(PlayerbotAI* ai) { return new MangleCatTrigger(ai); }
|
||||||
static Trigger* ferocious_bite_time(PlayerbotAI* ai) { return new FerociousBiteTimeTrigger(ai); }
|
static Trigger* ferocious_bite_time(PlayerbotAI* ai) { return new FerociousBiteTimeTrigger(ai); }
|
||||||
static Trigger* hurricane_channel_check(PlayerbotAI* ai) { return new HurricaneChannelCheckTrigger(ai); }
|
static Trigger* hurricane_channel_check(PlayerbotAI* ai) { return new HurricaneChannelCheckTrigger(ai); }
|
||||||
static Trigger* no_healer_dps_strategy(PlayerbotAI* ai) { return new NoHealerDpsStrategyTrigger(ai); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DruidAiObjectContextInternal : public NamedObjectContext<Action>
|
class DruidAiObjectContextInternal : public NamedObjectContext<Action>
|
||||||
|
|||||||
@ -149,10 +149,10 @@ void DruidHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
triggers.push_back(
|
triggers.push_back(
|
||||||
new TriggerNode("healer should attack",
|
new TriggerNode("healer should attack",
|
||||||
{
|
{
|
||||||
NextAction("cancel tree form", ACTION_DEFAULT + 0.4f),
|
NextAction("cancel tree form", ACTION_DEFAULT + 0.3f),
|
||||||
NextAction("moonfire", ACTION_DEFAULT + 0.3f),
|
NextAction("moonfire", ACTION_DEFAULT + 0.2f),
|
||||||
NextAction("wrath", ACTION_DEFAULT + 0.2f),
|
NextAction("wrath", ACTION_DEFAULT + 0.1f),
|
||||||
NextAction("starfire", ACTION_DEFAULT + 0.1f),
|
NextAction("starfire", ACTION_DEFAULT),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,10 +33,6 @@ void HealDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
{
|
{
|
||||||
GenericDruidStrategy::InitTriggers(triggers);
|
GenericDruidStrategy::InitTriggers(triggers);
|
||||||
|
|
||||||
// no healer dps strategy
|
|
||||||
triggers.push_back(new TriggerNode("no healer dps strategy",
|
|
||||||
{ NextAction("tree form", ACTION_DEFAULT) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode(
|
triggers.push_back(new TriggerNode(
|
||||||
"party member to heal out of spell range",
|
"party member to heal out of spell range",
|
||||||
{ NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9) }));
|
{ NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9) }));
|
||||||
|
|||||||
@ -280,15 +280,4 @@ protected:
|
|||||||
static const std::set<uint32> HURRICANE_SPELL_IDS;
|
static const std::set<uint32> HURRICANE_SPELL_IDS;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NoHealerDpsStrategyTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NoHealerDpsStrategyTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no healer dps strategy") {}
|
|
||||||
|
|
||||||
bool IsActive() override
|
|
||||||
{
|
|
||||||
return !botAI->HasStrategy("healer dps", BOT_STATE_COMBAT);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -107,8 +107,6 @@ bool SwitchToMeleeTrigger::IsActive()
|
|||||||
ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f));
|
ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", "current target"), 8.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid targets for "Improved Tracking".
|
|
||||||
// Optional/Utility targets (uncomment for selfbot).
|
|
||||||
bool NoTrackTrigger::IsActive()
|
bool NoTrackTrigger::IsActive()
|
||||||
{
|
{
|
||||||
std::vector<std::string> track_list = {
|
std::vector<std::string> track_list = {
|
||||||
@ -117,13 +115,8 @@ bool NoTrackTrigger::IsActive()
|
|||||||
"track dragonkin",
|
"track dragonkin",
|
||||||
"track elementals",
|
"track elementals",
|
||||||
"track giants",
|
"track giants",
|
||||||
"track humanoids",
|
"track hidden",
|
||||||
"track undead",
|
"track humanoids"
|
||||||
// "track hidden",
|
|
||||||
// "find herbs",
|
|
||||||
// "find minerals",
|
|
||||||
// "find fish",
|
|
||||||
// "find treasure",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto &track: track_list)
|
for (auto &track: track_list)
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "../../../../../src/server/scripts/Spells/spell_generic.cpp"
|
#include "../../../../../src/server/scripts/Spells/spell_generic.cpp"
|
||||||
#include "Ai/Base/Util/GenericBuffUtils.h"
|
#include "GenericBuffUtils.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "ObjectAccessor.h"
|
#include "ObjectAccessor.h"
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
#include "RaidNaxxStrategy.h"
|
#include "RaidNaxxStrategy.h"
|
||||||
#include "RaidSSCStrategy.h"
|
#include "RaidSSCStrategy.h"
|
||||||
#include "RaidTempestKeepStrategy.h"
|
#include "RaidTempestKeepStrategy.h"
|
||||||
#include "RaidZulAmanStrategy.h"
|
|
||||||
#include "RaidOsStrategy.h"
|
#include "RaidOsStrategy.h"
|
||||||
#include "RaidEoEStrategy.h"
|
#include "RaidEoEStrategy.h"
|
||||||
#include "RaidVoAStrategy.h"
|
#include "RaidVoAStrategy.h"
|
||||||
@ -33,7 +32,6 @@ public:
|
|||||||
creators["naxx"] = &RaidStrategyContext::naxx;
|
creators["naxx"] = &RaidStrategyContext::naxx;
|
||||||
creators["ssc"] = &RaidStrategyContext::ssc;
|
creators["ssc"] = &RaidStrategyContext::ssc;
|
||||||
creators["tempestkeep"] = &RaidStrategyContext::tempestkeep;
|
creators["tempestkeep"] = &RaidStrategyContext::tempestkeep;
|
||||||
creators["zulaman"] = &RaidStrategyContext::zulaman;
|
|
||||||
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;
|
||||||
@ -52,7 +50,6 @@ private:
|
|||||||
static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); }
|
static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(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* tempestkeep(PlayerbotAI* botAI) { return new RaidTempestKeepStrategy(botAI); }
|
||||||
static Strategy* zulaman(PlayerbotAI* botAI) { return new RaidZulAmanStrategy(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); }
|
||||||
|
|||||||
@ -116,8 +116,8 @@ public:
|
|||||||
creators["kael'thas sunstrider assign legendary weapon dps priority"] =
|
creators["kael'thas sunstrider assign legendary weapon dps priority"] =
|
||||||
&RaidTempestKeepActionContext::kaelthas_sunstrider_assign_legendary_weapon_dps_priority;
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_assign_legendary_weapon_dps_priority;
|
||||||
|
|
||||||
creators["kael'thas sunstrider move devastation away"] =
|
creators["kael'thas sunstrider main tank move devastation away"] =
|
||||||
&RaidTempestKeepActionContext::kaelthas_sunstrider_move_devastation_away;
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_main_tank_move_devastation_away;
|
||||||
|
|
||||||
creators["kael'thas sunstrider loot legendary weapons"] =
|
creators["kael'thas sunstrider loot legendary weapons"] =
|
||||||
&RaidTempestKeepActionContext::kaelthas_sunstrider_loot_legendary_weapons;
|
&RaidTempestKeepActionContext::kaelthas_sunstrider_loot_legendary_weapons;
|
||||||
@ -255,7 +255,7 @@ private:
|
|||||||
static Action* kaelthas_sunstrider_assign_legendary_weapon_dps_priority(
|
static Action* kaelthas_sunstrider_assign_legendary_weapon_dps_priority(
|
||||||
PlayerbotAI* botAI) { return new KaelthasSunstriderAssignLegendaryWeaponDpsPriorityAction(botAI); }
|
PlayerbotAI* botAI) { return new KaelthasSunstriderAssignLegendaryWeaponDpsPriorityAction(botAI); }
|
||||||
|
|
||||||
static Action* kaelthas_sunstrider_move_devastation_away(
|
static Action* kaelthas_sunstrider_main_tank_move_devastation_away(
|
||||||
PlayerbotAI* botAI) { return new KaelthasSunstriderMoveDevastationAwayAction(botAI); }
|
PlayerbotAI* botAI) { return new KaelthasSunstriderMoveDevastationAwayAction(botAI); }
|
||||||
|
|
||||||
static Action* kaelthas_sunstrider_loot_legendary_weapons(
|
static Action* kaelthas_sunstrider_loot_legendary_weapons(
|
||||||
|
|||||||
@ -105,7 +105,7 @@ void RaidTempestKeepStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
NextAction("kael'thas sunstrider assign legendary weapon dps priority", ACTION_RAID + 1) }));
|
NextAction("kael'thas sunstrider assign legendary weapon dps priority", ACTION_RAID + 1) }));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary axe casts whirlwind", {
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary axe casts whirlwind", {
|
||||||
NextAction("kael'thas sunstrider move devastation away", ACTION_EMERGENCY + 1) }));
|
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", {
|
triggers.push_back(new TriggerNode("kael'thas sunstrider legendary weapons are dead and lootable", {
|
||||||
NextAction("kael'thas sunstrider loot legendary weapons", ACTION_RAID) }));
|
NextAction("kael'thas sunstrider loot legendary weapons", ACTION_RAID) }));
|
||||||
|
|||||||
@ -1,745 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RaidZulAmanActions.h"
|
|
||||||
#include "RaidZulAmanHelpers.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "RaidBossHelpers.h"
|
|
||||||
|
|
||||||
using namespace ZulAmanHelpers;
|
|
||||||
|
|
||||||
// Trash
|
|
||||||
|
|
||||||
bool AmanishiMedicineManMarkWardAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
if (Unit* protectiveWard = GetFirstAliveUnitByEntry(
|
|
||||||
botAI, static_cast<uint32>(ZulAmanNPCs::NPC_AMANI_PROTECTIVE_WARD)))
|
|
||||||
{
|
|
||||||
MarkTargetWithSkull(bot, protectiveWard);
|
|
||||||
}
|
|
||||||
else if (Unit* healingWard = GetFirstAliveUnitByEntry(
|
|
||||||
botAI, static_cast<uint32>(ZulAmanNPCs::NPC_AMANI_HEALING_WARD)))
|
|
||||||
{
|
|
||||||
MarkTargetWithSkull(bot, healingWard);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
|
|
||||||
bool AkilzonMisdirectBossToMainTankAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* akilzon = AI_VALUE2(Unit*, "find target", "akil'zon");
|
|
||||||
if (!akilzon)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player* mainTank = GetGroupMainTank(botAI, bot);
|
|
||||||
if (!mainTank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
|
||||||
return botAI->CastSpell("misdirection", mainTank);
|
|
||||||
|
|
||||||
if (bot->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_MISDIRECTION)) &&
|
|
||||||
botAI->CanCastSpell("steady shot", akilzon))
|
|
||||||
return botAI->CastSpell("steady shot", akilzon);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonTanksPositionBossAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* akilzon = AI_VALUE2(Unit*, "find target", "akil'zon");
|
|
||||||
if (!akilzon)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->GetVictim() != akilzon)
|
|
||||||
return Attack(akilzon);
|
|
||||||
|
|
||||||
if (akilzon->GetVictim() == bot)
|
|
||||||
{
|
|
||||||
const Position& position = AKILZON_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonSpreadRangedAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
constexpr float minDistance = 13.0f;
|
|
||||||
constexpr uint32 minInterval = 1000;
|
|
||||||
if (Unit* nearestPlayer = GetNearestPlayerInRadius(bot, minDistance))
|
|
||||||
return FleePosition(nearestPlayer->GetPosition(), minDistance, minInterval);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonMoveToEyeOfTheStormAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Player* target = GetElectricalStormTarget(bot);
|
|
||||||
if (!target && !botAI->IsMainTank(bot))
|
|
||||||
target = GetGroupMainTank(botAI, bot);
|
|
||||||
|
|
||||||
if (target && bot->GetExactDist2d(target) > 2.0f)
|
|
||||||
{
|
|
||||||
botAI->Reset();
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, target->GetPositionX(), target->GetPositionY(),
|
|
||||||
bot->GetPositionZ(), false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonManageElectricalStormTimerAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
const time_t now = std::time(nullptr);
|
|
||||||
const uint32 instanceId = bot->GetMap()->GetInstanceId();
|
|
||||||
|
|
||||||
Unit* akilzon = AI_VALUE2(Unit*, "find target", "akil'zon");
|
|
||||||
if (akilzon)
|
|
||||||
{
|
|
||||||
auto [it, inserted] = akilzonStormTimer.try_emplace(instanceId, now);
|
|
||||||
return inserted;
|
|
||||||
}
|
|
||||||
else if (!bot->IsInCombat() && !akilzon && akilzonStormTimer.erase(instanceId) > 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
|
|
||||||
bool NalorakkMisdirectBossToMainTankAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* nalorakk = AI_VALUE2(Unit*, "find target", "nalorakk");
|
|
||||||
if (!nalorakk)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player* mainTank = GetGroupMainTank(botAI, bot);
|
|
||||||
if (!mainTank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
|
||||||
return botAI->CastSpell("misdirection", mainTank);
|
|
||||||
|
|
||||||
if (bot->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_MISDIRECTION)) &&
|
|
||||||
botAI->CanCastSpell("steady shot", nalorakk))
|
|
||||||
return botAI->CastSpell("steady shot", nalorakk);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NalorakkTanksPositionBossAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
if (!botAI->IsMainTank(bot) && !botAI->IsAssistTankOfIndex(bot, 0, true))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* nalorakk = AI_VALUE2(Unit*, "find target", "nalorakk");
|
|
||||||
if (!nalorakk)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot))
|
|
||||||
return MainTankPositionTrollForm(nalorakk);
|
|
||||||
else
|
|
||||||
return FirstAssistTankPositionBearForm(nalorakk);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NalorakkTanksPositionBossAction::MainTankPositionTrollForm(Unit* nalorakk)
|
|
||||||
{
|
|
||||||
if (!nalorakk->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_BEARFORM)))
|
|
||||||
{
|
|
||||||
if (bot->GetVictim() != nalorakk)
|
|
||||||
return Attack(nalorakk);
|
|
||||||
|
|
||||||
if (nalorakk->GetVictim() != bot)
|
|
||||||
return botAI->DoSpecificAction("taunt spell", Event(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Position& position = NALORAKK_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NalorakkTanksPositionBossAction::FirstAssistTankPositionBearForm(Unit* nalorakk)
|
|
||||||
{
|
|
||||||
if (nalorakk->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_BEARFORM)))
|
|
||||||
{
|
|
||||||
if (bot->GetVictim() != nalorakk)
|
|
||||||
return Attack(nalorakk);
|
|
||||||
|
|
||||||
if (nalorakk->GetVictim() != bot)
|
|
||||||
return botAI->DoSpecificAction("taunt spell", Event(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Position& position = NALORAKK_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NalorakkSpreadRangedAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
constexpr float minDistance = 11.0f;
|
|
||||||
constexpr uint32 minInterval = 1000;
|
|
||||||
if (Unit* nearestPlayer = GetNearestPlayerInRadius(bot, minDistance))
|
|
||||||
return FleePosition(nearestPlayer->GetPosition(), minDistance, minInterval);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
|
|
||||||
bool JanalaiMisdirectBossToMainTankAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* janalai = AI_VALUE2(Unit*, "find target", "jan'alai");
|
|
||||||
if (!janalai)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player* mainTank = GetGroupMainTank(botAI, bot);
|
|
||||||
if (!mainTank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
|
||||||
return botAI->CastSpell("misdirection", mainTank);
|
|
||||||
|
|
||||||
if (bot->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_MISDIRECTION)) &&
|
|
||||||
botAI->CanCastSpell("steady shot", janalai))
|
|
||||||
return botAI->CastSpell("steady shot", janalai);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiTanksPositionBossAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* janalai = AI_VALUE2(Unit*, "find target", "jan'alai");
|
|
||||||
if (!janalai)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->GetVictim() != janalai)
|
|
||||||
return Attack(janalai);
|
|
||||||
|
|
||||||
if (janalai->GetVictim() == bot)
|
|
||||||
{
|
|
||||||
const Position& position = JANALAI_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiSpreadRangedInCircleAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!group)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::vector<Player*> rangedMembers;
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member || !botAI->IsRanged(member))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rangedMembers.push_back(member);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rangedMembers.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto findIt = std::find(rangedMembers.begin(), rangedMembers.end(), bot);
|
|
||||||
size_t botIndex =
|
|
||||||
(findIt != rangedMembers.end()) ? std::distance(rangedMembers.begin(), findIt) : 0;
|
|
||||||
size_t count = rangedMembers.size();
|
|
||||||
if (count == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
constexpr float radius = 15.0f;
|
|
||||||
float angle = (count == 1) ? 0.0f :
|
|
||||||
(2.0f * M_PI * static_cast<float>(botIndex) / static_cast<float>(count));
|
|
||||||
|
|
||||||
float targetX = JANALAI_TANK_POSITION.GetPositionX() + radius * std::cos(angle);
|
|
||||||
float targetY = JANALAI_TANK_POSITION.GetPositionY() + radius * std::sin(angle);
|
|
||||||
|
|
||||||
if (bot->GetExactDist2d(targetX, targetY) > 2.0f)
|
|
||||||
{
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, targetX, targetY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiAvoidFireBombsAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
auto const& bombs = GetAllHazardTriggers(
|
|
||||||
bot, static_cast<uint32>(ZulAmanNPCs::NPC_FIRE_BOMB), 50.0f);
|
|
||||||
|
|
||||||
if (bombs.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
constexpr float hazardRadius = 5.0f;
|
|
||||||
bool inDanger = false;
|
|
||||||
for (Unit* bomb : bombs)
|
|
||||||
{
|
|
||||||
if (bot->GetDistance2d(bomb) < hazardRadius)
|
|
||||||
{
|
|
||||||
inDanger = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inDanger)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Position& janalaiCenter = JANALAI_TANK_POSITION;
|
|
||||||
constexpr float safeZoneRadius = 17.0f;
|
|
||||||
|
|
||||||
Position safestPos =
|
|
||||||
FindSafestNearbyPosition(bot, bombs, janalaiCenter, safeZoneRadius, hazardRadius, false);
|
|
||||||
|
|
||||||
bot->AttackStop();
|
|
||||||
bot->InterruptNonMeleeSpells(true);
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, safestPos.GetPositionX(), safestPos.GetPositionY(),
|
|
||||||
bot->GetPositionZ(), false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiMarkAmanishiHatchersAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
auto [hatcherLow, hatcherHigh] = GetAmanishiHatcherPair(botAI);
|
|
||||||
|
|
||||||
if (hatcherLow && hatcherHigh && hatcherHigh != hatcherLow)
|
|
||||||
{
|
|
||||||
MarkTargetWithSkull(bot, hatcherLow);
|
|
||||||
MarkTargetWithMoon(bot, hatcherHigh);
|
|
||||||
SetRtiTarget(botAI, "skull", hatcherLow);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
|
|
||||||
bool HalazziMisdirectBossToMainTankAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* halazzi = AI_VALUE2(Unit*, "find target", "halazzi");
|
|
||||||
if (!halazzi)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player* mainTank = GetGroupMainTank(botAI, bot);
|
|
||||||
if (!mainTank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
|
||||||
return botAI->CastSpell("misdirection", mainTank);
|
|
||||||
|
|
||||||
if (bot->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_MISDIRECTION)) &&
|
|
||||||
botAI->CanCastSpell("steady shot", halazzi))
|
|
||||||
return botAI->CastSpell("steady shot", halazzi);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HalazziMainTankPositionBossAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* halazzi = AI_VALUE2(Unit*, "find target", "halazzi");
|
|
||||||
if (!halazzi)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MarkTargetWithStar(bot, halazzi);
|
|
||||||
SetRtiTarget(botAI, "star", halazzi);
|
|
||||||
|
|
||||||
if (bot->GetVictim() != halazzi)
|
|
||||||
return Attack(halazzi);
|
|
||||||
|
|
||||||
if (halazzi->GetVictim() == bot)
|
|
||||||
{
|
|
||||||
const Position& position = HALAZZI_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HalazziFirstAssistTankAttackSpiritLynxAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
bool targetFound = false;
|
|
||||||
|
|
||||||
if (Unit* lynx = AI_VALUE2(Unit*, "find target", "spirit of the lynx"))
|
|
||||||
{
|
|
||||||
MarkTargetWithCircle(bot, lynx);
|
|
||||||
SetRtiTarget(botAI, "circle", lynx);
|
|
||||||
|
|
||||||
if (bot->GetVictim() != lynx)
|
|
||||||
return Attack(lynx);
|
|
||||||
|
|
||||||
if (lynx->GetVictim() != bot)
|
|
||||||
return botAI->DoSpecificAction("taunt spell", Event(), true);
|
|
||||||
|
|
||||||
targetFound = true;
|
|
||||||
}
|
|
||||||
else if (Unit* halazzi = AI_VALUE2(Unit*, "find target", "halazzi"))
|
|
||||||
{
|
|
||||||
SetRtiTarget(botAI, "star", halazzi);
|
|
||||||
|
|
||||||
if (bot->GetVictim() != halazzi)
|
|
||||||
return Attack(halazzi);
|
|
||||||
|
|
||||||
targetFound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!targetFound)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Position& position = HALAZZI_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HalazziAssignDpsPriorityAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
// Target priority 1: Corrupted Lightning Totems
|
|
||||||
if (Unit* totem = GetFirstAliveUnitByEntry(
|
|
||||||
botAI, static_cast<uint32>(ZulAmanNPCs::NPC_CORRUPTED_LIGHTNING_TOTEM)))
|
|
||||||
{
|
|
||||||
MarkTargetWithSkull(bot, totem);
|
|
||||||
SetRtiTarget(botAI, "skull", totem);
|
|
||||||
|
|
||||||
if (bot->GetTarget() != totem->GetGUID())
|
|
||||||
return Attack(totem);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Target priority 2: Halazzi
|
|
||||||
if (Unit* halazzi = AI_VALUE2(Unit*, "find target", "halazzi"))
|
|
||||||
{
|
|
||||||
SetRtiTarget(botAI, "star", halazzi);
|
|
||||||
|
|
||||||
if (bot->GetTarget() != halazzi->GetGUID())
|
|
||||||
return Attack(halazzi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't attack the Lynx
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
bool HexLordMalacrassMisdirectBossToMainTankAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
if (!malacrass)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player* mainTank = GetGroupMainTank(botAI, bot);
|
|
||||||
if (!mainTank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
|
||||||
return botAI->CastSpell("misdirection", mainTank);
|
|
||||||
|
|
||||||
if (bot->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_MISDIRECTION)) &&
|
|
||||||
botAI->CanCastSpell("steady shot", malacrass))
|
|
||||||
return botAI->CastSpell("steady shot", malacrass);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassAssignDpsPriorityAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
static constexpr uint32 priorityEntries[] =
|
|
||||||
{
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_LORD_RAADAN),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_ALYSON_ANTILLE),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_KORAGG),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_DARKHEART),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_FENSTALKER),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_GAZAKROTH),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_THURG),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_SLITHER),
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_HEX_LORD_MALACRASS)
|
|
||||||
};
|
|
||||||
|
|
||||||
auto const& targets =
|
|
||||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los")->Get();
|
|
||||||
|
|
||||||
Unit* priorityTarget = nullptr;
|
|
||||||
|
|
||||||
for (uint32 entry : priorityEntries)
|
|
||||||
{
|
|
||||||
for (auto const& guid : targets)
|
|
||||||
{
|
|
||||||
Unit* unit = botAI->GetUnit(guid);
|
|
||||||
if (unit && unit->IsAlive() && unit->GetEntry() == entry)
|
|
||||||
{
|
|
||||||
priorityTarget = unit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priorityTarget)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priorityTarget)
|
|
||||||
{
|
|
||||||
MarkTargetWithSkull(bot, priorityTarget);
|
|
||||||
SetRtiTarget(botAI, "skull", priorityTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassRunAwayFromWhirlwindAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
if (Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass"))
|
|
||||||
{
|
|
||||||
float currentDistance = bot->GetDistance2d(malacrass);
|
|
||||||
constexpr float safeDistance = 9.0f;
|
|
||||||
if (currentDistance < safeDistance)
|
|
||||||
{
|
|
||||||
bot->AttackStop();
|
|
||||||
bot->InterruptNonMeleeSpells(true);
|
|
||||||
return MoveAway(malacrass, safeDistance - currentDistance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassCastersStopAttackingAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
if (!malacrass ||
|
|
||||||
!malacrass->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_HEX_LORD_SPELL_REFLECTION)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->GetVictim() == malacrass)
|
|
||||||
{
|
|
||||||
bot->AttackStop();
|
|
||||||
bot->InterruptNonMeleeSpells(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassMoveAwayFromFreezingTrapAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
GameObject* trapGo = bot->FindNearestGameObject(
|
|
||||||
static_cast<uint32>(ZulAmanObjects::GO_FREEZING_TRAP), 20.0f, true);
|
|
||||||
|
|
||||||
if (!trapGo)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float currentDistance = bot->GetDistance2d(trapGo);
|
|
||||||
constexpr float safeDistance = 6.0f;
|
|
||||||
constexpr uint32 minInterval = 0;
|
|
||||||
if (currentDistance < safeDistance)
|
|
||||||
return FleePosition(trapGo->GetPosition(), safeDistance, minInterval);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
bool ZuljinMisdirectBossToMainTankAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Player* mainTank = GetGroupMainTank(botAI, bot);
|
|
||||||
if (!mainTank)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (botAI->CanCastSpell("misdirection", mainTank))
|
|
||||||
return botAI->CastSpell("misdirection", mainTank);
|
|
||||||
|
|
||||||
if (bot->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_MISDIRECTION)) &&
|
|
||||||
botAI->CanCastSpell("steady shot", zuljin))
|
|
||||||
return botAI->CastSpell("steady shot", zuljin);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinTanksPositionBossAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->GetVictim() != zuljin)
|
|
||||||
return Attack(zuljin);
|
|
||||||
|
|
||||||
if (zuljin->GetVictim() == bot)
|
|
||||||
{
|
|
||||||
const Position& position = ZULJIN_TANK_POSITION;
|
|
||||||
float distToPosition =
|
|
||||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
|
||||||
|
|
||||||
if (distToPosition > 2.0f)
|
|
||||||
{
|
|
||||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
|
||||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
|
||||||
float moveDist = std::min(10.0f, distToPosition);
|
|
||||||
float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
|
||||||
float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
|
||||||
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, moveX, moveY, bot->GetPositionZ(), false, false,
|
|
||||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinRunAwayFromWhirlwindAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
if (Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin"))
|
|
||||||
{
|
|
||||||
float currentDistance = bot->GetExactDist2d(zuljin);
|
|
||||||
constexpr float safeDistance = 10.0f;
|
|
||||||
if (currentDistance < safeDistance)
|
|
||||||
{
|
|
||||||
bot->AttackStop();
|
|
||||||
bot->InterruptNonMeleeSpells(true);
|
|
||||||
return MoveAway(zuljin, safeDistance - currentDistance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinAvoidCyclonesAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
auto const& cyclones = GetAllHazardTriggers(
|
|
||||||
bot, static_cast<uint32>(ZulAmanNPCs::NPC_FEATHER_VORTEX), 50.0f);
|
|
||||||
|
|
||||||
if (cyclones.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
constexpr float hazardRadius = 6.0f;
|
|
||||||
bool inDanger = false;
|
|
||||||
for (Unit* cyclone : cyclones)
|
|
||||||
{
|
|
||||||
if (bot->GetDistance2d(cyclone) < hazardRadius)
|
|
||||||
{
|
|
||||||
inDanger = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inDanger)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const Position& zuljinCenter = ZULJIN_TANK_POSITION;
|
|
||||||
constexpr float safeZoneRadius = 30.0f;
|
|
||||||
|
|
||||||
Position safestPos =
|
|
||||||
FindSafestNearbyPosition(bot, cyclones, zuljinCenter, safeZoneRadius, hazardRadius, true);
|
|
||||||
|
|
||||||
bot->AttackStop();
|
|
||||||
bot->InterruptNonMeleeSpells(true);
|
|
||||||
return MoveTo(ZULAMAN_MAP_ID, safestPos.GetPositionX(), safestPos.GetPositionY(),
|
|
||||||
bot->GetPositionZ(), false, false, false, false,
|
|
||||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinSpreadRangedAction::Execute(Event /*event*/)
|
|
||||||
{
|
|
||||||
constexpr float minDistance = 6.0f;
|
|
||||||
constexpr uint32 minInterval = 1000;
|
|
||||||
if (Unit* nearestPlayer = GetNearestPlayerInRadius(bot, minDistance))
|
|
||||||
return FleePosition(nearestPlayer->GetPosition(), minDistance, minInterval);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@ -1,253 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANACTIONS_H
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANACTIONS_H
|
|
||||||
|
|
||||||
#include "Action.h"
|
|
||||||
#include "AttackAction.h"
|
|
||||||
#include "MovementActions.h"
|
|
||||||
|
|
||||||
// Trash
|
|
||||||
|
|
||||||
class AmanishiMedicineManMarkWardAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AmanishiMedicineManMarkWardAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "amani'shi medicine man mark ward") : Action(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
|
|
||||||
class AkilzonMisdirectBossToMainTankAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonMisdirectBossToMainTankAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "akil'zon misdirect boss to main tank") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonTanksPositionBossAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonTanksPositionBossAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "akil'zon tanks position boss") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonSpreadRangedAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonSpreadRangedAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "akil'zon spread ranged") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonMoveToEyeOfTheStormAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonMoveToEyeOfTheStormAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "akil'zon move to eye of the storm") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonManageElectricalStormTimerAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonManageElectricalStormTimerAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "akil'zon manage electrical storm timer") : Action(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
|
|
||||||
class NalorakkMisdirectBossToMainTankAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkMisdirectBossToMainTankAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "nalorakk misdirect boss to main tank") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NalorakkTanksPositionBossAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkTanksPositionBossAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "nalorakk tanks position boss") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool MainTankPositionTrollForm(Unit* nalorakk);
|
|
||||||
bool FirstAssistTankPositionBearForm(Unit* nalorakk);
|
|
||||||
};
|
|
||||||
|
|
||||||
class NalorakkSpreadRangedAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkSpreadRangedAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "nalorakk spread ranged") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
|
|
||||||
class JanalaiMisdirectBossToMainTankAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiMisdirectBossToMainTankAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "jan'alai misdirect boss to main tank") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiTanksPositionBossAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiTanksPositionBossAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "jan'alai tanks position boss") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiSpreadRangedInCircleAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiSpreadRangedInCircleAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "jan'alai spread ranged in circle") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiAvoidFireBombsAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiAvoidFireBombsAction(PlayerbotAI* botAI, std::string const name = "jan'alai avoid fire bombs") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiMarkAmanishiHatchersAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiMarkAmanishiHatchersAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "jan'alai mark amani'shi hatchers") : Action(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
|
|
||||||
class HalazziMisdirectBossToMainTankAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziMisdirectBossToMainTankAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "halazzi misdirect boss to main tank") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziMainTankPositionBossAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziMainTankPositionBossAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "halazzi main tank position boss") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziFirstAssistTankAttackSpiritLynxAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziFirstAssistTankAttackSpiritLynxAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "halazzi first assist tank attack spirit lynx") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziAssignDpsPriorityAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziAssignDpsPriorityAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "halazzi assign dps priority") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
class HexLordMalacrassMisdirectBossToMainTankAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassMisdirectBossToMainTankAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "hex lord malacrass misdirect boss to main tank") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassAssignDpsPriorityAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassAssignDpsPriorityAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "hex lord malacrass assign dps priority") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassRunAwayFromWhirlwindAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassRunAwayFromWhirlwindAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "hex lord malacrass run away from whirlwind") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassCastersStopAttackingAction : public Action
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassCastersStopAttackingAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "hex lord malacrass casters stop attacking") : Action(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassMoveAwayFromFreezingTrapAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassMoveAwayFromFreezingTrapAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "hex lord malacrass move away from freezing trap") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
class ZuljinMisdirectBossToMainTankAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinMisdirectBossToMainTankAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "zul'jin misdirect boss to main tank") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinTanksPositionBossAction : public AttackAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinTanksPositionBossAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "zul'jin tanks position boss") : AttackAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinRunAwayFromWhirlwindAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinRunAwayFromWhirlwindAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "zul'jin run away from whirlwind") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinAvoidCyclonesAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinAvoidCyclonesAction(PlayerbotAI* botAI, std::string const name = "zul'jin avoid cyclones") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinSpreadRangedAction : public MovementAction
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinSpreadRangedAction(
|
|
||||||
PlayerbotAI* botAI, std::string const name = "zul'jin spread ranged") : MovementAction(botAI, name) {}
|
|
||||||
bool Execute(Event event) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,382 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RaidZulAmanMultipliers.h"
|
|
||||||
#include "RaidZulAmanActions.h"
|
|
||||||
#include "RaidZulAmanHelpers.h"
|
|
||||||
#include "ChooseTargetActions.h"
|
|
||||||
#include "DKActions.h"
|
|
||||||
#include "DruidBearActions.h"
|
|
||||||
#include "FollowActions.h"
|
|
||||||
#include "GenericSpellActions.h"
|
|
||||||
#include "HunterActions.h"
|
|
||||||
#include "MageActions.h"
|
|
||||||
#include "PaladinActions.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "PriestActions.h"
|
|
||||||
#include "RaidBossHelpers.h"
|
|
||||||
#include "ReachTargetActions.h"
|
|
||||||
#include "RogueActions.h"
|
|
||||||
#include "ShamanActions.h"
|
|
||||||
#include "WarlockActions.h"
|
|
||||||
#include "WarriorActions.h"
|
|
||||||
|
|
||||||
using namespace ZulAmanHelpers;
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
|
|
||||||
float AkilzonDisableCombatFormationMoveMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "akil'zon"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
|
|
||||||
!dynamic_cast<SetBehindTargetAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float AkilzonStayInEyeOfTheStormMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "akil'zon") /* ||
|
|
||||||
!GetElectricalStormTarget(bot)*/)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
auto it = akilzonStormTimer.find(bot->GetMap()->GetInstanceId());
|
|
||||||
if (it == akilzonStormTimer.end() ||
|
|
||||||
!IsInStormWindow(it->second, std::time(nullptr)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
|
||||||
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
|
||||||
dynamic_cast<CastBlinkBackAction*>(action) ||
|
|
||||||
dynamic_cast<CastDisengageAction*>(action) ||
|
|
||||||
dynamic_cast<SetBehindTargetAction*>(action) ||
|
|
||||||
dynamic_cast<FleeAction*>(action) ||
|
|
||||||
dynamic_cast<FollowAction*>(action) ||
|
|
||||||
dynamic_cast<ReachTargetAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
|
|
||||||
float NalorakkDisableTankActionsMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Unit* nalorakk = AI_VALUE2(Unit*, "find target", "nalorakk");
|
|
||||||
if (!nalorakk)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<TankFaceAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
if (bot->GetVictim() == nullptr)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
bool shouldTankBoss = false;
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot) &&
|
|
||||||
!nalorakk->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_BEARFORM)))
|
|
||||||
shouldTankBoss = true;
|
|
||||||
|
|
||||||
if (botAI->IsAssistTankOfIndex(bot, 0, true) &&
|
|
||||||
nalorakk->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_BEARFORM)))
|
|
||||||
shouldTankBoss = true;
|
|
||||||
|
|
||||||
if (!shouldTankBoss &&
|
|
||||||
(dynamic_cast<TankAssistAction*>(action) ||
|
|
||||||
dynamic_cast<CastTauntAction*>(action) ||
|
|
||||||
dynamic_cast<CastGrowlAction*>(action) ||
|
|
||||||
dynamic_cast<CastHandOfReckoningAction*>(action) ||
|
|
||||||
dynamic_cast<CastDarkCommandAction*>(action)))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float NalorakkControlMisdirectionMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "nalorakk"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastMisdirectionOnMainTankAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
|
|
||||||
float JanalaiDisableTankActionsMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "jan'alai"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<TankFaceAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
if (bot->GetVictim() == nullptr)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (botAI->IsMainTank(bot) &&
|
|
||||||
dynamic_cast<TankAssistAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
if (botAI->IsAssistTank(bot) &&
|
|
||||||
!GetFirstAliveUnitByEntry(
|
|
||||||
botAI, static_cast<uint32>(ZulAmanNPCs::NPC_AMANI_DRAGONHAWK_HATCHLING)) &&
|
|
||||||
dynamic_cast<TankAssistAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JanalaiDisableCombatFormationMoveMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "jan'alai"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CombatFormationMoveAction*>(action) &&
|
|
||||||
!dynamic_cast<SetBehindTargetAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JanalaiStayAwayFromFireBombsMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "jan'alai"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (!HasFireBombNearby(botAI, bot))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
|
||||||
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
|
||||||
dynamic_cast<CastBlinkBackAction*>(action) ||
|
|
||||||
dynamic_cast<CastDisengageAction*>(action) ||
|
|
||||||
dynamic_cast<FleeAction*>(action) ||
|
|
||||||
dynamic_cast<FollowAction*>(action) ||
|
|
||||||
dynamic_cast<ReachTargetAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JanalaiDoNotCrowdControlHatchersMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "amani'shi hatcher"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastCrowdControlSpellAction*>(action) ||
|
|
||||||
dynamic_cast<CastPolymorphAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float JanalaiDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_SHAMAN)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "jan'alai"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (AI_VALUE2(Unit*, "find target", "amani dragonhawk hatchling"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastBloodlustAction*>(action) ||
|
|
||||||
dynamic_cast<CastHeroismAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
|
|
||||||
float HalazziDisableTankActionsMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "halazzi"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<TankFaceAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
if (bot->GetVictim() != nullptr &&
|
|
||||||
dynamic_cast<TankAssistAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float HalazziControlMisdirectionMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "halazzi"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastMisdirectionOnMainTankAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
float HexLordMalacrassAvoidWhirlwindMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (botAI->IsMainTank(bot))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
if (!malacrass ||
|
|
||||||
!malacrass->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_HEX_LORD_WHIRLWIND)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
|
||||||
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
|
||||||
dynamic_cast<ReachTargetAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float HexLordMalacrassStopAttackingDuringSpellReflectionMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!botAI->IsCaster(bot))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
if (!malacrass ||
|
|
||||||
!malacrass->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_HEX_LORD_SPELL_REFLECTION)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
auto castSpellAction = dynamic_cast<CastSpellAction*>(action);
|
|
||||||
if (!castSpellAction)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (castSpellAction->getThreatType() == Action::ActionThreatType::Aoe ||
|
|
||||||
(bot->GetVictim() == malacrass &&
|
|
||||||
castSpellAction->getThreatType() == Action::ActionThreatType::Single))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float HexLordMalacrassDoNotDispelUnstableAfflictionMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_PRIEST &&
|
|
||||||
bot->getClass() != CLASS_PALADIN &&
|
|
||||||
bot->getClass() != CLASS_WARLOCK)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "hex lord malacrass"))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!group)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
bool hasUnstableAffliction = false;
|
|
||||||
for (GroupReference* ref = bot->GetGroup()->GetFirstMember(); ref != nullptr; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (!member || !member->IsAlive())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (member->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_UNSTABLE_AFFLICTION)))
|
|
||||||
{
|
|
||||||
hasUnstableAffliction = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasUnstableAffliction)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastDevourMagicCleanseAction*>(action) ||
|
|
||||||
dynamic_cast<CastDispelMagicAction*>(action) ||
|
|
||||||
dynamic_cast<CastDispelMagicOnPartyAction*>(action) ||
|
|
||||||
dynamic_cast<CastMassDispelAction*>(action) ||
|
|
||||||
dynamic_cast<CastPurgeAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
float ZuljinDisableTankFaceMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin ||
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_DRAGONHAWK)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<TankFaceAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ZuljinAvoidWhirlwindMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (botAI->IsMainTank(bot))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin ||
|
|
||||||
!zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_ZULJIN_WHIRLWIND)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
|
||||||
dynamic_cast<CastKillingSpreeAction*>(action) ||
|
|
||||||
dynamic_cast<ReachTargetAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ZuljinDisableAvoidAoeMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin ||
|
|
||||||
!zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_EAGLE)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<AvoidAoeAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ZuljinDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_SHAMAN)
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin ||
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_EAGLE)))
|
|
||||||
return 1.0f;
|
|
||||||
|
|
||||||
if (dynamic_cast<CastBloodlustAction*>(action) ||
|
|
||||||
dynamic_cast<CastHeroismAction*>(action))
|
|
||||||
return 0.0f;
|
|
||||||
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANMULTIPLIERS_H
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANMULTIPLIERS_H
|
|
||||||
|
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
|
|
||||||
class AkilzonDisableCombatFormationMoveMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonDisableCombatFormationMoveMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "akil'zon disable combat formation move") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonStayInEyeOfTheStormMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonStayInEyeOfTheStormMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "akil'zon stay in eye of the storm") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
|
|
||||||
class NalorakkDisableTankActionsMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkDisableTankActionsMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "nalorakk disable tank actions") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class NalorakkControlMisdirectionMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkControlMisdirectionMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "nalorakk control misdirection") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
|
|
||||||
class JanalaiDisableTankActionsMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiDisableTankActionsMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "jan'alai disable tank actions") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiDisableCombatFormationMoveMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiDisableCombatFormationMoveMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "jan'alai disable combat formation move") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiStayAwayFromFireBombsMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiStayAwayFromFireBombsMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "jan'alai stay away from fire bombs") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiDoNotCrowdControlHatchersMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiDoNotCrowdControlHatchersMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "jan'alai do not crowd control hatchers") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiDelayBloodlustAndHeroismMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiDelayBloodlustAndHeroismMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "jan'alai delay bloodlust and heroism") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
|
|
||||||
class HalazziDisableTankActionsMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziDisableTankActionsMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "halazzi disable tank actions") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziControlMisdirectionMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziControlMisdirectionMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "halazzi control misdirection") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
class HexLordMalacrassAvoidWhirlwindMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassAvoidWhirlwindMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "hex lord malacrass avoid whirlwind") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassDoNotDispelUnstableAfflictionMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassDoNotDispelUnstableAfflictionMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "hex lord malacrass do not dispel unstable affliction") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassStopAttackingDuringSpellReflectionMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassStopAttackingDuringSpellReflectionMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "hex lord malacrass stop attacking during spell reflection") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
class ZuljinDisableTankFaceMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinDisableTankFaceMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "zul'jin disable tank face") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinAvoidWhirlwindMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinAvoidWhirlwindMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "zul'jin avoid whirlwind") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinDisableAvoidAoeMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinDisableAvoidAoeMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "zul'jin disable avoid aoe") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinDelayBloodlustAndHeroismMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinDelayBloodlustAndHeroismMultiplier(PlayerbotAI* botAI) : Multiplier(
|
|
||||||
botAI, "zul'jin delay bloodlust and heroism") {}
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANACTIONCONTEXT_H
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANACTIONCONTEXT_H
|
|
||||||
|
|
||||||
#include "RaidZulAmanActions.h"
|
|
||||||
#include "NamedObjectContext.h"
|
|
||||||
|
|
||||||
class RaidZulAmanActionContext : public NamedObjectContext<Action>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RaidZulAmanActionContext()
|
|
||||||
{
|
|
||||||
// Trash
|
|
||||||
creators["amani'shi medicine man mark ward"] =
|
|
||||||
&RaidZulAmanActionContext::amanishi_medicine_man_mark_ward;
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
creators["akil'zon misdirect boss to main tank"] =
|
|
||||||
&RaidZulAmanActionContext::akilzon_misdirect_boss_to_main_tank;
|
|
||||||
|
|
||||||
creators["akil'zon tanks position boss"] =
|
|
||||||
&RaidZulAmanActionContext::akilzon_tanks_position_boss;
|
|
||||||
|
|
||||||
creators["akil'zon spread ranged"] =
|
|
||||||
&RaidZulAmanActionContext::akilzon_spread_ranged;
|
|
||||||
|
|
||||||
creators["akil'zon move to eye of the storm"] =
|
|
||||||
&RaidZulAmanActionContext::akilzon_move_to_eye_of_the_storm;
|
|
||||||
|
|
||||||
creators["akil'zon manage electrical storm timer"] =
|
|
||||||
&RaidZulAmanActionContext::akilzon_manage_electrical_storm_timer;
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
creators["nalorakk misdirect boss to main tank"] =
|
|
||||||
&RaidZulAmanActionContext::nalorakk_misdirect_boss_to_main_tank;
|
|
||||||
|
|
||||||
creators["nalorakk tanks position boss"] =
|
|
||||||
&RaidZulAmanActionContext::nalorakk_tanks_position_boss;
|
|
||||||
|
|
||||||
creators["nalorakk spread ranged"] =
|
|
||||||
&RaidZulAmanActionContext::nalorakk_spread_ranged;
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
creators["jan'alai misdirect boss to main tank"] =
|
|
||||||
&RaidZulAmanActionContext::janalai_misdirect_boss_to_main_tank;
|
|
||||||
|
|
||||||
creators["jan'alai tanks position boss"] =
|
|
||||||
&RaidZulAmanActionContext::janalai_tanks_position_boss;
|
|
||||||
|
|
||||||
creators["jan'alai spread ranged in circle"] =
|
|
||||||
&RaidZulAmanActionContext::janalai_spread_ranged_in_circle;
|
|
||||||
|
|
||||||
creators["jan'alai avoid fire bombs"] =
|
|
||||||
&RaidZulAmanActionContext::janalai_avoid_fire_bombs;
|
|
||||||
|
|
||||||
creators["jan'alai mark amani'shi hatchers"] =
|
|
||||||
&RaidZulAmanActionContext::janalai_mark_amanishi_hatchers;
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
creators["halazzi misdirect boss to main tank"] =
|
|
||||||
&RaidZulAmanActionContext::halazzi_misdirect_boss_to_main_tank;
|
|
||||||
|
|
||||||
creators["halazzi main tank position boss"] =
|
|
||||||
&RaidZulAmanActionContext::halazzi_main_tank_position_boss;
|
|
||||||
|
|
||||||
creators["halazzi first assist tank attack spirit lynx"] =
|
|
||||||
&RaidZulAmanActionContext::halazzi_first_assist_tank_attack_spirit_lynx;
|
|
||||||
|
|
||||||
creators["halazzi assign dps priority"] =
|
|
||||||
&RaidZulAmanActionContext::halazzi_assign_dps_priority;
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
creators["hex lord malacrass misdirect boss to main tank"] =
|
|
||||||
&RaidZulAmanActionContext::hex_lord_malacrass_misdirect_boss_to_main_tank;
|
|
||||||
|
|
||||||
creators["hex lord malacrass assign dps priority"] =
|
|
||||||
&RaidZulAmanActionContext::hex_lord_malacrass_assign_dps_priority;
|
|
||||||
|
|
||||||
creators["hex lord malacrass run away from whirlwind"] =
|
|
||||||
&RaidZulAmanActionContext::hex_lord_malacrass_run_away_from_whirlwind;
|
|
||||||
|
|
||||||
creators["hex lord malacrass casters stop attacking"] =
|
|
||||||
&RaidZulAmanActionContext::hex_lord_malacrass_casters_stop_attacking;
|
|
||||||
|
|
||||||
creators["hex lord malacrass move away from freezing trap"] =
|
|
||||||
&RaidZulAmanActionContext::hex_lord_malacrass_move_away_from_freezing_trap;
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
creators["zul'jin misdirect boss to main tank"] =
|
|
||||||
&RaidZulAmanActionContext::zuljin_misdirect_boss_to_main_tank;
|
|
||||||
|
|
||||||
creators["zul'jin tanks position boss"] =
|
|
||||||
&RaidZulAmanActionContext::zuljin_tanks_position_boss;
|
|
||||||
|
|
||||||
creators["zul'jin run away from whirlwind"] =
|
|
||||||
&RaidZulAmanActionContext::zuljin_run_away_from_whirlwind;
|
|
||||||
|
|
||||||
creators["zul'jin avoid cyclones"] =
|
|
||||||
&RaidZulAmanActionContext::zuljin_avoid_cyclones;
|
|
||||||
|
|
||||||
creators["zul'jin spread ranged"] =
|
|
||||||
&RaidZulAmanActionContext::zuljin_spread_ranged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Trash
|
|
||||||
static Action* amanishi_medicine_man_mark_ward(
|
|
||||||
PlayerbotAI* botAI) { return new AmanishiMedicineManMarkWardAction(botAI); }
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
static Action* akilzon_misdirect_boss_to_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonMisdirectBossToMainTankAction(botAI); }
|
|
||||||
|
|
||||||
static Action* akilzon_tanks_position_boss(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonTanksPositionBossAction(botAI); }
|
|
||||||
|
|
||||||
static Action* akilzon_spread_ranged(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonSpreadRangedAction(botAI); }
|
|
||||||
|
|
||||||
static Action* akilzon_move_to_eye_of_the_storm(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonMoveToEyeOfTheStormAction(botAI); }
|
|
||||||
|
|
||||||
static Action* akilzon_manage_electrical_storm_timer(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonManageElectricalStormTimerAction(botAI); }
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
static Action* nalorakk_misdirect_boss_to_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new NalorakkMisdirectBossToMainTankAction(botAI); }
|
|
||||||
|
|
||||||
static Action* nalorakk_tanks_position_boss(
|
|
||||||
PlayerbotAI* botAI) { return new NalorakkTanksPositionBossAction(botAI); }
|
|
||||||
|
|
||||||
static Action* nalorakk_spread_ranged(
|
|
||||||
PlayerbotAI* botAI) { return new NalorakkSpreadRangedAction(botAI); }
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
static Action* janalai_misdirect_boss_to_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiMisdirectBossToMainTankAction(botAI); }
|
|
||||||
|
|
||||||
static Action* janalai_tanks_position_boss(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiTanksPositionBossAction(botAI); }
|
|
||||||
|
|
||||||
static Action* janalai_spread_ranged_in_circle(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiSpreadRangedInCircleAction(botAI); }
|
|
||||||
|
|
||||||
static Action* janalai_avoid_fire_bombs(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiAvoidFireBombsAction(botAI); }
|
|
||||||
|
|
||||||
static Action* janalai_mark_amanishi_hatchers(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiMarkAmanishiHatchersAction(botAI); }
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
static Action* halazzi_misdirect_boss_to_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziMisdirectBossToMainTankAction(botAI); }
|
|
||||||
|
|
||||||
static Action* halazzi_main_tank_position_boss(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziMainTankPositionBossAction(botAI); }
|
|
||||||
|
|
||||||
static Action* halazzi_first_assist_tank_attack_spirit_lynx(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziFirstAssistTankAttackSpiritLynxAction(botAI); }
|
|
||||||
|
|
||||||
static Action* halazzi_assign_dps_priority(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziAssignDpsPriorityAction(botAI); }
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
static Action* hex_lord_malacrass_misdirect_boss_to_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassMisdirectBossToMainTankAction(botAI); }
|
|
||||||
|
|
||||||
static Action* hex_lord_malacrass_assign_dps_priority(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassAssignDpsPriorityAction(botAI); }
|
|
||||||
|
|
||||||
static Action* hex_lord_malacrass_run_away_from_whirlwind(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassRunAwayFromWhirlwindAction(botAI); }
|
|
||||||
|
|
||||||
static Action* hex_lord_malacrass_casters_stop_attacking(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassCastersStopAttackingAction(botAI); }
|
|
||||||
|
|
||||||
static Action* hex_lord_malacrass_move_away_from_freezing_trap(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassMoveAwayFromFreezingTrapAction(botAI); }
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
static Action* zuljin_misdirect_boss_to_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinMisdirectBossToMainTankAction(botAI); }
|
|
||||||
|
|
||||||
static Action* zuljin_tanks_position_boss(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinTanksPositionBossAction(botAI); }
|
|
||||||
|
|
||||||
static Action* zuljin_run_away_from_whirlwind(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinRunAwayFromWhirlwindAction(botAI); }
|
|
||||||
|
|
||||||
static Action* zuljin_avoid_cyclones(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinAvoidCyclonesAction(botAI); }
|
|
||||||
|
|
||||||
static Action* zuljin_spread_ranged(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinSpreadRangedAction(botAI); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,206 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANTRIGGERCONTEXT_H
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANTRIGGERCONTEXT_H
|
|
||||||
|
|
||||||
#include "RaidZulAmanTriggers.h"
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
|
|
||||||
class RaidZulAmanTriggerContext : public NamedObjectContext<Trigger>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RaidZulAmanTriggerContext()
|
|
||||||
{
|
|
||||||
// Trash
|
|
||||||
creators["amani'shi medicine man summoned ward"] =
|
|
||||||
&RaidZulAmanTriggerContext::amanishi_medicine_man_summoned_ward;
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
creators["akil'zon pulling boss"] =
|
|
||||||
&RaidZulAmanTriggerContext::akilzon_pulling_boss;
|
|
||||||
|
|
||||||
creators["akil'zon boss engaged by tanks"] =
|
|
||||||
&RaidZulAmanTriggerContext::akilzon_boss_engaged_by_tanks;
|
|
||||||
|
|
||||||
creators["akil'zon boss casts static disruption"] =
|
|
||||||
&RaidZulAmanTriggerContext::akilzon_boss_casts_static_disruption;
|
|
||||||
|
|
||||||
creators["akil'zon electrical storm incoming"] =
|
|
||||||
&RaidZulAmanTriggerContext::akilzon_electrical_storm_incoming;
|
|
||||||
|
|
||||||
creators["akil'zon bots need to prepare for electrical storm"] =
|
|
||||||
&RaidZulAmanTriggerContext::akilzon_bots_need_to_prepare_for_electrical_storm;
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
creators["nalorakk pulling boss"] =
|
|
||||||
&RaidZulAmanTriggerContext::nalorakk_pulling_boss;
|
|
||||||
|
|
||||||
creators["nalorakk boss casts surge"] =
|
|
||||||
&RaidZulAmanTriggerContext::nalorakk_boss_casts_surge;
|
|
||||||
|
|
||||||
creators["nalorakk boss switches forms"] =
|
|
||||||
&RaidZulAmanTriggerContext::nalorakk_boss_switches_forms;
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
creators["jan'alai pulling boss"] =
|
|
||||||
&RaidZulAmanTriggerContext::janalai_pulling_boss;
|
|
||||||
|
|
||||||
creators["jan'alai boss engaged by tanks"] =
|
|
||||||
&RaidZulAmanTriggerContext::janalai_boss_engaged_by_tanks;
|
|
||||||
|
|
||||||
creators["jan'alai boss casts flame breath"] =
|
|
||||||
&RaidZulAmanTriggerContext::janalai_boss_casts_flame_breath;
|
|
||||||
|
|
||||||
creators["jan'alai boss summoning fire bombs"] =
|
|
||||||
&RaidZulAmanTriggerContext::janalai_boss_summoning_fire_bombs;
|
|
||||||
|
|
||||||
creators["jan'alai amani'shi hatchers spawned"] =
|
|
||||||
&RaidZulAmanTriggerContext::janalai_amanishi_hatchers_spawned;
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
creators["halazzi pulling boss"] =
|
|
||||||
&RaidZulAmanTriggerContext::halazzi_pulling_boss;
|
|
||||||
|
|
||||||
creators["halazzi boss engaged by main tank"] =
|
|
||||||
&RaidZulAmanTriggerContext::halazzi_boss_engaged_by_main_tank;
|
|
||||||
|
|
||||||
creators["halazzi boss summons spirit lynx"] =
|
|
||||||
&RaidZulAmanTriggerContext::halazzi_boss_summons_spirit_lynx;
|
|
||||||
|
|
||||||
creators["halazzi determining dps target"] =
|
|
||||||
&RaidZulAmanTriggerContext::halazzi_determining_dps_target;
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
creators["hex lord malacrass pulling boss"] =
|
|
||||||
&RaidZulAmanTriggerContext::hex_lord_malacrass_pulling_boss;
|
|
||||||
|
|
||||||
creators["hex lord malacrass determining kill order"] =
|
|
||||||
&RaidZulAmanTriggerContext::hex_lord_malacrass_determining_kill_order;
|
|
||||||
|
|
||||||
creators["hex lord malacrass boss is channeling whirlwind"] =
|
|
||||||
&RaidZulAmanTriggerContext::hex_lord_malacrass_boss_is_channeling_whirlwind;
|
|
||||||
|
|
||||||
creators["hex lord malacrass boss has spell reflection"] =
|
|
||||||
&RaidZulAmanTriggerContext::hex_lord_malacrass_boss_has_spell_reflection;
|
|
||||||
|
|
||||||
creators["hex lord malacrass boss placed freezing trap"] =
|
|
||||||
&RaidZulAmanTriggerContext::hex_lord_malacrass_boss_placed_freezing_trap;
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
creators["zul'jin main tank needs aggro upon pull or phase change"] =
|
|
||||||
&RaidZulAmanTriggerContext::zuljin_main_tank_needs_aggro_upon_pull_or_phase_change;
|
|
||||||
|
|
||||||
creators["zul'jin boss engaged by tanks"] =
|
|
||||||
&RaidZulAmanTriggerContext::zuljin_boss_engaged_by_tanks;
|
|
||||||
|
|
||||||
creators["zul'jin boss is channeling whirlwind in troll form"] =
|
|
||||||
&RaidZulAmanTriggerContext::zuljin_boss_is_channeling_whirlwind_in_troll_form;
|
|
||||||
|
|
||||||
creators["zul'jin boss is summoning cyclones in eagle form"] =
|
|
||||||
&RaidZulAmanTriggerContext::zuljin_boss_is_summoning_cyclones_in_eagle_form;
|
|
||||||
|
|
||||||
creators["zul'jin boss casts aoe abilities in dragonhawk form"] =
|
|
||||||
&RaidZulAmanTriggerContext::zuljin_boss_casts_aoe_abilities_in_dragonhawk_form;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Trash
|
|
||||||
static Trigger* amanishi_medicine_man_summoned_ward(
|
|
||||||
PlayerbotAI* botAI) { return new AmanishiMedicineManSummonedWardTrigger(botAI); }
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
static Trigger* akilzon_pulling_boss(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonPullingBossTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* akilzon_boss_engaged_by_tanks(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonBossEngagedByTanksTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* akilzon_boss_casts_static_disruption(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonBossCastsStaticDisruptionTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* akilzon_electrical_storm_incoming(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonElectricalStormIncomingTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* akilzon_bots_need_to_prepare_for_electrical_storm(
|
|
||||||
PlayerbotAI* botAI) { return new AkilzonBotsNeedToPrepareForElectricalStormTrigger(botAI); }
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
static Trigger* nalorakk_pulling_boss(
|
|
||||||
PlayerbotAI* botAI) { return new NalorakkPullingBossTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* nalorakk_boss_casts_surge(
|
|
||||||
PlayerbotAI* botAI) { return new NalorakkBossCastsSurgeTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* nalorakk_boss_switches_forms(
|
|
||||||
PlayerbotAI* botAI) { return new NalorakkBossSwitchesFormsTrigger(botAI); }
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
static Trigger* janalai_pulling_boss(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiPullingBossTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* janalai_boss_engaged_by_tanks(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiBossEngagedByTanksTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* janalai_boss_casts_flame_breath(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiBossCastsFlameBreathTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* janalai_boss_summoning_fire_bombs(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiBossSummoningFireBombsTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* janalai_amanishi_hatchers_spawned(
|
|
||||||
PlayerbotAI* botAI) { return new JanalaiAmanishiHatchersSpawnedTrigger(botAI); }
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
static Trigger* halazzi_pulling_boss(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziPullingBossTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* halazzi_boss_engaged_by_main_tank(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziBossEngagedByMainTankTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* halazzi_boss_summons_spirit_lynx(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziBossSummonsSpiritLynxTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* halazzi_determining_dps_target(
|
|
||||||
PlayerbotAI* botAI) { return new HalazziDeterminingDpsTargetTrigger(botAI); }
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
static Trigger* hex_lord_malacrass_pulling_boss(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassPullingBossTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* hex_lord_malacrass_determining_kill_order(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassDeterminingKillOrderTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* hex_lord_malacrass_boss_is_channeling_whirlwind(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassBossIsChannelingWhirlwindTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* hex_lord_malacrass_boss_has_spell_reflection(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassBossHasSpellReflectionTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* hex_lord_malacrass_boss_placed_freezing_trap(
|
|
||||||
PlayerbotAI* botAI) { return new HexLordMalacrassBossPlacedFreezingTrapTrigger(botAI); }
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
static Trigger* zuljin_boss_engaged_by_tanks(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinBossEngagedByTanksTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* zuljin_main_tank_needs_aggro_upon_pull_or_phase_change(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinMainTankNeedsAggroUponPullOrPhaseChangeTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* zuljin_boss_is_channeling_whirlwind_in_troll_form(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinBossIsChannelingWhirlwindInTrollFormTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* zuljin_boss_is_summoning_cyclones_in_eagle_form(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinBossIsSummoningCyclonesInEagleFormTrigger(botAI); }
|
|
||||||
|
|
||||||
static Trigger* zuljin_boss_casts_aoe_abilities_in_dragonhawk_form(
|
|
||||||
PlayerbotAI* botAI) { return new ZuljinBossCastsAoeAbilitiesInDragonhawkFormTrigger(botAI); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RaidZulAmanStrategy.h"
|
|
||||||
#include "RaidZulAmanMultipliers.h"
|
|
||||||
|
|
||||||
void RaidZulAmanStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|
||||||
{
|
|
||||||
// Trash
|
|
||||||
triggers.push_back(new TriggerNode("amani'shi medicine man summoned ward", {
|
|
||||||
NextAction("amani'shi medicine man mark ward", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
triggers.push_back(new TriggerNode("akil'zon pulling boss", {
|
|
||||||
NextAction("akil'zon misdirect boss to main tank", ACTION_RAID + 2) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("akil'zon boss engaged by main tank", {
|
|
||||||
NextAction("akil'zon main tank position boss", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("akil'zon boss casts static disruption", {
|
|
||||||
NextAction("akil'zon spread ranged", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("akil'zon electrical storm incoming", {
|
|
||||||
NextAction("akil'zon move to eye of the storm", ACTION_EMERGENCY + 6) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("akil'zon bots need to prepare for electrical storm", {
|
|
||||||
NextAction("akil'zon manage electrical storm timer", ACTION_EMERGENCY + 10) }));
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
triggers.push_back(new TriggerNode("nalorakk pulling boss", {
|
|
||||||
NextAction("nalorakk misdirect boss to main tank", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("nalorakk boss switches forms", {
|
|
||||||
NextAction("nalorakk tanks position boss", ACTION_EMERGENCY + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("nalorakk boss casts surge", {
|
|
||||||
NextAction("nalorakk spread ranged", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
triggers.push_back(new TriggerNode("jan'alai pulling boss", {
|
|
||||||
NextAction("jan'alai misdirect boss to main tank", ACTION_RAID + 2) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("jan'alai boss engaged by main tank", {
|
|
||||||
NextAction("jan'alai main tank position boss", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("jan'alai boss casts flame breath", {
|
|
||||||
NextAction("jan'alai spread ranged in circle", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("jan'alai boss summoning fire bombs", {
|
|
||||||
NextAction("jan'alai avoid fire bombs", ACTION_EMERGENCY + 6) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("jan'alai amani'shi hatchers spawned", {
|
|
||||||
NextAction("jan'alai mark amani'shi hatchers", ACTION_RAID + 2) }));
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
triggers.push_back(new TriggerNode("halazzi pulling boss", {
|
|
||||||
NextAction("halazzi misdirect boss to main tank", ACTION_RAID + 2) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("halazzi boss engaged by main tank", {
|
|
||||||
NextAction("halazzi main tank position boss", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("halazzi boss summons spirit lynx", {
|
|
||||||
NextAction("halazzi first assist tank attack spirit lynx", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("halazzi determining dps target", {
|
|
||||||
NextAction("halazzi assign dps priority", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
triggers.push_back(new TriggerNode("hex lord malacrass pulling boss", {
|
|
||||||
NextAction("hex lord malacrass misdirect boss to main tank", ACTION_RAID + 2) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("hex lord malacrass determining kill order", {
|
|
||||||
NextAction("hex lord malacrass assign dps priority", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("hex lord malacrass boss is channeling whirlwind", {
|
|
||||||
NextAction("hex lord malacrass run away from whirlwind", ACTION_EMERGENCY + 6) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("hex lord malacrass boss has spell reflection", {
|
|
||||||
NextAction("hex lord malacrass casters stop attacking", ACTION_EMERGENCY + 6) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("hex lord malacrass boss placed freezing trap", {
|
|
||||||
NextAction("hex lord malacrass move away from freezing trap", ACTION_EMERGENCY + 1) }));
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
triggers.push_back(new TriggerNode("zul'jin main tank needs aggro upon pull or phase change", {
|
|
||||||
NextAction("zul'jin misdirect boss to main tank", ACTION_RAID + 2) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("zul'jin boss engaged by main tank", {
|
|
||||||
NextAction("zul'jin main tank position boss", ACTION_RAID + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("zul'jin boss is channeling whirlwind in troll form", {
|
|
||||||
NextAction("zul'jin run away from whirlwind", ACTION_EMERGENCY + 6) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("zul'jin boss is summoning cyclones in eagle form", {
|
|
||||||
NextAction("zul'jin avoid cyclones", ACTION_EMERGENCY + 1) }));
|
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("zul'jin boss casts aoe abilities in dragonhawk form", {
|
|
||||||
NextAction("zul'jin spread ranged", ACTION_RAID + 1) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void RaidZulAmanStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|
||||||
{
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
multipliers.push_back(new AkilzonDisableCombatFormationMoveMultiplier(botAI));
|
|
||||||
multipliers.push_back(new AkilzonStayInEyeOfTheStormMultiplier(botAI));
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
multipliers.push_back(new NalorakkDisableTankActionsMultiplier(botAI));
|
|
||||||
multipliers.push_back(new NalorakkControlMisdirectionMultiplier(botAI));
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
multipliers.push_back(new JanalaiDisableTankActionsMultiplier(botAI));
|
|
||||||
multipliers.push_back(new JanalaiDisableCombatFormationMoveMultiplier(botAI));
|
|
||||||
multipliers.push_back(new JanalaiStayAwayFromFireBombsMultiplier(botAI));
|
|
||||||
multipliers.push_back(new JanalaiDoNotCrowdControlHatchersMultiplier(botAI));
|
|
||||||
multipliers.push_back(new JanalaiDelayBloodlustAndHeroismMultiplier(botAI));
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
multipliers.push_back(new HalazziDisableTankActionsMultiplier(botAI));
|
|
||||||
multipliers.push_back(new HalazziControlMisdirectionMultiplier(botAI));
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
multipliers.push_back(new HexLordMalacrassAvoidWhirlwindMultiplier(botAI));
|
|
||||||
multipliers.push_back(new HexLordMalacrassStopAttackingDuringSpellReflectionMultiplier(botAI));
|
|
||||||
multipliers.push_back(new HexLordMalacrassDoNotDispelUnstableAfflictionMultiplier(botAI));
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
multipliers.push_back(new ZuljinDisableTankFaceMultiplier(botAI));
|
|
||||||
multipliers.push_back(new ZuljinAvoidWhirlwindMultiplier(botAI));
|
|
||||||
multipliers.push_back(new ZuljinDisableAvoidAoeMultiplier(botAI));
|
|
||||||
multipliers.push_back(new ZuljinDelayBloodlustAndHeroismMultiplier(botAI));
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANSTRATEGY_H_
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANSTRATEGY_H_
|
|
||||||
|
|
||||||
#include "Strategy.h"
|
|
||||||
#include "Multiplier.h"
|
|
||||||
|
|
||||||
class RaidZulAmanStrategy : public Strategy
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RaidZulAmanStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
|
||||||
|
|
||||||
std::string const getName() override { return "zulaman"; }
|
|
||||||
|
|
||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
|
||||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,271 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RaidZulAmanTriggers.h"
|
|
||||||
#include "RaidZulAmanHelpers.h"
|
|
||||||
#include "RaidZulAmanActions.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
#include "RaidBossHelpers.h"
|
|
||||||
|
|
||||||
using namespace ZulAmanHelpers;
|
|
||||||
|
|
||||||
// Trash
|
|
||||||
|
|
||||||
bool AmanishiMedicineManSummonedWardTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return AI_VALUE2(Unit*, "find target", "amani'shi medicine man");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
|
|
||||||
bool AkilzonPullingBossTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* akilzon = AI_VALUE2(Unit*, "find target", "akil'zon");
|
|
||||||
return akilzon && akilzon->GetHealthPct() > 95.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonBossEngagedByTanksTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "akil'zon"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !GetElectricalStormTarget(bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonBossCastsStaticDisruptionTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsRanged(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "akil'zon"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto it = akilzonStormTimer.find(bot->GetMap()->GetInstanceId());
|
|
||||||
if (it == akilzonStormTimer.end())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return !IsInStormWindow(it->second, std::time(nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonElectricalStormIncomingTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!AI_VALUE2(Unit*, "find target", "akil'zon"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto it = akilzonStormTimer.find(bot->GetMap()->GetInstanceId());
|
|
||||||
if (it == akilzonStormTimer.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return IsInStormWindow(it->second, std::time(nullptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkilzonBotsNeedToPrepareForElectricalStormTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return IsMechanicTrackerBot(botAI, bot, ZULAMAN_MAP_ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
|
|
||||||
bool NalorakkPullingBossTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* nalorakk = AI_VALUE2(Unit*, "find target", "nalorakk");
|
|
||||||
return nalorakk && nalorakk->GetHealthPct() > 95.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NalorakkBossSwitchesFormsTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0, true)) &&
|
|
||||||
AI_VALUE2(Unit*, "find target", "nalorakk");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool NalorakkBossCastsSurgeTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return botAI->IsRanged(bot) &&
|
|
||||||
AI_VALUE2(Unit*, "find target", "nalorakk");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
|
|
||||||
bool JanalaiPullingBossTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* janalai = AI_VALUE2(Unit*, "find target", "jan'alai");
|
|
||||||
return janalai && janalai->GetHealthPct() > 95.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiBossEngagedByTanksTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "jan'alai"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !HasFireBombNearby(botAI, bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiBossCastsFlameBreathTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsRanged(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "jan'alai") ||
|
|
||||||
AI_VALUE2(Unit*, "find target", "amani dragonhawk hatchling"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !HasFireBombNearby(botAI, bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiBossSummoningFireBombsTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return AI_VALUE2(Unit*, "find target", "jan'alai") &&
|
|
||||||
HasFireBombNearby(botAI, bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool JanalaiAmanishiHatchersSpawnedTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsRangedDps(bot) ||
|
|
||||||
!AI_VALUE2(Unit*, "find target", "jan'alai"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return bot->FindNearestCreature(
|
|
||||||
static_cast<uint32>(ZulAmanNPCs::NPC_AMANISHI_HATCHER), 40.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
|
|
||||||
bool HalazziPullingBossTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* halazzi = AI_VALUE2(Unit*, "find target", "halazzi");
|
|
||||||
return halazzi && halazzi->GetHealthPct() > 95.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HalazziBossEngagedByMainTankTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return botAI->IsMainTank(bot) &&
|
|
||||||
AI_VALUE2(Unit*, "find target", "halazzi");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HalazziBossSummonsSpiritLynxTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return botAI->IsAssistTankOfIndex(bot, 0, true) &&
|
|
||||||
AI_VALUE2(Unit*, "find target", "halazzi");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HalazziDeterminingDpsTargetTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return botAI->IsDps(bot) &&
|
|
||||||
AI_VALUE2(Unit*, "find target", "halazzi");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
bool HexLordMalacrassPullingBossTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
return malacrass && malacrass->GetHealthPct() > 95.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassDeterminingKillOrderTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return botAI->IsDps(bot) &&
|
|
||||||
AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassBossIsChannelingWhirlwindTrigger::IsActive()
|
|
||||||
{
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
if (!malacrass ||
|
|
||||||
!malacrass->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_HEX_LORD_WHIRLWIND)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !(botAI->IsTank(bot) && malacrass->GetVictim() == bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassBossHasSpellReflectionTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsCaster(bot))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* malacrass = AI_VALUE2(Unit*, "find target", "hex lord malacrass");
|
|
||||||
return malacrass &&
|
|
||||||
malacrass->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_HEX_LORD_SPELL_REFLECTION));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HexLordMalacrassBossPlacedFreezingTrapTrigger::IsActive()
|
|
||||||
{
|
|
||||||
return AI_VALUE2(Unit*, "find target", "hex lord malacrass") &&
|
|
||||||
bot->FindNearestGameObject(
|
|
||||||
static_cast<uint32>(ZulAmanObjects::GO_FREEZING_TRAP), 20.0f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
bool ZuljinMainTankNeedsAggroUponPullOrPhaseChangeTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (bot->getClass() != CLASS_HUNTER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float hp = zuljin->GetHealthPct();
|
|
||||||
|
|
||||||
return (hp <= 100.0f && hp > 95.0f) ||
|
|
||||||
(hp <= 80.0f && hp > 75.0f &&
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_BEAR))) ||
|
|
||||||
(hp <= 40.0f && hp > 35.0f &&
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_LYNX))) ||
|
|
||||||
(hp <= 20.0f && hp > 15.0f &&
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_DRAGONHAWK)));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinBossEngagedByTanksTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsTank(bot))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
return zuljin &&
|
|
||||||
!zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_EAGLE)) &&
|
|
||||||
!zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_DRAGONHAWK));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinBossIsChannelingWhirlwindInTrollFormTrigger::IsActive()
|
|
||||||
{
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
if (!zuljin ||
|
|
||||||
!zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_ZULJIN_WHIRLWIND)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !(botAI->IsTank(bot) && zuljin->GetVictim() == bot);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinBossIsSummoningCyclonesInEagleFormTrigger::IsActive()
|
|
||||||
{
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
return zuljin &&
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_EAGLE));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ZuljinBossCastsAoeAbilitiesInDragonhawkFormTrigger::IsActive()
|
|
||||||
{
|
|
||||||
if (!botAI->IsRanged(bot))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unit* zuljin = AI_VALUE2(Unit*, "find target", "zul'jin");
|
|
||||||
return zuljin &&
|
|
||||||
zuljin->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_SHAPE_OF_THE_DRAGONHAWK));
|
|
||||||
}
|
|
||||||
@ -1,249 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANTRIGGERS_H
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANTRIGGERS_H
|
|
||||||
|
|
||||||
#include "Trigger.h"
|
|
||||||
|
|
||||||
// Trash
|
|
||||||
|
|
||||||
class AmanishiMedicineManSummonedWardTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AmanishiMedicineManSummonedWardTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "amani'shi medicine man summoned ward") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
|
|
||||||
class AkilzonPullingBossTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonPullingBossTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "akil'zon pulling boss") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonBossEngagedByTanksTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonBossEngagedByTanksTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "akil'zon boss engaged by tanks") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonBossCastsStaticDisruptionTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonBossCastsStaticDisruptionTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "akil'zon boss casts static disruption") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonElectricalStormIncomingTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonElectricalStormIncomingTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "akil'zon electrical storm incoming") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AkilzonBotsNeedToPrepareForElectricalStormTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AkilzonBotsNeedToPrepareForElectricalStormTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "akil'zon bots need to prepare for electrical storm") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
|
|
||||||
class NalorakkPullingBossTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkPullingBossTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "nalorakk pulling boss") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NalorakkBossSwitchesFormsTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkBossSwitchesFormsTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "nalorakk boss switches forms") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NalorakkBossCastsSurgeTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NalorakkBossCastsSurgeTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "nalorakk boss casts surge") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
|
|
||||||
class JanalaiPullingBossTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiPullingBossTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "jan'alai pulling boss") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiBossEngagedByTanksTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiBossEngagedByTanksTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "jan'alai boss engaged by tanks") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiBossCastsFlameBreathTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiBossCastsFlameBreathTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "jan'alai boss casts flame breath") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiBossSummoningFireBombsTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiBossSummoningFireBombsTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "jan'alai boss summoning fire bombs") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class JanalaiAmanishiHatchersSpawnedTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
JanalaiAmanishiHatchersSpawnedTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "jan'alai amani'shi hatchers spawned") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
|
|
||||||
class HalazziPullingBossTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziPullingBossTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "halazzi pulling boss") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziBossEngagedByMainTankTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziBossEngagedByMainTankTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "halazzi boss engaged by main tank") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziBossSummonsSpiritLynxTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziBossSummonsSpiritLynxTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "halazzi boss summons spirit lynx") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HalazziDeterminingDpsTargetTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HalazziDeterminingDpsTargetTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "halazzi determining dps target") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
|
|
||||||
class HexLordMalacrassPullingBossTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassPullingBossTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "hex lord malacrass pulling boss") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassDeterminingKillOrderTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassDeterminingKillOrderTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "hex lord malacrass determining kill order") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassBossIsChannelingWhirlwindTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassBossIsChannelingWhirlwindTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "hex lord malacrass boss is channeling whirlwind") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassBossHasSpellReflectionTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassBossHasSpellReflectionTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "hex lord malacrass boss has spell reflection") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class HexLordMalacrassBossPlacedFreezingTrapTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HexLordMalacrassBossPlacedFreezingTrapTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "hex lord malacrass boss placed freezing trap") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
|
|
||||||
class ZuljinMainTankNeedsAggroUponPullOrPhaseChangeTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinMainTankNeedsAggroUponPullOrPhaseChangeTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "zul'jin main tank needs aggro upon pull or phase change") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinBossEngagedByTanksTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinBossEngagedByTanksTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "zul'jin boss engaged by tanks") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinBossIsChannelingWhirlwindInTrollFormTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinBossIsChannelingWhirlwindInTrollFormTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "zul'jin boss is channeling whirlwind in troll form") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinBossIsSummoningCyclonesInEagleFormTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinBossIsSummoningCyclonesInEagleFormTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "zul'jin boss is summoning cyclones in eagle form") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ZuljinBossCastsAoeAbilitiesInDragonhawkFormTrigger : public Trigger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ZuljinBossCastsAoeAbilitiesInDragonhawkFormTrigger(
|
|
||||||
PlayerbotAI* botAI) : Trigger(botAI, "zul'jin boss casts aoe abilities in dragonhawk form") {}
|
|
||||||
bool IsActive() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RaidZulAmanHelpers.h"
|
|
||||||
#include "Group.h"
|
|
||||||
#include "Playerbots.h"
|
|
||||||
|
|
||||||
namespace ZulAmanHelpers
|
|
||||||
{
|
|
||||||
// General
|
|
||||||
Position FindSafestNearbyPosition(Player* bot,
|
|
||||||
const std::vector<Unit*>& hazards, const Position& safeZoneCenter,
|
|
||||||
float safeZoneRadius, float hazardRadius, bool requireSafePath)
|
|
||||||
{
|
|
||||||
constexpr float searchStep = M_PI / 8.0f;
|
|
||||||
constexpr float distanceStep = 1.0f;
|
|
||||||
|
|
||||||
Position bestPos;
|
|
||||||
float minMoveDistance = std::numeric_limits<float>::max();
|
|
||||||
bool foundSafe = false;
|
|
||||||
|
|
||||||
for (float distance = 0.0f;
|
|
||||||
distance <= safeZoneRadius; distance += distanceStep)
|
|
||||||
{
|
|
||||||
for (float angle = 0.0f; angle < 2 * M_PI; angle += searchStep)
|
|
||||||
{
|
|
||||||
float x = bot->GetPositionX() + distance * std::cos(angle);
|
|
||||||
float y = bot->GetPositionY() + distance * std::sin(angle);
|
|
||||||
|
|
||||||
if (safeZoneCenter.GetExactDist2d(x, y) > safeZoneRadius)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!IsPositionSafeFromHazards(x, y, hazards, hazardRadius))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Position testPos(x, y, bot->GetPositionZ());
|
|
||||||
|
|
||||||
bool pathSafe = true;
|
|
||||||
if (requireSafePath)
|
|
||||||
{
|
|
||||||
pathSafe =
|
|
||||||
IsPathSafeFromHazards(bot->GetPosition(), testPos, hazards, hazardRadius);
|
|
||||||
if (!pathSafe)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float moveDistance = bot->GetExactDist2d(x, y);
|
|
||||||
if (!foundSafe || moveDistance < minMoveDistance)
|
|
||||||
{
|
|
||||||
bestPos = testPos;
|
|
||||||
minMoveDistance = moveDistance;
|
|
||||||
foundSafe = pathSafe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!IsPositionSafeFromHazards(checkX, checkY, hazards, hazardRadius))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsPositionSafeFromHazards(
|
|
||||||
float x, float y, const std::vector<Unit*>& hazards, float hazardRadius)
|
|
||||||
{
|
|
||||||
for (Unit* hazard : hazards)
|
|
||||||
{
|
|
||||||
if (hazard->GetDistance2d(x, y) < hazardRadius)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Unit*> GetAllHazardTriggers(Player* bot, uint32 entry, float searchRadius)
|
|
||||||
{
|
|
||||||
std::vector<Unit*> triggers;
|
|
||||||
std::list<Creature*> creatureList;
|
|
||||||
bot->GetCreatureListWithEntryInGrid(creatureList, entry, searchRadius);
|
|
||||||
|
|
||||||
for (Creature* creature : creatureList)
|
|
||||||
{
|
|
||||||
if (creature && creature->IsAlive())
|
|
||||||
triggers.push_back(creature);
|
|
||||||
}
|
|
||||||
|
|
||||||
return triggers;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
const Position AKILZON_TANK_POSITION = { 378.369f, 1407.718f, 74.797f };
|
|
||||||
std::unordered_map<uint32, time_t> akilzonStormTimer;
|
|
||||||
|
|
||||||
bool IsInStormWindow(time_t start, time_t now)
|
|
||||||
{
|
|
||||||
time_t elapsed = now - start;
|
|
||||||
uint32 seconds = elapsed % 60;
|
|
||||||
return elapsed >= 55 && (seconds >= 55 || seconds < 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
Player* GetElectricalStormTarget(Player* bot)
|
|
||||||
{
|
|
||||||
Group* group = bot->GetGroup();
|
|
||||||
if (!group)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
|
||||||
{
|
|
||||||
Player* member = ref->GetSource();
|
|
||||||
if (member &&
|
|
||||||
member->HasAura(static_cast<uint32>(ZulAmanSpells::SPELL_ELECTRICAL_STORM)))
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
const Position NALORAKK_TANK_POSITION = { -80.208f, 1324.530f, 40.942f };
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
const Position JANALAI_TANK_POSITION = { -33.873f, 1149.571f, 19.146f };
|
|
||||||
|
|
||||||
bool HasFireBombNearby(PlayerbotAI* botAI, Player* bot)
|
|
||||||
{
|
|
||||||
constexpr float searchRadius = 30.0f;
|
|
||||||
std::list<Creature*> creatureList;
|
|
||||||
bot->GetCreatureListWithEntryInGrid(
|
|
||||||
creatureList, static_cast<uint32>(ZulAmanNPCs::NPC_FIRE_BOMB), searchRadius);
|
|
||||||
|
|
||||||
for (Creature* creature : creatureList)
|
|
||||||
{
|
|
||||||
if (creature && creature->IsAlive())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<Unit*, Unit*> GetAmanishiHatcherPair(PlayerbotAI* botAI)
|
|
||||||
{
|
|
||||||
Unit* lowest = nullptr;
|
|
||||||
Unit* highest = nullptr;
|
|
||||||
|
|
||||||
for (auto const& guid :
|
|
||||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los")->Get())
|
|
||||||
{
|
|
||||||
Unit* unit = botAI->GetUnit(guid);
|
|
||||||
if (unit &&
|
|
||||||
unit->GetEntry() == static_cast<uint32>(ZulAmanNPCs::NPC_AMANISHI_HATCHER))
|
|
||||||
{
|
|
||||||
if (!lowest || unit->GetGUID().GetCounter() < lowest->GetGUID().GetCounter())
|
|
||||||
lowest = unit;
|
|
||||||
|
|
||||||
if (!highest || unit->GetGUID().GetCounter() > highest->GetGUID().GetCounter())
|
|
||||||
highest = unit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {lowest, highest};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
const Position HALAZZI_TANK_POSITION = { 370.733f, 1131.202f, 6.516f };
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
const Position ZULJIN_TANK_POSITION = { 120.210f, 705.564f, 45.111f };
|
|
||||||
}
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
||||||
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PLAYERBOT_RAIDZULAMANHELPERS_H_
|
|
||||||
#define _PLAYERBOT_RAIDZULAMANHELPERS_H_
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "AiObject.h"
|
|
||||||
#include "Position.h"
|
|
||||||
#include "Unit.h"
|
|
||||||
|
|
||||||
namespace ZulAmanHelpers
|
|
||||||
{
|
|
||||||
enum class ZulAmanSpells : uint32
|
|
||||||
{
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
SPELL_ELECTRICAL_STORM = 43648,
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
SPELL_BEARFORM = 42377,
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
SPELL_HEX_LORD_WHIRLWIND = 43442,
|
|
||||||
SPELL_HEX_LORD_SPELL_REFLECTION = 43443,
|
|
||||||
SPELL_UNSTABLE_AFFLICTION = 43522,
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
SPELL_ZULJIN_WHIRLWIND = 17207,
|
|
||||||
SPELL_SHAPE_OF_THE_BEAR = 42594,
|
|
||||||
SPELL_SHAPE_OF_THE_EAGLE = 42606,
|
|
||||||
SPELL_SHAPE_OF_THE_LYNX = 42607,
|
|
||||||
SPELL_SHAPE_OF_THE_DRAGONHAWK = 42608,
|
|
||||||
// SPELL_CLAW_RAGE = 43149, // Would require getting Zul'jin's bossai
|
|
||||||
|
|
||||||
// Hunter
|
|
||||||
SPELL_MISDIRECTION = 35079,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ZulAmanNPCs : uint32
|
|
||||||
{
|
|
||||||
// Trash
|
|
||||||
NPC_AMANI_HEALING_WARD = 23757,
|
|
||||||
NPC_AMANI_PROTECTIVE_WARD = 23822,
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
NPC_AMANI_DRAGONHAWK_HATCHLING = 23598,
|
|
||||||
NPC_AMANISHI_HATCHER = 23818,
|
|
||||||
NPC_FIRE_BOMB = 23920,
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
NPC_CORRUPTED_LIGHTNING_TOTEM = 24224,
|
|
||||||
|
|
||||||
// Hex Lord Malacrass
|
|
||||||
NPC_HEX_LORD_MALACRASS = 24239,
|
|
||||||
NPC_ALYSON_ANTILLE = 24240,
|
|
||||||
NPC_THURG = 24241,
|
|
||||||
NPC_SLITHER = 24242,
|
|
||||||
NPC_LORD_RAADAN = 24243,
|
|
||||||
NPC_GAZAKROTH = 24244,
|
|
||||||
NPC_FENSTALKER = 24245,
|
|
||||||
NPC_DARKHEART = 24246,
|
|
||||||
NPC_KORAGG = 24247,
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
NPC_FEATHER_VORTEX = 24136,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ZulAmanObjects : uint32
|
|
||||||
{
|
|
||||||
GO_FREEZING_TRAP = 186669,
|
|
||||||
};
|
|
||||||
|
|
||||||
// General
|
|
||||||
constexpr uint32 ZULAMAN_MAP_ID = 568;
|
|
||||||
Position FindSafestNearbyPosition(
|
|
||||||
Player* bot, const std::vector<Unit*>& hazards, const Position& center,
|
|
||||||
float safeZoneRadius, float hazardRadius, bool requireSafePath);
|
|
||||||
bool IsPathSafeFromHazards(
|
|
||||||
const Position& start, const Position& end,
|
|
||||||
const std::vector<Unit*>& hazards, float hazardRadius);
|
|
||||||
bool IsPositionSafeFromHazards(
|
|
||||||
float x, float y, const std::vector<Unit*>& hazards, float hazardRadius);
|
|
||||||
std::vector<Unit*> GetAllHazardTriggers(
|
|
||||||
Player* bot, uint32 entry, float searchRadius);
|
|
||||||
|
|
||||||
// Akil'zon <Eagle Avatar>
|
|
||||||
extern const Position AKILZON_TANK_POSITION;
|
|
||||||
extern std::unordered_map<uint32, time_t> akilzonStormTimer;
|
|
||||||
bool IsInStormWindow(time_t start, time_t now);
|
|
||||||
Player* GetElectricalStormTarget(Player* bot);
|
|
||||||
|
|
||||||
// Nalorakk <Bear Avatar>
|
|
||||||
extern const Position NALORAKK_TANK_POSITION;
|
|
||||||
|
|
||||||
// Jan'alai <Dragonhawk Avatar>
|
|
||||||
extern const Position JANALAI_TANK_POSITION;
|
|
||||||
bool HasFireBombNearby(PlayerbotAI* botAI, Player* bot);
|
|
||||||
std::pair<Unit*, Unit*> GetAmanishiHatcherPair(PlayerbotAI* botAI);
|
|
||||||
|
|
||||||
// Halazzi <Lynx Avatar>
|
|
||||||
extern const Position HALAZZI_TANK_POSITION;
|
|
||||||
|
|
||||||
// Zul'jin
|
|
||||||
extern const Position ZULJIN_TANK_POSITION;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -11,7 +11,6 @@
|
|||||||
#include "Ai/Raid/Magtheridon/RaidMagtheridonActionContext.h"
|
#include "Ai/Raid/Magtheridon/RaidMagtheridonActionContext.h"
|
||||||
#include "Ai/Raid/SerpentshrineCavern/RaidSSCActionContext.h"
|
#include "Ai/Raid/SerpentshrineCavern/RaidSSCActionContext.h"
|
||||||
#include "Ai/Raid/TempestKeep/RaidTempestKeepActionContext.h"
|
#include "Ai/Raid/TempestKeep/RaidTempestKeepActionContext.h"
|
||||||
#include "Ai/Raid/ZulAman/RaidZulAmanActionContext.h"
|
|
||||||
#include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.h"
|
#include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.h"
|
||||||
#include "Ai/Raid/EyeOfEternity/RaidEoEActionContext.h"
|
#include "Ai/Raid/EyeOfEternity/RaidEoEActionContext.h"
|
||||||
#include "Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h"
|
#include "Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h"
|
||||||
@ -33,7 +32,6 @@ void AiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList<Act
|
|||||||
actionContexts.Add(new RaidMagtheridonActionContext());
|
actionContexts.Add(new RaidMagtheridonActionContext());
|
||||||
actionContexts.Add(new RaidSSCActionContext());
|
actionContexts.Add(new RaidSSCActionContext());
|
||||||
actionContexts.Add(new RaidTempestKeepActionContext());
|
actionContexts.Add(new RaidTempestKeepActionContext());
|
||||||
actionContexts.Add(new RaidZulAmanActionContext());
|
|
||||||
actionContexts.Add(new RaidNaxxActionContext());
|
actionContexts.Add(new RaidNaxxActionContext());
|
||||||
actionContexts.Add(new RaidOsActionContext());
|
actionContexts.Add(new RaidOsActionContext());
|
||||||
actionContexts.Add(new RaidEoEActionContext());
|
actionContexts.Add(new RaidEoEActionContext());
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
#include "Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h"
|
#include "Ai/Raid/Naxxramas/RaidNaxxTriggerContext.h"
|
||||||
#include "Ai/Raid/SerpentshrineCavern/RaidSSCTriggerContext.h"
|
#include "Ai/Raid/SerpentshrineCavern/RaidSSCTriggerContext.h"
|
||||||
#include "Ai/Raid/TempestKeep/RaidTempestKeepTriggerContext.h"
|
#include "Ai/Raid/TempestKeep/RaidTempestKeepTriggerContext.h"
|
||||||
#include "Ai/Raid/ZulAman/RaidZulAmanTriggerContext.h"
|
|
||||||
#include "Ai/Raid/ObsidianSanctum/RaidOsTriggerContext.h"
|
#include "Ai/Raid/ObsidianSanctum/RaidOsTriggerContext.h"
|
||||||
#include "Ai/Raid/EyeOfEternity/RaidEoETriggerContext.h"
|
#include "Ai/Raid/EyeOfEternity/RaidEoETriggerContext.h"
|
||||||
#include "Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h"
|
#include "Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h"
|
||||||
@ -34,7 +33,6 @@ void AiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextList<Tr
|
|||||||
triggerContexts.Add(new RaidNaxxTriggerContext());
|
triggerContexts.Add(new RaidNaxxTriggerContext());
|
||||||
triggerContexts.Add(new RaidSSCTriggerContext());
|
triggerContexts.Add(new RaidSSCTriggerContext());
|
||||||
triggerContexts.Add(new RaidTempestKeepTriggerContext());
|
triggerContexts.Add(new RaidTempestKeepTriggerContext());
|
||||||
triggerContexts.Add(new RaidZulAmanTriggerContext());
|
|
||||||
triggerContexts.Add(new RaidOsTriggerContext());
|
triggerContexts.Add(new RaidOsTriggerContext());
|
||||||
triggerContexts.Add(new RaidEoETriggerContext());
|
triggerContexts.Add(new RaidEoETriggerContext());
|
||||||
triggerContexts.Add(new RaidVoATriggerContext());
|
triggerContexts.Add(new RaidVoATriggerContext());
|
||||||
|
|||||||
@ -1015,59 +1015,29 @@ void PlayerbotAI::HandleCommand(uint32 type, std::string const text, Player* fro
|
|||||||
}
|
}
|
||||||
else if (filtered == "logout")
|
else if (filtered == "logout")
|
||||||
{
|
{
|
||||||
if (bot->GetSession()->isLogingOut())
|
if (!bot->GetSession()->isLogingOut())
|
||||||
return;
|
|
||||||
|
|
||||||
// Verify the command came from this bot's master. Also handles nullptr
|
|
||||||
if (fromPlayer != master)
|
|
||||||
{
|
{
|
||||||
if (type == CHAT_MSG_WHISPER)
|
if (type == CHAT_MSG_WHISPER)
|
||||||
{
|
TellMaster("I'm logging out!");
|
||||||
std::string message = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"bot_not_your_master", "You are not my master!", {});
|
|
||||||
bot->Whisper(message, LANG_UNIVERSAL, fromPlayer);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerbotMgr* masterBotMgr = GET_PLAYERBOT_MGR(master);
|
|
||||||
if (!masterBotMgr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Only respond if this bot is in master's collection (alt/addclass)
|
|
||||||
if (masterBotMgr->GetPlayerBot(bot->GetGUID()))
|
|
||||||
{
|
|
||||||
if (type == CHAT_MSG_WHISPER)
|
|
||||||
{
|
|
||||||
std::string message = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"logout_start", "I'm logging out!", {});
|
|
||||||
TellMaster(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
PlayerbotMgr* masterBotMgr = nullptr;
|
||||||
|
if (master)
|
||||||
|
masterBotMgr = GET_PLAYERBOT_MGR(master);
|
||||||
|
if (masterBotMgr)
|
||||||
masterBotMgr->LogoutPlayerBot(bot->GetGUID());
|
masterBotMgr->LogoutPlayerBot(bot->GetGUID());
|
||||||
}
|
}
|
||||||
else if (type == CHAT_MSG_WHISPER)
|
|
||||||
{
|
|
||||||
std::string message = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
|
||||||
"bot_rndbot_no_logout", "You can't command me to logout!", {});
|
|
||||||
TellMaster(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (filtered == "logout cancel")
|
else if (filtered == "logout cancel")
|
||||||
{
|
{
|
||||||
if (!bot->GetSession()->isLogingOut())
|
if (bot->GetSession()->isLogingOut())
|
||||||
return;
|
|
||||||
|
|
||||||
if (type == CHAT_MSG_WHISPER)
|
|
||||||
{
|
{
|
||||||
std::string message = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
if (type == CHAT_MSG_WHISPER)
|
||||||
"logout_cancel", "Logout cancelled!", {});
|
TellMaster("Logout cancelled!");
|
||||||
TellMaster(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
WorldPackets::Character::LogoutCancel data = WorldPacket(CMSG_LOGOUT_CANCEL);
|
WorldPackets::Character::LogoutCancel data = WorldPacket(CMSG_LOGOUT_CANCEL);
|
||||||
bot->GetSession()->HandleLogoutCancelOpcode(data);
|
bot->GetSession()->HandleLogoutCancelOpcode(data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
chatCommands.push_back(ChatCommandHolder(filtered, fromPlayer, type));
|
chatCommands.push_back(ChatCommandHolder(filtered, fromPlayer, type));
|
||||||
@ -1562,7 +1532,7 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
"naxx", "onyxia", "ssc", "tempestkeep", "ulduar", "voa", "wotlk-an", "wotlk-cos",
|
"naxx", "onyxia", "ssc", "tempestkeep", "ulduar", "voa", "wotlk-an", "wotlk-cos",
|
||||||
"wotlk-dtk", "wotlk-eoe", "wotlk-fos", "wotlk-gd", "wotlk-hol", "wotlk-hor",
|
"wotlk-dtk", "wotlk-eoe", "wotlk-fos", "wotlk-gd", "wotlk-hol", "wotlk-hor",
|
||||||
"wotlk-hos", "wotlk-nex", "wotlk-occ", "wotlk-ok", "wotlk-os", "wotlk-pos",
|
"wotlk-hos", "wotlk-nex", "wotlk-occ", "wotlk-ok", "wotlk-os", "wotlk-pos",
|
||||||
"wotlk-toc", "wotlk-uk", "wotlk-up", "wotlk-vh", "zulaman"
|
"wotlk-toc", "wotlk-uk", "wotlk-up", "wotlk-vh"
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const std::string& strat : allInstanceStrategies)
|
for (const std::string& strat : allInstanceStrategies)
|
||||||
@ -1604,9 +1574,6 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
|||||||
case 565:
|
case 565:
|
||||||
strategyName = "gruulslair"; // Gruul's Lair
|
strategyName = "gruulslair"; // Gruul's Lair
|
||||||
break;
|
break;
|
||||||
case 568:
|
|
||||||
strategyName = "zulaman"; // Zul'Aman
|
|
||||||
break;
|
|
||||||
case 574:
|
case 574:
|
||||||
strategyName = "wotlk-uk"; // Utgarde Keep
|
strategyName = "wotlk-uk"; // Utgarde Keep
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -362,9 +362,6 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
|
|||||||
if (master)
|
if (master)
|
||||||
masterWorldSessionPtr = master->GetSession();
|
masterWorldSessionPtr = master->GetSession();
|
||||||
|
|
||||||
// TODO: Review whether or not to implement timed logout.
|
|
||||||
// Unused block. Useful only for timed logout.
|
|
||||||
/*
|
|
||||||
// check for instant logout
|
// check for instant logout
|
||||||
bool logout = botWorldSessionPtr->ShouldLogOut(time(nullptr));
|
bool logout = botWorldSessionPtr->ShouldLogOut(time(nullptr));
|
||||||
|
|
||||||
@ -376,19 +373,58 @@ void PlayerbotHolder::LogoutPlayerBot(ObjectGuid guid)
|
|||||||
|
|
||||||
if (bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || bot->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
|
if (bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || bot->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
|
||||||
botWorldSessionPtr->GetSecurity() >= (AccountTypes)sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))
|
botWorldSessionPtr->GetSecurity() >= (AccountTypes)sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))
|
||||||
|
{
|
||||||
logout = true;
|
logout = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (master &&
|
if (master &&
|
||||||
(master->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || master->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
|
(master->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || master->HasUnitState(UNIT_STATE_IN_FLIGHT) ||
|
||||||
(masterWorldSessionPtr &&
|
(masterWorldSessionPtr &&
|
||||||
masterWorldSessionPtr->GetSecurity() >= (AccountTypes)sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))))
|
masterWorldSessionPtr->GetSecurity() >= (AccountTypes)sWorld->getIntConfig(CONFIG_INSTANT_LOGOUT))))
|
||||||
logout = true;
|
|
||||||
*/
|
|
||||||
// Instant logout (the only option right now)
|
|
||||||
{
|
{
|
||||||
std::string message = PlayerbotTextMgr::instance().GetBotTextOrDefault(
|
logout = true;
|
||||||
"goodbye", "Goodbye!", {});
|
}
|
||||||
botAI->TellMaster(message);
|
|
||||||
|
TravelTarget* target = nullptr;
|
||||||
|
if (botAI->GetAiObjectContext()) // Maybe some day re-write to delate all pointer values.
|
||||||
|
{
|
||||||
|
target = botAI->GetAiObjectContext()->GetValue<TravelTarget*>("travel target")->Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peiru: Allow bots to always instant logout to see if this resolves logout crashes
|
||||||
|
logout = true;
|
||||||
|
|
||||||
|
// if no instant logout, request normal logout
|
||||||
|
if (!logout)
|
||||||
|
{
|
||||||
|
if (bot->GetSession()->isLogingOut())
|
||||||
|
return;
|
||||||
|
else if (bot)
|
||||||
|
{
|
||||||
|
botAI->TellMaster("I'm logging out!");
|
||||||
|
WorldPackets::Character::LogoutRequest data = WorldPacket(CMSG_LOGOUT_REQUEST);
|
||||||
|
botWorldSessionPtr->HandleLogoutRequestOpcode(data);
|
||||||
|
if (!bot)
|
||||||
|
{
|
||||||
|
RemoveFromPlayerbotsMap(guid);
|
||||||
|
delete botWorldSessionPtr;
|
||||||
|
if (target)
|
||||||
|
delete target;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveFromPlayerbotsMap(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
|
||||||
|
delete botWorldSessionPtr; // finally delete the bot's WorldSession
|
||||||
|
if (target)
|
||||||
|
delete target;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} // if instant logout possible, do it
|
||||||
|
else if (bot && (logout || !botWorldSessionPtr->isLogingOut()))
|
||||||
|
{
|
||||||
|
botAI->TellMaster("Goodbye!");
|
||||||
RemoveFromPlayerbotsMap(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
|
RemoveFromPlayerbotsMap(guid); // deletes bot player ptr inside this WorldSession PlayerBotMap
|
||||||
botWorldSessionPtr->LogoutPlayer(true); // this will delete the bot Player object and PlayerbotAI object
|
botWorldSessionPtr->LogoutPlayer(true); // this will delete the bot Player object and PlayerbotAI object
|
||||||
delete botWorldSessionPtr; // finally delete the bot's WorldSession
|
delete botWorldSessionPtr; // finally delete the bot's WorldSession
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user