Skip to content

Commit

Permalink
Old Kingdom implementation
Browse files Browse the repository at this point in the history
Ahn'kahet: The Old Kingdom bot AI
  • Loading branch information
Bobblybook committed Oct 8, 2024
1 parent 62a9a60 commit 16ea177
Show file tree
Hide file tree
Showing 15 changed files with 405 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/strategy/AiObjectContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
actionContexts.Add(new WotlkDungeonUKActionContext());
actionContexts.Add(new WotlkDungeonNexActionContext());
actionContexts.Add(new WotlkDungeonANActionContext());
actionContexts.Add(new WotlkDungeonOKActionContext());

triggerContexts.Add(new TriggerContext());
triggerContexts.Add(new ChatTriggerContext());
Expand All @@ -66,6 +67,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
triggerContexts.Add(new WotlkDungeonUKTriggerContext());
triggerContexts.Add(new WotlkDungeonNexTriggerContext());
triggerContexts.Add(new WotlkDungeonANTriggerContext());
triggerContexts.Add(new WotlkDungeonOKTriggerContext());

valueContexts.Add(new ValueContext());

Expand Down
9 changes: 3 additions & 6 deletions src/strategy/dungeons/DungeonStrategyContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@
#include "wotlk/utgardekeep/UtgardeKeepStrategy.h"
#include "wotlk/nexus/NexusStrategy.h"
#include "wotlk/azjolnerub/AzjolNerubStrategy.h"
#include "wotlk/oldkingdom/OldKingdomStrategy.h"

