fix(Scripts/BlackwingLair): Nefarian (#10536)

This commit is contained in:
Nefertumm
2022-03-09 13:32:09 -03:00
committed by GitHub
parent 59b5568d4f
commit 707968ee95
6 changed files with 842 additions and 222 deletions
@@ -0,0 +1,53 @@
INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1643946548773673200');
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_class_call_handler', 'spell_corrupted_totems', 'spell_class_call_polymorph', 'aura_class_call_wild_magic', 'aura_class_call_siphon_blessing', 'aura_class_call_berserk', 'spell_shadowblink');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(23410, 'spell_class_call_handler'), -- Mage
(23397, 'spell_class_call_handler'), -- Warrior
(23398, 'spell_class_call_handler'), -- Druid
(23401, 'spell_class_call_handler'), -- Priest
(23418, 'spell_class_call_handler'), -- Paladin
(23425, 'spell_class_call_handler'), -- Shaman
(23427, 'spell_class_call_handler'), -- Warlock
(23436, 'spell_class_call_handler'), -- Hunter
(23414, 'spell_class_call_handler'), -- Rogue
(23424, 'spell_corrupted_totems'),
(23603, 'spell_class_call_polymorph'),
(23410, 'aura_class_call_wild_magic'),
(23418, 'aura_class_call_siphon_blessing'),
(23397, 'aura_class_call_berserk'),
(22664, 'spell_shadowblink');
DELETE FROM `spell_target_position` WHERE `ID` IN (22668, 22669, 22670, 22671, 22672, 22673, 22674, 22675, 22676);
INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`) VALUES
(22668, 0, 469, -7581.11, -1216.19, 476.800, 0),
(22669, 0, 469, -7561.54, -1244.01, 476.800, 0),
(22670, 0, 469, -7542.47, -1191.92, 476.355, 0),
(22671, 0, 469, -7538.63, -1273.64, 476.800, 0),
(22672, 0, 469, -7524.36, -1219.12, 476.794, 0),
(22673, 0, 469, -7506.58, -1165.26, 476.796, 0),
(22674, 0, 469, -7500.70, -1249.89, 476.798, 0),
(22675, 0, 469, -7486.36, -1194.32, 476.800, 0),
(22676, 0, 469, -7469.93, -1227.93, 476.777, 0);
DELETE FROM `waypoint_data` WHERE `id` = 11583;
INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
(11583, 1, -7348.85, -1495.13, 552.515, 2.190162, 0, 2, 0, 100, 0),
(11583, 2, -7348.54, -1494.18, 552.515, 2.190162, 0, 2, 0, 100, 0),
(11583, 3, -7392.87, -1475.70, 544.619, 2.190162, 0, 2, 0, 100, 0),
(11583, 4, -7423.42, -1437.66, 535.314, 2.190162, 0, 2, 0, 100, 0),
(11583, 5, -7445.25, -1402.11, 523.842, 2.190162, 0, 2, 0, 100, 0),
(11583, 6, -7460.38, -1372.60, 513.092, 2.190162, 0, 2, 0, 100, 0),
(11583, 7, -7479.81, -1331.76, 498.759, 2.190162, 0, 2, 0, 100, 0),
(11583, 8, -7492.58, -1295.35, 488.091, 2.190162, 0, 2, 0, 100, 0),
(11583, 9, -7502.00, -1256.50, 476.758, 2.174731, 0, 2, 0, 100, 0);
UPDATE `creature_template_movement` SET `Flight` = 2 WHERE `CreatureID` = 11583;
UPDATE `creature_template` SET `unit_flags` = `unit_flags`|2|256|131072|33554432, `flags_extra` = `flags_extra`|128|256 WHERE `entry` = 14667;
UPDATE `creature_template` SET `unit_flags` = `unit_flags`|131072, `flags_extra` = `flags_extra`|1|256|16384|4194304, `mechanic_immune_mask`=`mechanic_immune_mask`|1|2|4|8|16|128|256|512|1024|2048|4096|8192|16384|65536|131072|4194304|8388608|33554432|67108864|536870912 , `ScriptName` = 'npc_corrupted_totem' WHERE `entry` IN (14662, 14663, 14664, 14666);
UPDATE `creature_template` SET `mingold` = 0, `maxgold` = 0 WHERE `entry` = 14668;
DELETE FROM `creature_loot_template` WHERE `entry` = 11583 AND `Item` = 19364;
+8
View File
@@ -6377,6 +6377,14 @@ SpellCastResult Spell::CheckCast(bool strict)
} }
break; break;
} }
case SPELL_AURA_MOD_SHAPESHIFT:
{
if (m_caster && m_caster->HasAura(23397)) // Nefarian Class Call (Warrior): Berserk -- Nefertum: I don't really like this but I didn't find another way.
{
return SPELL_FAILED_NOT_SHAPESHIFT;
}
break;
}
default: default:
break; break;
} }
+13
View File
@@ -1590,6 +1590,19 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL); addhealth = unitTarget->SpellHealingBonusTaken(caster, m_spellInfo, addhealth, HEAL);
} }
// Implemented this way as there is no other way to do it currently (that I know :P)...
if (caster->ToPlayer() && caster->ToPlayer()->HasAura(23401)) // Nefarian Corrupted Healing (priest)
{
if (m_spellInfo->Effects[EFFECT_0].ApplyAuraName != SPELL_AURA_PERIODIC_HEAL ||
m_spellInfo->Effects[EFFECT_1].ApplyAuraName != SPELL_AURA_PERIODIC_HEAL ||
m_spellInfo->Effects[EFFECT_2].ApplyAuraName != SPELL_AURA_PERIODIC_HEAL)
{
m_damage = 0;
caster->CastSpell(unitTarget, 23402, false); // Nefarian Corrupted Healing Periodic Damage effect.
return;
}
}
m_damage -= addhealth; m_damage -= addhealth;
} }
} }
@@ -4154,6 +4154,20 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_1].SpellClassMask[1] = 0x00020000; spellInfo->Effects[EFFECT_1].SpellClassMask[1] = 0x00020000;
}); });
// Nefarian: Shadowbolt, Shadow Command
ApplySpellFix({ 22667, 22677 }, [](SpellInfo* spellInfo)
{
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(152); // 150 yards
});
// Shadowbolt Volley
ApplySpellFix({ 22665 }, [](SpellInfo* spellInfo)
{
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(152); // 150 yards
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(41); // 150 yards
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
});
// Manastorm // Manastorm
ApplySpellFix({ 21097 }, [](SpellInfo* spellInfo) ApplySpellFix({ 21097 }, [](SpellInfo* spellInfo)
{ {
@@ -4180,6 +4194,12 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP;
}); });
// Improved Blessing Protection (Nefarian Class Call)
ApplySpellFix({ 23415 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_DEST_TARGET_ENEMY);
});
// Bestial Wrath // Bestial Wrath
ApplySpellFix({ 19574 }, [](SpellInfo* spellInfo) ApplySpellFix({ 19574 }, [](SpellInfo* spellInfo)
{ {
@@ -99,4 +99,6 @@ inline AI* GetBlackwingLairAI(T* obj)
return GetInstanceAI<AI>(obj, BWLScriptName); return GetInstanceAI<AI>(obj, BWLScriptName);
} }
#define RegisterBlackwingLairCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetBlackwingLairAI)
#endif #endif
@@ -22,30 +22,37 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "ScriptedGossip.h" #include "ScriptedGossip.h"
#include "SpellScript.h"
#include "TemporarySummon.h" #include "TemporarySummon.h"
#include "blackwing_lair.h" #include "blackwing_lair.h"
#include "TaskScheduler.h"
enum Events enum Events
{ {
// Victor Nefarius // Victor Nefarius
EVENT_SPAWN_ADD = 1, EVENT_SPAWN_ADD = 1,
EVENT_SHADOW_BOLT = 2, EVENT_START_EVENT,
EVENT_FEAR = 3, EVENT_SHADOW_BOLT,
EVENT_MIND_CONTROL = 4, EVENT_FEAR,
EVENT_SILENCE,
EVENT_MIND_CONTROL,
EVENT_SHADOWBLINK,
// Nefarian // Nefarian
EVENT_SHADOWFLAME = 5, EVENT_SHADOWFLAME,
EVENT_VEILOFSHADOW = 6, EVENT_VEILOFSHADOW,
EVENT_CLEAVE = 7, EVENT_CLEAVE,
EVENT_TAILLASH = 8, EVENT_TAILLASH,
EVENT_CLASSCALL = 9, EVENT_CLASSCALL,
// UBRS // UBRS
EVENT_CHAOS_1 = 10, EVENT_CHAOS_1,
EVENT_CHAOS_2 = 11, EVENT_CHAOS_2,
EVENT_PATH_2 = 12, EVENT_PATH_2,
EVENT_PATH_3 = 13, EVENT_PATH_3,
EVENT_SUCCESS_1 = 14, EVENT_SUCCESS_1,
EVENT_SUCCESS_2 = 15, EVENT_SUCCESS_2,
EVENT_SUCCESS_3 = 16, EVENT_SUCCESS_3,
ACTION_RESET = 0
}; };
enum Says enum Says
@@ -60,7 +67,7 @@ enum Says
SAY_GAMESBEGIN_2 = 13, SAY_GAMESBEGIN_2 = 13,
// Nefarian // Nefarian
SAY_RANDOM = 0, SAY_INTRO = 0,
SAY_RAISE_SKELETONS = 1, SAY_RAISE_SKELETONS = 1,
SAY_SLAY = 2, SAY_SLAY = 2,
SAY_DEATH = 3, SAY_DEATH = 3,
@@ -86,7 +93,8 @@ enum Gossip
enum Paths enum Paths
{ {
NEFARIUS_PATH_2 = 1379671, NEFARIUS_PATH_2 = 1379671,
NEFARIUS_PATH_3 = 1379672 NEFARIUS_PATH_3 = 1379672,
NEFARIAN_PATH = 11583
}; };
enum GameObjects enum GameObjects
@@ -104,6 +112,10 @@ enum Creatures
NPC_BLACK_DRAKANOID = 14265, NPC_BLACK_DRAKANOID = 14265,
NPC_CHROMATIC_DRAKANOID = 14302, NPC_CHROMATIC_DRAKANOID = 14302,
NPC_BONE_CONSTRUCT = 14605, NPC_BONE_CONSTRUCT = 14605,
NPC_TOTEM_C_FIRE_NOVA = 14662,
NPC_TOTEM_C_STONESKIN = 14663,
NPC_TOTEM_C_HEALING = 14664,
NPC_TOTEM_C_WINDFURY = 14666,
// UBRS // UBRS
NPC_GYTH = 10339 NPC_GYTH = 10339
}; };
@@ -117,8 +129,10 @@ enum Spells
// BWL Spells // BWL Spells
SPELL_SHADOWBOLT = 22677, SPELL_SHADOWBOLT = 22677,
SPELL_SHADOWBOLT_VOLLEY = 22665, SPELL_SHADOWBOLT_VOLLEY = 22665,
SPELL_SILENCE = 22666,
SPELL_SHADOW_COMMAND = 22667, SPELL_SHADOW_COMMAND = 22667,
SPELL_FEAR = 22678, SPELL_FEAR = 22678,
SPELL_SHADOWBLINK = 22664,
SPELL_NEFARIANS_BARRIER = 22663, SPELL_NEFARIANS_BARRIER = 22663,
@@ -126,7 +140,7 @@ enum Spells
SPELL_SHADOWFLAME_INITIAL = 22992, SPELL_SHADOWFLAME_INITIAL = 22992,
SPELL_SHADOWFLAME = 22539, SPELL_SHADOWFLAME = 22539,
SPELL_BELLOWINGROAR = 22686, SPELL_BELLOWINGROAR = 22686,
SPELL_VEILOFSHADOW = 7068, SPELL_VEILOFSHADOW = 22687,
SPELL_CLEAVE = 20691, SPELL_CLEAVE = 20691,
SPELL_TAILLASH = 23364, SPELL_TAILLASH = 23364,
@@ -134,17 +148,23 @@ enum Spells
SPELL_WARRIOR = 23397, // beserk SPELL_WARRIOR = 23397, // beserk
SPELL_DRUID = 23398, // cat form SPELL_DRUID = 23398, // cat form
SPELL_PRIEST = 23401, // corrupted healing SPELL_PRIEST = 23401, // corrupted healing
SPELL_PALADIN = 23418, // syphon blessing SPELL_PALADIN = 23418, // siphon blessing
SPELL_SHAMAN = 23425, // totems SPELL_SHAMAN = 23425, // totems
SPELL_WARLOCK = 23427, // infernals SPELL_WARLOCK = 23427, // infernals
SPELL_HUNTER = 23436, // bow broke SPELL_HUNTER = 23436, // bow broke
SPELL_ROGUE = 23414, // Paralise SPELL_ROGUE = 23414, // Paralise
SPELL_DEATH_KNIGHT = 49576 // Death Grip SPELL_DEATH_KNIGHT = 49576, // Death Grip
SPELL_ROOT_SELF = 17507,
// 19484 // Class Call effects
// 22664 SPELL_POLYMORPH = 23603,
// 22674 SPELL_BLESSING_PROTECTION = 23415,
// 22666 SPELL_SUMMON_INFERNALS = 23426,
SPELL_WARRIOR_BERSERK = 2458,
SPELL_CORRUPTED_FIRE_NOVA_TOTEM = 23419,
SPELL_CORRUPTED_STONESKIN_TOTEM = 23420,
SPELL_CORRUPTED_HEALING_TOTEM = 23422,
SPELL_CORRUPTED_WINDFURY_TOTEM = 23423
}; };
Position const DrakeSpawnLoc[2] = // drakonid Position const DrakeSpawnLoc[2] = // drakonid
@@ -153,11 +173,7 @@ Position const DrakeSpawnLoc[2] = // drakonid
{-7514.598633f, -1150.448853f, 476.796570f, 3.0f} {-7514.598633f, -1150.448853f, 476.796570f, 3.0f}
}; };
Position const NefarianLoc[2] = Position const NefarianSpawn = { -7348.849f, -1495.134f, 552.5152f, 1.798f };
{
{-7449.763672f, -1387.816040f, 526.783691f, 3.0f}, // nefarian spawn
{-7535.456543f, -1279.562500f, 476.798706f, 3.0f} // nefarian move
};
uint32 const Entry[5] = {NPC_BRONZE_DRAKANOID, NPC_BLUE_DRAKANOID, NPC_RED_DRAKANOID, NPC_GREEN_DRAKANOID, NPC_BLACK_DRAKANOID}; uint32 const Entry[5] = {NPC_BRONZE_DRAKANOID, NPC_BLUE_DRAKANOID, NPC_RED_DRAKANOID, NPC_GREEN_DRAKANOID, NPC_BLACK_DRAKANOID};
@@ -175,7 +191,7 @@ public:
void Initialize() void Initialize()
{ {
SpawnedAdds = 0; KilledAdds = 0;
} }
void Reset() override void Reset() override
@@ -193,36 +209,42 @@ public:
me->SetFaction(FACTION_FRIENDLY); me->SetFaction(FACTION_FRIENDLY);
me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR); me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR);
me->RemoveAura(SPELL_NEFARIANS_BARRIER); me->RemoveAura(SPELL_NEFARIANS_BARRIER);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
} }
} }
bool CanAIAttack(Unit const* /*target*/) const override { return me->IsVisible(); }
void JustReachedHome() override void JustReachedHome() override
{ {
Reset(); Reset();
} }
void BeginEvent(Player* target) void DoAction(int32 action) override
{
if (action == ACTION_RESET)
{
me->RemoveAura(SPELL_ROOT_SELF);
summons.DespawnAll();
}
}
void BeginEvent()
{ {
_EnterCombat(); _EnterCombat();
Talk(SAY_GAMESBEGIN_2); Talk(SAY_GAMESBEGIN_2);
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
DoCast(me, SPELL_NEFARIANS_BARRIER); DoCast(me, SPELL_NEFARIANS_BARRIER);
me->SetStandState(UNIT_STAND_STATE_STAND); SetCombatMovement(false);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true));
AttackStart(target); events.ScheduleEvent(EVENT_SHADOWBLINK, 500);
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 10000)); events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 10000));
events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000)); events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000));
events.ScheduleEvent(EVENT_SILENCE, urand(20000, 25000));
events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000)); events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000));
events.ScheduleEvent(EVENT_SPAWN_ADD, 10000); events.ScheduleEvent(EVENT_SPAWN_ADD, 10000);
} }
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{ {
if (summon->GetEntry() != NPC_NEFARIAN) if (summon->GetEntry() != NPC_NEFARIAN)
{ {
@@ -230,10 +252,11 @@ public:
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
summon->SetReactState(REACT_PASSIVE); summon->SetReactState(REACT_PASSIVE);
summon->SetStandState(UNIT_STAND_STATE_DEAD); summon->SetStandState(UNIT_STAND_STATE_DEAD);
++KilledAdds;
} }
} }
void JustSummoned(Creature* /*summon*/) override { } void JustSummoned(Creature* summon) override { summons.Summon(summon); }
void SetData(uint32 type, uint32 data) override void SetData(uint32 type, uint32 data) override
{ {
@@ -292,6 +315,9 @@ public:
case EVENT_PATH_3: case EVENT_PATH_3:
me->GetMotionMaster()->MovePath(NEFARIUS_PATH_3, false); me->GetMotionMaster()->MovePath(NEFARIUS_PATH_3, false);
break; break;
case EVENT_START_EVENT:
BeginEvent();
break;
default: default:
break; break;
} }
@@ -300,7 +326,7 @@ public:
} }
// Only do this if we haven't spawned nefarian yet // Only do this if we haven't spawned nefarian yet
if (UpdateVictim() && SpawnedAdds <= 42) if (UpdateVictim() && KilledAdds <= 42)
{ {
events.Update(diff); events.Update(diff);
@@ -315,11 +341,10 @@ public:
switch (urand(0, 1)) switch (urand(0, 1))
{ {
case 0: case 0:
DoCastVictim(SPELL_SHADOWBOLT_VOLLEY); DoCastAOE(SPELL_SHADOWBOLT_VOLLEY);
break; break;
case 1: case 1:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true)) DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f);
DoCast(target, SPELL_SHADOWBOLT);
break; break;
} }
DoResetThreat(); DoResetThreat();
@@ -330,11 +355,19 @@ public:
DoCast(target, SPELL_FEAR); DoCast(target, SPELL_FEAR);
events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000)); events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000));
break; break;
case EVENT_SILENCE:
DoCastRandomTarget(SPELL_SILENCE, 0, 150.f);
events.ScheduleEvent(EVENT_SILENCE, urand(14000, 23000));
break;
case EVENT_MIND_CONTROL: case EVENT_MIND_CONTROL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true)) if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true))
DoCast(target, SPELL_SHADOW_COMMAND); DoCast(target, SPELL_SHADOW_COMMAND);
events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000)); events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000));
break; break;
case EVENT_SHADOWBLINK:
DoCastSelf(SPELL_SHADOWBLINK);
events.ScheduleEvent(EVENT_SHADOWBLINK, urand(30000, 40000));
break;
case EVENT_SPAWN_ADD: case EVENT_SPAWN_ADD:
for (uint8 i=0; i<2; ++i) for (uint8 i=0; i<2; ++i)
{ {
@@ -349,19 +382,20 @@ public:
dragon->AI()->AttackStart(me->GetVictim()); dragon->AI()->AttackStart(me->GetVictim());
} }
if (++SpawnedAdds >= 42) if (KilledAdds >= 42)
{ {
if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianLoc[0])) if (Creature* nefarian = me->SummonCreature(NPC_NEFARIAN, NefarianSpawn))
{ {
nefarian->setActive(true); nefarian->setActive(true);
nefarian->SetCanFly(true); nefarian->SetCanFly(true);
nefarian->SetDisableGravity(true); nefarian->SetDisableGravity(true);
nefarian->CastSpell(nullptr, SPELL_SHADOWFLAME_INITIAL); nefarian->GetMotionMaster()->MovePath(NEFARIAN_PATH, false);
nefarian->GetMotionMaster()->MovePoint(1, NefarianLoc[1]);
} }
events.CancelEvent(EVENT_MIND_CONTROL); events.CancelEvent(EVENT_MIND_CONTROL);
events.CancelEvent(EVENT_FEAR); events.CancelEvent(EVENT_FEAR);
events.CancelEvent(EVENT_SHADOW_BOLT); events.CancelEvent(EVENT_SHADOW_BOLT);
events.CancelEvent(EVENT_SILENCE);
DoCastSelf(SPELL_ROOT_SELF, true);
me->SetVisible(false); me->SetVisible(false);
return; return;
} }
@@ -387,12 +421,16 @@ public:
CloseGossipMenuFor(player); CloseGossipMenuFor(player);
Talk(SAY_GAMESBEGIN_1); Talk(SAY_GAMESBEGIN_1);
BeginEvent(player); events.ScheduleEvent(EVENT_START_EVENT, 4000);
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
} }
} }
private: private:
uint32 SpawnedAdds; uint32 KilledAdds;
}; };
CreatureAI* GetAI(Creature* creature) const override CreatureAI* GetAI(Creature* creature) const override
@@ -401,14 +439,9 @@ public:
} }
}; };
class boss_nefarian : public CreatureScript struct boss_nefarian : public BossAI
{ {
public: boss_nefarian(Creature* creature) : BossAI(creature, DATA_NEFARIAN), _introDone(false)
boss_nefarian() : CreatureScript("boss_nefarian") { }
struct boss_nefarianAI : public BossAI
{
boss_nefarianAI(Creature* creature) : BossAI(creature, DATA_NEFARIAN)
{ {
Initialize(); Initialize();
} }
@@ -416,30 +449,30 @@ public:
void Initialize() void Initialize()
{ {
Phase3 = false; Phase3 = false;
canDespawn = false;
DespawnTimer = 30000;
} }
void Reset() override void Reset() override
{ {
Initialize(); Initialize();
me->SetReactState(REACT_PASSIVE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetCanFly(true);
me->SetDisableGravity(true);
if (_introDone) // already in combat, reset properly.
{
_Reset();
if (Unit* victor = me->FindNearestCreature(NPC_VICTOR_NEFARIUS, 200.f, true))
{
if (victor->ToCreature() && victor->ToCreature()->AI())
{
victor->ToCreature()->AI()->DoAction(ACTION_RESET);
}
}
me->DespawnOrUnsummon();
}
} }
void JustReachedHome() override void EnterCombat(Unit* /*who*/) override {}
{
canDespawn = true;
}
void EnterCombat(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_SHADOWFLAME, 12000);
events.ScheduleEvent(EVENT_FEAR, urand(25000, 35000));
events.ScheduleEvent(EVENT_VEILOFSHADOW, urand(25000, 35000));
events.ScheduleEvent(EVENT_CLEAVE, 7000);
//events.ScheduleEvent(EVENT_TAILLASH, 10000);
events.ScheduleEvent(EVENT_CLASSCALL, urand(30000, 35000));
Talk(SAY_RANDOM);
}
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
@@ -450,50 +483,70 @@ public:
void KilledUnit(Unit* victim) override void KilledUnit(Unit* victim) override
{ {
if (rand32() % 5) if (rand32() % 5)
{
return; return;
}
Talk(SAY_SLAY, victim); Talk(SAY_SLAY, victim);
} }
void MovementInform(uint32 type, uint32 id) override void MovementInform(uint32 type, uint32 id) override
{ {
if (type != POINT_MOTION_TYPE) if (type != WAYPOINT_MOTION_TYPE)
return;
if (id == 1)
{ {
return;
}
if (id == 3)
{
Talk(SAY_INTRO);
}
if (id == 5)
{
DoCastAOE(SPELL_SHADOWFLAME_INITIAL);
}
}
void PathEndReached(uint32 /*pathId*/) override
{
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
me->SetCanFly(false);
me->SetDisableGravity(false);
Position land = me->GetPosition();
me->GetMotionMaster()->MoveLand(0, land, 8.5f);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->GetMotionMaster()->MoveIdle();
me->SetReactState(REACT_AGGRESSIVE);
DoZoneInCombat(); DoZoneInCombat();
if (me->GetVictim()) if (me->GetVictim())
{
AttackStart(me->GetVictim()); AttackStart(me->GetVictim());
} }
events.ScheduleEvent(EVENT_SHADOWFLAME, 12000);
events.ScheduleEvent(EVENT_FEAR, urand(25000, 35000));
events.ScheduleEvent(EVENT_VEILOFSHADOW, urand(25000, 35000));
events.ScheduleEvent(EVENT_CLEAVE, 7000);
events.ScheduleEvent(EVENT_TAILLASH, 10000);
events.ScheduleEvent(EVENT_CLASSCALL, urand(30000, 35000));
_introDone = true;
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (canDespawn && DespawnTimer <= diff)
{
instance->SetBossState(DATA_NEFARIAN, FAIL);
std::list<Creature*> constructList;
me->GetCreatureListWithEntryInGrid(constructList, NPC_BONE_CONSTRUCT, 500.0f);
for (std::list<Creature*>::const_iterator itr = constructList.begin(); itr != constructList.end(); ++itr)
(*itr)->DespawnOrUnsummon();
}
else
{
DespawnTimer -= diff;
}
if (!UpdateVictim()) if (!UpdateVictim())
{
return; return;
}
if (canDespawn)
canDespawn = false;
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
}
while (uint32 eventId = events.ExecuteEvent()) while (uint32 eventId = events.ExecuteEvent())
{ {
@@ -522,6 +575,7 @@ public:
break; break;
case EVENT_CLASSCALL: case EVENT_CLASSCALL:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true)) if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
{
switch (target->getClass()) switch (target->getClass())
{ {
case CLASS_MAGE: case CLASS_MAGE:
@@ -562,18 +616,27 @@ public:
break; break;
case CLASS_DEATH_KNIGHT: case CLASS_DEATH_KNIGHT:
Talk(SAY_DEATH_KNIGHT); Talk(SAY_DEATH_KNIGHT);
DoCast(me, SPELL_DEATH_KNIGHT); me->GetMap()->DoForAllPlayers([&](Player* p)
{
if (!p->IsGameMaster())
{
me->CastSpell(p, SPELL_DEATH_KNIGHT, true);
}
});
break; break;
default: default:
break; break;
} }
}
events.ScheduleEvent(EVENT_CLASSCALL, urand(30000, 35000)); events.ScheduleEvent(EVENT_CLASSCALL, urand(30000, 35000));
break; break;
} }
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
{
return; return;
} }
}
// Phase3 begins when health below 20 pct // Phase3 begins when health below 20 pct
if (!Phase3 && HealthBelowPct(20)) if (!Phase3 && HealthBelowPct(20))
@@ -581,6 +644,7 @@ public:
std::list<Creature*> constructList; std::list<Creature*> constructList;
me->GetCreatureListWithEntryInGrid(constructList, NPC_BONE_CONSTRUCT, 500.0f); me->GetCreatureListWithEntryInGrid(constructList, NPC_BONE_CONSTRUCT, 500.0f);
for (std::list<Creature*>::const_iterator itr = constructList.begin(); itr != constructList.end(); ++itr) for (std::list<Creature*>::const_iterator itr = constructList.begin(); itr != constructList.end(); ++itr)
{
if ((*itr) && !(*itr)->IsAlive()) if ((*itr) && !(*itr)->IsAlive())
{ {
(*itr)->Respawn(); (*itr)->Respawn();
@@ -589,6 +653,7 @@ public:
(*itr)->SetReactState(REACT_AGGRESSIVE); (*itr)->SetReactState(REACT_AGGRESSIVE);
(*itr)->SetStandState(UNIT_STAND_STATE_STAND); (*itr)->SetStandState(UNIT_STAND_STATE_STAND);
} }
}
Phase3 = true; Phase3 = true;
Talk(SAY_RAISE_SKELETONS); Talk(SAY_RAISE_SKELETONS);
@@ -597,20 +662,479 @@ public:
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
private: private:
bool canDespawn;
uint32 DespawnTimer;
bool Phase3; bool Phase3;
}; bool _introDone;
};
CreatureAI* GetAI(Creature* creature) const override enum TotemSpells
{
AURA_AVOIDANCE = 23198,
SPELL_STONESKIN_EFFECT = 10405,
SPELL_HEALING_EFFECT = 10461,
SPELL_WINDFURY_EFFECT = 8515,
SPELL_FIRE_NOVA_EFFECT = 11307
};
struct npc_corrupted_totem : public ScriptedAI
{
npc_corrupted_totem(Creature* creature) : ScriptedAI(creature)
{ {
return GetBlackwingLairAI<boss_nefarianAI>(creature); uint32 hp = urand(200, 2000);
me->SetMaxHealth(hp);
me->SetHealth(hp);
_auraAdded = false;
Reset();
}
void Reset() override
{
me->AddUnitState(UNIT_STATE_ROOT);
if (!me->HasAura(SPELL_ROOT_SELF))
{
me->AddAura(SPELL_ROOT_SELF, me);
}
me->AddAura(AURA_AVOIDANCE, me);
_scheduler.CancelAll();
}
void SetAura(bool apply) const
{
uint32 spellId = 0;
switch (me->GetEntry())
{
case NPC_TOTEM_C_STONESKIN:
spellId = SPELL_STONESKIN_EFFECT;
break;
case NPC_TOTEM_C_HEALING:
spellId = SPELL_HEALING_EFFECT;
break;
case NPC_TOTEM_C_WINDFURY:
spellId = SPELL_WINDFURY_EFFECT;
break;
}
if (!spellId)
{
return;
}
std::vector<uint32> mobsEntries;
mobsEntries.push_back(NPC_NEFARIAN);
mobsEntries.push_back(NPC_BONE_CONSTRUCT);
mobsEntries.push_back(NPC_BRONZE_DRAKANOID);
mobsEntries.push_back(NPC_BLUE_DRAKANOID);
mobsEntries.push_back(NPC_RED_DRAKANOID);
mobsEntries.push_back(NPC_GREEN_DRAKANOID);
mobsEntries.push_back(NPC_BLACK_DRAKANOID);
mobsEntries.push_back(NPC_CHROMATIC_DRAKANOID);
for (auto& entry : mobsEntries)
{
std::list<Creature*> tmpMobList;
GetCreatureListWithEntryInGrid(tmpMobList, me, entry, 100.f);
while (!tmpMobList.empty())
{
Creature* curr = tmpMobList.front();
tmpMobList.pop_front();
if (!curr->IsAlive())
{
continue;
}
if (apply && me->IsAlive())
{
if (me->IsWithinDistInMap(curr, 40.f))
{
if (!curr->HasAura(spellId))
{
curr->AddAura(spellId, curr);
}
}
else
{
if (curr->HasAura(spellId))
{
curr->RemoveAurasDueToSpell(spellId);
}
}
}
else
{
curr->RemoveAurasDueToSpell(spellId);
}
}
}
}
void IsSummonedBy(Unit* /*summoner*/) override
{
me->SetInCombatWithZone();
_scheduler
.Schedule(1ms, [this](TaskContext context)
{
if (me->GetEntry() == NPC_TOTEM_C_FIRE_NOVA)
{
if (!_auraAdded)
{
context.Schedule(4s, [this](TaskContext /*context*/)
{
if (me->IsAlive())
{
DoCastAOE(SPELL_FIRE_NOVA_EFFECT, true);
}
});
_auraAdded = true;
return;
}
}
SetAura(true);
context.Repeat(1s);
})
.Schedule(me->GetEntry() == NPC_TOTEM_C_WINDFURY ? 89s : 59s, [this](TaskContext /*context*/)
{
SetAura(false);
me->DespawnOrUnsummon();
});
}
void JustDied(Unit* /*killer*/) override
{
if (me->GetEntry() != NPC_TOTEM_C_FIRE_NOVA)
{
SetAura(false);
}
_scheduler.CancelAll();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
_scheduler.Update(diff);
}
protected:
TaskScheduler _scheduler;
bool _auraAdded;
};
std::unordered_map<uint32, uint8> const classCallSpells =
{
{ SPELL_MAGE, CLASS_MAGE },
{ SPELL_WARRIOR, CLASS_WARRIOR },
{ SPELL_DRUID, CLASS_DRUID },
{ SPELL_PRIEST, CLASS_PRIEST },
{ SPELL_PALADIN, CLASS_PALADIN },
{ SPELL_SHAMAN, CLASS_SHAMAN },
{ SPELL_WARLOCK, CLASS_WARLOCK },
{ SPELL_HUNTER, CLASS_HUNTER },
{ SPELL_ROGUE, CLASS_ROGUE }
};
class spell_class_call_handler : public SpellScript
{
PrepareSpellScript(spell_class_call_handler);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SUMMON_INFERNALS });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
if (SpellInfo const* spellInfo = GetSpellInfo())
{
targets.remove_if([spellInfo](WorldObject const* target) -> bool
{
Player const* player = target->ToPlayer();
if (!player || player->getClass() == CLASS_DEATH_KNIGHT) // ignore all death knights from whatever spell, for some reason the condition below is not working x.x
{
return true;
}
auto it = classCallSpells.find(spellInfo->Id);
if (it != classCallSpells.end()) // should never happen but only to be sure.
{
return target->ToPlayer()->getClass() != it->second;
}
return false;
});
}
}
void HandleOnHitRogue()
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
{
return;
}
float angle = rand_norm() * 2 * M_PI;
Position tp = caster->GetPosition();
tp.m_positionX += std::cos(angle) * 5.f;
tp.m_positionY += std::sin(angle) * 5.f;
float z = tp.m_positionZ + 0.5f;
caster->UpdateAllowedPositionZ(tp.GetPositionX(), tp.GetPositionY(), z);
target->NearTeleportTo(tp.GetPositionX(), tp.GetPositionY(), z, angle - M_PI);
target->UpdatePositionData();
}
void HandleOnHitWarlock()
{
if (GetHitUnit())
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_INFERNALS, true);
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_class_call_handler::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
if (m_scriptSpellId == SPELL_ROGUE)
{
OnHit += SpellHitFn(spell_class_call_handler::HandleOnHitRogue);
}
else if (m_scriptSpellId == SPELL_WARLOCK)
{
OnHit += SpellHitFn(spell_class_call_handler::HandleOnHitWarlock);
}
}
};
class aura_class_call_wild_magic : public AuraScript
{
PrepareAuraScript(aura_class_call_wild_magic);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_POLYMORPH });
}
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
if (!GetTarget())
{
return;
}
GetTarget()->CastSpell(GetTarget(), SPELL_POLYMORPH, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(aura_class_call_wild_magic::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class aura_class_call_siphon_blessing : public AuraScript
{
PrepareAuraScript(aura_class_call_siphon_blessing);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BLESSING_PROTECTION });
}
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
if (Unit* target = GetTarget())
{
if (Unit* nefarian = target->FindNearestCreature(NPC_NEFARIAN, 100.f))
{
target->CastSpell(nefarian, SPELL_BLESSING_PROTECTION, true);
}
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(aura_class_call_siphon_blessing::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_class_call_polymorph : public SpellScript
{
PrepareSpellScript(spell_class_call_polymorph);
std::list<WorldObject*> targetList;
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if([&](WorldObject const* target) -> bool
{
return target->GetTypeId() != TYPEID_PLAYER || target->ToPlayer()->IsGameMaster() || target->ToPlayer()->HasAura(SPELL_POLYMORPH);
});
if (!targets.empty())
{
Acore::Containers::RandomResize(targets, 1);
targetList.clear();
targetList = targets;
}
}
void FilterTargetsEff(std::list<WorldObject*>& targets)
{
targets.clear();
targets = targetList;
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_class_call_polymorph::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_class_call_polymorph::FilterTargetsEff, EFFECT_1, TARGET_UNIT_SRC_AREA_ALLY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_class_call_polymorph::FilterTargetsEff, EFFECT_2, TARGET_UNIT_SRC_AREA_ALLY);
}
};
class aura_class_call_berserk : public AuraScript
{
PrepareAuraScript(aura_class_call_berserk);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARRIOR_BERSERK });
}
void HandleOnEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* target = GetTarget())
{
target->CastSpell(target, SPELL_WARRIOR_BERSERK);
}
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(aura_class_call_berserk::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_MOD_SHAPESHIFT, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_corrupted_totems : public SpellScript
{
PrepareSpellScript(spell_corrupted_totems);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_CORRUPTED_FIRE_NOVA_TOTEM, SPELL_CORRUPTED_HEALING_TOTEM, SPELL_CORRUPTED_STONESKIN_TOTEM, SPELL_CORRUPTED_WINDFURY_TOTEM });
}
void HandleDummy(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
if (!GetCaster())
{
return;
}
std::list<uint32> spellList = { SPELL_CORRUPTED_FIRE_NOVA_TOTEM, SPELL_CORRUPTED_HEALING_TOTEM, SPELL_CORRUPTED_STONESKIN_TOTEM, SPELL_CORRUPTED_WINDFURY_TOTEM };
uint32 spellId = Acore::Containers::SelectRandomContainerElement(spellList);
GetCaster()->CastSpell(GetCaster(), spellId);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_corrupted_totems::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
enum ShadowblinkRandomSpells
{
SPELL_SHADOWBLINK_TRIGGERED_1 = 22668,
SPELL_SHADOWBLINK_TRIGGERED_2 = 22669,
SPELL_SHADOWBLINK_TRIGGERED_3 = 22670,
SPELL_SHADOWBLINK_TRIGGERED_4 = 22671,
SPELL_SHADOWBLINK_TRIGGERED_5 = 22672,
SPELL_SHADOWBLINK_TRIGGERED_6 = 22673,
SPELL_SHADOWBLINK_TRIGGERED_7 = 22674,
SPELL_SHADOWBLINK_TRIGGERED_8 = 22675,
SPELL_SHADOWBLINK_TRIGGERED_9 = 22676,
};
std::unordered_map<uint32, const Position> const spellPos = {
{ SPELL_SHADOWBLINK_TRIGGERED_1, Position(-7581.11f, -1216.19f) },
{ SPELL_SHADOWBLINK_TRIGGERED_2, Position(-7561.54f, -1244.01f) },
{ SPELL_SHADOWBLINK_TRIGGERED_3, Position(-7542.47f, -1191.92f) },
{ SPELL_SHADOWBLINK_TRIGGERED_4, Position(-7538.63f, -1273.64f) },
{ SPELL_SHADOWBLINK_TRIGGERED_5, Position(-7524.36f, -1219.12f) },
{ SPELL_SHADOWBLINK_TRIGGERED_6, Position(-7506.58f, -1165.26f) },
{ SPELL_SHADOWBLINK_TRIGGERED_7, Position(-7500.70f, -1249.89f) },
{ SPELL_SHADOWBLINK_TRIGGERED_8, Position(-7486.36f, -1194.32f) },
{ SPELL_SHADOWBLINK_TRIGGERED_9, Position(-7469.93f, -1227.93f) },
};
class spell_shadowblink : public SpellScript
{
PrepareSpellScript(spell_shadowblink);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHADOWBLINK_TRIGGERED_1, SPELL_SHADOWBLINK_TRIGGERED_2, SPELL_SHADOWBLINK_TRIGGERED_3, SPELL_SHADOWBLINK_TRIGGERED_4, SPELL_SHADOWBLINK_TRIGGERED_5, SPELL_SHADOWBLINK_TRIGGERED_6, SPELL_SHADOWBLINK_TRIGGERED_7, SPELL_SHADOWBLINK_TRIGGERED_8, SPELL_SHADOWBLINK_TRIGGERED_9 });
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || !caster->ToCreature() || !caster->ToCreature()->AI())
{
return;
}
Unit* target = caster->ToCreature()->AI()->SelectTarget(SelectTargetMethod::Random, 0, 200.f, true);
if (!target)
{
return;
}
for (auto itr : spellPos)
{
float distTarget = target->GetDistance2d(itr.second.m_positionX, itr.second.m_positionY);
if (distTarget <= 30.f)
{
caster->CastSpell(caster, itr.first, true);
return;
}
}
// Selected target is not near any known position, randomize
auto spellId = Acore::Containers::SelectRandomContainerElement(spellPos);
caster->CastSpell(caster, spellId.first, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_shadowblink::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
} }
}; };
void AddSC_boss_nefarian() void AddSC_boss_nefarian()
{ {
new boss_victor_nefarius(); new boss_victor_nefarius();
new boss_nefarian(); RegisterCreatureAI(boss_nefarian);
RegisterCreatureAI(npc_corrupted_totem);
RegisterSpellScript(spell_class_call_handler);
RegisterSpellScript(aura_class_call_wild_magic);
RegisterSpellScript(aura_class_call_siphon_blessing);
RegisterSpellScript(spell_class_call_polymorph);
RegisterSpellScript(aura_class_call_berserk);
RegisterSpellScript(spell_corrupted_totems);
RegisterSpellScript(spell_shadowblink);
} }