Improve class spell and use trinket

This commit is contained in:
Yunfan Li
2024-08-14 18:18:01 +08:00
parent c778e303df
commit a1cb9dea05
47 changed files with 377 additions and 108 deletions

View File

@@ -225,7 +225,10 @@ bool StatsCollector::SpecialSpellFilter(uint32 spellId) {
if (type_ != CollectorType::SPELL_HEAL)
stats[STATS_TYPE_CRIT] += 50;
return true;
break;
case 59620:
if (type_ == CollectorType::MELEE)
stats[STATS_TYPE_ATTACK_POWER] += 120;
return true;
case 67702: // Death's Verdict
stats[STATS_TYPE_ATTACK_POWER] += 225;
return true;
@@ -493,6 +496,13 @@ void StatsCollector::HandleApplyAura(const SpellEffectInfo& effectInfo, float mu
case SPELL_AURA_MOD_INCREASE_HEALTH:
stats[STATS_TYPE_STAMINA] += val * multiplier / 15;
break;
case SPELL_AURA_SCHOOL_ABSORB:
{
int32 schoolType = effectInfo.MiscValue;
if (schoolType & SPELL_SCHOOL_MASK_NORMAL)
stats[STATS_TYPE_STAMINA] += val * multiplier / 15;
break;
}
case SPELL_AURA_MOD_ATTACK_POWER:
stats[STATS_TYPE_ATTACK_POWER] += val * multiplier;
break;

View File

@@ -9,6 +9,7 @@
#include "AiFactory.h"
#include "DBCStores.h"
#include "ItemTemplate.h"
#include "ObjectMgr.h"
#include "PlayerbotAI.h"
#include "SharedDefines.h"
@@ -231,7 +232,8 @@ void StatsWeightCalculator::GenerateBasicWeights(Player* player)
stats_weights_[STATS_TYPE_EXPERTISE] += 2.0f;
stats_weights_[STATS_TYPE_MELEE_DPS] += 5.2f;
}
else if (cls == CLASS_WARLOCK || cls == CLASS_MAGE ||
else if (cls == CLASS_WARLOCK ||
cls == CLASS_MAGE ||
(cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW) || // shadow
(cls == CLASS_SHAMAN && tab == SHAMAN_TAB_ELEMENTAL) || // element
(cls == CLASS_DRUID && tab == DRUID_TAB_BALANCE)) // balance
@@ -454,6 +456,16 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
{
weight_ *= 0.1;
}
if (cls == CLASS_ROGUE && player_->HasAura(13964)
&& (proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
{
weight_ *= 1.1;
}
if (cls == CLASS_WARRIOR && player_->HasAura(12785)
&& (proto->SubClass == ITEM_SUBCLASS_WEAPON_THROWN || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2))
{
weight_ *= 1.1;
}
}
}

View File

@@ -154,6 +154,9 @@ public:
creators["give water"] = &ActionContext::give_water;
creators["mount"] = &ActionContext::mount;
creators["war stomp"] = &ActionContext::war_stomp;
creators["blood fury"] = &ActionContext::blood_fury;
creators["berserking"] = &ActionContext::berserking;
creators["use trinket"] = &ActionContext::use_trinket;
creators["auto talents"] = &ActionContext::auto_talents;
creators["auto learn spell"] = &ActionContext::auto_learn_spell;
creators["auto share quest"] = &ActionContext::auto_share_quest;
@@ -324,6 +327,9 @@ private:
static Action* try_emergency(PlayerbotAI* botAI) { return new TryEmergencyAction(botAI); }
static Action* mount(PlayerbotAI* botAI) { return new CastSpellAction(botAI, "mount"); }
static Action* war_stomp(PlayerbotAI* botAI) { return new CastWarStompAction(botAI); }
static Action* blood_fury(PlayerbotAI* botAI) { return new CastBloodFuryAction(botAI); }
static Action* berserking(PlayerbotAI* botAI) { return new CastBerserkingAction(botAI); }
static Action* use_trinket(PlayerbotAI* botAI) { return new UseTrinketAction(botAI); }
static Action* auto_talents(PlayerbotAI* botAI) { return new AutoSetTalentsAction(botAI); }
static Action* auto_learn_spell(PlayerbotAI* botAI) { return new AutoLearnSpellAction(botAI); }
static Action* auto_share_quest(PlayerbotAI* ai) { return new AutoShareQuestAction(ai); }

View File

@@ -36,9 +36,9 @@ bool TogglePetSpellAutoCastAction::Execute(Event event)
continue;
bool shouldApply = true;
// imp's spell, felhunte's intelligence, ghoul's leap, cat stealth
// imp's spell, felhunte's intelligence, cat stealth
if (spellId == 4511 || spellId == 1742 || spellId == 54424 || spellId == 57564 || spellId == 57565 ||
spellId == 57566 || spellId == 57567 || spellId == 47482 || spellId == 24450)
spellId == 57566 || spellId == 57567 || spellId == 24450)
{
shouldApply = false;
}
@@ -72,7 +72,7 @@ bool PetAttackAction::Execute(Event event)
{
return false;
}
// pet->SetReactState(REACT_DEFENSIVE);
pet->SetReactState(REACT_PASSIVE);
pet->ClearUnitState(UNIT_STATE_FOLLOW);
pet->AttackStop();
pet->SetTarget(target->GetGUID());

View File

@@ -6,8 +6,13 @@
#include "GenericSpellActions.h"
#include "Event.h"
#include "ItemTemplate.h"
#include "ObjectDefines.h"
#include "Opcodes.h"
#include "Player.h"
#include "Playerbots.h"
#include "ServerFacade.h"
#include "WorldPacket.h"
CastSpellAction::CastSpellAction(PlayerbotAI* botAI, std::string const spell)
: Action(botAI, spell), range(botAI->GetRange("spell")), spell(spell)
@@ -124,11 +129,35 @@ bool CastSpellAction::isUseful()
CastMeleeSpellAction::CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell) : CastSpellAction(botAI, spell)
{
range = ATTACK_DISTANCE;
// Unit* target = AI_VALUE(Unit*, "current target");
// if (target)
// range = bot->GetMeleeRange(target);
}
// range = target->GetCombinedCombatReach();
bool CastMeleeSpellAction::isUseful()
{
Unit* target = GetTarget();
if (!target)
return false;
if (!bot->IsWithinMeleeRange(target))
return false;
return CastSpellAction::isUseful();
}
CastMeleeDebuffSpellAction::CastMeleeDebuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner, float needLifeTime) : CastDebuffSpellAction(botAI, spell, isOwner, needLifeTime)
{
range = ATTACK_DISTANCE;
}
bool CastMeleeDebuffSpellAction::isUseful()
{
Unit* target = GetTarget();
if (!target)
return false;
if (!bot->IsWithinMeleeRange(target))
return false;
return CastDebuffSpellAction::isUseful();
}
bool CastAuraSpellAction::isUseful()
@@ -209,17 +238,7 @@ CastShootAction::CastShootAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "s
NextAction** CastSpellAction::getPrerequisites()
{
if (spell == "mount")
return nullptr;
if (range > botAI->GetRange("spell"))
return nullptr;
else if (range > ATTACK_DISTANCE)
return NextAction::merge(NextAction::array(0, new NextAction("reach spell"), nullptr),
Action::getPrerequisites());
else
return NextAction::merge(NextAction::array(0, new NextAction("reach melee"), nullptr),
Action::getPrerequisites());
return nullptr;
}
Value<Unit*>* CastDebuffSpellOnAttackerAction::GetTargetValue()
@@ -271,6 +290,70 @@ bool CastVehicleSpellAction::Execute(Event event)
return botAI->CastVehicleSpell(spellId, GetTarget());
}
bool UseTrinketAction::Execute(Event event)
{
Item* trinket1 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TRINKET1);
if (trinket1 && UseTrinket(trinket1))
return true;
Item* trinket2 = bot->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_TRINKET2);
if (trinket2 && UseTrinket(trinket2))
return true;
return false;
}
bool UseTrinketAction::UseTrinket(Item* item)
{
if (bot->CanUseItem(item) != EQUIP_ERR_OK)
return false;
if (bot->IsNonMeleeSpellCast(true))
return false;
uint8 bagIndex = item->GetBagSlot();
uint8 slot = item->GetSlot();
uint8 spell_index = 0;
uint8 cast_count = 1;
ObjectGuid item_guid = item->GetGUID();
uint32 glyphIndex = 0;
uint8 castFlags = 0;
uint32 targetFlag = TARGET_FLAG_NONE;
uint32 spellId = 0;
for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
{
if (item->GetTemplate()->Spells[i].SpellId > 0 && item->GetTemplate()->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE)
{
spellId = item->GetTemplate()->Spells[i].SpellId;
if (!botAI->CanCastSpell(spellId, bot, false))
{
return false;
}
break;
}
}
if (!spellId)
return false;
WorldPacket packet(CMSG_USE_ITEM);
packet << bagIndex << slot << cast_count << spellId << item_guid << glyphIndex << castFlags;
Unit* target = AI_VALUE(Unit*, "current target");
if (target)
{
targetFlag = TARGET_FLAG_UNIT;
packet << targetFlag << target->GetGUID().WriteAsPacked();
}
else
{
targetFlag = TARGET_FLAG_NONE;
packet << targetFlag << bot->GetPackGUID();
}
bot->GetSession()->HandleUseItemOpcode(packet);
return true;
}
Value<Unit*>* BuffOnMainTankAction::GetTargetValue() { return context->GetValue<Unit*>("main tank", spell); }
bool CastDebuffSpellAction::isUseful()

