mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-01 09:53:47 +00:00
Merge pull request #302 from liyunfan1223/dev-combat-formation
Dev combat formation
This commit is contained in:
@@ -21,18 +21,9 @@ AiPlayerbot.BotAutologin = 0
|
|||||||
# Default: 0 (disabled)
|
# Default: 0 (disabled)
|
||||||
AiPlayerbot.AllowPlayerBots = 0
|
AiPlayerbot.AllowPlayerBots = 0
|
||||||
|
|
||||||
# Guild Task system
|
|
||||||
AiPlayerbot.EnableGuildTasks = 0
|
|
||||||
|
|
||||||
# Enable LFG for random bots
|
# Enable LFG for random bots
|
||||||
AiPlayerbot.RandomBotJoinLfg = 1
|
AiPlayerbot.RandomBotJoinLfg = 1
|
||||||
|
|
||||||
# Enable dungeon suggestions for random bots
|
|
||||||
AiPlayerbot.RandomBotSuggestDungeons = 1
|
|
||||||
|
|
||||||
# Enable dungeon suggestions in lower case randomly
|
|
||||||
AiPlayerbot.SuggestDungeonsInLowerCaseRandomly = 0
|
|
||||||
|
|
||||||
# Enable BG/Arena for random Bots
|
# Enable BG/Arena for random Bots
|
||||||
AiPlayerbot.RandomBotJoinBG = 1
|
AiPlayerbot.RandomBotJoinBG = 1
|
||||||
|
|
||||||
@@ -60,12 +51,6 @@ AiPlayerbot.RotationPoolSize = 500
|
|||||||
AiPlayerbot.RandomBotAccountPrefix = "rndbot"
|
AiPlayerbot.RandomBotAccountPrefix = "rndbot"
|
||||||
AiPlayerbot.RandomBotAccountCount = 200
|
AiPlayerbot.RandomBotAccountCount = 200
|
||||||
|
|
||||||
# Random bot guild count
|
|
||||||
AiPlayerbot.RandomBotGuildCount = 20
|
|
||||||
|
|
||||||
# Delete all random bot guilds
|
|
||||||
AiPlayerbot.DeleteRandomBotGuilds = 0
|
|
||||||
|
|
||||||
# Random bot arena team count
|
# Random bot arena team count
|
||||||
AiPlayerbot.RandomBotArenaTeamCount = 20
|
AiPlayerbot.RandomBotArenaTeamCount = 20
|
||||||
|
|
||||||
@@ -78,18 +63,6 @@ AiPlayerbot.RandomGearLoweringChance = 0
|
|||||||
# Chance random bot has max level on first randomize (default 0.15)
|
# Chance random bot has max level on first randomize (default 0.15)
|
||||||
AiPlayerbot.RandomBotMaxLevelChance = 0.15
|
AiPlayerbot.RandomBotMaxLevelChance = 0.15
|
||||||
|
|
||||||
# Chance bot chooses RPG (Teleport to random camp for their level) instead of grinding
|
|
||||||
AiPlayerbot.RandomBotRpgChance = 0.20 #unused now
|
|
||||||
|
|
||||||
# Set randombots movement speed to walking anywhere
|
|
||||||
AiPlayerbot.RandombotsWalkingRPG = 0
|
|
||||||
|
|
||||||
# Set randombots movement speed to walking only inside buildings
|
|
||||||
AiPlayerbot.RandombotsWalkingRPG.InDoors = 0
|
|
||||||
|
|
||||||
# Bots greet to the players
|
|
||||||
AiPlayerbot.EnableGreet = 0
|
|
||||||
|
|
||||||
# Bots will be summoned to player when accept group invitation
|
# Bots will be summoned to player when accept group invitation
|
||||||
AiPlayerbot.SummonWhenGroup = 1
|
AiPlayerbot.SummonWhenGroup = 1
|
||||||
|
|
||||||
@@ -116,10 +89,6 @@ AiPlayerbot.KillXPRate = 1
|
|||||||
# Need to reset rndbot after changing the setting (.playerbot rndbot reset)
|
# Need to reset rndbot after changing the setting (.playerbot rndbot reset)
|
||||||
AiPlayerbot.DisableDeathKnightLogin = 0
|
AiPlayerbot.DisableDeathKnightLogin = 0
|
||||||
|
|
||||||
# Specify percent of active bots
|
|
||||||
# The default is 10. With 10% of all bots going active or inactive each minute.
|
|
||||||
AiPlayerbot.BotActiveAlone = 100
|
|
||||||
|
|
||||||
# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable)
|
# Set minimum level of randombots where gets enchants on items (Maxlevel + 1 to disable)
|
||||||
# Default: 60
|
# Default: 60
|
||||||
AiPlayerbot.MinEnchantingBotLevel = 60
|
AiPlayerbot.MinEnchantingBotLevel = 60
|
||||||
@@ -224,8 +193,8 @@ AiPlayerbot.SyncQuestForPlayer = 0
|
|||||||
AiPlayerbot.SyncLevelWithPlayers = 0
|
AiPlayerbot.SyncLevelWithPlayers = 0
|
||||||
|
|
||||||
# Give free food to random bots
|
# Give free food to random bots
|
||||||
# Default: 0 (disabled)
|
# Default: 1 (enabled)
|
||||||
AiPlayerbot.FreeFood = 0
|
AiPlayerbot.FreeFood = 1
|
||||||
|
|
||||||
# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells)
|
# Bot automatically trains spells when talking to trainer (yes = train all available spells as long as the bot has the money, free = auto trains with no money cost, no = only list spells)
|
||||||
# Only for random bots
|
# Only for random bots
|
||||||
@@ -296,7 +265,7 @@ AiPlayerbot.ReactDelay = 100
|
|||||||
AiPlayerbot.PassiveDelay = 10000
|
AiPlayerbot.PassiveDelay = 10000
|
||||||
|
|
||||||
# Minimum delay between repeating actions (chat messages, emotes etc)
|
# Minimum delay between repeating actions (chat messages, emotes etc)
|
||||||
AiPlayerbot.RepeatDelay = 5000
|
AiPlayerbot.RepeatDelay = 2000
|
||||||
|
|
||||||
# Delay timers
|
# Delay timers
|
||||||
AiPlayerbot.ErrorDelay = 100
|
AiPlayerbot.ErrorDelay = 100
|
||||||
@@ -359,27 +328,6 @@ AiPlayerbot.RandomBotNonCombatStrategies = ""
|
|||||||
AiPlayerbot.CombatStrategies = ""
|
AiPlayerbot.CombatStrategies = ""
|
||||||
AiPlayerbot.NonCombatStrategies = ""
|
AiPlayerbot.NonCombatStrategies = ""
|
||||||
|
|
||||||
# How often tasks are changed
|
|
||||||
AiPlayerbot.MinGuildTaskChangeTime = 172800
|
|
||||||
AiPlayerbot.MaxGuildTaskChangeTime = 432000
|
|
||||||
|
|
||||||
# Mail spam interval
|
|
||||||
AiPlayerbot.MinGuildTaskAdvertisementTime = 300
|
|
||||||
AiPlayerbot.MaxGuildTaskAdvertisementTime = 28800
|
|
||||||
|
|
||||||
# Delay before reward is sent
|
|
||||||
AiPlayerbot.MinGuildTaskRewardTime = 300
|
|
||||||
AiPlayerbot.MaxGuildTaskRewardTime = 3600
|
|
||||||
|
|
||||||
# Cleanup of guild tasks interval
|
|
||||||
AiPlayerbot.GuildTaskAdvertCleanupTime = 300
|
|
||||||
|
|
||||||
# Specify max distance between victim and bot when creating guild kill task
|
|
||||||
AiPlayerbot.GuildTaskKillTaskDistance = 200
|
|
||||||
|
|
||||||
# Distance margin for facade calculations
|
|
||||||
AiPlayerbot.TargetPosRecalcDistance = 0.1
|
|
||||||
|
|
||||||
# Maps where bots can be teleported to
|
# Maps where bots can be teleported to
|
||||||
AiPlayerbot.RandomBotMaps = 0,1,530,571
|
AiPlayerbot.RandomBotMaps = 0,1,530,571
|
||||||
|
|
||||||
@@ -413,12 +361,8 @@ AiPlayerbot.RandomBotCountChangeMaxInterval = 7200
|
|||||||
AiPlayerbot.MinRandomBotInWorldTime = 3600
|
AiPlayerbot.MinRandomBotInWorldTime = 3600
|
||||||
AiPlayerbot.MaxRandomBotInWorldTime = 43200
|
AiPlayerbot.MaxRandomBotInWorldTime = 43200
|
||||||
AiPlayerbot.MinRandomBotRandomizeTime = 302400
|
AiPlayerbot.MinRandomBotRandomizeTime = 302400
|
||||||
AiPlayerbot.MaxRandomRandomizeTime = 1209600
|
AiPlayerbot.MaxRandomBotRandomizeTime = 1209600
|
||||||
AiPlayerbot.RandomBotsPerInterval = 500
|
AiPlayerbot.RandomBotsPerInterval = 500
|
||||||
AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200
|
|
||||||
AiPlayerbot.MaxRandomBotsPriceChangeInterval = 172800
|
|
||||||
AiPlayerbot.MinRandomBotChangeStrategyTime = 180
|
|
||||||
AiPlayerbot.MaxRandomBotChangeStrategyTime = 720
|
|
||||||
AiPlayerbot.MinRandomBotReviveTime = 60
|
AiPlayerbot.MinRandomBotReviveTime = 60
|
||||||
AiPlayerbot.MaxRandomBotReviveTime = 300
|
AiPlayerbot.MaxRandomBotReviveTime = 300
|
||||||
AiPlayerbot.MinRandomBotTeleportInterval = 3600
|
AiPlayerbot.MinRandomBotTeleportInterval = 3600
|
||||||
@@ -440,9 +384,6 @@ AiPlayerbot.CommandServerPort = 8888
|
|||||||
# Enables/Disables performance monitor
|
# Enables/Disables performance monitor
|
||||||
AiPlayerbot.PerfMonEnabled = 0
|
AiPlayerbot.PerfMonEnabled = 0
|
||||||
|
|
||||||
# Allow bots to be summoned near innkeepers
|
|
||||||
AiPlayerbot.SummonAtInnkeepersEnabled = 1
|
|
||||||
|
|
||||||
# Custom config to allow logfiles to be created.
|
# Custom config to allow logfiles to be created.
|
||||||
# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv
|
# Example: AiPlayerbot.AllowedLogFiles = travelNodes.csv,travelPaths.csv,TravelNodeStore.h,bot_movement.csv,bot_location.csv
|
||||||
AiPlayerbot.AllowedLogFiles = ""
|
AiPlayerbot.AllowedLogFiles = ""
|
||||||
@@ -744,6 +685,74 @@ AiPlayerbot.RandomClassSpecIndex.11.1 = 1
|
|||||||
AiPlayerbot.RandomClassSpecProb.11.2 = 40
|
AiPlayerbot.RandomClassSpecProb.11.2 = 40
|
||||||
AiPlayerbot.RandomClassSpecIndex.11.2 = 2
|
AiPlayerbot.RandomClassSpecIndex.11.2 = 2
|
||||||
|
|
||||||
|
##############################################
|
||||||
|
# Deprecated (temporary) #
|
||||||
|
##############################################
|
||||||
|
# Guild Task system
|
||||||
|
AiPlayerbot.EnableGuildTasks = 0
|
||||||
|
|
||||||
|
# Enable dungeon suggestions for random bots
|
||||||
|
AiPlayerbot.RandomBotSuggestDungeons = 1
|
||||||
|
|
||||||
|
# Enable dungeon suggestions in lower case randomly
|
||||||
|
AiPlayerbot.SuggestDungeonsInLowerCaseRandomly = 0
|
||||||
|
|
||||||
|
# Random bot guild count
|
||||||
|
AiPlayerbot.RandomBotGuildCount = 20
|
||||||
|
|
||||||
|
# Delete all random bot guilds
|
||||||
|
AiPlayerbot.DeleteRandomBotGuilds = 0
|
||||||
|
|
||||||
|
# Chance bot chooses RPG (Teleport to random camp for their level) instead of grinding
|
||||||
|
AiPlayerbot.RandomBotRpgChance = 0.20 #unused now
|
||||||
|
|
||||||
|
# Set randombots movement speed to walking anywhere
|
||||||
|
AiPlayerbot.RandombotsWalkingRPG = 0
|
||||||
|
|
||||||
|
# Set randombots movement speed to walking only inside buildings
|
||||||
|
AiPlayerbot.RandombotsWalkingRPG.InDoors = 0
|
||||||
|
|
||||||
|
# Bots greet to the players
|
||||||
|
AiPlayerbot.EnableGreet = 0
|
||||||
|
|
||||||
|
# Specify percent of active bots
|
||||||
|
# The default is 10. With 10% of all bots going active or inactive each minute.
|
||||||
|
AiPlayerbot.BotActiveAlone = 100
|
||||||
|
|
||||||
|
# Premade spell to avoid (undetected spells)
|
||||||
|
# spellid-radius, ...
|
||||||
|
AiPlayerbot.PremadeAvoidAoe = 62234-4
|
||||||
|
|
||||||
|
AiPlayerbot.MinRandomBotsPriceChangeInterval = 7200
|
||||||
|
AiPlayerbot.MaxRandomBotsPriceChangeInterval = 172800
|
||||||
|
AiPlayerbot.MinRandomBotChangeStrategyTime = 180
|
||||||
|
AiPlayerbot.MaxRandomBotChangeStrategyTime = 720
|
||||||
|
|
||||||
|
|
||||||
|
# How often tasks are changed
|
||||||
|
AiPlayerbot.MinGuildTaskChangeTime = 172800
|
||||||
|
AiPlayerbot.MaxGuildTaskChangeTime = 432000
|
||||||
|
|
||||||
|
# Mail spam interval
|
||||||
|
AiPlayerbot.MinGuildTaskAdvertisementTime = 300
|
||||||
|
AiPlayerbot.MaxGuildTaskAdvertisementTime = 28800
|
||||||
|
|
||||||
|
# Delay before reward is sent
|
||||||
|
AiPlayerbot.MinGuildTaskRewardTime = 300
|
||||||
|
AiPlayerbot.MaxGuildTaskRewardTime = 3600
|
||||||
|
|
||||||
|
# Cleanup of guild tasks interval
|
||||||
|
AiPlayerbot.GuildTaskAdvertCleanupTime = 300
|
||||||
|
|
||||||
|
# Specify max distance between victim and bot when creating guild kill task
|
||||||
|
AiPlayerbot.GuildTaskKillTaskDistance = 200
|
||||||
|
|
||||||
|
# Distance margin for facade calculations
|
||||||
|
AiPlayerbot.TargetPosRecalcDistance = 0.1
|
||||||
|
|
||||||
|
# Allow bots to be summoned near innkeepers
|
||||||
|
AiPlayerbot.SummonAtInnkeepersEnabled = 1
|
||||||
|
|
||||||
##################################################################################
|
##################################################################################
|
||||||
# #
|
# #
|
||||||
# Logging Stuff #
|
# Logging Stuff #
|
||||||
|
|||||||
@@ -274,11 +274,12 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
{
|
{
|
||||||
engine->addStrategy("avoid aoe");
|
engine->addStrategy("avoid aoe");
|
||||||
}
|
}
|
||||||
|
engine->addStrategy("combat formation");
|
||||||
switch (player->getClass())
|
switch (player->getClass())
|
||||||
{
|
{
|
||||||
case CLASS_PRIEST:
|
case CLASS_PRIEST:
|
||||||
if (tab == 2) {
|
if (tab == 2) {
|
||||||
engine->addStrategies("dps", "shadow debuff", "shadow aoe", "threat", nullptr);
|
engine->addStrategies("dps", "shadow debuff", "shadow aoe", nullptr);
|
||||||
} else if (tab == PRIEST_TAB_DISIPLINE) {
|
} else if (tab == PRIEST_TAB_DISIPLINE) {
|
||||||
engine->addStrategies("heal", nullptr);
|
engine->addStrategies("heal", nullptr);
|
||||||
} else {
|
} else {
|
||||||
@@ -289,11 +290,11 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
break;
|
break;
|
||||||
case CLASS_MAGE:
|
case CLASS_MAGE:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
engine->addStrategies("arcane", "arcane aoe", "threat", nullptr);
|
engine->addStrategies("arcane", "arcane aoe", nullptr);
|
||||||
else if (tab == 1)
|
else if (tab == 1)
|
||||||
engine->addStrategies("fire", "fire aoe", "threat", nullptr);
|
engine->addStrategies("fire", "fire aoe", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategies("frost", "frost aoe", "threat", nullptr);
|
engine->addStrategies("frost", "frost aoe", nullptr);
|
||||||
|
|
||||||
engine->addStrategies("dps", "dps assist", "cure", nullptr);
|
engine->addStrategies("dps", "dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
@@ -301,17 +302,17 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
if (tab == 2)
|
if (tab == 2)
|
||||||
engine->addStrategies("tank", "tank assist", "aoe", "mark rti", nullptr);
|
engine->addStrategies("tank", "tank assist", "aoe", "mark rti", nullptr);
|
||||||
else if (player->getLevel() < 36 || tab == 0)
|
else if (player->getLevel() < 36 || tab == 0)
|
||||||
engine->addStrategies("arms", "aoe", "dps assist", "threat", /*"behind",*/ nullptr);
|
engine->addStrategies("arms", "aoe", "dps assist",/*"behind",*/ nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategies("fury", "aoe", "dps assist", "threat", /*"behind",*/ nullptr);
|
engine->addStrategies("fury", "aoe", "dps assist",/*"behind",*/ nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_SHAMAN:
|
case CLASS_SHAMAN:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
engine->addStrategies("caster", "caster aoe", "bmana", "threat", nullptr);
|
engine->addStrategies("caster", "caster aoe", "bmana",nullptr);
|
||||||
else if (tab == 2)
|
else if (tab == 2)
|
||||||
engine->addStrategies("heal", "bmana", nullptr);
|
engine->addStrategies("heal", "bmana", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategies("melee", "melee aoe", "bdps", "threat", nullptr);
|
engine->addStrategies("melee", "melee aoe", "bdps", nullptr);
|
||||||
|
|
||||||
engine->addStrategies("dps assist", "cure", "totems", nullptr);
|
engine->addStrategies("dps assist", "cure", "totems", nullptr);
|
||||||
break;
|
break;
|
||||||
@@ -327,38 +328,41 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
{
|
{
|
||||||
engine->addStrategies("caster", "cure", "caster aoe", "threat", "dps assist", nullptr);
|
engine->addStrategies("caster", "cure", "caster aoe", "dps assist", nullptr);
|
||||||
engine->addStrategy("caster debuff");
|
engine->addStrategy("caster debuff");
|
||||||
}
|
}
|
||||||
else if (tab == 2)
|
else if (tab == 2)
|
||||||
engine->addStrategies("heal", "cure", "dps assist", nullptr);
|
engine->addStrategies("heal", "cure", "dps assist", nullptr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
engine->removeStrategy("flee");
|
if (player->GetLevel() >= 20 && !player->HasAura(16931)/*thick hide*/) {
|
||||||
engine->addStrategies("bear", "tank assist", nullptr);
|
engine->addStrategies("cat", "dps assist", nullptr);
|
||||||
|
} else {
|
||||||
|
engine->addStrategies("bear", "tank assist", nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_HUNTER:
|
case CLASS_HUNTER:
|
||||||
engine->addStrategies("dps", "aoe", "bdps", "threat", "dps assist", nullptr);
|
engine->addStrategies("dps", "aoe", "bdps", "dps assist", nullptr);
|
||||||
engine->addStrategy("dps debuff");
|
engine->addStrategy("dps debuff");
|
||||||
break;
|
break;
|
||||||
case CLASS_ROGUE:
|
case CLASS_ROGUE:
|
||||||
if (tab == ROGUE_TAB_ASSASSINATION) {
|
if (tab == ROGUE_TAB_ASSASSINATION) {
|
||||||
engine->addStrategies("melee", "threat", "dps assist", "aoe", /*"behind",*/ nullptr);
|
engine->addStrategies("melee", "dps assist", "aoe", /*"behind",*/ nullptr);
|
||||||
} else {
|
} else {
|
||||||
engine->addStrategies("dps", "threat", "dps assist", "aoe", /*"behind",*/ nullptr);
|
engine->addStrategies("dps", "dps assist", "aoe", /*"behind",*/ nullptr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CLASS_WARLOCK:
|
case CLASS_WARLOCK:
|
||||||
engine->addStrategies("dps assist", "dps", "dps debuff", "aoe", "threat", nullptr);
|
engine->addStrategies("dps assist", "dps", "dps debuff", "aoe", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_DEATH_KNIGHT:
|
case CLASS_DEATH_KNIGHT:
|
||||||
if (tab == 0)
|
if (tab == 0)
|
||||||
engine->addStrategies("blood", "tank assist", nullptr);
|
engine->addStrategies("blood", "tank assist", nullptr);
|
||||||
else if (tab == 1)
|
else if (tab == 1)
|
||||||
engine->addStrategies("frost", "frost aoe", "dps assist", "threat", nullptr);
|
engine->addStrategies("frost", "frost aoe", "dps assist", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategies("unholy", "unholy aoe", "dps assist", "threat", nullptr);
|
engine->addStrategies("unholy", "unholy aoe", "dps assist", nullptr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -504,8 +508,13 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == 1)
|
if (tab == 1) {
|
||||||
nonCombatEngine->addStrategy("tank assist");
|
if (player->GetLevel() >= 20 && !player->HasAura(16931)/*thick hide*/) {
|
||||||
|
nonCombatEngine->addStrategy("dps assist");
|
||||||
|
} else {
|
||||||
|
nonCombatEngine->addStrategy("tank assist");
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1900,19 +1900,19 @@ bool PlayerbotAI::TellMasterNoFacing(std::string const text, PlayerbotSecurityLe
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
time_t lastSaid = whispers[text];
|
time_t lastSaid = whispers[text];
|
||||||
// Yunfan: Remove tell cooldown
|
|
||||||
// if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
|
|
||||||
// {
|
|
||||||
whispers[text] = time(nullptr);
|
|
||||||
|
|
||||||
ChatMsg type = CHAT_MSG_WHISPER;
|
if (!lastSaid || (time(nullptr) - lastSaid) >= sPlayerbotAIConfig->repeatDelay / 1000)
|
||||||
if (currentChat.second - time(nullptr) >= 1)
|
{
|
||||||
type = currentChat.first;
|
whispers[text] = time(nullptr);
|
||||||
|
|
||||||
WorldPacket data;
|
ChatMsg type = CHAT_MSG_WHISPER;
|
||||||
ChatHandler::BuildChatPacket(data, type == CHAT_MSG_ADDON ? CHAT_MSG_PARTY : type, type == CHAT_MSG_ADDON ? LANG_ADDON : LANG_UNIVERSAL, bot, nullptr, text.c_str());
|
if (currentChat.second - time(nullptr) >= 1)
|
||||||
master->SendDirectMessage(&data);
|
type = currentChat.first;
|
||||||
// }
|
|
||||||
|
WorldPacket data;
|
||||||
|
ChatHandler::BuildChatPacket(data, type == CHAT_MSG_ADDON ? CHAT_MSG_PARTY : type, type == CHAT_MSG_ADDON ? LANG_ADDON : LANG_UNIVERSAL, bot, nullptr, text.c_str());
|
||||||
|
master->SendDirectMessage(&data);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
|
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
|
||||||
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 500);
|
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 500);
|
||||||
passiveDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.PassiveDelay", 10000);
|
passiveDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.PassiveDelay", 10000);
|
||||||
repeatDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RepeatDelay", 5000);
|
repeatDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RepeatDelay", 2000);
|
||||||
errorDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ErrorDelay", 5000);
|
errorDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ErrorDelay", 5000);
|
||||||
rpgDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgDelay", 10000);
|
rpgDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RpgDelay", 10000);
|
||||||
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
|
sitDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.SitDelay", 30000);
|
||||||
@@ -123,7 +123,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
minRandomBotInWorldTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotInWorldTime", 2 * HOUR);
|
minRandomBotInWorldTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotInWorldTime", 2 * HOUR);
|
||||||
maxRandomBotInWorldTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotInWorldTime", 12 * HOUR);
|
maxRandomBotInWorldTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotInWorldTime", 12 * HOUR);
|
||||||
minRandomBotRandomizeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotRandomizeTime", 2 * HOUR);
|
minRandomBotRandomizeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotRandomizeTime", 2 * HOUR);
|
||||||
maxRandomBotRandomizeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomRandomizeTime", 14 * 24 * HOUR);
|
maxRandomBotRandomizeTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotRandomizeTime", 14 * 24 * HOUR);
|
||||||
minRandomBotChangeStrategyTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotChangeStrategyTime", 30 * MINUTE);
|
minRandomBotChangeStrategyTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotChangeStrategyTime", 30 * MINUTE);
|
||||||
maxRandomBotChangeStrategyTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotChangeStrategyTime", 2 * HOUR);
|
maxRandomBotChangeStrategyTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxRandomBotChangeStrategyTime", 2 * HOUR);
|
||||||
minRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotReviveTime", MINUTE);
|
minRandomBotReviveTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MinRandomBotReviveTime", MINUTE);
|
||||||
@@ -327,6 +327,9 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
selfBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.SelfBotLevel", 1);
|
selfBotLevel = sConfigMgr->GetOption<int32>("AiPlayerbot.SelfBotLevel", 1);
|
||||||
|
|
||||||
RandomPlayerbotFactory::CreateRandomBots();
|
RandomPlayerbotFactory::CreateRandomBots();
|
||||||
|
if (World::IsStopped()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
PlayerbotFactory::Init();
|
PlayerbotFactory::Init();
|
||||||
sRandomItemMgr->Init();
|
sRandomItemMgr->Init();
|
||||||
sRandomItemMgr->InitAfterAhBot();
|
sRandomItemMgr->InitAfterAhBot();
|
||||||
|
|||||||
@@ -363,6 +363,11 @@ Player* PlayerbotHolder::GetPlayerBot(ObjectGuid::LowType lowGuid) const
|
|||||||
|
|
||||||
void PlayerbotHolder::OnBotLogin(Player* const bot)
|
void PlayerbotHolder::OnBotLogin(Player* const bot)
|
||||||
{
|
{
|
||||||
|
// Prevent duplicate login
|
||||||
|
if (playerBots.find(bot->GetGUID()) != playerBots.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sPlayerbotsMgr->AddPlayerbotData(bot, true);
|
sPlayerbotsMgr->AddPlayerbotData(bot, true);
|
||||||
playerBots[bot->GetGUID()] = bot;
|
playerBots[bot->GetGUID()] = bot;
|
||||||
OnBotLoginInternal(bot);
|
OnBotLoginInternal(bot);
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ int strcmpi(char const* s1, char const* s2);
|
|||||||
#define AI_VALUE_LAZY(type, name) context->GetValue<type>(name)->LazyGet()
|
#define AI_VALUE_LAZY(type, name) context->GetValue<type>(name)->LazyGet()
|
||||||
#define AI_VALUE2_LAZY(type, name, param) context->GetValue<type>(name, param)->LazyGet()
|
#define AI_VALUE2_LAZY(type, name, param) context->GetValue<type>(name, param)->LazyGet()
|
||||||
|
|
||||||
|
#define AI_VALUE_REF(type, name) context->GetValue<type>(name)->RefGet()
|
||||||
|
|
||||||
#define SET_AI_VALUE(type, name, value) context->GetValue<type>(name)->Set(value)
|
#define SET_AI_VALUE(type, name, value) context->GetValue<type>(name)->Set(value)
|
||||||
#define SET_AI_VALUE2(type, name, param, value) context->GetValue<type>(name, param)->Set(value)
|
#define SET_AI_VALUE2(type, name, param, value) context->GetValue<type>(name, param)->Set(value)
|
||||||
#define RESET_AI_VALUE(type, name) context->GetValue<type>(name)->Reset()
|
#define RESET_AI_VALUE(type, name) context->GetValue<type>(name)->Reset()
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class StrategyContext : public NamedObjectContext<Strategy>
|
|||||||
creators["grind"] = &StrategyContext::grind;
|
creators["grind"] = &StrategyContext::grind;
|
||||||
creators["avoid aoe"] = &StrategyContext::avoid_aoe;
|
creators["avoid aoe"] = &StrategyContext::avoid_aoe;
|
||||||
creators["move random"] = &StrategyContext::move_random;
|
creators["move random"] = &StrategyContext::move_random;
|
||||||
|
creators["combat formation"] = &StrategyContext::combat_formation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -174,6 +175,7 @@ class StrategyContext : public NamedObjectContext<Strategy>
|
|||||||
static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); }
|
static Strategy* grind(PlayerbotAI* botAI) { return new GrindingStrategy(botAI); }
|
||||||
static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); }
|
static Strategy* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeStrategy(botAI); }
|
||||||
static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); }
|
static Strategy* move_random(PlayerbotAI* ai) { return new MoveRandomStrategy(ai); }
|
||||||
|
static Strategy* combat_formation(PlayerbotAI* ai) { return new CombatFormationStrategy(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MovementStrategyContext : public NamedObjectContext<Strategy>
|
class MovementStrategyContext : public NamedObjectContext<Strategy>
|
||||||
|
|||||||
@@ -16,6 +16,16 @@
|
|||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
class Unit;
|
class Unit;
|
||||||
|
|
||||||
|
class FleeInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Position fromPos;
|
||||||
|
float radius;
|
||||||
|
float angle;
|
||||||
|
uint32 timestamp;
|
||||||
|
int GetAngleRangeIndex() { return (angle + 2 * M_PI) / (M_PI / 2); } // [0, 7)
|
||||||
|
};
|
||||||
|
|
||||||
struct CreatureData;
|
struct CreatureData;
|
||||||
|
|
||||||
class UntypedValue : public AiNamedObject
|
class UntypedValue : public AiNamedObject
|
||||||
@@ -37,6 +47,7 @@ class Value
|
|||||||
virtual ~Value() { }
|
virtual ~Value() { }
|
||||||
virtual T Get() = 0;
|
virtual T Get() = 0;
|
||||||
virtual T LazyGet() = 0;
|
virtual T LazyGet() = 0;
|
||||||
|
virtual T& RefGet() = 0;
|
||||||
virtual void Reset() { }
|
virtual void Reset() { }
|
||||||
virtual void Set(T value) = 0;
|
virtual void Set(T value) = 0;
|
||||||
operator T() { return Get(); }
|
operator T() { return Get(); }
|
||||||
@@ -79,7 +90,26 @@ class CalculatedValue : public UntypedValue, public Value<T>
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
T& RefGet() override
|
||||||
|
{
|
||||||
|
if (checkInterval < 2) {
|
||||||
|
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
|
||||||
|
value = Calculate();
|
||||||
|
// if (pmo)
|
||||||
|
// pmo->finish();
|
||||||
|
} else {
|
||||||
|
time_t now = getMSTime();
|
||||||
|
if (!lastCheckTime || now - lastCheckTime >= checkInterval)
|
||||||
|
{
|
||||||
|
lastCheckTime = now;
|
||||||
|
// PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_VALUE, this->getName(), this->context ? &this->context->performanceStack : nullptr);
|
||||||
|
value = Calculate();
|
||||||
|
// if (pmo)
|
||||||
|
// pmo->finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
void Set(T val) override { value = val; }
|
void Set(T val) override { value = val; }
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
void Reset() override { lastCheckTime = 0; }
|
void Reset() override { lastCheckTime = 0; }
|
||||||
@@ -304,6 +334,7 @@ class ManualSetValue : public UntypedValue, public Value<T>
|
|||||||
|
|
||||||
T Get() override { return value; }
|
T Get() override { return value; }
|
||||||
T LazyGet() override { return value; }
|
T LazyGet() override { return value; }
|
||||||
|
T& RefGet() override { return value; }
|
||||||
void Set(T val) override { value = val; }
|
void Set(T val) override { value = val; }
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
void Reset() override
|
void Reset() override
|
||||||
@@ -326,4 +357,32 @@ class UnitManualSetValue : public ManualSetValue<Unit*>
|
|||||||
Unit* Get() override;
|
Unit* Get() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DisperseDistanceValue : public ManualSetValue<float>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DisperseDistanceValue(PlayerbotAI* botAI, float defaultValue = -1.0f, std::string const name = "disperse distance") :
|
||||||
|
ManualSetValue<float>(botAI, defaultValue, name) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class LastFleeAngleValue : public ManualSetValue<float>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LastFleeAngleValue(PlayerbotAI* botAI, float defaultValue = 0.0f, std::string const name = "last flee angle") :
|
||||||
|
ManualSetValue<float>(botAI, defaultValue, name) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class LastFleeTimestampValue : public ManualSetValue<uint32>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LastFleeTimestampValue(PlayerbotAI* botAI, uint32 defaultValue = 0, std::string const name = "last flee timestamp") :
|
||||||
|
ManualSetValue<uint32>(botAI, defaultValue, name) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class RecentlyFleeInfo : public ManualSetValue<std::list<FleeInfo>>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RecentlyFleeInfo(PlayerbotAI* botAI, std::list<FleeInfo> defaultValue = {}, std::string const name = "recently flee info") :
|
||||||
|
ManualSetValue<std::list<FleeInfo>>(botAI, defaultValue, name) { }
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ class ActionContext : public NamedObjectContext<Action>
|
|||||||
creators["flee"] = &ActionContext::flee;
|
creators["flee"] = &ActionContext::flee;
|
||||||
creators["flee with pet"] = &ActionContext::flee_with_pet;
|
creators["flee with pet"] = &ActionContext::flee_with_pet;
|
||||||
creators["avoid aoe"] = &ActionContext::avoid_aoe;
|
creators["avoid aoe"] = &ActionContext::avoid_aoe;
|
||||||
|
creators["combat formation move"] = &ActionContext::combat_formation_move;
|
||||||
|
creators["disperse set"] = &ActionContext::disperse_set;
|
||||||
creators["gift of the naaru"] = &ActionContext::gift_of_the_naaru;
|
creators["gift of the naaru"] = &ActionContext::gift_of_the_naaru;
|
||||||
creators["shoot"] = &ActionContext::shoot;
|
creators["shoot"] = &ActionContext::shoot;
|
||||||
creators["lifeblood"] = &ActionContext::lifeblood;
|
creators["lifeblood"] = &ActionContext::lifeblood;
|
||||||
@@ -265,6 +267,8 @@ class ActionContext : public NamedObjectContext<Action>
|
|||||||
static Action* flee(PlayerbotAI* botAI) { return new FleeAction(botAI); }
|
static Action* flee(PlayerbotAI* botAI) { return new FleeAction(botAI); }
|
||||||
static Action* flee_with_pet(PlayerbotAI* botAI) { return new FleeWithPetAction(botAI); }
|
static Action* flee_with_pet(PlayerbotAI* botAI) { return new FleeWithPetAction(botAI); }
|
||||||
static Action* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeAction(botAI); }
|
static Action* avoid_aoe(PlayerbotAI* botAI) { return new AvoidAoeAction(botAI); }
|
||||||
|
static Action* combat_formation_move(PlayerbotAI* botAI) { return new CombatFormationMoveAction(botAI); }
|
||||||
|
static Action* disperse_set(PlayerbotAI* botAI) { return new DisperseSetAction(botAI); }
|
||||||
static Action* gift_of_the_naaru(PlayerbotAI* botAI) { return new CastGiftOfTheNaaruAction(botAI); }
|
static Action* gift_of_the_naaru(PlayerbotAI* botAI) { return new CastGiftOfTheNaaruAction(botAI); }
|
||||||
static Action* lifeblood(PlayerbotAI* botAI) { return new CastLifeBloodAction(botAI); }
|
static Action* lifeblood(PlayerbotAI* botAI) { return new CastLifeBloodAction(botAI); }
|
||||||
static Action* arcane_torrent(PlayerbotAI* botAI) { return new CastArcaneTorrentAction(botAI); }
|
static Action* arcane_torrent(PlayerbotAI* botAI) { return new CastArcaneTorrentAction(botAI); }
|
||||||
|
|||||||
@@ -44,9 +44,11 @@ bool ChangeTalentsAction::Execute(Event event)
|
|||||||
} else if (param.find("spec ") != std::string::npos) {
|
} else if (param.find("spec ") != std::string::npos) {
|
||||||
param = param.substr(5);
|
param = param.substr(5);
|
||||||
out << SpecPick(param);
|
out << SpecPick(param);
|
||||||
|
botAI->ResetStrategies();
|
||||||
} else if (param.find("apply ") != std::string::npos) {
|
} else if (param.find("apply ") != std::string::npos) {
|
||||||
param = param.substr(6);
|
param = param.substr(6);
|
||||||
out << SpecApply(param);
|
out << SpecApply(param);
|
||||||
|
botAI->ResetStrategies();
|
||||||
} else {
|
} else {
|
||||||
out << "Unknown command.";
|
out << "Unknown command.";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "MovementActions.h"
|
#include "MovementActions.h"
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
|
#include "Geometry.h"
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
#include "MotionMaster.h"
|
#include "MotionMaster.h"
|
||||||
#include "MoveSplineInitArgs.h"
|
#include "MoveSplineInitArgs.h"
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "PathGenerator.h"
|
#include "PathGenerator.h"
|
||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
|
#include "Position.h"
|
||||||
#include "Random.h"
|
#include "Random.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "SpellAuraEffects.h"
|
#include "SpellAuraEffects.h"
|
||||||
@@ -25,10 +27,15 @@
|
|||||||
#include "LootObjectStack.h"
|
#include "LootObjectStack.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
|
#include "Timer.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "Unit.h"
|
#include "Unit.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
#include "WaypointMovementGenerator.h"
|
#include "WaypointMovementGenerator.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
MovementAction::MovementAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name)
|
MovementAction::MovementAction(PlayerbotAI* botAI, std::string const name) : Action(botAI, name)
|
||||||
{
|
{
|
||||||
@@ -1495,6 +1502,9 @@ bool FleeWithPetAction::Execute(Event event)
|
|||||||
|
|
||||||
bool AvoidAoeAction::isUseful()
|
bool AvoidAoeAction::isUseful()
|
||||||
{
|
{
|
||||||
|
if (getMSTime() - moveInterval < lastMoveTimer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
GuidVector traps = AI_VALUE(GuidVector, "nearest trap with damage");
|
GuidVector traps = AI_VALUE(GuidVector, "nearest trap with damage");
|
||||||
GuidVector triggers = AI_VALUE(GuidVector, "possible triggers");
|
GuidVector triggers = AI_VALUE(GuidVector, "possible triggers");
|
||||||
return AI_VALUE(Aura*, "area debuff") || !traps.empty() || !triggers.empty();
|
return AI_VALUE(Aura*, "area debuff") || !traps.empty() || !triggers.empty();
|
||||||
@@ -1540,8 +1550,15 @@ bool AvoidAoeAction::AvoidAuraWithDynamicObj()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::ostringstream name;
|
std::ostringstream name;
|
||||||
name << spellInfo->SpellName[0]; // << "] (aura)";
|
name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (aura)";
|
||||||
if (FleePosition(dynOwner->GetPosition(), radius, name.str())) {
|
if (FleePosition(dynOwner->GetPosition(), radius)) {
|
||||||
|
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
||||||
|
lastTellTimer = time(NULL);
|
||||||
|
lastMoveTimer = getMSTime();
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "I'm avoiding " << name.str() << "...";
|
||||||
|
bot->Say(out.str(), LANG_UNIVERSAL);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1591,8 +1608,15 @@ bool AvoidAoeAction::AvoidGameObjectWithDamage()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::ostringstream name;
|
std::ostringstream name;
|
||||||
name << spellInfo->SpellName[0]; // << "] (object)";
|
name << spellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; // << "] (object)";
|
||||||
if (FleePosition(go->GetPosition(), radius, name.str())) {
|
if (FleePosition(go->GetPosition(), radius)) {
|
||||||
|
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
||||||
|
lastTellTimer = time(NULL);
|
||||||
|
lastMoveTimer = getMSTime();
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "I'm avoiding " << name.str() << "...";
|
||||||
|
bot->Say(out.str(), LANG_UNIVERSAL);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1633,9 +1657,15 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::ostringstream name;
|
std::ostringstream name;
|
||||||
name << triggerSpellInfo->SpellName[0]; //<< "] (unit)";
|
name << triggerSpellInfo->SpellName[sWorld->GetDefaultDbcLocale()]; //<< "] (unit)";
|
||||||
if (FleePosition(unit->GetPosition(), radius, name.str())) {
|
if (FleePosition(unit->GetPosition(), radius)) {
|
||||||
return true;
|
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
||||||
|
lastTellTimer = time(NULL);
|
||||||
|
lastMoveTimer = getMSTime();
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "I'm avoiding " << name.str() << "...";
|
||||||
|
bot->Say(out.str(), LANG_UNIVERSAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1645,7 +1675,7 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius)
|
Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
||||||
{
|
{
|
||||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||||
std::vector<CheckAngle> possibleAngles;
|
std::vector<CheckAngle> possibleAngles;
|
||||||
@@ -1670,13 +1700,18 @@ Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius)
|
|||||||
Position bestPos;
|
Position bestPos;
|
||||||
for (CheckAngle &checkAngle : possibleAngles) {
|
for (CheckAngle &checkAngle : possibleAngles) {
|
||||||
float angle = checkAngle.angle;
|
float angle = checkAngle.angle;
|
||||||
|
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||||
|
if (!CheckLastFlee(angle, infoList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
bool strict = checkAngle.strict;
|
bool strict = checkAngle.strict;
|
||||||
float fleeDis = sPlayerbotAIConfig->fleeDistance;
|
float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance);
|
||||||
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
|
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
|
||||||
bot->GetPositionY() + sin(angle) * fleeDis,
|
bot->GetPositionY() + sin(angle) * fleeDis,
|
||||||
bot->GetPositionZ()};
|
bot->GetPositionZ()};
|
||||||
if (strict && currentTarget
|
if (strict && currentTarget
|
||||||
&& fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance) {
|
&& fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance
|
||||||
|
&& bot->IsWithinMeleeRange(currentTarget)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pos.GetExactDist(fleePos) > farestDis) {
|
if (pos.GetExactDist(fleePos) > farestDis) {
|
||||||
@@ -1690,7 +1725,7 @@ Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius)
|
|||||||
return Position();
|
return Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius)
|
Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius)
|
||||||
{
|
{
|
||||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||||
std::vector<CheckAngle> possibleAngles;
|
std::vector<CheckAngle> possibleAngles;
|
||||||
@@ -1713,8 +1748,12 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius)
|
|||||||
Position bestPos;
|
Position bestPos;
|
||||||
for (CheckAngle &checkAngle : possibleAngles) {
|
for (CheckAngle &checkAngle : possibleAngles) {
|
||||||
float angle = checkAngle.angle;
|
float angle = checkAngle.angle;
|
||||||
|
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||||
|
if (!CheckLastFlee(angle, infoList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
bool strict = checkAngle.strict;
|
bool strict = checkAngle.strict;
|
||||||
float fleeDis = sPlayerbotAIConfig->fleeDistance;
|
float fleeDis = std::min(radius + 1.0f, sPlayerbotAIConfig->fleeDistance);
|
||||||
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
|
Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis,
|
||||||
bot->GetPositionY() + sin(angle) * fleeDis,
|
bot->GetPositionY() + sin(angle) * fleeDis,
|
||||||
bot->GetPositionZ()};
|
bot->GetPositionZ()};
|
||||||
@@ -1737,28 +1776,197 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius)
|
|||||||
return Position();
|
return Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name)
|
bool MovementAction::FleePosition(Position pos, float radius)
|
||||||
{
|
{
|
||||||
Position bestPos;
|
Position bestPos;
|
||||||
if (botAI->IsMelee(bot)) {
|
if (botAI->IsMelee(bot)) {
|
||||||
bestPos = BestPositionForMelee(pos, radius);
|
bestPos = BestPositionForMeleeToFlee(pos, radius);
|
||||||
} else {
|
} else {
|
||||||
bestPos = BestPositionForRanged(pos, radius);
|
bestPos = BestPositionForRangedToFlee(pos, radius);
|
||||||
}
|
}
|
||||||
if (bestPos != Position()) {
|
if (bestPos != Position()) {
|
||||||
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) {
|
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) {
|
||||||
if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) {
|
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||||
lastTellTimer = time(NULL);
|
uint32 curTS = getMSTime();
|
||||||
std::ostringstream out;
|
while (!infoList.empty()) {
|
||||||
out << "I'm avoiding " << name << "...";
|
if (infoList.size() > 10 || infoList.front().timestamp + 5000 < curTS) {
|
||||||
bot->Say(out.str(), LANG_UNIVERSAL);
|
infoList.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
infoList.push_back({pos, radius, bot->GetAngle(&bestPos), curTS});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MovementAction::CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList)
|
||||||
|
{
|
||||||
|
uint32 curTS = getMSTime();
|
||||||
|
curAngle = fmod(curAngle, 2 * M_PI);
|
||||||
|
while (!infoList.empty()) {
|
||||||
|
if (infoList.size() > 10 || infoList.front().timestamp + 5000 < curTS) {
|
||||||
|
infoList.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FleeInfo& info : infoList) {
|
||||||
|
// more than 5 sec
|
||||||
|
if (info.timestamp + 5000 < curTS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float revAngle = fmod(info.angle + M_PI, 2 * M_PI);
|
||||||
|
// angle too close
|
||||||
|
if (fabs(revAngle - curAngle) < M_PI / 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CombatFormationMoveAction::isUseful()
|
||||||
|
{
|
||||||
|
if (getMSTime() - moveInterval < lastMoveTimer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL) != nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
|
return dis > 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CombatFormationMoveAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
|
Player* playerToLeave = NearestGroupMember(dis);
|
||||||
|
if (playerToLeave && bot->GetExactDist(playerToLeave) < dis) {
|
||||||
|
if (FleePosition(playerToLeave->GetPosition(), dis)) {
|
||||||
|
lastMoveTimer = getMSTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position CombatFormationMoveAction::AverageGroupPos(float dis)
|
||||||
|
{
|
||||||
|
float averageX = 0, averageY = 0, averageZ = 0;
|
||||||
|
int cnt = 0;
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group) {
|
||||||
|
return Position();
|
||||||
|
}
|
||||||
|
Group::MemberSlotList const& groupSlot = group->GetMemberSlots();
|
||||||
|
for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++)
|
||||||
|
{
|
||||||
|
Player *member = ObjectAccessor::FindPlayer(itr->guid);
|
||||||
|
if (!member || !member->IsAlive() || member->GetMapId() != bot->GetMapId() || member->IsCharmed() || sServerFacade->GetDistance2d(bot, member) > dis)
|
||||||
|
continue;
|
||||||
|
cnt++;
|
||||||
|
averageX += member->GetPositionX();
|
||||||
|
averageY += member->GetPositionY();
|
||||||
|
averageZ += member->GetPositionZ();
|
||||||
|
}
|
||||||
|
averageX /= cnt;
|
||||||
|
averageY /= cnt;
|
||||||
|
averageZ /= cnt;
|
||||||
|
return Position(averageX, averageY, averageZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
Player* CombatFormationMoveAction::NearestGroupMember(float dis)
|
||||||
|
{
|
||||||
|
float nearestDis = 10000.0f;
|
||||||
|
Player* result = nullptr;
|
||||||
|
Group* group = bot->GetGroup();
|
||||||
|
if (!group) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Group::MemberSlotList const& groupSlot = group->GetMemberSlots();
|
||||||
|
for (Group::member_citerator itr = groupSlot.begin(); itr != groupSlot.end(); itr++)
|
||||||
|
{
|
||||||
|
Player *member = ObjectAccessor::FindPlayer(itr->guid);
|
||||||
|
if (!member || !member->IsAlive() || member == bot || member->GetMapId() != bot->GetMapId() || member->IsCharmed() || sServerFacade->GetDistance2d(bot, member) > dis)
|
||||||
|
continue;
|
||||||
|
if (nearestDis > bot->GetExactDist(member)) {
|
||||||
|
result = member;
|
||||||
|
nearestDis = bot->GetExactDist(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisperseSetAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
std::string const text = event.getParam();
|
||||||
|
if (text == "disable") {
|
||||||
|
RESET_AI_VALUE(float, "disperse distance");
|
||||||
|
botAI->TellMasterNoFacing("Disable disperse");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (text == "enable" || text == "reset") {
|
||||||
|
if (botAI->IsMelee(bot)) {
|
||||||
|
SET_AI_VALUE(float, "disperse distance", DEFAULT_DISPERSE_DISTANCE_MELEE);
|
||||||
|
} else {
|
||||||
|
SET_AI_VALUE(float, "disperse distance", DEFAULT_DISPERSE_DISTANCE_RANGED);
|
||||||
|
}
|
||||||
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "Enable disperse distance " << std::setprecision(2) << dis;
|
||||||
|
botAI->TellMasterNoFacing(out.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (text == "increase") {
|
||||||
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
|
std::ostringstream out;
|
||||||
|
if (dis <= 0.0f) {
|
||||||
|
out << "Enable disperse first";
|
||||||
|
botAI->TellMasterNoFacing(out.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
dis += 1.0f;
|
||||||
|
SET_AI_VALUE(float, "disperse distance", dis);
|
||||||
|
out << "Increase disperse distance to " << std::setprecision(2) << dis;
|
||||||
|
botAI->TellMasterNoFacing(out.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (text == "decrease") {
|
||||||
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
|
dis -= 1.0f;
|
||||||
|
if (dis <= 0.0f) {
|
||||||
|
dis += 1.0f;
|
||||||
|
}
|
||||||
|
SET_AI_VALUE(float, "disperse distance", dis);
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "Increase disperse distance to " << std::setprecision(2) << dis;
|
||||||
|
botAI->TellMasterNoFacing(out.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (text.starts_with("set")) {
|
||||||
|
float dis = -1.0f;;
|
||||||
|
sscanf(text.c_str(), "set %f", &dis);
|
||||||
|
std::ostringstream out;
|
||||||
|
if (dis < 0 || dis > 100.0f) {
|
||||||
|
out << "Invalid disperse distance " << std::setprecision(2) << dis;
|
||||||
|
} else {
|
||||||
|
SET_AI_VALUE(float, "disperse distance", dis);
|
||||||
|
out << "Set disperse distance to " << std::setprecision(2) << dis;
|
||||||
|
}
|
||||||
|
botAI->TellMasterNoFacing(out.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
std::ostringstream out;
|
||||||
|
out << "Usage: disperse [enable | disable | increase | decrease | set {distance}]";
|
||||||
|
float dis = AI_VALUE(float, "disperse distance");
|
||||||
|
if (dis > 0.0f) {
|
||||||
|
out << "(Current disperse distance: " << std::setprecision(2) << dis << ")";
|
||||||
|
}
|
||||||
|
botAI->TellMasterNoFacing(out.str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool RunAwayAction::Execute(Event event)
|
bool RunAwayAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
return Flee(AI_VALUE(Unit*, "master target"));
|
return Flee(AI_VALUE(Unit*, "master target"));
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class Player;
|
|||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
class Unit;
|
class Unit;
|
||||||
class WorldObject;
|
class WorldObject;
|
||||||
|
class Position;
|
||||||
|
|
||||||
class MovementAction : public Action
|
class MovementAction : public Action
|
||||||
{
|
{
|
||||||
@@ -41,6 +42,15 @@ class MovementAction : public Action
|
|||||||
bool MoveAway(Unit* target);
|
bool MoveAway(Unit* target);
|
||||||
bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance);
|
bool MoveInside(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->followDistance);
|
||||||
void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false);
|
void CreateWp(Player* wpOwner, float x, float y, float z, float o, uint32 entry, bool important = false);
|
||||||
|
Position BestPositionForMeleeToFlee(Position pos, float radius);
|
||||||
|
Position BestPositionForRangedToFlee(Position pos, float radius);
|
||||||
|
bool FleePosition(Position pos, float radius);
|
||||||
|
bool CheckLastFlee(float curAngle, std::list<FleeInfo>& infoList);
|
||||||
|
protected:
|
||||||
|
struct CheckAngle {
|
||||||
|
float angle;
|
||||||
|
bool strict;
|
||||||
|
};
|
||||||
private:
|
private:
|
||||||
// float SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range = 20.0f, bool normal_only = false, float step = 8.0f);
|
// float SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range = 20.0f, bool normal_only = false, float step = 8.0f);
|
||||||
const Movement::PointsArray SearchForBestPath(float x, float y, float z, float &modified_z, int maxSearchCount = 5, bool normal_only = false, float step = 8.0f);
|
const Movement::PointsArray SearchForBestPath(float x, float y, float z, float &modified_z, int maxSearchCount = 5, bool normal_only = false, float step = 8.0f);
|
||||||
@@ -69,7 +79,8 @@ class FleeWithPetAction : public MovementAction
|
|||||||
class AvoidAoeAction : public MovementAction
|
class AvoidAoeAction : public MovementAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AvoidAoeAction(PlayerbotAI* botAI) : MovementAction(botAI, "avoid aoe") { }
|
AvoidAoeAction(PlayerbotAI* botAI, int moveInterval = 1000) : MovementAction(botAI, "avoid aoe"),
|
||||||
|
moveInterval(moveInterval) { }
|
||||||
|
|
||||||
bool isUseful() override;
|
bool isUseful() override;
|
||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
@@ -78,14 +89,36 @@ class AvoidAoeAction : public MovementAction
|
|||||||
bool AvoidAuraWithDynamicObj();
|
bool AvoidAuraWithDynamicObj();
|
||||||
bool AvoidGameObjectWithDamage();
|
bool AvoidGameObjectWithDamage();
|
||||||
bool AvoidUnitWithDamageAura();
|
bool AvoidUnitWithDamageAura();
|
||||||
Position BestPositionForMelee(Position pos, float radius);
|
|
||||||
Position BestPositionForRanged(Position pos, float radius);
|
|
||||||
bool FleePosition(Position pos, float radius, std::string name);
|
|
||||||
time_t lastTellTimer = 0;
|
time_t lastTellTimer = 0;
|
||||||
struct CheckAngle {
|
int lastMoveTimer = 0;
|
||||||
float angle;
|
int moveInterval;
|
||||||
bool strict;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CombatFormationMoveAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CombatFormationMoveAction(PlayerbotAI* botAI, int moveInterval = 1000) : MovementAction(botAI, "combat formation move"),
|
||||||
|
moveInterval(moveInterval) { }
|
||||||
|
|
||||||
|
bool isUseful() override;
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Position AverageGroupPos(float dis = sPlayerbotAIConfig->sightDistance);
|
||||||
|
Player* NearestGroupMember(float dis = sPlayerbotAIConfig->sightDistance);
|
||||||
|
int lastMoveTimer = 0;
|
||||||
|
int moveInterval;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DisperseSetAction : public Action
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DisperseSetAction(PlayerbotAI* botAI, std::string const name = "disperse set") : Action(botAI, name) { }
|
||||||
|
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
float DEFAULT_DISPERSE_DISTANCE_RANGED = 5.0f;
|
||||||
|
float DEFAULT_DISPERSE_DISTANCE_MELEE = 2.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RunAwayAction : public MovementAction
|
class RunAwayAction : public MovementAction
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ bool AutoGearAction::Execute(Event event)
|
|||||||
sPlayerbotAIConfig->autoGearQualityLimit,
|
sPlayerbotAIConfig->autoGearQualityLimit,
|
||||||
gs);
|
gs);
|
||||||
factory.InitEquipment(true);
|
factory.InitEquipment(true);
|
||||||
|
factory.InitAmmo();
|
||||||
if (bot->getLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) {
|
if (bot->getLevel() >= sPlayerbotAIConfig->minEnchantingBotLevel) {
|
||||||
factory.ApplyEnchantAndGemsNew();
|
factory.ApplyEnchantAndGemsNew();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ bool SummonAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) {
|
if (master->GetSession()->GetSecurity() >= SEC_PLAYER) {
|
||||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
// botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
||||||
|
SET_AI_VALUE(std::list<FleeInfo>, "recently flee info", {});
|
||||||
return Teleport(master, bot);
|
return Teleport(master, bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -234,8 +234,6 @@ class CastDeathAndDecayAction : public CastSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastDeathAndDecayAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death and decay") { }
|
CastDeathAndDecayAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death and decay") { }
|
||||||
|
|
||||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastHornOfWinterAction : public CastSpellAction
|
class CastHornOfWinterAction : public CastSpellAction
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class BearTankDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionN
|
|||||||
static ActionNode* dire_bear_form([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* dire_bear_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode ("dire bear form",
|
return new ActionNode ("dire bear form",
|
||||||
/*P*/ nullptr,
|
/*P*/ NextAction::array(0, new NextAction("caster form"), nullptr),
|
||||||
/*A*/ NextAction::array(0, new NextAction("bear form"), nullptr),
|
/*A*/ NextAction::array(0, new NextAction("bear form"), nullptr),
|
||||||
/*C*/ nullptr);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ class CasterDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
|
|||||||
creators["insect swarm"] = &insect_swarm;
|
creators["insect swarm"] = &insect_swarm;
|
||||||
creators["moonfire"] = &moonfire;
|
creators["moonfire"] = &moonfire;
|
||||||
creators["starfire"] = &starfire;
|
creators["starfire"] = &starfire;
|
||||||
|
creators["moonkin form"] = &moonkin_form;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -94,6 +95,15 @@ class CasterDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
|
|||||||
/*A*/ nullptr,
|
/*A*/ nullptr,
|
||||||
/*C*/ nullptr);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ActionNode* moonkin_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
|
{
|
||||||
|
return new ActionNode ("moonkin form",
|
||||||
|
/*P*/ NextAction::array(0, new NextAction("caster form"), nullptr),
|
||||||
|
/*A*/ nullptr,
|
||||||
|
/*C*/ nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CasterDruidStrategy::CasterDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
|
CasterDruidStrategy::CasterDruidStrategy(PlayerbotAI* botAI) : GenericDruidStrategy(botAI)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class CatDpsDruidStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
|
|||||||
static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI)
|
static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
return new ActionNode ("cat form",
|
return new ActionNode ("cat form",
|
||||||
/*P*/ nullptr,
|
/*P*/ NextAction::array(0, new NextAction("caster form"), nullptr),
|
||||||
/*A*/ nullptr,
|
/*A*/ nullptr,
|
||||||
/*C*/ nullptr);
|
/*C*/ nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
|||||||
triggers.push_back(new TriggerNode("naxx", NextAction::array(0, new NextAction("naxx chat shortcut", relevance), NULL)));
|
triggers.push_back(new TriggerNode("naxx", NextAction::array(0, new NextAction("naxx chat shortcut", relevance), NULL)));
|
||||||
triggers.push_back(new TriggerNode("bwl", NextAction::array(0, new NextAction("bwl chat shortcut", relevance), NULL)));
|
triggers.push_back(new TriggerNode("bwl", NextAction::array(0, new NextAction("bwl chat shortcut", relevance), NULL)));
|
||||||
triggers.push_back(new TriggerNode("dps", NextAction::array(0, new NextAction("tell expected dps", relevance), NULL)));
|
triggers.push_back(new TriggerNode("dps", NextAction::array(0, new NextAction("tell expected dps", relevance), NULL)));
|
||||||
|
triggers.push_back(new TriggerNode("disperse", NextAction::array(0, new NextAction("disperse set", relevance), NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : PassTroughStrategy(botAI)
|
||||||
|
|||||||
@@ -82,3 +82,10 @@ void AvoidAoeStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
|||||||
{
|
{
|
||||||
// multipliers.push_back(new AvoidAoeStrategyMultiplier(botAI));
|
// multipliers.push_back(new AvoidAoeStrategyMultiplier(botAI));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NextAction** CombatFormationStrategy::getDefaultActions()
|
||||||
|
{
|
||||||
|
return NextAction::array(0,
|
||||||
|
new NextAction("combat formation move", ACTION_EMERGENCY),
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,4 +28,12 @@ public:
|
|||||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CombatFormationStrategy : public Strategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CombatFormationStrategy(PlayerbotAI* ai): Strategy(ai) {}
|
||||||
|
const std::string getName() override { return "combat formation"; }
|
||||||
|
NextAction** getDefaultActions() override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -203,12 +203,14 @@ class CastDragonsBreathAction : public CastSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastDragonsBreathAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "dragon's breath") { }
|
CastDragonsBreathAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "dragon's breath") { }
|
||||||
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastBlastWaveAction : public CastSpellAction
|
class CastBlastWaveAction : public CastSpellAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastBlastWaveAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blast wave") { }
|
CastBlastWaveAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blast wave") { }
|
||||||
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastInvisibilityAction : public CastBuffSpellAction
|
class CastInvisibilityAction : public CastBuffSpellAction
|
||||||
|
|||||||
@@ -161,5 +161,6 @@ class CastMindSearAction : public CastSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastMindSearAction(PlayerbotAI* ai) : CastSpellAction(ai, "mind sear") {}
|
CastMindSearAction(PlayerbotAI* ai) : CastSpellAction(ai, "mind sear") {}
|
||||||
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ class CastChainLightningAction : public CastSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastChainLightningAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chain lightning") { }
|
CastChainLightningAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chain lightning") { }
|
||||||
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastLightningBoltAction : public CastSpellAction
|
class CastLightningBoltAction : public CastSpellAction
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ class ChatTriggerContext : public NamedObjectContext<Trigger>
|
|||||||
creators["naxx"] = &ChatTriggerContext::naxx;
|
creators["naxx"] = &ChatTriggerContext::naxx;
|
||||||
creators["bwl"] = &ChatTriggerContext::bwl;
|
creators["bwl"] = &ChatTriggerContext::bwl;
|
||||||
creators["dps"] = &ChatTriggerContext::dps;
|
creators["dps"] = &ChatTriggerContext::dps;
|
||||||
|
creators["disperse"] = &ChatTriggerContext::disperse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -218,6 +219,7 @@ class ChatTriggerContext : public NamedObjectContext<Trigger>
|
|||||||
static Trigger* naxx(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "naxx"); }
|
static Trigger* naxx(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "naxx"); }
|
||||||
static Trigger* bwl(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "bwl"); }
|
static Trigger* bwl(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "bwl"); }
|
||||||
static Trigger* dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "dps"); }
|
static Trigger* dps(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "dps"); }
|
||||||
|
static Trigger* disperse(PlayerbotAI* ai) { return new ChatCommandTrigger(ai, "disperse"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ bool PartyMemberToHeal::Check(Unit* player)
|
|||||||
{
|
{
|
||||||
// return player && player != bot && player->GetMapId() == bot->GetMapId() && player->IsInWorld() &&
|
// return player && player != bot && player->GetMapId() == bot->GetMapId() && player->IsInWorld() &&
|
||||||
// sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f : 40.0f);
|
// sServerFacade->GetDistance2d(bot, player) < (player->IsPlayer() && botAI->IsTank((Player*)player) ? 50.0f : 40.0f);
|
||||||
return player->GetMapId() == bot->GetMapId() &&
|
return player->GetMapId() == bot->GetMapId() && !player->IsCharmed() &&
|
||||||
bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 &&
|
bot->GetDistance2d(player) < sPlayerbotAIConfig->healDistance * 2 &&
|
||||||
bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
|
bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -301,6 +301,10 @@ class ValueContext : public NamedObjectContext<UntypedValue>
|
|||||||
creators["expected group dps"] = &ValueContext::expected_group_dps;
|
creators["expected group dps"] = &ValueContext::expected_group_dps;
|
||||||
creators["area debuff"] = &ValueContext::area_debuff;
|
creators["area debuff"] = &ValueContext::area_debuff;
|
||||||
creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange;
|
creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange;
|
||||||
|
creators["disperse distance"] = &ValueContext::disperse_distance;
|
||||||
|
creators["last flee angle"] = &ValueContext::last_flee_angle;
|
||||||
|
creators["last flee timestamp"] = &ValueContext::last_flee_timestamp;
|
||||||
|
creators["recently flee info"] = &ValueContext::recently_flee_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -505,6 +509,10 @@ class ValueContext : public NamedObjectContext<UntypedValue>
|
|||||||
static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new ExpectedGroupDpsValue(ai); }
|
static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new ExpectedGroupDpsValue(ai); }
|
||||||
static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); }
|
static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); }
|
||||||
static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); }
|
static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); }
|
||||||
|
static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); }
|
||||||
|
static UntypedValue* last_flee_angle(PlayerbotAI* ai) { return new LastFleeAngleValue(ai); }
|
||||||
|
static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); }
|
||||||
|
static UntypedValue* recently_flee_info(PlayerbotAI* ai) { return new RecentlyFleeInfo(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -87,7 +87,10 @@ void DpsWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
|
|
||||||
void DpsAoeWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
void DpsAoeWarlockStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||||
{
|
{
|
||||||
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("rain of fire", 37.0f), nullptr)));
|
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
|
||||||
|
new NextAction("seed of corruption", 39.0f),
|
||||||
|
new NextAction("seed of corruption on attacker", 38.0f),
|
||||||
|
new NextAction("rain of fire", 37.0f), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr)));
|
triggers.push_back(new TriggerNode("corruption on attacker", NextAction::array(0, new NextAction("corruption on attacker", 27.0f), nullptr)));
|
||||||
triggers.push_back(new TriggerNode("unstable affliction on attacker", NextAction::array(0, new NextAction("unstable affliction on attacker", 26.0f), NULL)));
|
triggers.push_back(new TriggerNode("unstable affliction on attacker", NextAction::array(0, new NextAction("unstable affliction on attacker", 26.0f), NULL)));
|
||||||
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 25.0f), nullptr)));
|
triggers.push_back(new TriggerNode("curse of agony on attacker", NextAction::array(0, new NextAction("curse of agony on attacker", 25.0f), nullptr)));
|
||||||
|
|||||||
@@ -67,12 +67,18 @@ class CastCorruptionAction : public CastDebuffSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) { }
|
CastCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "corruption", true) { }
|
||||||
|
bool isUseful() override {
|
||||||
|
return CastDebuffSpellAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
class CastCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) { }
|
CastCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "corruption", true) { }
|
||||||
|
bool isUseful() override {
|
||||||
|
return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
class CastCurseOfAgonyOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
||||||
@@ -142,6 +148,20 @@ class CastSeedOfCorruptionAction : public CastDebuffSpellAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CastSeedOfCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "seed of corruption", true, 0) { }
|
CastSeedOfCorruptionAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "seed of corruption", true, 0) { }
|
||||||
|
bool isUseful() override {
|
||||||
|
return CastDebuffSpellAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true) ;
|
||||||
|
}
|
||||||
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class CastSeedOfCorruptionOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CastSeedOfCorruptionOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "seed of corruption", true, 0) { }
|
||||||
|
bool isUseful() override {
|
||||||
|
return CastDebuffSpellOnAttackerAction::isUseful() && !botAI->HasAura("corruption", GetTarget(), false, true) ;
|
||||||
|
}
|
||||||
|
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastRainOfFireAction : public CastSpellAction
|
class CastRainOfFireAction : public CastSpellAction
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
|
|||||||
creators["banish"] = &WarlockAiObjectContextInternal::banish;
|
creators["banish"] = &WarlockAiObjectContextInternal::banish;
|
||||||
creators["banish on cc"] = &WarlockAiObjectContextInternal::banish_on_cc;
|
creators["banish on cc"] = &WarlockAiObjectContextInternal::banish_on_cc;
|
||||||
creators["seed of corruption"] = &WarlockAiObjectContextInternal::seed_of_corruption;
|
creators["seed of corruption"] = &WarlockAiObjectContextInternal::seed_of_corruption;
|
||||||
|
creators["seed of corruption on attacker"] = &WarlockAiObjectContextInternal::seed_of_corruption_on_attacker;
|
||||||
creators["rain of fire"] = &WarlockAiObjectContextInternal::rain_of_fire;
|
creators["rain of fire"] = &WarlockAiObjectContextInternal::rain_of_fire;
|
||||||
creators["shadowfury"] = &WarlockAiObjectContextInternal::shadowfury;
|
creators["shadowfury"] = &WarlockAiObjectContextInternal::shadowfury;
|
||||||
creators["life tap"] = &WarlockAiObjectContextInternal::life_tap;
|
creators["life tap"] = &WarlockAiObjectContextInternal::life_tap;
|
||||||
@@ -209,6 +210,7 @@ class WarlockAiObjectContextInternal : public NamedObjectContext<Action>
|
|||||||
static Action* banish(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
|
static Action* banish(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
|
||||||
static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
|
static Action* banish_on_cc(PlayerbotAI* botAI) { return new CastBanishAction(botAI); }
|
||||||
static Action* seed_of_corruption(PlayerbotAI* botAI) { return new CastSeedOfCorruptionAction(botAI); }
|
static Action* seed_of_corruption(PlayerbotAI* botAI) { return new CastSeedOfCorruptionAction(botAI); }
|
||||||
|
static Action* seed_of_corruption_on_attacker(PlayerbotAI* botAI) { return new CastSeedOfCorruptionOnAttackerAction(botAI); }
|
||||||
static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); }
|
static Action* rain_of_fire(PlayerbotAI* botAI) { return new CastRainOfFireAction(botAI); }
|
||||||
static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); }
|
static Action* shadowfury(PlayerbotAI* botAI) { return new CastShadowfuryAction(botAI); }
|
||||||
static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); }
|
static Action* life_tap(PlayerbotAI* botAI) { return new CastLifeTapAction(botAI); }
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#define _PLAYERBOT_WARLOCKTRIGGERS_H
|
#define _PLAYERBOT_WARLOCKTRIGGERS_H
|
||||||
|
|
||||||
#include "GenericTriggers.h"
|
#include "GenericTriggers.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
|
|
||||||
@@ -32,13 +33,24 @@ class CurseOfAgonyTrigger : public DebuffTrigger
|
|||||||
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 20.0f) { }
|
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 20.0f) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEBUFF_CHECKISOWNER_TRIGGER(CorruptionTrigger, "corruption");
|
class CorruptionTrigger : public DebuffTrigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CorruptionTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "corruption", 1, true) { } \
|
||||||
|
bool IsActive() override {
|
||||||
|
return DebuffTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life");
|
DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life");
|
||||||
|
|
||||||
class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
|
class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) { }
|
CorruptionOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "corruption", true) { }
|
||||||
|
bool IsActive() override {
|
||||||
|
return DebuffOnAttackerTrigger::IsActive() && !botAI->HasAura("seed of corruption", GetTarget(), false, true) ;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
|
class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
|
||||||
|
|||||||
Reference in New Issue
Block a user