life time check for debuff spell & cast time spell

This commit is contained in:
Yunfan Li
2023-09-04 17:04:59 +08:00
parent 9575ca222b
commit 7e1de0b9cf
9 changed files with 138 additions and 25 deletions

View File

@@ -11,32 +11,46 @@ float CastTimeMultiplier::GetValue(Action* action)
if (action == nullptr)
return 1.0f;
uint8 targetHealth = AI_VALUE2(uint8, "health", "current target");
// uint8 targetHealth = AI_VALUE2(uint8, "health", "current target");
std::string const name = action->getName();
if (action->GetTarget() != AI_VALUE(Unit*, "current target"))
if (!action->GetTarget() || action->GetTarget() != AI_VALUE(Unit*, "current target"))
return 1.0f;
if (targetHealth < sPlayerbotAIConfig->criticalHealth && dynamic_cast<CastSpellAction*>(action))
if (/*targetHealth < sPlayerbotAIConfig->criticalHealth && */dynamic_cast<CastSpellAction*>(action))
{
uint32 spellId = AI_VALUE2(uint32, "spell id", name);
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
return 1.0f;
if ((spellInfo->Targets & TARGET_FLAG_DEST_LOCATION) != 0|| (spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) != 0)
if ((spellInfo->Targets & TARGET_FLAG_DEST_LOCATION) != 0 || (spellInfo->Targets & TARGET_FLAG_SOURCE_LOCATION) != 0)
return 1.0f;
uint32 castTime = spellInfo->CalcCastTime();
if (spellInfo->IsChanneled())
{
int32 duration = spellInfo->GetDuration();
bot->ApplySpellMod(spellInfo->Id, SPELLMOD_DURATION, duration);
duration = std::min(duration, 3000);
if (duration > 0)
castTime += duration;
}
if (castTime > (1000 * action->GetTarget()->GetHealth() / AI_VALUE(float, "expected group dps"))) {
return 0.0f;
}
}
// if (castTime >= 3000)
// return 0.0f;
if (castTime >= 1500)
return 0.5f;
// if (castTime >= 1500)
// return 0.5f;
if (castTime >= 1000)
return 0.25f;
}
// if (castTime >= 1000)
// return 0.25f;
// // }
return 1.0f;
}

View File

@@ -13,7 +13,7 @@ class ArcaneMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode
creators["arcane blast"] = &arcane_blast;
creators["arcane barrage"] = &arcane_barrage;
creators["arcane missiles"] = &arcane_missiles;
creators["firebolt"] = &firebolt;
// creators["firebolt"] = &firebolt;
}
private:
@@ -41,13 +41,13 @@ class ArcaneMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode
/*C*/ nullptr);
}
static ActionNode* firebolt([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("firebolt",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("shoot"), nullptr),
/*C*/ nullptr);
}
// static ActionNode* firebolt([[maybe_unused]] PlayerbotAI* botAI)
// {
// return new ActionNode ("firebolt",
// /*P*/ nullptr,
// /*A*/ NextAction::array(0, new NextAction("shoot"), nullptr),
// /*C*/ nullptr);
// }
};
ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)

View File

@@ -21,6 +21,7 @@ class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
creators["blast wave"] = &blast_wave;
creators["remove curse"] = &remove_curse;
creators["remove curse on party"] = &remove_curse_on_party;
creators["firebolt"] = &firebolt;
}
private:
@@ -111,6 +112,13 @@ class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNod
/*A*/ NextAction::array(0, new NextAction("remove lesser curse on party"), nullptr),
/*C*/ nullptr);
}
static ActionNode* firebolt([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode ("firebolt",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("shoot"), nullptr),
/*C*/ nullptr);
}
};
GenericMageStrategy::GenericMageStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI)

View File

@@ -207,7 +207,7 @@ bool TargetInSightTrigger::IsActive()
bool DebuffTrigger::IsActive()
{
return BuffTrigger::IsActive() && AI_VALUE2(uint8, "health", GetTargetName()) > life_bound;
return BuffTrigger::IsActive() && GetTarget() && (1000 * GetTarget()->GetHealth() / AI_VALUE(float, "expected group dps")) >= needLifeTime;
}
bool DebuffOnBossTrigger::IsActive()

View File