View File

@@ -9,6 +9,7 @@
#include "Action.h"
#include "PlayerbotAI.h"
#include "PlayerbotAIConfig.h"
#include "UseItemAction.h"
#include "Value.h"
class PlayerbotAI;
@@ -52,6 +53,7 @@ class CastMeleeSpellAction : public CastSpellAction
{
public:
CastMeleeSpellAction(PlayerbotAI* botAI, std::string const spell);
bool isUseful() override;
};
class CastDebuffSpellAction : public CastAuraSpellAction
@@ -67,6 +69,13 @@ private:
float needLifeTime;
};
class CastMeleeDebuffSpellAction : public CastDebuffSpellAction
{
public:
CastMeleeDebuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool isOwner = false, float needLifeTime = 8.0f);
bool isUseful() override;
};
class CastDebuffSpellOnAttackerAction : public CastDebuffSpellAction
{
public:
@@ -245,10 +254,31 @@ public:
CastManaTapAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mana tap") {}
};
class CastWarStompAction : public CastSpellAction
class CastWarStompAction : public CastMeleeSpellAction
{
public:
CastWarStompAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "war stomp") {}
CastWarStompAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "war stomp") {}
};
class CastBloodFuryAction : public CastBuffSpellAction
{
public:
CastBloodFuryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "blood fury") {}
};
class CastBerserkingAction : public CastBuffSpellAction
{
public:
CastBerserkingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "berserking") {}
};
class UseTrinketAction : public Action
{
public:
UseTrinketAction(PlayerbotAI* botAI) : Action(botAI, "use trinket") {}
bool Execute(Event event) override;
protected:
bool UseTrinket(Item* trinket);
};
class CastSpellOnEnemyHealerAction : public CastSpellAction

View File

@@ -143,7 +143,10 @@ std::vector<std::pair<uint32, std::string>> ListSpellsAction::GetSpellList(std::
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first);
if (!spellInfo)
continue;
if (spellInfo->IsPassive())
continue;
SkillLineAbilityEntry const* skillLine = skillSpells[itr->first];
if (skill != SKILL_NONE && (!skillLine || skillLine->SkillLine != skill))
continue;

View File

