From 360a025b341cb80c88e887bd1dc5e4ea4ea21cdf Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sun, 1 Sep 2024 17:11:46 +0800 Subject: [PATCH] Estimated dps calculation --- src/strategy/actions/ChatActionContext.h | 4 +- src/strategy/actions/GenericSpellActions.cpp | 2 +- src/strategy/actions/TellLosAction.cpp | 6 +- src/strategy/actions/TellLosAction.h | 4 +- src/strategy/generic/CastTimeStrategy.cpp | 2 +- .../generic/ChatCommandHandlerStrategy.cpp | 2 +- src/strategy/rogue/RogueTriggers.cpp | 2 +- src/strategy/shaman/ShamanActions.cpp | 2 +- src/strategy/triggers/GenericTriggers.cpp | 2 +- .../values/AttackerWithoutAuraTargetValue.cpp | 2 +- src/strategy/values/DpsTargetValue.cpp | 2 +- .../values/EstimatedLifetimeValue.cpp | 135 ++++++++++++++++++ ...fetimeValue.h => EstimatedLifetimeValue.h} | 16 ++- src/strategy/values/ExpectedLifetimeValue.cpp | 102 ------------- src/strategy/values/ValueContext.h | 10 +- 15 files changed, 165 insertions(+), 128 deletions(-) create mode 100644 src/strategy/values/EstimatedLifetimeValue.cpp rename src/strategy/values/{ExpectedLifetimeValue.h => EstimatedLifetimeValue.h} (51%) delete mode 100644 src/strategy/values/ExpectedLifetimeValue.cpp diff --git a/src/strategy/actions/ChatActionContext.h b/src/strategy/actions/ChatActionContext.h index 76c1bc54..d56c5e6f 100644 --- a/src/strategy/actions/ChatActionContext.h +++ b/src/strategy/actions/ChatActionContext.h @@ -172,7 +172,7 @@ public: creators["rtsc"] = &ChatActionContext::rtsc; creators["naxx chat shortcut"] = &ChatActionContext::naxx_chat_shortcut; creators["bwl chat shortcut"] = &ChatActionContext::bwl_chat_shortcut; - creators["tell expected dps"] = &ChatActionContext::tell_expected_dps; + creators["tell estimated dps"] = &ChatActionContext::tell_estimated_dps; creators["join"] = &ChatActionContext::join; creators["calc"] = &ChatActionContext::calc; } @@ -271,7 +271,7 @@ private: static Action* rtsc(PlayerbotAI* botAI) { return new RTSCAction(botAI); } static Action* naxx_chat_shortcut(PlayerbotAI* ai) { return new NaxxChatShortcutAction(ai); } static Action* bwl_chat_shortcut(PlayerbotAI* ai) { return new BwlChatShortcutAction(ai); } - static Action* tell_expected_dps(PlayerbotAI* ai) { return new TellExpectedDpsAction(ai); } + static Action* tell_estimated_dps(PlayerbotAI* ai) { return new TellEstimatedDpsAction(ai); } static Action* join(PlayerbotAI* ai) { return new JoinGroupAction(ai); } static Action* calc(PlayerbotAI* ai) { return new TellCalculateItemAction(ai); } }; diff --git a/src/strategy/actions/GenericSpellActions.cpp b/src/strategy/actions/GenericSpellActions.cpp index 05938358..2425a223 100644 --- a/src/strategy/actions/GenericSpellActions.cpp +++ b/src/strategy/actions/GenericSpellActions.cpp @@ -364,5 +364,5 @@ bool CastDebuffSpellAction::isUseful() return false; } return CastAuraSpellAction::isUseful() && - (target->GetHealth() / AI_VALUE(float, "expected group dps")) >= needLifeTime; + (target->GetHealth() / AI_VALUE(float, "estimated group dps")) >= needLifeTime; } \ No newline at end of file diff --git a/src/strategy/actions/TellLosAction.cpp b/src/strategy/actions/TellLosAction.cpp index 159fb845..03dd3569 100644 --- a/src/strategy/actions/TellLosAction.cpp +++ b/src/strategy/actions/TellLosAction.cpp @@ -130,10 +130,10 @@ bool TellAuraAction::Execute(Event event) return true; } -bool TellExpectedDpsAction::Execute(Event event) +bool TellEstimatedDpsAction::Execute(Event event) { - float dps = AI_VALUE(float, "expected group dps"); - botAI->TellMaster("Expected Group DPS: " + std::to_string(dps)); + float dps = AI_VALUE(float, "estimated group dps"); + botAI->TellMaster("Estimated Group DPS: " + std::to_string(dps)); return true; } diff --git a/src/strategy/actions/TellLosAction.h b/src/strategy/actions/TellLosAction.h index 1adc56d0..988564cf 100644 --- a/src/strategy/actions/TellLosAction.h +++ b/src/strategy/actions/TellLosAction.h @@ -30,10 +30,10 @@ public: virtual bool Execute(Event event); }; -class TellExpectedDpsAction : public Action +class TellEstimatedDpsAction : public Action { public: - TellExpectedDpsAction(PlayerbotAI* ai) : Action(ai, "tell expected dps") {} + TellEstimatedDpsAction(PlayerbotAI* ai) : Action(ai, "tell estimated dps") {} virtual bool Execute(Event event); }; diff --git a/src/strategy/generic/CastTimeStrategy.cpp b/src/strategy/generic/CastTimeStrategy.cpp index 7d1b4545..483e2b8c 100644 --- a/src/strategy/generic/CastTimeStrategy.cpp +++ b/src/strategy/generic/CastTimeStrategy.cpp @@ -47,7 +47,7 @@ float CastTimeMultiplier::GetValue(Action* action) return 1.0f; } - if (castTime > (1000 * target->GetHealth() / AI_VALUE(float, "expected group dps"))) + if (castTime > (1000 * target->GetHealth() / AI_VALUE(float, "estimated group dps"))) { return 0.1f; } diff --git a/src/strategy/generic/ChatCommandHandlerStrategy.cpp b/src/strategy/generic/ChatCommandHandlerStrategy.cpp index 78c5aef7..58db48f5 100644 --- a/src/strategy/generic/ChatCommandHandlerStrategy.cpp +++ b/src/strategy/generic/ChatCommandHandlerStrategy.cpp @@ -89,7 +89,7 @@ void ChatCommandHandlerStrategy::InitTriggers(std::vector& trigger triggers.push_back( new TriggerNode("bwl", NextAction::array(0, new NextAction("bwl chat shortcut", relevance), NULL))); triggers.push_back( - new TriggerNode("dps", NextAction::array(0, new NextAction("tell expected dps", relevance), NULL))); + new TriggerNode("dps", NextAction::array(0, new NextAction("tell estimated dps", relevance), NULL))); triggers.push_back( new TriggerNode("disperse", NextAction::array(0, new NextAction("disperse set", relevance), NULL))); } diff --git a/src/strategy/rogue/RogueTriggers.cpp b/src/strategy/rogue/RogueTriggers.cpp index 31e1a390..ed12016e 100644 --- a/src/strategy/rogue/RogueTriggers.cpp +++ b/src/strategy/rogue/RogueTriggers.cpp @@ -133,5 +133,5 @@ bool TargetWithComboPointsLowerHealTrigger::IsActive() return false; } return ComboPointsAvailableTrigger::IsActive() && - (target->GetHealth() / AI_VALUE(float, "expected group dps")) <= lifeTime; + (target->GetHealth() / AI_VALUE(float, "estimated group dps")) <= lifeTime; } \ No newline at end of file diff --git a/src/strategy/shaman/ShamanActions.cpp b/src/strategy/shaman/ShamanActions.cpp index 3815b2b6..9ce29240 100644 --- a/src/strategy/shaman/ShamanActions.cpp +++ b/src/strategy/shaman/ShamanActions.cpp @@ -17,7 +17,7 @@ bool CastTotemAction::isUseful() { return false; } - float dps = AI_VALUE(float, "expected group dps"); + float dps = AI_VALUE(float, "estimated group dps"); if (target->GetHealth() / dps < needLifeTime) { return false; diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index c1f80eb7..7c40ef37 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -221,7 +221,7 @@ bool DebuffTrigger::IsActive() { return false; } - return BuffTrigger::IsActive() && (target->GetHealth() / AI_VALUE(float, "expected group dps")) >= needLifeTime; + return BuffTrigger::IsActive() && (target->GetHealth() / AI_VALUE(float, "estimated group dps")) >= needLifeTime; } bool DebuffOnBossTrigger::IsActive() diff --git a/src/strategy/values/AttackerWithoutAuraTargetValue.cpp b/src/strategy/values/AttackerWithoutAuraTargetValue.cpp index 99489af4..e99d0f3e 100644 --- a/src/strategy/values/AttackerWithoutAuraTargetValue.cpp +++ b/src/strategy/values/AttackerWithoutAuraTargetValue.cpp @@ -52,7 +52,7 @@ Unit* MeleeAttackerWithoutAuraTargetValue::Calculate() if (!bot->IsWithinMeleeRange(unit)) continue; - if (checkArc && !bot->HasInArc(CAST_ANGLE_IN_FRONT, unit)) + if (checkArc && !bot->HasInArc(M_PI, unit)) continue; if (unit->GetHealth() < max_health) diff --git a/src/strategy/values/DpsTargetValue.cpp b/src/strategy/values/DpsTargetValue.cpp index e2e12cb3..5fc276df 100644 --- a/src/strategy/values/DpsTargetValue.cpp +++ b/src/strategy/values/DpsTargetValue.cpp @@ -291,7 +291,7 @@ Unit* DpsTargetValue::Calculate() return rti; // FindLeastHpTargetStrategy strategy(botAI); - float dps = AI_VALUE(float, "expected group dps"); + float dps = AI_VALUE(float, "estimated group dps"); if (botAI->IsCaster(bot)) { CasterFindTargetSmartStrategy strategy(botAI, dps); diff --git a/src/strategy/values/EstimatedLifetimeValue.cpp b/src/strategy/values/EstimatedLifetimeValue.cpp new file mode 100644 index 00000000..4352934f --- /dev/null +++ b/src/strategy/values/EstimatedLifetimeValue.cpp @@ -0,0 +1,135 @@ +#include "EstimatedLifetimeValue.h" + +#include "AiFactory.h" +#include "PlayerbotAI.h" +#include "PlayerbotAIConfig.h" +#include "Playerbots.h" +#include "SharedDefines.h" + +float EstimatedLifetimeValue::Calculate() +{ + Unit* target = AI_VALUE(Unit*, qualifier); + if (!target || !target->IsAlive()) + { + return 0.0f; + } + float dps = AI_VALUE(float, "estimated group dps"); + bool aoePenalty = AI_VALUE(uint8, "attacker count") >= 3; + if (aoePenalty) + dps *= 0.75; + float res = target->GetHealth() / dps; + // bot->Say(target->GetName() + " lifetime: " + std::to_string(res), LANG_UNIVERSAL); + return res; +} + +float EstimatedGroupDpsValue::Calculate() +{ + float totalDps; + + std::vector groupPlayer={bot}; + if (Group* group = bot->GetGroup()) + { + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (member == bot) // calculated + continue; + + if (!member || !member->IsInWorld()) + continue; + + if (member->GetMapId() != bot->GetMapId()) + continue; + + if (member->GetExactDist(bot) > sPlayerbotAIConfig->sightDistance) + continue; + + groupPlayer.push_back(member); + } + } + for (Player* player : groupPlayer) + { + float roleMultiplier; + if (botAI->IsTank(player)) + roleMultiplier = 0.3f; + else if (botAI->IsHeal(player)) + roleMultiplier = 0.1f; + else + roleMultiplier = 1.0f; + float basicDps = GetBasicDps(player->GetLevel()); + float basicGs = GetBasicGs(player->GetLevel()); + uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(player, true, false, 12); + + float gap = (float)mixedGearScore / basicGs - 1; + float gs_modifier = gap * 3 + 1; + if (gs_modifier < 0.75) + gs_modifier = 0.75; + if (gs_modifier > 4) + gs_modifier = 4; + totalDps += basicDps * roleMultiplier * gs_modifier; + } + + return totalDps; +} + +float EstimatedGroupDpsValue::GetBasicDps(uint32 level) +{ + float basic_dps; + + if (level <= 15) + { + basic_dps = 5 + level * 1; + } + else if (level <= 25) + { + basic_dps = 20 + (level - 15) * 2; + } + else if (level <= 45) + { + basic_dps = 40 + (level - 25) * 3; + } + else if (level <= 55) + { + basic_dps = 100 + (level - 45) * 20; + } + else if (level <= 60) + { + basic_dps = 300 + (level - 55) * 50; + } + else if (level <= 70) + { + basic_dps = 450 + (level - 60) * 40; + } + else + { + basic_dps = 750 + (level - 70) * 175; + } + return basic_dps; +} + +float EstimatedGroupDpsValue::GetBasicGs(uint32 level) +{ + float basic_gs; + + if (level <= 8) + { + basic_gs = (level + 5) * 2; + } + else if (level <= 15) + { + basic_gs = (level + 5) * 3; + } + else if (level <= 60) + { + basic_gs = (level + 5) * 4; + } + else if (level <= 70) + { + basic_gs = (85 + (level - 60) * 3) * 4; + } + else + { + basic_gs = (155 + (level - 70) * 4) * 4; + } + return basic_gs; +} \ No newline at end of file diff --git a/src/strategy/values/ExpectedLifetimeValue.h b/src/strategy/values/EstimatedLifetimeValue.h similarity index 51% rename from src/strategy/values/ExpectedLifetimeValue.h rename to src/strategy/values/EstimatedLifetimeValue.h index 2afcece8..f050ac71 100644 --- a/src/strategy/values/ExpectedLifetimeValue.h +++ b/src/strategy/values/EstimatedLifetimeValue.h @@ -3,8 +3,8 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ -#ifndef _PLAYERBOT_EXPECTEDLIFETIMEVALUE_H -#define _PLAYERBOT_EXPECTEDLIFETIMEVALUE_H +#ifndef _PLAYERBOT_EstimatedLifetimeValue_H +#define _PLAYERBOT_EstimatedLifetimeValue_H #include "NamedObjectContext.h" #include "PossibleTargetsValue.h" @@ -15,22 +15,26 @@ class PlayerbotAI; class Unit; // [target health] / [expected group single target dps] = [expected lifetime] -class ExpectedLifetimeValue : public FloatCalculatedValue, public Qualified +class EstimatedLifetimeValue : public FloatCalculatedValue, public Qualified { public: - ExpectedLifetimeValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "expected lifetime") {} + EstimatedLifetimeValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "estimated lifetime") {} public: float Calculate() override; }; -class ExpectedGroupDpsValue : public FloatCalculatedValue +class EstimatedGroupDpsValue : public FloatCalculatedValue { public: - ExpectedGroupDpsValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "expected group dps", 20 * 1000) {} + EstimatedGroupDpsValue(PlayerbotAI* botAI) : FloatCalculatedValue(botAI, "estimated group dps", 20 * 1000) {} public: float Calculate() override; + +protected: + float GetBasicDps(uint32 level); + float GetBasicGs(uint32 level); }; #endif diff --git a/src/strategy/values/ExpectedLifetimeValue.cpp b/src/strategy/values/ExpectedLifetimeValue.cpp deleted file mode 100644 index 892ee349..00000000 --- a/src/strategy/values/ExpectedLifetimeValue.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "ExpectedLifetimeValue.h" - -#include "AiFactory.h" -#include "PlayerbotAI.h" -#include "Playerbots.h" -#include "SharedDefines.h" - -float ExpectedLifetimeValue::Calculate() -{ - Unit* target = AI_VALUE(Unit*, qualifier); - if (!target || !target->IsAlive()) - { - return 0.0f; - } - float dps = AI_VALUE(float, "expected group dps"); - bool aoePenalty = AI_VALUE(uint8, "attacker count") >= 3; - if (aoePenalty) - dps *= 0.75; - float res = target->GetHealth() / dps; - // bot->Say(target->GetName() + " lifetime: " + std::to_string(res), LANG_UNIVERSAL); - return res; -} - -float ExpectedGroupDpsValue::Calculate() -{ - float dps_num; - Group* group = bot->GetGroup(); - if (!group) - { - dps_num = 0.7; - } - else - { - dps_num = botAI->GetNearGroupMemberCount() * 0.7; - } - uint32 mixedGearScore = PlayerbotAI::GetMixedGearScore(bot, true, false, 12); - // efficiency record based on rare gear level, is there better calculation method? - // float dps_efficiency = 1; - float basic_dps; - int32 basic_gs; - int32 level = bot->GetLevel(); - - if (level <= 15) - { - basic_dps = 5 + level * 1; - } - else if (level <= 25) - { - basic_dps = 20 + (level - 15) * 2; - } - else if (level <= 40) - { - basic_dps = 40 + (level - 30) * 4; - } - else if (level <= 55) - { - basic_dps = 100 + (level - 45) * 20; - } - else if (level <= 60) - { - basic_dps = 300 + (level - 55) * 50; - } - else if (level <= 70) - { - basic_dps = 450 + (level - 60) * 40; - } - else - { - basic_dps = 750 + (level - 70) * 175; - } - - if (level <= 8) - { - basic_gs = (level + 5) * 2; - } - else if (level <= 15) - { - basic_gs = (level + 5) * 3; - } - else if (level <= 60) - { - basic_gs = (level + 5) * 4; - } - else if (level <= 70) - { - basic_gs = (85 + (level - 60) * 3) * 4; - } - else - { - basic_gs = (155 + (level - 70) * 4) * 4; - } - float gap = mixedGearScore - basic_gs; - float gs_modifier = (float)mixedGearScore / basic_gs - 1; - gs_modifier = gs_modifier * 3 + 1; - - if (gs_modifier < 0.75) - gs_modifier = 0.75; - if (gs_modifier > 4) - gs_modifier = 4; - - return dps_num * basic_dps * gs_modifier; -} \ No newline at end of file diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 6fb93fdf..f8f4a8fe 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -26,7 +26,7 @@ #include "DuelTargetValue.h" #include "EnemyHealerTargetValue.h" #include "EnemyPlayerValue.h" -#include "ExpectedLifetimeValue.h" +#include "EstimatedLifetimeValue.h" #include "Formations.h" #include "GrindTargetValue.h" #include "GroupValues.h" @@ -299,8 +299,8 @@ public: creators["boss target"] = &ValueContext::boss_target; creators["nearest triggers"] = &ValueContext::nearest_triggers; creators["neglect threat"] = &ValueContext::neglect_threat; - creators["expected lifetime"] = &ValueContext::expected_lifetime; - creators["expected group dps"] = &ValueContext::expected_group_dps; + creators["estimated lifetime"] = &ValueContext::expected_lifetime; + creators["estimated group dps"] = &ValueContext::expected_group_dps; creators["area debuff"] = &ValueContext::area_debuff; creators["nearest trap with damage"] = &ValueContext::nearest_trap_with_damange; creators["disperse distance"] = &ValueContext::disperse_distance; @@ -538,8 +538,8 @@ private: static UntypedValue* boss_target(PlayerbotAI* ai) { return new BossTargetValue(ai); } static UntypedValue* nearest_triggers(PlayerbotAI* ai) { return new NearestTriggersValue(ai); } static UntypedValue* neglect_threat(PlayerbotAI* ai) { return new NeglectThreatResetValue(ai); } - static UntypedValue* expected_lifetime(PlayerbotAI* ai) { return new ExpectedLifetimeValue(ai); } - static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new ExpectedGroupDpsValue(ai); } + static UntypedValue* expected_lifetime(PlayerbotAI* ai) { return new EstimatedLifetimeValue(ai); } + static UntypedValue* expected_group_dps(PlayerbotAI* ai) { return new EstimatedGroupDpsValue(ai); } static UntypedValue* area_debuff(PlayerbotAI* ai) { return new AreaDebuffValue(ai); } static UntypedValue* nearest_trap_with_damange(PlayerbotAI* ai) { return new NearestTrapWithDamageValue(ai); } static UntypedValue* disperse_distance(PlayerbotAI* ai) { return new DisperseDistanceValue(ai); }