@@ -315,12 +315,12 @@ class TargetInSightTrigger : public Trigger
class DebuffTrigger : public BuffTrigger
{
public:
DebuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false, float life_bound = 0.25) : BuffTrigger(botAI, spell, checkInterval, checkIsOwner), life_bound(life_bound) { }
DebuffTrigger(PlayerbotAI* botAI, std::string const spell, int32 checkInterval = 1, bool checkIsOwner = false, float needLifeTime = 8000.0f) : BuffTrigger(botAI, spell, checkInterval, checkIsOwner), needLifeTime(needLifeTime) { }
std::string const GetTargetName() override { return "current target"; }
bool IsActive() override;
protected:
float life_bound;
float needLifeTime;
};
class DebuffOnBossTrigger : public DebuffTrigger
@@ -333,7 +333,7 @@ class DebuffOnBossTrigger : public DebuffTrigger
class DebuffOnAttackerTrigger : public DebuffTrigger
{
public:
DebuffOnAttackerTrigger(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = true) : DebuffTrigger(botAI, spell, 1, checkIsOwner) { }
DebuffOnAttackerTrigger(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = true, float needLifeTime = 8000.0f) : DebuffTrigger(botAI, spell, 1, checkIsOwner, needLifeTime) { }
Value<Unit*>* GetTargetValue() override;
std::string const getName() override { return spell + " on attacker"; }

View File

@@ -0,0 +1,43 @@
#include "ExpectedLifetimeValue.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");
float res = target->GetHealth() / dps * 1000;
// 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 = 1;
} else {
dps_num = group->GetMembersCount() * 0.7;
}
// efficiency record based on rare gear level, is there better calculation method?
float dps_efficiency = 1;
if (bot->GetLevel() < 30) {
dps_efficiency = 1.5;
} else if (bot->GetLevel() < 40) {
dps_efficiency = 2;
} else if (bot->GetLevel() < 50) {
dps_efficiency = 3;
} else if (bot->GetLevel() < 60) {
dps_efficiency = 4;
} else if (bot->GetLevel() < 70) {
dps_efficiency = 7;
} else if (bot->GetLevel() < 80) {
dps_efficiency = 12;
} else {
dps_efficiency = 30;
}
return dps_num * bot->GetLevel() * dps_efficiency;
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it 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
#include "NamedObjectContext.h"
#include "TargetValue.h"
#include "PossibleTargetsValue.h"
#include "Value.h"
class PlayerbotAI;
class Unit;
// [target health] / [expected group single target dps] = [expected lifetime]
class ExpectedLifetimeValue : public FloatCalculatedValue, public Qualified
{
public:
ExpectedLifetimeValue(PlayerbotAI* botAI) :
FloatCalculatedValue(botAI, "expected lifetime") { }
public:
float Calculate() override;
};
class ExpectedGroupDpsValue : public FloatCalculatedValue
{
public:
ExpectedGroupDpsValue(PlayerbotAI* botAI) :
FloatCalculatedValue(botAI, "expected group dps") { }
public:
float Calculate() override;
};
#endif

View File

@@ -25,6 +25,7 @@
#include "DistanceValue.h"
#include "EnemyHealerTargetValue.h"
#include "EnemyPlayerValue.h"
#include "ExpectedLifetimeValue.h"
#include "Formations.h"
#include "GroupValues.h"
#include "GrindTargetValue.h"
@@ -293,6 +294,8 @@ class ValueContext : public NamedObjectContext<UntypedValue>
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;
}
private:
@@ -490,6 +493,9 @@ class ValueContext : public NamedObjectContext<UntypedValue>
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); }
};
#endif

View File

@@ -25,7 +25,13 @@ class SpellstoneTrigger : public BuffTrigger
bool IsActive() override;
};
DEBUFF_CHECKISOWNER_TRIGGER(CurseOfAgonyTrigger, "curse of agony");
// DEBUFF_CHECKISOWNER_TRIGGER(CurseOfAgonyTrigger, "curse of agony");
class CurseOfAgonyTrigger : public DebuffTrigger
{
public:
CurseOfAgonyTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "curse of agony", 1, true, 20000.0f) { }
};
DEBUFF_CHECKISOWNER_TRIGGER(CorruptionTrigger, "corruption");
DEBUFF_CHECKISOWNER_TRIGGER(SiphonLifeTrigger, "siphon life");
@@ -38,7 +44,7 @@ class CorruptionOnAttackerTrigger : public DebuffOnAttackerTrigger
class CastCurseOfAgonyOnAttackerTrigger : public DebuffOnAttackerTrigger
{
public:
CastCurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "curse of agony", true) { }
CastCurseOfAgonyOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "curse of agony", true, 20000.0f) { }
};
class SiphonLifeOnAttackerTrigger : public DebuffOnAttackerTrigger