mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 00:58:33 +00:00
UP and CoS dungeons
- Utgarde Pinnacle implementation
- Culling of Stratholme implementation
- Added additional value ("nearest hostile npcs") needed to expose some hidden trigger-type npc units (eg. frost breath on Skadi fight in UP)
This commit is contained in:
@@ -59,6 +59,8 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
|||||||
actionContexts.Add(new WotlkDungeonGDActionContext());
|
actionContexts.Add(new WotlkDungeonGDActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonHoSActionContext());
|
actionContexts.Add(new WotlkDungeonHoSActionContext());
|
||||||
actionContexts.Add(new WotlkDungeonHoLActionContext());
|
actionContexts.Add(new WotlkDungeonHoLActionContext());
|
||||||
|
actionContexts.Add(new WotlkDungeonUPActionContext());
|
||||||
|
actionContexts.Add(new WotlkDungeonCoSActionContext());
|
||||||
|
|
||||||
triggerContexts.Add(new TriggerContext());
|
triggerContexts.Add(new TriggerContext());
|
||||||
triggerContexts.Add(new ChatTriggerContext());
|
triggerContexts.Add(new ChatTriggerContext());
|
||||||
@@ -78,6 +80,8 @@ AiObjectContext::AiObjectContext(PlayerbotAI* botAI) : PlayerbotAIAware(botAI)
|
|||||||
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
|
triggerContexts.Add(new WotlkDungeonGDTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonHoSTriggerContext());
|
triggerContexts.Add(new WotlkDungeonHoSTriggerContext());
|
||||||
triggerContexts.Add(new WotlkDungeonHoLTriggerContext());
|
triggerContexts.Add(new WotlkDungeonHoLTriggerContext());
|
||||||
|
triggerContexts.Add(new WotlkDungeonUPTriggerContext());
|
||||||
|
triggerContexts.Add(new WotlkDungeonCoSTriggerContext());
|
||||||
|
|
||||||
valueContexts.Add(new ValueContext());
|
valueContexts.Add(new ValueContext());
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,14 @@
|
|||||||
#include "wotlk/gundrak/GundrakStrategy.h"
|
#include "wotlk/gundrak/GundrakStrategy.h"
|
||||||
#include "wotlk/hallsofstone/HallsOfStoneStrategy.h"
|
#include "wotlk/hallsofstone/HallsOfStoneStrategy.h"
|
||||||
#include "wotlk/hallsoflightning/HallsOfLightningStrategy.h"
|
#include "wotlk/hallsoflightning/HallsOfLightningStrategy.h"
|
||||||
|
#include "wotlk/utgardepinnacle/UtgardePinnacleStrategy.h"
|
||||||
|
#include "wotlk/cullingofstratholme/CullingOfStratholmeStrategy.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Full list/TODO:
|
Full list/TODO:
|
||||||
|
|
||||||
The Oculus - Occ
|
The Oculus - Occ
|
||||||
Drakos the Interrogator, Varos Cloudstrider, Mage-Lord Urom, Ley-Guardian Eregos
|
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
|
Trial of the Champion - ToC
|
||||||
Alliance Champions: Deathstalker Visceri, Eressea Dawnsinger, Mokra the Skullcrusher, Runok Wildmane, Zul'tore
|
Alliance Champions: Deathstalker Visceri, Eressea Dawnsinger, Mokra the Skullcrusher, Runok Wildmane, Zul'tore
|
||||||
Horde Champions: Ambrose Boltspark, Colosos, Jacob Alerius, Jaelyne Evensong, Lana Stouthammer
|
Horde Champions: Ambrose Boltspark, Colosos, Jacob Alerius, Jaelyne Evensong, Lana Stouthammer
|
||||||
@@ -76,11 +74,12 @@ class DungeonStrategyContext : public NamedObjectContext<Strategy>
|
|||||||
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 WotlkDungeonHoSStrategy(botAI); }
|
||||||
static Strategy* wotlk_hol(PlayerbotAI* botAI) { return new WotlkDungeonHoLStrategy(botAI); }
|
static Strategy* wotlk_hol(PlayerbotAI* botAI) { return new WotlkDungeonHoLStrategy(botAI); }
|
||||||
|
// static Strategy* wotlk_occ(PlayerbotAI* botAI) { return new WotlkDungeonOccStrategy(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 WotlkDungeonUPStrategy(botAI); }
|
||||||
static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
static Strategy* wotlk_cos(PlayerbotAI* botAI) { return new WotlkDungeonCoSStrategy(botAI); }
|
||||||
static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
|
||||||
|
static Strategy* wotlk_toc(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); } // NYI from here down
|
||||||
static Strategy* wotlk_hor(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_pos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
||||||
static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
static Strategy* wotlk_fos(PlayerbotAI* botAI) { return new WotlkDungeonUKStrategy(botAI); }
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#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"
|
||||||
// #include "cullingofstratholme/CullingOfStratholmeActionContext.h"
|
#include "cullingofstratholme/CullingOfStratholmeActionContext.h"
|
||||||
// #include "trialofthechampion/TrialOfTheChampionActionContext.h"
|
// #include "trialofthechampion/TrialOfTheChampionActionContext.h"
|
||||||
// #include "hallsofreflection/HallsOfReflectionActionContext.h"
|
// #include "hallsofreflection/HallsOfReflectionActionContext.h"
|
||||||
// #include "pitofsaron/PitOfSaronActionContext.h"
|
// #include "pitofsaron/PitOfSaronActionContext.h"
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#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"
|
||||||
// #include "cullingofstratholme/CullingOfStratholmeTriggerContext.h"
|
#include "cullingofstratholme/CullingOfStratholmeTriggerContext.h"
|
||||||
// #include "trialofthechampion/TrialOfTheChampionTriggerContext.h"
|
// #include "trialofthechampion/TrialOfTheChampionTriggerContext.h"
|
||||||
// #include "hallsofreflection/HallsOfReflectionTriggerContext.h"
|
// #include "hallsofreflection/HallsOfReflectionTriggerContext.h"
|
||||||
// #include "pitofsaron/PitOfSaronTriggerContext.h"
|
// #include "pitofsaron/PitOfSaronTriggerContext.h"
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONCOSACTIONCONTEXT_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONCOSACTIONCONTEXT_H
|
||||||
|
|
||||||
|
#include "Action.h"
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "CullingOfStratholmeActions.h"
|
||||||
|
|
||||||
|
class WotlkDungeonCoSActionContext : public NamedObjectContext<Action>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonCoSActionContext() {
|
||||||
|
creators["explode ghoul spread"] = &WotlkDungeonCoSActionContext::explode_ghoul_spread;
|
||||||
|
creators["epoch stack"] = &WotlkDungeonCoSActionContext::epoch_stack;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static Action* explode_ghoul_spread(PlayerbotAI* ai) { return new ExplodeGhoulSpreadAction(ai); }
|
||||||
|
static Action* epoch_stack(PlayerbotAI* ai) { return new EpochStackAction(ai); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include "Playerbots.h"
|
||||||
|
#include "CullingOfStratholmeActions.h"
|
||||||
|
#include "CullingOfStratholmeStrategy.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool ExplodeGhoulSpreadAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "salramm the fleshcrafter");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
float distance = 10.0f;
|
||||||
|
float distanceExtra = 2.0f;
|
||||||
|
GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses");
|
||||||
|
for (auto i = corpses.begin(); i != corpses.end(); ++i)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
|
if (unit && unit->GetEntry() == NPC_GHOUL_MINION)
|
||||||
|
{
|
||||||
|
float currentDistance = bot->GetExactDist2d(unit);
|
||||||
|
if (currentDistance < distance + distanceExtra)
|
||||||
|
{
|
||||||
|
return MoveAway(unit, distance + distanceExtra - currentDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EpochStackAction::isUseful()
|
||||||
|
{
|
||||||
|
// Minimum hunter range is 5, but values too close to this seem to cause issues..
|
||||||
|
// Hunter bots will try and melee in between ranged attacks, or just melee entirely at 5 as they are in range.
|
||||||
|
// 7.5 or 8.0 solves this for this boss.
|
||||||
|
// Unfortunately at this range the boss will charge. So I guess just don't stack as a hunter..
|
||||||
|
// if(bot->getClass() == CLASS_HUNTER)
|
||||||
|
// {
|
||||||
|
// return AI_VALUE2(float, "distance", "current target") > 7.5f;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
return !(bot->getClass() == CLASS_HUNTER) && AI_VALUE2(float, "distance", "current target") > 5.0f;
|
||||||
|
}
|
||||||
|
bool EpochStackAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "chrono-lord epoch");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
float maxMovement = 10.0f;
|
||||||
|
// if(bot->getClass() == CLASS_HUNTER)
|
||||||
|
// {
|
||||||
|
// return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement));
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss), maxMovement));
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONCOSACTIONS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONCOSACTIONS_H
|
||||||
|
|
||||||
|
#include "Action.h"
|
||||||
|
#include "AttackAction.h"
|
||||||
|
#include "GenericSpellActions.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "CullingOfStratholmeTriggers.h"
|
||||||
|
|
||||||
|
class ExplodeGhoulSpreadAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExplodeGhoulSpreadAction(PlayerbotAI* ai) : MovementAction(ai, "explode ghoul spread") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EpochStackAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EpochStackAction(PlayerbotAI* ai) : MovementAction(ai, "epoch stack") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
bool isUseful() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include "CullingOfStratholmeMultipliers.h"
|
||||||
|
#include "CullingOfStratholmeActions.h"
|
||||||
|
#include "GenericSpellActions.h"
|
||||||
|
#include "ChooseTargetActions.h"
|
||||||
|
#include "MovementActions.h"
|
||||||
|
#include "CullingOfStratholmeTriggers.h"
|
||||||
|
#include "Action.h"
|
||||||
|
|
||||||
|
float EpochMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "chrono-lord epoch");
|
||||||
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
|
if (bot->getClass() == CLASS_HUNTER) { return 1.0f; }
|
||||||
|
|
||||||
|
if (dynamic_cast<FleeAction*>(action)) { return 0.0f; }
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONCOSMULTIPLIERS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONCOSMULTIPLIERS_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
|
||||||
|
class EpochMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EpochMultiplier(PlayerbotAI* ai) : Multiplier(ai, "chrono-lord epoch") {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "CullingOfStratholmeStrategy.h"
|
||||||
|
#include "CullingOfStratholmeMultipliers.h"
|
||||||
|
|
||||||
|
|
||||||
|
void WotlkDungeonCoSStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||||
|
{
|
||||||
|
// Meathook
|
||||||
|
// Can tank this in a fixed position to allow healer to LoS the stun, probably not necessary
|
||||||
|
|
||||||
|
// Salramm the Fleshcrafter
|
||||||
|
triggers.push_back(new TriggerNode("explode ghoul",
|
||||||
|
NextAction::array(0, new NextAction("explode ghoul spread", ACTION_MOVE + 5), nullptr)));
|
||||||
|
|
||||||
|
// Chrono-Lord Epoch
|
||||||
|
// Not sure if this actually works, I think I've seen him charge melee characters..?
|
||||||
|
triggers.push_back(new TriggerNode("epoch ranged",
|
||||||
|
NextAction::array(0, new NextAction("epoch stack", ACTION_MOVE + 5), nullptr)));
|
||||||
|
|
||||||
|
// Mal'Ganis
|
||||||
|
|
||||||
|
// Infinite Corruptor (Heroic only)
|
||||||
|
}
|
||||||
|
|
||||||
|
void WotlkDungeonCoSStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||||
|
{
|
||||||
|
multipliers.push_back(new EpochMultiplier(botAI));
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONCOSSTRATEGY_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONCOSSTRATEGY_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "Strategy.h"
|
||||||
|
|
||||||
|
|
||||||
|
class WotlkDungeonCoSStrategy : public Strategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonCoSStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||||
|
virtual std::string const getName() override { return "culling of stratholme"; }
|
||||||
|
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
|
||||||
|
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERCONTEXT_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERCONTEXT_H
|
||||||
|
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "CullingOfStratholmeTriggers.h"
|
||||||
|
|
||||||
|
class WotlkDungeonCoSTriggerContext : public NamedObjectContext<Trigger>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonCoSTriggerContext()
|
||||||
|
{
|
||||||
|
creators["explode ghoul"] = &WotlkDungeonCoSTriggerContext::explode_ghoul;
|
||||||
|
creators["epoch ranged"] = &WotlkDungeonCoSTriggerContext::epoch_ranged;
|
||||||
|
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static Trigger* explode_ghoul(PlayerbotAI* ai) { return new ExplodeGhoulTrigger(ai); }
|
||||||
|
static Trigger* epoch_ranged(PlayerbotAI* ai) { return new EpochRangedTrigger(ai); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include "Playerbots.h"
|
||||||
|
#include "CullingOfStratholmeTriggers.h"
|
||||||
|
#include "AiObject.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool ExplodeGhoulTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "salramm the fleshcrafter");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
float distance = 10.0f;
|
||||||
|
float distanceExtra = 2.0f;
|
||||||
|
GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses");
|
||||||
|
for (auto i = corpses.begin(); i != corpses.end(); ++i)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
|
if (unit && unit->GetEntry() == NPC_RISEN_GHOUL)
|
||||||
|
{
|
||||||
|
if (bot->GetExactDist2d(unit) < distance + distanceExtra)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EpochRangedTrigger::IsActive()
|
||||||
|
{
|
||||||
|
return !botAI->IsMelee(bot) && AI_VALUE2(Unit*, "find target", "chrono-lord epoch");
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONCOSTRIGGERS_H
|
||||||
|
|
||||||
|
#include "Trigger.h"
|
||||||
|
#include "PlayerbotAIConfig.h"
|
||||||
|
#include "GenericTriggers.h"
|
||||||
|
#include "DungeonStrategyUtils.h"
|
||||||
|
|
||||||
|
enum CullingOfStratholmeIDs
|
||||||
|
{
|
||||||
|
// Salramm the Fleshcrafter
|
||||||
|
NPC_GHOUL_MINION = 27733,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExplodeGhoulTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExplodeGhoulTrigger(PlayerbotAI* ai) : Trigger(ai, "explode ghoul") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EpochRangedTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EpochRangedTrigger(PlayerbotAI* ai) : Trigger(ai, "chrono-lord epoch ranged") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -8,16 +8,18 @@ bool CorpseExplodeSpreadAction::Execute(Event event)
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "trollgore");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "trollgore");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
float distance = 6.0f; // 5 unit radius, 1 unit added as buffer
|
float distance = 5.0f;
|
||||||
|
float distanceExtra = 2.0f;
|
||||||
GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses");
|
GuidVector corpses = AI_VALUE(GuidVector, "nearest corpses");
|
||||||
for (auto i = corpses.begin(); i != corpses.end(); ++i)
|
for (auto i = corpses.begin(); i != corpses.end(); ++i)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(*i);
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
if (unit && unit->GetEntry() == NPC_DRAKKARI_INVADER)
|
if (unit && unit->GetEntry() == NPC_DRAKKARI_INVADER)
|
||||||
{
|
{
|
||||||
if (bot->GetExactDist2d(unit) < distance)
|
float currentDistance = bot->GetExactDist2d(unit);
|
||||||
|
if (currentDistance < distance + distanceExtra)
|
||||||
{
|
{
|
||||||
return MoveAway(unit, distance - bot->GetExactDist2d(unit));
|
return MoveAway(unit, distance + distanceExtra - currentDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ bool LokenStackAction::isUseful()
|
|||||||
{
|
{
|
||||||
// Minimum hunter range is 5, but values too close to this seem to cause issues..
|
// Minimum hunter range is 5, but values too close to this seem to cause issues..
|
||||||
// Hunter bots will try and melee in between ranged attacks, or just melee entirely at 5 as they are in range.
|
// Hunter bots will try and melee in between ranged attacks, or just melee entirely at 5 as they are in range.
|
||||||
// 6.5 or 7.0 solves this.
|
// 6.5 or 7.0 solves this for this boss.
|
||||||
if(bot->getClass() == CLASS_HUNTER)
|
if(bot->getClass() == CLASS_HUNTER)
|
||||||
{
|
{
|
||||||
return AI_VALUE2(float, "distance", "current target") > 6.5f;
|
return AI_VALUE2(float, "distance", "current target") > 6.5f;
|
||||||
@@ -138,14 +138,15 @@ bool LokenStackAction::Execute(Event event)
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "loken");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "loken");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
float maxMovement = 10.0f;
|
||||||
if (!boss->HasUnitState(UNIT_STATE_CASTING))
|
if (!boss->HasUnitState(UNIT_STATE_CASTING))
|
||||||
{
|
{
|
||||||
if(bot->getClass() == CLASS_HUNTER)
|
if(bot->getClass() == CLASS_HUNTER)
|
||||||
{
|
{
|
||||||
return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, 10.0f));
|
return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss) - 6.5f, maxMovement));
|
||||||
}
|
}
|
||||||
// else
|
// else
|
||||||
return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss), 10.0f));
|
return Move(bot->GetAngle(boss), fmin(bot->GetExactDist2d(boss), maxMovement));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONUPACTIONCONTEXT_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONUPACTIONCONTEXT_H
|
||||||
|
|
||||||
|
#include "Action.h"
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "UtgardePinnacleActions.h"
|
||||||
|
|
||||||
|
class WotlkDungeonUPActionContext : public NamedObjectContext<Action>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonUPActionContext() {
|
||||||
|
creators["avoid freezing cloud"] = &WotlkDungeonUPActionContext::avoid_freezing_cloud;
|
||||||
|
creators["avoid skadi whirlwind"] = &WotlkDungeonUPActionContext::avoid_whirlwind;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static Action* avoid_freezing_cloud(PlayerbotAI* ai) { return new AvoidFreezingCloudAction(ai); }
|
||||||
|
static Action* avoid_whirlwind(PlayerbotAI* ai) { return new AvoidSkadiWhirlwindAction(ai); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include "Playerbots.h"
|
||||||
|
#include "UtgardePinnacleActions.h"
|
||||||
|
#include "UtgardePinnacleStrategy.h"
|
||||||
|
|
||||||
|
bool AvoidFreezingCloudAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* closestTrigger = nullptr;
|
||||||
|
GuidVector objects = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
|
|
||||||
|
for (auto i = objects.begin(); i != objects.end(); ++i)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
|
if (unit && unit->GetEntry() == NPC_BREATH_TRIGGER)
|
||||||
|
{
|
||||||
|
if (!closestTrigger || bot->GetExactDist2d(unit) < bot->GetExactDist2d(closestTrigger))
|
||||||
|
{
|
||||||
|
closestTrigger = unit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!closestTrigger) { return false; }
|
||||||
|
|
||||||
|
float distance = bot->GetExactDist2d(closestTrigger->GetPosition());
|
||||||
|
float radius = 3.0f;
|
||||||
|
// Large buffer for this - the radius of the breath is a lot smaller than the graphic, but it looks dumb
|
||||||
|
// if the bot stands just outside the hitbox but still visibly in the cloud patches.
|
||||||
|
float distanceExtra = 3.0f;
|
||||||
|
|
||||||
|
if (distance < radius + distanceExtra - 1.0f)
|
||||||
|
{
|
||||||
|
// bot->Yell("MOVING", LANG_UNIVERSAL);
|
||||||
|
return MoveAway(closestTrigger, radius + distanceExtra - distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AvoidSkadiWhirlwindAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless");
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONUPACTIONS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONUPACTIONS_H
|
||||||
|
|
||||||
|
#include "Action.h"
|
||||||
|
#include "AttackAction.h"
|
||||||
|
#include "PlayerbotAI.h"
|
||||||
|
#include "Playerbots.h"
|
||||||
|
#include "UtgardePinnacleTriggers.h"
|
||||||
|
|
||||||
|
class AvoidFreezingCloudAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AvoidFreezingCloudAction(PlayerbotAI* ai) : MovementAction(ai, "avoid freezing cloud") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AvoidSkadiWhirlwindAction : public MovementAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AvoidSkadiWhirlwindAction(PlayerbotAI* ai) : MovementAction(ai, "avoid skadi whirlwind") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#include "UtgardePinnacleMultipliers.h"
|
||||||
|
#include "UtgardePinnacleActions.h"
|
||||||
|
#include "GenericSpellActions.h"
|
||||||
|
#include "ChooseTargetActions.h"
|
||||||
|
#include "MovementActions.h"
|
||||||
|
#include "UtgardePinnacleTriggers.h"
|
||||||
|
#include "Action.h"
|
||||||
|
|
||||||
|
float SkadiMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless");
|
||||||
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
|
Unit* bossMount = AI_VALUE2(Unit*, "find target", "grauf");
|
||||||
|
|
||||||
|
if (!bossMount)
|
||||||
|
// Actual bossfight (dismounted)
|
||||||
|
{
|
||||||
|
if (boss->HasAura(SPELL_SKADI_WHIRLWIND))
|
||||||
|
{
|
||||||
|
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidSkadiWhirlwindAction*>(action))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Bots tend to get stuck trying to attack the boss in the sky, not the adds on the ground
|
||||||
|
if (dynamic_cast<AttackAction*>(action)
|
||||||
|
&& (action->GetTarget() == boss || action->GetTarget() == bossMount))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: BELOW IS EXPERIMENTAL
|
||||||
|
// Meant to stop the jittery movement when dodging the breath.
|
||||||
|
// Currently causes issues with making the bots unresponsive and often getting the healer killed.
|
||||||
|
// Semi-glitchy movement is better than semi-afk bots, so this is commented out until it gets improved
|
||||||
|
|
||||||
|
// bool cloudActive = false;
|
||||||
|
// // Need to check two conditions here - the persistent ground effect doesn't
|
||||||
|
// // seem to be detectable until 3-5 secs in, despite it dealing damage.
|
||||||
|
// // The initial breath triggers straight away but once it's over, the bots will run back on
|
||||||
|
// // to the frezzing cloud and take damage.
|
||||||
|
// // Therefore check both conditions and trigger on either.
|
||||||
|
|
||||||
|
// // Check this one early, if true then we don't need to iterate over any objects
|
||||||
|
// if (bossMount->HasAura(SPELL_FREEZING_CLOUD_BREATH))
|
||||||
|
// {
|
||||||
|
// cloudActive = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Otherwise, check for persistent ground objects emitting the freezing cloud
|
||||||
|
// GuidVector objects = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
|
// for (auto i = objects.begin(); i != objects.end(); ++i)
|
||||||
|
// {
|
||||||
|
// Unit* unit = botAI->GetUnit(*i);
|
||||||
|
// if (unit && unit->GetEntry() == NPC_BREATH_TRIGGER)
|
||||||
|
// {
|
||||||
|
// Unit::AuraApplicationMap const& Auras = unit->GetAppliedAuras();
|
||||||
|
// for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
|
||||||
|
// {
|
||||||
|
// Aura* aura = itr->second->GetBase();
|
||||||
|
// if (aura && aura->GetId() == SPELL_FREEZING_CLOUD)
|
||||||
|
// {
|
||||||
|
// cloudActive = true;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (cloudActive)
|
||||||
|
// {
|
||||||
|
// if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidFreezingCloudAction*>(action))
|
||||||
|
// {
|
||||||
|
// return 0.0f;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONUPMULTIPLIERS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONUPMULTIPLIERS_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
|
||||||
|
class SkadiMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SkadiMultiplier(PlayerbotAI* ai) : Multiplier(ai, "skadi the ruthless") {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include "UtgardePinnacleStrategy.h"
|
||||||
|
#include "UtgardePinnacleMultipliers.h"
|
||||||
|
|
||||||
|
|
||||||
|
void WotlkDungeonUPStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||||
|
{
|
||||||
|
// Svala Sorrowgrave
|
||||||
|
|
||||||
|
// Gortok Palehoof
|
||||||
|
|
||||||
|
// Skadi the Ruthless
|
||||||
|
// TODO: Harpoons launchable via GameObject. For now players should do them
|
||||||
|
triggers.push_back(new TriggerNode("freezing cloud",
|
||||||
|
NextAction::array(0, new NextAction("avoid freezing cloud", ACTION_RAID + 5), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("skadi whirlwind",
|
||||||
|
NextAction::array(0, new NextAction("avoid skadi whirlwind", ACTION_RAID + 4), nullptr)));
|
||||||
|
|
||||||
|
// King Ymiron
|
||||||
|
// May need to avoid orb.. unclear if the generic avoid AoE does this well
|
||||||
|
}
|
||||||
|
|
||||||
|
void WotlkDungeonUPStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||||
|
{
|
||||||
|
multipliers.push_back(new SkadiMultiplier(botAI));
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONUPSTRATEGY_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONUPSTRATEGY_H
|
||||||
|
|
||||||
|
#include "Multiplier.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "Strategy.h"
|
||||||
|
|
||||||
|
|
||||||
|
class WotlkDungeonUPStrategy : public Strategy
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonUPStrategy(PlayerbotAI* ai) : Strategy(ai) {}
|
||||||
|
virtual std::string const getName() override { return "utgarde pinnacle"; }
|
||||||
|
virtual void InitTriggers(std::vector<TriggerNode*> &triggers) override;
|
||||||
|
virtual void InitMultipliers(std::vector<Multiplier*> &multipliers) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONUPTRIGGERCONTEXT_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONUPTRIGGERCONTEXT_H
|
||||||
|
|
||||||
|
#include "NamedObjectContext.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
#include "UtgardePinnacleTriggers.h"
|
||||||
|
|
||||||
|
class WotlkDungeonUPTriggerContext : public NamedObjectContext<Trigger>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WotlkDungeonUPTriggerContext()
|
||||||
|
{
|
||||||
|
creators["freezing cloud"] = &WotlkDungeonUPTriggerContext::freezing_cloud;
|
||||||
|
creators["skadi whirlwind"] = &WotlkDungeonUPTriggerContext::whirlwind;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static Trigger* freezing_cloud(PlayerbotAI* ai) { return new SkadiFreezingCloudTrigger(ai); }
|
||||||
|
static Trigger* whirlwind(PlayerbotAI* ai) { return new SkadiWhirlwindTrigger(ai); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#include "Playerbots.h"
|
||||||
|
#include "UtgardePinnacleTriggers.h"
|
||||||
|
#include "AiObject.h"
|
||||||
|
#include "AiObjectContext.h"
|
||||||
|
|
||||||
|
bool SkadiFreezingCloudTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* bossMount = AI_VALUE2(Unit*, "find target", "grauf");
|
||||||
|
if (!bossMount) { return false; }
|
||||||
|
|
||||||
|
// Need to check two conditions here - the persistent ground effect doesn't
|
||||||
|
// seem to be detectable until 3-5 secs in, despite it dealing damage.
|
||||||
|
// The initial breath triggers straight away but once it's over, the bots will run back on
|
||||||
|
// to the frezzing cloud and take damage.
|
||||||
|
// Therefore check both conditions and trigger on either.
|
||||||
|
|
||||||
|
// Check this one first, if true then we don't need to iterate over any objects
|
||||||
|
if (bossMount->HasAura(SPELL_FREEZING_CLOUD_BREATH))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, check for persistent ground objects emitting the freezing cloud
|
||||||
|
GuidVector objects = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||||
|
for (auto i = objects.begin(); i != objects.end(); ++i)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
|
if (unit && unit->GetEntry() == NPC_BREATH_TRIGGER)
|
||||||
|
{
|
||||||
|
Unit::AuraApplicationMap const& Auras = unit->GetAppliedAuras();
|
||||||
|
for (Unit::AuraApplicationMap::const_iterator itr = Auras.begin(); itr != Auras.end(); ++itr)
|
||||||
|
{
|
||||||
|
Aura* aura = itr->second->GetBase();
|
||||||
|
if (aura && aura->GetId() == SPELL_FREEZING_CLOUD)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SkadiWhirlwindTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless");
|
||||||
|
return boss && boss->HasAura(SPELL_SKADI_WHIRLWIND);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _PLAYERBOT_WOTLKDUNGEONUPTRIGGERS_H
|
||||||
|
#define _PLAYERBOT_WOTLKDUNGEONUPTRIGGERS_H
|
||||||
|
|
||||||
|
#include "Trigger.h"
|
||||||
|
#include "PlayerbotAIConfig.h"
|
||||||
|
#include "GenericTriggers.h"
|
||||||
|
#include "DungeonStrategyUtils.h"
|
||||||
|
|
||||||
|
enum UtgardePinnacleIDs
|
||||||
|
{
|
||||||
|
// Skadi the Ruthless
|
||||||
|
SPELL_FREEZING_CLOUD_N = 47579,
|
||||||
|
SPELL_FREEZING_CLOUD_H = 60020,
|
||||||
|
SPELL_FREEZING_CLOUD_BREATH = 47592,
|
||||||
|
NPC_BREATH_TRIGGER = 28351,
|
||||||
|
SPELL_SKADI_WHIRLWIND_N = 50228,
|
||||||
|
SPELL_SKADI_WHIRLWIND_H = 59322,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPELL_FREEZING_CLOUD DUNGEON_MODE(bot, SPELL_FREEZING_CLOUD_N, SPELL_FREEZING_CLOUD_H)
|
||||||
|
#define SPELL_SKADI_WHIRLWIND DUNGEON_MODE(bot, SPELL_SKADI_WHIRLWIND_N, SPELL_SKADI_WHIRLWIND_H)
|
||||||
|
|
||||||
|
// const float SKADI_BREATH_CENTRELINE = -512.46875f;
|
||||||
|
|
||||||
|
class SkadiFreezingCloudTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SkadiFreezingCloudTrigger(PlayerbotAI* ai) : Trigger(ai, "skadi freezing cloud") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SkadiWhirlwindTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SkadiWhirlwindTrigger(PlayerbotAI* ai) : Trigger(ai, "skadi whirlwind") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,6 +20,15 @@ void NearestNpcsValue::FindUnits(std::list<Unit*>& targets)
|
|||||||
|
|
||||||
bool NearestNpcsValue::AcceptUnit(Unit* unit) { return !unit->IsHostileTo(bot) && !unit->IsPlayer(); }
|
bool NearestNpcsValue::AcceptUnit(Unit* unit) { return !unit->IsHostileTo(bot) && !unit->IsPlayer(); }
|
||||||
|
|
||||||
|
void NearestHostileNpcsValue::FindUnits(std::list<Unit*>& targets)
|
||||||
|
{
|
||||||
|
Acore::AnyUnitInObjectRangeCheck u_check(bot, range);
|
||||||
|
Acore::UnitListSearcher<Acore::AnyUnitInObjectRangeCheck> searcher(bot, targets, u_check);
|
||||||
|
Cell::VisitAllObjects(bot, searcher, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NearestHostileNpcsValue::AcceptUnit(Unit* unit) { return unit->IsHostileTo(bot) && !unit->IsPlayer(); }
|
||||||
|
|
||||||
void NearestVehiclesValue::FindUnits(std::list<Unit*>& targets)
|
void NearestVehiclesValue::FindUnits(std::list<Unit*>& targets)
|
||||||
{
|
{
|
||||||
Acore::AnyUnitInObjectRangeCheck u_check(bot, range);
|
Acore::AnyUnitInObjectRangeCheck u_check(bot, range);
|
||||||
|
|||||||
@@ -24,6 +24,19 @@ protected:
|
|||||||
bool AcceptUnit(Unit* unit) override;
|
bool AcceptUnit(Unit* unit) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NearestHostileNpcsValue : public NearestUnitsValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NearestHostileNpcsValue(PlayerbotAI* botAI, float range = sPlayerbotAIConfig->sightDistance)
|
||||||
|
: NearestUnitsValue(botAI, "nearest hostile npcs", range)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void FindUnits(std::list<Unit*>& targets) override;
|
||||||
|
bool AcceptUnit(Unit* unit) override;
|
||||||
|
};
|
||||||
|
|
||||||
class NearestVehiclesValue : public NearestUnitsValue
|
class NearestVehiclesValue : public NearestUnitsValue
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ public:
|
|||||||
creators["nearest game objects no los"] = &ValueContext::nearest_game_objects_no_los;
|
creators["nearest game objects no los"] = &ValueContext::nearest_game_objects_no_los;
|
||||||
creators["closest game objects"] = &ValueContext::closest_game_objects;
|
creators["closest game objects"] = &ValueContext::closest_game_objects;
|
||||||
creators["nearest npcs"] = &ValueContext::nearest_npcs;
|
creators["nearest npcs"] = &ValueContext::nearest_npcs;
|
||||||
|
creators["nearest hostile npcs"] = &ValueContext::nearest_hostile_npcs;
|
||||||
creators["nearest totems"] = &ValueContext::nearest_totems;
|
creators["nearest totems"] = &ValueContext::nearest_totems;
|
||||||
creators["nearest vehicles"] = &ValueContext::nearest_vehicles;
|
creators["nearest vehicles"] = &ValueContext::nearest_vehicles;
|
||||||
creators["nearest vehicles far"] = &ValueContext::nearest_vehicles_far;
|
creators["nearest vehicles far"] = &ValueContext::nearest_vehicles_far;
|
||||||
@@ -393,6 +394,7 @@ private:
|
|||||||
}
|
}
|
||||||
static UntypedValue* log_level(PlayerbotAI* botAI) { return new LogLevelValue(botAI); }
|
static UntypedValue* log_level(PlayerbotAI* botAI) { return new LogLevelValue(botAI); }
|
||||||
static UntypedValue* nearest_npcs(PlayerbotAI* botAI) { return new NearestNpcsValue(botAI); }
|
static UntypedValue* nearest_npcs(PlayerbotAI* botAI) { return new NearestNpcsValue(botAI); }
|
||||||
|
static UntypedValue* nearest_hostile_npcs(PlayerbotAI* botAI) { return new NearestHostileNpcsValue(botAI); }
|
||||||
static UntypedValue* nearest_totems(PlayerbotAI* botAI) { return new NearestTotemsValue(botAI); }
|
static UntypedValue* nearest_totems(PlayerbotAI* botAI) { return new NearestTotemsValue(botAI); }
|
||||||
static UntypedValue* nearest_vehicles(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI); }
|
static UntypedValue* nearest_vehicles(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI); }
|
||||||
static UntypedValue* nearest_vehicles_far(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI, 200.0f); }
|
static UntypedValue* nearest_vehicles_far(PlayerbotAI* botAI) { return new NearestVehiclesValue(botAI, 200.0f); }
|
||||||
|
|||||||
Reference in New Issue
Block a user