Small fixes to naxxramas strategy (#2201)

# Pull Request

Small fixes to naxxramas strategy

---

## Complexity & Impact

Does this change add new decision branches?
- - [x] No
- - [ ] Yes (**explain below**)

Does this change increase per-bot or per-tick processing?
- - [x] No
- - [ ] Yes (**describe and justify impact**)

Could this logic scale poorly under load?
- - [x] No
- - [ ] Yes (**explain why**)
---

## Defaults & Configuration

Does this change modify default bot behavior?
- - [x] No
- - [ ] Yes (**explain why**)

If this introduces more advanced or AI-heavy logic:
- - [x] Lightweight mode remains the default
- - [ ] More complex behavior is optional and thereby configurable
---

## AI Assistance

Was AI assistance (e.g. ChatGPT or similar tools) used while working on
this change?
- - [x] No
- - [ ] Yes (**explain below**)

If yes, please specify:

Copilot CLI to code review

---

## Final Checklist

- - [x] Stability is not compromised
- - [x] Performance impact is understood, tested, and acceptable
- - [x] Added logic complexity is justified and explained
- - [x] Documentation updated if needed
This commit is contained in:
kadeshar
2026-03-13 22:22:11 +01:00
committed by GitHub
parent 5e7613f719
commit a695ac77fa
14 changed files with 51 additions and 57 deletions

View File

@@ -37,10 +37,10 @@ public:
uint32 GetCurrWaypoint() override;
};
class GrobblulusMoveCenterAction : public MoveInsideAction
class GrobbulusMoveCenterAction : public MoveInsideAction
{
public:
GrobblulusMoveCenterAction(PlayerbotAI* ai) : MoveInsideAction(ai, 3281.23f, -3310.38f, 5.0f) {}
GrobbulusMoveCenterAction(PlayerbotAI* ai) : MoveInsideAction(ai, 3281.23f, -3310.38f, 5.0f) {}
};
class GrobbulusMoveAwayAction : public MovementAction
@@ -173,26 +173,26 @@ private:
RazuviousBossHelper helper;
};
class HorsemanAttractAlternativelyAction : public AttackAction
class FourHorsemenAttractAlternativelyAction : public AttackAction
{
public:
HorsemanAttractAlternativelyAction(PlayerbotAI* ai) : AttackAction(ai, "horseman attract alternatively"), helper(ai)
FourHorsemenAttractAlternativelyAction(PlayerbotAI* ai) : AttackAction(ai, "four horsemen attract alternatively"), helper(ai)
{
}
bool Execute(Event event) override;
protected:
FourhorsemanBossHelper helper;
FourHorsemenBossHelper helper;
};
class HorsemanAttactInOrderAction : public AttackAction
class FourHorsemenAttackInOrderAction : public AttackAction
{
public:
HorsemanAttactInOrderAction(PlayerbotAI* ai) : AttackAction(ai, "horseman attact in order"), helper(ai) {}
FourHorsemenAttackInOrderAction(PlayerbotAI* ai) : AttackAction(ai, "four horsemen attack in order"), helper(ai) {}
bool Execute(Event event) override;
protected:
FourhorsemanBossHelper helper;
FourHorsemenBossHelper helper;
};
// class SapphironGroundMainTankPositionAction : public MovementAction

View File

