diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index 4711f923..b4d0d936 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -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 diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e9d6b734..6580b845 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -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 diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 8254362c..05f2daec 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -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; } diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 0948a5da..7a4a803f 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -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 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(); +} \ No newline at end of file diff --git a/src/PlayerbotAI.h b/src/PlayerbotAI.h index f0be101f..fb76b5cc 100644 --- a/src/PlayerbotAI.h +++ b/src/PlayerbotAI.h @@ -554,11 +554,14 @@ public: uint32 GetInventoryItemsCountWithId(uint32 itemId); bool HasItemInInventory(uint32 itemId); std::vector> GetCurrentQuestsRequiringItemId(uint32 itemId); + uint32 GetReactDelay(); std::vector GetAllCurrentQuests(); std::vector GetCurrentIncompleteQuests(); std::set GetAllCurrentQuestIds(); std::set GetCurrentIncompleteQuestIds(); + void PetFollow(); + private: static void _fillGearScoreData(Player* player, Item* item, std::vector* gearScore, uint32& twoHandScore, bool mixed = false); bool IsTellAllowed(PlayerbotSecurityLevel securityLevel = PLAYERBOT_SECURITY_ALLOW_ALL); diff --git a/src/PlayerbotAIBase.cpp b/src/PlayerbotAIBase.cpp index b26a3e64..37cc9ebd 100644 --- a/src/PlayerbotAIBase.cpp +++ b/src/PlayerbotAIBase.cpp @@ -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; } diff --git a/src/PlayerbotAIBase.h b/src/PlayerbotAIBase.h index a1322211..6c1772e2 100644 --- a/src/PlayerbotAIBase.h +++ b/src/PlayerbotAIBase.h @@ -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(); diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 3782735e..7803fafb 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -59,7 +59,8 @@ bool PlayerbotAIConfig::Initialize() maxMovementSearchTime = sConfigMgr->GetOption("AiPlayerbot.MaxMovementSearchTime", 3); expireActionTime = sConfigMgr->GetOption("AiPlayerbot.ExpireActionTime", 5000); dispelAuraDuration = sConfigMgr->GetOption("AiPlayerbot.DispelAuraDuration", 7000); - reactDelay = sConfigMgr->GetOption("AiPlayerbot.ReactDelay", 500); + reactDelay = sConfigMgr->GetOption("AiPlayerbot.ReactDelay", 100); + dynamicReactDelay = sConfigMgr->GetOption("AiPlayerbot.DynamicReactDelay", true); passiveDelay = sConfigMgr->GetOption("AiPlayerbot.PassiveDelay", 10000); repeatDelay = sConfigMgr->GetOption("AiPlayerbot.RepeatDelay", 2000); errorDelay = sConfigMgr->GetOption("AiPlayerbot.ErrorDelay", 5000); @@ -77,7 +78,7 @@ bool PlayerbotAIConfig::Initialize() fleeDistance = sConfigMgr->GetOption("AiPlayerbot.FleeDistance", 7.5f); aggroDistance = sConfigMgr->GetOption("AiPlayerbot.AggroDistance", 22.0f); tooCloseDistance = sConfigMgr->GetOption("AiPlayerbot.TooCloseDistance", 5.0f); - meleeDistance = sConfigMgr->GetOption("AiPlayerbot.MeleeDistance", 1.5f); + meleeDistance = sConfigMgr->GetOption("AiPlayerbot.MeleeDistance", 0.75f); followDistance = sConfigMgr->GetOption("AiPlayerbot.FollowDistance", 1.5f); whisperDistance = sConfigMgr->GetOption("AiPlayerbot.WhisperDistance", 6000.0f); contactDistance = sConfigMgr->GetOption("AiPlayerbot.ContactDistance", 0.5f); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 11d45965..e7fd94cd 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -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; diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index cc806663..564403d2 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -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> 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; } + diff --git a/src/factory/PlayerbotFactory.cpp b/src/factory/PlayerbotFactory.cpp index 78744c50..9f87bc74 100644 --- a/src/factory/PlayerbotFactory.cpp +++ b/src/factory/PlayerbotFactory.cpp @@ -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(); diff --git a/src/factory/StatsCollector.cpp b/src/factory/StatsCollector.cpp index 70965177..322e4742 100644 --- a/src/factory/StatsCollector.cpp +++ b/src/factory/StatsCollector.cpp @@ -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; diff --git a/src/factory/StatsWeightCalculator.cpp b/src/factory/StatsWeightCalculator.cpp index 19dd85a0..9ee2b487 100644 --- a/src/factory/StatsWeightCalculator.cpp +++ b/src/factory/StatsWeightCalculator.cpp @@ -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; + } } } diff --git a/src/strategy/Engine.cpp b/src/strategy/Engine.cpp index a4e3845d..d298aaf5 100644 --- a/src/strategy/Engine.cpp +++ b/src/strategy/Engine.cpp @@ -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 siblings = aiObjectContext->GetSiblingStrategy(name); for (std::set::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::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; } diff --git a/src/strategy/Engine.h b/src/strategy/Engine.h index bd51c16b..c3a5d743 100644 --- a/src/strategy/Engine.h +++ b/src/strategy/Engine.h @@ -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); diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index 9c694364..0a2501bb 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -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: diff --git a/src/strategy/Value.h b/src/strategy/Value.h index 2ea60de7..a4189f78 100644 --- a/src/strategy/Value.h +++ b/src/strategy/Value.h @@ -405,14 +405,15 @@ public: } }; -class RecentlyFleeInfo : public ManualSetValue> +class RecentlyFleeInfo : public ManualSetValue&> { public: - RecentlyFleeInfo(PlayerbotAI* botAI, std::list defaultValue = {}, - std::string const name = "recently flee info") - : ManualSetValue>(botAI, defaultValue, name) + RecentlyFleeInfo(PlayerbotAI* botAI, std::string const name = "recently flee info") + : ManualSetValue&>(botAI, data, name) { } +private: + std::list data = {}; }; #endif diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index 3f0cf4e1..be2fa613 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -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); } diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 1dc98984..d1dd232b 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -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("current target")->Get(); + + if (oldTarget == target && botAI->GetState() == BOT_STATE_COMBAT && bot->GetVictim() == target) + return false; + context->GetValue("old target")->Set(oldTarget); context->GetValue("current target")->Set(target); context->GetValue("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; diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp deleted file mode 100644 index fe72b8d6..00000000 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , 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(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; -} diff --git a/src/strategy/actions/AutoMaintenanceOnLevelupAction.cpp b/src/strategy/actions/AutoMaintenanceOnLevelupAction.cpp new file mode 100644 index 00000000..5e01d18a --- /dev/null +++ b/src/strategy/actions/AutoMaintenanceOnLevelupAction.cpp @@ -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(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; +} + diff --git a/src/strategy/actions/AutoLearnSpellAction.h b/src/strategy/actions/AutoMaintenanceOnLevelupAction.h similarity index 51% rename from src/strategy/actions/AutoLearnSpellAction.h rename to src/strategy/actions/AutoMaintenanceOnLevelupAction.h index e9fb14ee..ca9bf630 100644 --- a/src/strategy/actions/AutoLearnSpellAction.h +++ b/src/strategy/actions/AutoMaintenanceOnLevelupAction.h @@ -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 diff --git a/src/strategy/actions/AutoTeleportForLevelAction.cpp b/src/strategy/actions/AutoTeleportForLevelAction.cpp deleted file mode 100644 index 9906ad25..00000000 --- a/src/strategy/actions/AutoTeleportForLevelAction.cpp +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/src/strategy/actions/AutoTeleportForLevelAction.h b/src/strategy/actions/AutoTeleportForLevelAction.h deleted file mode 100644 index 67be8932..00000000 --- a/src/strategy/actions/AutoTeleportForLevelAction.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , 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 diff --git a/src/strategy/actions/ChatShortcutActions.cpp b/src/strategy/actions/ChatShortcutActions.cpp index 85304a87..0d5163eb 100644 --- a/src/strategy/actions/ChatShortcutActions.cpp +++ b/src/strategy/actions/ChatShortcutActions.cpp @@ -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("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) diff --git a/src/strategy/actions/CheckMountStateAction.cpp b/src/strategy/actions/CheckMountStateAction.cpp index 6a51fd92..d85f51b5 100644 --- a/src/strategy/actions/CheckMountStateAction.cpp +++ b/src/strategy/actions/CheckMountStateAction.cpp @@ -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); diff --git a/src/strategy/actions/FollowActions.cpp b/src/strategy/actions/FollowActions.cpp index 81be99a6..10d15933 100644 --- a/src/strategy/actions/FollowActions.cpp +++ b/src/strategy/actions/FollowActions.cpp @@ -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); diff --git a/src/strategy/actions/GenericActions.cpp b/src/strategy/actions/GenericActions.cpp index be75370a..84997212 100644 --- a/src/strategy/actions/GenericActions.cpp +++ b/src/strategy/actions/GenericActions.cpp @@ -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()); diff --git a/src/strategy/actions/GenericSpellActions.cpp b/src/strategy/actions/GenericSpellActions.cpp index 3e4b2147..05938358 100644 --- a/src/strategy/actions/GenericSpellActions.cpp +++ b/src/strategy/actions/GenericSpellActions.cpp @@ -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* 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* BuffOnMainTankAction::GetTargetValue() { return context->GetValue("main tank", spell); } bool CastDebuffSpellAction::isUseful() diff --git a/src/strategy/actions/GenericSpellActions.h b/src/strategy/actions/GenericSpellActions.h index 773f3ac0..b9870011 100644 --- a/src/strategy/actions/GenericSpellActions.h +++ b/src/strategy/actions/GenericSpellActions.h @@ -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 diff --git a/src/strategy/actions/ListSpellsAction.cpp b/src/strategy/actions/ListSpellsAction.cpp index 82e786a0..652d22b7 100644 --- a/src/strategy/actions/ListSpellsAction.cpp +++ b/src/strategy/actions/ListSpellsAction.cpp @@ -143,7 +143,10 @@ std::vector> 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; diff --git a/src/strategy/actions/MoveToRpgTargetAction.cpp b/src/strategy/actions/MoveToRpgTargetAction.cpp index 9640fc5c..4facc600 100644 --- a/src/strategy/actions/MoveToRpgTargetAction.cpp +++ b/src/strategy/actions/MoveToRpgTargetAction.cpp @@ -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) { diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index ea460bc1..641b9cfc 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -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("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, "recently flee info"); + std::list& infoList = AI_VALUE(std::list&, "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, "recently flee info"); + std::list& infoList = AI_VALUE(std::list&, "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, "recently flee info"); + std::list& infoList = AI_VALUE(std::list&, "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; diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index 2b8a82fe..5b0f3c7a 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -9,6 +9,7 @@ #include #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) { } diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index f3eb79fe..f0df16b8 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -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("prioritized targets")->Set({}); - SET_AI_VALUE(std::list, "recently flee info", {}); + AI_VALUE(std::list&, "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("prioritized targets")->Set({}); } player->GetMotionMaster()->Clear(); diff --git a/src/strategy/deathknight/DKActions.h b/src/strategy/deathknight/DKActions.h index 9d35de2c..2fe9c708 100644 --- a/src/strategy/deathknight/DKActions.h +++ b/src/strategy/deathknight/DKActions.h @@ -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 diff --git a/src/strategy/druid/DruidActions.h b/src/strategy/druid/DruidActions.h index f73a6864..749ba3ea 100644 --- a/src/strategy/druid/DruidActions.h +++ b/src/strategy/druid/DruidActions.h @@ -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 diff --git a/src/strategy/druid/DruidAiObjectContext.cpp b/src/strategy/druid/DruidAiObjectContext.cpp index 1a938842..b1181ae2 100644 --- a/src/strategy/druid/DruidAiObjectContext.cpp +++ b/src/strategy/druid/DruidAiObjectContext.cpp @@ -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); } diff --git a/src/strategy/druid/DruidBearActions.h b/src/strategy/druid/DruidBearActions.h index 8377bdd1..e83821bb 100644 --- a/src/strategy/druid/DruidBearActions.h +++ b/src/strategy/druid/DruidBearActions.h @@ -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 diff --git a/src/strategy/druid/FeralDruidStrategy.cpp b/src/strategy/druid/FeralDruidStrategy.cpp index c00e4620..ed4b030b 100644 --- a/src/strategy/druid/FeralDruidStrategy.cpp +++ b/src/strategy/druid/FeralDruidStrategy.cpp @@ -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); } diff --git a/src/strategy/druid/GenericDruidStrategy.cpp b/src/strategy/druid/GenericDruidStrategy.cpp index 5d820c36..c44668f7 100644 --- a/src/strategy/druid/GenericDruidStrategy.cpp +++ b/src/strategy/druid/GenericDruidStrategy.cpp @@ -106,6 +106,9 @@ void GenericDruidStrategy::InitTriggers(std::vector& 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))); diff --git a/src/strategy/generic/CombatStrategy.cpp b/src/strategy/generic/CombatStrategy.cpp index 92bb27f8..9d2d9932 100644 --- a/src/strategy/generic/CombatStrategy.cpp +++ b/src/strategy/generic/CombatStrategy.cpp @@ -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& triggers) diff --git a/src/strategy/generic/CombatStrategy.h b/src/strategy/generic/CombatStrategy.h index 422b4b22..e96a3eaf 100644 --- a/src/strategy/generic/CombatStrategy.h +++ b/src/strategy/generic/CombatStrategy.h @@ -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& multipliers) override; void InitTriggers(std::vector& 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; }; diff --git a/src/strategy/generic/ConserveManaStrategy.h b/src/strategy/generic/ConserveManaStrategy.h index 4af44222..d63daae6 100644 --- a/src/strategy/generic/ConserveManaStrategy.h +++ b/src/strategy/generic/ConserveManaStrategy.h @@ -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& multipliers) override; - std::string const getName() override { return "auto save mana"; } + std::string const getName() override { return "smana"; } }; #endif diff --git a/src/strategy/generic/RacialsStrategy.cpp b/src/strategy/generic/RacialsStrategy.cpp index 4b17bdf9..7762abca 100644 --- a/src/strategy/generic/RacialsStrategy.cpp +++ b/src/strategy/generic/RacialsStrategy.cpp @@ -25,14 +25,18 @@ private: void RacialsStrategy::InitTriggers(std::vector& 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) diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index 992675d3..d68cea4c 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -49,14 +49,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& 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))); diff --git a/src/strategy/hunter/DpsHunterStrategy.cpp b/src/strategy/hunter/DpsHunterStrategy.cpp index 684622a3..325f3b93 100644 --- a/src/strategy/hunter/DpsHunterStrategy.cpp +++ b/src/strategy/hunter/DpsHunterStrategy.cpp @@ -10,7 +10,11 @@ class DpsHunterStrategyActionNodeFactory : public NamedObjectFactory { 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); diff --git a/src/strategy/hunter/GenericHunterStrategy.cpp b/src/strategy/hunter/GenericHunterStrategy.cpp index 7c621b2a..e59df4cd 100644 --- a/src/strategy/hunter/GenericHunterStrategy.cpp +++ b/src/strategy/hunter/GenericHunterStrategy.cpp @@ -97,6 +97,9 @@ void GenericHunterStrategy::InitTriggers(std::vector& 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", diff --git a/src/strategy/hunter/HunterActions.h b/src/strategy/hunter/HunterActions.h index ef95eb15..868905c6 100644 --- a/src/strategy/hunter/HunterActions.h +++ b/src/strategy/hunter/HunterActions.h @@ -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: diff --git a/src/strategy/hunter/HunterAiObjectContext.cpp b/src/strategy/hunter/HunterAiObjectContext.cpp index 588888a9..32548aad 100644 --- a/src/strategy/hunter/HunterAiObjectContext.cpp +++ b/src/strategy/hunter/HunterAiObjectContext.cpp @@ -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); } diff --git a/src/strategy/paladin/DpsPaladinStrategy.cpp b/src/strategy/paladin/DpsPaladinStrategy.cpp index e3ecf5c2..da74b42d 100644 --- a/src/strategy/paladin/DpsPaladinStrategy.cpp +++ b/src/strategy/paladin/DpsPaladinStrategy.cpp @@ -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& 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", diff --git a/src/strategy/paladin/GenericPaladinStrategy.cpp b/src/strategy/paladin/GenericPaladinStrategy.cpp index 68d5bc84..676a6159 100644 --- a/src/strategy/paladin/GenericPaladinStrategy.cpp +++ b/src/strategy/paladin/GenericPaladinStrategy.cpp @@ -17,8 +17,8 @@ void GenericPaladinStrategy::InitTriggers(std::vector& 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))); diff --git a/src/strategy/paladin/PaladinActions.cpp b/src/strategy/paladin/PaladinActions.cpp index 402d4a56..1b5e46c0 100644 --- a/src/strategy/paladin/PaladinActions.cpp +++ b/src/strategy/paladin/PaladinActions.cpp @@ -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() { diff --git a/src/strategy/paladin/PaladinActions.h b/src/strategy/paladin/PaladinActions.h index 826c82e2..17fe052b 100644 --- a/src/strategy/paladin/PaladinActions.h +++ b/src/strategy/paladin/PaladinActions.h @@ -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 diff --git a/src/strategy/paladin/PaladinAiObjectContext.cpp b/src/strategy/paladin/PaladinAiObjectContext.cpp index 770069a1..094e2fb7 100644 --- a/src/strategy/paladin/PaladinAiObjectContext.cpp +++ b/src/strategy/paladin/PaladinAiObjectContext.cpp @@ -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); } diff --git a/src/strategy/paladin/TankPaladinStrategy.cpp b/src/strategy/paladin/TankPaladinStrategy.cpp index 517a639a..649fe21e 100644 --- a/src/strategy/paladin/TankPaladinStrategy.cpp +++ b/src/strategy/paladin/TankPaladinStrategy.cpp @@ -82,7 +82,7 @@ void TankPaladinStrategy::InitTriggers(std::vector& 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& 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( diff --git a/src/strategy/priest/GenericPriestStrategy.cpp b/src/strategy/priest/GenericPriestStrategy.cpp index b087c79e..8ef2c3ae 100644 --- a/src/strategy/priest/GenericPriestStrategy.cpp +++ b/src/strategy/priest/GenericPriestStrategy.cpp @@ -31,8 +31,9 @@ void GenericPriestStrategy::InitTriggers(std::vector& 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( diff --git a/src/strategy/priest/HolyPriestStrategy.cpp b/src/strategy/priest/HolyPriestStrategy.cpp index decae30d..40f34a28 100644 --- a/src/strategy/priest/HolyPriestStrategy.cpp +++ b/src/strategy/priest/HolyPriestStrategy.cpp @@ -73,7 +73,9 @@ void HolyHealPriestStrategy::InitTriggers(std::vector& 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))); diff --git a/src/strategy/priest/PriestActions.h b/src/strategy/priest/PriestActions.h index e7a95937..468694c8 100644 --- a/src/strategy/priest/PriestActions.h +++ b/src/strategy/priest/PriestActions.h @@ -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 diff --git a/src/strategy/priest/PriestAiObjectContext.cpp b/src/strategy/priest/PriestAiObjectContext.cpp index d48d1109..0df50eec 100644 --- a/src/strategy/priest/PriestAiObjectContext.cpp +++ b/src/strategy/priest/PriestAiObjectContext.cpp @@ -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) diff --git a/src/strategy/priest/PriestTriggers.h b/src/strategy/priest/PriestTriggers.h index fbfeeb57..f4eab6da 100644 --- a/src/strategy/priest/PriestTriggers.h +++ b/src/strategy/priest/PriestTriggers.h @@ -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"); diff --git a/src/strategy/priest/ShadowPriestStrategy.cpp b/src/strategy/priest/ShadowPriestStrategy.cpp index 474ce4db..e2433c7d 100644 --- a/src/strategy/priest/ShadowPriestStrategy.cpp +++ b/src/strategy/priest/ShadowPriestStrategy.cpp @@ -29,8 +29,10 @@ void ShadowPriestStrategy::InitTriggers(std::vector& 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( diff --git a/src/strategy/raids/naxxramas/RaidNaxxActions.cpp b/src/strategy/raids/naxxramas/RaidNaxxActions.cpp index 5d75e31a..a1019d9b 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxActions.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxActions.cpp @@ -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 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 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 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 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; } diff --git a/src/strategy/rogue/AssassinationRogueStrategy.cpp b/src/strategy/rogue/AssassinationRogueStrategy.cpp index c0eafa69..380ac292 100644 --- a/src/strategy/rogue/AssassinationRogueStrategy.cpp +++ b/src/strategy/rogue/AssassinationRogueStrategy.cpp @@ -66,8 +66,11 @@ void AssassinationRogueStrategy::InitTriggers(std::vector& 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))); diff --git a/src/strategy/rogue/DpsRogueStrategy.cpp b/src/strategy/rogue/DpsRogueStrategy.cpp index f3b2ab1c..6fc450b9 100644 --- a/src/strategy/rogue/DpsRogueStrategy.cpp +++ b/src/strategy/rogue/DpsRogueStrategy.cpp @@ -108,8 +108,11 @@ void DpsRogueStrategy::InitTriggers(std::vector& 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& 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), diff --git a/src/strategy/rogue/RogueActions.h b/src/strategy/rogue/RogueActions.h index f68fb676..35d846ea 100644 --- a/src/strategy/rogue/RogueActions.h +++ b/src/strategy/rogue/RogueActions.h @@ -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: diff --git a/src/strategy/rogue/RogueAiObjectContext.cpp b/src/strategy/rogue/RogueAiObjectContext.cpp index e4f88909..355c8953 100644 --- a/src/strategy/rogue/RogueAiObjectContext.cpp +++ b/src/strategy/rogue/RogueAiObjectContext.cpp @@ -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); } diff --git a/src/strategy/rogue/RogueComboActions.h b/src/strategy/rogue/RogueComboActions.h index 171d0b7d..e5ebc5a8 100644 --- a/src/strategy/rogue/RogueComboActions.h +++ b/src/strategy/rogue/RogueComboActions.h @@ -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 diff --git a/src/strategy/rogue/RogueTriggers.h b/src/strategy/rogue/RogueTriggers.h index 30ca4105..467bd9fc 100644 --- a/src/strategy/rogue/RogueTriggers.h +++ b/src/strategy/rogue/RogueTriggers.h @@ -36,6 +36,13 @@ public: // bool isPossible(); }; +class BladeFuryTrigger : public BoostTrigger +{ +public: + BladeFuryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "blade fury") {} +}; + + class RuptureTrigger : public DebuffTrigger { public: diff --git a/src/strategy/shaman/ShamanActions.cpp b/src/strategy/shaman/ShamanActions.cpp index ee6e3bea..7394c320 100644 --- a/src/strategy/shaman/ShamanActions.cpp +++ b/src/strategy/shaman/ShamanActions.cpp @@ -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() { diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index 0356a144..2568cd11 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -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 diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 49617449..c1f80eb7 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -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; } diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index 2410f674..35a49e3f 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -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: diff --git a/src/strategy/triggers/HealthTriggers.h b/src/strategy/triggers/HealthTriggers.h index 88739fef..d9f3253c 100644 --- a/src/strategy/triggers/HealthTriggers.h +++ b/src/strategy/triggers/HealthTriggers.h @@ -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) { } }; diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index a10d9ca7..788b7743 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -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); diff --git a/src/strategy/values/AttackerCountValues.cpp b/src/strategy/values/AttackerCountValues.cpp index 9cc82a37..59de8995 100644 --- a/src/strategy/values/AttackerCountValues.cpp +++ b/src/strategy/values/AttackerCountValues.cpp @@ -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("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; } diff --git a/src/strategy/values/AttackerWithoutAuraTargetValue.cpp b/src/strategy/values/AttackerWithoutAuraTargetValue.cpp index a9fcd5c4..a3945e64 100644 --- a/src/strategy/values/AttackerWithoutAuraTargetValue.cpp +++ b/src/strategy/values/AttackerWithoutAuraTargetValue.cpp @@ -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) diff --git a/src/strategy/values/LastMovementValue.cpp b/src/strategy/values/LastMovementValue.cpp index f7b5488e..72acfee4 100644 --- a/src/strategy/values/LastMovementValue.cpp +++ b/src/strategy/values/LastMovementValue.cpp @@ -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) diff --git a/src/strategy/values/LastMovementValue.h b/src/strategy/values/LastMovementValue.h index fc073a2a..a22debb5 100644 --- a/src/strategy/values/LastMovementValue.h +++ b/src/strategy/values/LastMovementValue.h @@ -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 future; diff --git a/src/strategy/values/PartyMemberToHeal.cpp b/src/strategy/values/PartyMemberToHeal.cpp index e16d63d0..3fb0b45d 100644 --- a/src/strategy/values/PartyMemberToHeal.cpp +++ b/src/strategy/values/PartyMemberToHeal.cpp @@ -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(); diff --git a/src/strategy/values/PartyMemberValue.cpp b/src/strategy/values/PartyMemberValue.cpp index 023eeefd..48ae772a 100644 --- a/src/strategy/values/PartyMemberValue.cpp +++ b/src/strategy/values/PartyMemberValue.cpp @@ -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()); } diff --git a/src/strategy/warrior/WarriorActions.h b/src/strategy/warrior/WarriorActions.h index d571b67e..05505da0 100644 --- a/src/strategy/warrior/WarriorActions.h +++ b/src/strategy/warrior/WarriorActions.h @@ -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");