@@ -110,11 +110,11 @@ public:
CastIcyTouchAction(PlayerbotAI* ai) : CastSpellAction(ai, "icy touch") {}
};
class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnMeleeAttackerAction
class CastIcyTouchOnAttackerAction : public CastDebuffSpellOnAttackerAction
{
public:
CastIcyTouchOnAttackerAction(PlayerbotAI* botAI)
: CastDebuffSpellOnMeleeAttackerAction(botAI, "icy touch", true, .0f)
: CastDebuffSpellOnAttackerAction(botAI, "icy touch", true, .0f)
{
}
};
@@ -232,16 +232,17 @@ public:
CastDeathCoilAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death coil") {}
};
class CastBloodBoilAction : public CastSpellAction
class CastBloodBoilAction : public CastMeleeSpellAction
{
public:
CastBloodBoilAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blood boil") {}
CastBloodBoilAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "blood boil") {}
};
class CastDeathAndDecayAction : public CastSpellAction
{
public:
CastDeathAndDecayAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "death and decay") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};
class CastHornOfWinterAction : public CastSpellAction

View File

@@ -234,10 +234,10 @@ public:
NextAction** getAlternatives() override;
};
class CastBarskinAction : public CastBuffSpellAction
class CastBarkskinAction : public CastBuffSpellAction
{
public:
CastBarskinAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "barskin") {}
CastBarkskinAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "barkskin") {}
};
class CastInnervateAction : public CastSpellAction

View File

@@ -198,7 +198,7 @@ public:
creators["healing touch on party"] = &DruidAiObjectContextInternal::healing_touch_on_party;
creators["rebirth"] = &DruidAiObjectContextInternal::rebirth;
creators["revive"] = &DruidAiObjectContextInternal::revive;
creators["barskin"] = &DruidAiObjectContextInternal::barskin;
creators["barkskin"] = &DruidAiObjectContextInternal::barkskin;
creators["lacerate"] = &DruidAiObjectContextInternal::lacerate;
creators["hurricane"] = &DruidAiObjectContextInternal::hurricane;
creators["innervate"] = &DruidAiObjectContextInternal::innervate;
@@ -281,7 +281,7 @@ private:
static Action* healing_touch_on_party(PlayerbotAI* botAI) { return new CastHealingTouchOnPartyAction(botAI); }
static Action* rebirth(PlayerbotAI* botAI) { return new CastRebirthAction(botAI); }
static Action* revive(PlayerbotAI* botAI) { return new CastReviveAction(botAI); }
static Action* barskin(PlayerbotAI* botAI) { return new CastBarskinAction(botAI); }
static Action* barkskin(PlayerbotAI* botAI) { return new CastBarkskinAction(botAI); }
static Action* lacerate(PlayerbotAI* botAI) { return new CastLacerateAction(botAI); }
static Action* hurricane(PlayerbotAI* botAI) { return new CastHurricaneAction(botAI); }
static Action* innervate(PlayerbotAI* botAI) { return new CastInnervateAction(botAI); }

View File

@@ -43,10 +43,10 @@ public:
CastSwipeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "swipe") {}
};
class CastDemoralizingRoarAction : public CastDebuffSpellAction
class CastDemoralizingRoarAction : public CastMeleeDebuffSpellAction
{
public:
CastDemoralizingRoarAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "demoralizing roar") {}
CastDemoralizingRoarAction(PlayerbotAI* botAI) : CastMeleeDebuffSpellAction(botAI, "demoralizing roar") {}
};
class CastMangleBearAction : public CastMeleeSpellAction

View File

@@ -27,7 +27,7 @@ private:
{
return new ActionNode("survival instincts",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("barskin"), nullptr),
/*A*/ NextAction::array(0, new NextAction("barkskin"), nullptr),
/*C*/ nullptr);
}

View File

@@ -106,6 +106,9 @@ void GenericDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
CombatStrategy::InitTriggers(triggers);
triggers.push_back(
new TriggerNode("low health", NextAction::array(0, new NextAction("barkskin", ACTION_HIGH + 7), nullptr)));
// triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("regrowth",
// ACTION_MEDIUM_HEAL + 2), nullptr))); triggers.push_back(new TriggerNode("party member low health",
// NextAction::array(0, new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1), nullptr)));

View File

@@ -25,14 +25,18 @@ private:
void RacialsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
triggers.push_back(
new TriggerNode("low health", NextAction::array(0, new NextAction("lifeblood", 71.0f), nullptr)));
// triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("war stomp", 71.0f),
// nullptr)));
/*triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("war stomp", 71.0f),
* nullptr)));*/
/*triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("arcane torrent",
ACTION_EMERGENCY + 6), nullptr))); triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new
NextAction("mana tap", ACTION_EMERGENCY + 6), nullptr)));*/
new TriggerNode("low health", NextAction::array(0, new NextAction("lifeblood", ACTION_NORMAL + 5), nullptr)));
triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("war stomp", ACTION_NORMAL + 5), nullptr)));
triggers.push_back(new TriggerNode(
"low mana", NextAction::array(0, new NextAction("arcane torrent", ACTION_NORMAL + 5), nullptr)));
triggers.push_back(new TriggerNode(
"generic boost", NextAction::array(0, new NextAction("blood fury", ACTION_NORMAL + 5),
new NextAction("berserking", ACTION_NORMAL + 5),
new NextAction("use trinket", ACTION_NORMAL + 4),
nullptr)));
}
RacialsStrategy::RacialsStrategy(PlayerbotAI* botAI) : Strategy(botAI)

View File

