From 43c0435e78202b46101cf56afe11ebcc47d7d861 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 28 May 2024 10:28:06 +0800 Subject: [PATCH 01/13] [Attack Target] Invalid target check --- src/strategy/triggers/GenericTriggers.cpp | 12 +++++++----- src/strategy/values/InvalidTargetValue.cpp | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 7f55be58..6d2a9d0a 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/InvalidTargetValue.cpp b/src/strategy/values/InvalidTargetValue.cpp index fe2ab023..d2499c52 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); } From d5d1bb39042b0dac123dae48b51ac28c5c5ee2a6 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 28 May 2024 11:25:07 +0800 Subject: [PATCH 02/13] [Attack Target] Prioritized targets --- src/strategy/actions/AttackAction.cpp | 3 +- src/strategy/values/AttackersValue.cpp | 16 +++++++- src/strategy/values/AttackersValue.h | 6 +++ src/strategy/values/DpsTargetValue.cpp | 55 +++++++++++++++++++++++--- src/strategy/values/ValueContext.h | 2 + 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 20e496c3..58ebd02f 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); diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index d6442363..f33abb56 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -23,6 +23,20 @@ GuidVector AttackersValue::Calculate() if (Group* group = bot->GetGroup()) AddAttackersOf(group, targets); + // prioritize target + GuidVector prioritizedTargets = AI_VALUE(GuidVector, "prioritized targets"); + for (ObjectGuid target : prioritizedTargets) { + Unit* unit = botAI->GetUnit(target); + if (unit) { + targets.insert(unit); + } + } + ObjectGuid skullGuid = bot->GetGroup()->GetTargetIcon(4); + Unit* skullTarget = botAI->GetUnit(skullGuid); + if (skullTarget) { + targets.insert(skullTarget); + } + RemoveNonThreating(targets); for (Unit* unit : targets) @@ -30,7 +44,7 @@ GuidVector AttackersValue::Calculate() if (bot->duel && bot->duel->Opponent) result.push_back(bot->duel->Opponent->GetGUID()); - + return result; } diff --git a/src/strategy/values/AttackersValue.h b/src/strategy/values/AttackersValue.h index b3bb38b4..3a4ae20a 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 f16a3f84..4011c4f6 100644 --- a/src/strategy/values/DpsTargetValue.cpp +++ b/src/strategy/values/DpsTargetValue.cpp @@ -16,8 +16,17 @@ class FindLeastHpTargetStrategy : public FindTargetStrategy if (Group* group = botAI->GetBot()->GetGroup()) { ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) + if (guid && attacker->GetGUID() == guid) { + result = attacker; return; + } + } + GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); + for (ObjectGuid targetGuid : prioritizedTargets) { + if (targetGuid && attacker->GetGUID() == targetGuid) { + result = attacker; + return; + } } if (!attacker->IsAlive()) { return; @@ -40,8 +49,17 @@ class FindMaxThreatGapTargetStrategy : public FindTargetStrategy if (Group* group = botAI->GetBot()->GetGroup()) { ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) + if (guid && attacker->GetGUID() == guid) { + result = attacker; return; + } + } + GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); + for (ObjectGuid targetGuid : prioritizedTargets) { + if (targetGuid && attacker->GetGUID() == targetGuid) { + result = attacker; + return; + } } if (!attacker->IsAlive()) { return; @@ -70,8 +88,17 @@ class CasterFindTargetSmartStrategy : public FindTargetStrategy if (Group* group = botAI->GetBot()->GetGroup()) { ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) + if (guid && attacker->GetGUID() == guid) { + result = attacker; return; + } + } + GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); + for (ObjectGuid targetGuid : prioritizedTargets) { + if (targetGuid && attacker->GetGUID() == targetGuid) { + result = attacker; + return; + } } if (!attacker->IsAlive()) { return; @@ -135,8 +162,17 @@ class NonCasterFindTargetSmartStrategy : public FindTargetStrategy if (Group* group = botAI->GetBot()->GetGroup()) { ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) + if (guid && attacker->GetGUID() == guid) { + result = attacker; return; + } + } + GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); + for (ObjectGuid targetGuid : prioritizedTargets) { + if (targetGuid && attacker->GetGUID() == targetGuid) { + result = attacker; + return; + } } if (!attacker->IsAlive()) { return; @@ -188,8 +224,17 @@ class ComboFindTargetSmartStrategy : public FindTargetStrategy if (Group* group = botAI->GetBot()->GetGroup()) { ObjectGuid guid = group->GetTargetIcon(4); - if (guid && attacker->GetGUID() == guid) + if (guid && attacker->GetGUID() == guid) { + result = attacker; return; + } + } + GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); + for (ObjectGuid targetGuid : prioritizedTargets) { + if (targetGuid && attacker->GetGUID() == targetGuid) { + result = attacker; + return; + } } if (!attacker->IsAlive()) { return; diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 72e65185..4298b44e 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); } From 05236fddec80086c8f6a9c09cd9b79441c169d58 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 2 Jun 2024 23:22:20 +0800 Subject: [PATCH 03/13] [Attack target] Crash fix --- src/PlayerbotFactory.cpp | 38 +++++++++++++------------- src/strategy/values/AttackersValue.cpp | 12 ++++---- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 5a084cf8..4b16cb28 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -179,9 +179,9 @@ void PlayerbotFactory::Randomize(bool incremental) // return; // } - LOG_INFO("playerbots", "Preparing to {} randomize...", (incremental ? "incremental" : "full")); + 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(); } diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index f33abb56..ec82655b 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -23,7 +23,7 @@ GuidVector AttackersValue::Calculate() if (Group* group = bot->GetGroup()) AddAttackersOf(group, targets); - // prioritize target + // prioritized target GuidVector prioritizedTargets = AI_VALUE(GuidVector, "prioritized targets"); for (ObjectGuid target : prioritizedTargets) { Unit* unit = botAI->GetUnit(target); @@ -31,10 +31,12 @@ GuidVector AttackersValue::Calculate() targets.insert(unit); } } - ObjectGuid skullGuid = bot->GetGroup()->GetTargetIcon(4); - Unit* skullTarget = botAI->GetUnit(skullGuid); - if (skullTarget) { - targets.insert(skullTarget); + if (Group* group = bot->GetGroup()) { + ObjectGuid skullGuid = group->GetTargetIcon(4); + Unit* skullTarget = botAI->GetUnit(skullGuid); + if (skullTarget) { + targets.insert(skullTarget); + } } RemoveNonThreating(targets); From 5855d4e8fe84b488439a2b47c3827d6df129b0e9 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 3 Jun 2024 23:10:58 +0800 Subject: [PATCH 04/13] [Talents] Switch command --- src/strategy/actions/ChangeTalentsAction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/ChangeTalentsAction.cpp b/src/strategy/actions/ChangeTalentsAction.cpp index 6b41b747..e0f3b8db 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"; } From dfe093318938959ed767313cae7b0e6276366bfd Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 3 Jun 2024 23:12:57 +0800 Subject: [PATCH 05/13] [Initialization] No pet talents reset --- src/PlayerbotFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 4b16cb28..3b4277c6 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -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) { From 78f35f1b501802900d3d77290e67befcdb20bc58 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 3 Jun 2024 23:22:41 +0800 Subject: [PATCH 06/13] [Log] Downgrade duplicate log --- src/RandomPlayerbotMgr.cpp | 12 ++++++------ src/strategy/actions/ReviveFromCorpseAction.cpp | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index afb0b3a3..a1b10558 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->GetLevel(), bot->GetName().c_str(), 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/actions/ReviveFromCorpseAction.cpp b/src/strategy/actions/ReviveFromCorpseAction.cpp index 7096283a..7fb2856a 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); From 55eecba11b7206b87ad2835ba212b83c4e1a70f9 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 4 Jun 2024 09:47:40 +0800 Subject: [PATCH 07/13] [Crash fix] Target IsInWorld check --- src/PlayerbotAI.cpp | 4 ++++ src/RandomPlayerbotMgr.cpp | 4 ++-- src/strategy/actions/AttackAction.cpp | 4 ++++ src/strategy/values/AoeHealValues.cpp | 5 ++++- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotAI.cpp b/src/PlayerbotAI.cpp index 5038832e..e7d9552b 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/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index a1b10558..80c4a1bc 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 (level {}) {} to {} {},{},{} ({}/{} locations)", - bot->GetLevel(), 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) { diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index 58ebd02f..978eb1d9 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -63,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/values/AoeHealValues.cpp b/src/strategy/values/AoeHealValues.cpp index 9fc1d242..20a388a1 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; From 46e585f85477228463656f3f8941c72cffb4e49f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 4 Jun 2024 22:15:27 +0800 Subject: [PATCH 08/13] [Attack target] Fix attack --- src/strategy/values/DpsTargetValue.cpp | 115 +++++++++---------------- src/strategy/values/TargetValue.cpp | 18 ++++ src/strategy/values/TargetValue.h | 2 + 3 files changed, 60 insertions(+), 75 deletions(-) diff --git a/src/strategy/values/DpsTargetValue.cpp b/src/strategy/values/DpsTargetValue.cpp index 4011c4f6..fc8f6ce1 100644 --- a/src/strategy/values/DpsTargetValue.cpp +++ b/src/strategy/values/DpsTargetValue.cpp @@ -13,24 +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) { - result = attacker; - return; - } - } - GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); - for (ObjectGuid targetGuid : prioritizedTargets) { - if (targetGuid && attacker->GetGUID() == targetGuid) { - result = attacker; - return; - } - } if (!attacker->IsAlive()) { return; } + if (foundHighPriority) { + return; + } + if (IsHighPriority(attacker)) { + result = attacker; + foundHighPriority = true; + return; + } if (!result || result->GetHealth() > attacker->GetHealth()) result = attacker; } @@ -46,24 +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) { - result = attacker; - return; - } - } - GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); - for (ObjectGuid targetGuid : prioritizedTargets) { - if (targetGuid && attacker->GetGUID() == targetGuid) { - result = attacker; - 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; @@ -85,24 +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) { - result = attacker; - return; - } - } - GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); - for (ObjectGuid targetGuid : prioritizedTargets) { - if (targetGuid && attacker->GetGUID() == targetGuid) { - result = attacker; - 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)) { @@ -159,24 +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) { - result = attacker; - return; - } - } - GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); - for (ObjectGuid targetGuid : prioritizedTargets) { - if (targetGuid && attacker->GetGUID() == targetGuid) { - result = attacker; - 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)) { @@ -221,24 +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) { - result = attacker; - return; - } - } - GuidVector prioritizedTargets = botAI->GetAiObjectContext()->GetValue("prioritized targets")->Get(); - for (ObjectGuid targetGuid : prioritizedTargets) { - if (targetGuid && attacker->GetGUID() == targetGuid) { - result = attacker; - 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/TargetValue.cpp b/src/strategy/values/TargetValue.cpp index 44ee831a..ad709394 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 215977bd..b4ed6af6 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 From 5f40c39e5e3fa7788402109ec6d472da95611e94 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 4 Jun 2024 22:15:39 +0800 Subject: [PATCH 09/13] [Strategy] Focus strategy --- src/strategy/StrategyContext.h | 2 ++ src/strategy/generic/ThreatStrategy.cpp | 20 ++++++++++++++++++++ src/strategy/generic/ThreatStrategy.h | 17 +++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/src/strategy/StrategyContext.h b/src/strategy/StrategyContext.h index e87982c6..53c3f699 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/generic/ThreatStrategy.cpp b/src/strategy/generic/ThreatStrategy.cpp index 4b2d39ed..ba1cbf4c 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 5c917f4e..521233c9 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 From be3b2c82f8ef7fce15fc4e44fdd78ccf75917c30 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 4 Jun 2024 22:42:48 +0800 Subject: [PATCH 10/13] [Attack target] Fix --- src/strategy/values/AttackersValue.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index ec82655b..fcfd1d9a 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -23,24 +23,25 @@ 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) { + 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) { + if (skullTarget && IsValidTarget(skullTarget, bot)) { targets.insert(skullTarget); } } - RemoveNonThreating(targets); - for (Unit* unit : targets) result.push_back(unit->GetGUID()); @@ -130,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)); } From d0ee39aa3ad9e1c622529f4599c1ceb571450968 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 5 Jun 2024 19:37:39 +0800 Subject: [PATCH 11/13] [Raid] Naxx grobbulus --- src/strategy/actions/MovementActions.cpp | 2 +- src/strategy/deathknight/DKActions.h | 2 ++ .../raids/naxxramas/RaidNaxxMultipliers.cpp | 12 ++++++++++ .../raids/naxxramas/RaidNaxxMultipliers.h | 24 ++++++++++++------- .../raids/naxxramas/RaidNaxxStrategy.cpp | 1 + 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 89257233..c0de3249 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/deathknight/DKActions.h b/src/strategy/deathknight/DKActions.h index e4907ac8..6106af18 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/raids/naxxramas/RaidNaxxMultipliers.cpp b/src/strategy/raids/naxxramas/RaidNaxxMultipliers.cpp index b22dc604..72ea08dd 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 4d80d566..8ac9e071 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 c58d8b32..0d640273 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)); From f0f176d66f70247761d55c3db506bfb56e218e3c Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 5 Jun 2024 19:45:21 +0800 Subject: [PATCH 12/13] [Log] Intialization log info --- src/PlayerbotFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 3b4277c6..b7655e74 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -178,8 +178,8 @@ void PlayerbotFactory::Randomize(bool incremental) // { // return; // } - - LOG_DEBUG("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_DEBUG("playerbots", "Resetting player..."); PerformanceMonitorOperation* pmo = sPerformanceMonitor->start(PERF_MON_RNDBOT, "PlayerbotFactory_Reset"); From 7d1e17f92fe68a3abf288db52589ae5d390c969b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 6 Jun 2024 00:14:25 +0800 Subject: [PATCH 13/13] [Crash fix] Unit in world check for manual set value --- src/strategy/Value.cpp | 8 ++++++++ src/strategy/Value.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/strategy/Value.cpp b/src/strategy/Value.cpp index 4f64319e..464e0d1f 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 9ab4b89a..9cba6efe 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