Skip to content

Commit

Permalink
Merge pull request liyunfan1223#560 from Bobblybook/master
Browse files Browse the repository at this point in the history
Wotlk dungeon structure & Utgarde Keep
  • Loading branch information
liyunfan1223 authored Sep 30, 2024
2 parents 193aab6 + 94ebe58 commit 54a8445
Show file tree
Hide file tree
Showing 31 changed files with 802 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/PlayerbotAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1529,12 +1529,60 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster)
case 533:
strategyName = "naxx";
break;
case 574:
strategyName = "wotlk-uk"; // Utgarde Keep
break;
case 575:
strategyName = "wotlk-up"; // Utgarde Pinnacle
break;
case 576:
strategyName = "wotlk-nex"; // The Nexus
break;
case 578:
strategyName = "wotlk-occ"; // The Oculus
break;
case 595:
strategyName = "wotlk-cos"; // The Culling of Stratholme
break;
case 599:
strategyName = "wotlk-hos"; // Halls of Stone
break;
case 600:
strategyName = "wotlk-dtk"; // Drak'Tharon Keep
break;
case 601:
strategyName = "wotlk-an"; // Azjol-Nerub
break;
case 602:
strategyName = "wotlk-hol"; // Halls of Lightning
break;
case 603:
strategyName = "uld";
break;
case 604:
strategyName = "wotlk-gd"; // Gundrak
break;
case 608:
strategyName = "wotlk-vh"; // Violet Hold
break;
case 619:
strategyName = "wotlk-ok"; // Ahn'kahet: The Old Kingdom
break;
case 631:
strategyName = "icc";
break;
case 632:
strategyName = "wotlk-fos"; // The Forge of Souls
break;
case 650:
strategyName = "wotlk-toc"; // Trial of the Champion
break;
case 658:
strategyName = "wotlk-pos"; // Pit of Saron
break;
case 668:
strategyName = "wotlk-hor"; // Halls of Reflection
break;
default:
break;
}
Expand Down
6 changes: 6 additions & 0 deletions src/strategy/AiObjectContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include "raids/moltencore/RaidMcTriggerContext.h"
#include "raids/aq20/RaidAq20ActionContext.h"
#include "raids/aq20/RaidAq20TriggerContext.h"
#include "dungeons/DungeonStrategyContext.h"
#include "dungeons/wotlk/WotlkDungeonActionContext.h"
#include "dungeons/wotlk/WotlkDungeonTriggerContext.h"

AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
{
Expand All @@ -36,6 +39,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
strategyContexts.Add(new AssistStrategyContext());
strategyContexts.Add(new QuestStrategyContext());
strategyContexts.Add(new RaidStrategyContext());
strategyContexts.Add(new DungeonStrategyContext());

actionContexts.Add(new ActionContext());
actionContexts.Add(new ChatActionContext());
Expand All @@ -46,6 +50,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
actionContexts.Add(new RaidNaxxActionContext());
actionContexts.Add(new RaidUlduarActionContext());
actionContexts.Add(new RaidIccActionContext());
actionContexts.Add(new WotlkDungeonUKActionContext());

triggerContexts.Add(new TriggerContext());
triggerContexts.Add(new ChatTriggerContext());
Expand All @@ -56,6 +61,7 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
triggerContexts.Add(new RaidNaxxTriggerContext());
triggerContexts.Add(new RaidUlduarTriggerContext());
triggerContexts.Add(new RaidIccTriggerContext());
triggerContexts.Add(new WotlkDungeonUKTriggerContext());

valueContexts.Add(new ValueContext());

Expand Down
96 changes: 96 additions & 0 deletions src/strategy/dungeons/DungeonStrategyContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#ifndef _PLAYERBOT_DUNGEONSTRATEGYCONTEXT_H_
#define _PLAYERBOT_DUNGEONSTRATEGYCONTEXT_H_

#include "Strategy.h"
#include "wotlk/utgardekeep/UtgardeKeepStrategy.h"

/*
Full list/TODO:
The Nexus - Nex
Grand Magus Telestra, Anomalus, Ormorok the Tree-Shaper, Keristrasza, Commander Stoutbeard (Horde Heroic Only)/Commander Kolurg (Alliance Heroic Only)
Azjol-Nerub: Azjol-Nerub - AN
Krik'thir the Gatewatcher, Hadronox, Anub'arak
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
Erekem, Moragg, Ichoron, Xevozz, Lavanthor, Zuramat the Obliterator, Cyanigosa
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
General Bjarngrim, Volkhan, Ionar, Loken
The Oculus - Occ
Drakos the Interrogator, Varos Cloudstrider, Mage-Lord Urom, Ley-Guardian Eregos
Utgarde Pinnacle - UP
Svala Sorrowgrave, Gortok Palehoof, Skadi the Ruthless, King Ymiron
The Culling of Stratholme - CoS
Meathook, Salramm the Fleshcrafter, Chrono-Lord Epoch, Mal'Ganis, Infinite Corruptor (Heroic only)
Trial of the Champion - ToC
Alliance Champions: Deathstalker Visceri, Eressea Dawnsinger, Mokra the Skullcrusher, Runok Wildmane, Zul'tore
Horde Champions: Ambrose Boltspark, Colosos, Jacob Alerius, Jaelyne Evensong, Lana Stouthammer
Argent Champion: Argent Confessor Paletress/Eadric the Pure
The Black Knight
Halls of Reflection - HoR
Falric, Marwyn, The Lich King
Pit of Saron - PoS
Forgemaster Garfrost, Krick & Ick, Scourgelord Tyrannus
The Forge of Souls - FoS
Bronjahm, Devourer of Souls
*/



class DungeonStrategyContext : public NamedObjectContext<Strategy>
{
public:
DungeonStrategyContext() : NamedObjectContext<Strategy>(false, true)
{
// Vanilla
// ...

// Burning Crusade
// ...

// Wrath of the Lich King
creators["wotlk-uk"] = &DungeonStrategyContext::wotlk_uk; // Utgarde Keep
creators["wotlk-nex"] = &DungeonStrategyContext::wotlk_nex; // The Nexus
creators["wotlk-an"] = &DungeonStrategyContext::wotlk_an; // Azjol-Nerub
creators["wotlk-ok"] = &DungeonStrategyContext::wotlk_ok; // Ahn'kahet: The Old Kingdom
creators["wotlk-dtk"] = &DungeonStrategyContext::wotlk_dtk; // Drak'Tharon Keep
creators["wotlk-vh"] = &DungeonStrategyContext::wotlk_vh; // The Violet Hold
creators["wotlk-gd"] = &DungeonStrategyContext::wotlk_gd; // Gundrak
creators["wotlk-hos"] = &DungeonStrategyContext::wotlk_hos; // Halls of Stone
creators["wotlk-hol"] = &DungeonStrategyContext::wotlk_hol; // Halls of Lightning
creators["wotlk-occ"] = &DungeonStrategyContext::wotlk_occ; // The Oculus
creators["wotlk-up"] = &DungeonStrategyContext::wotlk_up; // Utgarde Pinnacle
creators["wotlk-cos"] = &DungeonStrategyContext::wotlk_cos; // The Culling of Stratholme
creators["wotlk-toc"] = &DungeonStrategyContext::wotlk_toc; // Trial of the Champion
creators["wotlk-hor"] = &DungeonStrategyContext::wotlk_hor; // Halls of Reflection
creators["wotlk-pos"] = &DungeonStrategyContext::wotlk_pos; // Pit of Saron
creators["wotlk-fos"] = &DungeonStrategyContext::wotlk_fos; // The Forge of Souls
}
private:
static Strategy* wotlk_uk(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_nex(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_an(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_ok(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(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); }
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); }
static Strategy* wotlk_up(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_hor(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
};

#endif
21 changes: 21 additions & 0 deletions src/strategy/dungeons/DungeonStrategyUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _PLAYERBOT_DUNGEONUTILS_H_
#define _PLAYERBOT_DUNGEONUTILS_H_


template<class T> inline
const T& DUNGEON_MODE(Player* bot, const T& normal5, const T& heroic10)
{
switch (bot->GetMap()->GetDifficulty())
{
case DUNGEON_DIFFICULTY_NORMAL:
return normal5;
case DUNGEON_DIFFICULTY_HEROIC:
return heroic10;
default:
break;
}

return heroic10;
}

#endif
21 changes: 21 additions & 0 deletions src/strategy/dungeons/wotlk/WotlkDungeonActionContext.h
Original file line number Diff line number Diff line change
@@ -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 changes: 21 additions & 0 deletions src/strategy/dungeons/wotlk/WotlkDungeonTriggerContext.h
Original file line number Diff line number Diff line change
@@ -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
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
30 changes: 30 additions & 0 deletions src/strategy/dungeons/wotlk/utgardekeep/UtgardeKeepActionContext.h
Original file line number Diff line number Diff line change
@@ -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
97 changes: 97 additions & 0 deletions src/strategy/dungeons/wotlk/utgardekeep/UtgardeKeepActions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#include "Playerbots.h"
#include "UtgardeKeepActions.h"
#include "UtgardeKeepStrategy.h"

bool AttackFrostTombAction::Execute(Event event)
{
Unit* frostTomb = 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")
{
frostTomb = unit;
break;
}
}
if (!frostTomb || AI_VALUE(Unit*, "current target") == frostTomb)
{
return false;
}
return Attack(frostTomb);
}

// TODO: Possibly add player stacking behaviour close to tank, to prevent Skarvald charging ranged
bool AttackDalronnAction::Execute(Event event)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "dalronn the controller");
if (!boss || AI_VALUE(Unit*, "current target") == boss)
{
return false;
}
return Attack(boss);
}

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());
}
Loading

0 comments on commit 54a8445

Please sign in to comment.