@@ -10,7 +10,11 @@
class DpsHunterStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
{
public:
DpsHunterStrategyActionNodeFactory() { creators["aimed shot"] = &aimed_shot; }
DpsHunterStrategyActionNodeFactory()
{
creators["aimed shot"] = &aimed_shot;
creators["steady shot"] = &steady_shot;
}
private:
static ActionNode* aimed_shot([[maybe_unused]] PlayerbotAI* botAI)
@@ -20,6 +24,13 @@ private:
/*A*/ NextAction::array(0, new NextAction("multi-shot"), nullptr),
/*C*/ nullptr);
}
static ActionNode* steady_shot([[maybe_unused]] PlayerbotAI* botAI)
{
return new ActionNode("steady shot",
/*P*/ nullptr,
/*A*/ NextAction::array(0, new NextAction("arcane shot"), nullptr),
/*C*/ nullptr);
}
};
DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI)
@@ -32,7 +43,7 @@ NextAction** DpsHunterStrategy::getDefaultActions()
return NextAction::array(
0, new NextAction("kill shot", ACTION_DEFAULT + 0.6f), new NextAction("chimera shot", ACTION_DEFAULT + 0.5f),
new NextAction("explosive shot", ACTION_DEFAULT + 0.4f), new NextAction("aimed shot", ACTION_DEFAULT + 0.3f),
new NextAction("arcane shot", ACTION_DEFAULT + 0.2f), new NextAction("steady shot", ACTION_DEFAULT + 0.1f),
/*new NextAction("arcane shot", ACTION_DEFAULT + 0.2f),*/ new NextAction("steady shot", ACTION_DEFAULT + 0.1f),
new NextAction("auto shot", ACTION_DEFAULT), nullptr);
// return NextAction::array(0, new NextAction("explosive shot", 11.0f), new NextAction("auto shot", 10.0f), new
// NextAction("auto attack", 9.0f), nullptr);

View File

@@ -97,6 +97,9 @@ void GenericHunterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(
new TriggerNode("misdirection on main tank",
NextAction::array(0, new NextAction("misdirection on main tank", ACTION_HIGH + 7), NULL)));
triggers.push_back(
new TriggerNode("low health", NextAction::array(0, new NextAction("deterrence", ACTION_HIGH + 5), nullptr)));
triggers.push_back(new TriggerNode("tranquilizing shot enrage",
NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL)));
triggers.push_back(new TriggerNode("tranquilizing shot magic",

View File

@@ -32,8 +32,11 @@ public:
BEGIN_RANGED_SPELL_ACTION(CastArcaneShotAction, "arcane shot")
END_SPELL_ACTION()
BEGIN_RANGED_SPELL_ACTION(CastExplosiveShotAction, "explosive shot")
END_SPELL_ACTION()
class CastExplosiveShotAction : public CastDebuffSpellAction
{
public:
CastExplosiveShotAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {}
};
BEGIN_RANGED_SPELL_ACTION(CastAimedShotAction, "aimed shot")
END_SPELL_ACTION()
@@ -160,6 +163,12 @@ public:
CastRapidFireAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "rapid fire") {}
};
class CastDeterrenceAction : public CastBuffSpellAction
{
public:
CastDeterrenceAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "deterrence") {}
};
class CastReadinessAction : public CastBuffSpellAction
{
public:

View File

@@ -149,6 +149,7 @@ public:
creators["freezing trap"] = &HunterAiObjectContextInternal::freezing_trap;
creators["rapid fire"] = &HunterAiObjectContextInternal::rapid_fire;
creators["boost"] = &HunterAiObjectContextInternal::rapid_fire;
creators["deterrence"] = &HunterAiObjectContextInternal::deterrence;
creators["readiness"] = &HunterAiObjectContextInternal::readiness;
creators["aspect of the hawk"] = &HunterAiObjectContextInternal::aspect_of_the_hawk;
creators["aspect of the monkey"] = &HunterAiObjectContextInternal::aspect_of_the_monkey;
@@ -200,6 +201,7 @@ private:
static Action* black_arrow(PlayerbotAI* botAI) { return new CastBlackArrow(botAI); }
static Action* freezing_trap(PlayerbotAI* botAI) { return new CastFreezingTrap(botAI); }
static Action* rapid_fire(PlayerbotAI* botAI) { return new CastRapidFireAction(botAI); }
static Action* deterrence(PlayerbotAI* botAI) { return new CastDeterrenceAction(botAI); }
static Action* readiness(PlayerbotAI* botAI) { return new CastReadinessAction(botAI); }
static Action* aspect_of_the_hawk(PlayerbotAI* botAI) { return new CastAspectOfTheHawkAction(botAI); }
static Action* aspect_of_the_monkey(PlayerbotAI* botAI) { return new CastAspectOfTheMonkeyAction(botAI); }

View File

@@ -85,7 +85,7 @@ NextAction** DpsPaladinStrategy::getDefaultActions()
return NextAction::array(0, new NextAction("crusader strike", ACTION_DEFAULT + 0.4f),
new NextAction("judgement of wisdom", ACTION_DEFAULT + 0.3f),
new NextAction("divine storm", ACTION_DEFAULT + 0.2f),
new NextAction("melee consecration", ACTION_DEFAULT + 0.1f),
new NextAction("consecration", ACTION_DEFAULT + 0.1f),
new NextAction("melee", ACTION_DEFAULT), NULL);
}
@@ -112,7 +112,7 @@ void DpsPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// triggers.push_back(new TriggerNode("repentance", NextAction::array(0, new NextAction("repentance",
// ACTION_INTERRUPT + 2), nullptr)));
triggers.push_back(new TriggerNode(
"medium aoe", NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 3), nullptr)));
"medium aoe", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 3), nullptr)));
triggers.push_back(
new TriggerNode("art of war", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 2), nullptr)));
triggers.push_back(new TriggerNode("target critical health",

View File

@@ -17,8 +17,8 @@ void GenericPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{
CombatStrategy::InitTriggers(triggers);
// triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("divine shield",
// ACTION_CRITICAL_HEAL + 2), new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), nullptr)));
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("divine shield",
ACTION_HIGH + 5), nullptr)));
triggers.push_back(
new TriggerNode("hammer of justice interrupt",
NextAction::array(0, new NextAction("hammer of justice", ACTION_INTERRUPT), nullptr)));

View File

