mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-12-01 21:12:50 +08:00
Halls of Stone implementation
This commit is contained in:
@@ -57,6 +57,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
|||||||
actionContexts.Add(new WotlkDungeonDTKActionContext());
|
actionContexts.Add(new WotlkDungeonDTKActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonVHActionContext());
|
actionContexts.Add(new WotlkDungeonVHActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonGDActionContext());
|
actionContexts.Add(new WotlkDungeonGDActionContext());
|
||||||
|
actionContexts.Add(new WotlkDungeonHoSActionContext());
|
||||||
|
|
||||||
triggerContexts.Add(new TriggerContext());
|
triggerContexts.Add(new TriggerContext());
|
||||||
triggerContexts.Add(new ChatTriggerContext());
|
triggerContexts.Add(new ChatTriggerContext());
|
||||||
@@ -74,6 +75,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
|||||||
triggerContexts.Add(new WotlkDungeonDTKTriggerContext());
|
triggerContexts.Add(new WotlkDungeonDTKTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonVHTriggerContext());
|
triggerContexts.Add(new WotlkDungeonVHTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
|
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
|
||||||
|
triggerContexts.Add(new WotlkDungeonHoSTriggerContext());
|
||||||
|
|
||||||
valueContexts.Add(new ValueContext());
|
valueContexts.Add(new ValueContext());
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,11 @@
|
|||||||
#include "wotlk/draktharonkeep/DrakTharonKeepStrategy.h"
|
#include "wotlk/draktharonkeep/DrakTharonKeepStrategy.h"
|
||||||
#include "wotlk/violethold/VioletHoldStrategy.h"
|
#include "wotlk/violethold/VioletHoldStrategy.h"
|
||||||
#include "wotlk/gundrak/GundrakStrategy.h"
|
#include "wotlk/gundrak/GundrakStrategy.h"
|
||||||
|
#include "wotlk/hallsofstone/HallsOfStoneStrategy.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Full list/TODO:
|
Full list/TODO:
|
||||||
|
|
||||||
Halls of Stone - HoS
|
|
||||||
Maiden of Grief, Krystallus, Tribunal of Ages, Sjonnir The Ironshaper
|
|
||||||
Halls of Lightning - HoL
|
Halls of Lightning - HoL
|
||||||
General Bjarngrim, Volkhan, Ionar, Loken
|
General Bjarngrim, Volkhan, Ionar, Loken
|
||||||
The Oculus - Occ
|
The Oculus - Occ
|
||||||
@@ -76,8 +75,8 @@ class DungeonStrategyContext : public NamedObjectContext<Strategy>
|
|||||||
static Strategy* wotlk_dtk(PlayerbotAI* botAI) { return new WotlkDungeonDTKStrategy(botAI); }
|
static Strategy* wotlk_dtk(PlayerbotAI* botAI) { return new WotlkDungeonDTKStrategy(botAI); }
|
||||||
static Strategy* wotlk_vh(PlayerbotAI* botAI) { return new WotlkDungeonVHStrategy(botAI); }
|
static Strategy* wotlk_vh(PlayerbotAI* botAI) { return new WotlkDungeonVHStrategy(botAI); }
|
||||||
static Strategy* wotlk_gd(PlayerbotAI* botAI) { return new WotlkDungeonGDStrategy(botAI); }
|
static Strategy* wotlk_gd(PlayerbotAI* botAI) { return new WotlkDungeonGDStrategy(botAI); }
|
||||||
|
static Strategy* wotlk_hos(PlayerbotAI* botAI) { return new WotlkDungeonHoSStrategy(botAI); }
|
||||||
|
|
||||||
static Strategy* wotlk_hos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
|
||||||
static Strategy* wotlk_hol(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
static Strategy* wotlk_hol(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
||||||
static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
||||||
static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "draktharonkeep/DrakTharonKeepActionContext.h"
|
#include "draktharonkeep/DrakTharonKeepActionContext.h"
|
||||||
#include "violethold/VioletHoldActionContext.h"
|
#include "violethold/VioletHoldActionContext.h"
|
||||||
#include "gundrak/GundrakActionContext.h"
|
#include "gundrak/GundrakActionContext.h"
|
||||||
// #include "hallsofstone/HallsOfStoneActionContext.h"
|
#include "hallsofstone/HallsOfStoneActionContext.h"
|
||||||
// #include "hallsoflightning/HallsOfLightningActionContext.h"
|
// #include "hallsoflightning/HallsOfLightningActionContext.h"
|
||||||
// #include "oculus/OculusActionContext.h"
|
// #include "oculus/OculusActionContext.h"
|
||||||
// #include "utgardepinnacle/UtgardePinnacleActionContext.h"
|
// #include "utgardepinnacle/UtgardePinnacleActionContext.h"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "draktharonkeep/DrakTharonKeepTriggerContext.h"
|
#include "draktharonkeep/DrakTharonKeepTriggerContext.h"
|
||||||
#include "violethold/VioletHoldTriggerContext.h"
|
#include "violethold/VioletHoldTriggerContext.h"
|
||||||
#include "gundrak/GundrakTriggerContext.h"
|
#include "gundrak/GundrakTriggerContext.h"
|
||||||
// #include "hallsofstone/HallsOfStoneTriggerContext.h"
|
#include "hallsofstone/HallsOfStoneTriggerContext.h"
|
||||||
// #include "hallsoflightning/HallsOfLightningTriggerContext.h"
|
// #include "hallsoflightning/HallsOfLightningTriggerContext.h"
|
||||||
// #include "oculus/OculusTriggerContext.h"
|
// #include "oculus/OculusTriggerContext.h"
|
||||||
// #include "utgardepinnacle/UtgardePinnacleTriggerContext.h"
|
// #include "utgardepinnacle/UtgardePinnacleTriggerContext.h"
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONHOSACTIONCONTEXT_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONHOSACTIONCONTEXT_H
|
||||||
|
|
||||||
|
#include "Action.h"
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "HallsOfStoneActions.h"
|
||||||
|
|
||||||
|
class WotlkDungeonHoSActionContext : public NamedObjectContext<Action>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonHoSActionContext() {
|
||||||
|
creators["shatter spread"] = &WotlkDungeonHoSActionContext::shatter_spread;
|
||||||
|
creators["avoid lightning ring"] = &WotlkDungeonHoSActionContext::avoid_lightning_ring;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static Action* shatter_spread(PlayerbotAI* ai) { return new ShatterSpreadAction(ai); }
|
||||||
|
static Action* avoid_lightning_ring(PlayerbotAI* ai) { return new AvoidLightningRingAction(ai); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#include "Playerbots.h"
|
||||||
|
#include "HallsOfStoneActions.h"
|
||||||
|
#include "HallsOfStoneStrategy.h"
|
||||||
|
|
||||||
|
bool ShatterSpreadAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "krystallus");
|
||||||
|
float radius = 40.0f;
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
Unit* closestMember = nullptr;
|
||||||
|
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||||
|
for (auto& member : members)
|
||||||
|
{
|
||||||
|
if (bot->GetGUID() == member)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!closestMember ||
|
||||||
|
bot->GetExactDist2d(botAI->GetUnit(member)) < bot->GetExactDist2d(closestMember))
|
||||||
|
{
|
||||||
|
closestMember = botAI->GetUnit(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closestMember && bot->GetExactDist2d(closestMember) < radius)
|
||||||
|
{
|
||||||
|
// Move in small increments so course can be corrected, otherwise two bots may
|
||||||
|
// run in the same direction and not adjust until they reach the destination
|
||||||
|
// return MoveAway(closestMember, radius - bot->GetExactDist2d(closestMember));
|
||||||
|
return MoveAway(closestMember, 5.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AvoidLightningRingAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "sjonnir the ironshaper");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
float distance = bot->GetExactDist2d(boss->GetPosition());
|
||||||
|
float radius = 10.0f;
|
||||||
|
float distanceExtra = 2.0f;
|
||||||
|
|
||||||
|
if (distance < radius + distanceExtra)
|
||||||
|
{
|
||||||
|
return MoveAway(boss, radius + distanceExtra - distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONHOSACTIONS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONHOSACTIONS_H
|
||||||
|
|
||||||
|
#include "Action.h"
|
||||||
|
#include "AttackAction.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "HallsOfStoneTriggers.h"
|
||||||
|
|
||||||
|
class ShatterSpreadAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShatterSpreadAction(PlayerbotAI* ai) : MovementAction(ai, "shatter spread") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AvoidLightningRingAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AvoidLightningRingAction(PlayerbotAI* ai) : MovementAction(ai, "avoid lightning ring") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#include "HallsOfStoneMultipliers.h"
|
||||||
|
#include "HallsOfStoneActions.h"
|
||||||
|
#include "GenericSpellActions.h"
|
||||||
|
#include "ChooseTargetActions.h"
|
||||||
|
#include "MovementActions.h"
|
||||||
|
#include "HallsOfStoneTriggers.h"
|
||||||
|
#include "Action.h"
|
||||||
|
|
||||||
|
float KrystallusMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "krystallus");
|
||||||
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
|
// Check both of these... the spell is applied first, debuff later.
|
||||||
|
// Neither is active for the full duration so we need to trigger off both
|
||||||
|
if (bot->HasAura(SPELL_GROUND_SLAM) || bot->HasAura(DEBUFF_GROUND_SLAM))
|
||||||
|
{
|
||||||
|
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<ShatterSpreadAction*>(action))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SjonnirMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "sjonnir the ironshaper");
|
||||||
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
|
if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_LIGHTNING_RING))
|
||||||
|
{
|
||||||
|
// Problematic since there's a lot of movement on this boss, will prevent players from positioning
|
||||||
|
// well to deal with adds etc. during the channel period. Takes a bit of work to improve this though
|
||||||
|
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidLightningRingAction*>(action))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONHOSMULTIPLIERS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONHOSMULTIPLIERS_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
|
||||||
|
class KrystallusMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KrystallusMultiplier(PlayerbotAI* ai) : Multiplier(ai, "krystallus") {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SjonnirMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SjonnirMultiplier(PlayerbotAI* ai) : Multiplier(ai, "sjonnir the ironshaper") {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#include "HallsOfStoneStrategy.h"
|
||||||
|
#include "HallsOfStoneMultipliers.h"
|
||||||
|
|
||||||
|
|
||||||
|
void WotlkDungeonHoSStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||||
|
{
|
||||||
|
// Maiden of Grief
|
||||||
|
// TODO: Jump into damage during shock of sorrow?
|
||||||
|
|
||||||
|
// Krystallus
|
||||||
|
// TODO: I think bots need to dismiss pets on this, or they nuke players they are standing close to
|
||||||
|
triggers.push_back(new TriggerNode("ground slam",
|
||||||
|
NextAction::array(0, new NextAction("shatter spread", ACTION_RAID + 5), nullptr)));
|
||||||
|
|
||||||
|
// Tribunal of Ages
|
||||||
|
// Seems fine, maybe add focus targeting strat if needed on heroic.
|
||||||
|
// Main issue is dps will immediately rambo in and sometimes die before tank gets aggro,
|
||||||
|
// this is mostly an issue with the bot AI as they do it on every fight
|
||||||
|
|
||||||
|
// Sjonnir The Ironshaper
|
||||||
|
// Possibly tank in place in the middle of the room, assign a dps to adds?
|
||||||
|
triggers.push_back(new TriggerNode("lightning ring",
|
||||||
|
NextAction::array(0, new NextAction("avoid lightning ring", ACTION_RAID + 5), nullptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WotlkDungeonHoSStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||||
|
{
|
||||||
|
multipliers.push_back(new KrystallusMultiplier(botAI));
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONHOSSTRATEGY_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONHOSSTRATEGY_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "Strategy.h"
|
||||||
|
|
||||||
|
|
||||||
|
class WotlkDungeonHoSStrategy : public Strategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonHoSStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||||
|
virtual std::string const getName() override { return "halls of stone"; }
|
||||||
|
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
|
||||||
|
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONHOSTRIGGERCONTEXT_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONHOSTRIGGERCONTEXT_H
|
||||||
|
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "HallsOfStoneTriggers.h"
|
||||||
|
|
||||||
|
class WotlkDungeonHoSTriggerContext : public NamedObjectContext<Trigger>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonHoSTriggerContext()
|
||||||
|
{
|
||||||
|
creators["ground slam"] = &WotlkDungeonHoSTriggerContext::ground_slam;
|
||||||
|
creators["lightning ring"] = &WotlkDungeonHoSTriggerContext::lightning_ring;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static Trigger* ground_slam(PlayerbotAI* ai) { return new KrystallusGroundSlamTrigger(ai); }
|
||||||
|
static Trigger* lightning_ring(PlayerbotAI* ai) { return new SjonnirLightningRingTrigger(ai); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include "Playerbots.h"
|
||||||
|
#include "HallsOfStoneTriggers.h"
|
||||||
|
#include "AiObject.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
|
bool KrystallusGroundSlamTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "krystallus");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
// Check both of these... the spell is applied first, debuff later.
|
||||||
|
// Neither is active for the full duration so we need to trigger off both
|
||||||
|
return bot->HasAura(SPELL_GROUND_SLAM) || bot->HasAura(DEBUFF_GROUND_SLAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SjonnirLightningRingTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "sjonnir the ironshaper");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_LIGHTNING_RING);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONHOSTRIGGERS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONHOSTRIGGERS_H
|
||||||
|
|
||||||
|
#include "Trigger.h"
|
||||||
|
#include "PlayerbotAIConfig.h"
|
||||||
|
#include "GenericTriggers.h"
|
||||||
|
#include "DungeonStrategyUtils.h"
|
||||||
|
|
||||||
|
enum HallsOfStoneIDs
|
||||||
|
{
|
||||||
|
// Krystallus
|
||||||
|
SPELL_GROUND_SLAM = 50827,
|
||||||
|
DEBUFF_GROUND_SLAM = 50833,
|
||||||
|
|
||||||
|
// Sjonnir The Ironshaper
|
||||||
|
SPELL_LIGHTNING_RING_N = 50840,
|
||||||
|
SPELL_LIGHTNING_RING_H = 59848,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPELL_LIGHTNING_RING DUNGEON_MODE(bot, SPELL_LIGHTNING_RING_N, SPELL_LIGHTNING_RING_H)
|
||||||
|
|
||||||
|
class KrystallusGroundSlamTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KrystallusGroundSlamTrigger(PlayerbotAI* ai) : Trigger(ai, "krystallus ground slam") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SjonnirLightningRingTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SjonnirLightningRingTrigger(PlayerbotAI* ai) : Trigger(ai, "sjonnir lightning ring") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user