/*
Full list/TODO:
Ahn'kahet: The Old Kingdom - OK
Elder Nadox, Prince Taldaram, Jedoga Shadowseeker, Herald Volazj, Amanitar (Heroic Only)
Drak'Tharon Keep - DTK
Trollgore, Novos the Summoner, King Dred, The Prophet Tharon'ja
The Violet Hold - VH
Expand Down Expand Up @@ -77,8 +74,8 @@ class DungeonStrategyContext : public NamedObjectContext<Strategy>
static Strategy* wotlk_uk(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_nex(PlayerbotAI* botAI) { return new WotlkDungeonNexStrategy(botAI); }
static Strategy* wotlk_an(PlayerbotAI* botAI) { return new WotlkDungeonANStrategy(botAI); }

static Strategy* wotlk_ok(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_ok(PlayerbotAI* botAI) { return new WotlkDungeonOKStrategy(botAI); }

static Strategy* wotlk_dtk(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_vh(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_gd(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
Expand Down
2 changes: 1 addition & 1 deletion src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "utgardekeep/UtgardeKeepActionContext.h"
#include "nexus/NexusActionContext.h"
#include "azjolnerub/AzjolNerubActionContext.h"
// #include "oldkingdom/OldKingdomActionContext.h"
#include "oldkingdom/OldKingdomActionContext.h"
// #include "draktharonkeep/DraktharonKeepActionContext.h"
// #include "violethold/VioletHoldActionContext.h"
// #include "gundrak/GundrakActionContext.h"
Expand Down
2 changes: 1 addition & 1 deletion src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "utgardekeep/UtgardeKeepTriggerContext.h"
#include "nexus/NexusTriggerContext.h"
#include "azjolnerub/AzjolNerubTriggerContext.h"
// #include "oldkingdom/OldKingdomTriggerContext.h"
#include "oldkingdom/OldKingdomTriggerContext.h"
// #include "draktharonkeep/DraktharonKeepTriggerContext.h"
// #include "violethold/VioletHoldTriggerContext.h"
// #include "gundrak/GundrakTriggerContext.h"
Expand Down
22 changes: 22 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActionContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONOKACTIONCONTEXT_H
#define _PLAYERBOT_WOTLKDUNGEONOKACTIONCONTEXT_H

#include "Action.h"
#include "NamedObjectContext.h"
#include "OldKingdomActions.h"

class WotlkDungeonOKActionContext : public NamedObjectContext<Action>
{
public:
WotlkDungeonOKActionContext() {
creators["attack nadox guardian"] = &WotlkDungeonOKActionContext::attack_nadox_guardian;
creators["attack jedoga volunteer"] = &WotlkDungeonOKActionContext::attack_jedoga_volunteer;
creators["avoid shadow crash"] = &WotlkDungeonOKActionContext::avoid_shadow_crash;
}
private:
static Action* attack_nadox_guardian(PlayerbotAI* ai) { return new AttackNadoxGuardianAction(ai); }
static Action* attack_jedoga_volunteer(PlayerbotAI* ai) { return new AttackJedogaVolunteerAction(ai); }
static Action* avoid_shadow_crash(PlayerbotAI* ai) { return new AvoidShadowCrashAction(ai); }
};

#endif
81 changes: 81 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include "Playerbots.h"
#include "OldKingdomActions.h"
#include "OldKingdomStrategy.h"


bool AttackNadoxGuardianAction::Execute(Event event)
{
Unit* target = AI_VALUE2(Unit*, "find target", "ahn'kahar guardian");
if (!target || AI_VALUE(Unit*, "current target") == target)
{
return false;
}

return Attack(target);
}

bool AttackJedogaVolunteerAction::Execute(Event event)
{
Unit* target = 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->GetEntry() == NPC_TWILIGHT_VOLUNTEER)
{
target = unit;
break;
}
}

if (!target || AI_VALUE(Unit*, "current target") == target)
{
return false;
}
return Attack(target);
}

bool AvoidShadowCrashAction::Execute(Event event)
{
// Could check all enemy units in range as it's possible to pull multiple of these mobs.
// They should really be killed 1 by 1, multipulls are messy so we just handle singles for now
Unit* npc = AI_VALUE2(Unit*, "find target", "forgotten one");
Unit* victim = nullptr;
float radius = 10.0f;
float targetDist = radius + 2.0f;
if (!npc) { return false; }

// Actively move if targeted by a shadow crash.
// Spell check not needed, they don't have any other non-instant casts
if (npc->HasUnitState(UNIT_STATE_CASTING)) // && npc->FindCurrentSpellBySpellId(SPELL_SHADOW_CRASH))
{
// This doesn't seem to avoid casts very well, perhaps because this isn't checked while allies are casting.
// TODO: Revisit if this is an issue in heroics, otherwise ignore shadow crashes for the most part.
victim = botAI->GetUnit(npc->GetTarget());
if (victim && bot->GetExactDist2d(victim) < radius)
{
return MoveAway(victim, targetDist - bot->GetExactDist2d(victim));
}
}

// Otherwise ranged members passively spread, to avoid AoE overlap
if (botAI->IsMelee(bot)) { return false; }

GuidVector members = AI_VALUE(GuidVector, "group members");
for (auto& member : members)
{
if (bot->GetGUID() == member)
{
continue;
}
float currentDist = bot->GetExactDist2d(botAI->GetUnit(member));
if (currentDist < radius)
{
return MoveAway(botAI->GetUnit(member), targetDist - currentDist);
}
}
return false;
}
31 changes: 31 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomActions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONOKACTIONS_H
#define _PLAYERBOT_WOTLKDUNGEONOKACTIONS_H

#include "Action.h"
#include "AttackAction.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
#include "OldKingdomTriggers.h"

class AttackNadoxGuardianAction : public AttackAction
{
public:
AttackNadoxGuardianAction(PlayerbotAI* ai) : AttackAction(ai, "attack nadox guardian") {}
bool Execute(Event event) override;
};

class AttackJedogaVolunteerAction : public AttackAction
{
public:
AttackJedogaVolunteerAction(PlayerbotAI* ai) : AttackAction(ai, "attack jedoga volunteer") {}
bool Execute(Event event) override;
};

class AvoidShadowCrashAction : public MovementAction
{
public:
AvoidShadowCrashAction(PlayerbotAI* ai) : MovementAction(ai, "avoid shadow crash") {}
bool Execute(Event event) override;
};

#endif
66 changes: 66 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomMultipliers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "OldKingdomMultipliers.h"
#include "OldKingdomActions.h"
#include "GenericSpellActions.h"
#include "ChooseTargetActions.h"
#include "MovementActions.h"
#include "OldKingdomTriggers.h"
#include "Action.h"

float ElderNadoxMultiplier::GetValue(Action* action)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "elder nadox");
Unit* guardian = AI_VALUE2(Unit*, "find target", "ahn'kahar guardian");

if (boss && guardian)
{
if (dynamic_cast<DpsAssistAction*>(action))
{
return 0.0f;
}
}
return 1.0f;
}

float JedogaShadowseekerMultiplier::GetValue(Action* action)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "jedoga shadowseeker");
// Unit* volunteer = AI_VALUE2(Unit*, "find target", "twilight volunteer");

Unit* volunteer = 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->GetEntry() == NPC_TWILIGHT_VOLUNTEER)
{
volunteer = unit;
break;
}
}

if (boss && volunteer)
{
if (dynamic_cast<DpsAssistAction*>(action))
{
return 0.0f;
}
}
return 1.0f;
}

float ForgottenOneMultiplier::GetValue(Action* action)
{
Unit* npc = AI_VALUE2(Unit*, "find target", "forgotten one");

if (npc && bot->isMoving())
{
if (dynamic_cast<MovementAction*>(action))
{
return 0.0f;
}
}
return 1.0f;
}
33 changes: 33 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomMultipliers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONOKMULTIPLIERS_H
#define _PLAYERBOT_WOTLKDUNGEONOKMULTIPLIERS_H

#include "Multiplier.h"

class ElderNadoxMultiplier : public Multiplier
{
public:
ElderNadoxMultiplier(PlayerbotAI* ai) : Multiplier(ai, "elder nadox") {}

public:
virtual float GetValue(Action* action);
};

class JedogaShadowseekerMultiplier : public Multiplier
{
public:
JedogaShadowseekerMultiplier(PlayerbotAI* ai) : Multiplier(ai, "jedoga shadowseeker") {}

public:
virtual float GetValue(Action* action);
};

class ForgottenOneMultiplier : public Multiplier
{
public:
ForgottenOneMultiplier(PlayerbotAI* ai) : Multiplier(ai, "forgotten one") {}

public:
virtual float GetValue(Action* action);
};

#endif
36 changes: 36 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomStrategy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#include "OldKingdomStrategy.h"
#include "OldKingdomMultipliers.h"


void WotlkDungeonOKStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
{
// Elder Nadox
triggers.push_back(new TriggerNode("nadox guardian",
NextAction::array(0, new NextAction("attack nadox guardian", ACTION_RAID + 5), nullptr)));

// Prince Taldaram
// Flame Orb spawns in melee, doesn't have a clear direction until it starts moving.
// Maybe not worth trying to avoid and just heal through. Only consideration is not to have ranged
// players anywhere near melee when it spawns

// Jedoga Shadowseeker
triggers.push_back(new TriggerNode("jedoga volunteer",
NextAction::array(0, new NextAction("attack jedoga volunteer", ACTION_RAID + 5), nullptr)));

// Herald Volazj
// Trash mobs before him have a big telegraphed shadow crash spell,
// this can be avoided and is intended to be dodged
triggers.push_back(new TriggerNode("shadow crash",
NextAction::array(0, new NextAction("avoid shadow crash", ACTION_MOVE + 5), nullptr)));
// Volazj is not implemented properly in AC, insanity phase does nothing.

// Amanitar (Heroic Only)
// TODO: once I get to heroics
}

void WotlkDungeonOKStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
{
multipliers.push_back(new ElderNadoxMultiplier(botAI));
multipliers.push_back(new JedogaShadowseekerMultiplier(botAI));
multipliers.push_back(new ForgottenOneMultiplier(botAI));
}
18 changes: 18 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomStrategy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONOKSTRATEGY_H
#define _PLAYERBOT_WOTLKDUNGEONOKSTRATEGY_H

#include "Multiplier.h"
#include "AiObjectContext.h"
#include "Strategy.h"


class WotlkDungeonOKStrategy : public Strategy
{
public:
WotlkDungeonOKStrategy(PlayerbotAI* ai) : Strategy(ai) {}
virtual std::string const getName() override { return "old kingdom"; }
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
};

#endif
23 changes: 23 additions & 0 deletions src/strategy/dungeons/wotlk/oldkingdom/OldKingdomTriggerContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef _PLAYERBOT_WOTLKDUNGEONOKTRIGGERCONTEXT_H
#define _PLAYERBOT_WOTLKDUNGEONOKTRIGGERCONTEXT_H

#include "NamedObjectContext.h"
#include "AiObjectContext.h"
#include "OldKingdomTriggers.h"

class WotlkDungeonOKTriggerContext : public NamedObjectContext<Trigger>
{
public:
WotlkDungeonOKTriggerContext()
{
creators["nadox guardian"] = &WotlkDungeonOKTriggerContext::nadox_guardian;
creators["jedoga volunteer"] = &WotlkDungeonOKTriggerContext::jedoga_volunteer;
creators["shadow crash"] = &WotlkDungeonOKTriggerContext::shadow_crash;
}
private:
static Trigger* nadox_guardian(PlayerbotAI* ai) { return new NadoxGuardianTrigger(ai); }
static Trigger* jedoga_volunteer(PlayerbotAI* ai) { return new JedogaVolunteerTrigger(ai); }
static Trigger* shadow_crash(PlayerbotAI* ai) { return new ShadowCrashTrigger(ai); }
};

#endif
Loading

0 comments on commit 16ea177

Please sign in to comment.