@@ -153,13 +153,6 @@ Unit* CastRighteousDefenseAction::GetTarget()
return current_target->GetVictim();
}
bool CastMeleeConsecrationAction::isUseful()
{
Unit* target = GetTarget();
// float dis = distance + CONTACT_DISTANCE;
return target && bot->IsWithinMeleeRange(target); // sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float,
// "distance", GetTargetName()), distance);
}
bool CastDivineSacrificeAction::isUseful()
{

View File

@@ -44,13 +44,6 @@ SPELL_ACTION(CastHolyShockAction, "holy shock");
// consecration
MELEE_ACTION(CastConsecrationAction, "consecration");
class CastMeleeConsecrationAction : public CastSpellAction
{
public:
CastMeleeConsecrationAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "consecration") {}
bool isUseful() override;
};
// repentance
SNARE_ACTION(CastRepentanceSnareAction, "repentance");
DEBUFF_ACTION(CastRepentanceAction, "repentance");
@@ -67,10 +60,10 @@ BUFF_ACTION(CastDivineFavorAction, "divine favor");
// fury
BUFF_ACTION(CastRighteousFuryAction, "righteous fury");
class CastDivineStormAction : public CastBuffSpellAction
class CastDivineStormAction : public CastMeleeSpellAction
{
public:
CastDivineStormAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "divine storm") {}
CastDivineStormAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "divine storm") {}
};
class CastCrusaderStrikeAction : public CastMeleeSpellAction

View File

@@ -232,7 +232,6 @@ public:
creators["concentration aura"] = &PaladinAiObjectContextInternal::concentration_aura;
creators["holy wrath"] = &PaladinAiObjectContextInternal::holy_wrath;
creators["consecration"] = &PaladinAiObjectContextInternal::consecration;
creators["melee consecration"] = &PaladinAiObjectContextInternal::melee_consecration;
creators["cleanse disease"] = &PaladinAiObjectContextInternal::cleanse_disease;
creators["cleanse poison"] = &PaladinAiObjectContextInternal::cleanse_poison;
creators["cleanse magic"] = &PaladinAiObjectContextInternal::cleanse_magic;
@@ -331,7 +330,6 @@ private:
static Action* concentration_aura(PlayerbotAI* botAI) { return new CastConcentrationAuraAction(botAI); }
static Action* holy_wrath(PlayerbotAI* botAI) { return new CastHolyWrathAction(botAI); }
static Action* consecration(PlayerbotAI* botAI) { return new CastConsecrationAction(botAI); }
static Action* melee_consecration(PlayerbotAI* botAI) { return new CastMeleeConsecrationAction(botAI); }
static Action* cleanse_poison(PlayerbotAI* botAI) { return new CastCleansePoisonAction(botAI); }
static Action* cleanse_disease(PlayerbotAI* botAI) { return new CastCleanseDiseaseAction(botAI); }
static Action* cleanse_magic(PlayerbotAI* botAI) { return new CastCleanseMagicAction(botAI); }

View File

@@ -82,7 +82,7 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"light aoe", NextAction::array(0, new NextAction("avenger's shield", ACTION_HIGH + 5), nullptr)));
triggers.push_back(
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("melee consecration", ACTION_HIGH + 7),
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 7),
new NextAction("avenger's shield", ACTION_HIGH + 6), nullptr)));
// triggers.push_back(new TriggerNode("avenger's shield", NextAction::array(0, new NextAction("avenger's shield",
// ACTION_HIGH + 7), nullptr)));
@@ -107,7 +107,7 @@ void TankPaladinStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
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)));
"enough mana", NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 4), nullptr)));
triggers.push_back(new TriggerNode("not facing target",
NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), nullptr)));
triggers.push_back(new TriggerNode(

View File

@@ -31,8 +31,9 @@ void GenericPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// NextAction("inner focus", 42.0f), nullptr))); triggers.push_back(new TriggerNode("medium mana",
// NextAction::array(0, new NextAction("symbol of hope", ACTION_EMERGENCY), nullptr))); triggers.push_back(new
// TriggerNode("low mana", NextAction::array(0, new NextAction("consume magic", 10.0f), nullptr)));
// triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("desperate prayer",
// ACTION_EMERGENCY), nullptr))); triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("desperate prayer",
ACTION_HIGH + 5), nullptr)));
// triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new
// NextAction("elune's grace", ACTION_EMERGENCY), nullptr))); triggers.push_back(new TriggerNode("chastise",
// NextAction::array(0, new NextAction("chastise", ACTION_INTERRUPT), nullptr)));
triggers.push_back(new TriggerNode(

View File

@@ -73,7 +73,9 @@ void HolyHealPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(new TriggerNode(
"party member critical health",
NextAction::array(0, new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
NextAction::array(0,
new NextAction("guardian spirit on party", ACTION_CRITICAL_HEAL + 6),
new NextAction("power word: shield on party", ACTION_CRITICAL_HEAL + 5),
new NextAction("flash heal on party", ACTION_CRITICAL_HEAL + 3),
new NextAction("prayer of mending on party", ACTION_CRITICAL_HEAL + 2), NULL)));

View File

@@ -173,4 +173,11 @@ public:
CastMindSearAction(PlayerbotAI* ai) : CastSpellAction(ai, "mind sear") {}
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
};
class CastGuardianSpiritOnPartyAction : public HealPartyMemberAction
{
public:
CastGuardianSpiritOnPartyAction(PlayerbotAI* ai) : HealPartyMemberAction(ai, "guardian spirit", 40.0f, HealingManaEfficiency::MEDIUM) {}
};
#endif

View File

@@ -234,6 +234,7 @@ public:
creators["hymn of hope"] = &PriestAiObjectContextInternal::hymn_of_hope;
creators["divine hymn"] = &PriestAiObjectContextInternal::divine_hymn;
creators["mind sear"] = &PriestAiObjectContextInternal::mind_sear;
creators["guardian spirit on party"] = &PriestAiObjectContextInternal::guardian_spirit_on_party;
}
private:
@@ -339,6 +340,7 @@ private:
static Action* hymn_of_hope(PlayerbotAI* ai) { return new CastHymnOfHopeAction(ai); }
static Action* divine_hymn(PlayerbotAI* ai) { return new CastDivineHymnAction(ai); }
static Action* mind_sear(PlayerbotAI* ai) { return new CastMindSearAction(ai); }
static Action* guardian_spirit_on_party(PlayerbotAI* ai) { return new CastGuardianSpiritOnPartyAction(ai); }
};
PriestAiObjectContext::PriestAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI)

