mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-02-03 19:03:49 +00:00
Wotlk dungeon structure & Utgarde Keep
This commit is contained in:
21
src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h
Normal file
21
src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONACTIONCONTEXT_H_
|
||||
#define _PLAYERBOT_WOTLKDUNGEONACTIONCONTEXT_H_
|
||||
|
||||
#include "utgardekeep/UtgardeKeepActionContext.h"
|
||||
// #include "nexus/NexusActionContext.h"
|
||||
// #include "azjolnerub/AzjolNerubActionContext.h"
|
||||
// #include "oldkingdom/OldKingdomActionContext.h"
|
||||
// #include "draktharonkeep/DraktharonKeepActionContext.h"
|
||||
// #include "violethold/VioletHoldActionContext.h"
|
||||
// #include "gundrak/GundrakActionContext.h"
|
||||
// #include "hallsofstone/HallsOfStoneActionContext.h"
|
||||
// #include "hallsoflightning/HallsOfLightningActionContext.h"
|
||||
// #include "oculus/OculusActionContext.h"
|
||||
// #include "utgardepinnacle/UtgardePinnacleActionContext.h"
|
||||
// #include "cullingofstratholme/CullingOfStratholmeActionContext.h"
|
||||
// #include "trialofthechampion/TrialOfTheChampionActionContext.h"
|
||||
// #include "hallsofreflection/HallsOfReflectionActionContext.h"
|
||||
// #include "pitofsaron/PitOfSaronActionContext.h"
|
||||
// #include "forgeofsouls/ForgeOfSoulsActionContext.h"
|
||||
|
||||
#endif
|
||||
21
src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h
Normal file
21
src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONTRIGGERCONTEXT_H_
|
||||
#define _PLAYERBOT_WOTLKDUNGEONTRIGGERCONTEXT_H_
|
||||
|
||||
#include "utgardekeep/UtgardeKeepTriggerContext.h"
|
||||
// #include "nexus/NexusTriggerContext.h"
|
||||
// #include "azjolnerub/AzjolNerubTriggerContext.h"
|
||||
// #include "oldkingdom/OldKingdomTriggerContext.h"
|
||||
// #include "draktharonkeep/DraktharonKeepTriggerContext.h"
|
||||
// #include "violethold/VioletHoldTriggerContext.h"
|
||||
// #include "gundrak/GundrakTriggerContext.h"
|
||||
// #include "hallsofstone/HallsOfStoneTriggerContext.h"
|
||||
// #include "hallsoflightning/HallsOfLightningTriggerContext.h"
|
||||
// #include "oculus/OculusTriggerContext.h"
|
||||
// #include "utgardepinnacle/UtgardePinnacleTriggerContext.h"
|
||||
// #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h"
|
||||
// #include "trialofthechampion/TrialOfTheChampionTriggerContext.h"
|
||||
// #include "hallsofreflection/HallsOfReflectionTriggerContext.h"
|
||||
// #include "pitofsaron/PitOfSaronTriggerContext.h"
|
||||
// #include "forgeofsouls/ForgeOfSoulsTriggerContext.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONUKACTIONCONTEXT_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONUKACTIONCONTEXT_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "NamedObjectContext.h"
|
||||
#include "UtgardeKeepActions.h"
|
||||
|
||||
class WotlkDungeonUKActionContext : public NamedObjectContext<Action>
|
||||
{
|
||||
public:
|
||||
WotlkDungeonUKActionContext() {
|
||||
creators["attack frost tomb"] = &WotlkDungeonUKActionContext::attack_frost_tomb;
|
||||
creators["attack dalronn"] = &WotlkDungeonUKActionContext::attack_dalronn;
|
||||
creators["ingvar stop casting"] = &WotlkDungeonUKActionContext::ingvar_stop_casting;
|
||||
creators["ingvar get behind"] = &WotlkDungeonUKActionContext::ingvar_get_behind;
|
||||
// creators["ingvar hide los"] = &WotlkDungeonUKActionContext::ingvar_hide_los;
|
||||
creators["ingvar dodge smash"] = &WotlkDungeonUKActionContext::ingvar_dodge_smash;
|
||||
creators["ingvar smash return"] = &WotlkDungeonUKActionContext::ingvar_smash_return;
|
||||
}
|
||||
private:
|
||||
static Action* attack_frost_tomb(PlayerbotAI* ai) { return new AttackFrostTombAction(ai); }
|
||||
static Action* attack_dalronn(PlayerbotAI* ai) { return new AttackDalronnAction(ai); }
|
||||
static Action* ingvar_stop_casting(PlayerbotAI* ai) { return new IngvarStopCastingAction(ai); }
|
||||
static Action* ingvar_get_behind(PlayerbotAI* ai) { return new SetBehindTargetAction(ai); }
|
||||
// static Action* ingvar_hide_los(PlayerbotAI* ai) { return new TellLosAction(ai); }
|
||||
static Action* ingvar_dodge_smash(PlayerbotAI* ai) { return new IngvarDodgeSmashAction(ai); }
|
||||
static Action* ingvar_smash_return(PlayerbotAI* ai) { return new IngvarSmashReturnAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "Playerbots.h"
|
||||
#include "UtgardeKeepActions.h"
|
||||
#include "UtgardeKeepStrategy.h"
|
||||
|
||||
bool AttackFrostTombAction::Execute(Event event)
|
||||
{
|
||||
Unit* frost_tomb = nullptr;
|
||||
|
||||
// Target is not findable from threat table using AI_VALUE2(),
|
||||
// therefore need to search manually for the unit name
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||
|
||||
for (auto i = targets.begin(); i != targets.end(); ++i)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(*i);
|
||||
if (unit && unit->GetName() == "Frost Tomb")
|
||||
{
|
||||
frost_tomb = unit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!frost_tomb || AI_VALUE(Unit*, "current target") == frost_tomb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Attack(frost_tomb);
|
||||
}
|
||||
|
||||
// TODO: Possibly add player stacking behaviour close to tank, to prevent Skarvald charging ranged
|
||||
bool AttackDalronnAction::Execute(Event event)
|
||||
{
|
||||
Unit* target = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
||||
|
||||
if (!target || AI_VALUE(Unit*, "current target") == target)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Attack(target);
|
||||
}
|
||||
|
||||
bool IngvarStopCastingAction::Execute(Event event)
|
||||
{
|
||||
// Doesn't work, this action gets queued behind the current spell instead of interrupting it
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 my_spell_id = AI_VALUE(uint32, "active spell");
|
||||
if (!my_spell_id || my_spell_id == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Spell* spell = bot->FindCurrentSpellBySpellId(my_spell_id);
|
||||
if (!spell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// bot->Yell("cancelling spell="+std::to_string(my_spell_id), LANG_UNIVERSAL);
|
||||
bot->InterruptSpell(spell->GetCurrentContainer(), false, true, true);
|
||||
|
||||
// Can slightly optimise by allowing bot to keep casting if they will finish the cast
|
||||
// before boss spell goes off, however need to hook boss AI for cast remaining.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IngvarDodgeSmashAction::isUseful() { return !AI_VALUE2(bool, "behind", "current target"); }
|
||||
bool IngvarDodgeSmashAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float distance = bot->GetExactDist2d(boss->GetPosition());
|
||||
// Extra units to move into the boss, instead of being just 1 pixel past his midpoint.
|
||||
// Can be adjusted - this value tends to mirror how a human would play,
|
||||
// and visibly ensures you won't get hit while not creating excessive movements.
|
||||
float distanceExtra = 2.0f;
|
||||
return Move(bot->GetAngle(boss), distance + distanceExtra);
|
||||
}
|
||||
|
||||
bool IngvarSmashReturnAction::isUseful() { return AI_VALUE2(bool, "behind", "current target"); }
|
||||
bool IngvarSmashReturnAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float distance = bot->GetExactDist2d(boss->GetPosition());
|
||||
return Move(bot->GetAngle(boss), distance + bot->GetMeleeReach());
|
||||
}
|
||||
47
src/strategy/dungeons/wotlk/utgardekeep/UtgardeKeepActions.h
Normal file
47
src/strategy/dungeons/wotlk/utgardekeep/UtgardeKeepActions.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONUKACTIONS_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONUKACTIONS_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "AttackAction.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "UtgardeKeepTriggers.h"
|
||||
|
||||
class AttackFrostTombAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackFrostTombAction(PlayerbotAI* ai) : AttackAction(ai, "attack frost tomb") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class AttackDalronnAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
AttackDalronnAction(PlayerbotAI* ai) : AttackAction(ai, "attack dalronn") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class IngvarStopCastingAction : public Action
|
||||
{
|
||||
public:
|
||||
IngvarStopCastingAction(PlayerbotAI* ai) : Action(ai, "ingvar stop casting") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class IngvarDodgeSmashAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
IngvarDodgeSmashAction(PlayerbotAI* ai) : MovementAction(ai, "ingvar dodge smash") {}
|
||||
bool isUseful() override;
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class IngvarSmashReturnAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
IngvarSmashReturnAction(PlayerbotAI* ai) : MovementAction(ai, "ingvar smash return") {}
|
||||
bool isUseful() override;
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "UtgardeKeepMultipliers.h"
|
||||
#include "UtgardeKeepActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "UtgardeKeepTriggers.h"
|
||||
|
||||
float PrinceKelesethMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "prince keleseth");
|
||||
|
||||
if (!boss)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
if (dynamic_cast<DpsAssistAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
float SkarvaldAndDalronnMultiplier::GetValue(Action* action)
|
||||
{
|
||||
// Unit* skarvald = AI_VALUE2(Unit*, "find target", "skarvald the constructor");
|
||||
Unit* dalronn = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
||||
|
||||
if (!dalronn)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<DpsAssistAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float IngvarThePlundererMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
bool isTank = botAI->IsTank(bot);
|
||||
if (!boss)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Prevent movement actions overriding current movement, we're probably dodging a slam
|
||||
if (isTank && bot->isMoving() && dynamic_cast<MovementAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// If boss is casting a roar, do not allow beginning a spell cast that is non-instant
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
if (boss->FindCurrentSpellBySpellId(SPELL_STAGGERING_ROAR) ||
|
||||
boss->FindCurrentSpellBySpellId(SPELL_DREADFUL_ROAR))
|
||||
{
|
||||
if (dynamic_cast<CastSpellAction*>(action))
|
||||
{
|
||||
std::string const name = action->getName();
|
||||
uint32 spellId = AI_VALUE2(uint32, "spell id", name);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
uint32 castTime = spellInfo->CalcCastTime(bot);
|
||||
if (castTime != 0)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Done with non-tank logic
|
||||
if (!isTank)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
// TANK ONLY
|
||||
if (boss->FindCurrentSpellBySpellId(SPELL_SMASH) ||
|
||||
boss->FindCurrentSpellBySpellId(SPELL_DARK_SMASH))
|
||||
{
|
||||
// Prevent movement actions during smash which can mess up boss position.
|
||||
// Allow through IngvarDodgeSmashAction only, as well as any non-movement actions.
|
||||
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<IngvarDodgeSmashAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1.0f;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef _PLAYERRBOT_WOTLKDUNGEONUKMULTIPLIERS_H_
|
||||
#define _PLAYERRBOT_WOTLKDUNGEONUKMULTIPLIERS_H_
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class PrinceKelesethMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
PrinceKelesethMultiplier(PlayerbotAI* ai) : Multiplier(ai, "prince keleseth") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class SkarvaldAndDalronnMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
SkarvaldAndDalronnMultiplier(PlayerbotAI* ai) : Multiplier(ai, "skarvald and dalronn") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class IngvarThePlundererMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
IngvarThePlundererMultiplier(PlayerbotAI* ai) : Multiplier(ai, "ingvar the plunderer") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "UtgardeKeepStrategy.h"
|
||||
#include "UtgardeKeepMultipliers.h"
|
||||
|
||||
|
||||
void WotlkDungeonUKStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||
{
|
||||
// Prince Keleseth
|
||||
triggers.push_back(new TriggerNode("keleseth frost tomb",
|
||||
NextAction::array(0, new NextAction("attack frost tomb", ACTION_RAID + 1), nullptr)));
|
||||
|
||||
// Skarvald the Constructor & Dalronn the Controller
|
||||
triggers.push_back(new TriggerNode("dalronn priority",
|
||||
NextAction::array(0, new NextAction("attack dalronn", ACTION_RAID + 1), nullptr)));
|
||||
|
||||
// Ingvar the Plunderer
|
||||
|
||||
// Doesn't work yet, this action doesn't get processed until the existing cast finishes
|
||||
// triggers.push_back(new TriggerNode("ingvar staggering roar",
|
||||
// NextAction::array(0, new NextAction("ingvar stop casting", ACTION_RAID + 1), nullptr)));
|
||||
|
||||
// No easy way to check LoS here, the pillars do not seem to count as gameobjects.
|
||||
// Not implemented for now, unsure if this is needed as a good group can probably burst through the boss
|
||||
// and just eat the debuff.
|
||||
// triggers.push_back(new TriggerNode("ingvar dreadful roar",
|
||||
// NextAction::array(0, new NextAction("ingvar hide los", ACTION_RAID + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode("ingvar smash tank",
|
||||
NextAction::array(0, new NextAction("ingvar dodge smash", ACTION_MOVE + 5), nullptr)));
|
||||
triggers.push_back(new TriggerNode("ingvar smash tank return",
|
||||
NextAction::array(0, new NextAction("ingvar smash return", ACTION_MOVE + 5), nullptr)));
|
||||
// Buggy... if not behind target, ai can get stuck running towards and away from target.
|
||||
// I think for ranged chars, a custom action should be added that doesn't attempt to run into melee.
|
||||
// This is a bandaid for now, needs to be improved.
|
||||
triggers.push_back(new TriggerNode("not behind ingvar",
|
||||
NextAction::array(0, new NextAction("set behind", ACTION_MOVE + 1), nullptr)));
|
||||
|
||||
}
|
||||
|
||||
void WotlkDungeonUKStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||
{
|
||||
multipliers.push_back(new PrinceKelesethMultiplier(botAI));
|
||||
multipliers.push_back(new SkarvaldAndDalronnMultiplier(botAI));
|
||||
multipliers.push_back(new IngvarThePlundererMultiplier(botAI));
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONUKSTRATEGY_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONUKSTRATEGY_H
|
||||
|
||||
#include "Multiplier.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
|
||||
class WotlkDungeonUKStrategy : public Strategy
|
||||
{
|
||||
public:
|
||||
WotlkDungeonUKStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||
virtual std::string const getName() override { return "utgarde keep"; }
|
||||
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
|
||||
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONUKTRIGGERCONTEXT_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONUKTRIGGERCONTEXT_H
|
||||
|
||||
#include "NamedObjectContext.h"
|
||||
#include "AiObjectContext.h"
|
||||
#include "UtgardeKeepTriggers.h"
|
||||
|
||||
class WotlkDungeonUKTriggerContext : public NamedObjectContext<Trigger>
|
||||
{
|
||||
public:
|
||||
WotlkDungeonUKTriggerContext()
|
||||
{
|
||||
creators["keleseth frost tomb"] = &WotlkDungeonUKTriggerContext::keleseth_frost_tomb;
|
||||
creators["dalronn priority"] = &WotlkDungeonUKTriggerContext::dalronn_priority_target;
|
||||
creators["ingvar staggering roar"] = &WotlkDungeonUKTriggerContext::ingvar_staggering_roar;
|
||||
creators["ingvar dreadful roar"] = &WotlkDungeonUKTriggerContext::ingvar_dreadful_roar;
|
||||
creators["ingvar smash tank"] = &WotlkDungeonUKTriggerContext::ingvar_smash_tank;
|
||||
creators["ingvar smash tank return"] = &WotlkDungeonUKTriggerContext::ingvar_smash_tank_return;
|
||||
creators["not behind ingvar"] = &WotlkDungeonUKTriggerContext::not_behind_ingvar;
|
||||
}
|
||||
private:
|
||||
static Trigger* keleseth_frost_tomb(PlayerbotAI* ai) { return new KelesethFrostTombTrigger(ai); }
|
||||
static Trigger* dalronn_priority_target(PlayerbotAI* ai) { return new DalronnNontankTrigger(ai); }
|
||||
static Trigger* ingvar_staggering_roar(PlayerbotAI* ai) { return new IngvarStaggeringRoarTrigger(ai); }
|
||||
static Trigger* ingvar_dreadful_roar(PlayerbotAI* ai) { return new IngvarDreadfulRoarTrigger(ai); }
|
||||
static Trigger* ingvar_smash_tank(PlayerbotAI* ai) { return new IngvarSmashTankTrigger(ai); }
|
||||
static Trigger* ingvar_smash_tank_return(PlayerbotAI* ai) { return new IngvarSmashTankReturnTrigger(ai); }
|
||||
static Trigger* not_behind_ingvar(PlayerbotAI* ai) { return new NotBehindIngvarTrigger(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
104
src/strategy/dungeons/wotlk/utgardekeep/UtgardeKeepTriggers.cpp
Normal file
104
src/strategy/dungeons/wotlk/utgardekeep/UtgardeKeepTriggers.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "Playerbots.h"
|
||||
#include "UtgardeKeepTriggers.h"
|
||||
#include "AiObject.h"
|
||||
#include "AiObjectContext.h"
|
||||
|
||||
bool KelesethFrostTombTrigger::IsActive()
|
||||
{
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
for (auto& member : members)
|
||||
{
|
||||
if (botAI->GetUnit(member)->HasAura(DEBUFF_FROST_TOMB))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DalronnNontankTrigger::IsActive()
|
||||
{
|
||||
Unit* dalronn = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
||||
if (!dalronn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !botAI->IsTank(bot);
|
||||
}
|
||||
|
||||
bool IngvarStaggeringRoarTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
if (boss->FindCurrentSpellBySpellId(SPELL_STAGGERING_ROAR))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IngvarDreadfulRoarTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
if (boss->FindCurrentSpellBySpellId(SPELL_DREADFUL_ROAR))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IngvarSmashTankTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss || !botAI->IsTank(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
if (boss->FindCurrentSpellBySpellId(SPELL_SMASH) ||
|
||||
boss->FindCurrentSpellBySpellId(SPELL_DARK_SMASH))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IngvarSmashTankReturnTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
// if (!boss || !botAI->IsTank(bot) || boss->HasUnitState(UNIT_STATE_CASTING))
|
||||
// Ignore casting state as Ingvar will sometimes chain-cast a roar after a smash..
|
||||
// We don't want this to prevent our tank from repositioning properly.
|
||||
if (!boss || !botAI->IsTank(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NotBehindIngvarTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||
if (!boss || botAI->IsTank(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return AI_VALUE2(bool, "behind", "current target");
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#ifndef _PLAYERBOT_WOTLKDUNGEONUKTRIGGERS_H
|
||||
#define _PLAYERBOT_WOTLKDUNGEONUKTRIGGERS_H
|
||||
|
||||
#include "EventMap.h"
|
||||
#include "Trigger.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "DungeonStrategyUtils.h"
|
||||
|
||||
// Taken from:
|
||||
// src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
|
||||
enum eSpells
|
||||
{
|
||||
SPELL_SUMMON_VALKYR = 42912,
|
||||
SPELL_RESURRECTION_BEAM = 42857,
|
||||
SPELL_RESURRECTION_BALL = 42862,
|
||||
SPELL_RESURRECTION_HEAL = 42704,
|
||||
SPELL_INGVAR_TRANSFORM = 42796,
|
||||
|
||||
SPELL_STAGGERING_ROAR_N = 42708,
|
||||
SPELL_STAGGERING_ROAR_H = 59708,
|
||||
SPELL_CLEAVE = 42724,
|
||||
SPELL_SMASH_N = 42669,
|
||||
SPELL_SMASH_H = 59706,
|
||||
SPELL_ENRAGE_N = 42705,
|
||||
SPELL_ENRAGE_H = 59707,
|
||||
|
||||
SPELL_DREADFUL_ROAR_N = 42729,
|
||||
SPELL_DREADFUL_ROAR_H = 59734,
|
||||
SPELL_WOE_STRIKE_N = 42730,
|
||||
SPELL_WOE_STRIKE_H = 59735,
|
||||
SPELL_DARK_SMASH = 42723,
|
||||
SPELL_SHADOW_AXE = 42749,
|
||||
|
||||
// Added
|
||||
DEBUFF_FROST_TOMB = 48400,
|
||||
};
|
||||
|
||||
#define SPELL_STAGGERING_ROAR DUNGEON_MODE(bot, SPELL_STAGGERING_ROAR_N, SPELL_STAGGERING_ROAR_H)
|
||||
#define SPELL_DREADFUL_ROAR DUNGEON_MODE(bot, SPELL_DREADFUL_ROAR_N, SPELL_DREADFUL_ROAR_H)
|
||||
#define SPELL_WOE_STRIKE DUNGEON_MODE(bot, SPELL_WOE_STRIKE_N, SPELL_WOE_STRIKE_H)
|
||||
#define SPELL_SMASH DUNGEON_MODE(bot, SPELL_SMASH_N, SPELL_SMASH_H)
|
||||
#define SPELL_ENRAGE DUNGEON_MODE(bot, SPELL_ENRAGE_N, SPELL_ENRAGE_H)
|
||||
|
||||
class KelesethFrostTombTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
KelesethFrostTombTrigger(PlayerbotAI* ai) : Trigger(ai, "keleseth frost tomb") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class DalronnNontankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
DalronnNontankTrigger(PlayerbotAI* ai) : Trigger(ai, "dalronn non-tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class IngvarStaggeringRoarTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
IngvarStaggeringRoarTrigger(PlayerbotAI* ai) : Trigger(ai, "ingvar staggering roar") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class IngvarDreadfulRoarTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
IngvarDreadfulRoarTrigger(PlayerbotAI* ai) : Trigger(ai, "ingvar dreadful roar") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class IngvarSmashTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
IngvarSmashTankTrigger(PlayerbotAI* ai) : Trigger(ai, "ingvar smash tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class IngvarSmashTankReturnTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
IngvarSmashTankReturnTrigger(PlayerbotAI* ai) : Trigger(ai, "ingvar smash tank return") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NotBehindIngvarTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NotBehindIngvarTrigger(PlayerbotAI* ai) : Trigger(ai, "not behind ingvar") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user