mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
life time check for debuff spell & cast time spell
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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"; }
|
||||
|
||||
43
src/strategy/values/ExpectedLifetimeValue.cpp
Normal file
43
src/strategy/values/ExpectedLifetimeValue.cpp
Normal 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;
|
||||
}
|
||||
36
src/strategy/values/ExpectedLifetimeValue.h
Normal file
36
src/strategy/values/ExpectedLifetimeValue.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user