@@ -1,7 +1,6 @@
#include "RaidNaxxActions.h"
#include "ObjectGuid.h"
#include "Playerbots.h"
#include "RaidNaxxActions.h"
bool AnubrekhanChooseTargetAction::Execute(Event /*event*/)
{
@@ -66,13 +65,10 @@ bool AnubrekhanPositionAction::Execute(Event /*event*/)
{
uint32 nearest = FindNearestWaypoint();
uint32 next_point;
if (inPhase)
next_point = (nearest + 1) % intervals;
else
next_point = nearest;
next_point = (nearest + 1) % intervals;
return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second, bot->GetPositionZ(), false, false,
false, false, MovementPriority::MOVEMENT_COMBAT);
return MoveTo(bot->GetMapId(), waypoints[next_point].first, waypoints[next_point].second,
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
}
else
return MoveInside(533, 3272.49f, -3476.27f, bot->GetPositionZ(), 3.0f, MovementPriority::MOVEMENT_COMBAT);

View File

@@ -2,7 +2,7 @@
#include "Playerbots.h"
bool HorsemanAttractAlternativelyAction::Execute(Event /*event*/)
bool FourHorsemenAttractAlternativelyAction::Execute(Event /*event*/)
{
if (!helper.UpdateBossAI())
return false;
@@ -13,13 +13,13 @@ bool HorsemanAttractAlternativelyAction::Execute(Event /*event*/)
return true;
Unit* attackTarget = helper.CurrentAttackTarget();
if (context->GetValue<Unit*>("current target")->Get() != attackTarget)
if (attackTarget && context->GetValue<Unit*>("current target")->Get() != attackTarget)
return Attack(attackTarget);
return false;
}
bool HorsemanAttactInOrderAction::Execute(Event /*event*/)
bool FourHorsemenAttackInOrderAction::Execute(Event /*event*/)
{
if (!helper.UpdateBossAI())
return false;

View File

@@ -70,7 +70,6 @@ bool SapphironFlightPositionAction::MoveToNearestIcebolt()
if (!group)
return false;
Group::MemberSlotList const& slots = group->GetMemberSlots();
Player* playerWithIcebolt = nullptr;
float minDistance;
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())

View File

@@ -13,7 +13,7 @@ bool ThaddiusAttackNearestPetAction::isUseful()
return false;
Unit* target = helper.GetNearestPet();
if (!bot->IsWithinDistInMap(target, 50.0f))
if (!target || !bot->IsWithinDistInMap(target, 50.0f))
return false;
return true;
@@ -22,7 +22,7 @@ bool ThaddiusAttackNearestPetAction::isUseful()
bool ThaddiusAttackNearestPetAction::Execute(Event /*event*/)
{
Unit* target = helper.GetNearestPet();
if (!bot->IsWithinLOSInMap(target))
if (!target || !bot->IsWithinLOSInMap(target))
return MoveTo(target, 0, MovementPriority::MOVEMENT_COMBAT);
if (AI_VALUE(Unit*, "current target") != target)

View File

@@ -245,7 +245,7 @@ float AnubrekhanGenericMultiplier::GetValue(Action* action)
return 1.0f;
}
float FourhorsemanGenericMultiplier::GetValue(Action* action)
float FourHorsemenGenericMultiplier::GetValue(Action* action)
{
Unit* boss = AI_VALUE2(Unit*, "find target", "sir zeliek");
if (!boss)

View File

@@ -1,6 +1,6 @@
#ifndef _PLAYERRBOT_RAIDNAXXMULTIPLIERS_H
#define _PLAYERRBOT_RAIDNAXXMULTIPLIERS_H
#ifndef _PLAYERBOT_RAIDNAXXMULTIPLIERS_H
#define _PLAYERBOT_RAIDNAXXMULTIPLIERS_H
#include "Multiplier.h"
#include "RaidNaxxBossHelper.h"
@@ -84,10 +84,10 @@ public:
virtual float GetValue(Action* action);
};
class FourhorsemanGenericMultiplier : public Multiplier
class FourHorsemenGenericMultiplier : public Multiplier
{
public:
FourhorsemanGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "fourhorseman generic") {}
FourHorsemenGenericMultiplier(PlayerbotAI* ai) : Multiplier(ai, "four horsemen generic") {}
public:
virtual float GetValue(Action* action);

View File

@@ -31,8 +31,8 @@ public:
creators["razuvious use obedience crystal"] = &RaidNaxxActionContext::razuvious_use_obedience_crystal;
creators["razuvious target"] = &RaidNaxxActionContext::razuvious_target;
creators["horseman attract alternatively"] = &RaidNaxxActionContext::horseman_attract_alternatively;
creators["horseman attack in order"] = &RaidNaxxActionContext::horseman_attack_in_order;
creators["four horsemen attract alternatively"] = &RaidNaxxActionContext::four_horsemen_attract_alternatively;
creators["four horsemen attack in order"] = &RaidNaxxActionContext::four_horsemen_attack_in_order;
creators["sapphiron ground position"] = &RaidNaxxActionContext::sapphiron_ground_position;
creators["sapphiron flight position"] = &RaidNaxxActionContext::sapphiron_flight_position;
@@ -56,7 +56,7 @@ public:
private:
static Action* go_behind_the_boss(PlayerbotAI* ai) { return new GrobbulusGoBehindAction(ai); }
static Action* rotate_grobbulus(PlayerbotAI* ai) { return new GrobbulusRotateAction(ai); }
static Action* grobbulus_move_center(PlayerbotAI* ai) { return new GrobblulusMoveCenterAction(ai); }
static Action* grobbulus_move_center(PlayerbotAI* ai) { return new GrobbulusMoveCenterAction(ai); }
static Action* grobbulus_move_away(PlayerbotAI* ai) { return new GrobbulusMoveAwayAction(ai); }
//static Action* heigan_dance_melee(PlayerbotAI* ai) { return new HeiganDanceMeleeAction(ai); }
//static Action* heigan_dance_ranged(PlayerbotAI* ai) { return new HeiganDanceRangedAction(ai); }
@@ -70,11 +70,8 @@ private:
{
return new RazuviousUseObedienceCrystalAction(ai);
}
static Action* horseman_attract_alternatively(PlayerbotAI* ai)
{
return new HorsemanAttractAlternativelyAction(ai);
}
static Action* horseman_attack_in_order(PlayerbotAI* ai) { return new HorsemanAttactInOrderAction(ai); }
static Action* four_horsemen_attract_alternatively(PlayerbotAI* ai) { return new FourHorsemenAttractAlternativelyAction(ai); }
static Action* four_horsemen_attack_in_order(PlayerbotAI* ai) { return new FourHorsemenAttackInOrderAction(ai); }
// static Action* sapphiron_ground_main_tank_position(PlayerbotAI* ai) { return new
// SapphironGroundMainTankPositionAction(ai); }
static Action* sapphiron_ground_position(PlayerbotAI* ai) { return new SapphironGroundPositionAction(ai); }

View File

@@ -30,8 +30,8 @@ public:
creators["razuvious tank"] = &RaidNaxxTriggerContext::razuvious_tank;
creators["razuvious nontank"] = &RaidNaxxTriggerContext::razuvious_nontank;
creators["horseman attractors"] = &RaidNaxxTriggerContext::horseman_attractors;
creators["horseman except attractors"] = &RaidNaxxTriggerContext::horseman_except_attractors;
creators["four horsemen attractors"] = &RaidNaxxTriggerContext::four_horsemen_attractors;
creators["four horsemen except attractors"] = &RaidNaxxTriggerContext::four_horsemen_except_attractors;
creators["sapphiron ground"] = &RaidNaxxTriggerContext::sapphiron_ground;
creators["sapphiron flight"] = &RaidNaxxTriggerContext::sapphiron_flight;
@@ -66,8 +66,8 @@ private:
static Trigger* razuvious_tank(PlayerbotAI* ai) { return new RazuviousTankTrigger(ai); }
static Trigger* razuvious_nontank(PlayerbotAI* ai) { return new RazuviousNontankTrigger(ai); }
static Trigger* horseman_attractors(PlayerbotAI* ai) { return new HorsemanAttractorsTrigger(ai); }
static Trigger* horseman_except_attractors(PlayerbotAI* ai) { return new HorsemanExceptAttractorsTrigger(ai); }
static Trigger* four_horsemen_attractors(PlayerbotAI* ai) { return new FourHorsemenAttractorsTrigger(ai); }
static Trigger* four_horsemen_except_attractors(PlayerbotAI* ai) { return new FourHorsemenExceptAttractorsTrigger(ai); }
static Trigger* sapphiron_ground(PlayerbotAI* ai) { return new SapphironGroundTrigger(ai); }
static Trigger* sapphiron_flight(PlayerbotAI* ai) { return new SapphironFlightTrigger(ai); }

View File

@@ -97,13 +97,13 @@ void RaidNaxxStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ NextAction("razuvious target", ACTION_RAID + 1) }
));
// four horseman
triggers.push_back(new TriggerNode("horseman attractors",
{ NextAction("horseman attract alternatively", ACTION_RAID + 1) }
// four horsemen
triggers.push_back(new TriggerNode("four horsemen attractors",
{ NextAction("four horsemen attract alternatively", ACTION_RAID + 1) }
));
triggers.push_back(new TriggerNode("horseman except attractors",
{ NextAction("horseman attack in order", ACTION_RAID + 1) }
triggers.push_back(new TriggerNode("four horsemen except attractors",
{ NextAction("four horsemen attack in order", ACTION_RAID + 1) }
));
// sapphiron
@@ -150,7 +150,7 @@ void RaidNaxxStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
multipliers.push_back(new InstructorRazuviousGenericMultiplier(botAI));
multipliers.push_back(new KelthuzadGenericMultiplier(botAI));
multipliers.push_back(new AnubrekhanGenericMultiplier(botAI));
multipliers.push_back(new FourhorsemanGenericMultiplier(botAI));
multipliers.push_back(new FourHorsemenGenericMultiplier(botAI));
// multipliers.push_back(new GothikGenericMultiplier(botAI));
multipliers.push_back(new GluthGenericMultiplier(botAI));
}

View File

@@ -114,7 +114,7 @@ bool RazuviousNontankTrigger::IsActive()
return helper.UpdateBossAI() && !(bot->getClass() == CLASS_PRIEST);
}
bool HorsemanAttractorsTrigger::IsActive()
bool FourHorsemenAttractorsTrigger::IsActive()
{
if (!helper.UpdateBossAI())
return false;
@@ -122,7 +122,7 @@ bool HorsemanAttractorsTrigger::IsActive()
return helper.IsAttracter(bot);
}
bool HorsemanExceptAttractorsTrigger::IsActive()
bool FourHorsemenExceptAttractorsTrigger::IsActive()
{
if (!helper.UpdateBossAI())
return false;

View File

@@ -186,24 +186,24 @@ private:
ThaddiusBossHelper helper;
};
class HorsemanAttractorsTrigger : public Trigger
class FourHorsemenAttractorsTrigger : public Trigger
{
public:
HorsemanAttractorsTrigger(PlayerbotAI* ai) : Trigger(ai, "fourhorsemen attractors"), helper(ai) {}
FourHorsemenAttractorsTrigger(PlayerbotAI* ai) : Trigger(ai, "four horsemen attractors"), helper(ai) {}
bool IsActive() override;
private:
FourhorsemanBossHelper helper;
FourHorsemenBossHelper helper;
};
class HorsemanExceptAttractorsTrigger : public Trigger
class FourHorsemenExceptAttractorsTrigger : public Trigger
{
public:
HorsemanExceptAttractorsTrigger(PlayerbotAI* ai) : Trigger(ai, "fourhorsemen except attractors"), helper(ai) {}
FourHorsemenExceptAttractorsTrigger(PlayerbotAI* ai) : Trigger(ai, "four horsemen except attractors"), helper(ai) {}
bool IsActive() override;
private:
FourhorsemanBossHelper helper;
FourHorsemenBossHelper helper;
};
class SapphironGroundTrigger : public Trigger

View File

@@ -202,7 +202,7 @@ public:
}
bool FindPosToAvoidChill(std::vector<float>& dest)
{
Aura* aura = NaxxSpellIds::GetAnyAura(bot, {NaxxSpellIds::Chill25});
Aura* aura = NaxxSpellIds::GetAnyAura(bot, {NaxxSpellIds::Chill10, NaxxSpellIds::Chill25});
if (!aura)
{
// Fallback to name for custom spell data.
@@ -363,13 +363,13 @@ private:
Unit* _unit = nullptr;
};
class FourhorsemanBossHelper : public AiObject
class FourHorsemenBossHelper : public AiObject
{
public:
const float posZ = 241.27f;
const std::pair<float, float> attractPos[2] = {{2502.03f, -2910.90f},
{2484.61f, -2947.07f}}; // left (sir zeliek), right (lady blaumeux)
FourhorsemanBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {}
FourHorsemenBossHelper(PlayerbotAI* botAI) : AiObject(botAI) {}
bool UpdateBossAI()
{
if (!bot->IsInCombat())
@@ -497,7 +497,8 @@ public:
if (feugen && feugen->IsAlive())
unit = feugen;
if (stalagg && stalagg->IsAlive() && (!feugen || bot->GetDistance(stalagg) < bot->GetDistance(feugen)))
if (stalagg && stalagg->IsAlive() &&
(!feugen || !feugen->IsAlive() || bot->GetDistance(stalagg) < bot->GetDistance(feugen)))
unit = stalagg;
return unit;

View File

@@ -58,6 +58,7 @@ namespace NaxxSpellIds
// Sapphiron
static constexpr uint32 Icebolt10 = 28522;
static constexpr uint32 Icebolt25 = 28526;
static constexpr uint32 Chill10 = 28547;
static constexpr uint32 Chill25 = 55699;
/*
// Fight