From 7cacca5293559e89700e3e4726db26fc312ec34d Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 24 Jun 2024 21:56:14 +0800 Subject: [PATCH 01/19] [Optimization] Better performance --- src/strategy/Engine.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/strategy/Engine.cpp b/src/strategy/Engine.cpp index 12328b6d..cef411c6 100644 --- a/src/strategy/Engine.cpp +++ b/src/strategy/Engine.cpp @@ -144,7 +144,7 @@ bool Engine::DoNextAction(Unit* unit, uint32 depth, bool minimal) ActionBasket* basket = nullptr; time_t currentTime = time(nullptr); - aiObjectContext->Update(); + // aiObjectContext->Update(); ProcessTriggers(minimal); PushDefaultActions(); @@ -469,7 +469,7 @@ bool Engine::HasStrategy(std::string const name) void Engine::ProcessTriggers(bool minimal) { - std::unordered_map fires; + // std::unordered_map fires; for (std::vector::iterator i = triggers.begin(); i != triggers.end(); i++) { TriggerNode* node = *i; @@ -499,21 +499,22 @@ void Engine::ProcessTriggers(bool minimal) if (!event) continue; - fires[trigger] = event; + // fires[trigger] = event; LogAction("T:%s", trigger->getName().c_str()); + MultiplyAndPush(node->getHandlers(), 0.0f, false, event, "trigger"); } } - for (std::vector::iterator i = triggers.begin(); i != triggers.end(); i++) - { - TriggerNode* node = *i; - Trigger* trigger = node->getTrigger(); - Event event = fires[trigger]; - if (!event) - continue; + // for (std::vector::iterator i = triggers.begin(); i != triggers.end(); i++) + // { + // TriggerNode* node = *i; + // Trigger* trigger = node->getTrigger(); + // if (fires.find(trigger) == fires.end()) + // continue; - MultiplyAndPush(node->getHandlers(), 0.0f, false, event, "trigger"); - } + // Event event = fires[trigger]; + + // } for (std::vector::iterator i = triggers.begin(); i != triggers.end(); i++) { From c950ea836e4fd54c7dd97ab546b91effee26364f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 24 Jun 2024 21:59:21 +0800 Subject: [PATCH 02/19] [Attack target] Ignore moon mark --- src/strategy/values/DpsTargetValue.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/strategy/values/DpsTargetValue.cpp b/src/strategy/values/DpsTargetValue.cpp index fc8f6ce1..05f6199b 100644 --- a/src/strategy/values/DpsTargetValue.cpp +++ b/src/strategy/values/DpsTargetValue.cpp @@ -71,6 +71,12 @@ 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; } @@ -138,6 +144,12 @@ 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; } @@ -193,6 +205,12 @@ 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; } From af5e5a3b071a64bf6f8befa67868349e38376281 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Mon, 24 Jun 2024 22:24:15 +0800 Subject: [PATCH 03/19] [Avoid aoe] Smarter position --- conf/playerbots.conf.dist | 2 +- src/strategy/actions/MovementActions.cpp | 74 +++++++++++++++++++++++- src/strategy/actions/MovementActions.h | 5 +- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 88cffdce..77c00a10 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -125,7 +125,7 @@ AiPlayerbot.MinEnchantingBotLevel = 60 AiPlayerbot.LimitEnchantExpansion = 1 # Randombots checking players gear score level and deny the group invite if it's too low -# Default: 1 (enabled) +# Default: 0 (disabled) AiPlayerbot.GearScoreCheck = 0 # Quest that will be completed and rewarded to all random bots diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 7ab12027..9eb05039 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1645,16 +1645,23 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() return false; } -bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name) +Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) { Unit* currentTarget = AI_VALUE(Unit*, "current target"); std::vector possibleAngles; if (currentTarget) { // Normally, move to left or right is the best position - float angleLeft = bot->GetAngle(currentTarget) + M_PI / 2; - float angleRight = bot->GetAngle(currentTarget) - M_PI / 2; + bool isTanking = (currentTarget->CanFreeMove()) && (currentTarget->GetVictim() == bot); + float angle = bot->GetAngle(currentTarget); + float angleLeft = angle + M_PI / 2; + float angleRight = angle - M_PI / 2; possibleAngles.push_back(angleLeft); possibleAngles.push_back(angleRight); + if (isTanking) { + possibleAngles.push_back(angle + M_PI); + possibleAngles.push_back(angle); + possibleAngles.push_back(bot->GetAngle(&pos) - M_PI); + } } else { float angleTo = bot->GetAngle(&pos) - M_PI; possibleAngles.push_back(angleTo); @@ -1673,6 +1680,67 @@ bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name) } } if (farestDis > 0.0f) { + return bestPos; + } + return Position(); +} + +Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) +{ + Unit* currentTarget = AI_VALUE(Unit*, "current target"); + std::vector possibleAngles; + float angleToTarget = 0.0f; + float angleFleeFromCenter = bot->GetAngle(&pos) - M_PI; + if (currentTarget) { + // Normally, move to left or right is the best position + angleToTarget = bot->GetAngle(currentTarget); + float angleLeft = angleToTarget + M_PI / 2; + float angleRight = angleToTarget - M_PI / 2; + possibleAngles.push_back(angleLeft); + possibleAngles.push_back(angleRight); + possibleAngles.push_back(angleToTarget + M_PI); + possibleAngles.push_back(angleToTarget); + possibleAngles.push_back(angleFleeFromCenter); + } else { + possibleAngles.push_back(angleFleeFromCenter); + } + float farestDis = 0.0f; + Position bestPos; + for (float &angle : possibleAngles) { + float fleeDis = sPlayerbotAIConfig->fleeDistance; + Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, + bot->GetPositionY() + sin(angle) * fleeDis, + bot->GetPositionZ()}; + // backward, flee + if (currentTarget && (angle == angleToTarget + M_PI || angle == angleFleeFromCenter) + && fleePos.GetExactDist(currentTarget) > sPlayerbotAIConfig->spellDistance) { + continue; + } + // forward, flee + if (currentTarget && (angle == angleToTarget || angle == angleFleeFromCenter) + && fleePos.GetExactDist(currentTarget) < (sPlayerbotAIConfig->tooCloseDistance + 5.0f)) { + continue; + } + if (pos.GetExactDist(fleePos) > farestDis) { + farestDis = pos.GetExactDist(fleePos); + bestPos = fleePos; + } + } + if (farestDis > 0.0f) { + return bestPos; + } + return Position(); +} + +bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name) +{ + Position bestPos; + if (botAI->IsMelee(bot)) { + bestPos = BestPositionForMelee(pos, radius); + } else if (botAI->IsRanged(bot)) { + bestPos = BestPositionForRanged(pos, radius); + } + if (bestPos != Position()) { if (MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(), false, false, true)) { if (sPlayerbotAIConfig->tellWhenAvoidAoe && lastTellTimer < time(NULL) - 10) { lastTellTimer = time(NULL); diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index c53bf25e..3cfdc685 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -78,9 +78,8 @@ class AvoidAoeAction : public MovementAction bool AvoidAuraWithDynamicObj(); bool AvoidGameObjectWithDamage(); bool AvoidUnitWithDamageAura(); - // Position PositionForTank(Position pos, float radius); - // Position PositionForMelee(Position pos, float radius); - // Position PositionForRanged(Position pos, float radius); + Position BestPositionForMelee(Position pos, float radius); + Position BestPositionForRanged(Position pos, float radius); bool FleePosition(Position pos, float radius, std::string name); time_t lastTellTimer = 0; }; From fb404b27a9ab0366897c594fdf5aaaab51309b17 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 26 Jun 2024 20:30:12 +0800 Subject: [PATCH 04/19] [Initialization] Glyphs remove and dual spec --- src/TravelMgr.cpp | 4 +++- src/strategy/actions/ChangeTalentsAction.cpp | 9 +++++++-- src/strategy/actions/ChatActionContext.h | 2 ++ src/strategy/actions/TrainerAction.cpp | 9 +++++++++ src/strategy/actions/TrainerAction.h | 7 +++++++ src/strategy/generic/ChatCommandHandlerStrategy.cpp | 1 + src/strategy/triggers/ChatTriggerContext.h | 2 ++ 7 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/TravelMgr.cpp b/src/TravelMgr.cpp index 755d1103..f010df99 100644 --- a/src/TravelMgr.cpp +++ b/src/TravelMgr.cpp @@ -1495,6 +1495,8 @@ void TravelTarget::setStatus(TravelStatus status) break; case TRAVEL_STATUS_COOLDOWN: statusTime = tDestination->getCooldownDelay(); + default: + break; } } @@ -3687,7 +3689,7 @@ void TravelMgr::LoadQuestTravelTable() } } else - "all"; + out << "all"; out << "\n"; } diff --git a/src/strategy/actions/ChangeTalentsAction.cpp b/src/strategy/actions/ChangeTalentsAction.cpp index e0f3b8db..69a6b19f 100644 --- a/src/strategy/actions/ChangeTalentsAction.cpp +++ b/src/strategy/actions/ChangeTalentsAction.cpp @@ -23,10 +23,15 @@ bool ChangeTalentsAction::Execute(Event event) if (param.find("help") != std::string::npos) { out << TalentsHelp(); } else if (param.find("switch") != std::string::npos) { - if (param.find("switch 1")) { + if (param.find("switch 1") != std::string::npos) { bot->ActivateSpec(0); out << "Active first talent"; - } else if (param.find("switch 2")) { + } else if (param.find("switch 2") != std::string::npos) { + if (bot->GetSpecsCount() == 1 && bot->GetLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL)) + { + bot->CastSpell(bot, 63680, true, nullptr, nullptr, bot->GetGUID()); + bot->CastSpell(bot, 63624, true, nullptr, nullptr, bot->GetGUID()); + } bot->ActivateSpec(1); out << "Active second talent"; } diff --git a/src/strategy/actions/ChatActionContext.h b/src/strategy/actions/ChatActionContext.h index 2930dae0..8fb48c64 100644 --- a/src/strategy/actions/ChatActionContext.h +++ b/src/strategy/actions/ChatActionContext.h @@ -115,6 +115,7 @@ class ChatActionContext : public NamedObjectContext creators["de"] = &ChatActionContext::dead; creators["trainer"] = &ChatActionContext::trainer; creators["maintenance"] = &ChatActionContext::maintenance; + creators["remove glyph"] = &ChatActionContext::remove_glyph; creators["autogear"] = &ChatActionContext::autogear; creators["equip upgrade"] = &ChatActionContext::equip_upgrade; creators["attack my target"] = &ChatActionContext::attack_my_target; @@ -215,6 +216,7 @@ class ChatActionContext : public NamedObjectContext static Action* attack_my_target(PlayerbotAI* botAI) { return new AttackMyTargetAction(botAI); } static Action* trainer(PlayerbotAI* botAI) { return new TrainerAction(botAI); } static Action* maintenance(PlayerbotAI* botAI) { return new MaintenanceAction(botAI); } + static Action* remove_glyph(PlayerbotAI* botAI) { return new RemoveGlyphAction(botAI); } static Action* autogear(PlayerbotAI* botAI) { return new AutoGearAction(botAI); } static Action* equip_upgrade(PlayerbotAI* botAI) { return new EquipUpgradeAction(botAI); } static Action* co(PlayerbotAI* botAI) { return new ChangeCombatStrategyAction(botAI); } diff --git a/src/strategy/actions/TrainerAction.cpp b/src/strategy/actions/TrainerAction.cpp index de3fea5d..2454e563 100644 --- a/src/strategy/actions/TrainerAction.cpp +++ b/src/strategy/actions/TrainerAction.cpp @@ -175,6 +175,15 @@ bool MaintenanceAction::Execute(Event event) return true; } +bool RemoveGlyphAction::Execute(Event event) +{ + for (uint32 slotIndex = 0; slotIndex < MAX_GLYPH_SLOT_INDEX; ++slotIndex) + { + bot->SetGlyph(slotIndex, 0, true); + } + return true; +} + bool AutoGearAction::Execute(Event event) { if (!sPlayerbotAIConfig->autoGearCommand) { diff --git a/src/strategy/actions/TrainerAction.h b/src/strategy/actions/TrainerAction.h index ea1f6e66..5ea6300c 100644 --- a/src/strategy/actions/TrainerAction.h +++ b/src/strategy/actions/TrainerAction.h @@ -35,6 +35,13 @@ class MaintenanceAction : public Action bool Execute(Event event) override; }; +class RemoveGlyphAction : public Action +{ + public: + RemoveGlyphAction(PlayerbotAI* botAI) : Action(botAI, "remove glyph") { } + bool Execute(Event event) override; +}; + class AutoGearAction : public Action { public: diff --git a/src/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/strategy/generic/ChatCommandHandlerStrategy.cpp index bbb1c1a4..4da74e5b 100644 --- a/src/strategy/generic/ChatCommandHandlerStrategy.cpp +++ b/src/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -89,6 +89,7 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas supported.push_back("de"); supported.push_back("trainer"); supported.push_back("maintenance"); + supported.push_back("remove glyph"); supported.push_back("autogear"); supported.push_back("equip upgrade"); supported.push_back("chat"); diff --git a/src/strategy/triggers/ChatTriggerContext.h b/src/strategy/triggers/ChatTriggerContext.h index c0721390..af52cd7e 100644 --- a/src/strategy/triggers/ChatTriggerContext.h +++ b/src/strategy/triggers/ChatTriggerContext.h @@ -55,6 +55,7 @@ class ChatTriggerContext : public NamedObjectContext creators["de"] = &ChatTriggerContext::dead; creators["trainer"] = &ChatTriggerContext::trainer; creators["maintenance"] = &ChatTriggerContext::maintenance; + creators["remove glyph"] = &ChatTriggerContext::remove_glyph; creators["autogear"] = &ChatTriggerContext::autogear; creators["equip upgrade"] = &ChatTriggerContext::equip_upgrade; creators["attack"] = &ChatTriggerContext::attack; @@ -168,6 +169,7 @@ class ChatTriggerContext : public NamedObjectContext static Trigger* attack(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "attack"); } static Trigger* trainer(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "trainer"); } static Trigger* maintenance(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "maintenance"); } + static Trigger* remove_glyph(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "remove glyph"); } static Trigger* autogear(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "autogear"); } static Trigger* equip_upgrade(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "equip upgrade"); } static Trigger* co(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "co"); } From 0615e6082bca70cd7cd6d5bf2cb9b4f02674a760 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 26 Jun 2024 20:46:38 +0800 Subject: [PATCH 05/19] [Configuration] Enable avoid aoe by default --- conf/playerbots.conf.dist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 77c00a10..2e60259f 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -338,8 +338,8 @@ AiPlayerbot.AutoSaveMana = 1 AiPlayerbot.SaveManaThreshold = 60 # Enable auto avoid aoe (experimental) -# Default: 0 (disable) -AiPlayerbot.AutoAvoidAoe = 0 +# Default: 1 (enable) +AiPlayerbot.AutoAvoidAoe = 1 # Tell which spell is avoiding (experimental) # Default: 1 (enable) From e91debc330a1c0ea25503b1de8804dd73858bdf4 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 26 Jun 2024 22:08:04 +0800 Subject: [PATCH 06/19] [Configuration] Enable avoid aoe by default --- src/PlayerbotAIConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 87b85830..c3892b91 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -91,7 +91,7 @@ bool PlayerbotAIConfig::Initialize() mediumMana = sConfigMgr->GetOption("AiPlayerbot.MediumMana", 40); autoSaveMana = sConfigMgr->GetOption("AiPlayerbot.AutoSaveMana", true); saveManaThreshold = sConfigMgr->GetOption("AiPlayerbot.SaveManaThreshold", 60); - autoAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.AutoAvoidAoe", false); + autoAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.AutoAvoidAoe", true); tellWhenAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.TellWhenAvoidAoe", true); randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.15f); From d8badd453284f039be19a31291d3f73fc03fb8ef Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 26 Jun 2024 23:44:40 +0800 Subject: [PATCH 07/19] [Avoid aoe] Fix avoid aoe position --- src/strategy/actions/MovementActions.cpp | 8 +++----- src/strategy/values/AoeValues.cpp | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 9eb05039..67cb4902 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1711,13 +1711,11 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; - // backward, flee - if (currentTarget && (angle == angleToTarget + M_PI || angle == angleFleeFromCenter) + if (currentTarget // && (angle == angleToTarget + M_PI || angle == angleFleeFromCenter) && fleePos.GetExactDist(currentTarget) > sPlayerbotAIConfig->spellDistance) { continue; } - // forward, flee - if (currentTarget && (angle == angleToTarget || angle == angleFleeFromCenter) + if (currentTarget // && (angle == angleToTarget || angle == angleFleeFromCenter) && fleePos.GetExactDist(currentTarget) < (sPlayerbotAIConfig->tooCloseDistance + 5.0f)) { continue; } @@ -1737,7 +1735,7 @@ bool AvoidAoeAction::FleePosition(Position pos, float radius, std::string name) Position bestPos; if (botAI->IsMelee(bot)) { bestPos = BestPositionForMelee(pos, radius); - } else if (botAI->IsRanged(bot)) { + } else { bestPos = BestPositionForRanged(pos, radius); } if (bestPos != Position()) { diff --git a/src/strategy/values/AoeValues.cpp b/src/strategy/values/AoeValues.cpp index b27fc307..e3f44bb2 100644 --- a/src/strategy/values/AoeValues.cpp +++ b/src/strategy/values/AoeValues.cpp @@ -125,7 +125,8 @@ Aura* AreaDebuffValue::Calculate() Unit::AuraEffectList const& aurasPeriodicDamagePercent = bot->GetAuraEffectsByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT); Unit::AuraEffectList const& aurasPeriodicTriggerSpell = bot->GetAuraEffectsByType(SPELL_AURA_PERIODIC_TRIGGER_SPELL); Unit::AuraEffectList const& aurasPeriodicTriggerWithValueSpell = bot->GetAuraEffectsByType(SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE); - for (const Unit::AuraEffectList& list : {aurasPeriodicDamage, aurasPeriodicDamagePercent, aurasPeriodicTriggerSpell, aurasPeriodicTriggerWithValueSpell}) { + Unit::AuraEffectList const& aurasDummy = bot->GetAuraEffectsByType(SPELL_AURA_DUMMY); + for (const Unit::AuraEffectList& list : {aurasPeriodicDamage, aurasPeriodicDamagePercent, aurasPeriodicTriggerSpell, aurasPeriodicTriggerWithValueSpell, aurasDummy}) { for (auto i = list.begin(); i != list.end(); ++i) { AuraEffect* aurEff = *i; From 10527eed2a3499dd7f3826fa61571d4c8238c514 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 26 Jun 2024 23:54:40 +0800 Subject: [PATCH 08/19] [Log] Better bot teleport info --- src/RandomPlayerbotMgr.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 1c320ebd..4d6295b7 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1190,6 +1190,10 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& AreaTableEntry const* zone = sAreaTableStore.LookupEntry(map->GetZoneId(bot->GetPhaseMask(), x, y, z)); if (!zone) continue; + + AreaTableEntry const* area = sAreaTableStore.LookupEntry(map->GetAreaId(bot->GetPhaseMask(), x, y, z)); + if (!area) + continue; // Do not teleport to enemy zones if level is low if (zone->team == 4 && bot->GetTeamId() == TEAM_ALLIANCE) @@ -1218,9 +1222,14 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& if (bot->GetLevel() <= 18 && (loc.GetMapId() != pInfo->mapId || dis > 10000.0f)) { continue; } - - LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to {} {},{},{} ({}/{} locations)", - bot->GetName().c_str(), bot->GetLevel(), zone->area_name[0], x, y, z, i + 1, tlocs.size()); + LocaleConstant locale = sWorld->GetDefaultDbcLocale(); + + LOG_INFO("playerbots", "Random teleporting bot {} (level {}) to Map: {} ({}) Zone: {} ({}) Area: {} ({}) {},{},{} ({}/{} locations)", + bot->GetName().c_str(), bot->GetLevel(), + map->GetId(), map->GetMapName(), + zone->ID, zone->area_name[locale], + area->ID, area->area_name[locale], + x, y, z, i + 1, tlocs.size()); if (hearth) { From 009be18646b5acb7c0b126ee9d79a14f6d6cf9a9 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 27 Jun 2024 23:30:04 +0800 Subject: [PATCH 09/19] [Configuration] Fixed level --- conf/playerbots.conf.dist | 4 ++++ src/PlayerbotAIConfig.cpp | 1 + src/PlayerbotAIConfig.h | 1 + src/RandomItemMgr.cpp | 3 +++ src/strategy/actions/XpGainAction.cpp | 6 ++++++ 5 files changed, 15 insertions(+) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 2e60259f..fa867e68 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -97,6 +97,10 @@ AiPlayerbot.SummonWhenGroup = 1 AiPlayerbot.RandomBotShowHelmet = 1 AiPlayerbot.RandomBotShowCloak = 1 +# Fix the level of random bot (won't level up by grinding) +# Default: 0 (disable) +AiPlayerbot.RandomBotFixedLevel = 0 + # Disable random levels for randombots # Every bots started on the specified level and level up by killing mobs. AiPlayerbot.DisableRandomLevels = 0 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index c3892b91..96142144 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -265,6 +265,7 @@ bool PlayerbotAIConfig::Initialize() // SPP switches enableGreet = sConfigMgr->GetOption("AiPlayerbot.EnableGreet", true); summonWhenGroup = sConfigMgr->GetOption("AiPlayerbot.SummonWhenGroup", true); + randomBotFixedLevel = sConfigMgr->GetOption("AiPlayerbot.RandomBotFixedLevel", false); disableRandomLevels = sConfigMgr->GetOption("AiPlayerbot.DisableRandomLevels", false); randomBotRandomPassword = sConfigMgr->GetOption("AiPlayerbot.RandomBotRandomPassword", true); downgradeMaxLevelBot = sConfigMgr->GetOption("AiPlayerbot.DowngradeMaxLevelBot", true); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index 5356bc49..cc5e72be 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -174,6 +174,7 @@ class PlayerbotAIConfig bool summonWhenGroup; bool randomBotShowHelmet; bool randomBotShowCloak; + bool randomBotFixedLevel; bool disableRandomLevels; uint32 playerbotsXPrate; bool disableDeathKnightLogin; diff --git a/src/RandomItemMgr.cpp b/src/RandomItemMgr.cpp index f2ff7bcb..d909b4b0 100644 --- a/src/RandomItemMgr.cpp +++ b/src/RandomItemMgr.cpp @@ -2159,6 +2159,9 @@ void RandomItemMgr::BuildEquipCacheNew() if (IsTestItem(itemId)) { continue; } + if (itemId == 22784) { // Sunwell Orb + continue; + } equipCacheNew[proto->RequiredLevel][proto->InventoryType].push_back(itemId); } } diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index fbf313cb..a82eacff 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -4,12 +4,18 @@ #include "XpGainAction.h" #include "Event.h" +#include "PlayerbotAIConfig.h" #include "Playerbots.h" bool XpGainAction::Execute(Event event) { context->GetValue("death count")->Set(0); + if (sPlayerbotAIConfig->randomBotFixedLevel) { + bot->SetUInt32Value(PLAYER_XP, 0); + return true; + } + if (!sRandomPlayerbotMgr->IsRandomBot(bot) || sPlayerbotAIConfig->playerbotsXPrate == 1) return true; From 0129788ea3bb6785644cfe894c8b436ab998c850 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 27 Jun 2024 23:31:36 +0800 Subject: [PATCH 10/19] [Configuration] Fixed level --- src/strategy/actions/XpGainAction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index a82eacff..c446780f 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -11,11 +11,11 @@ bool XpGainAction::Execute(Event event) { context->GetValue("death count")->Set(0); - if (sPlayerbotAIConfig->randomBotFixedLevel) { + if (sRandomPlayerbotMgr->IsRandomBot(bot) && sPlayerbotAIConfig->randomBotFixedLevel) { bot->SetUInt32Value(PLAYER_XP, 0); return true; } - + if (!sRandomPlayerbotMgr->IsRandomBot(bot) || sPlayerbotAIConfig->playerbotsXPrate == 1) return true; From 7395acb660760877e841a3078008779db19490c1 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 27 Jun 2024 23:39:54 +0800 Subject: [PATCH 11/19] [Configuration] Random bots fixed level --- src/PlayerbotMgr.cpp | 6 ++++++ src/strategy/actions/XpGainAction.cpp | 5 ----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index 97659583..ea239ca5 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -448,6 +448,12 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) uint32 accountId = bot->GetSession()->GetAccountId(); bool isRandomAccount = sPlayerbotAIConfig->IsInRandomAccountList(accountId); + if (isRandomAccount && sPlayerbotAIConfig->randomBotFixedLevel) { + bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); + } else { + bot->RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); + } + bot->SaveToDB(false, false); if (master && isRandomAccount && master->GetLevel() < bot->GetLevel()) { // PlayerbotFactory factory(bot, master->getLevel()); diff --git a/src/strategy/actions/XpGainAction.cpp b/src/strategy/actions/XpGainAction.cpp index c446780f..31322360 100644 --- a/src/strategy/actions/XpGainAction.cpp +++ b/src/strategy/actions/XpGainAction.cpp @@ -11,11 +11,6 @@ bool XpGainAction::Execute(Event event) { context->GetValue("death count")->Set(0); - if (sRandomPlayerbotMgr->IsRandomBot(bot) && sPlayerbotAIConfig->randomBotFixedLevel) { - bot->SetUInt32Value(PLAYER_XP, 0); - return true; - } - if (!sRandomPlayerbotMgr->IsRandomBot(bot) || sPlayerbotAIConfig->playerbotsXPrate == 1) return true; From 6abc8d51e972991874c01629dbeec1067d5fe100 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 28 Jun 2024 20:09:04 +0800 Subject: [PATCH 12/19] [Attack target] Valid target check --- src/strategy/values/AttackersValue.cpp | 21 ++++++--------------- src/strategy/values/InvalidTargetValue.cpp | 4 +--- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index 41ff417e..7ae853be 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -104,7 +104,7 @@ void AttackersValue::RemoveNonThreating(std::unordered_set& targets) for(std::unordered_set::iterator tIter = targets.begin(); tIter != targets.end();) { Unit* unit = *tIter; - if(bot->GetMapId() != unit->GetMapId() || !hasRealThreat(unit) || !IsValidTarget(unit, bot) || !bot->IsWithinLOSInMap(unit)) + if(bot->GetMapId() != unit->GetMapId() || !hasRealThreat(unit) || !IsValidTarget(unit, bot)) { std::unordered_set::iterator tIter2 = tIter; ++tIter; @@ -113,15 +113,6 @@ void AttackersValue::RemoveNonThreating(std::unordered_set& targets) else ++tIter; } - // Unit* unit = *tIter; - // if (!IsValidTarget(unit, bot) || !bot->IsWithinLOSInMap(unit)) - // { - // std::unordered_set::iterator tIter2 = tIter; - // ++tIter; - // targets.erase(tIter2); - // } - // else - // ++tIter; } bool AttackersValue::hasRealThreat(Unit *attacker) @@ -160,7 +151,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range) // bool inCannon = botAI->IsInVehicle(false, true); // bool enemy = botAI->GetAiObjectContext()->GetValue("enemy player target")->Get(); - return attacker && + return attacker && attacker->IsVisible() && attacker->IsInWorld() && attacker->GetMapId() == bot->GetMapId() && !attacker->isDead() && @@ -183,10 +174,10 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range) bool AttackersValue::IsValidTarget(Unit *attacker, Player *bot) { - return attacker->IsVisible() && - IsPossibleTarget(attacker, bot) && - (attacker->GetThreatMgr().getCurrentVictim() || attacker->GetGuidValue(UNIT_FIELD_TARGET) || - attacker->GetGUID().IsPlayer() || attacker->GetGUID() == GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("pull target")->Get()); + return bot->IsWithinLOSInMap(attacker) && + IsPossibleTarget(attacker, bot); + // (attacker->GetThreatMgr().getCurrentVictim() || attacker->GetGuidValue(UNIT_FIELD_TARGET) || + // attacker->GetGUID().IsPlayer() || attacker->GetGUID() == GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("pull target")->Get()); } bool PossibleAddsValue::Calculate() diff --git a/src/strategy/values/InvalidTargetValue.cpp b/src/strategy/values/InvalidTargetValue.cpp index d2499c52..c940424a 100644 --- a/src/strategy/values/InvalidTargetValue.cpp +++ b/src/strategy/values/InvalidTargetValue.cpp @@ -27,9 +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); + !AttackersValue::IsValidTarget(target, bot); } return !target; From 3556a38dcdd155473b468db2c7f840b0cd944517 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 28 Jun 2024 20:14:22 +0800 Subject: [PATCH 13/19] [Initialization] Ammo init --- src/PlayerbotFactory.cpp | 5 ++--- src/PlayerbotMgr.cpp | 2 +- src/RandomItemMgr.cpp | 10 ++++------ src/RandomPlayerbotMgr.cpp | 4 +--- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 1512046d..10fc482b 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -2502,8 +2502,7 @@ void PlayerbotFactory::InitAmmo() case ITEM_SUBCLASS_WEAPON_CROSSBOW: subClass = ITEM_SUBCLASS_ARROW; break; - case ITEM_SUBCLASS_WEAPON_THROWN: - subClass = ITEM_SUBCLASS_THROWN; + default: break; } @@ -2516,7 +2515,7 @@ void PlayerbotFactory::InitAmmo() if (count < maxCount / 2) { - if (Item* newItem = StoreNewItemInInventorySlot(bot, entry, maxCount / 2)) { + if (Item* newItem = StoreNewItemInInventorySlot(bot, entry, maxCount)) { newItem->AddToUpdateQueueOf(bot); } } diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index ea239ca5..099350f2 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -450,7 +450,7 @@ void PlayerbotHolder::OnBotLogin(Player* const bot) if (isRandomAccount && sPlayerbotAIConfig->randomBotFixedLevel) { bot->SetPlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); - } else { + } else if (isRandomAccount && !sPlayerbotAIConfig->randomBotFixedLevel) { bot->RemovePlayerFlag(PLAYER_FLAGS_NO_XP_GAIN); } diff --git a/src/RandomItemMgr.cpp b/src/RandomItemMgr.cpp index d909b4b0..e02b865b 100644 --- a/src/RandomItemMgr.cpp +++ b/src/RandomItemMgr.cpp @@ -2202,9 +2202,7 @@ RandomItemList RandomItemMgr::Query(uint32 level, uint8 clazz, uint8 slot, uint3 void RandomItemMgr::BuildAmmoCache() { - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; - if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); + uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); LOG_INFO("server.loading", "Building ammo cache for {} levels", maxLevel); @@ -2241,9 +2239,9 @@ uint32 RandomItemMgr::GetAmmo(uint32 level, uint32 subClass) void RandomItemMgr::BuildPotionCache() { - uint32 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; - if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); + uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); + // if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + // maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); LOG_INFO("server.loading", "Building potion cache for {} levels", maxLevel); diff --git a/src/RandomPlayerbotMgr.cpp b/src/RandomPlayerbotMgr.cpp index 4d6295b7..334b6499 100644 --- a/src/RandomPlayerbotMgr.cpp +++ b/src/RandomPlayerbotMgr.cpp @@ -1257,9 +1257,7 @@ void RandomPlayerbotMgr::RandomTeleport(Player* bot, std::vector& void RandomPlayerbotMgr::PrepareTeleportCache() { - uint8 maxLevel = sPlayerbotAIConfig->randomBotMaxLevel; - if (maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) - maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); + uint32 maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL); LOG_INFO("playerbots", "Preparing random teleport caches for {} levels...", maxLevel); From 4661715fcae05ef22cfec78b884c111464797624 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 28 Jun 2024 20:16:29 +0800 Subject: [PATCH 14/19] [Optimization] Valid target check order --- src/strategy/values/AttackersValue.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index 7ae853be..527b8def 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -174,8 +174,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range) bool AttackersValue::IsValidTarget(Unit *attacker, Player *bot) { - return bot->IsWithinLOSInMap(attacker) && - IsPossibleTarget(attacker, bot); + return IsPossibleTarget(attacker, bot) && bot->IsWithinLOSInMap(attacker); // (attacker->GetThreatMgr().getCurrentVictim() || attacker->GetGuidValue(UNIT_FIELD_TARGET) || // attacker->GetGUID().IsPlayer() || attacker->GetGUID() == GET_PLAYERBOT_AI(bot)->GetAiObjectContext()->GetValue("pull target")->Get()); } From b9b4362bdd90cd52adf5364ec50872ad8c152ae2 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 28 Jun 2024 20:26:41 +0800 Subject: [PATCH 15/19] [Initialization] Ammo amount --- src/PlayerbotFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 10fc482b..69efb9f6 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -2515,7 +2515,7 @@ void PlayerbotFactory::InitAmmo() if (count < maxCount / 2) { - if (Item* newItem = StoreNewItemInInventorySlot(bot, entry, maxCount)) { + if (Item* newItem = StoreNewItemInInventorySlot(bot, entry, maxCount / 2)) { newItem->AddToUpdateQueueOf(bot); } } From 55515f0ec579462b5704cea78f7e599a395f3605 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 29 Jun 2024 21:57:28 +0800 Subject: [PATCH 16/19] [Avoid aoe] Position selection --- src/PlayerbotFactory.cpp | 14 ++++-- src/strategy/actions/ChatShortcutActions.cpp | 1 + src/strategy/actions/MovementActions.cpp | 49 +++++++++++-------- src/strategy/actions/MovementActions.h | 4 ++ .../actions/UseMeetingStoneAction.cpp | 4 +- 5 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 69efb9f6..ec9d5729 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -2511,7 +2511,7 @@ void PlayerbotFactory::InitAmmo() uint32 entry = sRandomItemMgr->GetAmmo(level, subClass); uint32 count = bot->GetItemCount(entry); - uint32 maxCount = 5000; + uint32 maxCount = 6000; if (count < maxCount / 2) { @@ -3878,10 +3878,9 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) score *= 0.1; } // spec with double hand - // fury with titan's grip, fury without duel wield, arms, bear, retribution, blood dk - if (isDoubleHand && - ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && bot->CanTitanGrip()) || - (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !bot->CanDualWield()) || + // fury without duel wield, arms, bear, retribution, blood dk + if (isDoubleHand && + ((cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && !bot->CanDualWield()) || (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_ARMS) || (cls == CLASS_DRUID && tab == 1) || (cls == CLASS_PALADIN && tab == 2) || @@ -3889,6 +3888,11 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) (cls == CLASS_SHAMAN && tab == 1 && !bot->CanDualWield()))) { score *= 10; } + // fury with titan's grip + if (isDoubleHand && proto->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM && + (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && bot->CanTitanGrip())) { + score *= 0.1; + } } if (proto->Class == ITEM_CLASS_WEAPON) { if (cls == CLASS_HUNTER && proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN) { diff --git a/src/strategy/actions/ChatShortcutActions.cpp b/src/strategy/actions/ChatShortcutActions.cpp index 92e259fd..be1c4496 100644 --- a/src/strategy/actions/ChatShortcutActions.cpp +++ b/src/strategy/actions/ChatShortcutActions.cpp @@ -33,6 +33,7 @@ bool FollowChatShortcutAction::Execute(Event event) 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({}); PositionMap& posMap = context->GetValue("position")->Get(); PositionInfo pos = posMap["return"]; diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 67cb4902..5c9afbb4 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1648,32 +1648,37 @@ bool AvoidAoeAction::AvoidUnitWithDamageAura() Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) { Unit* currentTarget = AI_VALUE(Unit*, "current target"); - std::vector possibleAngles; + std::vector possibleAngles; if (currentTarget) { // Normally, move to left or right is the best position bool isTanking = (currentTarget->CanFreeMove()) && (currentTarget->GetVictim() == bot); float angle = bot->GetAngle(currentTarget); float angleLeft = angle + M_PI / 2; float angleRight = angle - M_PI / 2; - possibleAngles.push_back(angleLeft); - possibleAngles.push_back(angleRight); + possibleAngles.push_back({angleLeft, false}); + possibleAngles.push_back({angleRight, false}); + possibleAngles.push_back({angle, true}); if (isTanking) { - possibleAngles.push_back(angle + M_PI); - possibleAngles.push_back(angle); - possibleAngles.push_back(bot->GetAngle(&pos) - M_PI); + possibleAngles.push_back({angle + M_PI, false}); + possibleAngles.push_back({bot->GetAngle(&pos) - M_PI, false}); } } else { float angleTo = bot->GetAngle(&pos) - M_PI; - possibleAngles.push_back(angleTo); + possibleAngles.push_back({angleTo, false}); } float farestDis = 0.0f; Position bestPos; - for (float &angle : possibleAngles) { + for (CheckAngle &checkAngle : possibleAngles) { + float angle = checkAngle.angle; + bool strict = checkAngle.strict; float fleeDis = sPlayerbotAIConfig->fleeDistance; Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; - // todo (Yunfan): check carefully + if (strict && currentTarget + && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->tooCloseDistance) { + continue; + } if (pos.GetExactDist(fleePos) > farestDis) { farestDis = pos.GetExactDist(fleePos); bestPos = fleePos; @@ -1688,7 +1693,7 @@ Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) { Unit* currentTarget = AI_VALUE(Unit*, "current target"); - std::vector possibleAngles; + std::vector possibleAngles; float angleToTarget = 0.0f; float angleFleeFromCenter = bot->GetAngle(&pos) - M_PI; if (currentTarget) { @@ -1696,27 +1701,29 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) angleToTarget = bot->GetAngle(currentTarget); float angleLeft = angleToTarget + M_PI / 2; float angleRight = angleToTarget - M_PI / 2; - possibleAngles.push_back(angleLeft); - possibleAngles.push_back(angleRight); - possibleAngles.push_back(angleToTarget + M_PI); - possibleAngles.push_back(angleToTarget); - possibleAngles.push_back(angleFleeFromCenter); + possibleAngles.push_back({angleLeft, false}); + possibleAngles.push_back({angleRight, false}); + possibleAngles.push_back({angleToTarget + M_PI, true}); + possibleAngles.push_back({angleToTarget, true}); + possibleAngles.push_back({angleFleeFromCenter, true}); } else { - possibleAngles.push_back(angleFleeFromCenter); + possibleAngles.push_back({angleFleeFromCenter, false}); } float farestDis = 0.0f; Position bestPos; - for (float &angle : possibleAngles) { + for (CheckAngle &checkAngle : possibleAngles) { + float angle = checkAngle.angle; + bool strict = checkAngle.strict; float fleeDis = sPlayerbotAIConfig->fleeDistance; Position fleePos{bot->GetPositionX() + cos(angle) * fleeDis, bot->GetPositionY() + sin(angle) * fleeDis, bot->GetPositionZ()}; - if (currentTarget // && (angle == angleToTarget + M_PI || angle == angleFleeFromCenter) - && fleePos.GetExactDist(currentTarget) > sPlayerbotAIConfig->spellDistance) { + if (strict && currentTarget + && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() > sPlayerbotAIConfig->spellDistance) { continue; } - if (currentTarget // && (angle == angleToTarget || angle == angleFleeFromCenter) - && fleePos.GetExactDist(currentTarget) < (sPlayerbotAIConfig->tooCloseDistance + 5.0f)) { + if (strict && currentTarget + && fleePos.GetExactDist(currentTarget) - currentTarget->GetCombatReach() < (sPlayerbotAIConfig->tooCloseDistance)) { continue; } if (pos.GetExactDist(fleePos) > farestDis) { diff --git a/src/strategy/actions/MovementActions.h b/src/strategy/actions/MovementActions.h index 3cfdc685..f26991a4 100644 --- a/src/strategy/actions/MovementActions.h +++ b/src/strategy/actions/MovementActions.h @@ -82,6 +82,10 @@ class AvoidAoeAction : public MovementAction Position BestPositionForRanged(Position pos, float radius); bool FleePosition(Position pos, float radius, std::string name); time_t lastTellTimer = 0; + struct CheckAngle { + float angle; + bool strict; + }; }; class RunAwayAction : public MovementAction diff --git a/src/strategy/actions/UseMeetingStoneAction.cpp b/src/strategy/actions/UseMeetingStoneAction.cpp index 422fc3e9..3ef46e21 100644 --- a/src/strategy/actions/UseMeetingStoneAction.cpp +++ b/src/strategy/actions/UseMeetingStoneAction.cpp @@ -81,8 +81,10 @@ bool SummonAction::Execute(Event event) pet->GetCharmInfo()->IsReturning(); } - if (master->GetSession()->GetSecurity() >= SEC_PLAYER) + if (master->GetSession()->GetSecurity() >= SEC_PLAYER) { + botAI->GetAiObjectContext()->GetValue("prioritized targets")->Set({}); return Teleport(master, bot); + } if (SummonUsingGos(master, bot) || SummonUsingNpcs(master, bot)) { From ca9981bfbed1f999757136243fd6bb5c5a51ccd7 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 29 Jun 2024 22:30:53 +0800 Subject: [PATCH 17/19] [Initialization] Titan's grip for fury warrior --- src/PlayerbotFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index ec9d5729..d4cf2b7d 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -3891,7 +3891,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) // fury with titan's grip if (isDoubleHand && proto->SubClass != ITEM_SUBCLASS_WEAPON_POLEARM && (cls == CLASS_WARRIOR && tab == WARRIOR_TAB_FURY && bot->CanTitanGrip())) { - score *= 0.1; + score *= 10; } } if (proto->Class == ITEM_CLASS_WEAPON) { From 3008087833e8122455c3c3a9d6d16feb3d458e1f Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 30 Jun 2024 00:03:49 +0800 Subject: [PATCH 18/19] [Warnings] Fix double to float --- src/strategy/actions/MovementActions.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/strategy/actions/MovementActions.cpp b/src/strategy/actions/MovementActions.cpp index 5c9afbb4..f2652168 100644 --- a/src/strategy/actions/MovementActions.cpp +++ b/src/strategy/actions/MovementActions.cpp @@ -1653,17 +1653,17 @@ Position AvoidAoeAction::BestPositionForMelee(Position pos, float radius) // Normally, move to left or right is the best position bool isTanking = (currentTarget->CanFreeMove()) && (currentTarget->GetVictim() == bot); float angle = bot->GetAngle(currentTarget); - float angleLeft = angle + M_PI / 2; - float angleRight = angle - M_PI / 2; + float angleLeft = angle + (float)M_PI / 2; + float angleRight = angle - (float)M_PI / 2; possibleAngles.push_back({angleLeft, false}); possibleAngles.push_back({angleRight, false}); possibleAngles.push_back({angle, true}); if (isTanking) { - possibleAngles.push_back({angle + M_PI, false}); - possibleAngles.push_back({bot->GetAngle(&pos) - M_PI, false}); + possibleAngles.push_back({angle + (float)M_PI, false}); + possibleAngles.push_back({bot->GetAngle(&pos) - (float)M_PI, false}); } } else { - float angleTo = bot->GetAngle(&pos) - M_PI; + float angleTo = bot->GetAngle(&pos) - (float)M_PI; possibleAngles.push_back({angleTo, false}); } float farestDis = 0.0f; @@ -1695,15 +1695,15 @@ Position AvoidAoeAction::BestPositionForRanged(Position pos, float radius) Unit* currentTarget = AI_VALUE(Unit*, "current target"); std::vector possibleAngles; float angleToTarget = 0.0f; - float angleFleeFromCenter = bot->GetAngle(&pos) - M_PI; + float angleFleeFromCenter = bot->GetAngle(&pos) - (float)M_PI; if (currentTarget) { // Normally, move to left or right is the best position angleToTarget = bot->GetAngle(currentTarget); - float angleLeft = angleToTarget + M_PI / 2; - float angleRight = angleToTarget - M_PI / 2; + float angleLeft = angleToTarget + (float)M_PI / 2; + float angleRight = angleToTarget - (float)M_PI / 2; possibleAngles.push_back({angleLeft, false}); possibleAngles.push_back({angleRight, false}); - possibleAngles.push_back({angleToTarget + M_PI, true}); + possibleAngles.push_back({angleToTarget + (float)M_PI, true}); possibleAngles.push_back({angleToTarget, true}); possibleAngles.push_back({angleFleeFromCenter, true}); } else { From f56bbdf9e866b55c203ccbfa1d744d987204424e Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Wed, 3 Jul 2024 16:03:05 +0800 Subject: [PATCH 19/19] [Readme] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 02e557b0..c7e70bd7 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ Welcome to the Playerbots Module for AzerothCore, a work in progress project bas If you encounter any errors or experience crashes, we kindly request that you report them as GitHub issues. Your valuable feedback will help us improve and enhance this project collaboratively. +You can also get more information in our [discord](https://discord.gg/NQm5QShwf9). + ## Installation Please note that this module requires specific custom changes to AzerothCore. To ensure compatibility, you must compile it with a custom branch from my fork, which can be found here: [liyunfan1223/azerothcore-wotlk/tree/Playerbot](https://github.com/liyunfan1223/azerothcore-wotlk/tree/Playerbot). @@ -48,7 +50,9 @@ It's essential to note that there is still a significant amount of work to be do ## Addon -For enhanced control over the bots and to simplify command usage, you can also make use of our addon: [Unbot Addon](https://github.com/liyunfan1223/unbot-addon). Currently, this addon offers better support only for Simplified Chinese client. +For enhanced control over the bots and to simplify command usage, you can also make use of our addon: +- Chinese version: [Unbot Addon (zh)](https://github.com/liyunfan1223/unbot-addon). +- English version (maintained by @Revision): [Unbot Addon (en)](https://github.com/noisiver/unbot-addon/tree/english). ## Frequently Asked Questions