View File

@@ -23,7 +23,7 @@ CURE_TRIGGER(CureDiseaseTrigger, "cure disease", DISPEL_DISEASE);
CURE_PARTY_TRIGGER(PartyMemberCureDiseaseTrigger, "cure disease", DISPEL_DISEASE);
BUFF_TRIGGER_A(InnerFireTrigger, "inner fire");
BUFF_TRIGGER_A(ShadowformTrigger, "shadowform");
BUFF_TRIGGER(PowerInfusionTrigger, "power infusion");
BOOST_TRIGGER(PowerInfusionTrigger, "power infusion");
BUFF_TRIGGER(InnerFocusTrigger, "inner focus");
BUFF_TRIGGER(ShadowProtectionTrigger, "shadow protection");
BUFF_PARTY_TRIGGER(ShadowProtectionOnPartyTrigger, "shadow protection");

View File

@@ -29,8 +29,10 @@ void ShadowPriestStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// ACTION_MOVE + 9), nullptr)));
triggers.push_back(
new TriggerNode("shadowform", NextAction::array(0, new NextAction("shadowform", ACTION_HIGH), nullptr)));
// triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("dispersion", ACTION_EMERGENCY
// + 5), nullptr)));
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("dispersion", ACTION_HIGH
+ 5), nullptr)));
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("dispersion", ACTION_HIGH
+ 5), nullptr)));
triggers.push_back(
new TriggerNode("vampiric embrace", NextAction::array(0, new NextAction("vampiric embrace", 16.0f), nullptr)));
triggers.push_back(

View File

@@ -66,8 +66,11 @@ void AssassinationRogueStrategy::InitTriggers(std::vector<TriggerNode*>& trigger
new TriggerNode("medium threat", NextAction::array(0, new NextAction("vanish", ACTION_HIGH), NULL)));
triggers.push_back(
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_EMERGENCY),
new NextAction("feint", ACTION_EMERGENCY), NULL)));
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9),
new NextAction("feint", ACTION_HIGH + 8), nullptr)));
triggers.push_back(
new TriggerNode("critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr)));
triggers.push_back(
new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), NULL)));

View File

@@ -108,8 +108,11 @@ void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
new TriggerNode("medium threat", NextAction::array(0, new NextAction("vanish", ACTION_HIGH), nullptr)));
triggers.push_back(
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_EMERGENCY),
new NextAction("feint", ACTION_EMERGENCY), nullptr)));
new TriggerNode("low health", NextAction::array(0, new NextAction("evasion", ACTION_HIGH + 9),
new NextAction("feint", ACTION_HIGH + 8), nullptr)));
triggers.push_back(
new TriggerNode("critical health", NextAction::array(0, new NextAction("cloak of shadows", ACTION_HIGH + 7), nullptr)));
triggers.push_back(
new TriggerNode("kick", NextAction::array(0, new NextAction("kick", ACTION_INTERRUPT + 2), nullptr)));
@@ -125,6 +128,9 @@ void DpsRogueStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back(
new TriggerNode("light aoe", NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 3), nullptr)));
triggers.push_back(
new TriggerNode("blade flurry", NextAction::array(0, new NextAction("blade flurry", ACTION_HIGH + 2), nullptr)));
triggers.push_back(new TriggerNode(
"enemy out of melee",
NextAction::array(0, new NextAction("stealth", ACTION_NORMAL + 9), new NextAction("sprint", ACTION_NORMAL + 8),

View File

@@ -17,6 +17,12 @@ public:
CastEvasionAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "evasion") {}
};
class CastCloakOfShadowsAction : public CastBuffSpellAction
{
public:
CastCloakOfShadowsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cloak of shadows") {}
};
class CastHungerForBloodAction : public CastBuffSpellAction
{
public:

View File

@@ -76,12 +76,14 @@ public:
creators["off hand weapon no enchant"] = &RogueTriggerFactoryInternal::off_hand_weapon_no_enchant;
creators["tricks of the trade on main tank"] = &RogueTriggerFactoryInternal::tricks_of_the_trade_on_main_tank;
creators["adrenaline rush"] = &RogueTriggerFactoryInternal::adrenaline_rush;
creators["blade fury"] = &RogueTriggerFactoryInternal::blade_fury;
creators["target with combo points almost dead"] =
&RogueTriggerFactoryInternal::target_with_combo_points_almost_dead;
}
private:
static Trigger* adrenaline_rush(PlayerbotAI* botAI) { return new AdrenalineRushTrigger(botAI); }
static Trigger* blade_fury(PlayerbotAI* botAI) { return new BladeFuryTrigger(botAI); }
static Trigger* kick(PlayerbotAI* botAI) { return new KickInterruptSpellTrigger(botAI); }
static Trigger* rupture(PlayerbotAI* botAI) { return new RuptureTrigger(botAI); }
static Trigger* slice_and_dice(PlayerbotAI* botAI) { return new SliceAndDiceTrigger(botAI); }
@@ -122,6 +124,7 @@ public:
creators["eviscerate"] = &RogueAiObjectContextInternal::eviscerate;
creators["vanish"] = &RogueAiObjectContextInternal::vanish;
creators["evasion"] = &RogueAiObjectContextInternal::evasion;
creators["cloak of shadows"] = &RogueAiObjectContextInternal::cloak_of_shadows;
creators["kick"] = &RogueAiObjectContextInternal::kick;
creators["feint"] = &RogueAiObjectContextInternal::feint;
creators["backstab"] = &RogueAiObjectContextInternal::backstab;
@@ -161,6 +164,7 @@ private:
static Action* eviscerate(PlayerbotAI* botAI) { return new CastEviscerateAction(botAI); }
static Action* vanish(PlayerbotAI* botAI) { return new CastVanishAction(botAI); }
static Action* evasion(PlayerbotAI* botAI) { return new CastEvasionAction(botAI); }
static Action* cloak_of_shadows(PlayerbotAI* botAI) { return new CastCloakOfShadowsAction(botAI); }
static Action* kick(PlayerbotAI* botAI) { return new CastKickAction(botAI); }
static Action* feint(PlayerbotAI* botAI) { return new CastFeintAction(botAI); }
static Action* backstab(PlayerbotAI* botAI) { return new CastBackstabAction(botAI); }

View File

@@ -18,34 +18,34 @@ public:
bool isUseful() override;
};
class CastSinisterStrikeAction : public CastComboAction
class CastSinisterStrikeAction : public CastSpellAction
{
public:
CastSinisterStrikeAction(PlayerbotAI* botAI) : CastComboAction(botAI, "sinister strike") {}
CastSinisterStrikeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "sinister strike") {}
};
class CastMutilateAction : public CastComboAction
class CastMutilateAction : public CastSpellAction
{
public:
CastMutilateAction(PlayerbotAI* botAI) : CastComboAction(botAI, "mutilate") {}
CastMutilateAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "mutilate") {}
};
class CastRiposteAction : public CastComboAction
class CastRiposteAction : public CastSpellAction
{
public:
CastRiposteAction(PlayerbotAI* botAI) : CastComboAction(botAI, "riposte") {}
CastRiposteAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "riposte") {}
};
class CastGougeAction : public CastComboAction
class CastGougeAction : public CastSpellAction
{
public:
CastGougeAction(PlayerbotAI* botAI) : CastComboAction(botAI, "gouge") {}
CastGougeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "gouge") {}
};
class CastBackstabAction : public CastComboAction
class CastBackstabAction : public CastSpellAction
{
public:
CastBackstabAction(PlayerbotAI* botAI) : CastComboAction(botAI, "backstab") {}
CastBackstabAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "backstab") {}
};
#endif

