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:
|
||||
WotlkDungeonGDActionContext() {
|
||||
creators["avoid poison nova"] = &WotlkDungeonGDActionContext::avoid_poison_nova;
|
||||
creators["attack snake wrap"] = &WotlkDungeonGDActionContext::attack_snake_wrap;
|
||||
creators["avoid whirling slash"] = &WotlkDungeonGDActionContext::avoid_whirling_slash;
|
||||
}
|
||||
private:
|
||||
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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,32 @@ bool AvoidPoisonNovaAction::Execute(Event event)
|
||||
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)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "gal'darah");
|
||||
|
||||
@@ -14,6 +14,13 @@ public:
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -11,13 +11,38 @@ float SladranMultiplier::GetValue(Action* action)
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
||||
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))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
triggers.push_back(new TriggerNode("poison nova",
|
||||
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
|
||||
triggers.push_back(new TriggerNode("whirling slash",
|
||||
NextAction::array(0, new NextAction("avoid whirling slash", ACTION_RAID + 5), nullptr)));
|
||||
|
||||
// Eck the Ferocious (Heroic only)
|
||||
// TODO
|
||||
}
|
||||
|
||||
void WotlkDungeonGDStrategy::InitMultipliers(std::vector<Multiplier*> &multipliers)
|
||||
|
||||
@@ -11,10 +11,12 @@ class WotlkDungeonGDTriggerContext : public NamedObjectContext<Trigger>
|
||||
WotlkDungeonGDTriggerContext()
|
||||
{
|
||||
creators["poison nova"] = &WotlkDungeonGDTriggerContext::poison_nova;
|
||||
creators["snake wrap"] = &WotlkDungeonGDTriggerContext::snake_wrap;
|
||||
creators["whirling slash"] = &WotlkDungeonGDTriggerContext::whirling_slash;
|
||||
}
|
||||
private:
|
||||
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); }
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,26 @@ bool SladranPoisonNovaTrigger::IsActive()
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "slad'ran");
|
||||
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()
|
||||
|
||||
@@ -11,6 +11,7 @@ enum GundrakIDs
|
||||
// Slad'ran
|
||||
SPELL_POISON_NOVA_N = 55081,
|
||||
SPELL_POISON_NOVA_H = 59842,
|
||||
NPC_SNAKE_WRAP = 29742,
|
||||
|
||||
// Gal'darah
|
||||
SPELL_WHIRLING_SLASH_N = 55250,
|
||||
@@ -27,6 +28,13 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class SladranSnakeWrapTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
SladranSnakeWrapTrigger(PlayerbotAI* ai) : Trigger(ai, "slad'ran snake wrap") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class GaldarahWhirlingSlashTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -11,10 +11,12 @@ class WotlkDungeonUPActionContext : public NamedObjectContext<Action>
|
||||
WotlkDungeonUPActionContext() {
|
||||
creators["avoid freezing cloud"] = &WotlkDungeonUPActionContext::avoid_freezing_cloud;
|
||||
creators["avoid skadi whirlwind"] = &WotlkDungeonUPActionContext::avoid_whirlwind;
|
||||
creators["stop attack"] = &WotlkDungeonUPActionContext::stop_attack;
|
||||
}
|
||||
private:
|
||||
static Action* avoid_freezing_cloud(PlayerbotAI* ai) { return new AvoidFreezingCloudAction(ai); }
|
||||
static Action* avoid_whirlwind(PlayerbotAI* ai) { return new AvoidSkadiWhirlwindAction(ai); }
|
||||
static Action* stop_attack(PlayerbotAI* ai) { return new DropTargetAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -82,3 +82,18 @@ float SkadiMultiplier::GetValue(Action* action)
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
class YmironMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
YmironMultiplier(PlayerbotAI* ai) : Multiplier(ai, "king ymiron") {}
|
||||
|
||||
public:
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,9 +17,12 @@ void WotlkDungeonUPStrategy::InitTriggers(std::vector<TriggerNode*> &triggers)
|
||||
|
||||
// King Ymiron
|
||||
// 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)
|
||||
{
|
||||
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["skadi whirlwind"] = &WotlkDungeonUPTriggerContext::whirlwind;
|
||||
creators["ymiron bane"] = &WotlkDungeonUPTriggerContext::bane;
|
||||
}
|
||||
private:
|
||||
static Trigger* freezing_cloud(PlayerbotAI* ai) { return new SkadiFreezingCloudTrigger(ai); }
|
||||
static Trigger* whirlwind(PlayerbotAI* ai) { return new SkadiWhirlwindTrigger(ai); }
|
||||
static Trigger* bane(PlayerbotAI* ai) { return new YmironBaneTrigger(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,3 +46,11 @@ bool SkadiWhirlwindTrigger::IsActive()
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "skadi the ruthless");
|
||||
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,
|
||||
SPELL_SKADI_WHIRLWIND_N = 50228,
|
||||
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_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;
|
||||
|
||||
@@ -36,4 +41,11 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YmironBaneTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
YmironBaneTrigger(PlayerbotAI* ai) : Trigger(ai, "ymiron bane") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user