mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #487 from liyunfan1223/flame_leviathan
Flame leviathan strategy (normal mode)
This commit is contained in:
@@ -369,8 +369,8 @@ AiPlayerbot.SyncQuestForPlayer = 0
|
||||
#
|
||||
#
|
||||
|
||||
# Bot can flee for enemy
|
||||
AiPlayerbot.FleeingEnabled = 1
|
||||
# Auto add dungeon/raid strategies when entering the instance if implemented
|
||||
AiPlayerbot.ApplyInstanceStrategies = 1
|
||||
|
||||
# Enable auto avoid aoe (experimental)
|
||||
# Default: 1 (enable)
|
||||
@@ -388,6 +388,9 @@ AiPlayerbot.AutoSaveMana = 1
|
||||
# Default: 60 (60%)
|
||||
AiPlayerbot.SaveManaThreshold = 60
|
||||
|
||||
# Bot can flee for enemy
|
||||
AiPlayerbot.FleeingEnabled = 1
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
@@ -136,6 +136,8 @@ PlayerbotAI::PlayerbotAI(Player* bot)
|
||||
engines[BOT_STATE_COMBAT] = AiFactory::createCombatEngine(bot, this, aiObjectContext);
|
||||
engines[BOT_STATE_NON_COMBAT] = AiFactory::createNonCombatEngine(bot, this, aiObjectContext);
|
||||
engines[BOT_STATE_DEAD] = AiFactory::createDeadEngine(bot, this, aiObjectContext);
|
||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||
ApplyInstanceStrategies(bot->GetMapId());
|
||||
currentEngine = engines[BOT_STATE_NON_COMBAT];
|
||||
currentState = BOT_STATE_NON_COMBAT;
|
||||
|
||||
@@ -650,10 +652,11 @@ void PlayerbotAI::HandleTeleportAck()
|
||||
bot->GetSession()->HandleMoveWorldportAck();
|
||||
}
|
||||
SetNextCheckDelay(urand(2000, 5000));
|
||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||
ApplyInstanceStrategies(bot->GetMapId(), true);
|
||||
}
|
||||
|
||||
SetNextCheckDelay(sPlayerbotAIConfig->globalCoolDown);
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -1487,6 +1490,34 @@ std::vector<std::string> PlayerbotAI::GetStrategies(BotState type)
|
||||
return e->GetStrategies();
|
||||
}
|
||||
|
||||
void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
|
||||
{
|
||||
std::string strategyName;
|
||||
switch (mapId)
|
||||
{
|
||||
case 533:
|
||||
strategyName = "naxx";
|
||||
break;
|
||||
case 603:
|
||||
strategyName = "uld";
|
||||
break;
|
||||
case 469:
|
||||
strategyName = "bwl";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
engines[BOT_STATE_COMBAT]->addStrategy(strategyName);
|
||||
engines[BOT_STATE_NON_COMBAT]->addStrategy(strategyName);
|
||||
if (tellMaster && !strategyName.empty())
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "Add " << strategyName << " instance strategy";
|
||||
TellMaster(out.str());
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerbotAI::DoSpecificAction(std::string const name, Event event, bool silent, std::string const qualifier)
|
||||
{
|
||||
std::ostringstream out;
|
||||
@@ -1584,6 +1615,8 @@ void PlayerbotAI::ResetStrategies(bool load)
|
||||
AiFactory::AddDefaultCombatStrategies(bot, this, engines[BOT_STATE_COMBAT]);
|
||||
AiFactory::AddDefaultNonCombatStrategies(bot, this, engines[BOT_STATE_NON_COMBAT]);
|
||||
AiFactory::AddDefaultDeadStrategies(bot, this, engines[BOT_STATE_DEAD]);
|
||||
if (sPlayerbotAIConfig->applyInstanceStrategies)
|
||||
ApplyInstanceStrategies(bot->GetMapId());
|
||||
|
||||
for (uint8 i = 0; i < BOT_STATE_MAX; i++)
|
||||
engines[i]->Init();
|
||||
@@ -5736,7 +5769,7 @@ uint32 PlayerbotAI::GetReactDelay()
|
||||
bool isResting = bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
|
||||
if (!isResting)
|
||||
{
|
||||
multiplier = urand(5, 20);
|
||||
multiplier = urand(10, 30);
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,26 +129,25 @@ enum ChatChannelSource
|
||||
SRC_UNDEFINED
|
||||
};
|
||||
static std::map<ChatChannelSource, std::string> ChatChannelSourceStr = {
|
||||
{ SRC_GUILD, "SRC_GUILD"},
|
||||
{ SRC_WORLD, "SRC_WORLD"},
|
||||
{ SRC_GENERAL, "SRC_GENERAL"},
|
||||
{ SRC_TRADE, "SRC_TRADE"},
|
||||
{ SRC_LOOKING_FOR_GROUP, "SRC_LOOKING_FOR_GROUP"},
|
||||
{ SRC_LOCAL_DEFENSE, "SRC_LOCAL_DEFENSE"},
|
||||
{ SRC_WORLD_DEFENSE, "SRC_WORLD_DEFENSE"},
|
||||
{ SRC_GUILD_RECRUITMENT, "SRC_GUILD_RECRUITMENT"},
|
||||
{SRC_GUILD, "SRC_GUILD"},
|
||||
{SRC_WORLD, "SRC_WORLD"},
|
||||
{SRC_GENERAL, "SRC_GENERAL"},
|
||||
{SRC_TRADE, "SRC_TRADE"},
|
||||
{SRC_LOOKING_FOR_GROUP, "SRC_LOOKING_FOR_GROUP"},
|
||||
{SRC_LOCAL_DEFENSE, "SRC_LOCAL_DEFENSE"},
|
||||
{SRC_WORLD_DEFENSE, "SRC_WORLD_DEFENSE"},
|
||||
{SRC_GUILD_RECRUITMENT, "SRC_GUILD_RECRUITMENT"},
|
||||
|
||||
{ SRC_SAY, "SRC_SAY"},
|
||||
{ SRC_WHISPER, "SRC_WHISPER"},
|
||||
{ SRC_EMOTE, "SRC_EMOTE"},
|
||||
{ SRC_TEXT_EMOTE, "SRC_TEXT_EMOTE"},
|
||||
{ SRC_YELL, "SRC_YELL"},
|
||||
{SRC_SAY, "SRC_SAY"},
|
||||
{SRC_WHISPER, "SRC_WHISPER"},
|
||||
{SRC_EMOTE, "SRC_EMOTE"},
|
||||
{SRC_TEXT_EMOTE, "SRC_TEXT_EMOTE"},
|
||||
{SRC_YELL, "SRC_YELL"},
|
||||
|
||||
{ SRC_PARTY, "SRC_PARTY"},
|
||||
{ SRC_RAID, "SRC_RAID"},
|
||||
{SRC_PARTY, "SRC_PARTY"},
|
||||
{SRC_RAID, "SRC_RAID"},
|
||||
|
||||
{ SRC_UNDEFINED, "SRC_UNDEFINED"}
|
||||
};
|
||||
{SRC_UNDEFINED, "SRC_UNDEFINED"}};
|
||||
enum ChatChannelId
|
||||
{
|
||||
GENERAL = 1,
|
||||
@@ -390,10 +389,12 @@ public:
|
||||
void HandleTeleportAck();
|
||||
void ChangeEngine(BotState type);
|
||||
void DoNextAction(bool minimal = false);
|
||||
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false, std::string const qualifier = "");
|
||||
virtual bool DoSpecificAction(std::string const name, Event event = Event(), bool silent = false,
|
||||
std::string const qualifier = "");
|
||||
void ChangeStrategy(std::string const name, BotState type);
|
||||
void ClearStrategies(BotState type);
|
||||
std::vector<std::string> GetStrategies(BotState type);
|
||||
void ApplyInstanceStrategies(uint32 mapId, bool tellMaster = false);
|
||||
bool ContainsStrategy(StrategyType type);
|
||||
bool HasStrategy(std::string const name, BotState type);
|
||||
BotState GetState() { return currentState; };
|
||||
@@ -434,8 +435,10 @@ public:
|
||||
|
||||
bool TellMaster(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMaster(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::ostringstream& stream, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::ostringstream& stream,
|
||||
PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellMasterNoFacing(std::string const text,
|
||||
PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool TellError(std::string const text, PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
bool SayToGuild(const std::string& msg);
|
||||
bool SayToWorld(const std::string& msg);
|
||||
@@ -523,12 +526,16 @@ public:
|
||||
bool AllowActive(ActivityType activityType);
|
||||
bool AllowActivity(ActivityType activityType = ALL_ACTIVITY, bool checkNow = false);
|
||||
|
||||
//Check if player is safe to use.
|
||||
// Check if player is safe to use.
|
||||
bool IsSafe(Player* player);
|
||||
bool IsSafe(WorldObject* obj);
|
||||
ChatChannelSource GetChatChannelSource(Player* bot, uint32 type, std::string channelName);
|
||||
|
||||
bool HasCheat(BotCheatMask mask) { return ((uint32)mask & (uint32)cheatMask) != 0 || ((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0; }
|
||||
bool HasCheat(BotCheatMask mask)
|
||||
{
|
||||
return ((uint32)mask & (uint32)cheatMask) != 0 ||
|
||||
((uint32)mask & (uint32)sPlayerbotAIConfig->botCheatMask) != 0;
|
||||
}
|
||||
BotCheatMask GetCheat() { return cheatMask; }
|
||||
void SetCheat(BotCheatMask mask) { cheatMask = mask; }
|
||||
|
||||
@@ -563,7 +570,8 @@ public:
|
||||
void PetFollow();
|
||||
|
||||
private:
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore, bool mixed = false);
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore,
|
||||
bool mixed = false);
|
||||
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
|
||||
void HandleCommands();
|
||||
|
||||
@@ -286,6 +286,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
randomBotNonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotNonCombatStrategies", "");
|
||||
combatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.CombatStrategies", "+custom::say");
|
||||
nonCombatStrategies = sConfigMgr->GetOption<std::string>("AiPlayerbot.NonCombatStrategies", "+custom::say,+return");
|
||||
applyInstanceStrategies = sConfigMgr->GetOption<bool>("AiPlayerbot.ApplyInstanceStrategies", true);
|
||||
|
||||
commandPrefix = sConfigMgr->GetOption<std::string>("AiPlayerbot.CommandPrefix", "");
|
||||
commandSeparator = sConfigMgr->GetOption<std::string>("AiPlayerbot.CommandSeparator", "\\\\");
|
||||
@@ -477,11 +478,11 @@ bool PlayerbotAIConfig::Initialize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
PlayerbotFactory::Init();
|
||||
sRandomItemMgr->Init();
|
||||
sRandomItemMgr->InitAfterAhBot();
|
||||
sPlayerbotTextMgr->LoadBotTexts();
|
||||
sPlayerbotTextMgr->LoadBotTextChance();
|
||||
PlayerbotFactory::Init();
|
||||
|
||||
if (!sPlayerbotAIConfig->autoDoQuests)
|
||||
{
|
||||
|
||||
@@ -184,6 +184,7 @@ public:
|
||||
bool summonAtInnkeepersEnabled;
|
||||
std::string combatStrategies, nonCombatStrategies;
|
||||
std::string randomBotCombatStrategies, randomBotNonCombatStrategies;
|
||||
bool applyInstanceStrategies;
|
||||
uint32 randomBotMinLevel, randomBotMaxLevel;
|
||||
float randomChangeMultiplier;
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ public:
|
||||
|
||||
void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId)
|
||||
{
|
||||
// bot is loading
|
||||
if (botLoading.find(playerGuid) != botLoading.end())
|
||||
return;
|
||||
|
||||
// has bot already been added?
|
||||
Player* bot = ObjectAccessor::FindConnectedPlayer(playerGuid);
|
||||
if (bot && bot->IsInWorld())
|
||||
@@ -64,6 +68,8 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
||||
return;
|
||||
}
|
||||
|
||||
botLoading.insert(playerGuid);
|
||||
|
||||
if (WorldSession* masterSession = sWorld->FindSession(masterAccountId))
|
||||
{
|
||||
masterSession->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder))
|
||||
@@ -80,13 +86,6 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId
|
||||
|
||||
void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder)
|
||||
{
|
||||
// has bot already been added?
|
||||
Player* loginBot = ObjectAccessor::FindConnectedPlayer(holder.GetGuid());
|
||||
if (loginBot && loginBot->IsInWorld())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 botAccountId = holder.GetAccountId();
|
||||
|
||||
// At login DBC locale should be what the server is set to use by default (as spells etc are hardcoded to ENUS this
|
||||
@@ -101,8 +100,7 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
{
|
||||
botSession->LogoutPlayer(true);
|
||||
delete botSession;
|
||||
// LOG_ERROR("playerbots", "Error logging in bot {}, please try to reset all random bots",
|
||||
// holder.GetGuid().ToString().c_str());
|
||||
botLoading.erase(holder.GetGuid());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,12 +157,8 @@ void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder con
|
||||
}
|
||||
botSession->LogoutPlayer(true);
|
||||
delete botSession;
|
||||
// OnBotLogin(bot);
|
||||
// LogoutPlayerBot(bot->GetGUID());
|
||||
|
||||
// LOG_ERROR("playerbots", "Attempt to add not allowed bot {}, please try to reset all random bots",
|
||||
// bot->GetName());
|
||||
}
|
||||
botLoading.erase(holder.GetGuid());
|
||||
}
|
||||
|
||||
void PlayerbotHolder::UpdateSessions()
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define _PLAYERBOT_PLAYERBOTMGR_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAIBase.h"
|
||||
#include "QueryHolder.h"
|
||||
@@ -57,6 +58,7 @@ protected:
|
||||
virtual void OnBotLoginInternal(Player* const bot) = 0;
|
||||
|
||||
PlayerBotMap playerBots;
|
||||
std::unordered_set<ObjectGuid> botLoading;
|
||||
};
|
||||
|
||||
class PlayerbotMgr : public PlayerbotHolder
|
||||
|
||||
@@ -949,7 +949,6 @@ void RandomItemMgr::BuildItemInfoCache()
|
||||
|
||||
PlayerbotsDatabaseTransaction trans = PlayerbotsDatabase.BeginTransaction();
|
||||
|
||||
// generate stat weights for classes/specs
|
||||
for (auto const& itr : *itemTemplate)
|
||||
{
|
||||
ItemTemplate const* proto = &itr.second;
|
||||
@@ -958,11 +957,12 @@ void RandomItemMgr::BuildItemInfoCache()
|
||||
|
||||
// skip non armor/weapon
|
||||
if (proto->Class != ITEM_CLASS_WEAPON && proto->Class != ITEM_CLASS_ARMOR &&
|
||||
proto->Class != ITEM_CLASS_CONTAINER && proto->Class != ITEM_CLASS_PROJECTILE)
|
||||
proto->Class != ITEM_CLASS_CONTAINER && proto->Class != ITEM_CLASS_PROJECTILE &&
|
||||
proto->Class != ITEM_CLASS_GEM)
|
||||
continue;
|
||||
|
||||
if (!CanEquipItemNew(proto))
|
||||
continue;
|
||||
// if (!CanEquipItemNew(proto))
|
||||
// continue;
|
||||
|
||||
// skip test items
|
||||
if (strstr(proto->Name1.c_str(), "(Test)") || strstr(proto->Name1.c_str(), "(TEST)") ||
|
||||
@@ -990,29 +990,29 @@ void RandomItemMgr::BuildItemInfoCache()
|
||||
proto->RequiredReputationRank > 0)
|
||||
continue;*/
|
||||
|
||||
if (proto->RequiredHonorRank > 0 || proto->RequiredSkillRank > 0 || proto->RequiredCityRank > 0)
|
||||
continue;
|
||||
// if (proto->RequiredHonorRank > 0 || proto->RequiredSkillRank > 0 || proto->RequiredCityRank > 0)
|
||||
// continue;
|
||||
|
||||
// skip random enchant items
|
||||
if (proto->RandomProperty)
|
||||
continue;
|
||||
// // skip random enchant items
|
||||
// if (proto->RandomProperty)
|
||||
// continue;
|
||||
|
||||
// skip heirloom items
|
||||
if (proto->Quality == ITEM_QUALITY_HEIRLOOM)
|
||||
continue;
|
||||
// // skip heirloom items
|
||||
// if (proto->Quality == ITEM_QUALITY_HEIRLOOM)
|
||||
// continue;
|
||||
|
||||
// check possible equip slots
|
||||
EquipmentSlots slot = EQUIPMENT_SLOT_START;
|
||||
for (std::map<EquipmentSlots, std::set<InventoryType> >::iterator i = viableSlots.begin();
|
||||
i != viableSlots.end(); ++i)
|
||||
{
|
||||
std::set<InventoryType> slots = viableSlots[(EquipmentSlots)i->first];
|
||||
if (slots.find((InventoryType)proto->InventoryType) != slots.end())
|
||||
slot = i->first;
|
||||
}
|
||||
// // check possible equip slots
|
||||
// EquipmentSlots slot = EQUIPMENT_SLOT_START;
|
||||
// for (std::map<EquipmentSlots, std::set<InventoryType> >::iterator i = viableSlots.begin();
|
||||
// i != viableSlots.end(); ++i)
|
||||
// {
|
||||
// std::set<InventoryType> slots = viableSlots[(EquipmentSlots)i->first];
|
||||
// if (slots.find((InventoryType)proto->InventoryType) != slots.end())
|
||||
// slot = i->first;
|
||||
// }
|
||||
|
||||
if (slot == EQUIPMENT_SLOT_START)
|
||||
continue;
|
||||
// if (slot == EQUIPMENT_SLOT_START)
|
||||
// continue;
|
||||
|
||||
// Init Item cache
|
||||
// ItemInfoEntry cacheInfo;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "AiFactory.h"
|
||||
@@ -203,7 +204,7 @@ private:
|
||||
std::map<std::string, uint32> weightStatLink;
|
||||
std::map<std::string, uint32> weightRatingLink;
|
||||
std::map<uint32, ItemInfoEntry> itemInfoCache;
|
||||
std::set<uint32> itemForTest;
|
||||
std::unordered_set<uint32> itemForTest;
|
||||
static std::set<uint32> itemCache;
|
||||
// equipCacheNew[RequiredLevel][InventoryType]
|
||||
std::map<uint32, std::map<uint32, std::vector<uint32>>> equipCacheNew;
|
||||
|
||||
@@ -135,15 +135,17 @@ void PlayerbotFactory::Init()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (gemId == 49110)
|
||||
{ // unique gem
|
||||
continue;
|
||||
}
|
||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(gemId);
|
||||
|
||||
if (proto->ItemLevel < 60)
|
||||
continue;
|
||||
|
||||
if (proto->Flags & ITEM_FLAG_UNIQUE_EQUIPPABLE)
|
||||
{ // unique gem
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (sRandomItemMgr->IsTestItem(gemId))
|
||||
continue;
|
||||
if (!proto || !sGemPropertiesStore.LookupEntry(proto->GemProperties))
|
||||
{
|
||||
continue;
|
||||
@@ -438,7 +440,7 @@ void PlayerbotFactory::Refresh()
|
||||
uint32 money = urand(level * 1000, level * 5 * 1000);
|
||||
if (bot->GetMoney() < money)
|
||||
bot->SetMoney(money);
|
||||
bot->SaveToDB(false, false);
|
||||
// bot->SaveToDB(false, false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::AddConsumables()
|
||||
@@ -805,17 +807,13 @@ void PlayerbotFactory::ClearSkills()
|
||||
|
||||
void PlayerbotFactory::ClearEverything()
|
||||
{
|
||||
bot->SaveToDB(false, false);
|
||||
bot->GiveLevel(bot->getClass() == CLASS_DEATH_KNIGHT ? sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL)
|
||||
: sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL));
|
||||
bot->SetUInt32Value(PLAYER_XP, 0);
|
||||
LOG_INFO("playerbots", "Resetting player...");
|
||||
bot->resetTalents(true);
|
||||
bot->SaveToDB(false, false);
|
||||
ClearSkills();
|
||||
// bot->SaveToDB(false, false);
|
||||
ClearSpells();
|
||||
bot->SaveToDB(false, false);
|
||||
ClearInventory();
|
||||
ResetQuests();
|
||||
bot->SaveToDB(false, false);
|
||||
@@ -2027,6 +2025,7 @@ void PlayerbotFactory::InitSkills()
|
||||
SetRandomSkill(SKILL_THROWN);
|
||||
bot->SetSkill(SKILL_DUAL_WIELD, 0, dualWieldLevel, dualWieldLevel);
|
||||
bot->SetSkill(SKILL_PLATE_MAIL, 0, skillLevel, skillLevel);
|
||||
bot->SetCanDualWield(dualWieldLevel);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
SetRandomSkill(SKILL_SWORDS);
|
||||
@@ -2079,8 +2078,9 @@ void PlayerbotFactory::InitSkills()
|
||||
SetRandomSkill(SKILL_POLEARMS);
|
||||
SetRandomSkill(SKILL_FIST_WEAPONS);
|
||||
SetRandomSkill(SKILL_THROWN);
|
||||
bot->SetSkill(SKILL_MAIL, 0, skillLevel, skillLevel);
|
||||
bot->SetSkill(SKILL_DUAL_WIELD, 0, dualWieldLevel, dualWieldLevel);
|
||||
bot->SetSkill(SKILL_MAIL, 0, skillLevel, skillLevel);
|
||||
bot->SetCanDualWield(dualWieldLevel);
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
SetRandomSkill(SKILL_SWORDS);
|
||||
@@ -2093,6 +2093,7 @@ void PlayerbotFactory::InitSkills()
|
||||
SetRandomSkill(SKILL_FIST_WEAPONS);
|
||||
SetRandomSkill(SKILL_THROWN);
|
||||
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
|
||||
bot->SetCanDualWield(true);
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
SetRandomSkill(SKILL_SWORDS);
|
||||
@@ -2103,6 +2104,7 @@ void PlayerbotFactory::InitSkills()
|
||||
SetRandomSkill(SKILL_2H_AXES);
|
||||
SetRandomSkill(SKILL_POLEARMS);
|
||||
bot->SetSkill(SKILL_DUAL_WIELD, 0, dualWieldLevel, dualWieldLevel);
|
||||
bot->SetCanDualWield(dualWieldLevel);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -2572,7 +2574,6 @@ void PlayerbotFactory::InitInstanceQuests()
|
||||
|
||||
ClearInventory();
|
||||
bot->SetUInt32Value(PLAYER_XP, currentXP);
|
||||
bot->SaveToDB(false, false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::ClearInventory()
|
||||
@@ -3329,7 +3330,7 @@ void PlayerbotFactory::InitGuild()
|
||||
if (bot->GetGuildId())
|
||||
return;
|
||||
|
||||
bot->SaveToDB(false, false);
|
||||
// bot->SaveToDB(false, false);
|
||||
|
||||
// add guild tabard
|
||||
if (bot->GetGuildId() && !bot->HasItemCount(5976, 1))
|
||||
@@ -3365,7 +3366,7 @@ void PlayerbotFactory::InitGuild()
|
||||
if (bot->GetGuildId() && bot->GetLevel() > 9 && urand(0, 4) && !bot->HasItemCount(5976, 1))
|
||||
StoreItem(5976, 1);
|
||||
|
||||
bot->SaveToDB(false, false);
|
||||
// bot->SaveToDB(false, false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::InitImmersive()
|
||||
@@ -3554,7 +3555,7 @@ void PlayerbotFactory::InitArenaTeam()
|
||||
arenateams.erase(arenateams.begin() + index);
|
||||
}
|
||||
|
||||
bot->SaveToDB(false, false);
|
||||
// bot->SaveToDB(false, false);
|
||||
}
|
||||
|
||||
void PlayerbotFactory::ApplyEnchantTemplate()
|
||||
@@ -3670,6 +3671,9 @@ void PlayerbotFactory::ApplyEnchantAndGemsNew(bool destoryOld)
|
||||
if (!gemProperties)
|
||||
continue;
|
||||
|
||||
if (sPlayerbotAIConfig->limitEnchantExpansion && bot->GetLevel() <= 70 && enchantGem >= 39900)
|
||||
continue;
|
||||
|
||||
uint32 requiredLevel = gemTemplate->ItemLevel;
|
||||
|
||||
if (requiredLevel > bot->GetLevel())
|
||||
|
||||
@@ -431,7 +431,8 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
||||
// spec with double hand
|
||||
// fury without duel wield, arms, bear, retribution, blood dk
|
||||
if (isDoubleHand &&
|
||||
((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
||||
((cls == CLASS_HUNTER && !player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !player_->CanDualWield()) ||
|
||||
(cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == DRUID_TAB_FERAL) ||
|
||||
(cls == CLASS_PALADIN && tab == PALADIN_TAB_RETRIBUTION) ||
|
||||
(cls == CLASS_DEATH_KNIGHT && tab == DEATHKNIGHT_TAB_BLOOD) ||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "ChatActionContext.h"
|
||||
#include "ChatTriggerContext.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidUlduarTriggerContext.h"
|
||||
#include "RaidUlduarActionContext.h"
|
||||
#include "SharedValueContext.h"
|
||||
#include "StrategyContext.h"
|
||||
#include "TriggerContext.h"
|
||||
@@ -34,12 +36,14 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
||||
actionContexts.Add(new WorldPacketActionContext());
|
||||
actionContexts.Add(new RaidActionContext());
|
||||
actionContexts.Add(new RaidNaxxActionContext());
|
||||
actionContexts.Add(new RaidUlduarActionContext());
|
||||
|
||||
triggerContexts.Add(new TriggerContext());
|
||||
triggerContexts.Add(new ChatTriggerContext());
|
||||
triggerContexts.Add(new WorldPacketTriggerContext());
|
||||
triggerContexts.Add(new RaidTriggerContext());
|
||||
triggerContexts.Add(new RaidNaxxTriggerContext());
|
||||
triggerContexts.Add(new RaidUlduarTriggerContext());
|
||||
|
||||
valueContexts.Add(new ValueContext());
|
||||
|
||||
|
||||
@@ -140,6 +140,9 @@ std::vector<std::pair<uint32, std::string>> ListSpellsAction::GetSpellList(std::
|
||||
if (itr->second->State == PLAYERSPELL_REMOVED || !itr->second->Active)
|
||||
continue;
|
||||
|
||||
if (!(itr->second->specMask & bot->GetActiveSpecMask()))
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
@@ -197,6 +197,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
{
|
||||
VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(bot);
|
||||
Unit* vehicleBase = vehicle->GetBase();
|
||||
generatePath = vehicleBase->CanFly();
|
||||
if (!vehicleBase || !seat || !seat->CanControl()) // is passenger and cant move anyway
|
||||
return false;
|
||||
|
||||
@@ -815,7 +816,6 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
||||
|
||||
if (target->HasUnitMovementFlag(MOVEMENTFLAG_FORWARD)) // target is moving forward, predict the position
|
||||
{
|
||||
|
||||
float needToGo = bot->GetExactDist(target) - distance;
|
||||
float timeToGo = MoveDelay(abs(needToGo)) + sPlayerbotAIConfig->reactDelay / 1000.0f;
|
||||
float targetMoveDist = timeToGo * target->GetSpeed(MOVE_RUN);
|
||||
@@ -848,7 +848,8 @@ bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
||||
return false;
|
||||
path.ShortenPathUntilDist(G3D::Vector3(tx, ty, tz), distance);
|
||||
G3D::Vector3 endPos = path.GetPath().back();
|
||||
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
float MovementAction::GetFollowAngle()
|
||||
@@ -881,9 +882,9 @@ bool MovementAction::IsMovingAllowed(Unit* target)
|
||||
if (bot->GetMapId() != target->GetMapId())
|
||||
return false;
|
||||
|
||||
float distance = sServerFacade->GetDistance2d(bot, target);
|
||||
if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance)
|
||||
return false;
|
||||
// float distance = sServerFacade->GetDistance2d(bot, target);
|
||||
// if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance)
|
||||
// return false;
|
||||
|
||||
return IsMovingAllowed();
|
||||
}
|
||||
@@ -893,9 +894,10 @@ bool MovementAction::IsMovingAllowed(uint32 mapId, float x, float y, float z)
|
||||
// removed sqrt as means distance limit was effectively 22500 (ReactDistance<63>)
|
||||
// leaving it commented incase we find ReactDistance limit causes problems
|
||||
// float distance = sqrt(bot->GetDistance(x, y, z));
|
||||
float distance = bot->GetDistance(x, y, z);
|
||||
if (!bot->InBattleground() && distance > sPlayerbotAIConfig->reactDistance)
|
||||
return false;
|
||||
|
||||
// Remove react distance limit
|
||||
// if (!bot->InBattleground())
|
||||
// return false;
|
||||
|
||||
return IsMovingAllowed();
|
||||
}
|
||||
@@ -2401,7 +2403,8 @@ bool MoveInsideAction::Execute(Event event) { return MoveInside(bot->GetMapId(),
|
||||
bool RotateAroundTheCenterPointAction::Execute(Event event)
|
||||
{
|
||||
uint32 next_point = GetCurrWaypoint();
|
||||
if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
|
||||
if (MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false,
|
||||
false, false, false, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
call_counters += 1;
|
||||
return true;
|
||||
|
||||
@@ -319,7 +319,6 @@ bool SpiritHealerAction::Execute(Event event)
|
||||
PlayerbotChatHandler ch(bot);
|
||||
bot->ResurrectPlayer(0.5f);
|
||||
bot->SpawnCorpseBones();
|
||||
bot->SaveToDB(false, false);
|
||||
context->GetValue<Unit*>("current target")->Set(nullptr);
|
||||
bot->SetTarget();
|
||||
botAI->TellMaster("Hello");
|
||||
|
||||
@@ -175,6 +175,12 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (player->GetVehicle())
|
||||
{
|
||||
botAI->TellError("You cannot summon me while I'm on a vehicle");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!summoner->IsBeingTeleported() && !player->IsBeingTeleported())
|
||||
{
|
||||
float followAngle = GetFollowAngle();
|
||||
@@ -222,6 +228,7 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
}
|
||||
|
||||
player->GetMotionMaster()->Clear();
|
||||
AI_VALUE(LastMovement&, "last movement").clear();
|
||||
player->TeleportTo(mapId, x, y, z, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
|
||||
#include "BattlegroundIC.h"
|
||||
#include "ItemVisitors.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "Playerbots.h"
|
||||
#include "QuestValues.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "Unit.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
// TODO methods to enter/exit vehicle should be added to BGTactics or MovementAction (so that we can better control
|
||||
@@ -21,6 +24,21 @@ bool EnterVehicleAction::Execute(Event event)
|
||||
if (bot->GetVehicle())
|
||||
return false;
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
// Triggered by a chat command
|
||||
if (event.getOwner() && master && master->GetTarget())
|
||||
{
|
||||
Unit* vehicleBase = botAI->GetUnit(master->GetTarget());
|
||||
if (!vehicleBase)
|
||||
return false;
|
||||
Vehicle* veh = vehicleBase->GetVehicleKit();
|
||||
if (vehicleBase->IsVehicle() && veh && veh->GetAvailableSeatCount())
|
||||
{
|
||||
return EnterVehicle(vehicleBase, false);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest vehicles");
|
||||
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
|
||||
{
|
||||
@@ -28,6 +46,9 @@ bool EnterVehicleAction::Execute(Event event)
|
||||
if (!vehicleBase)
|
||||
continue;
|
||||
|
||||
if (vehicleBase->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
continue;
|
||||
|
||||
// dont let them get in the cannons as they'll stay forever and do nothing useful
|
||||
// dont let them in catapult they cant use them at all
|
||||
if (NPC_KEEP_CANNON == vehicleBase->GetEntry() || NPC_CATAPULT == vehicleBase->GetEntry())
|
||||
@@ -44,14 +65,26 @@ bool EnterVehicleAction::Execute(Event event)
|
||||
if (vehicleBase->GetVehicleKit()->IsVehicleInUse())
|
||||
continue;
|
||||
|
||||
if (EnterVehicle(vehicleBase, true))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EnterVehicleAction::EnterVehicle(Unit* vehicleBase, bool moveIfFar)
|
||||
{
|
||||
float dist = sServerFacade->GetDistance2d(bot, vehicleBase);
|
||||
if (dist > 40.0f)
|
||||
continue;
|
||||
return false;
|
||||
|
||||
if (dist > INTERACTION_DISTANCE && !moveIfFar)
|
||||
return false;
|
||||
|
||||
if (dist > INTERACTION_DISTANCE)
|
||||
return MoveTo(vehicleBase);
|
||||
|
||||
bot->EnterVehicle(vehicleBase);
|
||||
// Use HandleSpellClick instead of Unit::EnterVehicle to handle special vehicle script (ulduar)
|
||||
vehicleBase->HandleSpellClick(bot);
|
||||
|
||||
if (!bot->IsOnVehicle(vehicleBase))
|
||||
return false;
|
||||
@@ -60,9 +93,6 @@ bool EnterVehicleAction::Execute(Event event)
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LeaveVehicleAction::Execute(Event event)
|
||||
|
||||
@@ -17,6 +17,8 @@ public:
|
||||
EnterVehicleAction(PlayerbotAI* botAI, std::string const& name = "enter vehicle") : MovementAction(botAI, name) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
bool EnterVehicle(Unit* vehicleBase, bool moveIfFar);
|
||||
};
|
||||
|
||||
class LeaveVehicleAction : public MovementAction
|
||||
|
||||
@@ -60,6 +60,10 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
triggers.push_back(
|
||||
new TriggerNode("talk", NextAction::array(0, new NextAction("gossip hello", relevance),
|
||||
new NextAction("talk to quest giver", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("enter vehicle", NextAction::array(0, new NextAction("enter vehicle", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("leave vehicle", NextAction::array(0, new NextAction("leave vehicle", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("cast", NextAction::array(0, new NextAction("cast custom spell", relevance), nullptr)));
|
||||
triggers.push_back(
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef _PLAYERBOT_RAIDSTRATEGYCONTEXT_H_
|
||||
#define _PLAYERBOT_RAIDSTRATEGYCONTEXT_H_
|
||||
|
||||
#include "RaidUlduarStrategy.h"
|
||||
#include "Strategy.h"
|
||||
#include "raids/blackwinglair/RaidBwlStrategy.h"
|
||||
#include "raids/naxxramas/RaidNaxxStrategy.h"
|
||||
#include "RaidBwlStrategy.h"
|
||||
#include "RaidNaxxStrategy.h"
|
||||
|
||||
class RaidStrategyContext : public NamedObjectContext<Strategy>
|
||||
{
|
||||
@@ -12,11 +13,13 @@ public:
|
||||
{
|
||||
creators["naxx"] = &RaidStrategyContext::naxx;
|
||||
creators["bwl"] = &RaidStrategyContext::bwl;
|
||||
creators["uld"] = &RaidStrategyContext::uld;
|
||||
}
|
||||
|
||||
private:
|
||||
static Strategy* naxx(PlayerbotAI* botAI) { return new RaidNaxxStrategy(botAI); }
|
||||
static Strategy* bwl(PlayerbotAI* botAI) { return new RaidBwlStrategy(botAI); }
|
||||
static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -13,9 +13,15 @@
|
||||
class RaidUlduarActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
public:
|
||||
RaidUlduarActionContext() {}
|
||||
RaidUlduarActionContext()
|
||||
{
|
||||
creators["flame leviathan vehicle"] = &RaidUlduarActionContext::flame_leviathan_vehicle;
|
||||
creators["flame leviathan enter vehicle"] = &RaidUlduarActionContext::flame_leviathan_enter_vehicle;
|
||||
}
|
||||
|
||||
private:
|
||||
static Action* flame_leviathan_vehicle(PlayerbotAI* ai) { return new FlameLeviathanVehicleAction(ai); }
|
||||
static Action* flame_leviathan_enter_vehicle(PlayerbotAI* ai) { return new FlameLeviathanEnterVehicleAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,27 +1,376 @@
|
||||
|
||||
#include "RaidUlduarActions.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "DBCEnums.h"
|
||||
#include "GameObject.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Position.h"
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "RaidUlduarStrategy.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint()
|
||||
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
|
||||
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
|
||||
NPC_SALVAGED_SIEGE_ENGINE_TURRET};
|
||||
|
||||
const std::vector<Position> corners = {
|
||||
{183.53f, 66.53f, 409.80f}, {383.03f, 75.10f, 411.71f}, {379.74f, -133.05f, 410.88f}, {158.67f, -137.54f, 409.80f}};
|
||||
|
||||
bool FlameLeviathanVehicleAction::Execute(Event event)
|
||||
{
|
||||
float minDistance = 0;
|
||||
int ret = -1;
|
||||
for (int i = 0; i < intervals; i++)
|
||||
vehicleBase_ = bot->GetVehicleBase();
|
||||
vehicle_ = bot->GetVehicle();
|
||||
if (!vehicleBase_ || !vehicle_)
|
||||
return false;
|
||||
|
||||
GuidVector attackers = context->GetValue<GuidVector>("attackers")->Get();
|
||||
Unit* target = nullptr;
|
||||
Unit* flame = nullptr;
|
||||
for (auto i = attackers.begin(); i != attackers.end(); ++i)
|
||||
{
|
||||
float w_x = waypoints[i].first, w_y = waypoints[i].second;
|
||||
float dis = bot->GetDistance2d(w_x, w_y);
|
||||
if (ret == -1 || dis < minDistance)
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit->GetEntry() == 33139) // Flame Leviathan Turret
|
||||
continue;
|
||||
if (unit->GetEntry() == 33142) // Leviathan Defense Turret
|
||||
continue;
|
||||
if (unit->GetEntry() == 33113) // Flame Leviathan
|
||||
flame = unit;
|
||||
if (!target || bot->GetExactDist(target) > bot->GetExactDist(unit))
|
||||
{
|
||||
ret = i;
|
||||
minDistance = dis;
|
||||
target = unit;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
// Flame Leviathan is chasing me
|
||||
if (flame && flame->GetVictim() == vehicleBase_)
|
||||
if (MoveAvoidChasing(flame))
|
||||
return true;
|
||||
|
||||
uint32 entry = vehicleBase_->GetEntry();
|
||||
switch (entry)
|
||||
{
|
||||
case NPC_SALVAGED_DEMOLISHER:
|
||||
return DemolisherAction(target);
|
||||
case NPC_SALVAGED_DEMOLISHER_TURRET:
|
||||
return DemolisherTurretAction(target);
|
||||
case NPC_SALVAGED_SIEGE_ENGINE:
|
||||
return SiegeEngineAction(flame ? flame : target);
|
||||
case NPC_SALVAGED_SIEGE_ENGINE_TURRET:
|
||||
return SiegeEngineTurretAction(target);
|
||||
case NPC_VEHICLE_CHOPPER:
|
||||
return ChopperAction(target);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleAction::MoveAvoidChasing(Unit* target)
|
||||
{
|
||||
if (avoidChaseIdx == -1)
|
||||
{
|
||||
for (int i = 0; i < corners.size(); i++)
|
||||
{
|
||||
if (bot->GetExactDist(corners[i]) > target->GetExactDist(corners[i]))
|
||||
continue;
|
||||
if (avoidChaseIdx == -1 || bot->GetExactDist(corners[i]) > bot->GetExactDist(corners[avoidChaseIdx]))
|
||||
avoidChaseIdx = i;
|
||||
}
|
||||
if (avoidChaseIdx == -1)
|
||||
avoidChaseIdx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bot->GetExactDist(corners[avoidChaseIdx]) < 5.0f && target->GetExactDist(bot) < 50.0f)
|
||||
avoidChaseIdx = (avoidChaseIdx + 1) % corners.size();
|
||||
}
|
||||
const Position& to = corners[avoidChaseIdx];
|
||||
return MoveTo(bot->GetMap()->GetId(), to.GetPositionX(), to.GetPositionY(), to.GetPositionZ(), false, false, false,
|
||||
false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleAction::DemolisherAction(Unit* target)
|
||||
{
|
||||
Aura* bluePyrite = target->GetAura(68605);
|
||||
if (!bluePyrite || (bluePyrite->GetStackAmount() <= 6 && vehicleBase_->GetPower(POWER_ENERGY) > 25) || bluePyrite->GetDuration() <= 5000)
|
||||
{
|
||||
uint32 spellId = 62490;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
uint32 spellId = 62306;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleAction::DemolisherTurretAction(Unit* target)
|
||||
{
|
||||
{
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest npcs");
|
||||
for (auto i = npcs.begin(); i != npcs.end(); i++)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit->GetEntry() == 33189 && vehicleBase_->GetPower(POWER_ENERGY) <= 25) // Liquid Pyrite
|
||||
{
|
||||
uint32 spellId = 62479;
|
||||
if (botAI->CanCastVehicleSpell(spellId, unit))
|
||||
if (botAI->CastVehicleSpell(spellId, unit))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
for (auto i = targets.begin(); i != targets.end(); i++)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (!unit)
|
||||
continue;
|
||||
if (unit->GetEntry() == 33214) // Mechanolift 304-A
|
||||
{
|
||||
uint32 spellId = 64979;
|
||||
if (botAI->CanCastVehicleSpell(spellId, unit))
|
||||
if (botAI->CastVehicleSpell(spellId, unit))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32 spellId = 62634;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleAction::SiegeEngineAction(Unit* target)
|
||||
{
|
||||
if (target->GetCurrentSpell(CURRENT_CHANNELED_SPELL) || target->HasAura(62396))
|
||||
{
|
||||
uint32 spellId = 62522;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 10000);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
uint32 spellId = 62345;
|
||||
if (vehicleBase_->GetPower(POWER_ENERGY) >= 80 && botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleAction::SiegeEngineTurretAction(Unit* target)
|
||||
{
|
||||
uint32 spellId = 62358;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleAction::ChopperAction(Unit* target)
|
||||
{
|
||||
uint32 spellId = 62286;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 15000);
|
||||
return true;
|
||||
}
|
||||
spellId = 62974;
|
||||
if (botAI->CanCastVehicleSpell(spellId, target))
|
||||
if (botAI->CastVehicleSpell(spellId, target))
|
||||
{
|
||||
vehicleBase_->AddSpellCooldown(spellId, 0, 1000);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanEnterVehicleAction::Execute(Event event)
|
||||
{
|
||||
// do not switch vehicles yet
|
||||
if (bot->GetVehicle())
|
||||
return false;
|
||||
Unit* vehicleToEnter = nullptr;
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest vehicles far");
|
||||
for (GuidVector::iterator i = npcs.begin(); i != npcs.end(); i++)
|
||||
{
|
||||
Unit* vehicleBase = botAI->GetUnit(*i);
|
||||
if (!vehicleBase)
|
||||
continue;
|
||||
|
||||
if (vehicleBase->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
|
||||
continue;
|
||||
|
||||
if (!ShouldEnter(vehicleBase))
|
||||
continue;
|
||||
|
||||
if (!vehicleToEnter || bot->GetExactDist(vehicleToEnter) > bot->GetExactDist(vehicleBase))
|
||||
vehicleToEnter = vehicleBase;
|
||||
}
|
||||
|
||||
if (!vehicleToEnter)
|
||||
return false;
|
||||
|
||||
if (EnterVehicle(vehicleToEnter, true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanEnterVehicleAction::EnterVehicle(Unit* vehicleBase, bool moveIfFar)
|
||||
{
|
||||
float dist = bot->GetDistance(vehicleBase);
|
||||
|
||||
if (dist > INTERACTION_DISTANCE && !moveIfFar)
|
||||
return false;
|
||||
|
||||
if (dist > INTERACTION_DISTANCE)
|
||||
return MoveTo(vehicleBase);
|
||||
|
||||
botAI->RemoveShapeshift();
|
||||
// Use HandleSpellClick instead of Unit::EnterVehicle to handle special vehicle script (ulduar)
|
||||
vehicleBase->HandleSpellClick(bot);
|
||||
|
||||
if (!bot->IsOnVehicle(vehicleBase))
|
||||
return false;
|
||||
|
||||
// dismount because bots can enter vehicle on mount
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlameLeviathanEnterVehicleAction::ShouldEnter(Unit* target)
|
||||
{
|
||||
Vehicle* vehicleKit = target->GetVehicleKit();
|
||||
if (!vehicleKit)
|
||||
return false;
|
||||
|
||||
bool isMelee = botAI->IsMelee(bot);
|
||||
bool allMain = AllMainVehiclesOnUse();
|
||||
bool inUse = vehicleKit->IsVehicleInUse();
|
||||
int32 entry = target->GetEntry();
|
||||
if (entry != NPC_SALVAGED_DEMOLISHER && entry != NPC_SALVAGED_SIEGE_ENGINE && entry != NPC_VEHICLE_CHOPPER)
|
||||
return false;
|
||||
// two phase enter (make all main vehicles in use -> next player enter)
|
||||
if (!allMain)
|
||||
{
|
||||
if (inUse)
|
||||
return false;
|
||||
if (entry != NPC_SALVAGED_DEMOLISHER && entry != NPC_SALVAGED_SIEGE_ENGINE)
|
||||
return false;
|
||||
if (entry == NPC_SALVAGED_DEMOLISHER && isMelee)
|
||||
return false;
|
||||
if (entry == NPC_SALVAGED_SIEGE_ENGINE && !isMelee)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!vehicleKit->GetAvailableSeatCount())
|
||||
return false;
|
||||
|
||||
// do not enter useless seat
|
||||
if (entry == NPC_SALVAGED_SIEGE_ENGINE)
|
||||
{
|
||||
Unit* turret = vehicleKit->GetPassenger(7);
|
||||
if (!turret)
|
||||
return false;
|
||||
Vehicle* turretVehicle = turret->GetVehicleKit();
|
||||
if (!turretVehicle)
|
||||
return false;
|
||||
if (turretVehicle->IsVehicleInUse())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry == NPC_SALVAGED_DEMOLISHER)
|
||||
{
|
||||
if (vehicleKit->GetPassenger(0))
|
||||
{
|
||||
Unit* target2 = vehicleKit->GetPassenger(1);
|
||||
if (!target2)
|
||||
return false;
|
||||
Vehicle* vehicle2 = target2->GetVehicleKit();
|
||||
if (!vehicle2)
|
||||
return false;
|
||||
if (vehicle2->GetPassenger(0))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry == NPC_VEHICLE_CHOPPER && vehicleKit->GetAvailableSeatCount() <= 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlameLeviathanEnterVehicleAction::AllMainVehiclesOnUse()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
int demolisher = 0;
|
||||
int siege = 0;
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
if (!player)
|
||||
continue;
|
||||
Unit* vehicleBase = player->GetVehicleBase();
|
||||
if (!vehicleBase)
|
||||
continue;
|
||||
if (vehicleBase->GetEntry() == NPC_SALVAGED_DEMOLISHER)
|
||||
++demolisher;
|
||||
else if (vehicleBase->GetEntry() == NPC_SALVAGED_SIEGE_ENGINE)
|
||||
++siege;
|
||||
}
|
||||
Difficulty diff = bot->GetRaidDifficulty();
|
||||
int maxC = (diff == RAID_DIFFICULTY_10MAN_NORMAL || diff == RAID_DIFFICULTY_10MAN_HEROIC) ? 2 : 5;
|
||||
return demolisher >= maxC && siege >= maxC;
|
||||
}
|
||||
@@ -4,20 +4,42 @@
|
||||
#include "Action.h"
|
||||
#include "AttackAction.h"
|
||||
#include "GenericActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "MovementActions.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
// just for test
|
||||
// class TryToGetBossAIAction : public Action
|
||||
// {
|
||||
// public:
|
||||
// TryToGetBossAIAction(PlayerbotAI* ai) : Action(ai, "try to get boss ai") {}
|
||||
class FlameLeviathanVehicleAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
FlameLeviathanVehicleAction(PlayerbotAI* botAI) : MovementAction(botAI, "flame leviathan vehicle") {}
|
||||
bool Execute(Event event) override;
|
||||
|
||||
// public:
|
||||
// virtual bool Execute(Event event);
|
||||
// };
|
||||
protected:
|
||||
bool MoveAvoidChasing(Unit* target);
|
||||
bool DemolisherAction(Unit* target);
|
||||
bool DemolisherTurretAction(Unit* target);
|
||||
bool SiegeEngineAction(Unit* target);
|
||||
bool SiegeEngineTurretAction(Unit* target);
|
||||
bool ChopperAction(Unit* target);
|
||||
Unit* GetAttacker();
|
||||
Unit* vehicleBase_;
|
||||
Vehicle* vehicle_;
|
||||
int avoidChaseIdx = -1;
|
||||
};
|
||||
|
||||
class FlameLeviathanEnterVehicleAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
FlameLeviathanEnterVehicleAction(PlayerbotAI* botAI) : MovementAction(botAI, "flame leviathan enter vehicle") {}
|
||||
bool Execute(Event event);
|
||||
|
||||
protected:
|
||||
bool EnterVehicle(Unit* vehicleBase, bool moveIfFar);
|
||||
bool ShouldEnter(Unit* vehicleBase);
|
||||
bool AllMainVehiclesOnUse();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -11,73 +11,72 @@
|
||||
#include "Player.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
const uint32 ULDUAR_MAP_ID = 603;
|
||||
|
||||
template <class BossAiType>
|
||||
class GenericBossHelper : public AiObject
|
||||
{
|
||||
public:
|
||||
GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {}
|
||||
virtual bool UpdateBossAI()
|
||||
{
|
||||
if (!bot->IsInCombat())
|
||||
{
|
||||
_unit = nullptr;
|
||||
}
|
||||
if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive()))
|
||||
{
|
||||
_unit = nullptr;
|
||||
}
|
||||
if (!_unit)
|
||||
{
|
||||
_unit = AI_VALUE2(Unit*, "find target", _name);
|
||||
if (!_unit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_target = _unit->ToCreature();
|
||||
if (!_target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_ai = dynamic_cast<BossAiType*>(_target->GetAI());
|
||||
if (!_ai)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_event_map = &_ai->events;
|
||||
if (!_event_map)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!_event_map)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_timer = _event_map->GetTimer();
|
||||
return true;
|
||||
}
|
||||
virtual void Reset()
|
||||
{
|
||||
_unit = nullptr;
|
||||
_target = nullptr;
|
||||
_ai = nullptr;
|
||||
_event_map = nullptr;
|
||||
_timer = 0;
|
||||
}
|
||||
// template <class BossAiType>
|
||||
// class GenericBossHelper : public AiObject
|
||||
// {
|
||||
// public:
|
||||
// GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {}
|
||||
// virtual bool UpdateBossAI()
|
||||
// {
|
||||
// if (!bot->IsInCombat())
|
||||
// {
|
||||
// _unit = nullptr;
|
||||
// }
|
||||
// if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive()))
|
||||
// {
|
||||
// _unit = nullptr;
|
||||
// }
|
||||
// if (!_unit)
|
||||
// {
|
||||
// _unit = AI_VALUE2(Unit*, "find target", _name);
|
||||
// if (!_unit)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// _target = _unit->ToCreature();
|
||||
// if (!_target)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// _ai = dynamic_cast<BossAiType*>(_target->GetAI());
|
||||
// if (!_ai)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// _event_map = &_ai->events;
|
||||
// if (!_event_map)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// if (!_event_map)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// _timer = _event_map->GetTimer();
|
||||
// return true;
|
||||
// }
|
||||
// virtual void Reset()
|
||||
// {
|
||||
// _unit = nullptr;
|
||||
// _target = nullptr;
|
||||
// _ai = nullptr;
|
||||
// _event_map = nullptr;
|
||||
// _timer = 0;
|
||||
// }
|
||||
|
||||
protected:
|
||||
std::string _name;
|
||||
Unit* _unit = nullptr;
|
||||
Creature* _target = nullptr;
|
||||
BossAiType* _ai = nullptr;
|
||||
EventMap* _event_map = nullptr;
|
||||
uint32 _timer = 0;
|
||||
};
|
||||
// protected:
|
||||
// std::string _name;
|
||||
// Unit* _unit = nullptr;
|
||||
// Creature* _target = nullptr;
|
||||
// BossAiType* _ai = nullptr;
|
||||
// EventMap* _event_map = nullptr;
|
||||
// uint32 _timer = 0;
|
||||
// };
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,3 +19,10 @@
|
||||
#include "ShamanActions.h"
|
||||
#include "UseMeetingStoneAction.h"
|
||||
#include "WarriorActions.h"
|
||||
|
||||
float FlameLeviathanMultiplier::GetValue(Action* action)
|
||||
{
|
||||
// if (dynamic_cast<FleeAction*>(action))
|
||||
// return 0.0f;
|
||||
return 1.0f;
|
||||
}
|
||||
@@ -5,4 +5,13 @@
|
||||
#include "Multiplier.h"
|
||||
#include "raids/ulduar/RaidUlduarBossHelper.h"
|
||||
|
||||
class FlameLeviathanMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
FlameLeviathanMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flame leviathan") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
// There are no header files for bosses in Ulduar directory
|
||||
//#include "../../../../src/server/scripts/Northrend/Ulduar/Ulduar/"
|
||||
#include "../../../../src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
#include "RaidUlduarMultipliers.h"
|
||||
|
||||
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers) {}
|
||||
void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// Flame Leviathan
|
||||
triggers.push_back(new TriggerNode(
|
||||
"flame leviathan vehicle near",
|
||||
NextAction::array(0, new NextAction("flame leviathan enter vehicle", ACTION_RAID + 2), nullptr)));
|
||||
|
||||
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers) {}
|
||||
triggers.push_back(new TriggerNode(
|
||||
"flame leviathan on vehicle",
|
||||
NextAction::array(0, new NextAction("flame leviathan vehicle", ACTION_RAID + 1), nullptr)));
|
||||
|
||||
}
|
||||
|
||||
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new FlameLeviathanMultiplier(botAI));
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
|
||||
#include "AiObjectContext.h"
|
||||
#include "Multiplier.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
class RaidUlduarStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
RaidUlduarStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||
virtual std::string const getName() override { return "ulduar"; }
|
||||
virtual std::string const getName() override { return "uld"; }
|
||||
virtual void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
virtual void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
};
|
||||
|
||||
@@ -13,9 +13,15 @@
|
||||
class RaidUlduarTriggerContext : public NamedObjectContext<Trigger>
|
||||
{
|
||||
public:
|
||||
RaidUlduarTriggerContext() {}
|
||||
RaidUlduarTriggerContext()
|
||||
{
|
||||
creators["flame leviathan on vehicle"] = &RaidUlduarTriggerContext::flame_leviathan_on_vehicle;
|
||||
creators["flame leviathan vehicle near"] = &RaidUlduarTriggerContext::flame_leviathan_vehicle_near;
|
||||
}
|
||||
|
||||
private:
|
||||
static Trigger* flame_leviathan_on_vehicle(PlayerbotAI* ai) { return new FlameLeviathanOnVehicleTrigger(ai); }
|
||||
static Trigger* flame_leviathan_vehicle_near(PlayerbotAI* ai) { return new FlameLeviathanVehicleNearTrigger(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,45 @@
|
||||
#include "RaidUlduarTriggers.h"
|
||||
|
||||
#include "EventMap.h"
|
||||
#include "Object.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Trigger.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
|
||||
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
|
||||
NPC_SALVAGED_SIEGE_ENGINE_TURRET};
|
||||
|
||||
bool FlameLeviathanOnVehicleTrigger::IsActive()
|
||||
{
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
Vehicle* vehicle = bot->GetVehicle();
|
||||
if (!vehicleBase || !vehicle)
|
||||
return false;
|
||||
|
||||
uint32 entry = vehicleBase->GetEntry();
|
||||
for (uint32 comp : availableVehicles)
|
||||
{
|
||||
if (entry == comp)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FlameLeviathanVehicleNearTrigger::IsActive()
|
||||
{
|
||||
if (bot->GetVehicle())
|
||||
return false;
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
if (!master->GetVehicle())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,21 @@
|
||||
#include "GenericTriggers.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "Trigger.h"
|
||||
|
||||
|
||||
class FlameLeviathanOnVehicleTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
FlameLeviathanOnVehicleTrigger(PlayerbotAI* ai) : Trigger(ai, "flame leviathan on vehicle") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FlameLeviathanVehicleNearTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
FlameLeviathanVehicleNearTrigger(PlayerbotAI* ai) : Trigger(ai, "flame leviathan vehicle near") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -77,6 +77,8 @@ public:
|
||||
creators["grind"] = &ChatTriggerContext::grind;
|
||||
creators["tank attack"] = &ChatTriggerContext::tank_attack;
|
||||
creators["talk"] = &ChatTriggerContext::talk;
|
||||
creators["enter vehicle"] = &ChatTriggerContext::enter_vehicle;
|
||||
creators["leave vehicle"] = &ChatTriggerContext::leave_vehicle;
|
||||
creators["cast"] = &ChatTriggerContext::cast;
|
||||
creators["castnc"] = &ChatTriggerContext::castnc;
|
||||
creators["invite"] = &ChatTriggerContext::invite;
|
||||
@@ -155,6 +157,8 @@ private:
|
||||
static Trigger* cast(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cast"); }
|
||||
static Trigger* castnc(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "castnc"); }
|
||||
static Trigger* talk(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "talk"); }
|
||||
static Trigger* enter_vehicle(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "enter vehicle"); }
|
||||
static Trigger* leave_vehicle(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "leave vehicle"); }
|
||||
static Trigger* flee(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "flee"); }
|
||||
static Trigger* grind(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "grind"); }
|
||||
static Trigger* tank_attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "tank attack"); }
|
||||
|
||||
@@ -106,6 +106,7 @@ public:
|
||||
creators["nearest npcs"] = &ValueContext::nearest_npcs;
|
||||
creators["nearest totems"] = &ValueContext::nearest_totems;
|
||||
creators["nearest vehicles"] = &ValueContext::nearest_vehicles;
|
||||
creators["nearest vehicles far"] = &ValueContext::nearest_vehicles_far;
|
||||
creators["nearest friendly players"] = &ValueContext::nearest_friendly_players;
|
||||
creators["closest friendly players"] = &ValueContext::closest_friendly_players;
|
||||
creators["nearest enemy players"] = &ValueContext::nearest_enemy_players;
|
||||
@@ -394,6 +395,7 @@ private:
|
||||
static UntypedValue* nearest_npcs(PlayerbotAI* botAI) { return new NearestNpcsValue(botAI); }
|
||||
static UntypedValue* nearest_totems(PlayerbotAI* botAI) { return new NearestTotemsValue(botAI); }
|
||||
static UntypedValue* nearest_vehicles(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI); }
|
||||
static UntypedValue* nearest_vehicles_far(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI, 200.0f); }
|
||||
static UntypedValue* nearest_friendly_players(PlayerbotAI* botAI) { return new NearestFriendlyPlayersValue(botAI); }
|
||||
static UntypedValue* closest_friendly_players(PlayerbotAI* botAI)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user