View File

@@ -36,6 +36,13 @@ public:
// bool isPossible();
};
class BladeFuryTrigger : public BoostTrigger
{
public:
BladeFuryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "blade fury") {}
};
class RuptureTrigger : public DebuffTrigger
{
public:

View File

@@ -6,6 +6,7 @@
#include "ShamanActions.h"
#include "Playerbots.h"
#include "Totem.h"
bool CastTotemAction::isUseful()
{
@@ -41,7 +42,24 @@ bool CastSearingTotemAction::isUseful()
return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", "flametongue totem");
}
bool CastMagmaTotemAction::isUseful() { return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", name); }
bool CastMagmaTotemAction::isUseful() {
Unit* target = AI_VALUE(Unit*, "current target");
if (!target || !bot->IsWithinMeleeRange(target))
return false;
return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", name);
}
bool CastFireNovaAction::isUseful() {
Creature* fireTotem = bot->GetMap()->GetCreature(bot->m_SummonSlot[1]);
if (!fireTotem)
return false;
if (bot->GetDistance(fireTotem) > 8.0f)
return false;
return CastMeleeSpellAction::isUseful();
}
bool CastCleansingTotemAction::isUseful()
{

View File

@@ -231,10 +231,11 @@ public:
bool isUseful() override;
};
class CastFireNovaAction : public CastSpellAction
class CastFireNovaAction : public CastMeleeSpellAction
{
public:
CastFireNovaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "fire nova") {}
CastFireNovaAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "fire nova") {}
bool isUseful() override;
};
class CastWindShearAction : public CastSpellAction

View File

@@ -308,7 +308,23 @@ std::string const TwoTriggers::getName()
return name;
}
bool BoostTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE(uint8, "balance") <= balance; }
bool BoostTrigger::IsActive()
{
if (!BuffTrigger::IsActive())
return false;
Unit* target = AI_VALUE(Unit*, "current target");
if (target && target->ToPlayer())
return true;
return AI_VALUE(uint8, "balance") <= balance;
}
bool GenericBoostTrigger::IsActive()
{
Unit* target = AI_VALUE(Unit*, "current target");
if (target && target->ToPlayer())
return true;
return AI_VALUE(uint8, "balance") <= balance;
}
bool ItemCountTrigger::IsActive() { return AI_VALUE2(uint32, "item count", item) < count; }

View File

