diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 5038832ec..e7d9552bb 100644 --- a/src/PlayerbotAI.cpp +++ b/src/PlayerbotAI.cpp @@ -3090,6 +3090,10 @@ bool PlayerbotAI::IsInterruptableSpellCasting(Unit* target, std::string const sp bool PlayerbotAI::HasAuraToDispel(Unit* target, uint32 dispelType) { + if (!target->IsInWorld()) + { + return false; + } bool isFriend = bot->IsFriendlyTo(target); for (uint32 type = SPELL_AURA_NONE; type < TOTAL_AURAS; ++type) { diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 5a084cf88..b7655e74c 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -178,10 +178,10 @@ void PlayerbotFactory::Randomize(bool incremental) // { // return; // } - - LOG_INFO("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full")); + LOG_INFO("playerbots", "{} randomizing {} (level {} class = {})...", (incremental ? "Incremental" : "Full"), bot->GetName().c_str(), bot->GetLevel(), bot->getClass()); + // LOG_DEBUG("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full")); Prepare(); - LOG_INFO("playerbots", "Resetting player..."); + LOG_DEBUG("playerbots", "Resetting player..."); PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset"); bot->resetTalents(true); // bot->SaveToDB(false, false); @@ -221,14 +221,14 @@ void PlayerbotFactory::Randomize(bool incremental) } pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells1"); - LOG_INFO("playerbots", "Initializing spells (step 1)..."); + LOG_DEBUG("playerbots", "Initializing spells (step 1)..."); // bot->LearnDefaultSkills(); InitClassSpells(); InitAvailableSpells(); if (pmo) pmo->finish(); - LOG_INFO("playerbots", "Initializing skills (step 1)..."); + LOG_DEBUG("playerbots", "Initializing skills (step 1)..."); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Skills1"); InitSkills(); InitSpecialSpells(); @@ -238,7 +238,7 @@ void PlayerbotFactory::Randomize(bool incremental) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Talents"); - LOG_INFO("playerbots", "Initializing talents..."); + LOG_DEBUG("playerbots", "Initializing talents..."); if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { InitTalentsTree(); } @@ -252,13 +252,13 @@ void PlayerbotFactory::Randomize(bool incremental) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Spells2"); - LOG_INFO("playerbots", "Initializing spells (step 2)..."); + LOG_DEBUG("playerbots", "Initializing spells (step 2)..."); InitAvailableSpells(); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Mounts"); - LOG_INFO("playerbots", "Initializing mounts..."); + LOG_DEBUG("playerbots", "Initializing mounts..."); InitMounts(); bot->SaveToDB(false, false); if (pmo) @@ -271,7 +271,7 @@ void PlayerbotFactory::Randomize(bool incremental) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Equip"); - LOG_INFO("playerbots", "Initializing equipmemt..."); + LOG_DEBUG("playerbots", "Initializing equipmemt..."); if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { InitEquipment(incremental); } @@ -289,38 +289,38 @@ void PlayerbotFactory::Randomize(bool incremental) // } pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Bags"); - LOG_INFO("playerbots", "Initializing bags..."); + LOG_DEBUG("playerbots", "Initializing bags..."); InitBags(); // bot->SaveToDB(false, false); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Ammo"); - LOG_INFO("playerbots", "Initializing ammo..."); + LOG_DEBUG("playerbots", "Initializing ammo..."); InitAmmo(); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Food"); - LOG_INFO("playerbots", "Initializing food..."); + LOG_DEBUG("playerbots", "Initializing food..."); InitFood(); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Potions"); - LOG_INFO("playerbots", "Initializing potions..."); + LOG_DEBUG("playerbots", "Initializing potions..."); InitPotions(); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reagents"); - LOG_INFO("playerbots", "Initializing reagents..."); + LOG_DEBUG("playerbots", "Initializing reagents..."); InitReagents(); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_EqSets"); - LOG_INFO("playerbots", "Initializing second equipment set..."); + LOG_DEBUG("playerbots", "Initializing second equipment set..."); // InitSecondEquipmentSet(); if (pmo) pmo->finish(); @@ -337,18 +337,18 @@ void PlayerbotFactory::Randomize(bool incremental) // } pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Inventory"); - LOG_INFO("playerbots", "Initializing inventory..."); + LOG_DEBUG("playerbots", "Initializing inventory..."); // InitInventory(); if (pmo) pmo->finish(); pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Consumable"); - LOG_INFO("playerbots", "Initializing consumables..."); + LOG_DEBUG("playerbots", "Initializing consumables..."); AddConsumables(); if (pmo) pmo->finish(); - LOG_INFO("playerbots", "Initializing glyphs..."); + LOG_DEBUG("playerbots", "Initializing glyphs..."); bot->SaveToDB(false, false); InitGlyphs(); @@ -385,12 +385,12 @@ void PlayerbotFactory::Randomize(bool incremental) } pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Save"); - LOG_INFO("playerbots", "Saving to DB..."); + LOG_DEBUG("playerbots", "Saving to DB..."); bot->SetMoney(urand(level * 100000, level * 5 * 100000)); bot->SetHealth(bot->GetMaxHealth()); bot->SetPower(POWER_MANA, bot->GetMaxPower(POWER_MANA)); bot->SaveToDB(false, false); - LOG_INFO("playerbots", "Done."); + LOG_INFO("playerbots", "Initialization Done."); if (pmo) pmo->finish(); } @@ -587,7 +587,7 @@ void PlayerbotFactory::InitPetTalents() // LOG_INFO("playerbots", "{} init pet talents failed with petTalentType < 0({})", bot->GetName().c_str(), pet_family->petTalentType); return; } - pet->resetTalents(); + // pet->resetTalents(); std::unordered_map > spells; for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i) { diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index afb0b3a33..80c4a1bc3 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1196,8 +1196,8 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& z = 0.05f + ground; - LOG_INFO("playerbots", "Random teleporting bot {} to {} {},{},{} ({}/{} locations)", - bot->GetName().c_str(), zone->area_name[0], x, y, z, attemtps, tlocs.size()); + LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to {} {},{},{} ({}/{} locations)", + bot->GetName().c_str(), bot->GetLevel(), zone->area_name[0], x, y, z, attemtps, tlocs.size()); if (hearth) { @@ -1387,7 +1387,7 @@ void RandomPlayerbotMgr::RandomTeleportForLevel(Player* bot) uint32 level = bot->getLevel(); uint8 race = bot->getRace(); - LOG_INFO("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(), bot->GetLevel(), locsPerLevelCache[level].size()); + LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(), bot->GetLevel(), locsPerLevelCache[level].size()); if (urand(0, 100) < sPlayerbotAIConfig->probTeleToBankers * 100) { RandomTeleport(bot, bankerLocsPerLevelCache[level], true); } else { @@ -1402,7 +1402,7 @@ void RandomPlayerbotMgr::RandomTeleportGrindForLevel(Player* bot) uint32 level = bot->getLevel(); uint8 race = bot->getRace(); - LOG_INFO("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(), bot->GetLevel(), locsPerLevelCache[level].size()); + LOG_DEBUG("playerbots", "Random teleporting bot {} for level {} ({} locations available)", bot->GetName().c_str(), bot->GetLevel(), locsPerLevelCache[level].size()); RandomTeleport(bot, locsPerLevelCache[level]); } @@ -1642,7 +1642,7 @@ void RandomPlayerbotMgr::Refresh(Player* bot) if (bot->InBattleground()) return; - LOG_INFO("playerbots", "Refreshing bot {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetName().c_str()); + LOG_DEBUG("playerbots", "Refreshing bot {} <{}>", bot->GetGUID().ToString().c_str(), bot->GetName().c_str()); PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "Refresh"); @@ -2482,7 +2482,7 @@ void RandomPlayerbotMgr::RandomTeleportForRpg(Player* bot) { uint32 race = bot->getRace(); uint32 level = bot->GetLevel(); - LOG_INFO("playerbots", "Random teleporting bot {} for RPG ({} locations available)", bot->GetName().c_str(), rpgLocsCacheLevel[race].size()); + LOG_DEBUG("playerbots", "Random teleporting bot {} for RPG ({} locations available)", bot->GetName().c_str(), rpgLocsCacheLevel[race].size()); RandomTeleport(bot, rpgLocsCacheLevel[race][level], true); } diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index e87982c68..53c3f6998 100644 --- a/src/strategy/StrategyContext.h +++ b/src/strategy/StrategyContext.h @@ -72,6 +72,7 @@ class StrategyContext : public NamedObjectContext creators["potions"] = &StrategyContext::potions; creators["cast time"] = &StrategyContext::cast_time; creators["threat"] = &StrategyContext::threat; + creators["focus"] = &StrategyContext::focus; creators["tell target"] = &StrategyContext::tell_target; creators["pvp"] = &StrategyContext::pvp; creators["return"] = &StrategyContext::_return; @@ -120,6 +121,7 @@ class StrategyContext : public NamedObjectContext static Strategy* mark_rti(PlayerbotAI* botAI) { return new MarkRtiStrategy(botAI); } static Strategy* tell_target(PlayerbotAI* botAI) { return new TellTargetStrategy(botAI); } static Strategy* threat(PlayerbotAI* botAI) { return new ThreatStrategy(botAI); } + static Strategy* focus(PlayerbotAI* botAI) { return new FocusStrategy(botAI); } static Strategy* cast_time(PlayerbotAI* botAI) { return new CastTimeStrategy(botAI); } static Strategy* potions(PlayerbotAI* botAI) { return new UsePotionsStrategy(botAI); } static Strategy* kite(PlayerbotAI* botAI) { return new KiteStrategy(botAI); } diff --git a/src/strategy/Value.cpp b/src/strategy/Value.cpp index 4f64319ee..464e0d1f6 100644 --- a/src/strategy/Value.cpp +++ b/src/strategy/Value.cpp @@ -136,4 +136,12 @@ Unit* UnitCalculatedValue::Get() if (value && value->IsInWorld()) return value; return nullptr; +} + +Unit* UnitManualSetValue::Get() +{ + // Prevent crashing by InWorld check + if (value && value->IsInWorld()) + return value; + return nullptr; } \ No newline at end of file diff --git a/src/strategy/Value.h b/src/strategy/Value.h index 9ab4b89ad..9cba6efe6 100644 --- a/src/strategy/Value.h +++ b/src/strategy/Value.h @@ -323,6 +323,7 @@ class UnitManualSetValue : public ManualSetValue ManualSetValue(botAI, defaultValue, name) { } std::string const Format() override; + Unit* Get() override; }; #endif diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 20e496c30..978eb1d98 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -36,7 +36,8 @@ bool AttackMyTargetAction::Execute(Event event) return false; } - + + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({guid}); bool result = Attack(botAI->GetUnit(guid)); if (result) context->GetValue("pull target")->Set(guid); @@ -62,6 +63,10 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) return false; } + if (!target->IsInWorld()) + { + return false; + } std::ostringstream msg; msg << target->GetName(); diff --git a/src/strategy/actions/ChangeTalentsAction.cpp b/src/strategy/actions/ChangeTalentsAction.cpp index 6b41b7478..e0f3b8db5 100644 --- a/src/strategy/actions/ChangeTalentsAction.cpp +++ b/src/strategy/actions/ChangeTalentsAction.cpp @@ -23,10 +23,10 @@ bool ChangeTalentsAction::Execute(Event event) if (param.find("help") != std::string::npos) { out << TalentsHelp(); } else if (param.find("switch") != std::string::npos) { - if (param == "1") { + if (param.find("switch 1")) { bot->ActivateSpec(0); out << "Active first talent"; - } else if (param == "2") { + } else if (param.find("switch 2")) { bot->ActivateSpec(1); out << "Active second talent"; } diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 892572330..c0de32495 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -829,7 +829,7 @@ bool MovementAction::Follow(Unit* target, float distance) void MovementAction::UpdateMovementState() { - if (bot->Unit::IsInWater() || bot->Unit::IsUnderWater()) + if (bot->Unit::IsUnderWater()) { bot->SetSwim(true); } diff --git a/src/strategy/actions/ReviveFromCorpseAction.cpp b/src/strategy/actions/ReviveFromCorpseAction.cpp index 7096283ae..7fb2856ab 100644 --- a/src/strategy/actions/ReviveFromCorpseAction.cpp +++ b/src/strategy/actions/ReviveFromCorpseAction.cpp @@ -300,7 +300,7 @@ bool SpiritHealerAction::Execute(Event event) Unit* unit = botAI->GetUnit(*i); if (unit && unit->HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER)) { - LOG_INFO("playerbots", "Bot {} {}:{} <{}> revives at spirit healer", + LOG_DEBUG("playerbots", "Bot {} {}:{} <{}> revives at spirit healer", bot->GetGUID().ToString().c_str(), bot->GetTeamId() == TEAM_ALLIANCE ? "A" : "H", bot->getLevel(), bot->GetName()); PlayerbotChatHandler ch(bot); bot->ResurrectPlayer(0.5f); diff --git a/src/strategy/deathknight/DKActions.h b/src/strategy/deathknight/DKActions.h index e4907ac8f..6106af181 100644 --- a/src/strategy/deathknight/DKActions.h +++ b/src/strategy/deathknight/DKActions.h @@ -234,6 +234,8 @@ 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/generic/ThreatStrategy.cpp b/src/strategy/generic/ThreatStrategy.cpp index 4b2d39eda..ba1cbf4c6 100644 --- a/src/strategy/generic/ThreatStrategy.cpp +++ b/src/strategy/generic/ThreatStrategy.cpp @@ -4,6 +4,7 @@ #include "ThreatStrategy.h" #include "GenericSpellActions.h" +#include "Map.h" #include "Playerbots.h" float ThreatMultiplier::GetValue(Action* action) @@ -36,3 +37,22 @@ void ThreatStrategy::InitMultipliers(std::vector& multipliers) { multipliers.push_back(new ThreatMultiplier(botAI)); } + +float FocusMultiplier::GetValue(Action* action) +{ + if (!action) { + return 1.0f; + } + if (action->getThreatType() == Action::ActionThreatType::Aoe && !dynamic_cast(action)) { + return 0.0f; + } + if (dynamic_cast(action)) { + return 0.0f; + } + return 1.0f; +} + +void FocusStrategy::InitMultipliers(std::vector& multipliers) +{ + multipliers.push_back(new FocusMultiplier(botAI)); +} diff --git a/src/strategy/generic/ThreatStrategy.h b/src/strategy/generic/ThreatStrategy.h index 5c917f4e3..521233c97 100644 --- a/src/strategy/generic/ThreatStrategy.h +++ b/src/strategy/generic/ThreatStrategy.h @@ -26,4 +26,21 @@ class ThreatStrategy : public Strategy std::string const getName() override { return "threat"; } }; +class FocusMultiplier : public Multiplier +{ + public: + FocusMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "focus") { } + + float GetValue(Action* action) override; +}; + +class FocusStrategy : public Strategy +{ + public: + FocusStrategy(PlayerbotAI* botAI) : Strategy(botAI) { } + + void InitMultipliers(std::vector& multipliers) override; + std::string const getName() override { return "focus"; } +}; + #endif diff --git a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp index b22dc604d..72ea08dd7 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp @@ -19,6 +19,18 @@ #include "WarriorActions.h" #include "DruidBearActions.h" +float GrobbulusMultiplier::GetValue(Action* action) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "grobbulus"); + if (!boss) { + return 1.0f; + } + if (dynamic_cast(action)) { + return 0.0f; + } + return 1.0f; +} + float HeiganDanceMultiplier::GetValue(Action* action) { Unit* boss = AI_VALUE2(Unit*, "find target", "heigan the unclean"); diff --git a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h index 4d80d566c..8ac9e0716 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h +++ b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.h @@ -5,22 +5,30 @@ #include "Multiplier.h" #include "raids/naxxramas/RaidNaxxBossHelper.h" +class GrobbulusMultiplier : public Multiplier +{ + public: + GrobbulusMultiplier(PlayerbotAI* ai) : Multiplier(ai, "grobbulus") {} + + public: + virtual float GetValue(Action* action); +}; class HeiganDanceMultiplier : public Multiplier { -public: - HeiganDanceMultiplier(PlayerbotAI* ai) : Multiplier(ai, "helgan dance") {} + public: + HeiganDanceMultiplier(PlayerbotAI* ai) : Multiplier(ai, "helgan dance") {} -public: - virtual float GetValue(Action* action); + public: + virtual float GetValue(Action* action); }; class LoathebGenericMultiplier : public Multiplier { -public: - LoathebGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "loatheb generic") {} + public: + LoathebGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "loatheb generic") {} -public: - virtual float GetValue(Action* action); + public: + virtual float GetValue(Action* action); }; class ThaddiusGenericMultiplier : public Multiplier diff --git a/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp b/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp index c58d8b32b..0d640273e 100644 --- a/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp +++ b/src/strategy/raids/naxxramas/RaidNaxxStrategy.cpp @@ -112,6 +112,7 @@ void RaidNaxxStrategy::InitTriggers(std::vector &triggers) void RaidNaxxStrategy::InitMultipliers(std::vector &multipliers) { + multipliers.push_back(new GrobbulusMultiplier(botAI)); multipliers.push_back(new HeiganDanceMultiplier(botAI)); multipliers.push_back(new LoathebGenericMultiplier(botAI)); multipliers.push_back(new ThaddiusGenericMultiplier(botAI)); diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 7f55be586..6d2a9d0a7 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -469,14 +469,16 @@ bool PossibleAddsTrigger::IsActive() bool NotDpsTargetActiveTrigger::IsActive() { - Unit* dps = AI_VALUE(Unit*, "dps target"); Unit* target = AI_VALUE(Unit*, "current target"); - Unit* enemy = AI_VALUE(Unit*, "enemy player target"); - // do not switch if enemy target - if (target && target == enemy && target->IsAlive()) - return false; + if (target && target->IsAlive()) { + + Unit* enemy = AI_VALUE(Unit*, "enemy player target"); + if (target == enemy) + return false; + } + Unit* dps = AI_VALUE(Unit*, "dps target"); return dps && target != dps; } diff --git a/src/strategy/values/AoeHealValues.cpp b/src/strategy/values/AoeHealValues.cpp index 9fc1d2427..20a388a17 100644 --- a/src/strategy/values/AoeHealValues.cpp +++ b/src/strategy/values/AoeHealValues.cpp @@ -29,7 +29,10 @@ uint8 AoeHealValue::Calculate() Player* player = ObjectAccessor::FindPlayer(itr->guid); if (!player || !player->IsAlive()) continue; - + + if (player->GetDistance(bot) >= sPlayerbotAIConfig->sightDistance) + continue; + float percent = (static_cast (player->GetHealth()) / player->GetMaxHealth()) * 100; if (percent <= range) ++count; diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index d64423635..fcfd1d9a2 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -23,14 +23,31 @@ GuidVector AttackersValue::Calculate() if (Group* group = bot->GetGroup()) AddAttackersOf(group, targets); + RemoveNonThreating(targets); + // prioritized target + GuidVector prioritizedTargets = AI_VALUE(GuidVector, "prioritized targets"); + for (ObjectGuid target : prioritizedTargets) { + Unit* unit = botAI->GetUnit(target); + if (unit && IsValidTarget(unit, bot)) { + targets.insert(unit); + } + } + if (Group* group = bot->GetGroup()) { + ObjectGuid skullGuid = group->GetTargetIcon(4); + Unit* skullTarget = botAI->GetUnit(skullGuid); + if (skullTarget && IsValidTarget(skullTarget, bot)) { + targets.insert(skullTarget); + } + } + for (Unit* unit : targets) result.push_back(unit->GetGUID()); if (bot->duel && bot->duel->Opponent) result.push_back(bot->duel->Opponent->GetGUID()); - + return result; } @@ -114,7 +131,7 @@ bool AttackersValue::hasRealThreat(Unit *attacker) attacker->IsAlive() && !attacker->IsPolymorphed() && // !attacker->isInRoots() && - !attacker->IsFriendlyTo(bot) && + !attacker->IsFriendlyTo(bot); (attacker->GetThreatMgr().getCurrentVictim() || dynamic_cast(attacker)); } diff --git a/src/strategy/values/AttackersValue.h b/src/strategy/values/AttackersValue.h index b3bb38b41..3a4ae20ae 100644 --- a/src/strategy/values/AttackersValue.h +++ b/src/strategy/values/AttackersValue.h @@ -37,4 +37,10 @@ class PossibleAddsValue : public BoolCalculatedValue bool Calculate() override; }; +class PrioritizedTargetsValue : public ManualSetValue +{ + public: + PrioritizedTargetsValue(PlayerbotAI* botAI, std::string const name = "prioritized targets"): ManualSetValue(botAI, GuidVector(), name) {} +}; + #endif diff --git a/src/strategy/values/DpsTargetValue.cpp b/src/strategy/values/DpsTargetValue.cpp index f16a3f846..fc8f6ce1a 100644 --- a/src/strategy/values/DpsTargetValue.cpp +++ b/src/strategy/values/DpsTargetValue.cpp @@ -13,15 +13,17 @@ class FindLeastHpTargetStrategy : public FindTargetStrategy void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override { - if (Group* group = botAI->GetBot()->GetGroup()) - { - ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) - return; - } if (!attacker->IsAlive()) { return; } + if (foundHighPriority) { + return; + } + if (IsHighPriority(attacker)) { + result = attacker; + foundHighPriority = true; + return; + } if (!result || result->GetHealth() > attacker->GetHealth()) result = attacker; } @@ -37,15 +39,17 @@ class FindMaxThreatGapTargetStrategy : public FindTargetStrategy void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override { - if (Group* group = botAI->GetBot()->GetGroup()) - { - ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) - return; - } if (!attacker->IsAlive()) { return; } + if (foundHighPriority) { + return; + } + if (IsHighPriority(attacker)) { + result = attacker; + foundHighPriority = true; + return; + } Unit* victim = attacker->GetVictim(); if (!result || CalcThreatGap(attacker, threatMgr) > CalcThreatGap(result, &result->GetThreatMgr())) result = attacker; @@ -67,15 +71,17 @@ class CasterFindTargetSmartStrategy : public FindTargetStrategy void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override { - if (Group* group = botAI->GetBot()->GetGroup()) - { - ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) - return; - } if (!attacker->IsAlive()) { return; } + if (foundHighPriority) { + return; + } + if (IsHighPriority(attacker)) { + result = attacker; + foundHighPriority = true; + return; + } float expectedLifeTime = attacker->GetHealth() / dps_; // Unit* victim = attacker->GetVictim(); if (!result || IsBetter(attacker, result)) { @@ -132,15 +138,17 @@ class NonCasterFindTargetSmartStrategy : public FindTargetStrategy void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override { - if (Group* group = botAI->GetBot()->GetGroup()) - { - ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) - return; - } if (!attacker->IsAlive()) { return; } + if (foundHighPriority) { + return; + } + if (IsHighPriority(attacker)) { + result = attacker; + foundHighPriority = true; + return; + } float expectedLifeTime = attacker->GetHealth() / dps_; // Unit* victim = attacker->GetVictim(); if (!result || IsBetter(attacker, result)) { @@ -185,15 +193,17 @@ class ComboFindTargetSmartStrategy : public FindTargetStrategy void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) override { - if (Group* group = botAI->GetBot()->GetGroup()) - { - ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) - return; - } if (!attacker->IsAlive()) { return; } + if (foundHighPriority) { + return; + } + if (IsHighPriority(attacker)) { + result = attacker; + foundHighPriority = true; + return; + } float expectedLifeTime = attacker->GetHealth() / dps_; // Unit* victim = attacker->GetVictim(); if (!result || IsBetter(attacker, result)) { diff --git a/src/strategy/values/InvalidTargetValue.cpp b/src/strategy/values/InvalidTargetValue.cpp index fe2ab0231..d2499c521 100644 --- a/src/strategy/values/InvalidTargetValue.cpp +++ b/src/strategy/values/InvalidTargetValue.cpp @@ -27,6 +27,7 @@ bool InvalidTargetValue::Calculate() target->isFeared() || target->HasUnitState(UNIT_STATE_ISOLATED) || target->IsFriendlyTo(bot) || + !AttackersValue::IsValidTarget(target, bot) || // !bot->IsWithinDistInMap(target, sPlayerbotAIConfig->sightDistance) || !bot->IsWithinLOSInMap(target); } diff --git a/src/strategy/values/TargetValue.cpp b/src/strategy/values/TargetValue.cpp index 44ee831a0..ad709394e 100644 --- a/src/strategy/values/TargetValue.cpp +++ b/src/strategy/values/TargetValue.cpp @@ -100,6 +100,24 @@ void FindTargetStrategy::GetPlayerCount(Unit* creature, uint32* tankCount, uint3 dpsCountCache[creature] = *dpsCount; } +bool FindTargetStrategy::IsHighPriority(Unit* attacker) +{ + if (Group* group = botAI->GetBot()->GetGroup()) + { + ObjectGuid guid = group->GetTargetIcon(4); + if (guid && attacker->GetGUID() == guid) { + return true; + } + } + GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); + for (ObjectGuid targetGuid : prioritizedTargets) { + if (targetGuid && attacker->GetGUID() == targetGuid) { + return true; + } + } + return false; +} + WorldPosition LastLongMoveValue::Calculate() { LastMovement& lastMove = *context->GetValue("last movement"); diff --git a/src/strategy/values/TargetValue.h b/src/strategy/values/TargetValue.h index 215977bd1..b4ed6af6a 100644 --- a/src/strategy/values/TargetValue.h +++ b/src/strategy/values/TargetValue.h @@ -21,12 +21,14 @@ class FindTargetStrategy Unit* GetResult(); virtual void CheckAttacker(Unit* attacker, ThreatMgr* threatMgr) = 0; void GetPlayerCount(Unit* creature, uint32* tankCount, uint32* dpsCount); + bool IsHighPriority(Unit* attacker); protected: Unit* result; PlayerbotAI* botAI; std::map tankCountCache; std::map dpsCountCache; + bool foundHighPriority = false; }; class FindNonCcTargetStrategy : public FindTargetStrategy diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 72e65185a..4298b44e9 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -112,6 +112,7 @@ class ValueContext : public NamedObjectContext creators["possible targets no los"] = &ValueContext::possible_targets_no_los; creators["possible triggers"] = &ValueContext::possible_triggers; creators["possible adds"] = &ValueContext::possible_adds; + creators["prioritized targets"] = &ValueContext::prioritized_targets; creators["all targets"] = &ValueContext::all_targets; creators["possible rpg targets"] = &ValueContext::possible_rpg_targets; creators["nearest adds"] = &ValueContext::nearest_adds; @@ -382,6 +383,7 @@ class ValueContext : public NamedObjectContext static UntypedValue* possible_triggers(PlayerbotAI* botAI) { return new PossibleTriggersValue(botAI); } static UntypedValue* possible_targets_no_los(PlayerbotAI* botAI) { return new PossibleTargetsValue(botAI, "possible targets", sPlayerbotAIConfig->sightDistance, true); } static UntypedValue* possible_adds(PlayerbotAI* botAI) { return new PossibleAddsValue(botAI); } + static UntypedValue* prioritized_targets(PlayerbotAI* botAI) { return new PrioritizedTargetsValue(botAI); } static UntypedValue* all_targets(PlayerbotAI* botAI) { return new AllTargetsValue(botAI); } static UntypedValue* nearest_adds(PlayerbotAI* botAI) { return new NearestAddsValue(botAI); } static UntypedValue* party_member_without_aura(PlayerbotAI* botAI) { return new PartyMemberWithoutAuraValue(botAI); }