Merge pull request #599 from Bobblybook/master

Gundrak implementation
This commit is contained in:
Bobblybook
2024-10-13 23:58:11 +11:00
committed by GitHub
15 changed files with 278 additions and 5 deletions

View File

@@ -56,6 +56,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
actionContexts.Add(new WotlkDungeonOKActionContext());
actionContexts.Add(new WotlkDungeonDTKActionContext());
actionContexts.Add(new WotlkDungeonVHActionContext());
actionContexts.Add(new WotlkDungeonGDActionContext());
triggerContexts.Add(new TriggerContext());
triggerContexts.Add(new ChatTriggerContext());
@@ -72,6 +73,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
triggerContexts.Add(new WotlkDungeonOKTriggerContext());
triggerContexts.Add(new WotlkDungeonDTKTriggerContext());
triggerContexts.Add(new WotlkDungeonVHTriggerContext());
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
valueContexts.Add(new ValueContext());

View File

@@ -8,12 +8,11 @@
#include "wotlk/oldkingdom/OldKingdomStrategy.h"
#include "wotlk/draktharonkeep/DrakTharonKeepStrategy.h"
#include "wotlk/violethold/VioletHoldStrategy.h"
#include "wotlk/gundrak/GundrakStrategy.h"
/*
Full list/TODO:
Gundrak - GD
Slad'ran, Drakkari Colossus, Moorabi, Gal'darah, Eck the Ferocious (Heroic only)
Halls of Stone - HoS
Maiden of Grief, Krystallus, Tribunal of Ages, Sjonnir The Ironshaper
Halls of Lightning - HoL
@@ -76,8 +75,8 @@ class DungeonStrategyContext : public NamedObjectContext<Strategy>
static Strategy* wotlk_ok(PlayerbotAI* botAI) { return new WotlkDungeonOKStrategy(botAI); }
static Strategy* wotlk_dtk(PlayerbotAI* botAI) { return new WotlkDungeonDTKStrategy(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 WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_hos(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); }

View File

@@ -7,7 +7,7 @@
#include "oldkingdom/OldKingdomActionContext.h"
#include "draktharonkeep/DrakTharonKeepActionContext.h"
#include "violethold/VioletHoldActionContext.h"
// #include "gundrak/GundrakActionContext.h"
#include "gundrak/GundrakActionContext.h"
// #include "hallsofstone/HallsOfStoneActionContext.h"
// #include "hallsoflightning/HallsOfLightningActionContext.h"
// #include "oculus/OculusActionContext.h"

View File

@@ -7,7 +7,7 @@
#include "oldkingdom/OldKingdomTriggerContext.h"
#include "draktharonkeep/DrakTharonKeepTriggerContext.h"
#include "violethold/VioletHoldTriggerContext.h"
// #include "gundrak/GundrakTriggerContext.h"
#include "gundrak/GundrakTriggerContext.h"
// #include "hallsofstone/HallsOfStoneTriggerContext.h"
// #include "hallsoflightning/HallsOfLightningTriggerContext.h"
// #include "oculus/OculusTriggerContext.h"

View File

@@ -0,0 +1,20 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONGDACTIONCONTEXT_H
#define _PLAYERBOT_WOTLKDUNGEONGDACTIONCONTEXT_H
#include "Action.h"
#include "NamedObjectContext.h"
#include "GundrakActions.h"
class WotlkDungeonGDActionContext : public NamedObjectContext<Action>
{
public:
WotlkDungeonGDActionContext() {
creators["avoid poison nova"] = &WotlkDungeonGDActionContext::avoid_poison_nova;
creators["avoid whirling slash"] = &WotlkDungeonGDActionContext::avoid_whirling_slash;
}
private:
static Action* avoid_poison_nova(PlayerbotAI* ai) { return new AvoidPoisonNovaAction(ai); }
static Action* avoid_whirling_slash(PlayerbotAI* ai) { return new AvoidWhirlingSlashAction(ai); }
};
#endif

View File

@@ -0,0 +1,44 @@
#include "Playerbots.h"
#include "GundrakActions.h"
#include "GundrakStrategy.h"
bool AvoidPoisonNovaAction::Execute(Event event)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
if (!boss) { return false; }
float distance = bot->GetExactDist2d(boss->GetPosition());
float radius = 15.0f;
float distanceExtra = 2.0f;
if (distance < radius + distanceExtra)
{
return MoveAway(boss, radius + distanceExtra - distance);
}
return false;
}
bool AvoidWhirlingSlashAction::Execute(Event event)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "gal'darah");
if (!boss) { return false; }
float distance = bot->GetExactDist2d(boss->GetPosition());
float radius = 5.0f;
float distanceExtra = 2.0f;
if (distance < radius + distanceExtra)
{
if (botAI->IsTank(bot))
{
// The boss chases tank during this, leads to jittery stutter-stepping
// by the tank if we don't pre-move additional range. 2*radius seems ok
return MoveAway(boss, (2.0f * radius) + distanceExtra - distance);
}
// else
return MoveAway(boss, radius + distanceExtra - distance);
}
return false;
}

View File

@@ -0,0 +1,24 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONGDACTIONS_H
#define _PLAYERBOT_WOTLKDUNGEONGDACTIONS_H
#include "Action.h"
#include "AttackAction.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "GundrakTriggers.h"
class AvoidPoisonNovaAction : public MovementAction
{
public:
AvoidPoisonNovaAction(PlayerbotAI* ai) : MovementAction(ai, "avoid poison nova") {}
bool Execute(Event event) override;
};
class AvoidWhirlingSlashAction : public MovementAction
{
public:
AvoidWhirlingSlashAction(PlayerbotAI* ai) : MovementAction(ai, "avoid whirling slash") {}
bool Execute(Event event) override;
};
#endif

View File

@@ -0,0 +1,37 @@
#include "GundrakMultipliers.h"
#include "GundrakActions.h"
#include "GenericSpellActions.h"
#include "ChooseTargetActions.h"
#include "MovementActions.h"
#include "GundrakTriggers.h"
#include "Action.h"
float SladranMultiplier::GetValue(Action* action)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
if (!boss) { return 1.0f; }
if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA))
{
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidPoisonNovaAction*>(action))
{
return 0.0f;
}
}
return 1.0f;
}
float GaldarahMultiplier::GetValue(Action* action)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "gal'darah");
if (!boss) { return 1.0f; }
if (boss->HasAura(SPELL_WHIRLING_SLASH))
{
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidWhirlingSlashAction*>(action))
{
return 0.0f;
}
}
return 1.0f;
}

View File

@@ -0,0 +1,24 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONGDMULTIPLIERS_H
#define _PLAYERBOT_WOTLKDUNGEONGDMULTIPLIERS_H
#include "Multiplier.h"
class SladranMultiplier : public Multiplier
{
public:
SladranMultiplier(PlayerbotAI* ai) : Multiplier(ai, "slad'ran") {}
public:
virtual float GetValue(Action* action);
};
class GaldarahMultiplier : public Multiplier
{
public:
GaldarahMultiplier(PlayerbotAI* ai) : Multiplier(ai, "gal'darah") {}
public:
virtual float GetValue(Action* action);
};
#endif

View File

@@ -0,0 +1,29 @@
#include "GundrakStrategy.h"
#include "GundrakMultipliers.h"
void WotlkDungeonGDStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
{
// Moorabi
// Drakkari Colossus
// Slad'ran
// TODO: Might need to add target priority for heroic on the snakes or to burn down boss.
// Will re-test in heroic, decent dps groups should be able to blast him down with no funky strats.
triggers.push_back(new TriggerNode("poison nova",
NextAction::array(0, new NextAction("avoid poison nova", ACTION_RAID + 5), nullptr)));
// Gal'darah
triggers.push_back(new TriggerNode("whirling slash",
NextAction::array(0, new NextAction("avoid whirling slash", ACTION_RAID + 5), nullptr)));
// Eck the Ferocious (Heroic only)
// TODO
}
void WotlkDungeonGDStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
{
multipliers.push_back(new SladranMultiplier(botAI));
multipliers.push_back(new GaldarahMultiplier(botAI));
}

View File

@@ -0,0 +1,18 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONGDSTRATEGY_H
#define _PLAYERBOT_WOTLKDUNGEONGDSTRATEGY_H
#include "Multiplier.h"
#include "AiObjectContext.h"
#include "Strategy.h"
class WotlkDungeonGDStrategy : public Strategy
{
public:
WotlkDungeonGDStrategy(PlayerbotAI* ai) : Strategy(ai) {}
virtual std::string const getName() override { return "gundrak"; }
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
};
#endif

View File

@@ -0,0 +1,21 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONGDTRIGGERCONTEXT_H
#define _PLAYERBOT_WOTLKDUNGEONGDTRIGGERCONTEXT_H
#include "NamedObjectContext.h"
#include "AiObjectContext.h"
#include "GundrakTriggers.h"
class WotlkDungeonGDTriggerContext : public NamedObjectContext<Trigger>
{
public:
WotlkDungeonGDTriggerContext()
{
creators["poison nova"] = &WotlkDungeonGDTriggerContext::poison_nova;
creators["whirling slash"] = &WotlkDungeonGDTriggerContext::whirling_slash;
}
private:
static Trigger* poison_nova(PlayerbotAI* ai) { return new SladranPoisonNovaTrigger(ai); }
static Trigger* whirling_slash(PlayerbotAI* ai) { return new GaldarahWhirlingSlashTrigger(ai); }
};
#endif

View File

@@ -0,0 +1,18 @@
#include "Playerbots.h"
#include "GundrakTriggers.h"
#include "AiObject.h"
#include "AiObjectContext.h"
bool SladranPoisonNovaTrigger::IsActive()
{
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
if (!boss) { return false; }
return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA);
}
bool GaldarahWhirlingSlashTrigger::IsActive()
{
Unit* boss = AI_VALUE2(Unit*, "find target", "gal'darah");
return boss && boss->HasAura(SPELL_WHIRLING_SLASH);
}

View File

@@ -0,0 +1,37 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONGDTRIGGERS_H
#define _PLAYERBOT_WOTLKDUNGEONGDTRIGGERS_H
#include "Trigger.h"
#include "PlayerbotAIConfig.h"
#include "GenericTriggers.h"
#include "DungeonStrategyUtils.h"
enum GundrakIDs
{
// Slad'ran
SPELL_POISON_NOVA_N = 55081,
SPELL_POISON_NOVA_H = 59842,
// Gal'darah
SPELL_WHIRLING_SLASH_N = 55250,
SPELL_WHIRLING_SLASH_H = 59824,
};
#define SPELL_POISON_NOVA DUNGEON_MODE(bot, SPELL_POISON_NOVA_N, SPELL_POISON_NOVA_H)
#define SPELL_WHIRLING_SLASH DUNGEON_MODE(bot, SPELL_WHIRLING_SLASH_N, SPELL_WHIRLING_SLASH_H)
class SladranPoisonNovaTrigger : public Trigger
{
public:
SladranPoisonNovaTrigger(PlayerbotAI* ai) : Trigger(ai, "slad'ran poison nova") {}
bool IsActive() override;
};
class GaldarahWhirlingSlashTrigger : public Trigger
{
public:
GaldarahWhirlingSlashTrigger(PlayerbotAI* ai) : Trigger(ai, "gal'darah whirling slash") {}
bool IsActive() override;
};
#endif