Merge b33b932b664fe2e2944d7e94608ad857290eae5e into 5bef92d5eaca3e2ecc317f9d599312bc23eb71aa

This commit is contained in:
sogladev 2025-11-10 03:24:55 +01:00 committed by GitHub
commit 2b3520ffcc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 627 additions and 252 deletions

View File

@ -0,0 +1,74 @@
--
-- HARD_RESET
UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 2147483648 WHERE (`entry` IN (28921, 31611));
DELETE FROM `spelldifficulty_dbc` WHERE `ID` IN (53406, 53317, 53394, 53330, 53322);
INSERT INTO `spelldifficulty_dbc` (`ID`, `DifficultySpellID_1`, `DifficultySpellID_2`, `DifficultySpellID_3`, `DifficultySpellID_4`) VALUES
(53406, 53406, 59420, 0, 0),
(53317, 53317, 59343, 0, 0),
(53394, 53394, 59344, 0, 0),
(53330, 53330, 59348, 0, 0),
(53322, 53322, 59347, 0, 0);
DELETE FROM `spell_script_names` WHERE `spell_id` IN (53406, 59420) AND `ScriptName` = 'spell_hadronox_web_grab';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(53406, 'spell_hadronox_web_grab'),
(59420, 'spell_hadronox_web_grab');
DELETE FROM `creature_summon_groups` WHERE `summonerId` = 28921;
INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`, `Comment`) VALUES
(28921, 0, 1, 28922, 529.691, 547.126, 731.916, 4.79965, 6, 45000, 'Hadronox - Group 1 - Anub''ar Crusher'),
(28921, 0, 1, 29117, 539.208, 549.754, 732.867, 4.55531, 6, 30000, 'Hadronox - Group 1 - Anub''ar Champion'),
(28921, 0, 1, 29118, 520.391, 548.789, 732.012, 5.0091, 6, 30000, 'Hadronox - Group 1 - Anub''ar Crypt Fiend'),
(28921, 0, 2, 28922, 493.477, 603.344, 760.563, 5.44024, 6, 45000, 'Hadronox - Group 2 - Anub''ar Crusher'),
(28921, 0, 2, 29117, 490.442, 604.335, 763.182, 5.6256, 6, 30000, 'Hadronox - Group 2 - Anub''ar Champion'),
(28921, 0, 2, 29119, 488.825, 609.282, 767.588, 5.59029, 6, 30000, 'Hadronox - Group 2 - Anub''ar Necromancer'),
(28921, 0, 3, 28922, 566.979, 602.571, 759.642, 3.88597, 6, 45000, 'Hadronox - Group 3 - Anub''ar Crusher'),
(28921, 0, 3, 29118, 569.348, 604.999, 763.214, 4.17983, 6, 30000, 'Hadronox - Group 3 - Anub''ar Crypt Fiend'),
(28921, 0, 3, 29119, 572.474, 607.411, 767.178, 3.94417, 6, 30000, 'Hadronox - Group 3 - Anub''ar Necromancer'),
(28921, 0, 4, 23472, 581.448, 608.841, 739.405, 1.72788, 6, 3600000, 'Hadronox - Group 4 - World Trigger'),
(28921, 0, 4, 23472, 477.016, 618.4, 771.515, 2.35619, 6, 3600000, 'Hadronox - Group 4 - World Trigger'),
(28921, 0, 4, 23472, 583.091, 617.371, 771.551, 0.645772, 6, 3600000, 'Hadronox - Group 4 - World Trigger');
DELETE FROM `creature` WHERE (`id1` = 23472) AND (`guid` IN (127376, 127377, 127378));
DELETE FROM `creature_addon` WHERE (`guid` IN (127376, 127377, 127378));
DELETE FROM `smart_scripts` WHERE (`source_type` = 0) AND (`entryorguid` IN (29117, 29118, 29119));
UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_anub_ar_crusher_champion' WHERE (`entry` = 29117);
UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_anub_ar_crusher_crypt_fiend' WHERE (`entry` = 29118);
UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_anub_ar_crusher_necromancer' WHERE (`entry` = 29119);
SET @SPAWN_X := 522.53107;
SET @SPAWN_Y := 544.91125;
SET @SPAWN_Z := 674.6791;
SET @SPAWN_O := 5.633617;
DELETE FROM `creature` WHERE (`id1` = 28921) AND (`guid` = 127401);
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `Comment`, `VerifiedBuild`) VALUES
(127401, 28921, 0, 0, 601, 0, 0, 3, 1, 0, @SPAWN_X, @SPAWN_Y, @SPAWN_Z, @SPAWN_O, 86400, 0, 0, 154230, 0, 0, 0, 0, 0, '', NULL, 0);
DELETE FROM `waypoint_data` WHERE `id` IN (3000012, 3000013) AND `point` IN (13, 14);
DELETE FROM `waypoint_data` WHERE `id` = 3000014 AND `point` IN (9, 10);
INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
(3000012, 13, 538.0253, 529.9829, 686.0557, 0, 1, 0, 100, 0),
(3000012, 14, 532.7753, 535.2329, 681.0557, 0, 1, 0, 100, 0),
(3000013, 13, 538.0253, 529.9829, 686.0557, 0, 1, 0, 100, 0),
(3000013, 14, 532.7753, 535.2329, 681.0557, 0, 1, 0, 100, 0),
(3000014, 9, 538.0253, 529.9829, 686.0557, 0, 1, 0, 100, 0),
(3000014, 10, 532.7753, 535.2329, 681.0557, 0, 1, 0, 100, 0);
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (29062, 29063, 29064));
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(29062, 0, 0, 0, 0, 0, 100, 0, 4000, 7000, 12000, 18000, 0, 0, 11, 53317, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Champion - In Combat - Cast \'Rend\''),
(29062, 0, 1, 0, 105, 0, 100, 0, 9000, 13000, 9000, 13000, 0, 5, 11, 53394, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Champion - On Hostile Casting in Range - Cast \'Pummel\''),
(29062, 0, 2, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 10000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Champion - On Just Died - Despawn In 10000 ms'),
(29062, 0, 3, 0, 1, 0, 100, 0, 10000, 10000, 1000, 1000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 11, 28921, 50, 1, 0, 0, 0, 0, 0, 'Anub\'ar Champion Out of Combat - Start Attacking'),
(29062, 0, 4, 0, 0, 0, 100, 0, 15000, 50000, 15000, 50000, 0, 0, 11, 53798, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Champion - In Combat - Cast \'Taunt\''),
(29063, 0, 0, 0, 0, 0, 100, 0, 4000, 7000, 9000, 12000, 0, 0, 11, 53330, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Crypt Fiend - In Combat - Cast \'Infected Wound\''),
(29063, 0, 1, 0, 0, 0, 100, 0, 9000, 12000, 13000, 17000, 0, 0, 11, 53322, 0, 0, 0, 0, 0, 5, 30, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Crypt Fiend - In Combat - Cast \'Crushing Webs\''),
(29063, 0, 2, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 10000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Crypt Fiend - On Just Died - Despawn In 10000 ms'),
(29063, 0, 3, 0, 1, 0, 100, 0, 10000, 10000, 1000, 1000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 11, 28921, 50, 1, 0, 0, 0, 0, 0, 'Anub\'ar Crypt Fiend - Out of Combat - Start Attacking'),
(29063, 0, 4, 0, 0, 0, 100, 0, 15000, 50000, 15000, 50000, 0, 0, 11, 53798, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Crypt Fiend - In Combat - Cast \'Taunt\''),
(29064, 0, 0, 0, 1, 0, 100, 0, 0, 1000, 2000, 3000, 0, 0, 11, 53333, 64, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Necromancer - Out of Combat - Cast \'Shadow Bolt\''),
(29064, 0, 2, 0, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 10000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Necromancer - On Just Died - Despawn In 10000 ms'),
(29064, 0, 3, 0, 1, 0, 100, 0, 10000, 10000, 1000, 1000, 0, 0, 49, 0, 0, 0, 0, 0, 0, 11, 28921, 50, 1, 0, 0, 0, 0, 0, 'Anub\'ar Necromancer Out of Combat - Start Attacking'),
(29064, 0, 4, 0, 0, 0, 100, 0, 15000, 50000, 15000, 50000, 0, 0, 11, 53798, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Anub\'ar Necromancer - In Combat - Cast \'Taunt\'');

View File

@ -43,6 +43,7 @@ enum ANIds
NPC_HADRONOX = 28921,
NPC_ANUBARAK = 29120,
NPC_WORLD_TRIGGER_LAOI = 23472,
NPC_ANUB_AR_CHAMPION = 29062,
NPC_ANUB_AR_NECROMANCER = 29063,
NPC_ANUB_AR_CRYPTFIEND = 29064,

View File

@ -75,7 +75,6 @@ enum Events
enum CreatureIds
{
NPC_WORLD_TRIGGER = 22515,
NPC_ANUBAR_GUARDIAN = 29216,
NPC_ANUBAR_VENOMANCER = 29217,
};

View File

@ -26,19 +26,39 @@
enum Spells
{
// World Trigger
SPELL_SUMMON_ANUBAR_CHAMPION = 53064,
SPELL_SUMMON_ANUBAR_CRYPT_FIEND = 53065,
SPELL_SUMMON_ANUBAR_NECROMANCER = 53066,
SPELL_SUMMON_ANUBAR_CHAMPION_PERIODIC = 53035,
SPELL_SUMMON_ANUBAR_NECROMANCER_PERIODIC = 53036,
SPELL_SUMMON_ANUBAR_CRYPT_FIEND_PERIODIC = 53037,
// Hadronox
SPELL_WEB_FRONT_DOORS = 53177,
SPELL_WEB_SIDE_DOORS = 53185,
SPELL_ACID_CLOUD = 53400,
SPELL_LEECH_POISON = 53030,
SPELL_LEECH_POISON_HEAL = 53800,
SPELL_WEB_GRAB = 57731,
SPELL_WEB_GRAB = 53406,
SPELL_PIERCE_ARMOR = 53418,
// Anub'ar Crusher
SPELL_SMASH = 53318,
SPELL_FRENZY = 53801
SPELL_FRENZY = 53801,
// Anub'ar Champion
SPELL_REND = 59343,
SPELL_PUMMEL = 59344,
// Anub'ar Crypt Guard
SPELL_CRUSHING_WEBS = 59347,
SPELL_INFECTED_WOUND = 59348,
// Anub'ar Necromancer
SPELL_SHADOW_BOLT = 53333,
SPELL_ANIMATE_BONES_1 = 53334,
SPELL_ANIMATE_BONES_2 = 53336,
};
enum Events
@ -54,71 +74,134 @@ enum Events
EVENT_HADRONOX_SUMMON = 9,
EVENT_CRUSHER_SMASH = 20,
EVENT_CHECK_HEALTH = 21
EVENT_CHECK_HEALTH = 21,
EVENT_CHECK_EVADE = 22,
// Anub'ar Champion
EVENT_REND,
EVENT_PUMMEL,
// Anub'ar Crypt Guard
EVENT_CRUSHING_WEBS,
EVENT_INFECTED_WOUND,
// Anub'ar Necromancer
EVENT_SHADOW_BOLT,
EVENT_ANIMATE_BONES
};
enum NPCs
{
NPC_ANUB_AR_CRUSHER = 28922,
NPC_ANUB_AR_CHAMPION_PACK = 29117,
NPC_ANUB_AR_CRYPT_FIEND_PACK = 29118,
NPC_ANUB_AR_NECROMANCER_PACK = 29119,
};
enum SummonGroups : uint32
{
SUMMON_GROUP_CRUSHER_NONE = 0,
SUMMON_GROUP_CRUSHER_1 = 1,
SUMMON_GROUP_CRUSHER_2 = 2,
SUMMON_GROUP_CRUSHER_3 = 3,
SUMMON_GROUP_WORLD_TRIGGERS = 4,
};
enum Data
{
DATA_CRUSHER_PACK_ID = 1,
};
enum Misc
{
NPC_ANUB_AR_CRUSHER = 28922,
SAY_CRUSHER_AGGRO = 0,
SAY_CRUSHER_EMOTE = 1,
SAY_CRUSHER_AGGRO = 1,
SAY_CRUSHER_EMOTE = 2,
SAY_HADRONOX_EMOTE = 0,
ACTION_DESPAWN_ADDS = 1,
ACTION_START_EVENT = 2
ACTION_CRUSHER_ENGAGED = 1,
ACTION_CRUSHER_DIED = 2,
ACTION_PACK_WALK = 3,
};
const Position hadronoxSteps[4] =
{
{607.9f, 512.8f, 695.3f, 0.0f},
{611.67f, 564.11f, 720.0f, 0.0f},
{576.1f, 580.0f, 727.5f, 0.0f},
{534.87f, 554.0f, 733.0f, 0.0f}
};
static const std::array<Position, 3> hadronoxSteps =
{{
{ 562.191f, 514.068f, 696.50710f },
{ 615.802f, 517.418f, 695.68066f },
{ 530.420f, 560.003f, 733.22473f },
}};
class boss_hadronox : public CreatureScript
struct boss_hadronox : public BossAI
{
public:
boss_hadronox() : CreatureScript("boss_hadronox") { }
struct boss_hadronoxAI : public BossAI
{
boss_hadronoxAI(Creature* creature) : BossAI(creature, DATA_HADRONOX)
{
}
explicit boss_hadronox(Creature* creature) : BossAI(creature, DATA_HADRONOX), _crushersLeft(0), _doorsWebbed(false), _lastPlayerCombatState(false) { }
void Reset() override
{
summons.DoAction(ACTION_DESPAWN_ADDS);
BossAI::Reset();
me->SummonCreature(NPC_ANUB_AR_CRUSHER, 542.9f, 519.5f, 741.24f, 2.14f);
SummonCrusherPack(SUMMON_GROUP_CRUSHER_1);
me->SummonCreatureGroup(SUMMON_GROUP_WORLD_TRIGGERS);
_doorsWebbed = false;
_lastPlayerCombatState = false;
}
void SummonedCreatureEvade(Creature* summon) override
{
switch (summon->GetEntry())
{
case NPC_ANUB_AR_CRUSHER:
case NPC_ANUB_AR_CHAMPION_PACK:
case NPC_ANUB_AR_CRYPT_FIEND_PACK:
case NPC_ANUB_AR_NECROMANCER_PACK:
EnterEvadeMode(EVADE_REASON_OTHER);
break;
default:
break;
}
}
void DoAction(int32 param) override
{
if (param == ACTION_START_EVENT)
if (param == ACTION_CRUSHER_DIED)
--_crushersLeft;
else if (param == ACTION_CRUSHER_ENGAGED)
{
if (instance->GetBossState(DATA_HADRONOX) == IN_PROGRESS)
return;
instance->SetBossState(DATA_HADRONOX, IN_PROGRESS);
me->setActive(true);
events.ScheduleEvent(EVENT_HADRONOX_MOVE1, 20s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE2, 40s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE3, 60s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE4, 80s);
events.ScheduleEvent(EVENT_CHECK_EVADE, 5s);
SummonCrusherPack(SUMMON_GROUP_CRUSHER_2);
SummonCrusherPack(SUMMON_GROUP_CRUSHER_3);
events.ScheduleEvent(EVENT_HADRONOX_MOVE1, 0s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE2, 45s);
events.ScheduleEvent(EVENT_HADRONOX_MOVE3, 90s);
}
}
uint32 GetData(uint32 data) const override
void SummonCrusherPack(const SummonGroups group)
{
if (data == me->GetEntry())
return !me->isActiveObject() || events.HasTimeUntilEvent(EVENT_HADRONOX_MOVE4) ? 1 : 0;
return 0;
std::list<TempSummon*> summoned;
me->SummonCreatureGroup(group, &summoned);
_crushersLeft = summoned.size();
for (TempSummon* summon : summoned)
{
summon->AI()->SetData(DATA_CRUSHER_PACK_ID, group);
summon->AI()->DoAction(ACTION_PACK_WALK);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_WORLD_TRIGGER_LAOI:
summon->AddAura(SPELL_SUMMON_ANUBAR_CHAMPION_PERIODIC, summon);
summon->AddAura(SPELL_SUMMON_ANUBAR_NECROMANCER_PERIODIC, summon);
summon->AddAura(SPELL_SUMMON_ANUBAR_CRYPT_FIEND_PERIODIC, summon);
break;
case NPC_ANUB_AR_CHAMPION:
case NPC_ANUB_AR_NECROMANCER:
case NPC_ANUB_AR_CRYPTFIEND:
// Xinef: cannot use pathfinding...
if (summon->GetDistance(477.0f, 618.0f, 771.0f) < 5.0f)
summon->GetMotionMaster()->MoveWaypoint(3000012, false);
@ -126,6 +209,10 @@ public:
summon->GetMotionMaster()->MoveWaypoint(3000013, false);
else if (summon->GetDistance(581.0f, 608.5f, 739.0f) < 5.0f)
summon->GetMotionMaster()->MoveWaypoint(3000014, false);
break;
default:
break;
}
}
void KilledUnit(Unit* victim) override
@ -133,30 +220,24 @@ public:
if (!me->IsAlive() || !victim->HasAura(SPELL_LEECH_POISON))
return;
me->ModifyHealth(int32(me->CountPctFromMaxHealth(10)));
me->ModifyHealth(static_cast<int32>(me->CountPctFromMaxHealth(10)));
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit*) override
void JustEngagedWith(Unit* /*who*/) override
{
me->setActive(true);
events.RescheduleEvent(EVENT_HADRONOX_ACID, 10s);
events.RescheduleEvent(EVENT_HADRONOX_LEECH, 4s);
events.RescheduleEvent(EVENT_HADRONOX_PIERCE, 1s);
events.RescheduleEvent(EVENT_HADRONOX_GRAB, 15s);
events.RescheduleEvent(EVENT_CHECK_EVADE, 1s);
}
bool AnyPlayerValid() const
bool IsInCombatWithPlayer() const
{
Map::PlayerList const& playerList = me->GetMap()->GetPlayers();
for(Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
if (me->GetDistance(itr->GetSource()) < 130.0f && itr->GetSource()->IsAlive() && !itr->GetSource()->IsGameMaster() && me->CanCreatureAttack(itr->GetSource()))
return true;
return false;
return std::ranges::any_of(me->GetThreatMgr().GetThreatList(), [](auto const& ref) {
return ref->getTarget()->IsControlledByPlayer();
});
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
@ -164,164 +245,362 @@ public:
if ((!who || !who->IsControlledByPlayer()) && me->HealthBelowPct(70))
{
if (me->HealthBelowPctDamaged(5, damage))
{
damage = 0;
}
else
{
damage *= (me->GetHealthPct() - 5.0f) / 65.0f;
}
}
}
void UpdateAI(uint32 diff) override
{
events.Update(diff);
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (uint32 eventId = events.ExecuteEvent())
{
case EVENT_HADRONOX_PIERCE:
me->CastSpell(me->GetVictim(), SPELL_PIERCE_ARMOR, false);
events.ScheduleEvent(EVENT_HADRONOX_PIERCE, 8s);
DoCastVictim(SPELL_PIERCE_ARMOR);
events.Repeat(8s);
break;
case EVENT_HADRONOX_ACID:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, false))
me->CastSpell(target, SPELL_ACID_CLOUD, false);
events.ScheduleEvent(EVENT_HADRONOX_ACID, 25s);
DoCast(target, SPELL_ACID_CLOUD);
events.Repeat(25s);
break;
case EVENT_HADRONOX_LEECH:
me->CastSpell(me, SPELL_LEECH_POISON, false);
events.ScheduleEvent(EVENT_HADRONOX_LEECH, 12s);
DoCastSelf(SPELL_LEECH_POISON);
events.Repeat(12s);
break;
case EVENT_HADRONOX_GRAB:
me->CastSpell(me, SPELL_WEB_GRAB, false);
events.ScheduleEvent(EVENT_HADRONOX_GRAB, 25s);
DoCastSelf(SPELL_WEB_GRAB);
events.Repeat(25s);
break;
case EVENT_HADRONOX_MOVE4:
me->CastSpell(me, SPELL_WEB_FRONT_DOORS, true);
[[fallthrough]]; /// @todo: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked.
case EVENT_HADRONOX_MOVE3:
if (_crushersLeft > 0)
{
events.Repeat(2s);
break;
}
[[fallthrough]];
case EVENT_HADRONOX_MOVE1:
case EVENT_HADRONOX_MOVE2:
case EVENT_HADRONOX_MOVE3:
Talk(SAY_HADRONOX_EMOTE);
me->GetMotionMaster()->MoveCharge(hadronoxSteps[eventId - 1].GetPositionX(), hadronoxSteps[eventId - 1].GetPositionY(), hadronoxSteps[eventId - 1].GetPositionZ(), 10.0f, 0, nullptr, true);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->Clear();
me->AttackStop();
me->GetMotionMaster()->MovePoint(eventId, hadronoxSteps[eventId - 1]);
break;
case EVENT_CHECK_EVADE:
if (IsInCombatWithPlayer() != _lastPlayerCombatState)
{
_lastPlayerCombatState = !_lastPlayerCombatState;
if (_lastPlayerCombatState)
{
me->SetReactState(REACT_AGGRESSIVE);
if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
me->GetMotionMaster()->Clear();
}
else
EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
}
events.Repeat(1s);
break;
default:
break;
}
DoMeleeAttackIfReady();
}
bool CheckEvadeIfOutOfCombatArea() const override
void MovementInform(uint32 movementType, uint32 pointId) override
{
return me->isActiveObject() && !AnyPlayerValid();
if (movementType != POINT_MOTION_TYPE)
return;
me->SetReactState(REACT_AGGRESSIVE);
if (pointId == EVENT_HADRONOX_MOVE3)
{
DoCastSelf(SPELL_WEB_FRONT_DOORS, true);
_doorsWebbed = true;
}
}
uint32 GetData(uint32 data) const override
{
if (data == me->GetEntry()) // 'Hadronox Denied' achievement
return _doorsWebbed ? 0 : 1;
return 0;
}
private:
uint8 _crushersLeft;
bool _doorsWebbed;
bool _lastPlayerCombatState;
};
CreatureAI* GetAI(Creature* creature) const override
struct npc_hadronox_crusherPackAI : public ScriptedAI
{
return GetAzjolNerubAI<boss_hadronoxAI>(creature);
npc_hadronox_crusherPackAI(Creature* creature, Position const* positions) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _positions(positions), _myPack(SUMMON_GROUP_CRUSHER_NONE), _doFacing(false) { }
virtual void DoEngagedWith() = 0;
virtual void DoEvent(uint32 /*eventId*/) = 0;
void DoAction(int32 action) override
{
if (action == ACTION_PACK_WALK)
{
switch (_myPack)
{
case SUMMON_GROUP_CRUSHER_1:
case SUMMON_GROUP_CRUSHER_2:
case SUMMON_GROUP_CRUSHER_3:
me->GetMotionMaster()->MovePoint(ACTION_PACK_WALK, _positions[_myPack - SUMMON_GROUP_CRUSHER_1]);
break;
default:
break;
}
};
class npc_anub_ar_crusher : public CreatureScript
{
public:
npc_anub_ar_crusher() : CreatureScript("npc_anub_ar_crusher") { }
struct npc_anub_ar_crusherAI : public ScriptedAI
{
npc_anub_ar_crusherAI(Creature* c) : ScriptedAI(c), summons(me) {}
EventMap events;
SummonList summons;
void Reset() override
{
summons.DespawnAll();
events.Reset();
if (me->ToTempSummon())
if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
if (summoner->GetEntry() == me->GetEntry())
{
me->CastSpell(me, RAND(SPELL_SUMMON_ANUBAR_CHAMPION, SPELL_SUMMON_ANUBAR_CRYPT_FIEND, SPELL_SUMMON_ANUBAR_NECROMANCER), true);
me->CastSpell(me, RAND(SPELL_SUMMON_ANUBAR_CHAMPION, SPELL_SUMMON_ANUBAR_CRYPT_FIEND, SPELL_SUMMON_ANUBAR_NECROMANCER), true);
}
}
void JustSummoned(Creature* summon) override
void MovementInform(uint32 type, uint32 id) override
{
if (summon->GetEntry() != me->GetEntry())
{
summon->GetMotionMaster()->MovePoint(0, *me, FORCED_MOVEMENT_NONE, 0.f, false);
summon->GetMotionMaster()->MoveFollow(me, 0.1f, 0.0f + M_PI * 0.3f * summons.size());
}
summons.Summon(summon);
if (type == POINT_MOTION_TYPE && id == ACTION_PACK_WALK)
_doFacing = true;
}
void DoAction(int32 param) override
uint32 GetData(uint32 data) const override
{
if (param == ACTION_DESPAWN_ADDS)
if (data == DATA_CRUSHER_PACK_ID)
return _myPack;
return 0;
}
void SetData(uint32 data, uint32 value) override
{
summons.DoAction(ACTION_DESPAWN_ADDS);
summons.DespawnAll();
if (data == DATA_CRUSHER_PACK_ID)
{
_myPack = SummonGroups(value);
me->SetReactState(_myPack ? REACT_PASSIVE : REACT_AGGRESSIVE);
}
}
void JustEngagedWith(Unit*) override
void JustEngagedWith(Unit* who) override
{
if (me->ToTempSummon())
if (Unit* summoner = me->ToTempSummon()->GetSummonerUnit())
if (summoner->GetEntry() != me->GetEntry())
if (me->HasReactState(REACT_PASSIVE))
{
summoner->GetAI()->DoAction(ACTION_START_EVENT);
me->SummonCreature(NPC_ANUB_AR_CRUSHER, 519.58f, 573.73f, 734.30f, 4.50f);
me->SummonCreature(NPC_ANUB_AR_CRUSHER, 539.38f, 573.25f, 732.20f, 4.738f);
Talk(SAY_CRUSHER_AGGRO);
std::list<Creature*> creatures;
me->GetCreatureListWithEntryInGrid(creatures, { NPC_ANUB_AR_CRUSHER, NPC_ANUB_AR_CHAMPION_PACK, NPC_ANUB_AR_NECROMANCER_PACK, NPC_ANUB_AR_CRYPT_FIEND_PACK }, 40.0f);
for (Creature* creature : creatures)
if (creature->AI()->GetData(DATA_CRUSHER_PACK_ID) == _myPack)
{
creature->SetReactState(REACT_AGGRESSIVE);
creature->AI()->AttackStart(who);
}
}
DoEngagedWith();
ScriptedAI::JustEngagedWith(who);
}
events.ScheduleEvent(EVENT_CRUSHER_SMASH, 8s, 0, 0);
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1s);
void MoveInLineOfSight(Unit* who) override
{
if (!me->HasReactState(REACT_PASSIVE))
{
ScriptedAI::MoveInLineOfSight(who);
return;
}
if (me->CanStartAttack(who) && me->IsWithinDistInMap(who, me->GetAttackDistance(who) + me->m_CombatDistance))
JustEngagedWith(who);
}
void UpdateAI(uint32 diff) override
{
if (_doFacing)
{
_doFacing = false;
me->SetFacingTo(_positions[_myPack - SUMMON_GROUP_CRUSHER_1].GetOrientation());
}
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_CRUSHER_SMASH:
me->CastSpell(me->GetVictim(), SPELL_SMASH, false);
events.ScheduleEvent(EVENT_CRUSHER_SMASH, 15s);
break;
case EVENT_CHECK_HEALTH:
if (me->HealthBelowPct(30))
{
Talk(SAY_CRUSHER_EMOTE);
me->CastSpell(me, SPELL_FRENZY, false);
break;
}
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1s);
break;
}
while (uint32 eventId = events.ExecuteEvent())
DoEvent(eventId);
DoMeleeAttackIfReady();
}
protected:
InstanceScript* const _instance;
Position const* const _positions;
SummonGroups _myPack;
bool _doFacing;
};
CreatureAI* GetAI(Creature* creature) const override
static const Position crusherWaypoints[] =
{
return GetAzjolNerubAI<npc_anub_ar_crusherAI>(creature);
{ 529.6913f, 547.1257f, 731.9155f, 4.799650f },
{ 517.51f , 561.439f , 734.0306f, 4.520403f },
{ 543.414f , 551.728f , 732.0522f, 3.996804f }
};
struct npc_anub_ar_crusher : public npc_hadronox_crusherPackAI
{
explicit npc_anub_ar_crusher(Creature* creature) : npc_hadronox_crusherPackAI(creature, crusherWaypoints), _hadFrenzy(false) { }
void DoEngagedWith() override
{
events.ScheduleEvent(EVENT_CRUSHER_SMASH, 8s, 12s);
if (_myPack != SUMMON_GROUP_CRUSHER_1)
return;
if (_instance->GetBossState(DATA_HADRONOX) == IN_PROGRESS)
return;
if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX))
hadronox->AI()->DoAction(ACTION_CRUSHER_ENGAGED);
Talk(SAY_CRUSHER_AGGRO);
}
void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (_hadFrenzy || !me->HealthBelowPctDamaged(25, damage))
return;
_hadFrenzy = true;
Talk(SAY_CRUSHER_EMOTE);
DoCastSelf(SPELL_FRENZY);
}
void DoEvent(uint32 eventId) override
{
if (eventId == EVENT_CRUSHER_SMASH)
{
DoCastVictim(SPELL_SMASH);
events.Repeat(13s, 21s);
}
}
void JustDied(Unit* killer) override
{
if (Creature* hadronox = _instance->GetCreature(DATA_HADRONOX))
hadronox->AI()->DoAction(ACTION_CRUSHER_DIED);
ScriptedAI::JustDied(killer);
}
private:
bool _hadFrenzy;
};
static const Position championWaypoints[] =
{
{ 539.2076f, 549.7539f, 732.8668f, 4.55531f },
{ 527.3098f, 559.5197f, 732.9407f, 4.742493f },
{ }
};
struct npc_anub_ar_crusher_champion : public npc_hadronox_crusherPackAI
{
explicit npc_anub_ar_crusher_champion(Creature* creature) : npc_hadronox_crusherPackAI(creature, championWaypoints) { }
void DoEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_REND:
DoCastVictim(SPELL_REND);
events.Repeat(12s, 16s);
break;
case EVENT_PUMMEL:
DoCastVictim(SPELL_PUMMEL);
events.Repeat(12s, 17s);
break;
default:
break;
}
}
void DoEngagedWith() override
{
events.ScheduleEvent(EVENT_REND, 4s, 8s);
events.ScheduleEvent(EVENT_PUMMEL, 15s, 19s);
}
};
static const Position cryptFiendWaypoints[] =
{
{ 520.3911f, 548.7895f, 732.0118f, 5.0091f },
{ },
{ 550.9611f, 545.1674f, 731.9031f, 3.996804f }
};
struct npc_anub_ar_crusher_crypt_fiend : public npc_hadronox_crusherPackAI
{
explicit npc_anub_ar_crusher_crypt_fiend(Creature* creature) : npc_hadronox_crusherPackAI(creature, cryptFiendWaypoints) { }
void DoEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CRUSHING_WEBS:
DoCastVictim(SPELL_CRUSHING_WEBS);
events.Repeat(12s, 16s);
break;
case EVENT_INFECTED_WOUND:
DoCastVictim(SPELL_INFECTED_WOUND);
events.Repeat(16s, 25s);
break;
default:
break;
}
}
void DoEngagedWith() override
{
events.ScheduleEvent(EVENT_CRUSHING_WEBS, 4s, 8s);
events.ScheduleEvent(EVENT_INFECTED_WOUND, 15s, 19s);
}
};
static const Position necromancerWaypoints[] =
{
{ },
{ 507.6937f, 563.3471f, 734.8986f, 4.520403f },
{ 535.1049f, 552.8961f, 732.8441f, 3.996804f },
};
struct npc_anub_ar_crusher_necromancer : public npc_hadronox_crusherPackAI
{
explicit npc_anub_ar_crusher_necromancer(Creature* creature) : npc_hadronox_crusherPackAI(creature, necromancerWaypoints) { }
void DoEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_SHADOW_BOLT:
DoCastVictim(SPELL_SHADOW_BOLT);
events.Repeat(2s, 5s);
break;
case EVENT_ANIMATE_BONES:
DoCastVictim(RAND(SPELL_ANIMATE_BONES_2, SPELL_ANIMATE_BONES_1));
events.Repeat(35s, 50s);
break;
default:
break;
}
}
void DoEngagedWith() override
{
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2s, 4s);
events.ScheduleEvent(EVENT_ANIMATE_BONES, 37s, 45s);
}
};
@ -330,7 +609,7 @@ class spell_hadronox_summon_periodic_aura : public AuraScript
PrepareAuraScript(spell_hadronox_summon_periodic_aura);
public:
spell_hadronox_summon_periodic_aura(uint32 delay, uint32 spellEntry) : _delay(delay), _spellEntry(spellEntry) { }
spell_hadronox_summon_periodic_aura(int32 delay, uint32 spellEntry) : _delay(delay), _spellEntry(spellEntry) { }
bool Validate(SpellInfo const* /*spellInfo*/) override
{
@ -342,7 +621,7 @@ public:
PreventDefaultAction();
Unit* owner = GetUnitOwner();
if (InstanceScript* instance = owner->GetInstanceScript())
if (!instance->IsBossDone(DATA_HADRONOX))
if (!instance->IsBossDone(DATA_HADRONOX) != NOT_STARTED)
{
if (!owner->HasAura(SPELL_WEB_FRONT_DOORS))
owner->CastSpell(owner, _spellEntry, true);
@ -363,7 +642,7 @@ public:
}
private:
uint32 _delay;
int32 _delay;
uint32 _spellEntry;
};
@ -389,12 +668,29 @@ class spell_hadronox_leech_poison_aura : public AuraScript
}
};
class spell_hadronox_web_grab : public SpellScript
{
PrepareSpellScript(spell_hadronox_web_grab);
// hack to avoid pulling Anub'ar Crusher through the floor and causing Hadronox to evade
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if([&](WorldObject* target) -> bool
{
return target->GetEntry() == NPC_ANUB_AR_CRUSHER;
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hadronox_web_grab::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
class achievement_hadronox_denied : public AchievementCriteriaScript
{
public:
achievement_hadronox_denied() : AchievementCriteriaScript("achievement_hadronox_denied")
{
}
achievement_hadronox_denied() : AchievementCriteriaScript("achievement_hadronox_denied") { }
bool OnCheck(Player* /*player*/, Unit* target, uint32 /*criteria_id*/) override
{
@ -407,11 +703,15 @@ public:
void AddSC_boss_hadronox()
{
new boss_hadronox();
new npc_anub_ar_crusher();
RegisterSpellScriptWithArgs(spell_hadronox_summon_periodic_aura, "spell_hadronox_summon_periodic_champion_aura", 15000, SPELL_SUMMON_ANUBAR_CHAMPION);
RegisterSpellScriptWithArgs(spell_hadronox_summon_periodic_aura, "spell_hadronox_summon_periodic_necromancer_aura", 10000, SPELL_SUMMON_ANUBAR_NECROMANCER);
RegisterSpellScriptWithArgs(spell_hadronox_summon_periodic_aura, "spell_hadronox_summon_periodic_crypt_fiend_aura", 5000, SPELL_SUMMON_ANUBAR_CRYPT_FIEND);
RegisterAzjolNerubCreatureAI(boss_hadronox);
RegisterAzjolNerubCreatureAI(npc_anub_ar_crusher);
RegisterAzjolNerubCreatureAI(npc_anub_ar_crusher_champion);
RegisterAzjolNerubCreatureAI(npc_anub_ar_crusher_crypt_fiend);
RegisterAzjolNerubCreatureAI(npc_anub_ar_crusher_necromancer);
RegisterSpellScriptWithArgs(spell_hadronox_summon_periodic_aura, "spell_hadronox_summon_periodic_champion_aura", 15'000, SPELL_SUMMON_ANUBAR_CHAMPION);
RegisterSpellScriptWithArgs(spell_hadronox_summon_periodic_aura, "spell_hadronox_summon_periodic_necromancer_aura", 10'000, SPELL_SUMMON_ANUBAR_NECROMANCER);
RegisterSpellScriptWithArgs(spell_hadronox_summon_periodic_aura, "spell_hadronox_summon_periodic_crypt_fiend_aura", 5'000, SPELL_SUMMON_ANUBAR_CRYPT_FIEND);
RegisterSpellScript(spell_hadronox_leech_poison_aura);
RegisterSpellScript(spell_hadronox_web_grab);
new achievement_hadronox_denied();
}

View File

@ -47,6 +47,7 @@ ObjectData const summonData[] =
{ NPC_ANUB_AR_CHAMPION, DATA_HADRONOX },
{ NPC_ANUB_AR_NECROMANCER, DATA_HADRONOX },
{ NPC_ANUB_AR_CRYPTFIEND, DATA_HADRONOX },
{ NPC_WORLD_TRIGGER_LAOI, DATA_HADRONOX },
{ 0, 0 }
};