mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
@@ -12,12 +12,12 @@ bool ShatterSpreadAction::Execute(Event event)
|
|||||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||||
for (auto& member : members)
|
for (auto& member : members)
|
||||||
{
|
{
|
||||||
if (bot->GetGUID() == member)
|
Unit* unit = botAI->GetUnit(member);
|
||||||
|
if (!unit || bot->GetGUID() == member)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!closestMember ||
|
if (!closestMember || bot->GetExactDist2d(unit) < bot->GetExactDist2d(closestMember))
|
||||||
bot->GetExactDist2d(botAI->GetUnit(member)) < bot->GetExactDist2d(closestMember))
|
|
||||||
{
|
{
|
||||||
closestMember = botAI->GetUnit(member);
|
closestMember = botAI->GetUnit(member);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,4 +26,5 @@ void WotlkDungeonHoSStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
|||||||
void WotlkDungeonHoSStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
void WotlkDungeonHoSStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||||
{
|
{
|
||||||
multipliers.push_back(new KrystallusMultiplier(botAI));
|
multipliers.push_back(new KrystallusMultiplier(botAI));
|
||||||
|
multipliers.push_back(new SjonnirMultiplier(botAI));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,11 +33,12 @@ bool MoveFromWhirlwindAction::Execute(Event event)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!boss || bot->GetExactDist2d(boss->GetPosition()) > targetDist)
|
float bossDistance = bot->GetExactDist2d(boss->GetPosition());
|
||||||
|
if (!boss || bossDistance > targetDist)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return MoveAway(boss, targetDist - bot->GetExactDist2d(boss->GetPosition()));
|
return MoveAway(boss, targetDist - bossDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FirebombSpreadAction::Execute(Event event)
|
bool FirebombSpreadAction::Execute(Event event)
|
||||||
@@ -50,13 +51,16 @@ bool FirebombSpreadAction::Execute(Event event)
|
|||||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||||
for (auto& member : members)
|
for (auto& member : members)
|
||||||
{
|
{
|
||||||
if (bot->GetGUID() == member)
|
Unit* unit = botAI->GetUnit(member);
|
||||||
|
if (!unit || bot->GetGUID() == member)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (bot->GetExactDist2d(botAI->GetUnit(member)) < targetDist)
|
|
||||||
|
if (bot->GetExactDist2d(unit) < targetDist)
|
||||||
{
|
{
|
||||||
return MoveAway(botAI->GetUnit(member), targetDist);
|
float bossDistance = bot->GetExactDist2d(boss->GetPosition());
|
||||||
|
return MoveAway(unit, targetDist - bossDistance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -70,24 +74,22 @@ bool TelestraSplitTargetAction::Execute(Event event)
|
|||||||
|
|
||||||
for (auto& attacker : attackers)
|
for (auto& attacker : attackers)
|
||||||
{
|
{
|
||||||
Unit* npc = botAI->GetUnit(attacker);
|
Unit* unit = botAI->GetUnit(attacker);
|
||||||
if (!npc)
|
if (!unit) { continue; }
|
||||||
{
|
|
||||||
continue;
|
switch (unit->GetEntry())
|
||||||
}
|
|
||||||
switch (npc->GetEntry())
|
|
||||||
{
|
{
|
||||||
// Focus arcane clone first
|
// Focus arcane clone first
|
||||||
case NPC_ARCANE_MAGUS:
|
case NPC_ARCANE_MAGUS:
|
||||||
splitTargets[0] = npc;
|
splitTargets[0] = unit;
|
||||||
break;
|
break;
|
||||||
// Then the frost clone
|
// Then the frost clone
|
||||||
case NPC_FROST_MAGUS:
|
case NPC_FROST_MAGUS:
|
||||||
splitTargets[1] = npc;
|
splitTargets[1] = unit;
|
||||||
break;
|
break;
|
||||||
// Fire clone last
|
// Fire clone last
|
||||||
case NPC_FIRE_MAGUS:
|
case NPC_FIRE_MAGUS:
|
||||||
splitTargets[2] = npc;
|
splitTargets[2] = unit;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,11 +141,15 @@ bool ChaoticRiftTargetAction::Execute(Event event)
|
|||||||
bool DodgeSpikesAction::isUseful()
|
bool DodgeSpikesAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ormorok the tree-shaper");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ormorok the tree-shaper");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
return bot->GetExactDist2d(boss) > 0.5f;
|
return bot->GetExactDist2d(boss) > 0.5f;
|
||||||
}
|
}
|
||||||
bool DodgeSpikesAction::Execute(Event event)
|
bool DodgeSpikesAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ormorok the tree-shaper");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ormorok the tree-shaper");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
return Move(bot->GetAngle(boss), bot->GetExactDist2d(boss) - 0.3f);
|
return Move(bot->GetAngle(boss), bot->GetExactDist2d(boss) - 0.3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,22 +7,6 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "NexusTriggers.h"
|
#include "NexusTriggers.h"
|
||||||
|
|
||||||
#define ANGLE_45_DEG (static_cast<float>(M_PI) / 4.f)
|
|
||||||
#define ANGLE_90_DEG M_PI_2
|
|
||||||
#define ANGLE_120_DEG (2.f * static_cast<float>(M_PI) / 3.f)
|
|
||||||
|
|
||||||
// Slice of the circle that we want melee dps to attack from.
|
|
||||||
// Measured from boss orientation, on one side.
|
|
||||||
|
|
||||||
// Even though the breath cone is not the full 180 degrees,
|
|
||||||
// avoid melee dps from the front due to parry potential.
|
|
||||||
// Bots should learn good dps etiquette :)
|
|
||||||
#define DRAGON_MELEE_MIN_ANGLE ANGLE_90_DEG
|
|
||||||
// This leaves a danger zone of 60 degrees at the tail end on both sides.
|
|
||||||
// This is a total of 120 degrees tail arc that bots will avoid -
|
|
||||||
// number just happens to be the same in this case, but this is always measured from the front.
|
|
||||||
#define DRAGON_MELEE_MAX_ANGLE ANGLE_120_DEG
|
|
||||||
|
|
||||||
class MoveFromWhirlwindAction : public MovementAction
|
class MoveFromWhirlwindAction : public MovementAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -77,10 +77,8 @@ float AnomalusMultiplier::GetValue(Action* action)
|
|||||||
float OrmorokMultiplier::GetValue(Action* action)
|
float OrmorokMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ormorok the tree-shaper");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ormorok the tree-shaper");
|
||||||
if (!boss)
|
if (!boss) { return 1.0f; }
|
||||||
{
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
// These are used for auto ranged repositioning, need to suppress so ranged dps don't ping-pong
|
// These are used for auto ranged repositioning, need to suppress so ranged dps don't ping-pong
|
||||||
if (dynamic_cast<FleeAction*>(action))
|
if (dynamic_cast<FleeAction*>(action))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,13 +39,4 @@ class OrmorokMultiplier : public Multiplier
|
|||||||
virtual float GetValue(Action* action);
|
virtual float GetValue(Action* action);
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeristraszaMultiplier : public Multiplier
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
KeristraszaMultiplier(PlayerbotAI* ai) : Multiplier(ai, "keristrasza") {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual float GetValue(Action* action);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -50,5 +50,4 @@ void WotlkDungeonNexStrategy::InitMultipliers(std::vector<Multiplier*> &multipli
|
|||||||
multipliers.push_back(new TelestraMultiplier(botAI));
|
multipliers.push_back(new TelestraMultiplier(botAI));
|
||||||
multipliers.push_back(new AnomalusMultiplier(botAI));
|
multipliers.push_back(new AnomalusMultiplier(botAI));
|
||||||
multipliers.push_back(new OrmorokMultiplier(botAI));
|
multipliers.push_back(new OrmorokMultiplier(botAI));
|
||||||
// multipliers.push_back(new KeristraszaMultiplier(botAI));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,22 +42,22 @@ bool AvoidShadowCrashAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
// Could check all enemy units in range as it's possible to pull multiple of these mobs.
|
// 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
|
// 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* unit = AI_VALUE2(Unit*, "find target", "forgotten one");
|
||||||
Unit* victim = nullptr;
|
Unit* victim = nullptr;
|
||||||
float radius = 10.0f;
|
float radius = 10.0f;
|
||||||
float targetDist = radius + 2.0f;
|
float targetDist = radius + 2.0f;
|
||||||
if (!npc) { return false; }
|
if (!unit) { return false; }
|
||||||
|
|
||||||
// Actively move if targeted by a shadow crash.
|
// Actively move if targeted by a shadow crash.
|
||||||
// Spell check not needed, they don't have any other non-instant casts
|
// Spell check not needed, they don't have any other non-instant casts
|
||||||
if (npc->HasUnitState(UNIT_STATE_CASTING)) // && npc->FindCurrentSpellBySpellId(SPELL_SHADOW_CRASH))
|
if (unit->HasUnitState(UNIT_STATE_CASTING)) // && unit->FindCurrentSpellBySpellId(SPELL_SHADOW_CRASH))
|
||||||
{
|
{
|
||||||
// This doesn't seem to avoid casts very well, perhaps because this isn't checked while allies are casting.
|
// 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.
|
// TODO: Revisit if this is an issue in heroics, otherwise ignore shadow crashes for the most part.
|
||||||
victim = botAI->GetUnit(npc->GetTarget());
|
victim = botAI->GetUnit(unit->GetTarget());
|
||||||
if (victim && bot->GetExactDist2d(victim) < radius)
|
if (victim && bot->GetExactDist2d(victim) < radius)
|
||||||
{
|
{
|
||||||
return MoveAway(victim, targetDist - bot->GetExactDist2d(victim));
|
return MoveAway(victim, targetDist - bot->GetExactDist2d(victim->GetPosition()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,10 @@
|
|||||||
float ElderNadoxMultiplier::GetValue(Action* action)
|
float ElderNadoxMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "elder nadox");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "elder nadox");
|
||||||
Unit* guardian = AI_VALUE2(Unit*, "find target", "ahn'kahar guardian");
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
if (boss && guardian)
|
Unit* guardian = AI_VALUE2(Unit*, "find target", "ahn'kahar guardian");
|
||||||
|
if (guardian)
|
||||||
{
|
{
|
||||||
if (dynamic_cast<DpsAssistAction*>(action))
|
if (dynamic_cast<DpsAssistAction*>(action))
|
||||||
{
|
{
|
||||||
@@ -24,7 +25,7 @@ float ElderNadoxMultiplier::GetValue(Action* action)
|
|||||||
float JedogaShadowseekerMultiplier::GetValue(Action* action)
|
float JedogaShadowseekerMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "jedoga shadowseeker");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "jedoga shadowseeker");
|
||||||
// Unit* volunteer = AI_VALUE2(Unit*, "find target", "twilight volunteer");
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
Unit* volunteer = nullptr;
|
Unit* volunteer = nullptr;
|
||||||
// Target is not findable from threat table using AI_VALUE2(),
|
// Target is not findable from threat table using AI_VALUE2(),
|
||||||
@@ -41,7 +42,7 @@ float JedogaShadowseekerMultiplier::GetValue(Action* action)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boss && volunteer)
|
if (volunteer)
|
||||||
{
|
{
|
||||||
if (dynamic_cast<DpsAssistAction*>(action))
|
if (dynamic_cast<DpsAssistAction*>(action))
|
||||||
{
|
{
|
||||||
@@ -53,9 +54,10 @@ float JedogaShadowseekerMultiplier::GetValue(Action* action)
|
|||||||
|
|
||||||
float ForgottenOneMultiplier::GetValue(Action* action)
|
float ForgottenOneMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
Unit* npc = AI_VALUE2(Unit*, "find target", "forgotten one");
|
Unit* unit = AI_VALUE2(Unit*, "find target", "forgotten one");
|
||||||
|
if (!unit) { return 1.0f; }
|
||||||
|
|
||||||
if (npc && bot->isMoving())
|
if (bot->isMoving())
|
||||||
{
|
{
|
||||||
if (dynamic_cast<MovementAction*>(action))
|
if (dynamic_cast<MovementAction*>(action))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ bool NadoxGuardianTrigger::IsActive()
|
|||||||
bool JedogaVolunteerTrigger::IsActive()
|
bool JedogaVolunteerTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "jedoga shadowseeker");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "jedoga shadowseeker");
|
||||||
// Unit* volunteer = AI_VALUE2(Unit*, "find target", "twilight volunteer");
|
if (!boss) { return false; }
|
||||||
Unit* volunteer = nullptr;
|
|
||||||
// Target is not findable from threat table using AI_VALUE2(),
|
// Volunteer is not findable from threat table using AI_VALUE2(),
|
||||||
// therefore need to search manually for the unit name
|
// therefore need to search manually for the unit name
|
||||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||||
|
|
||||||
@@ -28,16 +28,16 @@ bool JedogaVolunteerTrigger::IsActive()
|
|||||||
Unit* unit = botAI->GetUnit(*i);
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
if (unit && unit->GetEntry() == NPC_TWILIGHT_VOLUNTEER)
|
if (unit && unit->GetEntry() == NPC_TWILIGHT_VOLUNTEER)
|
||||||
{
|
{
|
||||||
volunteer = unit;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
return boss && volunteer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShadowCrashTrigger::IsActive()
|
bool ShadowCrashTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (botAI->IsMelee(bot)) { return false; }
|
Unit* unit = AI_VALUE2(Unit*, "find target", "forgotten one");
|
||||||
return !botAI->IsMelee(bot) && AI_VALUE2(Unit*, "find target", "forgotten one");
|
if (!unit) { return false; }
|
||||||
|
|
||||||
|
return !botAI->IsMelee(bot);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ bool AttackFrostTombAction::Execute(Event event)
|
|||||||
for (auto i = targets.begin(); i != targets.end(); ++i)
|
for (auto i = targets.begin(); i != targets.end(); ++i)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(*i);
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
if (unit && unit->GetName() == "Frost Tomb")
|
if (unit && unit->GetEntry() == NPC_FROST_TOMB)
|
||||||
{
|
{
|
||||||
frostTomb = unit;
|
frostTomb = unit;
|
||||||
break;
|
break;
|
||||||
@@ -31,7 +31,9 @@ bool AttackFrostTombAction::Execute(Event event)
|
|||||||
bool AttackDalronnAction::Execute(Event event)
|
bool AttackDalronnAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
||||||
if (!boss || AI_VALUE(Unit*, "current target") == boss)
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
if (AI_VALUE(Unit*, "current target") == boss)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -42,10 +44,7 @@ bool IngvarStopCastingAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
// Doesn't work, this action gets queued behind the current spell instead of interrupting it
|
// 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");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss)
|
if (!boss) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 my_spell_id = AI_VALUE(uint32, "active spell");
|
int32 my_spell_id = AI_VALUE(uint32, "active spell");
|
||||||
if (!my_spell_id || my_spell_id == 0)
|
if (!my_spell_id || my_spell_id == 0)
|
||||||
@@ -54,10 +53,7 @@ bool IngvarStopCastingAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Spell* spell = bot->FindCurrentSpellBySpellId(my_spell_id);
|
Spell* spell = bot->FindCurrentSpellBySpellId(my_spell_id);
|
||||||
if (!spell)
|
if (!spell) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bot->Yell("cancelling spell="+std::to_string(my_spell_id), LANG_UNIVERSAL);
|
// bot->Yell("cancelling spell="+std::to_string(my_spell_id), LANG_UNIVERSAL);
|
||||||
bot->InterruptSpell(spell->GetCurrentContainer(), false, true, true);
|
bot->InterruptSpell(spell->GetCurrentContainer(), false, true, true);
|
||||||
@@ -71,10 +67,7 @@ bool IngvarDodgeSmashAction::isUseful() { return !AI_VALUE2(bool, "behind", "cur
|
|||||||
bool IngvarDodgeSmashAction::Execute(Event event)
|
bool IngvarDodgeSmashAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss)
|
if (!boss) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance = bot->GetExactDist2d(boss->GetPosition());
|
float distance = bot->GetExactDist2d(boss->GetPosition());
|
||||||
// Extra units to move into the boss, instead of being just 1 pixel past his midpoint.
|
// Extra units to move into the boss, instead of being just 1 pixel past his midpoint.
|
||||||
@@ -88,10 +81,7 @@ bool IngvarSmashReturnAction::isUseful() { return AI_VALUE2(bool, "behind", "cur
|
|||||||
bool IngvarSmashReturnAction::Execute(Event event)
|
bool IngvarSmashReturnAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss)
|
if (!boss) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance = bot->GetExactDist2d(boss->GetPosition());
|
float distance = bot->GetExactDist2d(boss->GetPosition());
|
||||||
return Move(bot->GetAngle(boss), distance + bot->GetMeleeReach());
|
return Move(bot->GetAngle(boss), distance + bot->GetMeleeReach());
|
||||||
|
|||||||
@@ -7,10 +7,8 @@
|
|||||||
float PrinceKelesethMultiplier::GetValue(Action* action)
|
float PrinceKelesethMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "prince keleseth");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "prince keleseth");
|
||||||
if (!boss)
|
if (!boss) { return 1.0f; }
|
||||||
{
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
if (dynamic_cast<DpsAssistAction*>(action))
|
if (dynamic_cast<DpsAssistAction*>(action))
|
||||||
{
|
{
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
@@ -20,13 +18,9 @@ float PrinceKelesethMultiplier::GetValue(Action* action)
|
|||||||
|
|
||||||
float SkarvaldAndDalronnMultiplier::GetValue(Action* action)
|
float SkarvaldAndDalronnMultiplier::GetValue(Action* action)
|
||||||
{
|
{
|
||||||
// Unit* skarvald = AI_VALUE2(Unit*, "find target", "skarvald the constructor");
|
// Only need to deal with Dalronn here. If he's dead, just fall back to normal dps strat
|
||||||
Unit* dalronn = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
||||||
|
if (!boss) { return 1.0f; }
|
||||||
if (!dalronn)
|
|
||||||
{
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dynamic_cast<DpsAssistAction*>(action))
|
if (dynamic_cast<DpsAssistAction*>(action))
|
||||||
{
|
{
|
||||||
@@ -39,10 +33,7 @@ float IngvarThePlundererMultiplier::GetValue(Action* action)
|
|||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
bool isTank = botAI->IsTank(bot);
|
bool isTank = botAI->IsTank(bot);
|
||||||
if (!boss)
|
if (!boss) { return 1.0f; }
|
||||||
{
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prevent movement actions overriding current movement, we're probably dodging a slam
|
// Prevent movement actions overriding current movement, we're probably dodging a slam
|
||||||
if (isTank && bot->isMoving() && dynamic_cast<MovementAction*>(action))
|
if (isTank && bot->isMoving() && dynamic_cast<MovementAction*>(action))
|
||||||
@@ -60,10 +51,7 @@ float IngvarThePlundererMultiplier::GetValue(Action* action)
|
|||||||
{
|
{
|
||||||
uint32 spellId = AI_VALUE2(uint32, "spell id", action->getName());
|
uint32 spellId = AI_VALUE2(uint32, "spell id", action->getName());
|
||||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||||
if (!spellInfo)
|
if (!spellInfo) { return 1.0f; }
|
||||||
{
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 castTime = spellInfo->CalcCastTime(bot);
|
uint32 castTime = spellInfo->CalcCastTime(bot);
|
||||||
if (castTime != 0)
|
if (castTime != 0)
|
||||||
@@ -73,10 +61,8 @@ float IngvarThePlundererMultiplier::GetValue(Action* action)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Done with non-tank logic
|
// Done with non-tank logic
|
||||||
if (!isTank)
|
if (!isTank) { return 1.0f; }
|
||||||
{
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
// TANK ONLY
|
// TANK ONLY
|
||||||
if (boss->FindCurrentSpellBySpellId(SPELL_SMASH) ||
|
if (boss->FindCurrentSpellBySpellId(SPELL_SMASH) ||
|
||||||
boss->FindCurrentSpellBySpellId(SPELL_DARK_SMASH))
|
boss->FindCurrentSpellBySpellId(SPELL_DARK_SMASH))
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ bool KelesethFrostTombTrigger::IsActive()
|
|||||||
for (auto& member : members)
|
for (auto& member : members)
|
||||||
{
|
{
|
||||||
Unit* unit = botAI->GetUnit(member);
|
Unit* unit = botAI->GetUnit(member);
|
||||||
if (unit && unit->HasAura(DEBUFF_FROST_TOMB))
|
if (unit && unit->HasAura(SPELL_FROST_TOMB))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -19,21 +19,17 @@ bool KelesethFrostTombTrigger::IsActive()
|
|||||||
|
|
||||||
bool DalronnNontankTrigger::IsActive()
|
bool DalronnNontankTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* dalronn = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "dalronn the controller");
|
||||||
if (!dalronn)
|
if (!boss) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !botAI->IsTank(bot);
|
return !botAI->IsTank(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IngvarStaggeringRoarTrigger::IsActive()
|
bool IngvarStaggeringRoarTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss)
|
if (!boss) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
||||||
{
|
{
|
||||||
if (boss->FindCurrentSpellBySpellId(SPELL_STAGGERING_ROAR))
|
if (boss->FindCurrentSpellBySpellId(SPELL_STAGGERING_ROAR))
|
||||||
@@ -47,16 +43,12 @@ bool IngvarStaggeringRoarTrigger::IsActive()
|
|||||||
bool IngvarDreadfulRoarTrigger::IsActive()
|
bool IngvarDreadfulRoarTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss)
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
if (boss->HasUnitState(UNIT_STATE_CASTING) &&
|
||||||
|
boss->FindCurrentSpellBySpellId(SPELL_DREADFUL_ROAR))
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
|
||||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
|
||||||
{
|
|
||||||
if (boss->FindCurrentSpellBySpellId(SPELL_DREADFUL_ROAR))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -64,10 +56,7 @@ bool IngvarDreadfulRoarTrigger::IsActive()
|
|||||||
bool IngvarSmashTankTrigger::IsActive()
|
bool IngvarSmashTankTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss || !botAI->IsTank(bot))
|
if (!boss || !botAI->IsTank(bot)) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
if (boss->HasUnitState(UNIT_STATE_CASTING))
|
||||||
{
|
{
|
||||||
@@ -86,20 +75,15 @@ bool IngvarSmashTankReturnTrigger::IsActive()
|
|||||||
// if (!boss || !botAI->IsTank(bot) || boss->HasUnitState(UNIT_STATE_CASTING))
|
// if (!boss || !botAI->IsTank(bot) || boss->HasUnitState(UNIT_STATE_CASTING))
|
||||||
// Ignore casting state as Ingvar will sometimes chain-cast a roar after a smash..
|
// Ignore casting state as Ingvar will sometimes chain-cast a roar after a smash..
|
||||||
// We don't want this to prevent our tank from repositioning properly.
|
// We don't want this to prevent our tank from repositioning properly.
|
||||||
if (!boss || !botAI->IsTank(bot))
|
if (!boss || !botAI->IsTank(bot)) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NotBehindIngvarTrigger::IsActive()
|
bool NotBehindIngvarTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ingvar the plunderer");
|
||||||
if (!boss || botAI->IsTank(bot))
|
if (!boss || botAI->IsTank(bot)) { return false; }
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return AI_VALUE2(bool, "behind", "current target");
|
return AI_VALUE2(bool, "behind", "current target");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ bool AttackErekemAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
// Focus boss first, adds after
|
// Focus boss first, adds after
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "erekem");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "erekem");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
if (AI_VALUE(Unit*, "current target") != boss)
|
if (AI_VALUE(Unit*, "current target") != boss)
|
||||||
{
|
{
|
||||||
return Attack(boss);
|
return Attack(boss);
|
||||||
@@ -19,6 +21,8 @@ bool AttackIchorGlobuleAction::Execute(Event event)
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "ichoron");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ichoron");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||||
|
|
||||||
// Tank prioritise boss if it's up
|
// Tank prioritise boss if it's up
|
||||||
if (botAI->IsTank(bot) && !boss->HasAura(SPELL_DRAINED))
|
if (botAI->IsTank(bot) && !boss->HasAura(SPELL_DRAINED))
|
||||||
{
|
{
|
||||||
@@ -38,7 +42,6 @@ bool AttackIchorGlobuleAction::Execute(Event event)
|
|||||||
Unit* unit = botAI->GetUnit(*i);
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
if (unit && unit->GetEntry() == NPC_ICHOR_GLOBULE)
|
if (unit && unit->GetEntry() == NPC_ICHOR_GLOBULE)
|
||||||
{
|
{
|
||||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
|
||||||
// Check IDs here, NOT Unit* pointers:
|
// Check IDs here, NOT Unit* pointers:
|
||||||
// Don't keep swapping between sentries.
|
// Don't keep swapping between sentries.
|
||||||
// If we're already attacking one, don't retarget another
|
// If we're already attacking one, don't retarget another
|
||||||
@@ -50,7 +53,7 @@ bool AttackIchorGlobuleAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No ichor globules left alive, fall back to targeting boss
|
// No ichor globules left alive, fall back to targeting boss
|
||||||
if (AI_VALUE(Unit*, "current target") != boss)
|
if (currentTarget != boss)
|
||||||
{
|
{
|
||||||
return Attack(boss);
|
return Attack(boss);
|
||||||
}
|
}
|
||||||
@@ -62,6 +65,8 @@ bool AttackVoidSentryAction::Execute(Event event)
|
|||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "zuramat the obliterator");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "zuramat the obliterator");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||||
|
|
||||||
// Target is not findable from threat table using AI_VALUE2(),
|
// Target is not findable from threat table using AI_VALUE2(),
|
||||||
// therefore need to search manually for the unit name
|
// therefore need to search manually for the unit name
|
||||||
@@ -73,7 +78,6 @@ bool AttackVoidSentryAction::Execute(Event event)
|
|||||||
Unit* unit = botAI->GetUnit(*i);
|
Unit* unit = botAI->GetUnit(*i);
|
||||||
if (unit && unit->GetEntry() == NPC_VOID_SENTRY)
|
if (unit && unit->GetEntry() == NPC_VOID_SENTRY)
|
||||||
{
|
{
|
||||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
|
||||||
// Check IDs here, NOT Unit* pointers:
|
// Check IDs here, NOT Unit* pointers:
|
||||||
// Don't keep swapping between sentries.
|
// Don't keep swapping between sentries.
|
||||||
// If we're already attacking one, don't retarget another
|
// If we're already attacking one, don't retarget another
|
||||||
@@ -85,7 +89,7 @@ bool AttackVoidSentryAction::Execute(Event event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No void sentries left alive, fall back to targeting boss
|
// No void sentries left alive, fall back to targeting boss
|
||||||
if (AI_VALUE(Unit*, "current target") != boss)
|
if (currentTarget != boss)
|
||||||
{
|
{
|
||||||
return Attack(boss);
|
return Attack(boss);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "VioletHoldTriggers.h"
|
#include "VioletHoldTriggers.h"
|
||||||
|
|
||||||
// const Position NOVOS_PARTY_POSITION = Position(-378.852f, -760.349f, 28.587f);
|
|
||||||
|
|
||||||
class AttackErekemAction : public AttackAction
|
class AttackErekemAction : public AttackAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -6,30 +6,42 @@
|
|||||||
|
|
||||||
bool ErekemTargetTrigger::IsActive()
|
bool ErekemTargetTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return AI_VALUE2(Unit*, "find target", "erekem") && botAI->IsDps(bot);
|
Unit* boss = AI_VALUE2(Unit*, "find target", "erekem");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
return botAI->IsDps(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IchoronTargetTrigger::IsActive()
|
bool IchoronTargetTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return AI_VALUE2(Unit*, "find target", "ichoron") && !botAI->IsHeal(bot);
|
Unit* boss = AI_VALUE2(Unit*, "find target", "ichoron");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
return !botAI->IsHeal(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoidShiftTrigger::IsActive()
|
bool VoidShiftTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "zuramat the obliterator");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "zuramat the obliterator");
|
||||||
return boss && bot->HasAura(SPELL_VOID_SHIFTED) && !botAI->IsHeal(bot);
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
return bot->HasAura(SPELL_VOID_SHIFTED) && !botAI->IsHeal(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShroudOfDarknessTrigger::IsActive()
|
bool ShroudOfDarknessTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "zuramat the obliterator");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "zuramat the obliterator");
|
||||||
return boss && boss->HasAura(SPELL_SHROUD_OF_DARKNESS);
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
return boss->HasAura(SPELL_SHROUD_OF_DARKNESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CyanigosaPositioningTrigger::IsActive()
|
bool CyanigosaPositioningTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "cyanigosa");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "cyanigosa");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
// Include healers here for now, otherwise they stand in things
|
// Include healers here for now, otherwise they stand in things
|
||||||
return boss && !botAI->IsTank(bot) && !botAI->IsRangedDps(bot);
|
return !botAI->IsTank(bot) && !botAI->IsRangedDps(bot);
|
||||||
// return boss && botAI->IsMelee(bot) && !botAI->IsTank(bot);
|
// return botAI->IsMelee(bot) && !botAI->IsTank(bot);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user