mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-15 18:00:27 +00:00
Merge pull request #475 from liyunfan1223/dev-0814
Improve combat and spell
This commit is contained in:
6
.github/workflows/core_build.yml
vendored
6
.github/workflows/core_build.yml
vendored
@@ -14,15 +14,15 @@ jobs:
|
||||
matrix:
|
||||
# the result of the matrix will be the combination of all attributes, so we get os*compiler builds
|
||||
include:
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
c_compiler: clang
|
||||
cpp_compiler: clang++
|
||||
build_type: Release
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
c_compiler: gcc
|
||||
cpp_compiler: g++
|
||||
build_type: Release
|
||||
- os: ubuntu-latest
|
||||
- os: ubuntu-24.04
|
||||
c_compiler: gcc
|
||||
cpp_compiler: g++
|
||||
build_type: Release
|
||||
|
||||
@@ -271,6 +271,9 @@ AiPlayerbot.DispelAuraDuration = 700
|
||||
# Delay between two bot actions
|
||||
AiPlayerbot.ReactDelay = 100
|
||||
|
||||
# Dynamically adjust react delay for bots in different status to reduce server lags
|
||||
AiPlayerbot.DynamicReactDelay = 1
|
||||
|
||||
# Inactivity delay
|
||||
AiPlayerbot.PassiveDelay = 10000
|
||||
|
||||
|
||||
@@ -276,116 +276,116 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
|
||||
if (!player->InBattleground())
|
||||
{
|
||||
engine->addStrategies("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
|
||||
engine->addStrategiesNoInit("racials", "chat", "default", "cast time", "duel", "boost", nullptr);
|
||||
}
|
||||
if (sPlayerbotAIConfig->autoSaveMana)
|
||||
{
|
||||
engine->addStrategy("auto save mana");
|
||||
engine->addStrategy("smana", false);
|
||||
}
|
||||
if (sPlayerbotAIConfig->autoAvoidAoe && facade->HasRealPlayerMaster())
|
||||
{
|
||||
engine->addStrategy("avoid aoe");
|
||||
engine->addStrategy("aaoe", false);
|
||||
}
|
||||
engine->addStrategy("combat formation");
|
||||
engine->addStrategy("formation", false);
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
if (tab == 2)
|
||||
{
|
||||
engine->addStrategies("dps", "shadow debuff", "shadow aoe", nullptr);
|
||||
engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr);
|
||||
}
|
||||
else if (tab == PRIEST_TAB_DISIPLINE)
|
||||
{
|
||||
engine->addStrategies("heal", nullptr);
|
||||
engine->addStrategiesNoInit("heal", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategies("holy heal", nullptr);
|
||||
engine->addStrategiesNoInit("holy heal", nullptr);
|
||||
}
|
||||
|
||||
engine->addStrategies("dps assist", "cure", nullptr);
|
||||
engine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
if (tab == 0)
|
||||
engine->addStrategies("arcane", "arcane aoe", nullptr);
|
||||
engine->addStrategiesNoInit("arcane", "arcane aoe", nullptr);
|
||||
else if (tab == 1)
|
||||
engine->addStrategies("fire", "fire aoe", nullptr);
|
||||
engine->addStrategiesNoInit("fire", "fire aoe", nullptr);
|
||||
else
|
||||
engine->addStrategies("frost", "frost aoe", nullptr);
|
||||
engine->addStrategiesNoInit("frost", "frost aoe", nullptr);
|
||||
|
||||
engine->addStrategies("dps", "dps assist", "cure", nullptr);
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == 2)
|
||||
engine->addStrategies("tank", "tank assist", "aoe", "mark rti", nullptr);
|
||||
engine->addStrategiesNoInit("tank", "tank assist", "aoe", "mark rti", nullptr);
|
||||
else if (player->GetLevel() < 36 || tab == 0)
|
||||
engine->addStrategies("arms", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||
engine->addStrategiesNoInit("arms", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||
else
|
||||
engine->addStrategies("fury", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||
engine->addStrategiesNoInit("fury", "aoe", "dps assist", /*"behind",*/ nullptr);
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == 0)
|
||||
engine->addStrategies("caster", "caster aoe", "bmana", nullptr);
|
||||
engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr);
|
||||
else if (tab == 2)
|
||||
engine->addStrategies("heal", "bmana", nullptr);
|
||||
engine->addStrategiesNoInit("heal", "bmana", nullptr);
|
||||
else
|
||||
engine->addStrategies("melee", "melee aoe", "bdps", nullptr);
|
||||
engine->addStrategiesNoInit("melee", "melee aoe", "bdps", nullptr);
|
||||
|
||||
engine->addStrategies("dps assist", "cure", "totems", nullptr);
|
||||
engine->addStrategiesNoInit("dps assist", "cure", "totems", nullptr);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == 1)
|
||||
engine->addStrategies("tank", "tank assist", "bthreat", "barmor", "cure", nullptr);
|
||||
engine->addStrategiesNoInit("tank", "tank assist", "bthreat", "barmor", "cure", nullptr);
|
||||
else if (tab == 0)
|
||||
engine->addStrategies("heal", "dps assist", "cure", "bcast", nullptr);
|
||||
engine->addStrategiesNoInit("heal", "dps assist", "cure", "bcast", nullptr);
|
||||
else
|
||||
engine->addStrategies("dps", "dps assist", "cure", "baoe", nullptr);
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "baoe", nullptr);
|
||||
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == 0)
|
||||
{
|
||||
engine->addStrategies("caster", "cure", "caster aoe", "dps assist", nullptr);
|
||||
engine->addStrategy("caster debuff");
|
||||
engine->addStrategiesNoInit("caster", "cure", "caster aoe", "dps assist", nullptr);
|
||||
engine->addStrategy("caster debuff", false);
|
||||
}
|
||||
else if (tab == 2)
|
||||
engine->addStrategies("heal", "cure", "dps assist", nullptr);
|
||||
engine->addStrategiesNoInit("heal", "cure", "dps assist", nullptr);
|
||||
else
|
||||
{
|
||||
if (player->GetLevel() >= 20 && !player->HasAura(16931) /*thick hide*/)
|
||||
{
|
||||
engine->addStrategies("cat", "dps assist", nullptr);
|
||||
engine->addStrategiesNoInit("cat", "dps assist", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategies("bear", "tank assist", nullptr);
|
||||
engine->addStrategiesNoInit("bear", "tank assist", nullptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
engine->addStrategies("dps", "aoe", "bdps", "dps assist", nullptr);
|
||||
engine->addStrategy("dps debuff");
|
||||
engine->addStrategiesNoInit("dps", "aoe", "bdps", "dps assist", nullptr);
|
||||
engine->addStrategy("dps debuff", false);
|
||||
break;
|
||||
case CLASS_ROGUE:
|
||||
if (tab == ROGUE_TAB_ASSASSINATION)
|
||||
{
|
||||
engine->addStrategies("melee", "dps assist", "aoe", /*"behind",*/ nullptr);
|
||||
engine->addStrategiesNoInit("melee", "dps assist", "aoe", /*"behind",*/ nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategies("dps", "dps assist", "aoe", /*"behind",*/ nullptr);
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "aoe", /*"behind",*/ nullptr);
|
||||
}
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
engine->addStrategies("dps assist", "dps", "dps debuff", "aoe", nullptr);
|
||||
engine->addStrategiesNoInit("dps assist", "dps", "dps debuff", "aoe", nullptr);
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab == 0)
|
||||
engine->addStrategies("blood", "tank assist", nullptr);
|
||||
engine->addStrategiesNoInit("blood", "tank assist", nullptr);
|
||||
else if (tab == 1)
|
||||
engine->addStrategies("frost", "frost aoe", "dps assist", nullptr);
|
||||
engine->addStrategiesNoInit("frost", "frost aoe", "dps assist", nullptr);
|
||||
else
|
||||
engine->addStrategies("unholy", "unholy aoe", "dps assist", nullptr);
|
||||
engine->addStrategiesNoInit("unholy", "unholy aoe", "dps assist", nullptr);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -395,9 +395,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
if (!player->GetGroup())
|
||||
{
|
||||
// change for heal spec
|
||||
engine->addStrategy("boost");
|
||||
engine->addStrategy("dps assist");
|
||||
engine->removeStrategy("threat");
|
||||
engine->addStrategy("boost", false);
|
||||
engine->addStrategy("dps assist", false);
|
||||
engine->removeStrategy("threat", false);
|
||||
// engine-
|
||||
switch (player->getClass())
|
||||
{
|
||||
@@ -405,7 +405,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
{
|
||||
if (tab != PRIEST_TAB_SHADOW)
|
||||
{
|
||||
engine->addStrategies("holy dps", "shadow debuff", "shadow aoe", nullptr);
|
||||
engine->addStrategiesNoInit("holy dps", "shadow debuff", "shadow aoe", nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -413,8 +413,8 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
{
|
||||
if (tab == DRUID_TAB_RESTORATION)
|
||||
{
|
||||
engine->addStrategies("caster", "caster aoe", nullptr);
|
||||
engine->addStrategy("caster debuff");
|
||||
engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
|
||||
engine->addStrategy("caster debuff", false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -422,7 +422,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
{
|
||||
if (tab == SHAMAN_TAB_RESTORATION)
|
||||
{
|
||||
engine->addStrategies("caster", "caster aoe", "bmana", nullptr);
|
||||
engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -430,7 +430,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
{
|
||||
if (tab == PALADIN_TAB_HOLY)
|
||||
{
|
||||
engine->addStrategies("dps", "dps assist", "baoe", nullptr);
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "baoe", nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -452,40 +452,40 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
bgType = player->GetBattleground()->GetBgTypeID(true);
|
||||
|
||||
if (bgType == BATTLEGROUND_WS)
|
||||
engine->addStrategy("warsong");
|
||||
engine->addStrategy("warsong", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_AB)
|
||||
engine->addStrategy("arathi");
|
||||
engine->addStrategy("arathi", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_AV)
|
||||
engine->addStrategy("alterac");
|
||||
engine->addStrategy("alterac", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_EY)
|
||||
engine->addStrategy("eye");
|
||||
engine->addStrategy("eye", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_IC)
|
||||
engine->addStrategy("isle");
|
||||
engine->addStrategy("isle", false);
|
||||
|
||||
if (player->InArena())
|
||||
{
|
||||
engine->addStrategy("arena");
|
||||
engine->addStrategy("arena", false);
|
||||
}
|
||||
|
||||
engine->addStrategies("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist",
|
||||
engine->addStrategiesNoInit("boost", "racials", "chat", "default", "aoe", "potions", "cast time", "dps assist",
|
||||
nullptr);
|
||||
engine->removeStrategy("custom::say");
|
||||
engine->removeStrategy("flee");
|
||||
engine->removeStrategy("threat");
|
||||
engine->addStrategy("boost");
|
||||
engine->removeStrategy("custom::say", false);
|
||||
engine->removeStrategy("flee", false);
|
||||
engine->removeStrategy("threat", false);
|
||||
engine->addStrategy("boost", false);
|
||||
|
||||
if ((player->getClass() == CLASS_DRUID && tab == 2) || (player->getClass() == CLASS_SHAMAN && tab == 2))
|
||||
engine->addStrategies("caster", "caster aoe", nullptr);
|
||||
engine->addStrategiesNoInit("caster", "caster aoe", nullptr);
|
||||
|
||||
if (player->getClass() == CLASS_DRUID && tab == 1)
|
||||
engine->addStrategies(/*"behind",*/ "dps", nullptr);
|
||||
engine->addStrategiesNoInit(/*"behind",*/ "dps", nullptr);
|
||||
|
||||
if (player->getClass() == CLASS_ROGUE)
|
||||
engine->addStrategies(/*"behind",*/ "stealth", nullptr);
|
||||
engine->addStrategiesNoInit(/*"behind",*/ "stealth", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,6 +493,7 @@ Engine* AiFactory::createCombatEngine(Player* player, PlayerbotAI* const facade,
|
||||
{
|
||||
Engine* engine = new Engine(facade, aiObjectContext);
|
||||
AddDefaultCombatStrategies(player, facade, engine);
|
||||
engine->Init();
|
||||
return engine;
|
||||
}
|
||||
|
||||
@@ -503,103 +504,103 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
switch (player->getClass())
|
||||
{
|
||||
case CLASS_PRIEST:
|
||||
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_PALADIN:
|
||||
if (tab == 1)
|
||||
{
|
||||
nonCombatEngine->addStrategies("bthreat", "tank assist", "barmor", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("bthreat", "tank assist", "barmor", nullptr);
|
||||
if (player->GetLevel() >= 20)
|
||||
{
|
||||
nonCombatEngine->addStrategy("bstats");
|
||||
nonCombatEngine->addStrategy("bstats", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("bdps");
|
||||
nonCombatEngine->addStrategy("bdps", false);
|
||||
}
|
||||
}
|
||||
else if (tab == 0)
|
||||
nonCombatEngine->addStrategies("dps assist", "bmana", "bcast", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "bmana", "bcast", nullptr);
|
||||
else
|
||||
nonCombatEngine->addStrategies("dps assist", "bdps", "baoe", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "bdps", "baoe", nullptr);
|
||||
|
||||
nonCombatEngine->addStrategies("cure", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("cure", nullptr);
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
nonCombatEngine->addStrategies("bdps", "dps assist", "pet", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("bdps", "dps assist", "pet", nullptr);
|
||||
break;
|
||||
case CLASS_SHAMAN:
|
||||
if (tab == 0 || tab == 2)
|
||||
nonCombatEngine->addStrategy("bmana");
|
||||
nonCombatEngine->addStrategy("bmana", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("bdps");
|
||||
nonCombatEngine->addStrategy("bdps", false);
|
||||
|
||||
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
if (tab == MAGE_TAB_ARCANE || tab == MAGE_TAB_FIRE)
|
||||
nonCombatEngine->addStrategy("bdps");
|
||||
nonCombatEngine->addStrategy("bdps", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("bmana");
|
||||
nonCombatEngine->addStrategy("bmana", false);
|
||||
|
||||
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_DRUID:
|
||||
if (tab == 1)
|
||||
{
|
||||
if (player->GetLevel() >= 20 && !player->HasAura(16931) /*thick hide*/)
|
||||
{
|
||||
nonCombatEngine->addStrategy("dps assist");
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("tank assist");
|
||||
nonCombatEngine->addStrategy("tank assist", false);
|
||||
}
|
||||
}
|
||||
else
|
||||
nonCombatEngine->addStrategies("dps assist", "cure", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr);
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == 2)
|
||||
nonCombatEngine->addStrategy("tank assist");
|
||||
nonCombatEngine->addStrategy("tank assist", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("dps assist");
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
break;
|
||||
case CLASS_WARLOCK:
|
||||
if (tab == WARLOCK_TAB_AFFLICATION)
|
||||
{
|
||||
nonCombatEngine->addStrategies("bmana", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("bmana", nullptr);
|
||||
}
|
||||
else if (tab == WARLOCK_TAB_DEMONOLOGY)
|
||||
{
|
||||
nonCombatEngine->addStrategies("bdps", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("bdps", nullptr);
|
||||
}
|
||||
else if (tab == WARLOCK_TAB_DESTRUCTION)
|
||||
{
|
||||
nonCombatEngine->addStrategies("bhealth", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("bhealth", nullptr);
|
||||
}
|
||||
nonCombatEngine->addStrategies("dps assist", nullptr);
|
||||
nonCombatEngine->addStrategiesNoInit("dps assist", nullptr);
|
||||
break;
|
||||
case CLASS_DEATH_KNIGHT:
|
||||
if (tab == 0)
|
||||
nonCombatEngine->addStrategy("tank assist");
|
||||
nonCombatEngine->addStrategy("tank assist", false);
|
||||
else
|
||||
nonCombatEngine->addStrategy("dps assist");
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
break;
|
||||
default:
|
||||
nonCombatEngine->addStrategy("dps assist");
|
||||
nonCombatEngine->addStrategy("dps assist", false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!player->InBattleground())
|
||||
{
|
||||
nonCombatEngine->addStrategies("nc", "food", "chat", "follow", "default", "quest", "loot", "gather", "duel",
|
||||
nonCombatEngine->addStrategiesNoInit("nc", "food", "chat", "follow", "default", "quest", "loot", "gather", "duel",
|
||||
"buff", "mount", "emote", nullptr);
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->autoSaveMana)
|
||||
{
|
||||
nonCombatEngine->addStrategy("auto save mana");
|
||||
nonCombatEngine->addStrategy("smana", false);
|
||||
}
|
||||
if ((sRandomPlayerbotMgr->IsRandomBot(player)) && !player->InBattleground())
|
||||
{
|
||||
@@ -607,10 +608,10 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
|
||||
// let 25% of free bots start duels.
|
||||
if (!urand(0, 3))
|
||||
nonCombatEngine->addStrategy("start duel");
|
||||
nonCombatEngine->addStrategy("start duel", false);
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotJoinLfg)
|
||||
nonCombatEngine->addStrategy("lfg");
|
||||
nonCombatEngine->addStrategy("lfg", false);
|
||||
|
||||
if (!player->GetGroup() || player->GetGroup()->GetLeaderGUID() == player->GetGUID())
|
||||
{
|
||||
@@ -618,24 +619,24 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
// if (!urand(0, 3))
|
||||
// nonCombatEngine->addStrategy("attack tagged");
|
||||
|
||||
nonCombatEngine->addStrategy("pvp");
|
||||
nonCombatEngine->addStrategy("pvp", false);
|
||||
// nonCombatEngine->addStrategy("collision");
|
||||
nonCombatEngine->addStrategy("grind");
|
||||
nonCombatEngine->addStrategy("grind", false);
|
||||
// nonCombatEngine->addStrategy("group");
|
||||
// nonCombatEngine->addStrategy("guild");
|
||||
|
||||
if (sPlayerbotAIConfig->autoDoQuests)
|
||||
{
|
||||
// nonCombatEngine->addStrategy("travel");
|
||||
nonCombatEngine->addStrategy("rpg");
|
||||
nonCombatEngine->addStrategy("rpg", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("move random");
|
||||
nonCombatEngine->addStrategy("move random", false);
|
||||
}
|
||||
|
||||
if (sPlayerbotAIConfig->randomBotJoinBG)
|
||||
nonCombatEngine->addStrategy("bg");
|
||||
nonCombatEngine->addStrategy("bg", false);
|
||||
|
||||
// if (!master || GET_PLAYERBOT_AI(master))
|
||||
// nonCombatEngine->addStrategy("maintenance");
|
||||
@@ -651,7 +652,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master);
|
||||
if (masterBotAI || sRandomPlayerbotMgr->IsRandomBot(player))
|
||||
{
|
||||
nonCombatEngine->addStrategy("pvp");
|
||||
nonCombatEngine->addStrategy("pvp", false);
|
||||
// nonCombatEngine->addStrategy("collision");
|
||||
// nonCombatEngine->addStrategy("group");
|
||||
// nonCombatEngine->addStrategy("guild");
|
||||
@@ -671,7 +672,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
}
|
||||
else
|
||||
{
|
||||
nonCombatEngine->addStrategy("pvp");
|
||||
nonCombatEngine->addStrategy("pvp", false);
|
||||
nonCombatEngine->ChangeStrategy(sPlayerbotAIConfig->nonCombatStrategies);
|
||||
}
|
||||
}
|
||||
@@ -687,12 +688,12 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
// Battleground switch
|
||||
if (player->InBattleground() && player->GetBattleground())
|
||||
{
|
||||
nonCombatEngine->addStrategies("nc", "chat", "default", "buff", "food", "mount", "pvp", "dps assist",
|
||||
nonCombatEngine->addStrategiesNoInit("nc", "chat", "default", "buff", "food", "mount", "pvp", "dps assist",
|
||||
"attack tagged", "emote", nullptr);
|
||||
nonCombatEngine->removeStrategy("custom::say");
|
||||
nonCombatEngine->removeStrategy("travel");
|
||||
nonCombatEngine->removeStrategy("rpg");
|
||||
nonCombatEngine->removeStrategy("grind");
|
||||
nonCombatEngine->removeStrategy("custom::say", false);
|
||||
nonCombatEngine->removeStrategy("travel", false);
|
||||
nonCombatEngine->removeStrategy("rpg", false);
|
||||
nonCombatEngine->removeStrategy("grind", false);
|
||||
|
||||
BattlegroundTypeId bgType = player->GetBattlegroundTypeId();
|
||||
if (bgType == BATTLEGROUND_RB)
|
||||
@@ -700,27 +701,27 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
||||
|
||||
if ((bgType <= BATTLEGROUND_EY || bgType == BATTLEGROUND_IC) &&
|
||||
!player->InArena()) // do not add for not supported bg or arena
|
||||
nonCombatEngine->addStrategy("battleground");
|
||||
nonCombatEngine->addStrategy("battleground", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_WS)
|
||||
nonCombatEngine->addStrategy("warsong");
|
||||
nonCombatEngine->addStrategy("warsong", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_AV)
|
||||
nonCombatEngine->addStrategy("alterac");
|
||||
nonCombatEngine->addStrategy("alterac", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_AB)
|
||||
nonCombatEngine->addStrategy("arathi");
|
||||
nonCombatEngine->addStrategy("arathi", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_EY)
|
||||
nonCombatEngine->addStrategy("eye");
|
||||
nonCombatEngine->addStrategy("eye", false);
|
||||
|
||||
if (bgType == BATTLEGROUND_IC)
|
||||
nonCombatEngine->addStrategy("isle");
|
||||
nonCombatEngine->addStrategy("isle", false);
|
||||
|
||||
if (player->InArena())
|
||||
{
|
||||
nonCombatEngine->addStrategy("arena");
|
||||
nonCombatEngine->removeStrategy("mount");
|
||||
nonCombatEngine->addStrategy("arena", false);
|
||||
nonCombatEngine->removeStrategy("mount", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -730,17 +731,18 @@ Engine* AiFactory::createNonCombatEngine(Player* player, PlayerbotAI* const faca
|
||||
Engine* nonCombatEngine = new Engine(facade, aiObjectContext);
|
||||
|
||||
AddDefaultNonCombatStrategies(player, facade, nonCombatEngine);
|
||||
nonCombatEngine->Init();
|
||||
return nonCombatEngine;
|
||||
}
|
||||
|
||||
void AiFactory::AddDefaultDeadStrategies(Player* player, PlayerbotAI* const facade, Engine* deadEngine)
|
||||
{
|
||||
(void)facade; // unused and remove warning
|
||||
deadEngine->addStrategies("dead", "stay", "chat", "default", "follow", nullptr);
|
||||
deadEngine->addStrategiesNoInit("dead", "stay", "chat", "default", "follow", nullptr);
|
||||
|
||||
if (sRandomPlayerbotMgr->IsRandomBot(player) && !player->GetGroup())
|
||||
{
|
||||
deadEngine->removeStrategy("follow");
|
||||
deadEngine->removeStrategy("follow", false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -748,5 +750,6 @@ Engine* AiFactory::createDeadEngine(Player* player, PlayerbotAI* const facade, A
|
||||
{
|
||||
Engine* deadEngine = new Engine(facade, AiObjectContext);
|
||||
AddDefaultDeadStrategies(player, facade, deadEngine);
|
||||
deadEngine->Init();
|
||||
return deadEngine;
|
||||
}
|
||||
|
||||
@@ -342,16 +342,7 @@ void PlayerbotAI::UpdateAI(uint32 elapsed, bool minimal)
|
||||
|
||||
bool min = minimal;
|
||||
UpdateAIInternal(elapsed, min);
|
||||
inCombat = bot->IsInCombat();
|
||||
// test fix lags because of BG
|
||||
bool inBG = bot->InBattleground() || bot->InArena();
|
||||
if (bot && !inCombat)
|
||||
min = true;
|
||||
|
||||
if (HasRealPlayerMaster() || (sPlayerbotAIConfig->fastReactInBG && inBG))
|
||||
min = false;
|
||||
|
||||
YieldThread(min);
|
||||
YieldThread(GetReactDelay());
|
||||
}
|
||||
|
||||
void PlayerbotAI::UpdateAIInternal([[maybe_unused]] uint32 elapsed, bool minimal)
|
||||
@@ -940,6 +931,7 @@ void PlayerbotAI::HandleBotOutgoingPacket(WorldPacket const& packet)
|
||||
|
||||
if (!AllowActivity())
|
||||
return;
|
||||
|
||||
WorldPacket p(packet);
|
||||
if (!p.empty() && (p.GetOpcode() == SMSG_MESSAGECHAT || p.GetOpcode() == SMSG_GM_MESSAGECHAT))
|
||||
{
|
||||
@@ -1584,6 +1576,9 @@ void PlayerbotAI::ResetStrategies(bool load)
|
||||
AiFactory::AddDefaultNonCombatStrategies(bot, this, engines[BOT_STATE_NON_COMBAT]);
|
||||
AiFactory::AddDefaultDeadStrategies(bot, this, engines[BOT_STATE_DEAD]);
|
||||
|
||||
for (uint8 i = 0; i < BOT_STATE_MAX; i++)
|
||||
engines[i]->Init();
|
||||
|
||||
// if (load)
|
||||
// sPlayerbotDbStore->Load(this);
|
||||
}
|
||||
@@ -2748,7 +2743,8 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
||||
}
|
||||
|
||||
uint32 CastingTime = !spellInfo->IsChanneled() ? spellInfo->CalcCastTime(bot) : spellInfo->GetDuration();
|
||||
if (CastingTime && bot->isMoving())
|
||||
bool interruptOnMove = spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT;
|
||||
if ((CastingTime || interruptOnMove) && bot->isMoving())
|
||||
{
|
||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
||||
{
|
||||
@@ -4795,7 +4791,8 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const
|
||||
{
|
||||
for (const auto& id : uPriorizedWizardOilIds)
|
||||
{
|
||||
if (oil = FindConsumable(id))
|
||||
oil = FindConsumable(id);
|
||||
if (oil)
|
||||
return oil;
|
||||
}
|
||||
}
|
||||
@@ -4804,7 +4801,8 @@ Item* PlayerbotAI::FindOilFor(Item* weapon) const
|
||||
{
|
||||
for (const auto& id : uPriorizedManaOilIds)
|
||||
{
|
||||
if (oil = FindConsumable(id))
|
||||
oil = FindConsumable(id);
|
||||
if (oil)
|
||||
return oil;
|
||||
}
|
||||
}
|
||||
@@ -5691,3 +5689,81 @@ std::set<uint32> PlayerbotAI::GetCurrentIncompleteQuestIds()
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32 PlayerbotAI::GetReactDelay()
|
||||
{
|
||||
uint32 base = sPlayerbotAIConfig->reactDelay;
|
||||
// old calculate method
|
||||
if (!sPlayerbotAIConfig->dynamicReactDelay)
|
||||
{
|
||||
inCombat = bot->IsInCombat();
|
||||
bool min = false;
|
||||
// test fix lags because of BG
|
||||
bool inBG = bot->InBattleground() || bot->InArena();
|
||||
if (bot && !inCombat)
|
||||
min = true;
|
||||
|
||||
if (HasRealPlayerMaster() || (sPlayerbotAIConfig->fastReactInBG && inBG))
|
||||
min = false;
|
||||
if (min)
|
||||
return base * 10;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
float multiplier = 1.0f;
|
||||
|
||||
if (HasRealPlayerMaster())
|
||||
{
|
||||
multiplier = 1.0f;
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
bool inBg = bot->InBattleground() || bot->InArena();
|
||||
if (inBg)
|
||||
{
|
||||
multiplier = sPlayerbotAIConfig->fastReactInBG ? 1.0f : 10.0f;
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
if (bot->IsInCombat() || currentState == BOT_STATE_COMBAT)
|
||||
{
|
||||
multiplier = 5.0f;
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
bool isResting = bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
|
||||
if (!isResting)
|
||||
{
|
||||
multiplier = urand(5, 20);
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
multiplier = urand(20, 200);
|
||||
return base * multiplier;
|
||||
}
|
||||
|
||||
void PlayerbotAI::PetFollow()
|
||||
{
|
||||
Pet* pet = bot->GetPet();
|
||||
if (!pet)
|
||||
return;
|
||||
pet->AttackStop();
|
||||
pet->InterruptNonMeleeSpells(false);
|
||||
pet->ClearInPetCombat();
|
||||
pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
if (pet->ToPet())
|
||||
pet->ToPet()->ClearCastWhenWillAvailable();
|
||||
CharmInfo* charmInfo = pet->GetCharmInfo();
|
||||
if (!charmInfo)
|
||||
return;
|
||||
charmInfo->SetCommandState(COMMAND_FOLLOW);
|
||||
|
||||
charmInfo->SetIsCommandAttack(false);
|
||||
charmInfo->SetIsAtStay(false);
|
||||
charmInfo->SetIsReturning(true);
|
||||
charmInfo->SetIsCommandFollow(true);
|
||||
charmInfo->SetIsFollowing(false);
|
||||
charmInfo->RemoveStayPosition();
|
||||
charmInfo->SetForcedSpell(0);
|
||||
charmInfo->SetForcedTargetGUID();
|
||||
}
|
||||
@@ -554,11 +554,14 @@ public:
|
||||
uint32 GetInventoryItemsCountWithId(uint32 itemId);
|
||||
bool HasItemInInventory(uint32 itemId);
|
||||
std::vector<std::pair<const Quest*, uint32>> GetCurrentQuestsRequiringItemId(uint32 itemId);
|
||||
uint32 GetReactDelay();
|
||||
|
||||
std::vector<const Quest*> GetAllCurrentQuests();
|
||||
std::vector<const Quest*> GetCurrentIncompleteQuests();
|
||||
std::set<uint32> GetAllCurrentQuestIds();
|
||||
std::set<uint32> GetCurrentIncompleteQuestIds();
|
||||
void PetFollow();
|
||||
|
||||
private:
|
||||
static void _fillGearScoreData(Player* player, Item* item, std::vector<uint32>* gearScore, uint32& twoHandScore, bool mixed = false);
|
||||
bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL);
|
||||
|
||||
@@ -49,10 +49,10 @@ void PlayerbotAIBase::IncreaseNextCheckDelay(uint32 delay)
|
||||
|
||||
bool PlayerbotAIBase::CanUpdateAI() { return nextAICheckDelay == 0; }
|
||||
|
||||
void PlayerbotAIBase::YieldThread(bool delay)
|
||||
void PlayerbotAIBase::YieldThread(uint32 delay)
|
||||
{
|
||||
if (nextAICheckDelay < sPlayerbotAIConfig->reactDelay)
|
||||
nextAICheckDelay = delay ? sPlayerbotAIConfig->reactDelay * 10 : sPlayerbotAIConfig->reactDelay;
|
||||
if (nextAICheckDelay < delay)
|
||||
nextAICheckDelay = delay;
|
||||
}
|
||||
|
||||
bool PlayerbotAIBase::IsActive() { return nextAICheckDelay < sPlayerbotAIConfig->maxWaitForMove; }
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define _PLAYERBOT_PLAYERBOTAIBASE_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
|
||||
class PlayerbotAIBase
|
||||
{
|
||||
@@ -16,7 +17,7 @@ public:
|
||||
bool CanUpdateAI();
|
||||
void SetNextCheckDelay(uint32 const delay);
|
||||
void IncreaseNextCheckDelay(uint32 delay);
|
||||
void YieldThread(bool delay = false);
|
||||
void YieldThread(uint32 delay = sPlayerbotAIConfig->reactDelay);
|
||||
virtual void UpdateAI(uint32 elapsed, bool minimal = false);
|
||||
virtual void UpdateAIInternal(uint32 elapsed, bool minimal = false) = 0;
|
||||
bool IsActive();
|
||||
|
||||
@@ -59,7 +59,8 @@ bool PlayerbotAIConfig::Initialize()
|
||||
maxMovementSearchTime = sConfigMgr->GetOption<int32>("AiPlayerbot.MaxMovementSearchTime", 3);
|
||||
expireActionTime = sConfigMgr->GetOption<int32>("AiPlayerbot.ExpireActionTime", 5000);
|
||||
dispelAuraDuration = sConfigMgr->GetOption<int32>("AiPlayerbot.DispelAuraDuration", 7000);
|
||||
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 500);
|
||||
reactDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ReactDelay", 100);
|
||||
dynamicReactDelay = sConfigMgr->GetOption<bool>("AiPlayerbot.DynamicReactDelay", true);
|
||||
passiveDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.PassiveDelay", 10000);
|
||||
repeatDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.RepeatDelay", 2000);
|
||||
errorDelay = sConfigMgr->GetOption<int32>("AiPlayerbot.ErrorDelay", 5000);
|
||||
@@ -77,7 +78,7 @@ bool PlayerbotAIConfig::Initialize()
|
||||
fleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FleeDistance", 7.5f);
|
||||
aggroDistance = sConfigMgr->GetOption<float>("AiPlayerbot.AggroDistance", 22.0f);
|
||||
tooCloseDistance = sConfigMgr->GetOption<float>("AiPlayerbot.TooCloseDistance", 5.0f);
|
||||
meleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.MeleeDistance", 1.5f);
|
||||
meleeDistance = sConfigMgr->GetOption<float>("AiPlayerbot.MeleeDistance", 0.75f);
|
||||
followDistance = sConfigMgr->GetOption<float>("AiPlayerbot.FollowDistance", 1.5f);
|
||||
whisperDistance = sConfigMgr->GetOption<float>("AiPlayerbot.WhisperDistance", 6000.0f);
|
||||
contactDistance = sConfigMgr->GetOption<float>("AiPlayerbot.ContactDistance", 0.5f);
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
bool randomBotGuildNearby, randomBotInvitePlayer, inviteChat;
|
||||
uint32 globalCoolDown, reactDelay, maxWaitForMove, disableMoveSplinePath, maxMovementSearchTime, expireActionTime,
|
||||
dispelAuraDuration, passiveDelay, repeatDelay, errorDelay, rpgDelay, sitDelay, returnDelay, lootDelay;
|
||||
bool dynamicReactDelay;
|
||||
float sightDistance, spellDistance, reactDistance, grindDistance, lootDistance, shootDistance, fleeDistance,
|
||||
tooCloseDistance, meleeDistance, followDistance, whisperDistance, contactDistance, aoeRadius, rpgDistance,
|
||||
targetPosRecalcDistance, farDistance, healDistance, aggroDistance;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "LFGMgr.h"
|
||||
#include "MapMgr.h"
|
||||
#include "PerformanceMonitor.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotCommandServer.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
@@ -2333,6 +2334,11 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
uint32 taxi = 0;
|
||||
uint32 moving = 0;
|
||||
uint32 mounted = 0;
|
||||
uint32 inBg = 0;
|
||||
uint32 rest = 0;
|
||||
uint32 engine_noncombat = 0;
|
||||
uint32 engine_combat = 0;
|
||||
uint32 engine_dead = 0;
|
||||
uint32 stateCount[MAX_TRAVEL_STATE + 1] = {0};
|
||||
std::vector<std::pair<Quest const*, int32>> questCount;
|
||||
for (PlayerBotMap::iterator i = playerBots.begin(); i != playerBots.end(); ++i)
|
||||
@@ -2369,7 +2375,33 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
// if (!GetEventValue(botId, "dead"))
|
||||
//++revive;
|
||||
}
|
||||
|
||||
if (bot->IsInCombat())
|
||||
{
|
||||
++combat;
|
||||
}
|
||||
if (bot->isMoving())
|
||||
{
|
||||
++moving;
|
||||
}
|
||||
if (bot->IsMounted())
|
||||
{
|
||||
++mounted;
|
||||
}
|
||||
if (bot->InBattleground() || bot->InArena())
|
||||
{
|
||||
++inBg;
|
||||
}
|
||||
if (bot->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING))
|
||||
{
|
||||
++rest;
|
||||
}
|
||||
if (botAI->GetState() == BOT_STATE_NON_COMBAT)
|
||||
++engine_noncombat;
|
||||
else if (botAI->GetState() == BOT_STATE_COMBAT)
|
||||
++engine_combat;
|
||||
else
|
||||
++engine_dead;
|
||||
|
||||
uint8 spec = AiFactory::GetPlayerSpecTab(bot);
|
||||
switch (bot->getClass())
|
||||
{
|
||||
@@ -2490,8 +2522,15 @@ void RandomPlayerbotMgr::PrintStats()
|
||||
LOG_INFO("playerbots", " On taxi: {}", taxi);
|
||||
LOG_INFO("playerbots", " On mount: {}", mounted);
|
||||
LOG_INFO("playerbots", " In combat: {}", combat);
|
||||
LOG_INFO("playerbots", " In BG: {}", inBg);
|
||||
LOG_INFO("playerbots", " In Rest: {}", rest);
|
||||
LOG_INFO("playerbots", " Dead: {}", dead);
|
||||
|
||||
LOG_INFO("playerbots", "Bots engine:", dead);
|
||||
LOG_INFO("playerbots", " Non-combat: {}", engine_noncombat);
|
||||
LOG_INFO("playerbots", " Combat: {}", engine_combat);
|
||||
LOG_INFO("playerbots", " Dead: {}", engine_dead);
|
||||
|
||||
LOG_INFO("playerbots", "Bots questing:");
|
||||
LOG_INFO("playerbots", " Picking quests: {}",
|
||||
stateCount[TRAVEL_STATE_TRAVEL_PICK_UP_QUEST] + stateCount[TRAVEL_STATE_WORK_PICK_UP_QUEST]);
|
||||
@@ -2746,3 +2785,4 @@ ObjectGuid const RandomPlayerbotMgr::GetBattleMasterGUID(Player* bot, Battlegrou
|
||||
|
||||
return battleMasterGUID;
|
||||
}
|
||||
|
||||
|
||||
@@ -412,10 +412,10 @@ void PlayerbotFactory::Randomize(bool incremental)
|
||||
void PlayerbotFactory::Refresh()
|
||||
{
|
||||
// Prepare();
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
{
|
||||
InitEquipment(true);
|
||||
}
|
||||
// if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
// {
|
||||
// InitEquipment(true);
|
||||
// }
|
||||
ClearInventory();
|
||||
InitAmmo();
|
||||
InitFood();
|
||||
|
||||
@@ -225,7 +225,10 @@ bool StatsCollector::SpecialSpellFilter(uint32 spellId) {
|
||||
if (type_ != CollectorType::SPELL_HEAL)
|
||||
stats[STATS_TYPE_CRIT] += 50;
|
||||
return true;
|
||||
break;
|
||||
case 59620:
|
||||
if (type_ == CollectorType::MELEE)
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 120;
|
||||
return true;
|
||||
case 67702: // Death's Verdict
|
||||
stats[STATS_TYPE_ATTACK_POWER] += 225;
|
||||
return true;
|
||||
@@ -493,6 +496,13 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu
|
||||
case SPELL_AURA_MOD_INCREASE_HEALTH:
|
||||
stats[STATS_TYPE_STAMINA] += val * multiplier / 15;
|
||||
break;
|
||||
case SPELL_AURA_SCHOOL_ABSORB:
|
||||
{
|
||||
int32 schoolType = effectInfo.MiscValue;
|
||||
if (schoolType & SPELL_SCHOOL_MASK_NORMAL)
|
||||
stats[STATS_TYPE_STAMINA] += val * multiplier / 15;
|
||||
break;
|
||||
}
|
||||
case SPELL_AURA_MOD_ATTACK_POWER:
|
||||
stats[STATS_TYPE_ATTACK_POWER] += val * multiplier;
|
||||
break;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "AiFactory.h"
|
||||
#include "DBCStores.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "SharedDefines.h"
|
||||
@@ -231,7 +232,8 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
|
||||
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
|
||||
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.2f;
|
||||
}
|
||||
else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE ||
|
||||
else if (cls == CLASS_WARLOCK ||
|
||||
cls == CLASS_MAGE ||
|
||||
(cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW) || // shadow
|
||||
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL) || // element
|
||||
(cls == CLASS_DRUID && tab == DRUID_TAB_BALANCE)) // balance
|
||||
@@ -454,6 +456,16 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
||||
{
|
||||
weight_ *= 0.1;
|
||||
}
|
||||
if (cls == CLASS_ROGUE && player_->HasAura(13964)
|
||||
&& (proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
||||
{
|
||||
weight_ *= 1.1;
|
||||
}
|
||||
if (cls == CLASS_WARRIOR && player_->HasAura(12785)
|
||||
&& (proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2))
|
||||
{
|
||||
weight_ *= 1.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -409,26 +409,26 @@ ActionResult Engine::ExecuteAction(std::string const name, Event event, std::str
|
||||
return result ? ACTION_RESULT_OK : ACTION_RESULT_FAILED;
|
||||
}
|
||||
|
||||
void Engine::addStrategy(std::string const name)
|
||||
void Engine::addStrategy(std::string const name, bool init)
|
||||
{
|
||||
removeStrategy(name);
|
||||
removeStrategy(name, init);
|
||||
|
||||
if (Strategy* strategy = aiObjectContext->GetStrategy(name))
|
||||
{
|
||||
std::set<std::string> siblings = aiObjectContext->GetSiblingStrategy(name);
|
||||
for (std::set<std::string>::iterator i = siblings.begin(); i != siblings.end(); i++)
|
||||
removeStrategy(*i);
|
||||
removeStrategy(*i, init);
|
||||
|
||||
LogAction("S:+%s", strategy->getName().c_str());
|
||||
strategies[strategy->getName()] = strategy;
|
||||
}
|
||||
|
||||
Init();
|
||||
if (init)
|
||||
Init();
|
||||
}
|
||||
|
||||
void Engine::addStrategies(std::string first, ...)
|
||||
{
|
||||
addStrategy(first);
|
||||
addStrategy(first, false);
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, first);
|
||||
@@ -438,13 +438,34 @@ void Engine::addStrategies(std::string first, ...)
|
||||
{
|
||||
cur = va_arg(vl, const char*);
|
||||
if (cur)
|
||||
addStrategy(cur);
|
||||
addStrategy(cur, false);
|
||||
} while (cur);
|
||||
|
||||
Init();
|
||||
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void Engine::addStrategiesNoInit(std::string first, ...)
|
||||
{
|
||||
addStrategy(first, false);
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, first);
|
||||
|
||||
const char* cur;
|
||||
do
|
||||
{
|
||||
cur = va_arg(vl, const char*);
|
||||
if (cur)
|
||||
addStrategy(cur, false);
|
||||
} while (cur);
|
||||
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
bool Engine::removeStrategy(std::string const name)
|
||||
|
||||
bool Engine::removeStrategy(std::string const name, bool init)
|
||||
{
|
||||
std::map<std::string, Strategy*>::iterator i = strategies.find(name);
|
||||
if (i == strategies.end())
|
||||
@@ -452,7 +473,8 @@ bool Engine::removeStrategy(std::string const name)
|
||||
|
||||
LogAction("S:-%s", name.c_str());
|
||||
strategies.erase(i);
|
||||
Init();
|
||||
if (init)
|
||||
Init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -65,9 +65,10 @@ public:
|
||||
Engine(PlayerbotAI* botAI, AiObjectContext* factory);
|
||||
|
||||
void Init();
|
||||
void addStrategy(std::string const name);
|
||||
void addStrategy(std::string const name, bool init = true);
|
||||
void addStrategies(std::string first, ...);
|
||||
bool removeStrategy(std::string const name);
|
||||
void addStrategiesNoInit(std::string first, ...);
|
||||
bool removeStrategy(std::string const name, bool init = true);
|
||||
bool HasStrategy(std::string const name);
|
||||
void removeAllStrategies();
|
||||
void toggleStrategy(std::string const name);
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
creators["emote"] = &StrategyContext::emote;
|
||||
creators["passive"] = &StrategyContext::passive;
|
||||
// creators["conserve mana"] = &StrategyContext::conserve_mana;
|
||||
creators["auto save mana"] = &StrategyContext::auto_save_mana;
|
||||
creators["smana"] = &StrategyContext::auto_save_mana;
|
||||
creators["food"] = &StrategyContext::food;
|
||||
creators["chat"] = &StrategyContext::chat;
|
||||
creators["default"] = &StrategyContext::world_packet;
|
||||
@@ -112,9 +112,9 @@ public:
|
||||
creators["group"] = &StrategyContext::group;
|
||||
creators["guild"] = &StrategyContext::guild;
|
||||
creators["grind"] = &StrategyContext::grind;
|
||||
creators["avoid aoe"] = &StrategyContext::avoid_aoe;
|
||||
creators["aaoe"] = &StrategyContext::avoid_aoe;
|
||||
creators["move random"] = &StrategyContext::move_random;
|
||||
creators["combat formation"] = &StrategyContext::combat_formation;
|
||||
creators["formation"] = &StrategyContext::combat_formation;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -405,14 +405,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class RecentlyFleeInfo : public ManualSetValue<std::list<FleeInfo>>
|
||||
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)
|
||||
RecentlyFleeInfo(PlayerbotAI* botAI, std::string const name = "recently flee info")
|
||||
: ManualSetValue<std::list<FleeInfo>&>(botAI, data, name)
|
||||
{
|
||||
}
|
||||
private:
|
||||
std::list<FleeInfo> data = {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,10 +8,9 @@
|
||||
|
||||
#include "AddLootAction.h"
|
||||
#include "AttackAction.h"
|
||||
#include "AutoLearnSpellAction.h"
|
||||
#include "ShareQuestAction.h"
|
||||
#include "BattleGroundTactics.h"
|
||||
#include "AutoTeleportForLevelAction.h"
|
||||
#include "AutoMaintenanceOnLevelupAction.h"
|
||||
#include "BattleGroundJoinAction.h"
|
||||
#include "BattleGroundTactics.h"
|
||||
#include "BuyAction.h"
|
||||
@@ -92,7 +91,7 @@ public:
|
||||
creators["reach party member to resurrect"] = &ActionContext::reach_party_member_to_resurrect;
|
||||
creators["flee"] = &ActionContext::flee;
|
||||
creators["flee with pet"] = &ActionContext::flee_with_pet;
|
||||
creators["avoid aoe"] = &ActionContext::avoid_aoe;
|
||||
creators["aaoe"] = &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;
|
||||
@@ -154,11 +153,12 @@ public:
|
||||
creators["give water"] = &ActionContext::give_water;
|
||||
creators["mount"] = &ActionContext::mount;
|
||||
creators["war stomp"] = &ActionContext::war_stomp;
|
||||
creators["blood fury"] = &ActionContext::blood_fury;
|
||||
creators["berserking"] = &ActionContext::berserking;
|
||||
creators["use trinket"] = &ActionContext::use_trinket;
|
||||
creators["auto talents"] = &ActionContext::auto_talents;
|
||||
creators["auto learn spell"] = &ActionContext::auto_learn_spell;
|
||||
creators["auto share quest"] = &ActionContext::auto_share_quest;
|
||||
creators["auto teleport for level"] = &ActionContext::auto_teleport_for_level;
|
||||
creators["auto upgrade equip"] = &ActionContext::auto_upgrade_equip;
|
||||
creators["auto maintenance on levelup"] = &ActionContext::auto_maintenance_on_levelup;
|
||||
creators["xp gain"] = &ActionContext::xp_gain;
|
||||
creators["invite nearby"] = &ActionContext::invite_nearby;
|
||||
creators["invite guild"] = &ActionContext::invite_guild;
|
||||
@@ -324,11 +324,12 @@ private:
|
||||
static Action* try_emergency(PlayerbotAI* botAI) { return new TryEmergencyAction(botAI); }
|
||||
static Action* mount(PlayerbotAI* botAI) { return new CastSpellAction(botAI, "mount"); }
|
||||
static Action* war_stomp(PlayerbotAI* botAI) { return new CastWarStompAction(botAI); }
|
||||
static Action* blood_fury(PlayerbotAI* botAI) { return new CastBloodFuryAction(botAI); }
|
||||
static Action* berserking(PlayerbotAI* botAI) { return new CastBerserkingAction(botAI); }
|
||||
static Action* use_trinket(PlayerbotAI* botAI) { return new UseTrinketAction(botAI); }
|
||||
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
|
||||
static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); }
|
||||
static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); }
|
||||
static Action* auto_teleport_for_level(PlayerbotAI* botAI) { return new AutoTeleportForLevelAction(botAI); }
|
||||
static Action* auto_upgrade_equip(PlayerbotAI* botAI) { return new AutoUpgradeEquipAction(botAI); }
|
||||
static Action* auto_maintenance_on_levelup(PlayerbotAI* botAI) { return new AutoMaintenanceOnLevelupAction(botAI); }
|
||||
static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); }
|
||||
static Action* invite_nearby(PlayerbotAI* botAI) { return new InviteNearbyToGroupAction(botAI); }
|
||||
static Action* invite_guild(PlayerbotAI* botAI) { return new InviteGuildToGroupAction(botAI); }
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "Event.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "LootObjectStack.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
|
||||
bool AttackAction::Execute(Event event)
|
||||
@@ -109,24 +112,32 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/)
|
||||
bot->SetSelection(target->GetGUID());
|
||||
|
||||
Unit* oldTarget = context->GetValue<Unit*>("current target")->Get();
|
||||
|
||||
if (oldTarget == target && botAI->GetState() == BOT_STATE_COMBAT && bot->GetVictim() == target)
|
||||
return false;
|
||||
|
||||
context->GetValue<Unit*>("old target")->Set(oldTarget);
|
||||
|
||||
context->GetValue<Unit*>("current target")->Set(target);
|
||||
context->GetValue<LootObjectStack*>("available loot")->Get()->Add(guid);
|
||||
|
||||
LastMovement& lastMovement = AI_VALUE(LastMovement&, "last movement");
|
||||
if (lastMovement.priority < MovementPriority::MOVEMENT_COMBAT && bot->isMoving())
|
||||
{
|
||||
AI_VALUE(LastMovement&, "last movement").clear();
|
||||
bot->GetMotionMaster()->Clear(false);
|
||||
bot->StopMoving();
|
||||
}
|
||||
|
||||
bool melee = bot->IsWithinMeleeRange(target) || botAI->IsMelee(bot);
|
||||
bot->Attack(target, melee);
|
||||
|
||||
if (IsMovingAllowed() && !bot->HasInArc(CAST_ANGLE_IN_FRONT, target))
|
||||
{
|
||||
sServerFacade->SetFacingTo(bot, target);
|
||||
}
|
||||
botAI->ChangeEngine(BOT_STATE_COMBAT);
|
||||
|
||||
if (!bot->GetVictim())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bot->Attack(target, melee);
|
||||
/* prevent pet dead immediately in group */
|
||||
// if (bot->GetMap()->IsDungeon() && bot->GetGroup() && !target->IsInCombat()) {
|
||||
// with_pet = false;
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#include "AutoLearnSpellAction.h"
|
||||
|
||||
#include "Event.h"
|
||||
#include "GuildMgr.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool AutoLearnSpellAction::Execute(Event event)
|
||||
{
|
||||
std::string const param = event.getParam();
|
||||
|
||||
std::ostringstream out;
|
||||
LearnSpells(&out);
|
||||
|
||||
if (!out.str().empty())
|
||||
{
|
||||
std::string const temp = out.str();
|
||||
out.seekp(0);
|
||||
out << "Learned spells: ";
|
||||
out << temp;
|
||||
out.seekp(-2, out.cur);
|
||||
out << ".";
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnSpells(std::ostringstream* out)
|
||||
{
|
||||
BroadcastHelper::BroadcastLevelup(botAI, bot);
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells &&
|
||||
sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
LearnTrainerSpells(out);
|
||||
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells &&
|
||||
sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
LearnQuestSpells(out);
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnTrainerSpells(std::ostringstream* out)
|
||||
{
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
factory.InitClassSpells();
|
||||
factory.InitAvailableSpells();
|
||||
factory.InitSkills();
|
||||
factory.InitPet();
|
||||
// bot->LearnDefaultSkills();
|
||||
|
||||
// CreatureTemplateContainer const* creatureTemplateContainer = sObjectMgr->GetCreatureTemplates();
|
||||
// for (CreatureTemplateContainer::const_iterator i = creatureTemplateContainer->begin(); i !=
|
||||
// creatureTemplateContainer->end(); ++i)
|
||||
// {
|
||||
// CreatureTemplate const& co = i->second;
|
||||
// if (co.trainer_type != TRAINER_TYPE_TRADESKILLS && co.trainer_type != TRAINER_TYPE_CLASS)
|
||||
// continue;
|
||||
|
||||
// if (co.trainer_type == TRAINER_TYPE_CLASS && co.trainer_class != bot->getClass())
|
||||
// continue;
|
||||
|
||||
// uint32 trainerId = co.Entry;
|
||||
|
||||
// TrainerSpellData const* trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
|
||||
// if (!trainer_spells)
|
||||
// trainer_spells = sObjectMgr->GetNpcTrainerSpells(trainerId);
|
||||
|
||||
// if (!trainer_spells)
|
||||
// continue;
|
||||
|
||||
// for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr !=
|
||||
// trainer_spells->spellList.end(); ++itr)
|
||||
// {
|
||||
// TrainerSpell const* tSpell = &itr->second;
|
||||
|
||||
// if (!tSpell)
|
||||
// continue;
|
||||
|
||||
// if (!tSpell->learnedSpell[0] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[0]))
|
||||
// continue;
|
||||
|
||||
// TrainerSpellState state = bot->GetTrainerSpellState(tSpell);
|
||||
// if (state != TRAINER_SPELL_GREEN)
|
||||
// continue;
|
||||
|
||||
// SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(tSpell->spell);
|
||||
// bool learn = true;
|
||||
// for (uint8 j = 0; j < 3; ++j)
|
||||
// {
|
||||
// if (!tSpell->learnedSpell[j] && !bot->IsSpellFitByClassAndRace(tSpell->learnedSpell[j]))
|
||||
// continue;
|
||||
|
||||
// if (spellInfo->Effects[j].Effect == SPELL_EFFECT_PROFICIENCY ||
|
||||
// spellInfo->Effects[j].Effect == SPELL_EFFECT_SKILL_STEP ||
|
||||
// spellInfo->Effects[j].Effect == SPELL_EFFECT_DUAL_WIELD)
|
||||
// {
|
||||
// learn = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!learn) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// if (tSpell->learnedSpell[0]) {
|
||||
// bot->learnSpell(tSpell->learnedSpell[0], false);
|
||||
// }
|
||||
// else {
|
||||
// LOG_INFO("playerbots", "!tSpell->learnedSpell[0] {}", tSpell->spell);
|
||||
// botAI->CastSpell(tSpell->spell, bot);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnQuestSpells(std::ostringstream* out)
|
||||
{
|
||||
// CreatureTemplate const* co = sCreatureStorage.LookupEntry<CreatureTemplate>(id);
|
||||
ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates();
|
||||
for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i)
|
||||
{
|
||||
uint32 questId = i->first;
|
||||
Quest const* quest = i->second;
|
||||
|
||||
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10)
|
||||
continue;
|
||||
|
||||
if (!bot->SatisfyQuestClass(quest, false) || quest->GetMinLevel() > bot->GetLevel() ||
|
||||
!bot->SatisfyQuestRace(quest, false))
|
||||
continue;
|
||||
|
||||
if (quest->GetRewSpellCast() > 0)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpellCast(), out);
|
||||
}
|
||||
else if (quest->GetRewSpell() > 0)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpell(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string const FormatSpell(SpellInfo const* sInfo)
|
||||
{
|
||||
std::ostringstream out;
|
||||
std::string const rank = sInfo->Rank[0];
|
||||
|
||||
if (rank.empty())
|
||||
out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << "]|h|r";
|
||||
else
|
||||
out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << " " << rank << "]|h|r";
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void AutoLearnSpellAction::LearnSpell(uint32 spellId, std::ostringstream* out)
|
||||
{
|
||||
SpellInfo const* proto = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!proto)
|
||||
return;
|
||||
|
||||
bool learned = false;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
if (proto->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
{
|
||||
uint32 learnedSpell = proto->Effects[j].TriggerSpell;
|
||||
|
||||
if (!bot->HasSpell(learnedSpell))
|
||||
{
|
||||
bot->learnSpell(learnedSpell);
|
||||
*out << FormatSpell(sSpellMgr->GetSpellInfo(learnedSpell)) << ", ";
|
||||
}
|
||||
|
||||
learned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!learned)
|
||||
{
|
||||
if (!bot->HasSpell(spellId))
|
||||
{
|
||||
bot->learnSpell(spellId);
|
||||
*out << FormatSpell(proto) << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool AutoUpgradeEquipAction::Execute(Event event)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
{
|
||||
factory.InitEquipment(true);
|
||||
}
|
||||
factory.InitAmmo();
|
||||
return true;
|
||||
}
|
||||
171
src/strategy/actions/AutoMaintenanceOnLevelupAction.cpp
Normal file
171
src/strategy/actions/AutoMaintenanceOnLevelupAction.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "AutoMaintenanceOnLevelupAction.h"
|
||||
|
||||
#include "GuildMgr.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "BroadcastHelper.h"
|
||||
|
||||
bool AutoMaintenanceOnLevelupAction::Execute(Event event)
|
||||
{
|
||||
AutoPickTalents();
|
||||
AutoLearnSpell();
|
||||
AutoUpgradeEquip();
|
||||
AutoTeleportForLevel();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoTeleportForLevel()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (botAI->HasRealPlayerMaster())
|
||||
{
|
||||
return;
|
||||
}
|
||||
sRandomPlayerbotMgr->RandomTeleportForLevel(bot);
|
||||
return;
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoPickTalents()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoPickTalents || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
return;
|
||||
|
||||
if (bot->GetFreeTalentPoints() <= 0)
|
||||
return;
|
||||
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
factory.InitTalentsTree(true, true, true);
|
||||
factory.InitPetTalents();
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoLearnSpell()
|
||||
{
|
||||
std::ostringstream out;
|
||||
LearnSpells(&out);
|
||||
|
||||
if (!out.str().empty())
|
||||
{
|
||||
std::string const temp = out.str();
|
||||
out.seekp(0);
|
||||
out << "Learned spells: ";
|
||||
out << temp;
|
||||
out.seekp(-2, out.cur);
|
||||
out << ".";
|
||||
botAI->TellMaster(out);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnSpells(std::ostringstream* out)
|
||||
{
|
||||
BroadcastHelper::BroadcastLevelup(botAI, bot);
|
||||
if (sPlayerbotAIConfig->autoLearnTrainerSpells)
|
||||
LearnTrainerSpells(out);
|
||||
|
||||
if (sPlayerbotAIConfig->autoLearnQuestSpells)
|
||||
LearnQuestSpells(out);
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnTrainerSpells(std::ostringstream* out)
|
||||
{
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
factory.InitClassSpells();
|
||||
factory.InitAvailableSpells();
|
||||
factory.InitSkills();
|
||||
factory.InitPet();
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnQuestSpells(std::ostringstream* out)
|
||||
{
|
||||
// CreatureTemplate const* co = sCreatureStorage.LookupEntry<CreatureTemplate>(id);
|
||||
ObjectMgr::QuestMap const& questTemplates = sObjectMgr->GetQuestTemplates();
|
||||
for (ObjectMgr::QuestMap::const_iterator i = questTemplates.begin(); i != questTemplates.end(); ++i)
|
||||
{
|
||||
uint32 questId = i->first;
|
||||
Quest const* quest = i->second;
|
||||
|
||||
if (!quest->GetRequiredClasses() || quest->IsRepeatable() || quest->GetMinLevel() < 10)
|
||||
continue;
|
||||
|
||||
if (!bot->SatisfyQuestClass(quest, false) || quest->GetMinLevel() > bot->GetLevel() ||
|
||||
!bot->SatisfyQuestRace(quest, false))
|
||||
continue;
|
||||
|
||||
if (quest->GetRewSpellCast() > 0)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpellCast(), out);
|
||||
}
|
||||
else if (quest->GetRewSpell() > 0)
|
||||
{
|
||||
LearnSpell(quest->GetRewSpell(), out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string const AutoMaintenanceOnLevelupAction::FormatSpell(SpellInfo const* sInfo)
|
||||
{
|
||||
std::ostringstream out;
|
||||
std::string const rank = sInfo->Rank[0];
|
||||
|
||||
if (rank.empty())
|
||||
out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << "]|h|r";
|
||||
else
|
||||
out << "|cffffffff|Hspell:" << sInfo->Id << "|h[" << sInfo->SpellName[LOCALE_enUS] << " " << rank << "]|h|r";
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::LearnSpell(uint32 spellId, std::ostringstream* out)
|
||||
{
|
||||
SpellInfo const* proto = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!proto)
|
||||
return;
|
||||
|
||||
bool learned = false;
|
||||
for (uint8 j = 0; j < 3; ++j)
|
||||
{
|
||||
if (proto->Effects[j].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
{
|
||||
uint32 learnedSpell = proto->Effects[j].TriggerSpell;
|
||||
|
||||
if (!bot->HasSpell(learnedSpell))
|
||||
{
|
||||
bot->learnSpell(learnedSpell);
|
||||
*out << FormatSpell(sSpellMgr->GetSpellInfo(learnedSpell)) << ", ";
|
||||
}
|
||||
|
||||
learned = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!learned)
|
||||
{
|
||||
if (!bot->HasSpell(spellId))
|
||||
{
|
||||
bot->learnSpell(spellId);
|
||||
*out << FormatSpell(proto) << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoMaintenanceOnLevelupAction::AutoUpgradeEquip()
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
return;
|
||||
}
|
||||
PlayerbotFactory factory(bot, bot->GetLevel());
|
||||
if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel)
|
||||
{
|
||||
factory.InitEquipment(true);
|
||||
}
|
||||
factory.InitAmmo();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,33 +3,33 @@
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AUTOLEARNSPELLACTION_H
|
||||
#define _PLAYERBOT_AUTOLEARNSPELLACTION_H
|
||||
#ifndef _PLAYERBOT_AUTOTELEPORTFORLEVELACTION_H
|
||||
#define _PLAYERBOT_AUTOTELEPORTFORLEVELACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AutoLearnSpellAction : public Action
|
||||
class AutoMaintenanceOnLevelupAction : public Action
|
||||
{
|
||||
public:
|
||||
AutoLearnSpellAction(PlayerbotAI* botAI, std::string const name = "auto learn spell") : Action(botAI, name) {}
|
||||
AutoMaintenanceOnLevelupAction(PlayerbotAI* botAI, std::string const name = "auto maintenance on levelup")
|
||||
: Action(botAI, name)
|
||||
{
|
||||
}
|
||||
|
||||
bool Execute(Event event);
|
||||
|
||||
private:
|
||||
protected:
|
||||
void AutoTeleportForLevel();
|
||||
void AutoPickTalents();
|
||||
void AutoLearnSpell();
|
||||
void AutoUpgradeEquip();
|
||||
void LearnSpells(std::ostringstream* out);
|
||||
void LearnTrainerSpells(std::ostringstream* out);
|
||||
void LearnQuestSpells(std::ostringstream* out);
|
||||
void LearnSpell(uint32 spellId, std::ostringstream* out);
|
||||
};
|
||||
|
||||
class AutoUpgradeEquipAction : public Action
|
||||
{
|
||||
public:
|
||||
AutoUpgradeEquipAction(PlayerbotAI* botAI, std::string const name = "auto upgrade equip") : Action(botAI, name) {}
|
||||
|
||||
bool Execute(Event event);
|
||||
std::string const FormatSpell(SpellInfo const* sInfo);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "AutoTeleportForLevelAction.h"
|
||||
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "PlayerbotFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RandomPlayerbotMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
|
||||
bool AutoTeleportForLevelAction::Execute(Event event)
|
||||
{
|
||||
if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (botAI->HasRealPlayerMaster())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
sRandomPlayerbotMgr->RandomTeleportForLevel(bot);
|
||||
return true;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it
|
||||
* and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
*/
|
||||
|
||||
#ifndef _PLAYERBOT_AUTOTELEPORTFORLEVELACTION_H
|
||||
#define _PLAYERBOT_AUTOTELEPORTFORLEVELACTION_H
|
||||
|
||||
#include "Action.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
class AutoTeleportForLevelAction : public Action
|
||||
{
|
||||
public:
|
||||
AutoTeleportForLevelAction(PlayerbotAI* botAI, std::string const name = "auto teleport for level")
|
||||
: Action(botAI, name)
|
||||
{
|
||||
}
|
||||
|
||||
bool Execute(Event event);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -32,7 +32,7 @@ bool FollowChatShortcutAction::Execute(Event event)
|
||||
if (!master)
|
||||
return false;
|
||||
|
||||
botAI->Reset();
|
||||
// botAI->Reset();
|
||||
botAI->ChangeStrategy("+follow,-passive,-grind", BOT_STATE_NON_COMBAT);
|
||||
botAI->ChangeStrategy("-follow,-passive,-grind", BOT_STATE_COMBAT);
|
||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
||||
@@ -57,7 +57,14 @@ bool FollowChatShortcutAction::Execute(Event event)
|
||||
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
|
||||
return false;
|
||||
|
||||
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ());
|
||||
MovementPriority priority = botAI->GetState() == BOT_STATE_COMBAT ? MovementPriority::MOVEMENT_COMBAT : MovementPriority::MOVEMENT_NORMAL;
|
||||
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false,
|
||||
true, priority);
|
||||
}
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
botAI->PetFollow();
|
||||
}
|
||||
|
||||
if (moved)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "BattlegroundWS.h"
|
||||
#include "Event.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
@@ -17,35 +18,46 @@ bool CheckMountStateAction::Execute(Event event)
|
||||
bool noattackers =
|
||||
AI_VALUE2(bool, "combat", "self target") ? (AI_VALUE(uint8, "attacker count") > 0 ? false : true) : true;
|
||||
bool enemy = AI_VALUE(Unit*, "enemy player target");
|
||||
// ignore grind target in BG or bots will dismount near any creature (eg: the rams in AV)
|
||||
bool dps = AI_VALUE(Unit*, "dps target");
|
||||
// bool fartarget = (enemy && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "enemy player
|
||||
// target"), 40.0f)) ||
|
||||
// (dps && sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "dps target"), 50.0f));
|
||||
bool attackdistance = false;
|
||||
bool shouldDismount = false;
|
||||
bool shouldMount = false;
|
||||
// bool chasedistance = false;
|
||||
float attack_distance = 35.0f;
|
||||
float attack_distance;
|
||||
float mount_distance;
|
||||
if (PlayerbotAI::IsMelee(bot))
|
||||
{
|
||||
attack_distance = 5.0f;
|
||||
attack_distance = sPlayerbotAIConfig->meleeDistance + 2.0f;
|
||||
mount_distance = sPlayerbotAIConfig->meleeDistance + 10.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
attack_distance = 30.0f;
|
||||
attack_distance = sPlayerbotAIConfig->spellDistance + 2.0f;
|
||||
mount_distance = sPlayerbotAIConfig->spellDistance + 10.0f;
|
||||
}
|
||||
|
||||
// if (enemy)
|
||||
// attack_distance /= 2;
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
|
||||
if (dps || enemy)
|
||||
if (currentTarget)
|
||||
{
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
attackdistance =
|
||||
(enemy || dps) && currentTarget &&
|
||||
sServerFacade->IsDistanceLessThan(AI_VALUE2(float, "distance", "current target"), attack_distance);
|
||||
float combatReach = bot->GetCombatReach() + currentTarget->GetCombatReach();
|
||||
attack_distance += combatReach;
|
||||
float disToTarget = bot->GetExactDist(currentTarget);
|
||||
shouldDismount = disToTarget <= attack_distance;
|
||||
}
|
||||
else
|
||||
shouldDismount = false;
|
||||
|
||||
if (bot->IsMounted() && attackdistance)
|
||||
if (currentTarget)
|
||||
{
|
||||
float combatReach = bot->GetCombatReach() + currentTarget->GetCombatReach();
|
||||
mount_distance += combatReach;
|
||||
float disToTarget = bot->GetExactDist(currentTarget);
|
||||
shouldMount = disToTarget > mount_distance;
|
||||
}
|
||||
else
|
||||
shouldMount = true;
|
||||
|
||||
if (bot->IsMounted() && shouldDismount)
|
||||
{
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
@@ -59,7 +71,7 @@ bool CheckMountStateAction::Execute(Event event)
|
||||
return false;
|
||||
|
||||
// bool farFromMaster = sServerFacade->GetDistance2d(bot, master) > sPlayerbotAIConfig->sightDistance;
|
||||
if (master->IsMounted() && !bot->IsMounted() && noattackers && !attackdistance && !bot->IsInCombat() &&
|
||||
if (master->IsMounted() && !bot->IsMounted() && noattackers && shouldMount && !bot->IsInCombat() &&
|
||||
botAI->GetState() != BOT_STATE_COMBAT)
|
||||
{
|
||||
return Mount();
|
||||
@@ -71,16 +83,6 @@ bool CheckMountStateAction::Execute(Event event)
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
return true;
|
||||
}
|
||||
// if (!bot->IsMounted() && (chasedistance || (farFromMaster && botAI->HasStrategy("follow",
|
||||
// BOT_STATE_NON_COMBAT))) && !bot->IsInCombat() && !dps)
|
||||
// return Mount();
|
||||
|
||||
// if (!bot->IsFlying() && ((!farFromMaster && !master->IsMounted()) || attackdistance) && bot->IsMounted())
|
||||
// {
|
||||
// WorldPacket emptyPacket;
|
||||
// bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -88,13 +90,13 @@ bool CheckMountStateAction::Execute(Event event)
|
||||
// For random bots
|
||||
if (!bot->InBattleground() && !master)
|
||||
{
|
||||
if (!bot->IsMounted() && noattackers && !attackdistance && !bot->IsInCombat())
|
||||
if (!bot->IsMounted() && noattackers && shouldMount && !bot->IsInCombat())
|
||||
{
|
||||
return Mount();
|
||||
}
|
||||
}
|
||||
|
||||
if (bot->InBattleground() && !attackdistance && noattackers && !bot->IsInCombat() && !bot->IsMounted())
|
||||
if (bot->InBattleground() && shouldMount && noattackers && !bot->IsInCombat() && !bot->IsMounted())
|
||||
{
|
||||
if (bot->GetBattlegroundTypeId() == BATTLEGROUND_WS)
|
||||
{
|
||||
@@ -108,24 +110,7 @@ bool CheckMountStateAction::Execute(Event event)
|
||||
return Mount();
|
||||
}
|
||||
|
||||
// if (!bot->InBattleground())
|
||||
// {
|
||||
// if (AI_VALUE(GuidPosition, "rpg target"))
|
||||
// {
|
||||
// if (sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "rpg target"),
|
||||
// sPlayerbotAIConfig->farDistance) && noattackers && !dps && !enemy)
|
||||
// return Mount();
|
||||
// }
|
||||
|
||||
// if (((!AI_VALUE(GuidVector, "possible rpg targets").empty()) && noattackers && !dps && !enemy) && urand(0,
|
||||
// 100) > 50)
|
||||
// return Mount();
|
||||
// }
|
||||
|
||||
// if (!bot->IsMounted() && !attackdistance && (fartarget || chasedistance))
|
||||
// return Mount();
|
||||
|
||||
if (!bot->IsFlying() && attackdistance && bot->IsMounted() && (enemy || dps || (!noattackers && bot->IsInCombat())))
|
||||
if (!bot->IsFlying() && shouldDismount && bot->IsMounted() && (enemy || dps || (!noattackers && bot->IsInCombat())))
|
||||
{
|
||||
WorldPacket emptyPacket;
|
||||
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "Event.h"
|
||||
#include "Formations.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
@@ -28,25 +30,15 @@ bool FollowAction::Execute(Event event)
|
||||
WorldLocation loc = formation->GetLocation();
|
||||
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
|
||||
return false;
|
||||
|
||||
|
||||
MovementPriority priority = botAI->GetState() == BOT_STATE_COMBAT ? MovementPriority::MOVEMENT_COMBAT : MovementPriority::MOVEMENT_NORMAL;
|
||||
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false,
|
||||
true);
|
||||
true, priority);
|
||||
}
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
|
||||
{
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->GetCharmInfo()->SetIsCommandFollow(true);
|
||||
pet->GetCharmInfo()->IsReturning();
|
||||
pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
// pet->GetCharmInfo()->SetCommandState(COMMAND_FOLLOW);
|
||||
// pet->GetCharmInfo()->SetIsFollowing(true);
|
||||
// pet->AttackStop();
|
||||
// pet->GetCharmInfo()->IsReturning();
|
||||
// pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
}
|
||||
botAI->PetFollow();
|
||||
}
|
||||
// if (moved)
|
||||
// botAI->SetNextCheckDelay(sPlayerbotAIConfig->reactDelay);
|
||||
|
||||
@@ -36,9 +36,9 @@ bool TogglePetSpellAutoCastAction::Execute(Event event)
|
||||
continue;
|
||||
|
||||
bool shouldApply = true;
|
||||
// imp's spell, felhunte's intelligence, ghoul's leap, cat stealth
|
||||
// imp's spell, felhunte's intelligence, cat stealth
|
||||
if (spellId == 4511 || spellId == 1742 || spellId == 54424 || spellId == 57564 || spellId == 57565 ||
|
||||
spellId == 57566 || spellId == 57567 || spellId == 47482 || spellId == 24450)
|
||||
spellId == 57566 || spellId == 57567 || spellId == 24450)
|
||||
{
|
||||
shouldApply = false;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ bool PetAttackAction::Execute(Event event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// pet->SetReactState(REACT_DEFENSIVE);
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->ClearUnitState(UNIT_STATE_FOLLOW);
|
||||
pet->AttackStop();
|
||||
pet->SetTarget(target->GetGUID());
|
||||
|
||||
@@ -6,8 +6,13 @@
|
||||
#include "GenericSpellActions.h"
|
||||
|
||||
#include "Event.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "ObjectDefines.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
|
||||
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell)
|
||||
@@ -124,11 +129,35 @@ bool CastSpellAction::isUseful()
|
||||
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
|
||||
{
|
||||
range = ATTACK_DISTANCE;
|
||||
// Unit* target = AI_VALUE(Unit*, "current target");
|
||||
// if (target)
|
||||
// range = bot->GetMeleeRange(target);
|
||||
}
|
||||
|
||||
// range = target->GetCombinedCombatReach();
|
||||
bool CastMeleeSpellAction::isUseful()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!bot->IsWithinMeleeRange(target))
|
||||
return false;
|
||||
|
||||
return CastSpellAction::isUseful();
|
||||
}
|
||||
|
||||
CastMeleeDebuffSpellAction::CastMeleeDebuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner, float needLifeTime) : CastDebuffSpellAction(botAI, spell, isOwner, needLifeTime)
|
||||
{
|
||||
range = ATTACK_DISTANCE;
|
||||
}
|
||||
|
||||
bool CastMeleeDebuffSpellAction::isUseful()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
if (!bot->IsWithinMeleeRange(target))
|
||||
return false;
|
||||
|
||||
return CastDebuffSpellAction::isUseful();
|
||||
}
|
||||
|
||||
bool CastAuraSpellAction::isUseful()
|
||||
@@ -209,17 +238,7 @@ CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "s
|
||||
|
||||
NextAction** CastSpellAction::getPrerequisites()
|
||||
{
|
||||
if (spell == "mount")
|
||||
return nullptr;
|
||||
|
||||
if (range > botAI->GetRange("spell"))
|
||||
return nullptr;
|
||||
else if (range > ATTACK_DISTANCE)
|
||||
return NextAction::merge(NextAction::array(0, new NextAction("reach spell"), nullptr),
|
||||
Action::getPrerequisites());
|
||||
else
|
||||
return NextAction::merge(NextAction::array(0, new NextAction("reach melee"), nullptr),
|
||||
Action::getPrerequisites());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Value<Unit*>* CastDebuffSpellOnAttackerAction::GetTargetValue()
|
||||
@@ -271,6 +290,70 @@ bool CastVehicleSpellAction::Execute(Event event)
|
||||
return botAI->CastVehicleSpell(spellId, GetTarget());
|
||||
}
|
||||
|
||||
bool UseTrinketAction::Execute(Event event)
|
||||
{
|
||||
Item* trinket1 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TRINKET1);
|
||||
|
||||
if (trinket1 && UseTrinket(trinket1))
|
||||
return true;
|
||||
|
||||
Item* trinket2 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TRINKET2);
|
||||
|
||||
if (trinket2 && UseTrinket(trinket2))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UseTrinketAction::UseTrinket(Item* item)
|
||||
{
|
||||
if (bot->CanUseItem(item) != EQUIP_ERR_OK)
|
||||
return false;
|
||||
|
||||
if (bot->IsNonMeleeSpellCast(true))
|
||||
return false;
|
||||
|
||||
uint8 bagIndex = item->GetBagSlot();
|
||||
uint8 slot = item->GetSlot();
|
||||
uint8 spell_index = 0;
|
||||
uint8 cast_count = 1;
|
||||
ObjectGuid item_guid = item->GetGUID();
|
||||
uint32 glyphIndex = 0;
|
||||
uint8 castFlags = 0;
|
||||
uint32 targetFlag = TARGET_FLAG_NONE;
|
||||
uint32 spellId = 0;
|
||||
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
|
||||
{
|
||||
if (item->GetTemplate()->Spells[i].SpellId > 0 && item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
|
||||
{
|
||||
spellId = item->GetTemplate()->Spells[i].SpellId;
|
||||
if (!botAI->CanCastSpell(spellId, bot, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!spellId)
|
||||
return false;
|
||||
WorldPacket packet(CMSG_USE_ITEM);
|
||||
packet << bagIndex << slot << cast_count << spellId << item_guid << glyphIndex << castFlags;
|
||||
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (target)
|
||||
{
|
||||
targetFlag = TARGET_FLAG_UNIT;
|
||||
packet << targetFlag << target->GetGUID().WriteAsPacked();
|
||||
}
|
||||
else
|
||||
{
|
||||
targetFlag = TARGET_FLAG_NONE;
|
||||
packet << targetFlag << bot->GetPackGUID();
|
||||
}
|
||||
bot->GetSession()->HandleUseItemOpcode(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
Value<Unit*>* BuffOnMainTankAction::GetTargetValue() { return context->GetValue<Unit*>("main tank", spell); }
|
||||
|
||||
bool CastDebuffSpellAction::isUseful()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Action.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "UseItemAction.h"
|
||||
#include "Value.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
@@ -52,6 +53,7 @@ class CastMeleeSpellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell);
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastDebuffSpellAction : public CastAuraSpellAction
|
||||
@@ -67,6 +69,13 @@ private:
|
||||
float needLifeTime;
|
||||
};
|
||||
|
||||
class CastMeleeDebuffSpellAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMeleeDebuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner = false, float needLifeTime = 8.0f);
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastDebuffSpellOnAttackerAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
@@ -245,10 +254,31 @@ public:
|
||||
CastManaTapAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mana tap") {}
|
||||
};
|
||||
|
||||
class CastWarStompAction : public CastSpellAction
|
||||
class CastWarStompAction : public CastMeleeSpellAction
|
||||
{
|
||||
public:
|
||||
CastWarStompAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "war stomp") {}
|
||||
CastWarStompAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "war stomp") {}
|
||||
};
|
||||
|
||||
class CastBloodFuryAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastBloodFuryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "blood fury") {}
|
||||
};
|
||||
|
||||
class CastBerserkingAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastBerserkingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "berserking") {}
|
||||
};
|
||||
|
||||
class UseTrinketAction : public Action
|
||||
{
|
||||
public:
|
||||
UseTrinketAction(PlayerbotAI* botAI) : Action(botAI, "use trinket") {}
|
||||
bool Execute(Event event) override;
|
||||
protected:
|
||||
bool UseTrinket(Item* trinket);
|
||||
};
|
||||
|
||||
class CastSpellOnEnemyHealerAction : public CastSpellAction
|
||||
|
||||
@@ -143,7 +143,10 @@ std::vector<std::pair<uint32, std::string>> ListSpellsAction::GetSpellList(std::
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
|
||||
if (spellInfo->IsPassive())
|
||||
continue;
|
||||
|
||||
SkillLineAbilityEntry const* skillLine = skillSpells[itr->first];
|
||||
if (skill != SKILL_NONE && (!skillLine || skillLine->SkillLine != skill))
|
||||
continue;
|
||||
|
||||
@@ -94,12 +94,14 @@ bool MoveToRpgTargetAction::Execute(Event event)
|
||||
|
||||
x += cos(angle) * INTERACTION_DISTANCE * distance;
|
||||
y += sin(angle) * INTERACTION_DISTANCE * distance;
|
||||
bool exact = true;
|
||||
if (!wo->GetMap()->CheckCollisionAndGetValidCoords(wo, wo->GetPositionX(), wo->GetPositionY(), wo->GetPositionZ(),
|
||||
x, y, z))
|
||||
{
|
||||
x = wo->GetPositionX();
|
||||
y = wo->GetPositionY();
|
||||
z = wo->GetPositionZ();
|
||||
exact = false;
|
||||
}
|
||||
// WaitForReach(distance);
|
||||
|
||||
@@ -108,7 +110,7 @@ bool MoveToRpgTargetAction::Execute(Event event)
|
||||
// if (bot->IsWithinLOS(x, y, z))
|
||||
// couldMove = MoveNear(mapId, x, y, z, 0);
|
||||
// else
|
||||
couldMove = MoveTo(mapId, x, y, z, false, false, false, true);
|
||||
couldMove = MoveTo(mapId, x, y, z, false, false, false, exact);
|
||||
|
||||
if (!couldMove && WorldPosition(mapId, x, y, z).distance(bot) > INTERACTION_DISTANCE)
|
||||
{
|
||||
|
||||
@@ -61,23 +61,37 @@ void MovementAction::CreateWp(Player* wpOwner, float x, float y, float z, float
|
||||
wpCreature->SetObjectScale(0.5f);
|
||||
}
|
||||
|
||||
void MovementAction::JumpTo(uint32 mapId, float x, float y, float z)
|
||||
bool MovementAction::JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority)
|
||||
{
|
||||
UpdateMovementState();
|
||||
if (!IsMovingAllowed(mapId, x, y, z))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (IsDuplicateMove(mapId, x, y, z))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (IsWaitingForLastMove(priority))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
float botZ = bot->GetPositionZ();
|
||||
float speed = bot->GetSpeed(MOVE_RUN);
|
||||
MotionMaster& mm = *bot->GetMotionMaster();
|
||||
mm.Clear();
|
||||
mm.MoveJump(x, y, z, speed, speed, 1);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), 1000);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), 1000, priority);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovementAction::MoveNear(uint32 mapId, float x, float y, float z, float distance)
|
||||
bool MovementAction::MoveNear(uint32 mapId, float x, float y, float z, float distance, MovementPriority priority)
|
||||
{
|
||||
float angle = GetFollowAngle();
|
||||
return MoveTo(mapId, x + cos(angle) * distance, y + sin(angle) * distance, z);
|
||||
return MoveTo(mapId, x + cos(angle) * distance, y + sin(angle) * distance, z, false, false, false, false, priority);
|
||||
}
|
||||
|
||||
bool MovementAction::MoveNear(WorldObject* target, float distance)
|
||||
bool MovementAction::MoveNear(WorldObject* target, float distance, MovementPriority priority)
|
||||
{
|
||||
if (!target)
|
||||
return false;
|
||||
@@ -99,7 +113,7 @@ bool MovementAction::MoveNear(WorldObject* target, float distance)
|
||||
if (!bot->IsWithinLOS(x, y, z))
|
||||
continue;
|
||||
|
||||
bool moved = MoveTo(target->GetMapId(), x, y, z);
|
||||
bool moved = MoveTo(target->GetMapId(), x, y, z, false, false, false, false, priority);
|
||||
if (moved)
|
||||
return true;
|
||||
}
|
||||
@@ -161,7 +175,7 @@ bool MovementAction::MoveToLOS(WorldObject* target, bool ranged)
|
||||
}
|
||||
|
||||
bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle, bool react, bool normal_only,
|
||||
bool exact_waypoint)
|
||||
bool exact_waypoint, MovementPriority priority)
|
||||
{
|
||||
UpdateMovementState();
|
||||
if (!IsMovingAllowed(mapId, x, y, z))
|
||||
@@ -172,21 +186,10 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (IsWaitingForLastMove())
|
||||
if (IsWaitingForLastMove(priority))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if (bot->Unit::IsFalling()) {
|
||||
// bot->Say("I'm falling!, flag:" + std::to_string(bot->m_movementInfo.GetMovementFlags()), LANG_UNIVERSAL);
|
||||
// return false;
|
||||
// }
|
||||
// if (bot->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING)) {
|
||||
// bot->Say("I'm swimming", LANG_UNIVERSAL);
|
||||
// }
|
||||
// if (bot->Unit::IsFalling()) {
|
||||
// bot->Say("I'm falling", LANG_UNIVERSAL);
|
||||
// }
|
||||
bool generatePath = !bot->IsFlying() && !bot->isSwimming();
|
||||
bool disableMoveSplinePath = sPlayerbotAIConfig->disableMoveSplinePath >= 2 ||
|
||||
(sPlayerbotAIConfig->disableMoveSplinePath == 1 && bot->InBattleground());
|
||||
@@ -202,11 +205,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
{
|
||||
MotionMaster& mm = *vehicleBase->GetMotionMaster(); // need to move vehicle, not bot
|
||||
mm.Clear();
|
||||
mm.MovePoint(mapId, x, y, z, generatePath);
|
||||
float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN)) - sPlayerbotAIConfig->reactDelay;
|
||||
mm.MovePoint(0, x, y, z, generatePath);
|
||||
float delay = 1000.0f * (distance / vehicleBase->GetSpeed(MOVE_RUN));
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -225,11 +228,11 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
}
|
||||
MotionMaster& mm = *bot->GetMotionMaster();
|
||||
mm.Clear();
|
||||
mm.MovePoint(mapId, x, y, z, generatePath);
|
||||
float delay = 1000.0f * MoveDelay(distance) - sPlayerbotAIConfig->reactDelay;
|
||||
mm.MovePoint(0, x, y, z, generatePath);
|
||||
float delay = 1000.0f * MoveDelay(distance);
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -254,14 +257,13 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
botAI->InterruptSpell();
|
||||
}
|
||||
MotionMaster& mm = *bot->GetMotionMaster();
|
||||
|
||||
G3D::Vector3 endP = path.back();
|
||||
mm.Clear();
|
||||
mm.MoveSplinePath(&path);
|
||||
// mm.MoveSplinePath(&path);
|
||||
float delay = 1000.0f * MoveDelay(distance) - sPlayerbotAIConfig->reactDelay;
|
||||
mm.MovePoint(0, endP.x, endP.y, endP.z, generatePath);
|
||||
float delay = 1000.0f * MoveDelay(distance);
|
||||
delay = std::max(.0f, delay);
|
||||
delay = std::min((float)sPlayerbotAIConfig->maxWaitForMove, delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay);
|
||||
AI_VALUE(LastMovement&, "last movement").Set(mapId, x, y, z, bot->GetOrientation(), delay, priority);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -759,7 +761,7 @@ bool MovementAction::MoveTo(uint32 mapId, float x, float y, float z, bool idle,
|
||||
// return true;
|
||||
}
|
||||
|
||||
bool MovementAction::MoveTo(Unit* target, float distance)
|
||||
bool MovementAction::MoveTo(Unit* target, float distance, MovementPriority priority)
|
||||
{
|
||||
if (!IsMovingAllowed(target))
|
||||
return false;
|
||||
@@ -793,7 +795,7 @@ bool MovementAction::MoveTo(Unit* target, float distance)
|
||||
{
|
||||
dz = tz;
|
||||
}
|
||||
return MoveTo(target->GetMapId(), dx, dy, dz);
|
||||
return MoveTo(target->GetMapId(), dx, dy, dz, false, false, false, false, priority);
|
||||
}
|
||||
|
||||
bool MovementAction::ReachCombatTo(Unit* target, float distance)
|
||||
@@ -813,6 +815,7 @@ 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);
|
||||
@@ -845,7 +848,7 @@ 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);
|
||||
return MoveTo(target->GetMapId(), endPos.x, endPos.y, endPos.z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
float MovementAction::GetFollowAngle()
|
||||
@@ -909,10 +912,13 @@ bool MovementAction::IsDuplicateMove(uint32 mapId, float x, float y, float z)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovementAction::IsWaitingForLastMove()
|
||||
bool MovementAction::IsWaitingForLastMove(MovementPriority priority)
|
||||
{
|
||||
LastMovement& lastMove = *context->GetValue<LastMovement&>("last movement");
|
||||
|
||||
if (priority > lastMove.priority)
|
||||
return false;
|
||||
|
||||
// heuristic 5s
|
||||
if (lastMove.lastdelayTime + lastMove.msTime > getMSTime())
|
||||
return true;
|
||||
@@ -1216,7 +1222,7 @@ bool MovementAction::Follow(Unit* target, float distance, float angle)
|
||||
botAI->InterruptSpell();
|
||||
}
|
||||
|
||||
AI_VALUE(LastMovement&, "last movement").Set(target);
|
||||
// AI_VALUE(LastMovement&, "last movement").Set(target);
|
||||
ClearIdleState();
|
||||
|
||||
if (bot->GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE)
|
||||
@@ -1506,7 +1512,17 @@ bool MovementAction::MoveAway(Unit* target)
|
||||
float dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
float dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
float dz = bot->GetPositionZ();
|
||||
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true))
|
||||
bool exact = true;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), dx, dy, dz))
|
||||
{
|
||||
// disable prediction if position is invalid
|
||||
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
dz = bot->GetPositionZ();
|
||||
exact = false;
|
||||
}
|
||||
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1514,11 +1530,21 @@ bool MovementAction::MoveAway(Unit* target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
exact = true;
|
||||
angle = init_angle - delta;
|
||||
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
dz = bot->GetPositionZ();
|
||||
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true))
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), dx, dy, dz))
|
||||
{
|
||||
// disable prediction if position is invalid
|
||||
dx = bot->GetPositionX() + cos(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
dy = bot->GetPositionY() + sin(angle) * sPlayerbotAIConfig->fleeDistance;
|
||||
dz = bot->GetPositionZ();
|
||||
exact = false;
|
||||
}
|
||||
if (MoveTo(target->GetMapId(), dx, dy, dz, false, false, true, exact, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -1526,13 +1552,13 @@ bool MovementAction::MoveAway(Unit* target)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float distance)
|
||||
bool MovementAction::MoveInside(uint32 mapId, float x, float y, float z, float distance, MovementPriority priority)
|
||||
{
|
||||
if (bot->GetDistance2d(x, y) <= distance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return MoveNear(mapId, x, y, z, distance);
|
||||
return MoveNear(mapId, x, y, z, distance, priority);
|
||||
}
|
||||
|
||||
// float MovementAction::SearchBestGroundZForPath(float x, float y, float z, bool generatePath, float range, bool
|
||||
@@ -1678,13 +1704,7 @@ bool FleeWithPetAction::Execute(Event event)
|
||||
{
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
if (CreatureAI* creatureAI = ((Creature*)pet)->AI())
|
||||
{
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->GetCharmInfo()->SetIsCommandFollow(true);
|
||||
pet->GetCharmInfo()->IsReturning();
|
||||
pet->GetMotionMaster()->MoveFollow(bot, PET_FOLLOW_DIST, pet->GetFollowAngle());
|
||||
}
|
||||
botAI->PetFollow();
|
||||
}
|
||||
|
||||
return Flee(AI_VALUE(Unit*, "current target"));
|
||||
@@ -1929,7 +1949,7 @@ Position MovementAction::BestPositionForMeleeToFlee(Position pos, float radius)
|
||||
for (CheckAngle& checkAngle : possibleAngles)
|
||||
{
|
||||
float angle = checkAngle.angle;
|
||||
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||
if (!CheckLastFlee(angle, infoList))
|
||||
{
|
||||
continue;
|
||||
@@ -1985,7 +2005,7 @@ Position MovementAction::BestPositionForRangedToFlee(Position pos, float radius)
|
||||
for (CheckAngle& checkAngle : possibleAngles)
|
||||
{
|
||||
float angle = checkAngle.angle;
|
||||
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||
if (!CheckLastFlee(angle, infoList))
|
||||
{
|
||||
continue;
|
||||
@@ -2032,9 +2052,9 @@ bool MovementAction::FleePosition(Position pos, float radius)
|
||||
if (bestPos != Position())
|
||||
{
|
||||
if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false,
|
||||
false, true))
|
||||
false, true, false, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
auto& infoList = AI_VALUE_REF(std::list<FleeInfo>, "recently flee info");
|
||||
std::list<FleeInfo>& infoList = AI_VALUE(std::list<FleeInfo>&, "recently flee info");
|
||||
uint32 curTS = getMSTime();
|
||||
while (!infoList.empty())
|
||||
{
|
||||
@@ -2346,10 +2366,10 @@ bool MoveOutOfCollisionAction::isUseful()
|
||||
|
||||
bool MoveRandomAction::Execute(Event event)
|
||||
{
|
||||
float distance = sPlayerbotAIConfig->tooCloseDistance + sPlayerbotAIConfig->grindDistance * urand(3, 10) / 10.0f;
|
||||
float distance = sPlayerbotAIConfig->tooCloseDistance + urand(10, 30);
|
||||
|
||||
Map* map = bot->GetMap();
|
||||
for (int i = 0; i < 10; ++i)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
float x = bot->GetPositionX();
|
||||
float y = bot->GetPositionY();
|
||||
@@ -2362,11 +2382,7 @@ bool MoveRandomAction::Execute(Event event)
|
||||
float oz = z;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), x, y, z))
|
||||
{
|
||||
x = ox;
|
||||
y = oy;
|
||||
z = oz;
|
||||
}
|
||||
continue;
|
||||
if (map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
|
||||
continue;
|
||||
|
||||
@@ -2385,7 +2401,7 @@ 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()))
|
||||
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;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "Action.h"
|
||||
#include "LastMovementValue.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
|
||||
class Player;
|
||||
@@ -17,19 +18,20 @@ class Unit;
|
||||
class WorldObject;
|
||||
class Position;
|
||||
|
||||
|
||||
class MovementAction : public Action
|
||||
{
|
||||
public:
|
||||
MovementAction(PlayerbotAI* botAI, std::string const name);
|
||||
|
||||
protected:
|
||||
void JumpTo(uint32 mapId, float x, float y, float z);
|
||||
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance);
|
||||
bool JumpTo(uint32 mapId, float x, float y, float z, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveNear(uint32 mapId, float x, float y, float z, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveToLOS(WorldObject* target, bool ranged = false);
|
||||
bool MoveTo(uint32 mapId, float x, float y, float z, bool idle = false, bool react = false,
|
||||
bool normal_only = false, bool exact_waypoint = false);
|
||||
bool MoveTo(Unit* target, float distance = 0.0f);
|
||||
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance);
|
||||
bool normal_only = false, bool exact_waypoint = false, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveTo(Unit* target, float distance = 0.0f, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
bool MoveNear(WorldObject* target, float distance = sPlayerbotAIConfig->contactDistance, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
float GetFollowAngle();
|
||||
bool Follow(Unit* target, float distance = sPlayerbotAIConfig->followDistance);
|
||||
bool Follow(Unit* target, float distance, float angle);
|
||||
@@ -40,13 +42,13 @@ protected:
|
||||
bool IsMovingAllowed(Unit* target);
|
||||
bool IsMovingAllowed(uint32 mapId, float x, float y, float z);
|
||||
bool IsDuplicateMove(uint32 mapId, float x, float y, float z);
|
||||
bool IsWaitingForLastMove();
|
||||
bool IsWaitingForLastMove(MovementPriority priority);
|
||||
bool IsMovingAllowed();
|
||||
bool Flee(Unit* target);
|
||||
void ClearIdleState();
|
||||
void UpdateMovementState();
|
||||
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, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
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);
|
||||
@@ -94,7 +96,7 @@ class AvoidAoeAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
AvoidAoeAction(PlayerbotAI* botAI, int moveInterval = 1000)
|
||||
: MovementAction(botAI, "avoid aoe"), moveInterval(moveInterval)
|
||||
: MovementAction(botAI, "aaoe"), moveInterval(moveInterval)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -79,15 +79,13 @@ bool SummonAction::Execute(Event event)
|
||||
|
||||
if (Pet* pet = bot->GetPet())
|
||||
{
|
||||
pet->SetReactState(REACT_PASSIVE);
|
||||
pet->GetCharmInfo()->SetIsCommandFollow(true);
|
||||
pet->GetCharmInfo()->IsReturning();
|
||||
botAI->PetFollow();
|
||||
}
|
||||
|
||||
if (master->GetSession()->GetSecurity() >= SEC_PLAYER)
|
||||
{
|
||||
// botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
||||
SET_AI_VALUE(std::list<FleeInfo>, "recently flee info", {});
|
||||
AI_VALUE(std::list<FleeInfo>&, "recently flee info").clear();
|
||||
return Teleport(master, bot);
|
||||
}
|
||||
|
||||
@@ -215,10 +213,12 @@ bool SummonAction::Teleport(Player* summoner, Player* player)
|
||||
bool revive =
|
||||
sPlayerbotAIConfig->reviveBotWhenSummoned == 2 ||
|
||||
(sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !master->IsInCombat() && master->IsAlive());
|
||||
|
||||
if (bot->isDead() && revive)
|
||||
{
|
||||
bot->ResurrectPlayer(1.0f, false);
|
||||
botAI->TellMasterNoFacing("I live, again!");
|
||||
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
|
||||
}
|
||||
|
||||
player->GetMotionMaster()->Clear();
|
||||
|
||||
@@ -110,11 +110,11 @@ public:
|
||||
CastIcyTouchAction(PlayerbotAI* ai) : CastSpellAction(ai, "icy touch") {}
|
||||
};
|
||||
|
||||
class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnMeleeAttackerAction
|
||||
class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnAttackerAction
|
||||
{
|
||||
public:
|
||||
CastIcyTouchOnAttackerAction(PlayerbotAI* botAI)
|
||||
: CastDebuffSpellOnMeleeAttackerAction(botAI, "icy touch", true, .0f)
|
||||
: CastDebuffSpellOnAttackerAction(botAI, "icy touch", true, .0f)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -232,16 +232,17 @@ public:
|
||||
CastDeathCoilAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death coil") {}
|
||||
};
|
||||
|
||||
class CastBloodBoilAction : public CastSpellAction
|
||||
class CastBloodBoilAction : public CastMeleeSpellAction
|
||||
{
|
||||
public:
|
||||
CastBloodBoilAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blood boil") {}
|
||||
CastBloodBoilAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "blood boil") {}
|
||||
};
|
||||
|
||||
class CastDeathAndDecayAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastDeathAndDecayAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death and decay") {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
};
|
||||
|
||||
class CastHornOfWinterAction : public CastSpellAction
|
||||
|
||||
@@ -234,10 +234,10 @@ public:
|
||||
NextAction** getAlternatives() override;
|
||||
};
|
||||
|
||||
class CastBarskinAction : public CastBuffSpellAction
|
||||
class CastBarkskinAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastBarskinAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "barskin") {}
|
||||
CastBarkskinAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "barkskin") {}
|
||||
};
|
||||
|
||||
class CastInnervateAction : public CastSpellAction
|
||||
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
creators["healing touch on party"] = &DruidAiObjectContextInternal::healing_touch_on_party;
|
||||
creators["rebirth"] = &DruidAiObjectContextInternal::rebirth;
|
||||
creators["revive"] = &DruidAiObjectContextInternal::revive;
|
||||
creators["barskin"] = &DruidAiObjectContextInternal::barskin;
|
||||
creators["barkskin"] = &DruidAiObjectContextInternal::barkskin;
|
||||
creators["lacerate"] = &DruidAiObjectContextInternal::lacerate;
|
||||
creators["hurricane"] = &DruidAiObjectContextInternal::hurricane;
|
||||
creators["innervate"] = &DruidAiObjectContextInternal::innervate;
|
||||
@@ -281,7 +281,7 @@ private:
|
||||
static Action* healing_touch_on_party(PlayerbotAI* botAI) { return new CastHealingTouchOnPartyAction(botAI); }
|
||||
static Action* rebirth(PlayerbotAI* botAI) { return new CastRebirthAction(botAI); }
|
||||
static Action* revive(PlayerbotAI* botAI) { return new CastReviveAction(botAI); }
|
||||
static Action* barskin(PlayerbotAI* botAI) { return new CastBarskinAction(botAI); }
|
||||
static Action* barkskin(PlayerbotAI* botAI) { return new CastBarkskinAction(botAI); }
|
||||
static Action* lacerate(PlayerbotAI* botAI) { return new CastLacerateAction(botAI); }
|
||||
static Action* hurricane(PlayerbotAI* botAI) { return new CastHurricaneAction(botAI); }
|
||||
static Action* innervate(PlayerbotAI* botAI) { return new CastInnervateAction(botAI); }
|
||||
|
||||
@@ -43,10 +43,10 @@ public:
|
||||
CastSwipeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "swipe") {}
|
||||
};
|
||||
|
||||
class CastDemoralizingRoarAction : public CastDebuffSpellAction
|
||||
class CastDemoralizingRoarAction : public CastMeleeDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastDemoralizingRoarAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "demoralizing roar") {}
|
||||
CastDemoralizingRoarAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "demoralizing roar") {}
|
||||
};
|
||||
|
||||
class CastMangleBearAction : public CastMeleeSpellAction
|
||||
|
||||
@@ -27,7 +27,7 @@ private:
|
||||
{
|
||||
return new ActionNode("survival instincts",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("barskin"), nullptr),
|
||||
/*A*/ NextAction::array(0, new NextAction("barkskin"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,9 @@ void GenericDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("barkskin", ACTION_HIGH + 7), nullptr)));
|
||||
|
||||
// triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("regrowth",
|
||||
// ACTION_MEDIUM_HEAL + 2), nullptr))); triggers.push_back(new TriggerNode("party member low health",
|
||||
// NextAction::array(0, new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1), nullptr)));
|
||||
|
||||
@@ -70,7 +70,7 @@ AvoidAoeStrategy::AvoidAoeStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
NextAction** AvoidAoeStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("avoid aoe", ACTION_EMERGENCY), nullptr);
|
||||
return NextAction::array(0, new NextAction("aaoe", ACTION_EMERGENCY), nullptr);
|
||||
}
|
||||
|
||||
void AvoidAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
@@ -23,7 +23,7 @@ class AvoidAoeStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
explicit AvoidAoeStrategy(PlayerbotAI* ai);
|
||||
const std::string getName() override { return "avoid aoe"; }
|
||||
const std::string getName() override { return "aaoe"; }
|
||||
NextAction** getDefaultActions() override;
|
||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
@@ -33,7 +33,7 @@ class CombatFormationStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
CombatFormationStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||
const std::string getName() override { return "combat formation"; }
|
||||
const std::string getName() override { return "formation"; }
|
||||
NextAction** getDefaultActions() override;
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class PlayerbotAI;
|
||||
class HealerAutoSaveManaMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
HealerAutoSaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "auto save mana") {}
|
||||
HealerAutoSaveManaMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "smana") {}
|
||||
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
HealerAutoSaveManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) {}
|
||||
|
||||
void InitMultipliers(std::vector<Multiplier*>& multipliers) override;
|
||||
std::string const getName() override { return "auto save mana"; }
|
||||
std::string const getName() override { return "smana"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,14 +25,18 @@ private:
|
||||
void RacialsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("lifeblood", 71.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("war stomp", 71.0f),
|
||||
// nullptr)));
|
||||
/*triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("war stomp", 71.0f),
|
||||
* nullptr)));*/
|
||||
/*triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("arcane torrent",
|
||||
ACTION_EMERGENCY + 6), nullptr))); triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new
|
||||
NextAction("mana tap", ACTION_EMERGENCY + 6), nullptr)));*/
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("lifeblood", ACTION_NORMAL + 5), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("war stomp", ACTION_NORMAL + 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"low mana", NextAction::array(0, new NextAction("arcane torrent", ACTION_NORMAL + 5), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"generic boost", NextAction::array(0, new NextAction("blood fury", ACTION_NORMAL + 5),
|
||||
new NextAction("berserking", ACTION_NORMAL + 5),
|
||||
new NextAction("use trinket", ACTION_NORMAL + 4),
|
||||
nullptr)));
|
||||
|
||||
}
|
||||
|
||||
RacialsStrategy::RacialsStrategy(PlayerbotAI* botAI) : Strategy(botAI)
|
||||
|
||||
@@ -49,14 +49,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
//triggers.push_back(new TriggerNode("no non bot players around", NextAction::array(0, new NextAction("delay", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("levelup", NextAction::array(0,
|
||||
new NextAction("auto teleport for level", relevance + 3),
|
||||
new NextAction("auto talents", relevance + 2),
|
||||
new NextAction("auto learn spell", relevance + 1),
|
||||
new NextAction("auto upgrade equip", relevance),
|
||||
nullptr)));
|
||||
// triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("levelup", NextAction::array(0, new NextAction("auto maintenance on levelup", relevance + 3), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI",
|
||||
// relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("group list", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("see spell", NextAction::array(0, new NextAction("see spell", relevance), nullptr)));
|
||||
triggers.push_back(new TriggerNode("release spirit", NextAction::array(0, new NextAction("release", relevance), nullptr)));
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
class DpsHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
DpsHunterStrategyActionNodeFactory() { creators["aimed shot"] = &aimed_shot; }
|
||||
DpsHunterStrategyActionNodeFactory()
|
||||
{
|
||||
creators["aimed shot"] = &aimed_shot;
|
||||
creators["steady shot"] = &steady_shot;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* aimed_shot([[maybe_unused]] PlayerbotAI* botAI)
|
||||
@@ -20,6 +24,13 @@ private:
|
||||
/*A*/ NextAction::array(0, new NextAction("multi-shot"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
static ActionNode* steady_shot([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("steady shot",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("arcane shot"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
|
||||
@@ -32,7 +43,7 @@ NextAction** DpsHunterStrategy::getDefaultActions()
|
||||
return NextAction::array(
|
||||
0, new NextAction("kill shot", ACTION_DEFAULT + 0.6f), new NextAction("chimera shot", ACTION_DEFAULT + 0.5f),
|
||||
new NextAction("explosive shot", ACTION_DEFAULT + 0.4f), new NextAction("aimed shot", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("arcane shot", ACTION_DEFAULT + 0.2f), new NextAction("steady shot", ACTION_DEFAULT + 0.1f),
|
||||
/*new NextAction("arcane shot", ACTION_DEFAULT + 0.2f),*/ new NextAction("steady shot", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("auto shot", ACTION_DEFAULT), nullptr);
|
||||
// return NextAction::array(0, new NextAction("explosive shot", 11.0f), new NextAction("auto shot", 10.0f), new
|
||||
// NextAction("auto attack", 9.0f), nullptr);
|
||||
|
||||
@@ -97,6 +97,9 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(
|
||||
new TriggerNode("misdirection on main tank",
|
||||
NextAction::array(0, new NextAction("misdirection on main tank", ACTION_HIGH + 7), NULL)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("deterrence", ACTION_HIGH + 5), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("tranquilizing shot enrage",
|
||||
NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL)));
|
||||
triggers.push_back(new TriggerNode("tranquilizing shot magic",
|
||||
|
||||
@@ -32,8 +32,11 @@ public:
|
||||
BEGIN_RANGED_SPELL_ACTION(CastArcaneShotAction, "arcane shot")
|
||||
END_SPELL_ACTION()
|
||||
|
||||
BEGIN_RANGED_SPELL_ACTION(CastExplosiveShotAction, "explosive shot")
|
||||
END_SPELL_ACTION()
|
||||
class CastExplosiveShotAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastExplosiveShotAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
|
||||
};
|
||||
|
||||
BEGIN_RANGED_SPELL_ACTION(CastAimedShotAction, "aimed shot")
|
||||
END_SPELL_ACTION()
|
||||
@@ -160,6 +163,12 @@ public:
|
||||
CastRapidFireAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "rapid fire") {}
|
||||
};
|
||||
|
||||
class CastDeterrenceAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastDeterrenceAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "deterrence") {}
|
||||
};
|
||||
|
||||
class CastReadinessAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -149,6 +149,7 @@ public:
|
||||
creators["freezing trap"] = &HunterAiObjectContextInternal::freezing_trap;
|
||||
creators["rapid fire"] = &HunterAiObjectContextInternal::rapid_fire;
|
||||
creators["boost"] = &HunterAiObjectContextInternal::rapid_fire;
|
||||
creators["deterrence"] = &HunterAiObjectContextInternal::deterrence;
|
||||
creators["readiness"] = &HunterAiObjectContextInternal::readiness;
|
||||
creators["aspect of the hawk"] = &HunterAiObjectContextInternal::aspect_of_the_hawk;
|
||||
creators["aspect of the monkey"] = &HunterAiObjectContextInternal::aspect_of_the_monkey;
|
||||
@@ -200,6 +201,7 @@ private:
|
||||
static Action* black_arrow(PlayerbotAI* botAI) { return new CastBlackArrow(botAI); }
|
||||
static Action* freezing_trap(PlayerbotAI* botAI) { return new CastFreezingTrap(botAI); }
|
||||
static Action* rapid_fire(PlayerbotAI* botAI) { return new CastRapidFireAction(botAI); }
|
||||
static Action* deterrence(PlayerbotAI* botAI) { return new CastDeterrenceAction(botAI); }
|
||||
static Action* readiness(PlayerbotAI* botAI) { return new CastReadinessAction(botAI); }
|
||||
static Action* aspect_of_the_hawk(PlayerbotAI* botAI) { return new CastAspectOfTheHawkAction(botAI); }
|
||||
static Action* aspect_of_the_monkey(PlayerbotAI* botAI) { return new CastAspectOfTheMonkeyAction(botAI); }
|
||||
|
||||
@@ -85,7 +85,7 @@ NextAction** DpsPaladinStrategy::getDefaultActions()
|
||||
return NextAction::array(0, new NextAction("crusader strike", ACTION_DEFAULT + 0.4f),
|
||||
new NextAction("judgement of wisdom", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("divine storm", ACTION_DEFAULT + 0.2f),
|
||||
new NextAction("melee consecration", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("consecration", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("melee", ACTION_DEFAULT), NULL);
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ void DpsPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// triggers.push_back(new TriggerNode("repentance", NextAction::array(0, new NextAction("repentance",
|
||||
// ACTION_INTERRUPT + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"medium aoe", NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 3), nullptr)));
|
||||
"medium aoe", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 3), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("art of war", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode("target critical health",
|
||||
|
||||
@@ -17,8 +17,8 @@ void GenericPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
CombatStrategy::InitTriggers(triggers);
|
||||
|
||||
// triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("divine shield",
|
||||
// ACTION_CRITICAL_HEAL + 2), new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), nullptr)));
|
||||
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("divine shield",
|
||||
ACTION_HIGH + 5), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("hammer of justice interrupt",
|
||||
NextAction::array(0, new NextAction("hammer of justice", ACTION_INTERRUPT), nullptr)));
|
||||
|
||||
@@ -153,13 +153,6 @@ Unit* CastRighteousDefenseAction::GetTarget()
|
||||
return current_target->GetVictim();
|
||||
}
|
||||
|
||||
bool CastMeleeConsecrationAction::isUseful()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
// float dis = distance + CONTACT_DISTANCE;
|
||||
return target && bot->IsWithinMeleeRange(target); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float,
|
||||
// "distance", GetTargetName()), distance);
|
||||
}
|
||||
|
||||
bool CastDivineSacrificeAction::isUseful()
|
||||
{
|
||||
|
||||
@@ -44,13 +44,6 @@ SPELL_ACTION(CastHolyShockAction, "holy shock");
|
||||
// consecration
|
||||
MELEE_ACTION(CastConsecrationAction, "consecration");
|
||||
|
||||
class CastMeleeConsecrationAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastMeleeConsecrationAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "consecration") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
// repentance
|
||||
SNARE_ACTION(CastRepentanceSnareAction, "repentance");
|
||||
DEBUFF_ACTION(CastRepentanceAction, "repentance");
|
||||
@@ -67,10 +60,10 @@ BUFF_ACTION(CastDivineFavorAction, "divine favor");
|
||||
// fury
|
||||
BUFF_ACTION(CastRighteousFuryAction, "righteous fury");
|
||||
|
||||
class CastDivineStormAction : public CastBuffSpellAction
|
||||
class CastDivineStormAction : public CastMeleeSpellAction
|
||||
{
|
||||
public:
|
||||
CastDivineStormAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "divine storm") {}
|
||||
CastDivineStormAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "divine storm") {}
|
||||
};
|
||||
|
||||
class CastCrusaderStrikeAction : public CastMeleeSpellAction
|
||||
|
||||
@@ -232,7 +232,6 @@ public:
|
||||
creators["concentration aura"] = &PaladinAiObjectContextInternal::concentration_aura;
|
||||
creators["holy wrath"] = &PaladinAiObjectContextInternal::holy_wrath;
|
||||
creators["consecration"] = &PaladinAiObjectContextInternal::consecration;
|
||||
creators["melee consecration"] = &PaladinAiObjectContextInternal::melee_consecration;
|
||||
creators["cleanse disease"] = &PaladinAiObjectContextInternal::cleanse_disease;
|
||||
creators["cleanse poison"] = &PaladinAiObjectContextInternal::cleanse_poison;
|
||||
creators["cleanse magic"] = &PaladinAiObjectContextInternal::cleanse_magic;
|
||||
@@ -331,7 +330,6 @@ private:
|
||||
static Action* concentration_aura(PlayerbotAI* botAI) { return new CastConcentrationAuraAction(botAI); }
|
||||
static Action* holy_wrath(PlayerbotAI* botAI) { return new CastHolyWrathAction(botAI); }
|
||||
static Action* consecration(PlayerbotAI* botAI) { return new CastConsecrationAction(botAI); }
|
||||
static Action* melee_consecration(PlayerbotAI* botAI) { return new CastMeleeConsecrationAction(botAI); }
|
||||
static Action* cleanse_poison(PlayerbotAI* botAI) { return new CastCleansePoisonAction(botAI); }
|
||||
static Action* cleanse_disease(PlayerbotAI* botAI) { return new CastCleanseDiseaseAction(botAI); }
|
||||
static Action* cleanse_magic(PlayerbotAI* botAI) { return new CastCleanseMagicAction(botAI); }
|
||||
|
||||
@@ -82,7 +82,7 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode(
|
||||
"light aoe", NextAction::array(0, new NextAction("avenger's shield", ACTION_HIGH + 5), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 7),
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 7),
|
||||
new NextAction("avenger's shield", ACTION_HIGH + 6), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("avenger's shield", NextAction::array(0, new NextAction("avenger's shield",
|
||||
// ACTION_HIGH + 7), nullptr)));
|
||||
@@ -107,7 +107,7 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
new TriggerNode("medium group heal occasion",
|
||||
NextAction::array(0, new NextAction("divine sacrifice", ACTION_HIGH + 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enough mana", NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 4), nullptr)));
|
||||
"enough mana", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 4), nullptr)));
|
||||
triggers.push_back(new TriggerNode("not facing target",
|
||||
NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
|
||||
@@ -31,8 +31,9 @@ void GenericPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// NextAction("inner focus", 42.0f), nullptr))); triggers.push_back(new TriggerNode("medium mana",
|
||||
// NextAction::array(0, new NextAction("symbol of hope", ACTION_EMERGENCY), nullptr))); triggers.push_back(new
|
||||
// TriggerNode("low mana", NextAction::array(0, new NextAction("consume magic", 10.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("desperate prayer",
|
||||
// ACTION_EMERGENCY), nullptr))); triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new
|
||||
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("desperate prayer",
|
||||
ACTION_HIGH + 5), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new
|
||||
// NextAction("elune's grace", ACTION_EMERGENCY), nullptr))); triggers.push_back(new TriggerNode("chastise",
|
||||
// NextAction::array(0, new NextAction("chastise", ACTION_INTERRUPT), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
|
||||
@@ -73,7 +73,9 @@ void HolyHealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"party member critical health",
|
||||
NextAction::array(0, new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
|
||||
NextAction::array(0,
|
||||
new NextAction("guardian spirit on party", ACTION_CRITICAL_HEAL + 6),
|
||||
new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
|
||||
new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 3),
|
||||
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 2), NULL)));
|
||||
|
||||
|
||||
@@ -173,4 +173,11 @@ public:
|
||||
CastMindSearAction(PlayerbotAI* ai) : CastSpellAction(ai, "mind sear") {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
};
|
||||
|
||||
class CastGuardianSpiritOnPartyAction : public HealPartyMemberAction
|
||||
{
|
||||
public:
|
||||
CastGuardianSpiritOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "guardian spirit", 40.0f, HealingManaEfficiency::MEDIUM) {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -234,6 +234,7 @@ public:
|
||||
creators["hymn of hope"] = &PriestAiObjectContextInternal::hymn_of_hope;
|
||||
creators["divine hymn"] = &PriestAiObjectContextInternal::divine_hymn;
|
||||
creators["mind sear"] = &PriestAiObjectContextInternal::mind_sear;
|
||||
creators["guardian spirit on party"] = &PriestAiObjectContextInternal::guardian_spirit_on_party;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -339,6 +340,7 @@ private:
|
||||
static Action* hymn_of_hope(PlayerbotAI* ai) { return new CastHymnOfHopeAction(ai); }
|
||||
static Action* divine_hymn(PlayerbotAI* ai) { return new CastDivineHymnAction(ai); }
|
||||
static Action* mind_sear(PlayerbotAI* ai) { return new CastMindSearAction(ai); }
|
||||
static Action* guardian_spirit_on_party(PlayerbotAI* ai) { return new CastGuardianSpiritOnPartyAction(ai); }
|
||||
};
|
||||
|
||||
PriestAiObjectContext::PriestAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)
|
||||
|
||||
@@ -23,7 +23,7 @@ CURE_TRIGGER(CureDiseaseTrigger, "cure disease", DISPEL_DISEASE);
|
||||
CURE_PARTY_TRIGGER(PartyMemberCureDiseaseTrigger, "cure disease", DISPEL_DISEASE);
|
||||
BUFF_TRIGGER_A(InnerFireTrigger, "inner fire");
|
||||
BUFF_TRIGGER_A(ShadowformTrigger, "shadowform");
|
||||
BUFF_TRIGGER(PowerInfusionTrigger, "power infusion");
|
||||
BOOST_TRIGGER(PowerInfusionTrigger, "power infusion");
|
||||
BUFF_TRIGGER(InnerFocusTrigger, "inner focus");
|
||||
BUFF_TRIGGER(ShadowProtectionTrigger, "shadow protection");
|
||||
BUFF_PARTY_TRIGGER(ShadowProtectionOnPartyTrigger, "shadow protection");
|
||||
|
||||
@@ -29,8 +29,10 @@ void ShadowPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// ACTION_MOVE + 9), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("shadowform", NextAction::array(0, new NextAction("shadowform", ACTION_HIGH), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("dispersion", ACTION_EMERGENCY
|
||||
// + 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("dispersion", ACTION_HIGH
|
||||
+ 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("dispersion", ACTION_HIGH
|
||||
+ 5), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("vampiric embrace", NextAction::array(0, new NextAction("vampiric embrace", 16.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
#include "RaidNaxxActions.h"
|
||||
|
||||
#include "LastMovementValue.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
@@ -23,7 +24,7 @@ bool GrobbulusGoBehindAction::Execute(Event event)
|
||||
float z = boss->GetPositionZ();
|
||||
float rx = x + cos(orientation) * distance;
|
||||
float ry = y + sin(orientation) * distance;
|
||||
return MoveTo(bot->GetMapId(), rx, ry, z);
|
||||
return MoveTo(bot->GetMapId(), rx, ry, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
uint32 RotateAroundTheCenterPointAction::FindNearestWaypoint()
|
||||
@@ -91,7 +92,7 @@ bool HeiganDanceMeleeAction::Execute(Event event)
|
||||
}
|
||||
assert(curr_safe >= 0 && curr_safe <= 3);
|
||||
return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(),
|
||||
botAI->IsMainTank(bot) ? 0 : 0);
|
||||
botAI->IsMainTank(bot) ? 0 : 0, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
bool HeiganDanceRangedAction::Execute(Event event)
|
||||
@@ -99,10 +100,10 @@ bool HeiganDanceRangedAction::Execute(Event event)
|
||||
CalculateSafe();
|
||||
if (prev_phase != 1)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), platform.first, platform.second, 276.54f);
|
||||
return MoveTo(bot->GetMapId(), platform.first, platform.second, 276.54f, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
botAI->InterruptSpell();
|
||||
return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), 0);
|
||||
return MoveInside(bot->GetMapId(), waypoints[curr_safe].first, waypoints[curr_safe].second, bot->GetPositionZ(), 0, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
bool ThaddiusAttackNearestPetAction::isUseful()
|
||||
@@ -128,7 +129,7 @@ bool ThaddiusAttackNearestPetAction::Execute(Event event)
|
||||
Unit* target = helper.GetNearestPet();
|
||||
if (!bot->IsWithinLOSInMap(target))
|
||||
{
|
||||
return MoveTo(target);
|
||||
return MoveTo(target, 0, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
if (AI_VALUE(Unit*, "current target") != target)
|
||||
{
|
||||
@@ -137,12 +138,12 @@ bool ThaddiusAttackNearestPetAction::Execute(Event event)
|
||||
if (botAI->IsTank(bot) && AI_VALUE2(bool, "has aggro", "current target"))
|
||||
{
|
||||
std::pair<float, float> posForTank = helper.PetPhaseGetPosForTank();
|
||||
return MoveTo(533, posForTank.first, posForTank.second, helper.tankPosZ);
|
||||
return MoveTo(533, posForTank.first, posForTank.second, helper.tankPosZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
if (botAI->IsRanged(bot))
|
||||
{
|
||||
std::pair<float, float> posForRanged = helper.PetPhaseGetPosForRanged();
|
||||
return MoveTo(533, posForRanged.first, posForRanged.second, helper.tankPosZ);
|
||||
return MoveTo(533, posForRanged.first, posForRanged.second, helper.tankPosZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -170,22 +171,28 @@ bool ThaddiusMoveToPlatformAction::Execute(Event event)
|
||||
{
|
||||
if (is_left)
|
||||
{
|
||||
if (!MoveTo(bot->GetMapId(), position[0].first, position[0].second, high_z))
|
||||
if (!MoveTo(bot->GetMapId(), position[0].first, position[0].second, high_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
bot->TeleportTo(bot->GetMapId(), position[2].first, position[2].second, low_z, bot->GetOrientation());
|
||||
float distance = bot->GetExactDist2d(position[0].first, position[0].second);
|
||||
if (distance < sPlayerbotAIConfig->contactDistance)
|
||||
JumpTo(bot->GetMapId(), position[2].first, position[2].second, low_z, MovementPriority::MOVEMENT_COMBAT);
|
||||
// bot->TeleportTo(bot->GetMapId(), position[2].first, position[2].second, low_z, bot->GetOrientation());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!MoveTo(bot->GetMapId(), position[1].first, position[1].second, high_z))
|
||||
if (!MoveTo(bot->GetMapId(), position[1].first, position[1].second, high_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
bot->TeleportTo(bot->GetMapId(), position[3].first, position[3].second, low_z, bot->GetOrientation());
|
||||
float distance = bot->GetExactDist2d(position[1].first, position[1].second);
|
||||
if (distance < sPlayerbotAIConfig->contactDistance)
|
||||
JumpTo(bot->GetMapId(), position[3].first, position[3].second, low_z, MovementPriority::MOVEMENT_COMBAT);
|
||||
// bot->TeleportTo(bot->GetMapId(), position[3].first, position[3].second, low_z, bot->GetOrientation());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), position[4].first, position[4].second, low_z);
|
||||
return MoveTo(bot->GetMapId(), position[4].first, position[4].second, low_z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -225,7 +232,7 @@ bool ThaddiusMovePolarityAction::Execute(Event event)
|
||||
idx = 2;
|
||||
}
|
||||
idx = idx * 2 + botAI->IsRanged(bot);
|
||||
return MoveTo(bot->GetMapId(), position[idx].first, position[idx].second, bot->GetPositionZ());
|
||||
return MoveTo(bot->GetMapId(), position[idx].first, position[idx].second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
bool RazuviousUseObedienceCrystalAction::Execute(Event event)
|
||||
@@ -322,7 +329,7 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event event)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (MoveTo(unit))
|
||||
if (MoveTo(unit, 0.0f, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -352,7 +359,7 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event event)
|
||||
{
|
||||
if (bot->GetDistance2d(target) > sPlayerbotAIConfig->spellDistance)
|
||||
{
|
||||
return MoveNear(target, sPlayerbotAIConfig->spellDistance);
|
||||
return MoveNear(target, sPlayerbotAIConfig->spellDistance, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -396,7 +403,7 @@ bool HorsemanAttractAlternativelyAction::Execute(Event event)
|
||||
}
|
||||
helper.CalculatePosToGo(bot);
|
||||
auto [posX, posY] = helper.CurrentAttractPos();
|
||||
if (MoveTo(bot->GetMapId(), posX, posY, helper.posZ))
|
||||
if (MoveTo(bot->GetMapId(), posX, posY, helper.posZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -444,7 +451,7 @@ bool HorsemanAttactInOrderAction::Execute(Event event)
|
||||
}
|
||||
if (!bot->IsWithinLOSInMap(target))
|
||||
{
|
||||
return MoveNear(target, 22.0f);
|
||||
return MoveNear(target, 22.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return Attack(target);
|
||||
}
|
||||
@@ -461,7 +468,7 @@ bool SapphironGroundPositionAction::Execute(Event event)
|
||||
{
|
||||
if (AI_VALUE2(bool, "has aggro", "current target"))
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, helper.mainTankPos.first, helper.mainTankPos.second, helper.GENERIC_HEIGHT);
|
||||
return MoveTo(NAXX_MAP_ID, helper.mainTankPos.first, helper.mainTankPos.second, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -485,14 +492,14 @@ bool SapphironGroundPositionAction::Execute(Event event)
|
||||
distance = 5.0f;
|
||||
}
|
||||
return MoveTo(NAXX_MAP_ID, helper.center.first + cos(angle) * distance,
|
||||
helper.center.second + sin(angle) * distance, helper.GENERIC_HEIGHT);
|
||||
helper.center.second + sin(angle) * distance, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<float> dest;
|
||||
if (helper.FindPosToAvoidChill(dest))
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2]);
|
||||
return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2], false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -513,7 +520,7 @@ bool SapphironFlightPositionAction::Execute(Event event)
|
||||
std::vector<float> dest;
|
||||
if (helper.FindPosToAvoidChill(dest))
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2]);
|
||||
return MoveTo(NAXX_MAP_ID, dest[0], dest[1], dest[2], false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -548,7 +555,7 @@ bool SapphironFlightPositionAction::MoveToNearestIcebolt()
|
||||
{
|
||||
float angle = boss->GetAngle(playerWithIcebolt);
|
||||
return MoveTo(NAXX_MAP_ID, playerWithIcebolt->GetPositionX() + cos(angle) * 3.0f,
|
||||
playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, helper.GENERIC_HEIGHT);
|
||||
playerWithIcebolt->GetPositionY() + sin(angle) * 3.0f, helper.GENERIC_HEIGHT, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -679,7 +686,7 @@ bool KelthuzadPositionAction::Execute(Event event)
|
||||
{
|
||||
if (AI_VALUE(Unit*, "current target") == nullptr)
|
||||
{
|
||||
return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f);
|
||||
return MoveInside(NAXX_MAP_ID, helper.center.first, helper.center.second, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
else if (helper.IsPhaseTwo())
|
||||
@@ -692,7 +699,7 @@ bool KelthuzadPositionAction::Execute(Event event)
|
||||
{
|
||||
if (AI_VALUE2(bool, "has aggro", "current target"))
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, helper.tank_pos.first, helper.tank_pos.second, bot->GetPositionZ());
|
||||
return MoveTo(NAXX_MAP_ID, helper.tank_pos.first, helper.tank_pos.second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -715,7 +722,7 @@ bool KelthuzadPositionAction::Execute(Event event)
|
||||
float dx, dy;
|
||||
dx = helper.center.first + cos(angle) * distance;
|
||||
dy = helper.center.second + sin(angle) * distance;
|
||||
return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ());
|
||||
return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else if (botAI->IsTank(bot))
|
||||
{
|
||||
@@ -725,7 +732,7 @@ bool KelthuzadPositionAction::Execute(Event event)
|
||||
botAI->IsAssistTank(cur_tar->GetVictim()->ToPlayer()))
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, helper.assist_tank_pos.first, helper.assist_tank_pos.second,
|
||||
bot->GetPositionZ());
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -747,7 +754,7 @@ bool KelthuzadPositionAction::Execute(Event event)
|
||||
}
|
||||
dx = shadow_fissure->GetPositionX() + cos(angle) * 10.0f;
|
||||
dy = shadow_fissure->GetPositionY() + sin(angle) * 10.0f;
|
||||
return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ());
|
||||
return MoveTo(NAXX_MAP_ID, dx, dy, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -846,11 +853,11 @@ bool AnubrekhanPositionAction::Execute(Event event)
|
||||
next_point = nearest;
|
||||
}
|
||||
return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second,
|
||||
bot->GetPositionZ());
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f);
|
||||
return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -964,12 +971,12 @@ bool GluthPositionAction::Execute(Event event)
|
||||
if (raid25)
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, helper.mainTankPos25.first, helper.mainTankPos25.second,
|
||||
bot->GetPositionZ());
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveTo(NAXX_MAP_ID, helper.mainTankPos10.first, helper.mainTankPos10.second,
|
||||
bot->GetPositionZ());
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -978,7 +985,7 @@ bool GluthPositionAction::Execute(Event event)
|
||||
if (helper.BeforeDecimate())
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), helper.beforeDecimatePos.first, helper.beforeDecimatePos.second,
|
||||
bot->GetPositionZ());
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -987,7 +994,7 @@ bool GluthPositionAction::Execute(Event event)
|
||||
uint32 nearest = FindNearestWaypoint();
|
||||
uint32 next_point = (nearest + 1) % intervals;
|
||||
return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second,
|
||||
bot->GetPositionZ());
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -998,19 +1005,19 @@ bool GluthPositionAction::Execute(Event event)
|
||||
if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 0)
|
||||
{
|
||||
return MoveInside(NAXX_MAP_ID, helper.leftSlowDownPos.first, helper.leftSlowDownPos.second,
|
||||
bot->GetPositionZ(), 0.0f);
|
||||
bot->GetPositionZ(), 0.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
if (botAI->GetClassIndex(bot, CLASS_HUNTER) == 1)
|
||||
{
|
||||
return MoveInside(NAXX_MAP_ID, helper.rightSlowDownPos.first, helper.rightSlowDownPos.second,
|
||||
bot->GetPositionZ(), 0.0f);
|
||||
bot->GetPositionZ(), 0.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
return MoveInside(NAXX_MAP_ID, helper.rangedPos.first, helper.rangedPos.second, bot->GetPositionZ(), 3.0f);
|
||||
return MoveInside(NAXX_MAP_ID, helper.rangedPos.first, helper.rangedPos.second, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
else if (botAI->IsHeal(bot))
|
||||
{
|
||||
return MoveInside(NAXX_MAP_ID, helper.healPos.first, helper.healPos.second, bot->GetPositionZ(), 0.0f);
|
||||
return MoveInside(NAXX_MAP_ID, helper.healPos.first, helper.healPos.second, bot->GetPositionZ(), 0.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1051,12 +1058,12 @@ bool LoathebPositionAction::Execute(Event event)
|
||||
{
|
||||
if (AI_VALUE2(bool, "has aggro", "boss target"))
|
||||
{
|
||||
return MoveTo(533, helper.mainTankPos.first, helper.mainTankPos.second, bot->GetPositionZ());
|
||||
return MoveTo(533, helper.mainTankPos.first, helper.mainTankPos.second, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
}
|
||||
else if (botAI->IsRanged(bot))
|
||||
{
|
||||
return MoveInside(533, helper.rangePos.first, helper.rangePos.second, bot->GetPositionZ(), 1.0f);
|
||||
return MoveInside(533, helper.rangePos.first, helper.rangePos.second, bot->GetPositionZ(), 1.0f, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -66,8 +66,11 @@ void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
|
||||
new TriggerNode("medium threat", NextAction::array(0, new NextAction("vanish", ACTION_HIGH), NULL)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_EMERGENCY),
|
||||
new NextAction("feint", ACTION_EMERGENCY), NULL)));
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9),
|
||||
new NextAction("feint", ACTION_HIGH + 8), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), NULL)));
|
||||
|
||||
@@ -108,8 +108,11 @@ void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
new TriggerNode("medium threat", NextAction::array(0, new NextAction("vanish", ACTION_HIGH), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_EMERGENCY),
|
||||
new NextAction("feint", ACTION_EMERGENCY), nullptr)));
|
||||
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9),
|
||||
new NextAction("feint", ACTION_HIGH + 8), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), nullptr)));
|
||||
@@ -125,6 +128,9 @@ void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(
|
||||
new TriggerNode("light aoe", NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 3), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("blade flurry", NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 2), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"enemy out of melee",
|
||||
NextAction::array(0, new NextAction("stealth", ACTION_NORMAL + 9), new NextAction("sprint", ACTION_NORMAL + 8),
|
||||
|
||||
@@ -17,6 +17,12 @@ public:
|
||||
CastEvasionAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "evasion") {}
|
||||
};
|
||||
|
||||
class CastCloakOfShadowsAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastCloakOfShadowsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cloak of shadows") {}
|
||||
};
|
||||
|
||||
class CastHungerForBloodAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -76,12 +76,14 @@ public:
|
||||
creators["off hand weapon no enchant"] = &RogueTriggerFactoryInternal::off_hand_weapon_no_enchant;
|
||||
creators["tricks of the trade on main tank"] = &RogueTriggerFactoryInternal::tricks_of_the_trade_on_main_tank;
|
||||
creators["adrenaline rush"] = &RogueTriggerFactoryInternal::adrenaline_rush;
|
||||
creators["blade fury"] = &RogueTriggerFactoryInternal::blade_fury;
|
||||
creators["target with combo points almost dead"] =
|
||||
&RogueTriggerFactoryInternal::target_with_combo_points_almost_dead;
|
||||
}
|
||||
|
||||
private:
|
||||
static Trigger* adrenaline_rush(PlayerbotAI* botAI) { return new AdrenalineRushTrigger(botAI); }
|
||||
static Trigger* blade_fury(PlayerbotAI* botAI) { return new BladeFuryTrigger(botAI); }
|
||||
static Trigger* kick(PlayerbotAI* botAI) { return new KickInterruptSpellTrigger(botAI); }
|
||||
static Trigger* rupture(PlayerbotAI* botAI) { return new RuptureTrigger(botAI); }
|
||||
static Trigger* slice_and_dice(PlayerbotAI* botAI) { return new SliceAndDiceTrigger(botAI); }
|
||||
@@ -122,6 +124,7 @@ public:
|
||||
creators["eviscerate"] = &RogueAiObjectContextInternal::eviscerate;
|
||||
creators["vanish"] = &RogueAiObjectContextInternal::vanish;
|
||||
creators["evasion"] = &RogueAiObjectContextInternal::evasion;
|
||||
creators["cloak of shadows"] = &RogueAiObjectContextInternal::cloak_of_shadows;
|
||||
creators["kick"] = &RogueAiObjectContextInternal::kick;
|
||||
creators["feint"] = &RogueAiObjectContextInternal::feint;
|
||||
creators["backstab"] = &RogueAiObjectContextInternal::backstab;
|
||||
@@ -161,6 +164,7 @@ private:
|
||||
static Action* eviscerate(PlayerbotAI* botAI) { return new CastEviscerateAction(botAI); }
|
||||
static Action* vanish(PlayerbotAI* botAI) { return new CastVanishAction(botAI); }
|
||||
static Action* evasion(PlayerbotAI* botAI) { return new CastEvasionAction(botAI); }
|
||||
static Action* cloak_of_shadows(PlayerbotAI* botAI) { return new CastCloakOfShadowsAction(botAI); }
|
||||
static Action* kick(PlayerbotAI* botAI) { return new CastKickAction(botAI); }
|
||||
static Action* feint(PlayerbotAI* botAI) { return new CastFeintAction(botAI); }
|
||||
static Action* backstab(PlayerbotAI* botAI) { return new CastBackstabAction(botAI); }
|
||||
|
||||
@@ -18,34 +18,34 @@ public:
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastSinisterStrikeAction : public CastComboAction
|
||||
class CastSinisterStrikeAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastSinisterStrikeAction(PlayerbotAI* botAI) : CastComboAction(botAI, "sinister strike") {}
|
||||
CastSinisterStrikeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "sinister strike") {}
|
||||
};
|
||||
|
||||
class CastMutilateAction : public CastComboAction
|
||||
class CastMutilateAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastMutilateAction(PlayerbotAI* botAI) : CastComboAction(botAI, "mutilate") {}
|
||||
CastMutilateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "mutilate") {}
|
||||
};
|
||||
|
||||
class CastRiposteAction : public CastComboAction
|
||||
class CastRiposteAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastRiposteAction(PlayerbotAI* botAI) : CastComboAction(botAI, "riposte") {}
|
||||
CastRiposteAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "riposte") {}
|
||||
};
|
||||
|
||||
class CastGougeAction : public CastComboAction
|
||||
class CastGougeAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastGougeAction(PlayerbotAI* botAI) : CastComboAction(botAI, "gouge") {}
|
||||
CastGougeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "gouge") {}
|
||||
};
|
||||
|
||||
class CastBackstabAction : public CastComboAction
|
||||
class CastBackstabAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastBackstabAction(PlayerbotAI* botAI) : CastComboAction(botAI, "backstab") {}
|
||||
CastBackstabAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "backstab") {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,13 @@ public:
|
||||
// bool isPossible();
|
||||
};
|
||||
|
||||
class BladeFuryTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
BladeFuryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "blade fury") {}
|
||||
};
|
||||
|
||||
|
||||
class RuptureTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "ShamanActions.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Totem.h"
|
||||
|
||||
bool CastTotemAction::isUseful()
|
||||
{
|
||||
@@ -41,7 +42,24 @@ bool CastSearingTotemAction::isUseful()
|
||||
return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", "flametongue totem");
|
||||
}
|
||||
|
||||
bool CastMagmaTotemAction::isUseful() { return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", name); }
|
||||
bool CastMagmaTotemAction::isUseful() {
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (!target || !bot->IsWithinMeleeRange(target))
|
||||
return false;
|
||||
|
||||
return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", name);
|
||||
}
|
||||
|
||||
bool CastFireNovaAction::isUseful() {
|
||||
Creature* fireTotem = bot->GetMap()->GetCreature(bot->m_SummonSlot[1]);
|
||||
if (!fireTotem)
|
||||
return false;
|
||||
|
||||
if (bot->GetDistance(fireTotem) > 8.0f)
|
||||
return false;
|
||||
|
||||
return CastMeleeSpellAction::isUseful();
|
||||
}
|
||||
|
||||
bool CastCleansingTotemAction::isUseful()
|
||||
{
|
||||
|
||||
@@ -231,10 +231,11 @@ public:
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastFireNovaAction : public CastSpellAction
|
||||
class CastFireNovaAction : public CastMeleeSpellAction
|
||||
{
|
||||
public:
|
||||
CastFireNovaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "fire nova") {}
|
||||
CastFireNovaAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "fire nova") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastWindShearAction : public CastSpellAction
|
||||
|
||||
@@ -308,7 +308,23 @@ std::string const TwoTriggers::getName()
|
||||
return name;
|
||||
}
|
||||
|
||||
bool BoostTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE(uint8, "balance") <= balance; }
|
||||
bool BoostTrigger::IsActive()
|
||||
{
|
||||
if (!BuffTrigger::IsActive())
|
||||
return false;
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (target && target->ToPlayer())
|
||||
return true;
|
||||
return AI_VALUE(uint8, "balance") <= balance;
|
||||
}
|
||||
|
||||
bool GenericBoostTrigger::IsActive()
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
if (target && target->ToPlayer())
|
||||
return true;
|
||||
return AI_VALUE(uint8, "balance") <= balance;
|
||||
}
|
||||
|
||||
bool ItemCountTrigger::IsActive() { return AI_VALUE2(uint32, "item count", item) < count; }
|
||||
|
||||
|
||||
@@ -409,6 +409,21 @@ protected:
|
||||
float balance;
|
||||
};
|
||||
|
||||
class GenericBoostTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
GenericBoostTrigger(PlayerbotAI* botAI, float balance = 50.f)
|
||||
: Trigger(botAI, "generic boost", 1), balance(balance)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsActive() override;
|
||||
|
||||
protected:
|
||||
float balance;
|
||||
};
|
||||
|
||||
|
||||
class RandomTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -48,7 +48,7 @@ class LowHealthTrigger : public HealthInRangeTrigger
|
||||
{
|
||||
public:
|
||||
LowHealthTrigger(PlayerbotAI* botAI, std::string const name = "low health",
|
||||
float value = sPlayerbotAIConfig->lowHealth, float minValue = sPlayerbotAIConfig->criticalHealth)
|
||||
float value = sPlayerbotAIConfig->lowHealth, float minValue = 0)
|
||||
: HealthInRangeTrigger(botAI, name, value, minValue)
|
||||
{
|
||||
}
|
||||
@@ -69,7 +69,7 @@ class MediumHealthTrigger : public LowHealthTrigger
|
||||
{
|
||||
public:
|
||||
MediumHealthTrigger(PlayerbotAI* botAI)
|
||||
: LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig->mediumHealth, sPlayerbotAIConfig->lowHealth)
|
||||
: LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig->mediumHealth, 0)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -89,7 +89,7 @@ class PartyMemberLowHealthTrigger : public HealthInRangeTrigger
|
||||
public:
|
||||
PartyMemberLowHealthTrigger(PlayerbotAI* botAI, std::string const name = "party member low health",
|
||||
float value = sPlayerbotAIConfig->lowHealth,
|
||||
float minValue = sPlayerbotAIConfig->criticalHealth)
|
||||
float minValue = 0)
|
||||
: HealthInRangeTrigger(botAI, name, value, minValue)
|
||||
{
|
||||
}
|
||||
@@ -111,7 +111,7 @@ class PartyMemberMediumHealthTrigger : public PartyMemberLowHealthTrigger
|
||||
public:
|
||||
PartyMemberMediumHealthTrigger(PlayerbotAI* botAI)
|
||||
: PartyMemberLowHealthTrigger(botAI, "party member medium health", sPlayerbotAIConfig->mediumHealth,
|
||||
sPlayerbotAIConfig->lowHealth)
|
||||
0)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -121,7 +121,7 @@ class PartyMemberAlmostFullHealthTrigger : public PartyMemberLowHealthTrigger
|
||||
public:
|
||||
PartyMemberAlmostFullHealthTrigger(PlayerbotAI* botAI)
|
||||
: PartyMemberLowHealthTrigger(botAI, "party member almost full health", sPlayerbotAIConfig->almostFullHealth,
|
||||
sPlayerbotAIConfig->mediumHealth)
|
||||
0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
creators["party member medium health"] = &TriggerContext::PartyMemberMediumHealth;
|
||||
creators["party member almost full health"] = &TriggerContext::PartyMemberAlmostFullHealth;
|
||||
|
||||
creators["generic boost"] = &TriggerContext::generic_boost;
|
||||
|
||||
creators["protect party member"] = &TriggerContext::protect_party_member;
|
||||
|
||||
creators["light rage available"] = &TriggerContext::LightRageAvailable;
|
||||
@@ -318,6 +320,7 @@ private:
|
||||
{
|
||||
return new PartyMemberAlmostFullHealthTrigger(botAI);
|
||||
}
|
||||
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
|
||||
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
|
||||
{
|
||||
return new PartyMemberCriticalHealthTrigger(botAI);
|
||||
|
||||
@@ -66,8 +66,13 @@ uint8 BalancePercentValue::Calculate()
|
||||
|
||||
playerLevel += player->GetLevel();
|
||||
}
|
||||
uint32 memberCount = group->GetMembersCount();
|
||||
playerLevel /= memberCount;
|
||||
if (memberCount <= 10)
|
||||
playerLevel *= memberCount;
|
||||
else
|
||||
playerLevel *= 10;
|
||||
}
|
||||
|
||||
GuidVector v = context->GetValue<GuidVector>("attackers")->Get();
|
||||
for (ObjectGuid const guid : v)
|
||||
{
|
||||
@@ -89,7 +94,7 @@ uint8 BalancePercentValue::Calculate()
|
||||
level *= 3;
|
||||
break;
|
||||
case CREATURE_ELITE_WORLDBOSS:
|
||||
level *= 50;
|
||||
level *= 30;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Unit* AttackerWithoutAuraTargetValue::Calculate()
|
||||
if (!unit || !unit->IsAlive())
|
||||
continue;
|
||||
|
||||
if (bot->GetDistance(unit) > botAI->GetRange(range))
|
||||
if (!bot->IsWithinCombatRange(unit, botAI->GetRange(range)))
|
||||
continue;
|
||||
|
||||
if (unit->GetHealth() < max_health)
|
||||
|
||||
@@ -24,6 +24,7 @@ LastMovement::LastMovement(LastMovement& other)
|
||||
lastMoveShort = other.lastMoveShort;
|
||||
nextTeleport = other.nextTeleport;
|
||||
lastPath = other.lastPath;
|
||||
priority = other.priority;
|
||||
}
|
||||
|
||||
void LastMovement::clear()
|
||||
@@ -41,6 +42,7 @@ void LastMovement::clear()
|
||||
nextTeleport = 0;
|
||||
msTime = 0;
|
||||
lastdelayTime = 0;
|
||||
priority = MovementPriority::MOVEMENT_NORMAL;
|
||||
}
|
||||
|
||||
void LastMovement::Set(Unit* follow)
|
||||
@@ -51,7 +53,7 @@ void LastMovement::Set(Unit* follow)
|
||||
lastFollow = follow;
|
||||
}
|
||||
|
||||
void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime)
|
||||
void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float delayTime, MovementPriority pri)
|
||||
{
|
||||
lastMoveToMapId = mapId;
|
||||
lastMoveToX = x;
|
||||
@@ -62,6 +64,7 @@ void LastMovement::Set(uint32 mapId, float x, float y, float z, float ori, float
|
||||
lastMoveShort = WorldPosition(mapId, x, y, z, ori);
|
||||
msTime = getMSTime();
|
||||
lastdelayTime = delayTime;
|
||||
priority = pri;
|
||||
}
|
||||
|
||||
void LastMovement::setShort(WorldPosition point)
|
||||
|
||||
@@ -13,6 +13,15 @@
|
||||
class PlayerbotAI;
|
||||
class Unit;
|
||||
|
||||
// High priority movement can override the previous low priority one
|
||||
enum class MovementPriority
|
||||
{
|
||||
MOVEMENT_IDLE,
|
||||
MOVEMENT_NORMAL,
|
||||
MOVEMENT_COMBAT,
|
||||
MOVEMENT_FORCED
|
||||
};
|
||||
|
||||
class LastMovement
|
||||
{
|
||||
public:
|
||||
@@ -28,14 +37,14 @@ public:
|
||||
lastMoveShort = other.lastMoveShort;
|
||||
lastPath = other.lastPath;
|
||||
nextTeleport = other.nextTeleport;
|
||||
|
||||
priority = other.priority;
|
||||
return *this;
|
||||
};
|
||||
|
||||
void clear();
|
||||
|
||||
void Set(Unit* follow);
|
||||
void Set(uint32 mapId, float x, float y, float z, float ori, float delayTime);
|
||||
void Set(uint32 mapId, float x, float y, float z, float ori, float delayTime, MovementPriority priority = MovementPriority::MOVEMENT_NORMAL);
|
||||
|
||||
void setShort(WorldPosition point);
|
||||
void setPath(TravelPath path);
|
||||
@@ -53,6 +62,7 @@ public:
|
||||
float lastdelayTime;
|
||||
WorldPosition lastMoveShort;
|
||||
uint32 msTime;
|
||||
MovementPriority priority;
|
||||
TravelPath lastPath;
|
||||
time_t nextTeleport;
|
||||
std::future<TravelPath> future;
|
||||
|
||||
@@ -41,6 +41,8 @@ Unit* PartyMemberToHeal::Calculate()
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
if (player->IsGameMaster())
|
||||
continue;
|
||||
if (player && player->IsAlive())
|
||||
{
|
||||
uint8 health = player->GetHealthPct();
|
||||
|
||||
@@ -103,7 +103,8 @@ bool PartyMemberValue::Check(Unit* player)
|
||||
{
|
||||
// return player && player != bot && player->GetMapId() == bot->GetMapId() && bot->IsWithinDistInMap(player,
|
||||
// sPlayerbotAIConfig->sightDistance, false);
|
||||
return player && player->GetMapId() == bot->GetMapId() &&
|
||||
bool isGM = player->ToPlayer() && player->ToPlayer()->IsGameMaster();
|
||||
return player && player->GetMapId() == bot->GetMapId() && !isGM &&
|
||||
bot->GetDistance(player) < sPlayerbotAIConfig->spellDistance * 2 &&
|
||||
bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
|
||||
}
|
||||
|
||||
@@ -20,14 +20,21 @@ BUFF_ACTION(CastBerserkerStanceAction, "berserker stance");
|
||||
// shouts
|
||||
BUFF_ACTION(CastBattleShoutAction, "battle shout");
|
||||
MELEE_ACTION_U(CastBattleShoutTauntAction, "battle shout", CastSpellAction::isUseful()); // useful to rebuff
|
||||
DEBUFF_ACTION_R(CastDemoralizingShoutAction, "demoralizing shout", 8.0f); // low range debuff
|
||||
class CastDemoralizingShoutWithoutLifeTimeCheckAction : public CastDebuffSpellAction
|
||||
// DEBUFF_ACTION_R(CastDemoralizingShoutAction, "demoralizing shout", 8.0f); // low range debuff
|
||||
|
||||
class CastDemoralizingShoutAction : public CastMeleeDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastDemoralizingShoutAction(PlayerbotAI* botAI)
|
||||
: CastMeleeDebuffSpellAction(botAI, "demoralizing shout") {}
|
||||
};
|
||||
|
||||
class CastDemoralizingShoutWithoutLifeTimeCheckAction : public CastMeleeDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastDemoralizingShoutWithoutLifeTimeCheckAction(PlayerbotAI* botAI)
|
||||
: CastDebuffSpellAction(botAI, "demoralizing shout", false, 0.0f)
|
||||
: CastMeleeDebuffSpellAction(botAI, "demoralizing shout", false, 0.0f)
|
||||
{
|
||||
range = 8.0f;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -63,7 +70,7 @@ DEBUFF_ACTION(CastShatteringThrowAction, "shattering throw");
|
||||
MELEE_ACTION(CastMortalStrikeAction, "mortal strike");
|
||||
BUFF_ACTION(CastSweepingStrikesAction, "sweeping strikes");
|
||||
// arms talents 3.3.5
|
||||
BUFF_ACTION(CastBladestormAction, "bladestorm");
|
||||
MELEE_ACTION(CastBladestormAction, "bladestorm");
|
||||
|
||||
// fury
|
||||
MELEE_ACTION(CastCleaveAction, "cleave");
|
||||
|
||||
Reference in New Issue
Block a user