mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #700 from Bobblybook/master
Dungeon strat improvements (GD & UP)
This commit is contained in:
@@ -10,10 +10,12 @@ class WotlkDungeonGDActionContext : public NamedObjectContext<Action>
|
|||||||
public:
|
public:
|
||||||
WotlkDungeonGDActionContext() {
|
WotlkDungeonGDActionContext() {
|
||||||
creators["avoid poison nova"] = &WotlkDungeonGDActionContext::avoid_poison_nova;
|
creators["avoid poison nova"] = &WotlkDungeonGDActionContext::avoid_poison_nova;
|
||||||
|
creators["attack snake wrap"] = &WotlkDungeonGDActionContext::attack_snake_wrap;
|
||||||
creators["avoid whirling slash"] = &WotlkDungeonGDActionContext::avoid_whirling_slash;
|
creators["avoid whirling slash"] = &WotlkDungeonGDActionContext::avoid_whirling_slash;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static Action* avoid_poison_nova(PlayerbotAI* ai) { return new AvoidPoisonNovaAction(ai); }
|
static Action* avoid_poison_nova(PlayerbotAI* ai) { return new AvoidPoisonNovaAction(ai); }
|
||||||
|
static Action* attack_snake_wrap(PlayerbotAI* ai) { return new AttackSnakeWrapAction(ai); }
|
||||||
static Action* avoid_whirling_slash(PlayerbotAI* ai) { return new AvoidWhirlingSlashAction(ai); }
|
static Action* avoid_whirling_slash(PlayerbotAI* ai) { return new AvoidWhirlingSlashAction(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,32 @@ bool AvoidPoisonNovaAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AttackSnakeWrapAction::Execute(Event event)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
Unit* snakeWrap = 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& target : targets)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(target);
|
||||||
|
if (unit && unit->GetEntry() == NPC_SNAKE_WRAP)
|
||||||
|
{
|
||||||
|
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||||
|
if (!currentTarget || currentTarget->GetEntry() != NPC_SNAKE_WRAP)
|
||||||
|
{
|
||||||
|
return Attack(unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool AvoidWhirlingSlashAction::Execute(Event event)
|
bool AvoidWhirlingSlashAction::Execute(Event event)
|
||||||
{
|
{
|
||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "gal'darah");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "gal'darah");
|
||||||
|
|||||||
@@ -14,6 +14,13 @@ public:
|
|||||||
bool Execute(Event event) override;
|
bool Execute(Event event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AttackSnakeWrapAction : public AttackAction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AttackSnakeWrapAction(PlayerbotAI* ai) : AttackAction(ai, "attack snake wrap") {}
|
||||||
|
bool Execute(Event event) override;
|
||||||
|
};
|
||||||
|
|
||||||
class AvoidWhirlingSlashAction : public MovementAction
|
class AvoidWhirlingSlashAction : public MovementAction
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -11,13 +11,38 @@ float SladranMultiplier::GetValue(Action* action)
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
||||||
if (!boss) { return 1.0f; }
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA))
|
if (boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA))
|
||||||
|
{
|
||||||
|
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidPoisonNovaAction*>(action))
|
||||||
{
|
{
|
||||||
if (dynamic_cast<MovementAction*>(action) && !dynamic_cast<AvoidPoisonNovaAction*>(action))
|
return 0.0f;
|
||||||
{
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!botAI->IsDps(bot)) { return 1.0f; }
|
||||||
|
|
||||||
|
if (action->getThreatType() == Action::ActionThreatType::Aoe)
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit* snakeWrap = nullptr;
|
||||||
|
GuidVector targets = AI_VALUE(GuidVector, "possible targets no los");
|
||||||
|
for (auto& target : targets)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(target);
|
||||||
|
if (unit && unit->GetEntry() == NPC_SNAKE_WRAP)
|
||||||
|
{
|
||||||
|
snakeWrap = unit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Prevent auto-target acquisition during snake wraps
|
||||||
|
if (snakeWrap && dynamic_cast<DpsAssistAction*>(action))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,14 @@ void WotlkDungeonGDStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
|||||||
// Will re-test in heroic, decent dps groups should be able to blast him down with no funky strats.
|
// Will re-test in heroic, decent dps groups should be able to blast him down with no funky strats.
|
||||||
triggers.push_back(new TriggerNode("poison nova",
|
triggers.push_back(new TriggerNode("poison nova",
|
||||||
NextAction::array(0, new NextAction("avoid poison nova", ACTION_RAID + 5), nullptr)));
|
NextAction::array(0, new NextAction("avoid poison nova", ACTION_RAID + 5), nullptr)));
|
||||||
|
triggers.push_back(new TriggerNode("snake wrap",
|
||||||
|
NextAction::array(0, new NextAction("attack snake wrap", ACTION_RAID + 4), nullptr)));
|
||||||
|
|
||||||
// Gal'darah
|
// Gal'darah
|
||||||
triggers.push_back(new TriggerNode("whirling slash",
|
triggers.push_back(new TriggerNode("whirling slash",
|
||||||
NextAction::array(0, new NextAction("avoid whirling slash", ACTION_RAID + 5), nullptr)));
|
NextAction::array(0, new NextAction("avoid whirling slash", ACTION_RAID + 5), nullptr)));
|
||||||
|
|
||||||
// Eck the Ferocious (Heroic only)
|
// Eck the Ferocious (Heroic only)
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WotlkDungeonGDStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
void WotlkDungeonGDStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ class WotlkDungeonGDTriggerContext : public NamedObjectContext<Trigger>
|
|||||||
WotlkDungeonGDTriggerContext()
|
WotlkDungeonGDTriggerContext()
|
||||||
{
|
{
|
||||||
creators["poison nova"] = &WotlkDungeonGDTriggerContext::poison_nova;
|
creators["poison nova"] = &WotlkDungeonGDTriggerContext::poison_nova;
|
||||||
|
creators["snake wrap"] = &WotlkDungeonGDTriggerContext::snake_wrap;
|
||||||
creators["whirling slash"] = &WotlkDungeonGDTriggerContext::whirling_slash;
|
creators["whirling slash"] = &WotlkDungeonGDTriggerContext::whirling_slash;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static Trigger* poison_nova(PlayerbotAI* ai) { return new SladranPoisonNovaTrigger(ai); }
|
static Trigger* poison_nova(PlayerbotAI* ai) { return new SladranPoisonNovaTrigger(ai); }
|
||||||
|
static Trigger* snake_wrap(PlayerbotAI* ai) { return new SladranSnakeWrapTrigger(ai); }
|
||||||
static Trigger* whirling_slash(PlayerbotAI* ai) { return new GaldarahWhirlingSlashTrigger(ai); }
|
static Trigger* whirling_slash(PlayerbotAI* ai) { return new GaldarahWhirlingSlashTrigger(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,26 @@ bool SladranPoisonNovaTrigger::IsActive()
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
||||||
if (!boss) { return false; }
|
if (!boss) { return false; }
|
||||||
|
|
||||||
return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA);
|
return bool(boss->FindCurrentSpellBySpellId(SPELL_POISON_NOVA));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SladranSnakeWrapTrigger::IsActive()
|
||||||
|
{
|
||||||
|
if (!botAI->IsDps(bot)) { return false; }
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
|
||||||
|
for (auto& target : targets)
|
||||||
|
{
|
||||||
|
Unit* unit = botAI->GetUnit(target);
|
||||||
|
if (unit && unit->GetEntry() == NPC_SNAKE_WRAP)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GaldarahWhirlingSlashTrigger::IsActive()
|
bool GaldarahWhirlingSlashTrigger::IsActive()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ enum GundrakIDs
|
|||||||
// Slad'ran
|
// Slad'ran
|
||||||
SPELL_POISON_NOVA_N = 55081,
|
SPELL_POISON_NOVA_N = 55081,
|
||||||
SPELL_POISON_NOVA_H = 59842,
|
SPELL_POISON_NOVA_H = 59842,
|
||||||
|
NPC_SNAKE_WRAP = 29742,
|
||||||
|
|
||||||
// Gal'darah
|
// Gal'darah
|
||||||
SPELL_WHIRLING_SLASH_N = 55250,
|
SPELL_WHIRLING_SLASH_N = 55250,
|
||||||
@@ -27,6 +28,13 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SladranSnakeWrapTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SladranSnakeWrapTrigger(PlayerbotAI* ai) : Trigger(ai, "slad'ran snake wrap") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
class GaldarahWhirlingSlashTrigger : public Trigger
|
class GaldarahWhirlingSlashTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ class WotlkDungeonUPActionContext : public NamedObjectContext<Action>
|
|||||||
WotlkDungeonUPActionContext() {
|
WotlkDungeonUPActionContext() {
|
||||||
creators["avoid freezing cloud"] = &WotlkDungeonUPActionContext::avoid_freezing_cloud;
|
creators["avoid freezing cloud"] = &WotlkDungeonUPActionContext::avoid_freezing_cloud;
|
||||||
creators["avoid skadi whirlwind"] = &WotlkDungeonUPActionContext::avoid_whirlwind;
|
creators["avoid skadi whirlwind"] = &WotlkDungeonUPActionContext::avoid_whirlwind;
|
||||||
|
creators["stop attack"] = &WotlkDungeonUPActionContext::stop_attack;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static Action* avoid_freezing_cloud(PlayerbotAI* ai) { return new AvoidFreezingCloudAction(ai); }
|
static Action* avoid_freezing_cloud(PlayerbotAI* ai) { return new AvoidFreezingCloudAction(ai); }
|
||||||
static Action* avoid_whirlwind(PlayerbotAI* ai) { return new AvoidSkadiWhirlwindAction(ai); }
|
static Action* avoid_whirlwind(PlayerbotAI* ai) { return new AvoidSkadiWhirlwindAction(ai); }
|
||||||
|
static Action* stop_attack(PlayerbotAI* ai) { return new DropTargetAction(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -82,3 +82,18 @@ float SkadiMultiplier::GetValue(Action* action)
|
|||||||
|
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float YmironMultiplier::GetValue(Action* action)
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "king ymiron");
|
||||||
|
if (!boss) { return 1.0f; }
|
||||||
|
|
||||||
|
if (boss->FindCurrentSpellBySpellId(SPELL_BANE) || boss->HasAura(SPELL_BANE))
|
||||||
|
{
|
||||||
|
if (dynamic_cast<AttackAction*>(action))
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
@@ -12,4 +12,13 @@ class SkadiMultiplier : public Multiplier
|
|||||||
virtual float GetValue(Action* action);
|
virtual float GetValue(Action* action);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class YmironMultiplier : public Multiplier
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
YmironMultiplier(PlayerbotAI* ai) : Multiplier(ai, "king ymiron") {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual float GetValue(Action* action);
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,9 +17,12 @@ void WotlkDungeonUPStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
|||||||
|
|
||||||
// King Ymiron
|
// King Ymiron
|
||||||
// May need to avoid orb.. unclear if the generic avoid AoE does this well
|
// May need to avoid orb.. unclear if the generic avoid AoE does this well
|
||||||
|
triggers.push_back(new TriggerNode("ymiron bane",
|
||||||
|
NextAction::array(0, new NextAction("stop attack", ACTION_RAID + 5), nullptr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WotlkDungeonUPStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
void WotlkDungeonUPStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||||
{
|
{
|
||||||
multipliers.push_back(new SkadiMultiplier(botAI));
|
multipliers.push_back(new SkadiMultiplier(botAI));
|
||||||
|
multipliers.push_back(new YmironMultiplier(botAI));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ class WotlkDungeonUPTriggerContext : public NamedObjectContext<Trigger>
|
|||||||
{
|
{
|
||||||
creators["freezing cloud"] = &WotlkDungeonUPTriggerContext::freezing_cloud;
|
creators["freezing cloud"] = &WotlkDungeonUPTriggerContext::freezing_cloud;
|
||||||
creators["skadi whirlwind"] = &WotlkDungeonUPTriggerContext::whirlwind;
|
creators["skadi whirlwind"] = &WotlkDungeonUPTriggerContext::whirlwind;
|
||||||
|
creators["ymiron bane"] = &WotlkDungeonUPTriggerContext::bane;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static Trigger* freezing_cloud(PlayerbotAI* ai) { return new SkadiFreezingCloudTrigger(ai); }
|
static Trigger* freezing_cloud(PlayerbotAI* ai) { return new SkadiFreezingCloudTrigger(ai); }
|
||||||
static Trigger* whirlwind(PlayerbotAI* ai) { return new SkadiWhirlwindTrigger(ai); }
|
static Trigger* whirlwind(PlayerbotAI* ai) { return new SkadiWhirlwindTrigger(ai); }
|
||||||
|
static Trigger* bane(PlayerbotAI* ai) { return new YmironBaneTrigger(ai); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -46,3 +46,11 @@ bool SkadiWhirlwindTrigger::IsActive()
|
|||||||
Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless");
|
Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless");
|
||||||
return boss && boss->HasAura(SPELL_SKADI_WHIRLWIND);
|
return boss && boss->HasAura(SPELL_SKADI_WHIRLWIND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool YmironBaneTrigger::IsActive()
|
||||||
|
{
|
||||||
|
Unit* boss = AI_VALUE2(Unit*, "find target", "king ymiron");
|
||||||
|
if (!boss) { return false; }
|
||||||
|
|
||||||
|
return boss->FindCurrentSpellBySpellId(SPELL_BANE) || boss->HasAura(SPELL_BANE);
|
||||||
|
}
|
||||||
@@ -15,10 +15,15 @@ enum UtgardePinnacleIDs
|
|||||||
NPC_BREATH_TRIGGER = 28351,
|
NPC_BREATH_TRIGGER = 28351,
|
||||||
SPELL_SKADI_WHIRLWIND_N = 50228,
|
SPELL_SKADI_WHIRLWIND_N = 50228,
|
||||||
SPELL_SKADI_WHIRLWIND_H = 59322,
|
SPELL_SKADI_WHIRLWIND_H = 59322,
|
||||||
|
|
||||||
|
// King Ymiron
|
||||||
|
SPELL_BANE_N = 48294,
|
||||||
|
SPELL_BANE_H = 59301,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SPELL_FREEZING_CLOUD DUNGEON_MODE(bot, SPELL_FREEZING_CLOUD_N, SPELL_FREEZING_CLOUD_H)
|
#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)
|
#define SPELL_SKADI_WHIRLWIND DUNGEON_MODE(bot, SPELL_SKADI_WHIRLWIND_N, SPELL_SKADI_WHIRLWIND_H)
|
||||||
|
#define SPELL_BANE DUNGEON_MODE(bot, SPELL_BANE_N, SPELL_BANE_H)
|
||||||
|
|
||||||
// const float SKADI_BREATH_CENTRELINE = -512.46875f;
|
// const float SKADI_BREATH_CENTRELINE = -512.46875f;
|
||||||
|
|
||||||
@@ -36,4 +41,11 @@ public:
|
|||||||
bool IsActive() override;
|
bool IsActive() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class YmironBaneTrigger : public Trigger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
YmironBaneTrigger(PlayerbotAI* ai) : Trigger(ai, "ymiron bane") {}
|
||||||
|
bool IsActive() override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user