@@ -409,6 +409,21 @@ protected:
float balance;
};
class GenericBoostTrigger : public Trigger
{
public:
GenericBoostTrigger(PlayerbotAI* botAI, float balance = 50.f)
: Trigger(botAI, "generic boost", 1), balance(balance)
{
}
bool IsActive() override;
protected:
float balance;
};
class RandomTrigger : public Trigger
{
public:

View File

@@ -48,7 +48,7 @@ class LowHealthTrigger : public HealthInRangeTrigger
{
public:
LowHealthTrigger(PlayerbotAI* botAI, std::string const name = "low health",
float value = sPlayerbotAIConfig->lowHealth, float minValue = sPlayerbotAIConfig->criticalHealth)
float value = sPlayerbotAIConfig->lowHealth, float minValue = 0)
: HealthInRangeTrigger(botAI, name, value, minValue)
{
}
@@ -69,7 +69,7 @@ class MediumHealthTrigger : public LowHealthTrigger
{
public:
MediumHealthTrigger(PlayerbotAI* botAI)
: LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig->mediumHealth, sPlayerbotAIConfig->lowHealth)
: LowHealthTrigger(botAI, "medium health", sPlayerbotAIConfig->mediumHealth, 0)
{
}
};
@@ -89,7 +89,7 @@ class PartyMemberLowHealthTrigger : public HealthInRangeTrigger
public:
PartyMemberLowHealthTrigger(PlayerbotAI* botAI, std::string const name = "party member low health",
float value = sPlayerbotAIConfig->lowHealth,
float minValue = sPlayerbotAIConfig->criticalHealth)
float minValue = 0)
: HealthInRangeTrigger(botAI, name, value, minValue)
{
}
@@ -111,7 +111,7 @@ class PartyMemberMediumHealthTrigger : public PartyMemberLowHealthTrigger
public:
PartyMemberMediumHealthTrigger(PlayerbotAI* botAI)
: PartyMemberLowHealthTrigger(botAI, "party member medium health", sPlayerbotAIConfig->mediumHealth,
sPlayerbotAIConfig->lowHealth)
0)
{
}
};
@@ -121,7 +121,7 @@ class PartyMemberAlmostFullHealthTrigger : public PartyMemberLowHealthTrigger
public:
PartyMemberAlmostFullHealthTrigger(PlayerbotAI* botAI)
: PartyMemberLowHealthTrigger(botAI, "party member almost full health", sPlayerbotAIConfig->almostFullHealth,
sPlayerbotAIConfig->mediumHealth)
0)
{
}
};

View File

@@ -53,6 +53,8 @@ public:
creators["party member medium health"] = &TriggerContext::PartyMemberMediumHealth;
creators["party member almost full health"] = &TriggerContext::PartyMemberAlmostFullHealth;
creators["generic boost"] = &TriggerContext::generic_boost;
creators["protect party member"] = &TriggerContext::protect_party_member;
creators["light rage available"] = &TriggerContext::LightRageAvailable;
@@ -318,6 +320,7 @@ private:
{
return new PartyMemberAlmostFullHealthTrigger(botAI);
}
static Trigger* generic_boost(PlayerbotAI* botAI) { return new GenericBoostTrigger(botAI); }
static Trigger* PartyMemberCriticalHealth(PlayerbotAI* botAI)
{
return new PartyMemberCriticalHealthTrigger(botAI);

View File

@@ -66,8 +66,13 @@ uint8 BalancePercentValue::Calculate()
playerLevel += player->GetLevel();
}
uint32 memberCount = group->GetMembersCount();
playerLevel /= memberCount;
if (memberCount <= 10)
playerLevel *= memberCount;
else
playerLevel *= 10;
}
GuidVector v = context->GetValue<GuidVector>("attackers")->Get();
for (ObjectGuid const guid : v)
{
@@ -89,7 +94,7 @@ uint8 BalancePercentValue::Calculate()
level *= 3;
break;
case CREATURE_ELITE_WORLDBOSS:
level *= 50;
level *= 30;
break;
}

View File

@@ -19,7 +19,7 @@ Unit* AttackerWithoutAuraTargetValue::Calculate()
if (!unit || !unit->IsAlive())
continue;
if (bot->GetDistance(unit) > botAI->GetRange(range))
if (!bot->IsWithinCombatRange(unit, botAI->GetRange(range)))
continue;
if (unit->GetHealth() < max_health)

View File

@@ -41,6 +41,8 @@ Unit* PartyMemberToHeal::Calculate()
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
{
Player* player = gref->GetSource();
if (player->IsGameMaster())
continue;
if (player && player->IsAlive())
{
uint8 health = player->GetHealthPct();

View File

@@ -103,7 +103,8 @@ bool PartyMemberValue::Check(Unit* player)
{
// return player && player != bot && player->GetMapId() == bot->GetMapId() && bot->IsWithinDistInMap(player,
// sPlayerbotAIConfig->sightDistance, false);
return player && player->GetMapId() == bot->GetMapId() &&
bool isGM = player->ToPlayer() && player->ToPlayer()->IsGameMaster();
return player && player->GetMapId() == bot->GetMapId() && !isGM &&
bot->GetDistance(player) < sPlayerbotAIConfig->spellDistance * 2 &&
bot->IsWithinLOS(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
}

View File

@@ -20,14 +20,21 @@ BUFF_ACTION(CastBerserkerStanceAction, "berserker stance");
// shouts
BUFF_ACTION(CastBattleShoutAction, "battle shout");
MELEE_ACTION_U(CastBattleShoutTauntAction, "battle shout", CastSpellAction::isUseful()); // useful to rebuff
DEBUFF_ACTION_R(CastDemoralizingShoutAction, "demoralizing shout", 8.0f); // low range debuff
class CastDemoralizingShoutWithoutLifeTimeCheckAction : public CastDebuffSpellAction
// DEBUFF_ACTION_R(CastDemoralizingShoutAction, "demoralizing shout", 8.0f); // low range debuff
class CastDemoralizingShoutAction : public CastMeleeDebuffSpellAction
{
public:
CastDemoralizingShoutAction(PlayerbotAI* botAI)
: CastMeleeDebuffSpellAction(botAI, "demoralizing shout") {}
};
class CastDemoralizingShoutWithoutLifeTimeCheckAction : public CastMeleeDebuffSpellAction
{
public:
CastDemoralizingShoutWithoutLifeTimeCheckAction(PlayerbotAI* botAI)
: CastDebuffSpellAction(botAI, "demoralizing shout", false, 0.0f)
: CastMeleeDebuffSpellAction(botAI, "demoralizing shout", false, 0.0f)
{
range = 8.0f;
}
};
@@ -63,7 +70,7 @@ DEBUFF_ACTION(CastShatteringThrowAction, "shattering throw");
MELEE_ACTION(CastMortalStrikeAction, "mortal strike");
BUFF_ACTION(CastSweepingStrikesAction, "sweeping strikes");
// arms talents 3.3.5
BUFF_ACTION(CastBladestormAction, "bladestorm");
MELEE_ACTION(CastBladestormAction, "bladestorm");
// fury
MELEE_ACTION(CastCleaveAction, "cleave");