From 3881d7054b6e28250b46683b8fc8172bdd56c808 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Tue, 9 Jul 2024 23:09:21 +0800 Subject: [PATCH 01/13] [Crash fix] Fix crash caused by duplicate login --- src/PlayerbotMgr.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PlayerbotMgr.cpp b/src/PlayerbotMgr.cpp index bd004267..1de95c56 100644 --- a/src/PlayerbotMgr.cpp +++ b/src/PlayerbotMgr.cpp @@ -74,6 +74,12 @@ void PlayerbotHolder::AddPlayerBot(ObjectGuid playerGuid, uint32 masterAccountId void PlayerbotHolder::HandlePlayerBotLoginCallback(PlayerbotLoginQueryHolder const& holder) { + // has bot already been added? + Player* loginBot = ObjectAccessor::FindConnectedPlayer(holder.GetGuid()); + if (loginBot && loginBot->IsInWorld()) { + return; + } + uint32 botAccountId = holder.GetAccountId(); WorldSession* botSession = new WorldSession(botAccountId, "", nullptr, SEC_PLAYER, EXPANSION_WRATH_OF_THE_LICH_KING, time_t(0), LOCALE_enUS, 0, false, false, 0, true); From 80b7f18841b91df6d8c759957a1fc3f842222c6b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 11:28:01 +0800 Subject: [PATCH 02/13] [Misc] Cat druid equip score calculation --- src/PlayerbotFactory.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 82ad1279..d9f29740 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -3821,6 +3821,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) score += (agility + strength + intellect + spirit + stamina + defense + dodge + parry + block + resilience + hit + crit + haste + expertise + attack_power + mana_regeneration + spell_power + armor_penetration + spell_penetration + armor + rangeDps + meleeDps) * 0.001; + // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; @@ -3840,7 +3841,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) ) { // HEALER score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; - } else if (cls == CLASS_ROGUE) { + } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution @@ -4242,6 +4243,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) float score = (agility + strength + intellect + spirit + stamina + defense + dodge + parry + block + resilience + hit + crit + haste + expertise + attack_power + mana_regeneration + spell_power + armor_penetration + spell_penetration + armor + dps) * 0.001; + // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; @@ -4261,7 +4263,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) ) { // HEALER score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1; - } else if (cls == CLASS_ROGUE) { + } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution @@ -4521,6 +4523,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 } } float score = 0; + // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; @@ -4540,7 +4543,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 ) { // HEALER score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; - } else if (cls == CLASS_ROGUE) { + } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution From 53c4198afd0310916ba30dccdc32615c07efa8f8 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 11:28:57 +0800 Subject: [PATCH 03/13] [Attack target] Cancel mount aura and remove within dist check --- src/strategy/actions/AttackAction.cpp | 2 +- src/strategy/values/AttackersValue.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategy/actions/AttackAction.cpp b/src/strategy/actions/AttackAction.cpp index f0d85a8c..1ba9f4b5 100644 --- a/src/strategy/actions/AttackAction.cpp +++ b/src/strategy/actions/AttackAction.cpp @@ -95,7 +95,7 @@ bool AttackAction::Attack(Unit* target, bool with_pet /*true*/) return false; } - if (bot->IsMounted() && bot->IsWithinLOSInMap(target) && sServerFacade->GetDistance2d(bot, target) < 40.0f) + if (bot->IsMounted() && bot->IsWithinLOSInMap(target)) { WorldPacket emptyPacket; bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); diff --git a/src/strategy/values/AttackersValue.cpp b/src/strategy/values/AttackersValue.cpp index cae2223a..177ff89f 100644 --- a/src/strategy/values/AttackersValue.cpp +++ b/src/strategy/values/AttackersValue.cpp @@ -172,7 +172,7 @@ bool AttackersValue::IsPossibleTarget(Unit* attacker, Player* bot, float range) // (inCannon || !attacker->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) && attacker->CanSeeOrDetect(bot) && // !(attacker->HasUnitState(UNIT_STATE_STUNNED) && botAI->HasAura("shackle undead", attacker)) && !((attacker->IsPolymorphed() || botAI->HasAura("sap", attacker) || /*attacker->IsCharmed() ||*/ attacker->isFeared()) && !rti) && /*!sServerFacade->IsInRoots(attacker) &&*/ - !attacker->IsFriendlyTo(bot) && bot->IsWithinDistInMap(attacker, range) && + !attacker->IsFriendlyTo(bot) && !attacker->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION) && // !(attacker->GetGUID().IsPet() && enemy) && !(attacker->GetCreatureType() == CREATURE_TYPE_CRITTER && !attacker->IsInCombat()) && From c362630ce6c75380c6440ecc9bbbf4cbd38873b8 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 11:29:34 +0800 Subject: [PATCH 04/13] [Class spell] Reduce reach spell relevance --- src/strategy/generic/CombatStrategy.cpp | 62 +++++++++++------------ src/strategy/values/PartyMemberToDispel.h | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/strategy/generic/CombatStrategy.cpp b/src/strategy/generic/CombatStrategy.cpp index c9e3a95c..b77277fd 100644 --- a/src/strategy/generic/CombatStrategy.cpp +++ b/src/strategy/generic/CombatStrategy.cpp @@ -8,7 +8,7 @@ void CombatStrategy::InitTriggers(std::vector &triggers) { - triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_MOVE + 11), nullptr))); + triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("invalid target", NextAction::array(0, new NextAction("drop target", 100), nullptr))); triggers.push_back(new TriggerNode("mounted", NextAction::array(0, new NextAction("check mount state", 54), nullptr))); // triggers.push_back(new TriggerNode("out of react range", NextAction::array(0, new NextAction("flee to master", 55), nullptr))); @@ -24,44 +24,44 @@ AvoidAoeStrategy::AvoidAoeStrategy(PlayerbotAI* botAI) : Strategy(botAI) } -class AvoidAoeStrategyMultiplier : public Multiplier -{ -public: - AvoidAoeStrategyMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "run away on area debuff") {} +// class AvoidAoeStrategyMultiplier : public Multiplier +// { +// public: +// AvoidAoeStrategyMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "run away on area debuff") {} -public: - virtual float GetValue(Action* action); +// public: +// virtual float GetValue(Action* action); -private: -}; +// private: +// }; -float AvoidAoeStrategyMultiplier::GetValue(Action* action) -{ - if (!action) - return 1.0f; +// float AvoidAoeStrategyMultiplier::GetValue(Action* action) +// { +// if (!action) +// return 1.0f; - std::string name = action->getName(); - if (name == "follow" || name == "co" || name == "nc" || name == "drop target") - return 1.0f; +// std::string name = action->getName(); +// if (name == "follow" || name == "co" || name == "nc" || name == "drop target") +// return 1.0f; - uint32 spellId = AI_VALUE2(uint32, "spell id", name); - const SpellInfo* const pSpellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!pSpellInfo) return 1.0f; +// uint32 spellId = AI_VALUE2(uint32, "spell id", name); +// const SpellInfo* const pSpellInfo = sSpellMgr->GetSpellInfo(spellId); +// if (!pSpellInfo) return 1.0f; - if (spellId && pSpellInfo->Targets & TARGET_FLAG_DEST_LOCATION) - return 1.0f; - else if (spellId && pSpellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) - return 1.0f; +// if (spellId && pSpellInfo->Targets & TARGET_FLAG_DEST_LOCATION) +// return 1.0f; +// else if (spellId && pSpellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) +// return 1.0f; - uint32 castTime = pSpellInfo->CalcCastTime(bot); +// uint32 castTime = pSpellInfo->CalcCastTime(bot); - if (AI_VALUE2(bool, "has area debuff", "self target") && spellId && castTime > 0) - { - return 0.0f; - } +// if (AI_VALUE2(bool, "has area debuff", "self target") && spellId && castTime > 0) +// { +// return 0.0f; +// } - return 1.0f; -} +// return 1.0f; +// } NextAction** AvoidAoeStrategy::getDefaultActions() { @@ -86,6 +86,6 @@ void AvoidAoeStrategy::InitMultipliers(std::vector& multipliers) NextAction** CombatFormationStrategy::getDefaultActions() { return NextAction::array(0, - new NextAction("combat formation move", ACTION_EMERGENCY), + new NextAction("combat formation move", ACTION_NORMAL), nullptr); } diff --git a/src/strategy/values/PartyMemberToDispel.h b/src/strategy/values/PartyMemberToDispel.h index 36197ea9..ac2c441f 100644 --- a/src/strategy/values/PartyMemberToDispel.h +++ b/src/strategy/values/PartyMemberToDispel.h @@ -14,7 +14,7 @@ class Unit; class PartyMemberToDispel : public PartyMemberValue, public Qualified { public: - PartyMemberToDispel(PlayerbotAI* botAI, std::string const name = "party member to dispel") : PartyMemberValue(botAI, name, 2 * 1000), Qualified() { } + PartyMemberToDispel(PlayerbotAI* botAI, std::string const name = "party member to dispel") : PartyMemberValue(botAI, name, 1000), Qualified() { } protected: Unit* Calculate() override; From adc9c96b29298cec44a0904903ca41393ec6ece0 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 12:32:22 +0800 Subject: [PATCH 05/13] [Configuration] Gear quality on random bots --- conf/playerbots.conf.dist | 8 ++++++++ src/PlayerbotAIConfig.cpp | 5 ++++- src/PlayerbotAIConfig.h | 2 ++ src/PlayerbotFactory.cpp | 5 ++++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index be3ab4ba..7f6a7668 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -891,6 +891,14 @@ AiPlayerbot.AutoPickTalents = 1 # # +# Equips quality limitation for random bots (1 = normal, 2 = uncommon, 3 = rare, 4 = epic, 5 = legendary) +# default: 3 (rare) +AiPlayerbot.RandomGearQualityLimit = 3 + +# Equips gear score limitation for random bots (0 = no limit) +# default: 0 (no limit) +AiPlayerbot.RandomGearScoreLimit = 0 + # Change random bot has lower gear AiPlayerbot.RandomGearLoweringChance = 0 diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 4d6a2a50..66148931 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -95,7 +95,10 @@ bool PlayerbotAIConfig::Initialize() autoAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.AutoAvoidAoe", true); tellWhenAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.TellWhenAvoidAoe", true); - randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.15f); + randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.0f); + randomGearQualityLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearQualityLimit", 3); + randomGearScoreLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearScoreLimit", 0); + randomBotMaxLevelChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotMaxLevelChance", 0.15f); randomBotRpgChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotRpgChance", 0.20f); diff --git a/src/PlayerbotAIConfig.h b/src/PlayerbotAIConfig.h index d347b87e..7bbc0512 100644 --- a/src/PlayerbotAIConfig.h +++ b/src/PlayerbotAIConfig.h @@ -79,6 +79,8 @@ class PlayerbotAIConfig std::vector randomBotQuestIds; uint32 randomBotTeleportDistance; float randomGearLoweringChance; + int32 randomGearQualityLimit; + int32 randomGearScoreLimit; float randomBotMaxLevelChance; float randomBotRpgChance; uint32 minRandomBots, maxRandomBots; diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index d9f29740..8f95d9a7 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -149,7 +149,10 @@ void PlayerbotFactory::Prepare() { if (!itemQuality) { - itemQuality = ITEM_QUALITY_RARE; + uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 ? 0 : + PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, sPlayerbotAIConfig->randomGearQualityLimit); + itemQuality = sPlayerbotAIConfig->randomGearScoreLimit; + gearScoreLimit = gs; } if (bot->isDead()) From 487796e7e1d0eb0586049ff0f167c8f1bd90d441 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 13:14:17 +0800 Subject: [PATCH 06/13] [Initialization] Fix random bot gear quality --- src/PlayerbotAIConfig.cpp | 4 ++-- src/PlayerbotFactory.cpp | 44 +++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/PlayerbotAIConfig.cpp b/src/PlayerbotAIConfig.cpp index 66148931..48783180 100644 --- a/src/PlayerbotAIConfig.cpp +++ b/src/PlayerbotAIConfig.cpp @@ -96,8 +96,8 @@ bool PlayerbotAIConfig::Initialize() tellWhenAvoidAoe = sConfigMgr->GetOption("AiPlayerbot.TellWhenAvoidAoe", true); randomGearLoweringChance = sConfigMgr->GetOption("AiPlayerbot.RandomGearLoweringChance", 0.0f); - randomGearQualityLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearQualityLimit", 3); - randomGearScoreLimit = sConfigMgr->GetOption("AiPlayerbot.AutoGearScoreLimit", 0); + randomGearQualityLimit = sConfigMgr->GetOption("AiPlayerbot.RandomGearQualityLimit", 3); + randomGearScoreLimit = sConfigMgr->GetOption("AiPlayerbot.RandomGearScoreLimit", 0); randomBotMaxLevelChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotMaxLevelChance", 0.15f); randomBotRpgChance = sConfigMgr->GetOption("AiPlayerbot.RandomBotRpgChance", 0.20f); diff --git a/src/PlayerbotFactory.cpp b/src/PlayerbotFactory.cpp index 8f95d9a7..c74b722d 100644 --- a/src/PlayerbotFactory.cpp +++ b/src/PlayerbotFactory.cpp @@ -151,7 +151,7 @@ void PlayerbotFactory::Prepare() { uint32 gs = sPlayerbotAIConfig->randomGearScoreLimit == 0 ? 0 : PlayerbotFactory::CalcMixedGearScore(sPlayerbotAIConfig->randomGearScoreLimit, sPlayerbotAIConfig->randomGearQualityLimit); - itemQuality = sPlayerbotAIConfig->randomGearScoreLimit; + itemQuality = sPlayerbotAIConfig->randomGearQualityLimit; gearScoreLimit = gs; } @@ -3827,7 +3827,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only - score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2 + crit * 2 + haste * 2 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -3836,7 +3836,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1.2 + crit * 0.7 + haste * 1 + rangeDps; + + hit * 1 + crit * 0.7 + haste * 1 + rangeDps; } else if ((cls == CLASS_PALADIN && tab == 0) || // holy (cls == CLASS_PRIEST && tab != 2) || // discipline / holy (cls == CLASS_SHAMAN && tab == 2) || // heal @@ -3846,7 +3846,7 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) - score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy @@ -3856,20 +3856,20 @@ float PlayerbotFactory::CalculateItemScore(uint32 item_id, Player* bot) } else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement // STRENGTH mainly (AGILITY, INTELLECT also) score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + meleeDps * 5 - + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3 - + hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; } else if (cls == CLASS_DEATH_KNIGHT && tab == 0){ // BLOOD DK TANK score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5 - + hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { - // BEAR DRUID TANK (AND FERAL DRUID...?) + // BEAR DRUID TANK score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + meleeDps * 2 + defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; @@ -4249,7 +4249,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only - score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + dps * 5 + hit * 2 + crit * 2 + haste * 2.5 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -4258,7 +4258,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1.2 + crit * 0.7 + haste * 1; + + hit * 1 + crit * 0.7 + haste * 1; } else if ((cls == CLASS_PALADIN && tab == 0) || // holy (cls == CLASS_PRIEST && tab != 2) || // discipline / holy (cls == CLASS_SHAMAN && tab == 2) || // heal @@ -4268,7 +4268,7 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1; } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) - score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + dps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy @@ -4278,20 +4278,20 @@ float PlayerbotFactory::CalculateEnchantScore(uint32 enchant_id, Player* bot) } else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement // STRENGTH mainly (AGILITY, INTELLECT also) score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + dps * 5 - + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3 - + hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; } else if (cls == CLASS_DEATH_KNIGHT && tab == 0){ // BLOOD DK TANK score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5 - + hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { - // BEAR DRUID TANK (AND FERAL DRUID...?) + // BEAR DRUID TANK score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + dps * 2 + defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; @@ -4529,7 +4529,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 // todo: remove duplicate code if (cls == CLASS_HUNTER) { // AGILITY only - score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2.5 + crit * 2 + haste * 2.5 + intellect; + score += agility * 2.5 + attack_power + armor_penetration * 2 + rangeDps * 5 + hit * 2 + crit * 2 + haste * 2.5 + intellect; } else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE || (cls == CLASS_PRIEST && tab == 2) || // shadow @@ -4538,7 +4538,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 ) { // SPELL DPS score += intellect * 0.5 + spirit * 0.5 + spell_power + spell_penetration - + hit * 1.2 + crit * 0.7 + haste * 1 + rangeDps; + + hit * 1 + crit * 0.7 + haste * 1 + rangeDps; } else if ((cls == CLASS_PALADIN && tab == 0) || // holy (cls == CLASS_PRIEST && tab != 2) || // discipline / holy (cls == CLASS_SHAMAN && tab == 2) || // heal @@ -4548,7 +4548,7 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 score += intellect * 0.5 + spirit * 0.5 + spell_power + mana_regeneration * 0.5 + crit * 0.5 + haste * 1 + rangeDps; } else if (cls == CLASS_ROGUE || (cls == CLASS_DRUID && tab == 2 && !PlayerbotAI::IsTank(bot))) { // AGILITY mainly (STRENGTH also) - score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2.5; + score += agility * 2 + strength + attack_power + armor_penetration * 1 + meleeDps * 5 + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2.5; } else if ((cls == CLASS_PALADIN && tab == 2) || // retribution (cls == CLASS_WARRIOR && tab != 2) || // arm / fury (cls == CLASS_DEATH_KNIGHT && tab != 0) // ice / unholy @@ -4558,20 +4558,20 @@ float PlayerbotFactory::CalculateSpellScore(uint32 spell_id, Player* bot, uint32 } else if ((cls == CLASS_SHAMAN && tab == 1)) { // enhancement // STRENGTH mainly (AGILITY, INTELLECT also) score += strength * 1 + agility * 1.5 + intellect * 1.5 + attack_power + spell_power * 1.5 + armor_penetration * 0.5 + meleeDps * 5 - + hit * 2 + crit * 1.5 + haste * 1.5 + expertise * 2; + + hit * 1.5 + crit * 1.5 + haste * 1.5 + expertise * 2; } else if ((cls == CLASS_WARRIOR && tab == 2) || (cls == CLASS_PALADIN && tab == 1)) { // TANK WITH SHIELD score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 2.5 + parry * 2 + dodge * 2 + resilience * 2 + block * 2 + armor * 0.3 + stamina * 3 - + hit * 1 + crit * 0.2 + haste * 0.5 + expertise * 3; + + hit * 0.5 + crit * 0.2 + haste * 0.5 + expertise * 3; } else if (cls == CLASS_DEATH_KNIGHT && tab == 0){ // BLOOD DK TANK score += strength * 1 + agility * 2 + attack_power * 0.2 + defense * 3.5 + parry * 2 + dodge * 2 + resilience * 2 + armor * 0.3 + stamina * 2.5 - + hit * 2 + crit * 0.5 + haste * 0.5 + expertise * 3.5; + + hit * 0.5 + crit * 0.5 + haste * 0.5 + expertise * 3.5; } else { - // BEAR DRUID TANK (AND FERAL DRUID...?) + // BEAR DRUID TANK score += agility * 1.5 + strength * 1 + attack_power * 0.5 + armor_penetration * 0.5 + meleeDps * 2 + defense * 0.25 + dodge * 0.25 + armor * 0.3 + stamina * 1.5 + hit * 1 + crit * 1 + haste * 0.5 + expertise * 3; From 68565dd813ea95e7e6704cd899ab0aecf7ab9b74 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 15:48:23 +0800 Subject: [PATCH 07/13] [Class spell] Shaman elemental mastery --- src/strategy/shaman/CasterShamanStrategy.cpp | 1 + src/strategy/shaman/ShamanActions.h | 6 ++++++ src/strategy/shaman/ShamanAiObjectContext.cpp | 4 ++++ src/strategy/shaman/ShamanTriggers.h | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp index aa1fef0a..61a31b32 100644 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ b/src/strategy/shaman/CasterShamanStrategy.cpp @@ -52,6 +52,7 @@ void CasterShamanStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue weapon", 23.0f), nullptr))); // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("searing totem", 19.0f), nullptr))); triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("elemental mastery", NextAction::array(0, new NextAction("elemental mastery", 27.0f), nullptr))); // triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost shock", 21.0f), nullptr))); triggers.push_back(new TriggerNode( "no fire totem", diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index c9467e49..2db469fb 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -350,6 +350,12 @@ class CastBloodlustAction : public CastBuffSpellAction CastBloodlustAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bloodlust") { } }; +class CastElementalMasteryAction : public CastBuffSpellAction +{ + public: + CastElementalMasteryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "elemental mastery") { } +}; + class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction { public: diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index c40f4957..819cf3d1 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -96,6 +96,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext creators["frost shock snare"] = &ShamanATriggerFactoryInternal::frost_shock_snare; creators["heroism"] = &ShamanATriggerFactoryInternal::heroism; creators["bloodlust"] = &ShamanATriggerFactoryInternal::bloodlust; + creators["elemental mastery"] = &ShamanATriggerFactoryInternal::elemental_mastery; creators["wind shear on enemy healer"] = &ShamanATriggerFactoryInternal::wind_shear_on_enemy_healer; creators["cure poison"] = &ShamanATriggerFactoryInternal::cure_poison; creators["party member cure poison"] = &ShamanATriggerFactoryInternal::party_member_cure_poison; @@ -114,6 +115,7 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext static Trigger* maelstrom_weapon(PlayerbotAI* botAI) { return new MaelstromWeaponTrigger(botAI); } static Trigger* heroism(PlayerbotAI* botAI) { return new HeroismTrigger(botAI); } static Trigger* bloodlust(PlayerbotAI* botAI) { return new BloodlustTrigger(botAI); } + static Trigger* elemental_mastery(PlayerbotAI* botAI) { return new ElementalMasteryTrigger(botAI); } static Trigger* party_member_cleanse_disease(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritDiseaseTrigger(botAI); } static Trigger* party_member_cleanse_curse(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritCurseTrigger(botAI); } static Trigger* party_member_cleanse_poison(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritPoisonTrigger(botAI); } @@ -206,6 +208,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext creators["thunderstorm"] = &ShamanAiObjectContextInternal::thunderstorm; creators["heroism"] = &ShamanAiObjectContextInternal::heroism; creators["bloodlust"] = &ShamanAiObjectContextInternal::bloodlust; + creators["elemental mastery"] = &ShamanAiObjectContextInternal::elemental_mastery; // creators["cure disease"] = &ShamanAiObjectContextInternal::cure_disease; // creators["cure disease on party"] = &ShamanAiObjectContextInternal::cure_disease_on_party; // creators["cure poison"] = &ShamanAiObjectContextInternal::cure_poison; @@ -222,6 +225,7 @@ class ShamanAiObjectContextInternal : public NamedObjectContext private: static Action* heroism(PlayerbotAI* botAI) { return new CastHeroismAction(botAI); } static Action* bloodlust(PlayerbotAI* botAI) { return new CastBloodlustAction(botAI); } + static Action* elemental_mastery(PlayerbotAI* botAI) { return new CastElementalMasteryAction(botAI); } static Action* thunderstorm(PlayerbotAI* botAI) { return new CastThunderstormAction(botAI); } static Action* lightning_bolt(PlayerbotAI* botAI) { return new CastLightningBoltAction(botAI); } static Action* chain_lightning(PlayerbotAI* botAI) { return new CastChainLightningAction(botAI); } diff --git a/src/strategy/shaman/ShamanTriggers.h b/src/strategy/shaman/ShamanTriggers.h index 54395b4b..d85f0888 100644 --- a/src/strategy/shaman/ShamanTriggers.h +++ b/src/strategy/shaman/ShamanTriggers.h @@ -201,6 +201,12 @@ class BloodlustTrigger : public BoostTrigger BloodlustTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "bloodlust") { } }; +class ElementalMasteryTrigger : public BoostTrigger +{ + public: + ElementalMasteryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "elemental mastery") { } +}; + class MaelstromWeaponTrigger : public HasAuraStackTrigger { public: From 8358ea71549b8ae4caea6aafcca84cf93929f780 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 15:48:44 +0800 Subject: [PATCH 08/13] [Configuration] Talents for fire mage and resto shaman --- conf/playerbots.conf.dist | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index 7f6a7668..e9e53a62 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -696,8 +696,8 @@ AiPlayerbot.PremadeSpecLink.7.1.60 = -30205033005001333031131131051 AiPlayerbot.PremadeSpecLink.7.1.80 = 053030052-30205033005021333031131131051 AiPlayerbot.PremadeSpecName.7.2 = resto pve AiPlayerbot.PremadeSpecGlyph.7.2 = 41517,43385,41527,43386,44923,45775 -AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301335310501002331241 -AiPlayerbot.PremadeSpecLink.7.2.80 = -00505031-50005331335310501022331251 +AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301235310501102321251 +AiPlayerbot.PremadeSpecLink.7.2.80 = -00502033-50005331335310501122331251 # # @@ -715,8 +715,8 @@ AiPlayerbot.PremadeSpecLink.8.0.60 = 23000503110033014032310150532 AiPlayerbot.PremadeSpecLink.8.0.80 = 23000523310033015032310250532-03-203203001 AiPlayerbot.PremadeSpecName.8.1 = fire pve AiPlayerbot.PremadeSpecGlyph.8.1 = 42739,43339,45737,43364,44920,42751 -AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030012303330053120300351 -AiPlayerbot.PremadeSpecLink.8.1.80 = 23000503310003-0055030012303330053120300351 +AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030011302231053120321341 +AiPlayerbot.PremadeSpecLink.8.1.80 = 23000503110003-0055030011302331053120321351 AiPlayerbot.PremadeSpecName.8.2 = frost pve AiPlayerbot.PremadeSpecGlyph.8.2 = 42742,43339,50045,43364,43361,42751 AiPlayerbot.PremadeSpecLink.8.2.60 = --3533103310203100232102231151 From 05e799cff40af8ee5196d4c35e13e86c027547a7 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 21:54:08 +0800 Subject: [PATCH 09/13] [Class spell] Improve warrior, dk, paladin --- src/strategy/deathknight/DKAiObjectContext.cpp | 4 ++-- src/strategy/deathknight/DKTriggers.cpp | 2 +- src/strategy/deathknight/DKTriggers.h | 4 ++-- src/strategy/deathknight/GenericDKStrategy.cpp | 2 +- src/strategy/paladin/PaladinActions.cpp | 2 +- src/strategy/paladin/TankPaladinStrategy.cpp | 3 +++ src/strategy/triggers/GenericTriggers.cpp | 5 +++++ src/strategy/triggers/GenericTriggers.h | 8 ++++++++ src/strategy/triggers/TriggerContext.h | 2 ++ src/strategy/warrior/ArmsWarriorStrategy.cpp | 5 ++++- src/strategy/warrior/FuryWarriorStrategy.cpp | 2 +- src/strategy/warrior/TankWarriorStrategy.cpp | 2 ++ src/strategy/warrior/WarriorAiObjectContext.cpp | 2 +- 13 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/strategy/deathknight/DKAiObjectContext.cpp b/src/strategy/deathknight/DKAiObjectContext.cpp index 99883cbc..e7641e71 100644 --- a/src/strategy/deathknight/DKAiObjectContext.cpp +++ b/src/strategy/deathknight/DKAiObjectContext.cpp @@ -67,7 +67,7 @@ class DeathKnightTriggerFactoryInternal : public NamedObjectContext DeathKnightTriggerFactoryInternal() { creators["bone shield"] = &DeathKnightTriggerFactoryInternal::bone_shield; - creators["pestilence"] = &DeathKnightTriggerFactoryInternal::pestilence; + creators["pestilence glyph"] = &DeathKnightTriggerFactoryInternal::pestilence_glyph; creators["blood strike"] = &DeathKnightTriggerFactoryInternal::blood_strike; creators["plague strike"] = &DeathKnightTriggerFactoryInternal::plague_strike; creators["plague strike on attacker"] = &DeathKnightTriggerFactoryInternal::plague_strike_on_attacker; @@ -94,7 +94,7 @@ class DeathKnightTriggerFactoryInternal : public NamedObjectContext private: static Trigger* bone_shield(PlayerbotAI* botAI) { return new BoneShieldTrigger(botAI); } - static Trigger* pestilence(PlayerbotAI* botAI) { return new PestilenceTrigger(botAI); } + static Trigger* pestilence_glyph(PlayerbotAI* botAI) { return new PestilenceGlyphTrigger(botAI); } static Trigger* blood_strike(PlayerbotAI* botAI) { return new BloodStrikeTrigger(botAI); } static Trigger* plague_strike(PlayerbotAI* botAI) { return new PlagueStrikeDebuffTrigger(botAI); } static Trigger* plague_strike_on_attacker(PlayerbotAI* botAI) { return new PlagueStrikeDebuffOnAttackerTrigger(botAI); } diff --git a/src/strategy/deathknight/DKTriggers.cpp b/src/strategy/deathknight/DKTriggers.cpp index 8eee1045..3f7f696e 100644 --- a/src/strategy/deathknight/DKTriggers.cpp +++ b/src/strategy/deathknight/DKTriggers.cpp @@ -14,7 +14,7 @@ bool DKPresenceTrigger::IsActive() return !botAI->HasAura("blood presence", target) && !botAI->HasAura("unholy presence", target) && !botAI->HasAura("frost presence", target); } -bool PestilenceTrigger::IsActive() { +bool PestilenceGlyphTrigger::IsActive() { if (!SpellTrigger::IsActive()) { return false; } diff --git a/src/strategy/deathknight/DKTriggers.h b/src/strategy/deathknight/DKTriggers.h index 08b91a82..f9dc88dc 100644 --- a/src/strategy/deathknight/DKTriggers.h +++ b/src/strategy/deathknight/DKTriggers.h @@ -71,10 +71,10 @@ class DeathCoilTrigger : public SpellCanBeCastTrigger DeathCoilTrigger(PlayerbotAI* botAI) : SpellCanBeCastTrigger(botAI, "death coil") { } }; -class PestilenceTrigger : public DebuffTrigger +class PestilenceGlyphTrigger : public SpellTrigger { public: - PestilenceTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pestilence") { } + PestilenceGlyphTrigger(PlayerbotAI* botAI) : SpellTrigger(botAI, "pestilence") { } virtual bool IsActive() override; }; diff --git a/src/strategy/deathknight/GenericDKStrategy.cpp b/src/strategy/deathknight/GenericDKStrategy.cpp index 42c4ffa4..3e26cae2 100644 --- a/src/strategy/deathknight/GenericDKStrategy.cpp +++ b/src/strategy/deathknight/GenericDKStrategy.cpp @@ -192,5 +192,5 @@ void GenericDKStrategy::InitTriggers(std::vector& triggers) // triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, // new NextAction("pestilence", ACTION_NORMAL + 4), // nullptr))); - triggers.push_back(new TriggerNode("pestilence", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL))); + triggers.push_back(new TriggerNode("pestilence glyph", NextAction::array(0, new NextAction("pestilence", ACTION_HIGH + 9), NULL))); } diff --git a/src/strategy/paladin/PaladinActions.cpp b/src/strategy/paladin/PaladinActions.cpp index b2291d3d..6a56478b 100644 --- a/src/strategy/paladin/PaladinActions.cpp +++ b/src/strategy/paladin/PaladinActions.cpp @@ -153,7 +153,7 @@ bool CastMeleeConsecrationAction::isUseful() { Unit* target = GetTarget(); // float dis = distance + CONTACT_DISTANCE; - return target && bot->IsWithinCombatRange(target, sPlayerbotAIConfig->meleeDistance); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance); + return target && bot->IsWithinMeleeRange(target); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", GetTargetName()), distance); } bool CastDivineSacrificeAction::isUseful() diff --git a/src/strategy/paladin/TankPaladinStrategy.cpp b/src/strategy/paladin/TankPaladinStrategy.cpp index bbbeac00..cb1ca7b5 100644 --- a/src/strategy/paladin/TankPaladinStrategy.cpp +++ b/src/strategy/paladin/TankPaladinStrategy.cpp @@ -94,6 +94,9 @@ void TankPaladinStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode( "medium group heal occasion", NextAction::array(0, new NextAction("divine sacrifice", ACTION_HIGH + 5), nullptr))); + triggers.push_back(new TriggerNode( + "enough mana", + NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 4), nullptr))); triggers.push_back(new TriggerNode( "not facing target", NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr))); diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 6d2a9d0a..dff60e0d 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -64,6 +64,11 @@ bool AlmostFullManaTrigger::IsActive() return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 85; } +bool EnoughManaTrigger::IsActive() +{ + return AI_VALUE2(bool, "has mana", "self target") && AI_VALUE2(uint8, "mana", "self target") > 65; +} + bool RageAvailable::IsActive() { return AI_VALUE2(uint8, "rage", "self target") >= amount; diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index 2731f9ef..4f5cee27 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -30,6 +30,14 @@ class HighManaTrigger : public Trigger bool IsActive() override; }; +class EnoughManaTrigger : public Trigger +{ + public: + EnoughManaTrigger(PlayerbotAI* botAI) : Trigger(botAI, "enough mana") { } + + bool IsActive() override; +}; + class AlmostFullManaTrigger : public Trigger { public: diff --git a/src/strategy/triggers/TriggerContext.h b/src/strategy/triggers/TriggerContext.h index 34ef3480..df04b983 100644 --- a/src/strategy/triggers/TriggerContext.h +++ b/src/strategy/triggers/TriggerContext.h @@ -45,6 +45,7 @@ class TriggerContext : public NamedObjectContext creators["medium mana"] = &TriggerContext::MediumMana; creators["high mana"] = &TriggerContext::HighMana; creators["almost full mana"] = &TriggerContext::AlmostFullMana; + creators["enough mana"] = &TriggerContext::EnoughMana; creators["party member critical health"] = &TriggerContext::PartyMemberCriticalHealth; creators["party member low health"] = &TriggerContext::PartyMemberLowHealth; @@ -253,6 +254,7 @@ class TriggerContext : public NamedObjectContext static Trigger* MediumMana(PlayerbotAI* botAI) { return new MediumManaTrigger(botAI); } static Trigger* HighMana(PlayerbotAI* botAI) { return new HighManaTrigger(botAI); } static Trigger* AlmostFullMana(PlayerbotAI* botAI) { return new AlmostFullManaTrigger(botAI); } + static Trigger* EnoughMana(PlayerbotAI* botAI) { return new EnoughManaTrigger(botAI); } static Trigger* LightRageAvailable(PlayerbotAI* botAI) { return new LightRageAvailableTrigger(botAI); } static Trigger* MediumRageAvailable(PlayerbotAI* botAI) { return new MediumRageAvailableTrigger(botAI); } static Trigger* HighRageAvailable(PlayerbotAI* botAI) { return new HighRageAvailableTrigger(botAI); } diff --git a/src/strategy/warrior/ArmsWarriorStrategy.cpp b/src/strategy/warrior/ArmsWarriorStrategy.cpp index c6314bae..ef27b800 100644 --- a/src/strategy/warrior/ArmsWarriorStrategy.cpp +++ b/src/strategy/warrior/ArmsWarriorStrategy.cpp @@ -32,7 +32,9 @@ ArmsWarriorStrategy::ArmsWarriorStrategy(PlayerbotAI* botAI) : GenericWarriorStr NextAction** ArmsWarriorStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("heroic strike", ACTION_DEFAULT), nullptr); + return NextAction::array(0, + new NextAction("bladestorm", ACTION_DEFAULT + 0.1f), + new NextAction("melee", ACTION_DEFAULT), nullptr); } void ArmsWarriorStrategy::InitTriggers(std::vector& triggers) @@ -56,4 +58,5 @@ void ArmsWarriorStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("rend on attacker", NextAction::array(0, new NextAction("rend on attacker", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr))); } diff --git a/src/strategy/warrior/FuryWarriorStrategy.cpp b/src/strategy/warrior/FuryWarriorStrategy.cpp index 60cece7b..57cf118e 100644 --- a/src/strategy/warrior/FuryWarriorStrategy.cpp +++ b/src/strategy/warrior/FuryWarriorStrategy.cpp @@ -61,7 +61,7 @@ void FuryWarriorStrategy::InitTriggers(std::vector &triggers) triggers.push_back(new TriggerNode("bloodthirst", NextAction::array(0, new NextAction("bloodthirst", ACTION_HIGH + 7), nullptr))); triggers.push_back(new TriggerNode("instant slam", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); - triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), NULL))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), NULL))); // triggers.push_back(new TriggerNode("berserker rage", NextAction::array(0, new NextAction("berserker rage", ACTION_HIGH + 2), nullptr))); // triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, // new NextAction("whirlwind", ACTION_HIGH + 2), diff --git a/src/strategy/warrior/TankWarriorStrategy.cpp b/src/strategy/warrior/TankWarriorStrategy.cpp index 42f71fa2..bbdfb740 100644 --- a/src/strategy/warrior/TankWarriorStrategy.cpp +++ b/src/strategy/warrior/TankWarriorStrategy.cpp @@ -88,4 +88,6 @@ void TankWarriorStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("rend on attacker", NextAction::array(0, new NextAction("rend on attacker", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("protect party member", NextAction::array(0, new NextAction("intervene", ACTION_EMERGENCY), nullptr))); + triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 1), nullptr))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 1), nullptr))); } diff --git a/src/strategy/warrior/WarriorAiObjectContext.cpp b/src/strategy/warrior/WarriorAiObjectContext.cpp index 90917300..1cabf441 100644 --- a/src/strategy/warrior/WarriorAiObjectContext.cpp +++ b/src/strategy/warrior/WarriorAiObjectContext.cpp @@ -117,7 +117,7 @@ class WarriorTriggerFactoryInternal : public NamedObjectContext static Trigger* SwordAndBoard(PlayerbotAI* botAI) { return new SwordAndBoardTrigger(botAI); } static Trigger* shield_bash_on_enemy_healer(PlayerbotAI* botAI) { return new ShieldBashInterruptEnemyHealerSpellTrigger(botAI); } - static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunderclap", "light rage available"); } + static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunder clap", "light rage available"); } static Trigger* intercept_can_cast(PlayerbotAI* botAI) { return new InterceptCanCastTrigger(botAI); } static Trigger* intercept_and_far_enemy(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "enemy is out of melee", "intercept can cast"); } static Trigger* intercept_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "intercept and far enemy", "light rage available"); } From 2a542b13457c361905d44985fcd93cdc6458a73b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 21:54:22 +0800 Subject: [PATCH 10/13] [Configuration] Rogue glyphs --- 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 e9e53a62..d955b9c2 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -614,11 +614,11 @@ AiPlayerbot.PremadeSpecLink.3.2.80 = -005305101-5000032500033330522135301331 # AiPlayerbot.PremadeSpecName.4.0 = as pve -AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45767 +AiPlayerbot.PremadeSpecGlyph.4.0 = 45768,43379,45761,43380,43378,45766 AiPlayerbot.PremadeSpecLink.4.0.60 = 005323005350100520103331051 AiPlayerbot.PremadeSpecLink.4.0.80 = 005323005350100520103331051-005005005003-2 AiPlayerbot.PremadeSpecName.4.1 = combat pve -AiPlayerbot.PremadeSpecGlyph.4.1 = 45762,43379,45767,43380,43378,45766 +AiPlayerbot.PremadeSpecGlyph.4.1 = 42962,43379,45762,43380,43378,42969 AiPlayerbot.PremadeSpecLink.4.1.60 = -0252051000035015223100501251 AiPlayerbot.PremadeSpecLink.4.1.80 = 00532000523-0252051000035015223100501251 AiPlayerbot.PremadeSpecName.4.2 = subtlety pve From db1cfa6abc63db576bda65586a7364f778093417 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Thu, 11 Jul 2024 23:01:25 +0800 Subject: [PATCH 11/13] [Random bots] Ensure teleport after randomize --- src/strategy/actions/ActionContext.h | 2 ++ src/strategy/actions/AutoLearnSpellAction.cpp | 13 ++++++++++++- src/strategy/actions/AutoLearnSpellAction.h | 8 ++++++++ src/strategy/actions/AutoTeleportForLevelAction.cpp | 13 ------------- src/strategy/actions/AutoTeleportForLevelAction.h | 2 -- src/strategy/generic/WorldPacketHandlerStrategy.cpp | 7 ++++--- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/strategy/actions/ActionContext.h b/src/strategy/actions/ActionContext.h index f2c1062c..ea8b3362 100644 --- a/src/strategy/actions/ActionContext.h +++ b/src/strategy/actions/ActionContext.h @@ -152,6 +152,7 @@ class ActionContext : public NamedObjectContext creators["auto talents"] = &ActionContext::auto_talents; creators["auto learn spell"] = &ActionContext::auto_learn_spell; creators["auto teleport for level"] = &ActionContext::auto_teleport_for_level; + creators["auto upgrade equip"] = &ActionContext::auto_upgrade_equip; creators["xp gain"] = &ActionContext::xp_gain; creators["invite nearby"] = &ActionContext::invite_nearby; creators["invite guild"] = &ActionContext::invite_guild; @@ -319,6 +320,7 @@ class ActionContext : public NamedObjectContext static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); } static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); } static Action* auto_teleport_for_level(PlayerbotAI* botAI) { return new AutoTeleportForLevelAction(botAI); } + static Action* auto_upgrade_equip(PlayerbotAI* botAI) { return new AutoUpgradeEquipAction(botAI); } static Action* xp_gain(PlayerbotAI* botAI) { return new XpGainAction(botAI); } static Action* invite_nearby(PlayerbotAI* botAI) { return new InviteNearbyToGroupAction(botAI); } static Action* invite_guild(PlayerbotAI* botAI) { return new InviteGuildToGroupAction(botAI); } diff --git a/src/strategy/actions/AutoLearnSpellAction.cpp b/src/strategy/actions/AutoLearnSpellAction.cpp index 3202eb96..d742d4ad 100644 --- a/src/strategy/actions/AutoLearnSpellAction.cpp +++ b/src/strategy/actions/AutoLearnSpellAction.cpp @@ -24,7 +24,6 @@ bool AutoLearnSpellAction::Execute(Event event) out << "."; botAI->TellMaster(out); } - return true; } @@ -181,3 +180,15 @@ void AutoLearnSpellAction::LearnSpell(uint32 spellId, std::ostringstream* out) } } } + +bool AutoUpgradeEquipAction::Execute(Event event) { + if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) { + return false; + } + PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); + if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { + factory.InitEquipment(true); + } + factory.InitAmmo(); + return true; +} diff --git a/src/strategy/actions/AutoLearnSpellAction.h b/src/strategy/actions/AutoLearnSpellAction.h index 9e6267c3..1cefaf48 100644 --- a/src/strategy/actions/AutoLearnSpellAction.h +++ b/src/strategy/actions/AutoLearnSpellAction.h @@ -23,4 +23,12 @@ class AutoLearnSpellAction : public Action void LearnSpell(uint32 spellId, std::ostringstream* out); }; +class AutoUpgradeEquipAction : public Action +{ + public: + AutoUpgradeEquipAction(PlayerbotAI* botAI, std::string const name = "auto upgrade equip") : Action(botAI, name) { } + + bool Execute(Event event); +}; + #endif diff --git a/src/strategy/actions/AutoTeleportForLevelAction.cpp b/src/strategy/actions/AutoTeleportForLevelAction.cpp index 1ad4e0c4..0f4c8f63 100644 --- a/src/strategy/actions/AutoTeleportForLevelAction.cpp +++ b/src/strategy/actions/AutoTeleportForLevelAction.cpp @@ -6,8 +6,6 @@ #include "SharedDefines.h" bool AutoTeleportForLevelAction::Execute(Event event) { - AutoUpgradeEquip(); - if (!sPlayerbotAIConfig->autoTeleportForLevel || !sRandomPlayerbotMgr->IsRandomBot(bot)) { return false; } @@ -16,15 +14,4 @@ bool AutoTeleportForLevelAction::Execute(Event event) { } sRandomPlayerbotMgr->RandomTeleportForLevel(bot); return true; -} - -void AutoTeleportForLevelAction::AutoUpgradeEquip() { - if (!sPlayerbotAIConfig->autoUpgradeEquip || !sRandomPlayerbotMgr->IsRandomBot(bot)) { - return; - } - PlayerbotFactory factory(bot, bot->GetLevel(), ITEM_QUALITY_RARE); - if (!sPlayerbotAIConfig->equipmentPersistence || bot->GetLevel() < sPlayerbotAIConfig->equipmentPersistenceLevel) { - factory.InitEquipment(true); - } - factory.InitAmmo(); } \ No newline at end of file diff --git a/src/strategy/actions/AutoTeleportForLevelAction.h b/src/strategy/actions/AutoTeleportForLevelAction.h index c8397d53..ca13edf2 100644 --- a/src/strategy/actions/AutoTeleportForLevelAction.h +++ b/src/strategy/actions/AutoTeleportForLevelAction.h @@ -15,8 +15,6 @@ class AutoTeleportForLevelAction : public Action AutoTeleportForLevelAction(PlayerbotAI* botAI, std::string const name = "auto teleport for level") : Action(botAI, name) { } bool Execute(Event event); - private: - void AutoUpgradeEquip(); }; #endif diff --git a/src/strategy/generic/WorldPacketHandlerStrategy.cpp b/src/strategy/generic/WorldPacketHandlerStrategy.cpp index a5c1065d..2db5ed84 100644 --- a/src/strategy/generic/WorldPacketHandlerStrategy.cpp +++ b/src/strategy/generic/WorldPacketHandlerStrategy.cpp @@ -37,9 +37,10 @@ void WorldPacketHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back(new TriggerNode("bg status", NextAction::array(0, new NextAction("bg status", relevance), nullptr))); triggers.push_back(new TriggerNode("xpgain", NextAction::array(0, new NextAction("xp gain", relevance), nullptr))); triggers.push_back(new TriggerNode("levelup", NextAction::array(0, - new NextAction("auto talents", relevance), - new NextAction("auto learn spell", relevance), - new NextAction("auto teleport for level", relevance), + new NextAction("auto teleport for level", relevance + 3), + new NextAction("auto talents", relevance + 2), + new NextAction("auto learn spell", relevance + 1), + new NextAction("auto upgrade equip", relevance), nullptr))); // triggers.push_back(new TriggerNode("group destroyed", NextAction::array(0, new NextAction("reset botAI", relevance), nullptr))); triggers.push_back(new TriggerNode("questgiver quest details", NextAction::array(0, new NextAction("turn in query quest", relevance), nullptr))); From 266aa1ec888c9589d4d47cd57da7faa515e91898 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Fri, 12 Jul 2024 00:26:42 +0800 Subject: [PATCH 12/13] [Warnings] Fix warnings --- src/strategy/actions/BattleGroundTactics.cpp | 7 +++++-- src/strategy/actions/BuyAction.cpp | 2 ++ src/strategy/actions/CastCustomSpellAction.cpp | 4 ++-- src/strategy/actions/CustomStrategyEditAction.cpp | 2 +- src/strategy/actions/RangeAction.cpp | 2 +- src/strategy/actions/TalkToQuestGiverAction.cpp | 4 ++++ src/strategy/actions/WhoAction.cpp | 4 ++-- src/strategy/values/BudgetValues.cpp | 2 ++ src/strategy/values/ItemForSpellValue.cpp | 4 ++-- 9 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/strategy/actions/BattleGroundTactics.cpp b/src/strategy/actions/BattleGroundTactics.cpp index 80eff17b..a9e916d3 100644 --- a/src/strategy/actions/BattleGroundTactics.cpp +++ b/src/strategy/actions/BattleGroundTactics.cpp @@ -4115,7 +4115,8 @@ bool BGTactics::selectObjective(bool reset) } break; } - + default: + break; } return false; @@ -4503,7 +4504,7 @@ bool BGTactics::atFlag(std::vector const& vPaths, std::vectorisSpawned() || !go->GetGoState() == GO_STATE_READY) + if (!go->isSpawned() || go->GetGoState() != GO_STATE_READY) continue; if (!bot->CanUseBattlegroundObject(go) && bgType != BATTLEGROUND_WS) @@ -4644,6 +4645,8 @@ bool BGTactics::atFlag(std::vector const& vPaths, std::vectorFormatQuest(quest); @@ -257,6 +259,8 @@ bool TurnInQueryQuestAction::Execute(Event event) case QUEST_STATUS_REWARDED: out << "|cffff0000Rewarded|r"; break; + default: + break; } out << ": " << chat->FormatQuest(quest); diff --git a/src/strategy/actions/WhoAction.cpp b/src/strategy/actions/WhoAction.cpp index 76bfd608..d7b9f2bc 100644 --- a/src/strategy/actions/WhoAction.cpp +++ b/src/strategy/actions/WhoAction.cpp @@ -11,8 +11,8 @@ #ifndef WIN32 inline int strcmpi(char const* s1, char const* s2) { - for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); - return *s1 - *s2; + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2) {} + return *s1 - *s2; } #endif diff --git a/src/strategy/values/BudgetValues.cpp b/src/strategy/values/BudgetValues.cpp index b1045d1f..d9806087 100644 --- a/src/strategy/values/BudgetValues.cpp +++ b/src/strategy/values/BudgetValues.cpp @@ -180,6 +180,8 @@ uint32 MoneyNeededForValue::Calculate() case NeedMoneyFor::tradeskill: moneyWanted = (level * level * level); //Or level^3 (10s @ lvl10, 3g @ lvl30, 20g @ lvl60, 50g @ lvl80): Todo replace (Should be buyable reagents that combined allow crafting of usefull items) break; + default: + break; } return moneyWanted; diff --git a/src/strategy/values/ItemForSpellValue.cpp b/src/strategy/values/ItemForSpellValue.cpp index e52bbbf6..58c4fae1 100644 --- a/src/strategy/values/ItemForSpellValue.cpp +++ b/src/strategy/values/ItemForSpellValue.cpp @@ -8,8 +8,8 @@ #ifndef WIN32 inline int strcmpi(char const* s1, char const* s2) { - for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2); - return *s1 - *s2; + for (; *s1 && *s2 && (toupper(*s1) == toupper(*s2)); ++s1, ++s2) {} + return *s1 - *s2; } #endif From 2d1fc5b932908aa768c1efde3dd710ee12642051 Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 13 Jul 2024 11:39:06 +0800 Subject: [PATCH 13/13] [Warnings] Fix --- src/strategy/actions/ChooseTravelTargetAction.cpp | 10 +++++----- src/strategy/actions/LootRollAction.cpp | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/strategy/actions/ChooseTravelTargetAction.cpp b/src/strategy/actions/ChooseTravelTargetAction.cpp index f6b37494..614a8b73 100644 --- a/src/strategy/actions/ChooseTravelTargetAction.cpp +++ b/src/strategy/actions/ChooseTravelTargetAction.cpp @@ -46,19 +46,19 @@ void ChooseTravelTargetAction::getNewTarget(TravelTarget* newTarget, TravelTarge foundTarget = SetNpcFlagTarget(newTarget, { UNIT_NPC_FLAG_BANKER,UNIT_NPC_FLAG_BATTLEMASTER,UNIT_NPC_FLAG_AUCTIONEER }); //Grind for money - if (!foundTarget && AI_VALUE(bool, "should get money")) + if (!foundTarget && AI_VALUE(bool, "should get money")) { if (urand(1, 100) > 66) { foundTarget = SetQuestTarget(newTarget, true); //Turn in quests for money. if (!foundTarget) foundTarget = SetQuestTarget(newTarget); //Do low level quests - } - else if (urand(1, 100) > 50) + } else if (urand(1, 100) > 50) { foundTarget = SetGrindTarget(newTarget); //Go grind mobs for money - else + } else { foundTarget = SetNewQuestTarget(newTarget); //Find a low level quest to do - + } + } //Continue if (!foundTarget && urand(1, 100) > 10) //90% chance diff --git a/src/strategy/actions/LootRollAction.cpp b/src/strategy/actions/LootRollAction.cpp index 9f5db411..5b4835b4 100644 --- a/src/strategy/actions/LootRollAction.cpp +++ b/src/strategy/actions/LootRollAction.cpp @@ -147,6 +147,8 @@ RollVote LootRollAction::CalculateRollVote(ItemTemplate const* proto) case ITEM_USAGE_VENDOR: needVote = GREED; break; + default: + break; } return StoreLootAction::IsLootAllowed(proto->ItemId, GET_PLAYERBOT_AI(bot)) ? needVote : PASS;