update spell scripts, some fixes

This commit is contained in:
Jelle Meeus
2024-06-11 19:47:45 +02:00
parent f7a7b0a425
commit ba6f3cb7b8
18 changed files with 1296 additions and 992 deletions

View File

@@ -1,4 +1,3 @@
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
@@ -117,7 +116,6 @@ class npc_omarion : public CreatureScript
public: public:
npc_omarion() : CreatureScript("npc_omarion_gossip") { } npc_omarion() : CreatureScript("npc_omarion_gossip") { }
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
ClearGossipMenuFor(player); ClearGossipMenuFor(player);
@@ -311,7 +309,7 @@ public:
} }
}; };
void AddSC_npc_omarion() void AddSC_omarion_40()
{ {
new npc_omarion(); new npc_omarion();
} }

View File

@@ -37,9 +37,9 @@ enum Spells
{ {
SPELL_IMPALE = 28783, SPELL_IMPALE = 28783,
SPELL_LOCUST_SWARM = 28785, SPELL_LOCUST_SWARM = 28785,
SPELL_LOCUST_SWARM_TRIGGER = 28786, // periodic effect SPELL_LOCUST_SWARM_TRIGGER = 28786, // periodic effect
SPELL_SUMMON_CORPSE_SCRABS_5 = 90001, // Changed from 29105 to Level 60 Mob ID for summon SPELL_SUMMON_CORPSE_SCRABS_5 = 90001, // Changed from 29105 to Level 60 Mob ID for summon
SPELL_SUMMON_CORPSE_SCRABS_10 = 90002, // Changed from 29105 to Level 60 Mob ID for summon SPELL_SUMMON_CORPSE_SCRABS_10 = 90002, // Changed from 29105 to Level 60 Mob ID for summon
SPELL_BERSERK = 26662 SPELL_BERSERK = 26662
}; };
@@ -243,7 +243,7 @@ public:
} }
case EVENT_SPAWN_GUARD: case EVENT_SPAWN_GUARD:
me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
break; break;
case EVENT_BERSERK: case EVENT_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true); me->CastSpell(me, SPELL_BERSERK, true);
break; break;
@@ -253,49 +253,7 @@ public:
}; };
}; };
class spell_anub_locust_swarm_40 : public SpellScriptLoader
{
public:
spell_anub_locust_swarm_40() : SpellScriptLoader("spell_anub_locust_swarm_40") { }
class spell_anub_locust_swarm_40_AuraScript : public AuraScript
{
PrepareAuraScript(spell_anub_locust_swarm_40_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_LOCUST_SWARM_TRIGGER });
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
int32 modifiedLocustSwarmDamage = 812;
CustomSpellValues values;
values.AddSpellMod(SPELLVALUE_BASE_POINT0, modifiedLocustSwarmDamage);
values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 3000); // 30yd
caster->CastCustomSpell(SPELL_LOCUST_SWARM_TRIGGER, values, caster, TRIGGERED_FULL_MASK, nullptr, nullptr, GetCasterGUID());
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_anub_locust_swarm_40_AuraScript::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_anub_locust_swarm_40_AuraScript();
}
};
void AddSC_boss_anubrekhan_40() void AddSC_boss_anubrekhan_40()
{ {
new boss_anubrekhan_40(); new boss_anubrekhan_40();
new spell_anub_locust_swarm_40();
} }

View File

@@ -24,29 +24,25 @@
enum Spells enum Spells
{ {
SPELL_BERSERK = 26662, SPELL_BERSERK = 26662,
SPELL_SHIELDWALL = 29061, // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds
SPELL_SUMMON_PLAYER = 25104,
// Marks // Marks
SPELL_MARK_OF_KORTHAZZ = 28832, SPELL_MARK_OF_KORTHAZZ = 28832,
SPELL_MARK_OF_BLAUMEUX = 28833, SPELL_MARK_OF_BLAUMEUX = 28833,
SPELL_MARK_OF_MOGRAINE = 28834, // TODO: Requires Spell DBC Edit SPELL_MARK_OF_MOGRAINE = 28834, // TODO: Requires Spell DBC Edit
SPELL_MARK_OF_ZELIEK = 28835, SPELL_MARK_OF_ZELIEK = 28835,
SPELL_MARK_DAMAGE = 28836, SPELL_MARK_DAMAGE = 28836,
// Korth'azz // Korth'azz
SPELL_KORTHAZZ_METEOR_10 = 28884, SPELL_KORTHAZZ_METEOR = 28884,
SPELL_KORTHAZZ_METEOR_25 = 57467,
// Blaumeux // Blaumeux
SPELL_BLAUMEUX_SHADOW_BOLT_10 = 57374, SPELL_BLAUMEUX_SHADOW_BOLT = 57374,
SPELL_BLAUMEUX_SHADOW_BOLT_25 = 57464, SPELL_BLAUMEUX_VOID_ZONE = 28863,
SPELL_BLAUMEUX_VOID_ZONE_10 = 28863,
SPELL_BLAUMEUX_VOID_ZONE_25 = 57463,
// Zeliek // Zeliek
SPELL_ZELIEK_HOLY_WRATH_10 = 28883, SPELL_ZELIEK_HOLY_WRATH = 28883,
SPELL_ZELIEK_HOLY_WRATH_25 = 57466, SPELL_ZELIEK_HOLY_BOLT = 57376,
SPELL_ZELIEK_HOLY_BOLT_10 = 57376,
SPELL_ZELIEK_HOLY_BOLT_25 = 57465,
// Mograine // Mograine
SPELL_RIVENDARE_UNHOLY_SHADOW_10 = 28882, SPELL_RIVENDARE_UNHOLY_SHADOW = 28882,
SPELL_RIVENDARE_UNHOLY_SHADOW_25 = 57369
}; };
enum Events enum Events
@@ -54,15 +50,12 @@ enum Events
EVENT_MARK_CAST = 1, EVENT_MARK_CAST = 1,
EVENT_PRIMARY_SPELL = 2, EVENT_PRIMARY_SPELL = 2,
EVENT_SECONDARY_SPELL = 3, EVENT_SECONDARY_SPELL = 3,
EVENT_BERSERK = 4 EVENT_BERSERK = 4,
EVENT_HEALTH_CHECK = 5
}; };
enum Misc enum Misc
{ {
// Movement
MOVE_PHASE_NONE = 0,
MOVE_PHASE_STARTED = 1,
MOVE_PHASE_FINISHED = 2,
// Horseman // Horseman
HORSEMAN_ZELIEK = 0, HORSEMAN_ZELIEK = 0,
HORSEMAN_BLAUMEUX = 1, HORSEMAN_BLAUMEUX = 1,
@@ -70,6 +63,20 @@ enum Misc
HORSEMAN_KORTHAZZ = 3 HORSEMAN_KORTHAZZ = 3
}; };
enum Spirits
{
// Spells
SPELL_SUMMON_SPIRIT_ZELIEK = 28934,
SPELL_SUMMON_SPIRIT_BLAUMEUX = 28931,
SPELL_SUMMON_SPIRIT_MOGRAINE = 28928,
SPELL_SUMMON_SPIRIT_KORTHAZZ = 28932,
// NPCs
NPC_SPIRIT_ZELIEK = 16777,
NPC_SPIRIT_BLAUMEUX = 16776,
NPC_SPIRIT_MOGRAINE = 16775,
NPC_SPIRIT_KORTHAZZ = 16778
};
enum FourHorsemen enum FourHorsemen
{ {
SAY_AGGRO = 0, SAY_AGGRO = 0,
@@ -82,26 +89,8 @@ enum FourHorsemen
// MARKS // MARKS
const uint32 TABLE_SPELL_MARK[4] = {SPELL_MARK_OF_ZELIEK, SPELL_MARK_OF_BLAUMEUX, SPELL_MARK_OF_MOGRAINE, SPELL_MARK_OF_KORTHAZZ}; const uint32 TABLE_SPELL_MARK[4] = {SPELL_MARK_OF_ZELIEK, SPELL_MARK_OF_BLAUMEUX, SPELL_MARK_OF_MOGRAINE, SPELL_MARK_OF_KORTHAZZ};
// SPIRITS
const Position WaypointPositions[12] = const uint32 TABLE_SPELL_SUMMON_SPIRIT[4] = {SPELL_SUMMON_SPIRIT_ZELIEK, SPELL_SUMMON_SPIRIT_BLAUMEUX, SPELL_SUMMON_SPIRIT_MOGRAINE, SPELL_SUMMON_SPIRIT_KORTHAZZ};
{
// Thane waypoints
{2542.3f, -2984.1f, 241.49f, 5.362f},
{2547.6f, -2999.4f, 241.34f, 5.049f},
{2542.9f, -3015.0f, 241.35f, 4.654f},
// Lady waypoints
{2498.3f, -2961.8f, 241.28f, 3.267f},
{2487.7f, -2959.2f, 241.28f, 2.890f},
{2469.4f, -2947.6f, 241.28f, 2.576f},
// Mograine waypoints
{2553.8f, -2968.4f, 241.33f, 5.757f},
{2564.3f, -2972.5f, 241.33f, 5.890f},
{2583.9f, -2971.6f, 241.35f, 0.008f},
// Sir waypoints
{2534.5f, -2921.7f, 241.53f, 1.363f},
{2523.5f, -2902.8f, 241.28f, 2.095f},
{2517.8f, -2896.6f, 241.28f, 2.315f}
};
class boss_four_horsemen_40 : public CreatureScript class boss_four_horsemen_40 : public CreatureScript
{ {
@@ -137,29 +126,8 @@ public:
EventMap events; EventMap events;
InstanceScript* pInstance; InstanceScript* pInstance;
uint8 currentWaypoint{};
uint8 movementPhase{};
uint8 horsemanId; uint8 horsemanId;
bool doneFirstShieldWall;
void MoveToCorner()
{
switch(me->GetEntry())
{
case NPC_THANE_KORTHAZZ_40:
currentWaypoint = 0;
break;
case NPC_LADY_BLAUMEUX_40:
currentWaypoint = 3;
break;
case NPC_HIGHLORD_MOGRAINE_40:
currentWaypoint = 6;
break;
case NPC_SIR_ZELIEK_40:
currentWaypoint = 9;
break;
}
me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]);
}
bool IsInRoom() bool IsInRoom()
{ {
@@ -175,12 +143,13 @@ public:
{ {
BossAI::Reset(); BossAI::Reset();
me->SetPosition(me->GetHomePosition()); me->SetPosition(me->GetHomePosition());
movementPhase = MOVE_PHASE_NONE;
currentWaypoint = 0;
me->SetReactState(REACT_AGGRESSIVE); me->SetReactState(REACT_AGGRESSIVE);
doneFirstShieldWall = false;
events.Reset(); events.Reset();
events.RescheduleEvent(EVENT_MARK_CAST, 24000); events.RescheduleEvent(EVENT_MARK_CAST, 20000);
events.RescheduleEvent(EVENT_BERSERK, 600000); events.RescheduleEvent(EVENT_BERSERK, 600000);
summons.DespawnAll(); // despawn spirits
if ((me->GetEntry() != NPC_LADY_BLAUMEUX_40 && me->GetEntry() != NPC_SIR_ZELIEK_40)) if ((me->GetEntry() != NPC_LADY_BLAUMEUX_40 && me->GetEntry() != NPC_SIR_ZELIEK_40))
{ {
events.RescheduleEvent(EVENT_PRIMARY_SPELL, 10000 + rand() % 5000); events.RescheduleEvent(EVENT_PRIMARY_SPELL, 10000 + rand() % 5000);
@@ -201,47 +170,6 @@ public:
} }
} }
void MovementInform(uint32 type, uint32 id) override
{
if (type != POINT_MOTION_TYPE)
return;
// final waypoint
if (id % 3 == 2)
{
movementPhase = MOVE_PHASE_FINISHED;
me->SetReactState(REACT_AGGRESSIVE);
me->SetInCombatWithZone();
if (!UpdateVictim())
{
EnterEvadeMode();
return;
}
if (me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40)
{
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveIdle();
}
return;
}
currentWaypoint = id + 1;
}
void AttackStart(Unit* who) override
{
if (movementPhase == MOVE_PHASE_FINISHED)
{
if (me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40)
{
me->Attack(who, false);
}
else
{
ScriptedAI::AttackStart(who);
}
}
}
void KilledUnit(Unit* who) override void KilledUnit(Unit* who) override
{ {
if (who->GetTypeId() != TYPEID_PLAYER) if (who->GetTypeId() != TYPEID_PLAYER)
@@ -254,6 +182,14 @@ public:
} }
} }
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
{
if (spellInfo->Id == TABLE_SPELL_MARK[horsemanId])
{
DoModifyThreatByPercent(target, -50);
}
}
void JustDied(Unit* killer) override void JustDied(Unit* killer) override
{ {
BossAI::JustDied(killer); BossAI::JustDied(killer);
@@ -261,6 +197,14 @@ public:
{ {
if (pInstance->GetBossState(BOSS_HORSEMAN) == DONE) if (pInstance->GetBossState(BOSS_HORSEMAN) == DONE)
{ {
if (Creature* spirit = GetClosestCreatureWithEntry(me, NPC_SPIRIT_ZELIEK, 200.0f))
spirit->DespawnOrUnsummon();
if (Creature* spirit = GetClosestCreatureWithEntry(me, NPC_SPIRIT_BLAUMEUX, 200.0f))
spirit->DespawnOrUnsummon();
if (Creature* spirit = GetClosestCreatureWithEntry(me, NPC_SPIRIT_MOGRAINE, 200.0f))
spirit->DespawnOrUnsummon();
if (Creature* spirit = GetClosestCreatureWithEntry(me, NPC_SPIRIT_KORTHAZZ, 200.0f))
spirit->DespawnOrUnsummon();
if (!me->GetMap()->GetPlayers().IsEmpty()) if (!me->GetMap()->GetPlayers().IsEmpty())
{ {
if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource()) if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource())
@@ -276,22 +220,30 @@ public:
go->SetGoState(GO_STATE_ACTIVE); go->SetGoState(GO_STATE_ACTIVE);
} }
} }
else
{
// Prevent spawning if last horseman killed
DoCastSelf(TABLE_SPELL_SUMMON_SPIRIT[horsemanId], true);
}
} }
Talk(SAY_DEATH); Talk(SAY_DEATH);
} }
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
summons.DoZoneInCombat();
summon->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
}
void JustEngagedWith(Unit* who) override void JustEngagedWith(Unit* who) override
{ {
BossAI::JustEngagedWith(who); BossAI::JustEngagedWith(who);
if (movementPhase == MOVE_PHASE_NONE) Talk(SAY_AGGRO);
{ me->SetReactState(REACT_AGGRESSIVE);
Talk(SAY_AGGRO); me->SetInCombatWithZone();
me->SetReactState(REACT_PASSIVE);
movementPhase = MOVE_PHASE_STARTED;
me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true);
MoveToCorner();
}
if (pInstance) if (pInstance)
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
{ {
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE))) if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE)))
{ {
@@ -302,18 +254,18 @@ public:
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (movementPhase == MOVE_PHASE_STARTED && currentWaypoint)
{
me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]);
currentWaypoint = 0;
}
if (!IsInRoom()) if (!IsInRoom())
return; return;
if (movementPhase < MOVE_PHASE_FINISHED || !UpdateVictim()) if (!UpdateVictim())
return; return;
if (Unit* victim = me->GetVictim())
{
if (!me->IsWithinDistInMap(victim, VISIBILITY_DISTANCE_NORMAL))
me->CastSpell(victim, SPELL_SUMMON_PLAYER, true);
}
events.Update(diff); events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
@@ -322,7 +274,7 @@ public:
{ {
case EVENT_MARK_CAST: case EVENT_MARK_CAST:
me->CastSpell(me, TABLE_SPELL_MARK[horsemanId], false); me->CastSpell(me, TABLE_SPELL_MARK[horsemanId], false);
events.RepeatEvent((me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40) ? 15000 : 12000); events.RepeatEvent(12000);
return; return;
case EVENT_BERSERK: case EVENT_BERSERK:
Talk(SAY_SPECIAL); Talk(SAY_SPECIAL);
@@ -333,22 +285,22 @@ public:
if (horsemanId == HORSEMAN_ZELIEK) if (horsemanId == HORSEMAN_ZELIEK)
{ {
int32 bp0 = 1109; // spell not used in vanilla, reduced damage from ~2.5 to ~1.2k int32 bp0 = 1109; // spell not used in vanilla, reduced damage from ~2.5 to ~1.2k
me->CastCustomSpell(me->GetVictim(), SPELL_ZELIEK_HOLY_BOLT_10, &bp0, 0, 0, false); me->CastCustomSpell(me->GetVictim(), SPELL_ZELIEK_HOLY_BOLT, &bp0, 0, 0, false);
} }
else if (horsemanId == HORSEMAN_BLAUMEUX) else if (horsemanId == HORSEMAN_BLAUMEUX)
{ {
int32 bp0 = 1109; // spell not used in vanilla, reduced damage from ~2.5 to ~1.2k int32 bp0 = 1109; // spell not used in vanilla, reduced damage from ~2.5 to ~1.2k
me->CastCustomSpell(me->GetVictim(), SPELL_BLAUMEUX_SHADOW_BOLT_10, &bp0, 0, 0, false); me->CastCustomSpell(me->GetVictim(), SPELL_BLAUMEUX_SHADOW_BOLT, &bp0, 0, 0, false);
} }
else if (horsemanId == HORSEMAN_MOGRAINE) else if (horsemanId == HORSEMAN_MOGRAINE)
{ {
// same dbc as vanilla. Shadow damage instead of fire // same dbc as vanilla. Shadow damage instead of fire
me->CastSpell(me->GetVictim(), SPELL_RIVENDARE_UNHOLY_SHADOW_10, false); me->CastSpell(me->GetVictim(), SPELL_RIVENDARE_UNHOLY_SHADOW, false);
} }
else // HORSEMAN_KORTHAZZ else // HORSEMAN_KORTHAZZ
{ {
int32 bp0 = 12824; // 14.5k to 13.5k int32 bp0 = 12824; // 14.5k to 13.5k
me->CastCustomSpell(me->GetVictim(), SPELL_KORTHAZZ_METEOR_10, &bp0, 0, 0, false); me->CastCustomSpell(me->GetVictim(), SPELL_KORTHAZZ_METEOR, &bp0, 0, 0, false);
} }
events.RepeatEvent(15000); events.RepeatEvent(15000);
return; return;
@@ -359,159 +311,102 @@ public:
CustomSpellValues values; CustomSpellValues values;
values.AddSpellMod(SPELLVALUE_BASE_POINT0, bp0); values.AddSpellMod(SPELLVALUE_BASE_POINT0, bp0);
values.AddSpellMod(SPELLVALUE_MAX_TARGETS, 50); // 30yd values.AddSpellMod(SPELLVALUE_MAX_TARGETS, 50); // 30yd
me->CastCustomSpell(SPELL_ZELIEK_HOLY_WRATH_10, values, me->GetVictim(), TRIGGERED_NONE, nullptr, nullptr, ObjectGuid::Empty); me->CastCustomSpell(SPELL_ZELIEK_HOLY_WRATH, values, me->GetVictim(), TRIGGERED_NONE, nullptr, nullptr, ObjectGuid::Empty);
} }
else // HORSEMAN_BLAUMEUX else // HORSEMAN_BLAUMEUX
{ {
me->CastSpell(me->GetVictim(), SPELL_BLAUMEUX_VOID_ZONE_10, false); me->CastSpell(me->GetVictim(), SPELL_BLAUMEUX_VOID_ZONE, false);
} }
events.RepeatEvent(15000); events.RepeatEvent(15000);
return; return;
} case EVENT_HEALTH_CHECK:
if (!doneFirstShieldWall && me->GetHealthPct() <= 50.0f)
if ((me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40))
{
if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 45.0f, true))
{
if (horsemanId == HORSEMAN_ZELIEK)
{ {
int32 bp0 = 1109; // spell not used in vanilla, reduced damage from ~2.5 to ~1.2k DoCastSelf(SPELL_SHIELDWALL, true);
me->CastCustomSpell(me->GetVictim(), SPELL_ZELIEK_HOLY_BOLT_10, &bp0, 0, 0, false); doneFirstShieldWall = true;
events.Repeat(1s);
break;
} }
else if (horsemanId == HORSEMAN_BLAUMEUX) if (doneFirstShieldWall && me->GetHealthPct() <= 20.0f)
{ {
int32 bp0 = 1109; // spell not used in vanilla, reduced damage from ~2.5 to ~1.2k if (!me->HasAura(SPELL_SHIELDWALL)) // prevent refresh of first shield wall
me->CastCustomSpell(me->GetVictim(), SPELL_BLAUMEUX_SHADOW_BOLT_10, &bp0, 0, 0, false); {
DoCastSelf(SPELL_SHIELDWALL, true);
}
break;
} }
} events.Repeat(1s);
} return;
else
{
DoMeleeAttackIfReady();
} }
DoMeleeAttackIfReady();
} }
}; };
}; };
class spell_four_horsemen_mark : public SpellScriptLoader class spell_four_horsemen_mark_aura : public AuraScript
{ {
public: PrepareAuraScript(spell_four_horsemen_mark_aura);
spell_four_horsemen_mark() : SpellScriptLoader("spell_four_horsemen_mark") { }
class spell_four_horsemen_mark_AuraScript : public AuraScript void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
PrepareAuraScript(spell_four_horsemen_mark_AuraScript); if (Unit* caster = GetCaster())
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{ {
if (Unit* caster = GetCaster()) int32 damage;
{
int32 damage;
switch (GetStackAmount())
{
case 1:
damage = 0;
break;
case 2:
damage = 500;
break;
case 3:
damage = 1500;
break;
case 4:
damage = 4000;
break;
case 5:
damage = 12000;
break;
case 6:
damage = 20000;
break;
default:
damage = 20000 + 1000 * (GetStackAmount() - 7);
break;
}
if (caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC)
{
switch (GetStackAmount()) switch (GetStackAmount())
{ {
case 1: case 1: damage = 0; break;
damage = 0; case 2: damage = 250; break;
break; case 3: damage = 1000; break;
case 2: case 4: damage = 3000; break;
damage = 500;
break;
case 3:
damage = 1500;
break;
case 4:
damage = 4000;
break;
case 5:
damage = 12000;
break;
case 6:
damage = 20000;
break;
default: default:
damage = 20000 + 1000 * (GetStackAmount() - 7); damage = 1000 * GetStackAmount();
break; break;
} }
if (caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC)
{
switch (GetStackAmount())
{
case 1: damage = 0; break;
case 2: damage = 250; break;
case 3: damage = 1000; break;
case 4: damage = 3000; break;
default:
damage = 1000 * GetStackAmount();
break;
}
}
if (damage)
{
caster->CastCustomSpell(SPELL_MARK_DAMAGE, SPELLVALUE_BASE_POINT0, damage, GetTarget());
}
} }
}
void Register() override if (damage)
{
AfterEffectApply += AuraEffectApplyFn(spell_four_horsemen_mark_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_four_horsemen_mark_AuraScript();
}
};
class spell_gen_consumption : public SpellScript
{
PrepareSpellScript(spell_gen_consumption);
void CalculateDamage(SpellEffIndex /*effIndex*/)
{
Map* map = GetCaster()->GetMap();
if (!map)
{
return;
}
int32 value = 0;
if (map->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) // NAXX25 N
{
value = urand(4500, 4700);
}
else if (map->GetId() == 533) // NAXX10 N
{
if (map->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
{ {
value = urand(3000, 3200); caster->CastCustomSpell(SPELL_MARK_DAMAGE, SPELLVALUE_BASE_POINT0, damage, GetTarget());
} }
else
{
value = urand(3960, 4840); // NAXX40
}
}
else if (map->GetId() == 532) // Karazhan
{
value = urand(1110, 1310);
}
if (value)
{
SetEffectValue(value);
} }
} }
void Register() override void Register() override
{ {
OnEffectLaunchTarget += SpellEffectFn(spell_gen_consumption::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); AfterEffectApply += AuraEffectApplyFn(spell_four_horsemen_mark_aura::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
} }
}; };
void AddSC_boss_four_horsemen_40() void AddSC_boss_four_horsemen_40()
{ {
new boss_four_horsemen_40(); new boss_four_horsemen_40();
new spell_four_horsemen_mark(); RegisterSpellScript(spell_four_horsemen_mark_aura);
RegisterSpellScript(spell_gen_consumption);
} }

View File

@@ -179,7 +179,6 @@ public:
if (me->HasUnitState(UNIT_STATE_CASTING)) if (me->HasUnitState(UNIT_STATE_CASTING))
return; return;
switch (events.ExecuteEvent()) switch (events.ExecuteEvent())
{ {
case EVENT_BERSERK: case EVENT_BERSERK:
@@ -251,49 +250,38 @@ public:
}; };
}; };
class spell_gluth_decimate : public SpellScriptLoader class spell_gluth_decimate : public SpellScript
{ {
public: PrepareSpellScript(spell_gluth_decimate);
spell_gluth_decimate() : SpellScriptLoader("spell_gluth_decimate") { }
class spell_gluth_decimate_SpellScript : public SpellScript void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{ {
PrepareSpellScript(spell_gluth_decimate_SpellScript); if (Unit* unitTarget = GetHitUnit())
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{ {
if (Unit* unitTarget = GetHitUnit()) int32 damage = int32(unitTarget->GetHealth()) - int32(unitTarget->CountPctFromMaxHealth(5));
if (damage <= 0)
return;
if (Creature* cTarget = unitTarget->ToCreature())
{ {
int32 damage = int32(unitTarget->GetHealth()) - int32(unitTarget->CountPctFromMaxHealth(5)); cTarget->SetWalk(true);
if (damage <= 0) cTarget->GetMotionMaster()->MoveFollow(GetCaster(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
return; cTarget->SetReactState(REACT_PASSIVE);
Unit::DealDamage(GetCaster(), cTarget, damage);
if (Creature* cTarget = unitTarget->ToCreature()) return;
{
cTarget->SetWalk(true);
cTarget->GetMotionMaster()->MoveFollow(GetCaster(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
cTarget->SetReactState(REACT_PASSIVE);
Unit::DealDamage(GetCaster(), cTarget, damage);
return;
}
GetCaster()->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget);
} }
GetCaster()->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget);
} }
}
void Register() override void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_gluth_decimate_SpellScript(); OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
} }
}; };
void AddSC_boss_gluth_40() void AddSC_boss_gluth_40()
{ {
new boss_gluth_40(); new boss_gluth_40();
new spell_gluth_decimate(); RegisterSpellScript(spell_gluth_decimate);
} }

View File

@@ -684,29 +684,18 @@ public:
}; };
}; };
class spell_gothik_shadow_bolt_volley : public SpellScriptLoader class spell_gothik_shadow_bolt_volley : public SpellScript
{ {
public: PrepareSpellScript(spell_gothik_shadow_bolt_volley);
spell_gothik_shadow_bolt_volley() : SpellScriptLoader("spell_gothik_shadow_bolt_volley") { }
class spell_gothik_shadow_bolt_volley_SpellScript : public SpellScript void FilterTargets(std::list<WorldObject*>& targets)
{ {
PrepareSpellScript(spell_gothik_shadow_bolt_volley_SpellScript); targets.remove_if(Acore::UnitAuraCheck(false, SPELL_SHADOW_MARK));
}
void FilterTargets(std::list<WorldObject*>& targets) void Register() override
{
targets.remove_if(Acore::UnitAuraCheck(false, SPELL_SHADOW_MARK));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gothik_shadow_bolt_volley_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_gothik_shadow_bolt_volley_SpellScript(); OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gothik_shadow_bolt_volley::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
} }
}; };
@@ -714,5 +703,5 @@ void AddSC_boss_gothik_40()
{ {
new boss_gothik_40(); new boss_gothik_40();
new npc_boss_gothik_minion_40(); new npc_boss_gothik_minion_40();
// new spell_gothik_shadow_bolt_volley(); // RegisterSpellScript(spell_gothik_shadow_bolt_volley);
} }

View File

@@ -241,140 +241,77 @@ public:
}; };
}; };
class spell_grobbulus_poison : public SpellScriptLoader class spell_grobbulus_poison : public SpellScript
{ {
public: PrepareSpellScript(spell_grobbulus_poison);
spell_grobbulus_poison() : SpellScriptLoader("spell_grobbulus_poison") { }
class spell_grobbulus_poison_SpellScript : public SpellScript void FilterTargets(std::list<WorldObject*>& targets)
{ {
PrepareSpellScript(spell_grobbulus_poison_SpellScript); std::list<WorldObject*> tmplist;
for (auto& target : targets)
void FilterTargets(std::list<WorldObject*>& targets)
{ {
std::list<WorldObject*> tmplist; if (GetCaster()->IsWithinDist3d(target, 0.0f))
for (auto& target : targets)
{ {
if (GetCaster()->IsWithinDist3d(target, 0.0f)) tmplist.push_back(target);
{
tmplist.push_back(target);
}
}
targets.clear();
for (auto& itr : tmplist)
{
targets.push_back(itr);
} }
} }
targets.clear();
void Register() override for (auto& itr : tmplist)
{ {
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grobbulus_poison_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); targets.push_back(itr);
} }
}; }
SpellScript* GetSpellScript() const override void Register() override
{ {
return new spell_grobbulus_poison_SpellScript(); OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grobbulus_poison::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
} }
}; };
// This will overwrite the declared 10 and 25 man mutating injection to handle all versions of the spell script // This will overwrite the declared 10 and 25 man mutating injection to handle all versions of the spell script
class spell_grobbulus_mutating_injection_40 : public SpellScriptLoader class spell_grobbulus_mutating_injection_aura : public AuraScript
{ {
public: PrepareAuraScript(spell_grobbulus_mutating_injection_aura);
spell_grobbulus_mutating_injection_40() : SpellScriptLoader("spell_grobbulus_mutating_injection") { }
class spell_grobbulus_mutating_injection_40_AuraScript : public AuraScript bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MUTATING_EXPLOSION });
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
switch (GetTargetApplication()->GetRemoveMode())
{ {
PrepareAuraScript(spell_grobbulus_mutating_injection_40_AuraScript); case AURA_REMOVE_BY_ENEMY_SPELL:
case AURA_REMOVE_BY_EXPIRE:
bool Validate(SpellInfo const* /*spellInfo*/) override if (auto caster = GetCaster())
{
return ValidateSpellInfo({ SPELL_MUTATING_EXPLOSION });
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
switch (GetTargetApplication()->GetRemoveMode())
{ {
case AURA_REMOVE_BY_ENEMY_SPELL: if (caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC)
case AURA_REMOVE_BY_EXPIRE: {
if (auto caster = GetCaster()) int32 modifiedMutatingExplosionDamage = 2379;
{ caster->CastCustomSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, &modifiedMutatingExplosionDamage, 0, 0, true);
if (caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC) }
{ else
int32 modifiedMutatingExplosionDamage = 2379; {
caster->CastCustomSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, &modifiedMutatingExplosionDamage, 0, 0, true); caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true);
} }
else
{
caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true);
}
}
break;
default:
return;
} }
} break;
default:
void Register() override return;
{
AfterEffectRemove += AuraEffectRemoveFn(spell_grobbulus_mutating_injection_40_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_grobbulus_mutating_injection_40_AuraScript();
} }
}; }
void Register() override
class spell_grobbulus_poison_cloud_poison_40 : public SpellScriptLoader {
{ AfterEffectRemove += AuraEffectRemoveFn(spell_grobbulus_mutating_injection_aura::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
public: }
spell_grobbulus_poison_cloud_poison_40() : SpellScriptLoader("spell_grobbulus_poison_cloud_poison_40") { }
class spell_grobbulus_poison_cloud_poison_40_AuraScript : public AuraScript
{
PrepareAuraScript(spell_grobbulus_poison_cloud_poison_40_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_POISON_CLOUD_POISON_DAMAGE }); // Poison trigger
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
int32 bp0 = 1109;
caster->CastCustomSpell(GetTarget(), SPELL_POISON_CLOUD_POISON_DAMAGE, &bp0, 0, 0, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_grobbulus_poison_cloud_poison_40_AuraScript::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_grobbulus_poison_cloud_poison_40_AuraScript();
}
}; };
void AddSC_boss_grobbulus_40() void AddSC_boss_grobbulus_40()
{ {
new boss_grobbulus_40(); new boss_grobbulus_40();
new boss_grobbulus_poison_cloud_40(); new boss_grobbulus_poison_cloud_40();
new spell_grobbulus_mutating_injection_40(); // RegisterSpellScript(spell_grobbulus_poison);
// new spell_grobbulus_poison(); RegisterSpellScript(spell_grobbulus_mutating_injection_aura);
new spell_grobbulus_poison_cloud_poison_40();
} }

View File

@@ -38,11 +38,12 @@ enum Says
enum Spells enum Spells
{ {
SPELL_SPELL_DISRUPTION = 29310, SPELL_SUMMON_PLAYER = 25104,
SPELL_DISRUPTION = 55010, // 29310->55010: Mana Burn AoE spell similar to vanilla
SPELL_DECREPIT_FEVER = 29998, SPELL_DECREPIT_FEVER = 29998,
SPELL_PLAGUE_CLOUD = 29350, SPELL_PLAGUE_CLOUD = 29350,
SPELL_PLAGUE_CLOUD_TRIGGER = 30122, SPELL_TELEPORT_SELF = 30211,
SPELL_TELEPORT_SELF = 30211 SPELL_TELEPORT_PLAYERS = 29273 // updated target in db
}; };
enum Events enum Events
@@ -52,7 +53,8 @@ enum Events
EVENT_ERUPT_SECTION = 3, EVENT_ERUPT_SECTION = 3,
EVENT_SWITCH_PHASE = 4, EVENT_SWITCH_PHASE = 4,
EVENT_SAFETY_DANCE = 5, EVENT_SAFETY_DANCE = 5,
EVENT_PLAGUE_CLOUD = 6 EVENT_PLAGUE_CLOUD = 6,
EVENT_TELEPORT_PLAYER = 7
}; };
enum Misc enum Misc
@@ -61,14 +63,38 @@ enum Misc
PHASE_FAST_DANCE = 1 PHASE_FAST_DANCE = 1
}; };
const Position EyeStalkPositions[20] =
{
{ 2761.28f, -3765.37f, 275.08f, 1.24f },
{ 2770.17f, -3782.11f, 275.08f, 1.33f },
{ 2798.11f, -3788.94f, 275.08f, 2.35f },
{ 2797.91f, -3776.86f, 275.08f, 2.25f },
{ 2792.06f, -3762.52f, 275.08f, 2.9f, },
{ 2789.87f, -3752.15f, 275.08f, 2.74f },
{ 2804.21f, -3757.96f, 275.08f, 3.9f },
{ 2821.16f, -3759.75f, 275.08f, 4.47f },
{ 2834.64f, -3751.23f, 275.08f, 4.27f },
{ 2843.54f, -3768.08f, 275.08f, 3.06f },
{ 2862.4f, -3758.3f, 275.08f, 4.8f },
{ 2877.8f, -3762.46f, 275.08f, 4.8f },
{ 2894.11f, -3757.89f, 275.08f, 4.56f },
{ 2895.25f, -3779.5f, 275.08f, 2.4f },
{ 2881.59f, -3782.22f, 275.08f, 2.79f },
{ 2867.2f, -3778.21f, 275.08f, 3.01f },
{ 2851.39f, -3776.54f, 275.08f, 2.69f },
{ 2846.16f, -3789.13f, 275.08f, 1.79f },
{ 2830.09f, -3776.49f, 275.08f, 0.94f },
{ 2813.34f, -3780.97f, 275.08f, 1.84f },
};
class boss_heigan_40 : public CreatureScript class boss_heigan_40 : public CreatureScript
{ {
public: public:
boss_heigan_40() : CreatureScript("boss_heigan_40") { } boss_heigan_40() : CreatureScript("boss_heigan_40") { }
CreatureAI* GetAI(Creature* pCreature) const override CreatureAI* GetAI(Creature* creature) const override
{ {
return GetNaxxramasAI<boss_heigan_40AI>(pCreature); return GetNaxxramasAI<boss_heigan_40AI>(creature);
} }
struct boss_heigan_40AI : public BossAI struct boss_heigan_40AI : public BossAI
@@ -83,6 +109,7 @@ public:
uint8 currentPhase{}; uint8 currentPhase{};
uint8 currentSection{}; uint8 currentSection{};
bool moveRight{}; bool moveRight{};
GuidList portedPlayersThisPhase;
void Reset() override void Reset() override
{ {
@@ -90,6 +117,8 @@ public:
events.Reset(); events.Reset();
currentPhase = 0; currentPhase = 0;
currentSection = 3; currentSection = 3;
portedPlayersThisPhase.clear();
KillPlayersInTheTunnel();
moveRight = true; moveRight = true;
if (pInstance) if (pInstance)
{ {
@@ -97,6 +126,11 @@ public:
{ {
go->SetGoState(GO_STATE_ACTIVE); go->SetGoState(GO_STATE_ACTIVE);
} }
// Close tunnel door
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_EXIT_GATE)))
{
go->SetGoState(GO_STATE_READY);
}
} }
} }
@@ -129,6 +163,16 @@ public:
{ {
go->SetGoState(GO_STATE_READY); go->SetGoState(GO_STATE_READY);
} }
// Open tunnel door
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_EXIT_GATE)))
{
go->SetGoState(GO_STATE_ACTIVE);
}
// Close loatheb door
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_EXIT_GATE_OLD)))
{
go->SetGoState(GO_STATE_READY);
}
} }
StartFightPhase(PHASE_SLOW_DANCE); StartFightPhase(PHASE_SLOW_DANCE);
} }
@@ -147,6 +191,8 @@ public:
events.ScheduleEvent(EVENT_DECEPIT_FEVER, 17000); events.ScheduleEvent(EVENT_DECEPIT_FEVER, 17000);
events.ScheduleEvent(EVENT_ERUPT_SECTION, 15000); events.ScheduleEvent(EVENT_ERUPT_SECTION, 15000);
events.ScheduleEvent(EVENT_SWITCH_PHASE, 90000); events.ScheduleEvent(EVENT_SWITCH_PHASE, 90000);
events.ScheduleEvent(EVENT_TELEPORT_PLAYER, 40000);
portedPlayersThisPhase.clear();
} }
else // if (phase == PHASE_FAST_DANCE) else // if (phase == PHASE_FAST_DANCE)
{ {
@@ -176,6 +222,60 @@ public:
return true; return true;
} }
void KillPlayersInTheTunnel()
{
// hackfix: kill everyone in the tunnel
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
for (const auto& itr : PlayerList)
{
if (Player* player = itr.GetSource())
{
if (player->IsAlive() && !player->IsGameMaster())
{
if (player->GetPositionX() <= 2769.0f)
{
player->KillSelf();
}
}
}
}
}
void DoEventTeleportPlayer()
{
std::list<Unit*> candidates;
SelectTargetList(candidates, 3, SelectTargetMethod::Random, 0, [&](Unit* target)
{
if (!target->IsPlayer()) // never target nonplayers (pets, guardians, etc.)
return false;
if (!target->IsAlive())
return false;
if (me->GetVictim() == target) // never target tank
return false;
// skip players who already have been teleported this phase
if (std::find(portedPlayersThisPhase.begin(), portedPlayersThisPhase.end(), target->GetGUID()) != portedPlayersThisPhase.end())
return false;
return true;
});
if (candidates.empty())
return;
for (int i = 0; i < 3 ; i++)
{
if (candidates.empty())
break;
auto itr = candidates.begin();
if (candidates.size() > 1)
std::advance(itr, urand(0, candidates.size() - 1));
Unit *target = *itr;
candidates.erase(itr);
portedPlayersThisPhase.push_back(target->GetGUID());
DoModifyThreatByPercent(target, -99); // prevent heigan chasing and resetting
target->CastSpell(target, SPELL_TELEPORT_PLAYERS, true);
}
}
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!IsInRoom(me)) if (!IsInRoom(me))
@@ -184,12 +284,17 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
if (Unit* victim = me->GetVictim())
{
if (!me->IsWithinDistInMap(victim, VISIBILITY_DISTANCE_NORMAL))
me->CastSpell(victim, SPELL_SUMMON_PLAYER, true);
}
events.Update(diff); events.Update(diff);
switch (events.ExecuteEvent()) switch (events.ExecuteEvent())
{ {
case EVENT_DISRUPTION: case EVENT_DISRUPTION:
me->CastSpell(me, SPELL_SPELL_DISRUPTION, false); me->CastCustomSpell(SPELL_DISRUPTION, SPELLVALUE_RADIUS_MOD, 2500, me, false); // 25yd
events.RepeatEvent(10000); events.RepeatEvent(10000);
break; break;
case EVENT_DECEPIT_FEVER: case EVENT_DECEPIT_FEVER:
@@ -216,6 +321,11 @@ public:
case EVENT_ERUPT_SECTION: case EVENT_ERUPT_SECTION:
if (pInstance) if (pInstance)
{ {
if (currentPhase == PHASE_FAST_DANCE)
{
if (currentSection >= 1)
KillPlayersInTheTunnel();
}
pInstance->SetData(DATA_HEIGAN_ERUPTION, currentSection); pInstance->SetData(DATA_HEIGAN_ERUPTION, currentSection);
if (currentSection == 3) if (currentSection == 3)
{ {
@@ -248,85 +358,16 @@ public:
events.RepeatEvent(5000); events.RepeatEvent(5000);
return; return;
} }
case EVENT_TELEPORT_PLAYER:
DoEventTeleportPlayer();
break;
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
}; };
}; };
class spell_heigan_plague_cloud_40 : public SpellScriptLoader
{
public:
spell_heigan_plague_cloud_40() : SpellScriptLoader("spell_heigan_plague_cloud_40") { }
class spell_heigan_plague_cloud_40_AuraScript : public AuraScript
{
PrepareAuraScript(spell_heigan_plague_cloud_40_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PLAGUE_CLOUD_TRIGGER });
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
int32 bp0 = 4000;
caster->CastCustomSpell(caster, SPELL_PLAGUE_CLOUD_TRIGGER, &bp0, 0, 0, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_heigan_plague_cloud_40_AuraScript::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_heigan_plague_cloud_40_AuraScript();
}
};
class spell_heigan_eruption_40 : public SpellScriptLoader
{
public:
spell_heigan_eruption_40() : SpellScriptLoader("spell_heigan_eruption_40") { }
class spell_heigan_eruption_40_SpellScript : public SpellScript
{
PrepareSpellScript(spell_heigan_eruption_40_SpellScript);
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
SetEffectValue(urand(3500, 4500));
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_heigan_eruption_40_SpellScript::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_heigan_eruption_40_SpellScript();
}
};
void AddSC_boss_heigan_40() void AddSC_boss_heigan_40()
{ {
new boss_heigan_40(); new boss_heigan_40();
new spell_heigan_plague_cloud_40();
new spell_heigan_eruption_40();
} }

View File

@@ -662,103 +662,60 @@ public:
}; };
}; };
class spell_kelthuzad_frost_blast : public SpellScriptLoader class spell_kelthuzad_frost_blast : public SpellScript
{ {
public: PrepareSpellScript(spell_kelthuzad_frost_blast);
spell_kelthuzad_frost_blast() : SpellScriptLoader("spell_kelthuzad_frost_blast") { }
class spell_kelthuzad_frost_blast_SpellScript : public SpellScript void FilterTargets(std::list<WorldObject*>& targets)
{
PrepareSpellScript(spell_kelthuzad_frost_blast_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
if (!caster || !caster->ToCreature())
return;
std::list<WorldObject*> tmplist;
for (auto& target : targets)
{
if (!target->ToUnit()->HasAura(SPELL_FROST_BLAST))
{
tmplist.push_back(target);
}
}
targets.clear();
for (auto& itr : tmplist)
{
targets.push_back(itr);
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kelthuzad_frost_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_kelthuzad_frost_blast_SpellScript();
}
};
class spell_kelthuzad_detonate_mana : public SpellScriptLoader
{
public:
spell_kelthuzad_detonate_mana() : SpellScriptLoader("spell_kelthuzad_detonate_mana") { }
class spell_kelthuzad_detonate_mana_AuraScript : public AuraScript
{
PrepareAuraScript(spell_kelthuzad_detonate_mana_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_MANA_DETONATION_DAMAGE });
}
void HandleScript(AuraEffect const* aurEff)
{
PreventDefaultAction();
Unit* target = GetTarget();
if (auto mana = int32(target->GetMaxPower(POWER_MANA) / 10))
{
mana = target->ModifyPower(POWER_MANA, -mana);
target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, nullptr, aurEff);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_AuraScript::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_kelthuzad_detonate_mana_AuraScript();
}
};
class spell_kelthuzad_dark_blast : public SpellScript
{
PrepareSpellScript(spell_kelthuzad_dark_blast);
void CalculateDamage(SpellEffIndex /*effIndex*/)
{ {
Unit* caster = GetCaster(); Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC)) if (!caster || !caster->ToCreature())
{
return; return;
std::list<WorldObject*> tmplist;
for (auto& target : targets)
{
if (!target->ToUnit()->HasAura(SPELL_FROST_BLAST))
{
tmplist.push_back(target);
}
}
targets.clear();
for (auto& itr : tmplist)
{
targets.push_back(itr);
} }
SetEffectValue(urand(1750,2250));
} }
void Register() override void Register() override
{ {
OnEffectLaunchTarget += SpellEffectFn(spell_kelthuzad_dark_blast::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kelthuzad_frost_blast::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
}
};
class spell_kelthuzad_detonate_mana_aura : public AuraScript
{
PrepareAuraScript(spell_kelthuzad_detonate_mana_aura);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_MANA_DETONATION_DAMAGE });
}
void HandleScript(AuraEffect const* aurEff)
{
PreventDefaultAction();
Unit* target = GetTarget();
if (auto mana = int32(target->GetMaxPower(POWER_MANA) / 10))
{
mana = target->ModifyPower(POWER_MANA, -mana);
target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, nullptr, aurEff);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_aura::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
} }
}; };
@@ -766,7 +723,6 @@ void AddSC_boss_kelthuzad_40()
{ {
new boss_kelthuzad_40(); new boss_kelthuzad_40();
new boss_kelthuzad_minion_40(); new boss_kelthuzad_minion_40();
// new spell_kelthuzad_frost_blast(); // RegisterSpellScript(spell_kelthuzad_frost_blast);
// new spell_kelthuzad_detonate_mana(); // RegisterSpellScript(spell_kelthuzad_detonate_mana_aura);
RegisterSpellScript(spell_kelthuzad_dark_blast);
} }

View File

@@ -15,32 +15,37 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "PassiveAI.h" #include "CreatureScript.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "PassiveAI.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "SpellAuras.h" #include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "naxxramas.h" #include "naxxramas.h"
enum Spells enum Spells
{ {
SPELL_WEB_WRAP = 28622, SPELL_WEB_SPRAY = 29484,
SPELL_WEB_SPRAY = 29484, SPELL_POISON_SHOCK = 28741,
SPELL_POISON_SHOCK = 28741, SPELL_NECROTIC_POISON = 54121,
SPELL_NECROTIC_POISON = 54121, SPELL_FRENZY = 54123,
SPELL_FRENZY = 54123, SPELL_WEB_WRAP_STUN = 28622,
SPELL_WEB_WRAP_SUMMON = 28627,
SPELL_WEB_WRAP_SUMMON_40 = 90007, // custom summon entry: 16486 -> 351075
SPELL_WEB_WRAP_PACIFY_5 = 28618
}; };
enum Events enum Events
{ {
EVENT_WEB_SPRAY = 1, EVENT_WEB_SPRAY = 1,
EVENT_POISON_SHOCK = 2, EVENT_POISON_SHOCK = 2,
EVENT_NECROTIC_POISON = 3, EVENT_NECROTIC_POISON = 3,
EVENT_WEB_WRAP = 4, EVENT_WEB_WRAP = 4,
EVENT_HEALTH_CHECK = 5, EVENT_HEALTH_CHECK = 5,
EVENT_SUMMON_SPIDERLINGS = 6 EVENT_SUMMON_SPIDERLINGS = 6,
EVENT_WEB_WRAP_APPLY_STUN = 7
}; };
enum Emotes enum Emotes
{ {
EMOTE_SPIDERS = 0, EMOTE_SPIDERS = 0,
@@ -54,11 +59,33 @@ enum Misc
NPC_MAEXXNA_SPIDERLING = 351088 NPC_MAEXXNA_SPIDERLING = 351088
}; };
const Position PosWrap[3] = const Position PosWrap[7] =
{ {
{3546.796f, -3869.082f, 296.450f, 0.0f}, {3496.615f, -3834.182f, 320.7863f},
{3531.271f, -3847.424f, 299.450f, 0.0f}, {3509.108f, -3833.922f, 320.4750f},
{3497.067f, -3843.384f, 302.384f, 0.0f} {3523.644f, -3838.309f, 320.5775f},
{3538.152f, -3846.353f, 320.5188f},
{3546.219f, -3856.167f, 320.9324f},
{3555.135f, -3869.507f, 320.8307f},
{3560.282f, -3886.143f, 321.2827f}
};
struct WebTargetSelector
{
WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
bool operator()(Unit const* target) const
{
if (!target->IsPlayer()) // never web nonplayers (pets, guardians, etc.)
return false;
if (_maexxna->GetVictim() == target) // never target tank
return false;
if (target->HasAura(SPELL_WEB_WRAP_STUN)) // never target targets that are already webbed
return false;
return true;
}
private:
Unit const* _maexxna;
}; };
class boss_maexxna_40 : public CreatureScript class boss_maexxna_40 : public CreatureScript
@@ -81,6 +108,7 @@ public:
InstanceScript* pInstance; InstanceScript* pInstance;
EventMap events; EventMap events;
SummonList summons; SummonList summons;
GuidList wraps;
bool IsInRoom() bool IsInRoom()
{ {
@@ -110,12 +138,12 @@ public:
{ {
BossAI::JustEngagedWith(who); BossAI::JustEngagedWith(who);
me->SetInCombatWithZone(); me->SetInCombatWithZone();
events.ScheduleEvent(EVENT_WEB_WRAP, 20000); events.ScheduleEvent(EVENT_WEB_WRAP, 20s);
events.ScheduleEvent(EVENT_WEB_SPRAY, 40000); events.ScheduleEvent(EVENT_WEB_SPRAY, 40s);
events.ScheduleEvent(EVENT_POISON_SHOCK, 10000); events.ScheduleEvent(EVENT_POISON_SHOCK, 10s);
events.ScheduleEvent(EVENT_NECROTIC_POISON, 5000); events.ScheduleEvent(EVENT_NECROTIC_POISON, 5s);
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30000); events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30s);
if (pInstance) if (pInstance)
{ {
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE))) if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE)))
@@ -149,7 +177,55 @@ public:
void JustDied(Unit* killer) override void JustDied(Unit* killer) override
{ {
BossAI::JustDied(killer); BossAI::JustDied(killer);
summons.DespawnAll(); }
void DoCastWebWrap()
{
std::list<Unit*> candidates;
SelectTargetList(candidates, 2, SelectTargetMethod::Random, 0, WebTargetSelector(me));
std::vector<uint32> positions {0, 1, 2, 3, 4, 5, 6};
Acore::Containers::RandomShuffle(positions);
if (candidates.empty())
return;
for (int i = 0; i < 2 ; i++)
{
if (candidates.empty())
break;
const Position &randomPos = PosWrap[positions[i]];
auto itr = candidates.begin();
if (candidates.size() > 1)
std::advance(itr, urand(0, candidates.size() - 1));
Unit *target = *itr;
candidates.erase(itr);
float dx = randomPos.GetPositionX() - target->GetPositionX();
float dy = randomPos.GetPositionY() - target->GetPositionY();
float distXY = std::hypotf(dx, dy);
// smooth knockback arc that avoids the ceiling
float horizontalSpeed = distXY / 1.5f;
float verticalSpeed = 28.0f;
if (distXY <= 10.0f)
verticalSpeed = 12.0f;
else if (distXY <= 20.0f)
verticalSpeed = 16.0f;
else if (distXY <= 30.0f)
verticalSpeed = 20.0f;
else if (distXY <= 40.0f)
verticalSpeed = 24.0f;
target->KnockbackFrom(randomPos.GetPositionX(), randomPos.GetPositionY(), -horizontalSpeed, verticalSpeed);
me->CastSpell(target, SPELL_WEB_WRAP_PACIFY_5, true); // pacify silence for 5 seconds
wraps.push_back(target->GetGUID());
}
events.ScheduleEvent(EVENT_WEB_WRAP_APPLY_STUN, 2s);
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
@@ -200,59 +276,48 @@ public:
break; break;
case EVENT_WEB_WRAP: case EVENT_WEB_WRAP:
Talk(EMOTE_WEB_WRAP); Talk(EMOTE_WEB_WRAP);
for (uint8 i = 0; i < 2; ++i) DoCastWebWrap();
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0, true, true, -SPELL_WEB_WRAP))
{
target->RemoveAura(SPELL_WEB_SPRAY);
uint8 pos = urand(0, 2);
if (Creature* wrap = me->SummonCreature(NPC_WEB_WRAP, PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000))
{
wrap->AI()->SetGUID(target->GetGUID());
target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20);
}
}
}
events.Repeat(40s); events.Repeat(40s);
break; break;
case EVENT_WEB_WRAP_APPLY_STUN:
{
for (auto& p : wraps)
{
if (Player* player = ObjectAccessor::GetPlayer(*me, p))
{
player->CastSpell(player, SPELL_WEB_WRAP_STUN, true);
}
}
wraps.clear();
break;
}
} }
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
}; };
}; };
class boss_maexxna_webwrap_40 : public CreatureScript
class boss_maexxna_webwrap40 : public CreatureScript
{ {
public: public:
boss_maexxna_webwrap40() : CreatureScript("boss_maexxna_webwrap40") { } boss_maexxna_webwrap_40() : CreatureScript("boss_maexxna_webwrap40") { }
CreatureAI* GetAI(Creature* pCreature) const override CreatureAI* GetAI(Creature* pCreature) const override
{ {
return GetNaxxramasAI<boss_maexxna_webwrap40AI>(pCreature); return GetNaxxramasAI<boss_maexxna_webwrap_40AI>(pCreature);
} }
struct boss_maexxna_webwrap40AI : public NullCreatureAI struct boss_maexxna_webwrap_40AI : public NullCreatureAI
{ {
explicit boss_maexxna_webwrap40AI(Creature* c) : NullCreatureAI(c) {} explicit boss_maexxna_webwrap_40AI(Creature* c) : NullCreatureAI(c) { }
ObjectGuid victimGUID; ObjectGuid victimGUID;
void SetGUID(ObjectGuid guid, int32 /*param*/) override void IsSummonedBy(WorldObject* summoner) override
{ {
victimGUID = guid; if (!summoner)
return;
if (victimGUID) victimGUID = summoner->GetGUID();
{
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
{
if (victim->GetTypeId() == TYPEID_PLAYER && victim->GetEntry() != NPC_WEB_WRAP)
{
int32 bp1 = 242;
victim->CastCustomSpell(victim, SPELL_WEB_WRAP, 0, &bp1, 0, true, nullptr, nullptr, me->GetGUID());
}
}
}
} }
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
@@ -261,15 +326,55 @@ public:
{ {
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID)) if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
{ {
victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP, me->GetGUID()); victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_SUMMON);
victim->RemoveAurasDueToSpell(SPELL_WEB_WRAP_STUN);
}
}
}
void UpdateAI(uint32 /*diff*/) override
{
if (victimGUID)
{
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
{
if (!victim->IsAlive())
{
me->KillSelf();
}
} }
} }
} }
}; };
}; };
class spell_web_wrap_damage : public AuraScript
{
public:
PrepareAuraScript(spell_web_wrap_damage);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WEB_WRAP_SUMMON });
}
void OnPeriodic(AuraEffect const* aurEff)
{
if (aurEff->GetTickNumber() == 2)
{
GetTarget()->CastSpell(GetTarget(), SPELL_WEB_WRAP_SUMMON, true);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_web_wrap_damage::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DAMAGE);
}
};
void AddSC_boss_maexxna_40() void AddSC_boss_maexxna_40()
{ {
new boss_maexxna_40(); new boss_maexxna_40();
new boss_maexxna_webwrap40(); new boss_maexxna_webwrap_40();
RegisterSpellScript(spell_web_wrap_damage);
} }

View File

@@ -300,51 +300,7 @@ public:
}; };
}; };
class spell_gothik_curse_of_the_plaguebringer_40 : public SpellScriptLoader
{
public:
spell_gothik_curse_of_the_plaguebringer_40() : SpellScriptLoader("spell_gothik_curse_of_the_plaguebringer_40") { }
class spell_gothik_curse_of_the_plaguebringer_40_AuraScript : public AuraScript
{
PrepareAuraScript(spell_gothik_curse_of_the_plaguebringer_40_AuraScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_REVENGE_OF_THE_PLAGUEBRINGER }); // Revenge of the Plaguebringer
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
CustomSpellValues values;
int32 bp0 = 1757; // instant damage
int32 bp1 = 874; // periodic damage
values.AddSpellMod(SPELLVALUE_BASE_POINT0, bp0);
values.AddSpellMod(SPELLVALUE_BASE_POINT1, bp1);
values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 3500); // 35yd
GetTarget()->CastCustomSpell(SPELL_REVENGE_OF_THE_PLAGUEBRINGER, values, GetTarget(), TRIGGERED_NONE, nullptr, nullptr, GetCasterGUID());
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_gothik_curse_of_the_plaguebringer_40_AuraScript::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_gothik_curse_of_the_plaguebringer_40_AuraScript();
}
};
void AddSC_boss_noth_40() void AddSC_boss_noth_40()
{ {
new boss_noth_40(); new boss_noth_40();
new spell_gothik_curse_of_the_plaguebringer_40();
} }

View File

@@ -17,6 +17,8 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "naxxramas.h" #include "naxxramas.h"
enum Says enum Says
@@ -73,13 +75,12 @@ public:
void SpawnHelpers() void SpawnHelpers()
{ {
// 10man
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2762.23f, -3085.07f, 267.685f, 1.95f); me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2762.23f, -3085.07f, 267.685f, 1.95f);
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2758.24f, -3110.97f, 267.685f, 3.94f); me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2758.24f, -3110.97f, 267.685f, 3.94f);
if (Is25ManRaid()) // 25man
{ me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2782.45f, -3088.03f, 267.685f, 0.75f);
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2782.45f, -3088.03f, 267.685f, 0.75f); me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2778.56f, -3113.74f, 267.685f, 5.28f);
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2778.56f, -3113.74f, 267.685f, 5.28f);
}
} }
void JustSummoned(Creature* cr) override void JustSummoned(Creature* cr) override
@@ -136,7 +137,8 @@ public:
BossAI::JustEngagedWith(who); BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 20000); // TODO: This can be 30 seconds to match vanilla events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 20000); // TODO: This can be 30 seconds to match vanilla
events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 15000); events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 5s);
// events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 15s);
//events.ScheduleEvent(EVENT_JAGGED_KNIFE, 10000); // New wrath mechanic //events.ScheduleEvent(EVENT_JAGGED_KNIFE, 10000); // New wrath mechanic
summons.DoZoneInCombat(); summons.DoZoneInCombat();
} }
@@ -157,17 +159,9 @@ public:
events.RepeatEvent(20000); events.RepeatEvent(20000);
break; break;
case EVENT_DISRUPTING_SHOUT: case EVENT_DISRUPTING_SHOUT:
{ me->CastSpell(me, SPELL_DISRUPTING_SHOUT, false);
// TODO: Custom patch needed to implement power burn, or remove visual effect events.RepeatEvent(10000);
// 45yd that ignores line of sight
CustomSpellValues values;
int32 customDisruptingShoutDamage = 2200; // some value as we ignore LoS without patch
values.AddSpellMod(SPELLVALUE_BASE_POINT0, customDisruptingShoutDamage);
values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 4500); // 45yd
me->CastCustomSpell(SPELL_DISRUPTING_SHOUT, values, me, TRIGGERED_NONE, nullptr, nullptr, ObjectGuid::Empty);
events.RepeatEvent(15000);
break; break;
}
case EVENT_JAGGED_KNIFE: case EVENT_JAGGED_KNIFE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f)) if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f))
{ {

View File

@@ -469,50 +469,39 @@ public:
}; };
// This will overwrite the declared 10 and 25 man frost explosion to handle all versions of the spell script // This will overwrite the declared 10 and 25 man frost explosion to handle all versions of the spell script
class spell_sapphiron_frost_explosion_40 : public SpellScriptLoader class spell_sapphiron_frost_explosion : public SpellScript
{ {
public: PrepareSpellScript(spell_sapphiron_frost_explosion);
spell_sapphiron_frost_explosion_40() : SpellScriptLoader("spell_sapphiron_frost_explosion") { }
class spell_sapphiron_frost_explosion_40_SpellScript : public SpellScript void FilterTargets(std::list<WorldObject*>& targets)
{ {
PrepareSpellScript(spell_sapphiron_frost_explosion_40_SpellScript); Unit* caster = GetCaster();
if (!caster || !caster->ToCreature())
return;
void FilterTargets(std::list<WorldObject*>& targets) std::list<WorldObject*> tmplist;
for (auto& target : targets)
{ {
Unit* caster = GetCaster(); if (CAST_AI(boss_sapphiron_40::boss_sapphiron_40AI, caster->ToCreature()->AI())->IsValidExplosionTarget(target))
if (!caster || !caster->ToCreature())
return;
std::list<WorldObject*> tmplist;
for (auto& target : targets)
{ {
if (CAST_AI(boss_sapphiron_40::boss_sapphiron_40AI, caster->ToCreature()->AI())->IsValidExplosionTarget(target)) tmplist.push_back(target);
{
tmplist.push_back(target);
}
}
targets.clear();
for (auto& itr : tmplist)
{
targets.push_back(itr);
} }
} }
targets.clear();
void Register() override for (auto& itr : tmplist)
{ {
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_explosion_40_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); targets.push_back(itr);
} }
}; }
SpellScript* GetSpellScript() const override void Register() override
{ {
return new spell_sapphiron_frost_explosion_40_SpellScript(); OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_explosion::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
} }
}; };
void AddSC_boss_sapphiron_40() void AddSC_boss_sapphiron_40()
{ {
new boss_sapphiron_40(); new boss_sapphiron_40();
new spell_sapphiron_frost_explosion_40(); RegisterSpellScript(spell_sapphiron_frost_explosion);
} }

View File

@@ -610,126 +610,104 @@ public:
}; };
// This will overwrite the declared 10 and 25 man pos_neg_charge to handle all versions of the spell script // This will overwrite the declared 10 and 25 man pos_neg_charge to handle all versions of the spell script
class spell_thaddius_pos_neg_charge_40 : public SpellScriptLoader class spell_thaddius_pos_neg_charge : public SpellScript
{ {
public: PrepareSpellScript(spell_thaddius_pos_neg_charge);
spell_thaddius_pos_neg_charge_40() : SpellScriptLoader("spell_thaddius_pos_neg_charge") { }
class spell_thaddius_pos_neg_charge_40_SpellScript : public SpellScript void HandleTargets(std::list<WorldObject*>& targets)
{ {
PrepareSpellScript(spell_thaddius_pos_neg_charge_40_SpellScript); uint8 count = 0;
for (auto& ihit : targets)
void HandleTargets(std::list<WorldObject*>& targets)
{ {
uint8 count = 0; if (ihit->GetGUID() != GetCaster()->GetGUID())
for (auto& ihit : targets)
{ {
if (ihit->GetGUID() != GetCaster()->GetGUID()) if (Player* target = ihit->ToPlayer())
{ {
if (Player* target = ihit->ToPlayer()) if (target->HasAura(GetTriggeringSpell()->Id))
{ {
if (target->HasAura(GetTriggeringSpell()->Id)) ++count;
{
++count;
}
} }
} }
} }
if (count)
{
uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK;
GetCaster()->SetAuraStack(spellId, GetCaster(), count);
}
} }
void HandleDamage(SpellEffIndex /*effIndex*/) if (count)
{ {
if (!GetTriggeringSpell()) uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK;
return; GetCaster()->SetAuraStack(spellId, GetCaster(), count);
Unit* target = GetHitUnit();
if (!target)
return;
if (target->HasAura(GetTriggeringSpell()->Id) || target->GetTypeId() != TYPEID_PLAYER)
{
SetHitDamage(0);
}
else if (target->GetInstanceScript())
{
target->GetInstanceScript()->SetData(DATA_CHARGES_CROSSED, 0);
}
// Adjust damage to 2000 from 4500 for naxx40
if (target->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC)
{
SetHitDamage(2000);
}
} }
}
void Register() override void HandleDamage(SpellEffIndex /*effIndex*/)
{
OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge_40_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_pos_neg_charge_40_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_thaddius_pos_neg_charge_40_SpellScript(); if (!GetTriggeringSpell())
return;
Unit* target = GetHitUnit();
if (!target)
return;
if (target->HasAura(GetTriggeringSpell()->Id) || target->GetTypeId() != TYPEID_PLAYER)
{
SetHitDamage(0);
}
else if (target->GetInstanceScript())
{
target->GetInstanceScript()->SetData(DATA_CHARGES_CROSSED, 0);
}
// Adjust damage to 2000 from 4500 for naxx40
if (target->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC)
{
SetHitDamage(2000);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_pos_neg_charge::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
} }
}; };
class spell_thaddius_polarity_shift : public SpellScriptLoader class spell_thaddius_polarity_shift : public SpellScript
{ {
public: PrepareSpellScript(spell_thaddius_polarity_shift);
spell_thaddius_polarity_shift() : SpellScriptLoader("spell_thaddius_polarity_shift") { }
class spell_thaddius_polarity_shift_SpellScript : public SpellScript bool Validate(SpellInfo const* /*spell*/) override
{ {
PrepareSpellScript(spell_thaddius_polarity_shift_SpellScript); return ValidateSpellInfo({ SPELL_POSITIVE_POLARITY, SPELL_NEGATIVE_POLARITY });
}
bool Validate(SpellInfo const* /*spell*/) override void HandleDummy(SpellEffIndex /* effIndex */)
{
Unit* caster = GetCaster();
if (Unit* target = GetHitUnit())
{ {
return ValidateSpellInfo({ SPELL_POSITIVE_POLARITY, SPELL_NEGATIVE_POLARITY }); target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK);
target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK);
target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, caster->GetGUID());
} }
}
void HandleDummy(SpellEffIndex /* effIndex */) void HandleAfterCast()
{
if (GetCaster())
{ {
Unit* caster = GetCaster(); if (Creature* caster = GetCaster()->ToCreature())
if (Unit* target = GetHitUnit())
{ {
target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK); if (caster->GetEntry() == NPC_THADDIUS_40)
target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK);
target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, caster->GetGUID());
}
}
void HandleAfterCast()
{
if (GetCaster())
{
if (Creature* caster = GetCaster()->ToCreature())
{ {
if (caster->GetEntry() == NPC_THADDIUS_40) caster->AI()->Talk(SAY_ELECT);
{ caster->AI()->Talk(EMOTE_POLARITY_SHIFTED);
caster->AI()->Talk(SAY_ELECT);
caster->AI()->Talk(EMOTE_POLARITY_SHIFTED);
}
} }
} }
} }
}
void Register() override void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
AfterCast += SpellCastFn(spell_thaddius_polarity_shift_SpellScript::HandleAfterCast);
}
};
SpellScript* GetSpellScript() const override
{ {
return new spell_thaddius_polarity_shift_SpellScript(); OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
AfterCast += SpellCastFn(spell_thaddius_polarity_shift::HandleAfterCast);
} }
}; };
@@ -775,39 +753,28 @@ public:
} }
}; };
class spell_feugen_static_field_40 : public SpellScriptLoader class spell_feugen_static_field : public SpellScript
{ {
public: PrepareSpellScript(spell_feugen_static_field);
spell_feugen_static_field_40() : SpellScriptLoader("spell_feugen_static_field") { }
class spell_feugen_static_field_40_SpellScript : public SpellScript void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{ {
PrepareSpellScript(spell_feugen_static_field_40_SpellScript); Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{ {
Unit* caster = GetCaster(); return;
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
if (Unit* target = GetHitUnit())
{
Powers PowerType = POWER_MANA;
int32 drainedAmount = -target->ModifyPower(PowerType, -500);
SetEffectValue(drainedAmount);
}
} }
if (Unit* target = GetHitUnit())
void Register() override
{ {
OnEffectLaunchTarget += SpellEffectFn(spell_feugen_static_field_40_SpellScript::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); Powers PowerType = POWER_MANA;
int32 drainedAmount = -target->ModifyPower(PowerType, -500);
SetEffectValue(drainedAmount);
} }
}; }
SpellScript* GetSpellScript() const override void Register() override
{ {
return new spell_feugen_static_field_40_SpellScript(); OnEffectLaunchTarget += SpellEffectFn(spell_feugen_static_field::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
} }
}; };
@@ -816,8 +783,8 @@ void AddSC_boss_thaddius_40()
new boss_thaddius_40(); new boss_thaddius_40();
new boss_thaddius_summon_40(); new boss_thaddius_summon_40();
// new npc_tesla(); // new npc_tesla();
new spell_thaddius_pos_neg_charge_40(); RegisterSpellScript(spell_thaddius_pos_neg_charge);
// new spell_thaddius_polarity_shift(); // RegisterSpellScript(spell_thaddius_polarity_shift);
// new at_thaddius_entrance(); // new at_thaddius_entrance();
new spell_feugen_static_field_40(); RegisterSpellScript(spell_feugen_static_field);
} }

View File

@@ -0,0 +1,175 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "Player.h"
#include "naxxramas.h"
class npc_naxx40_area_trigger : public CreatureScript
{
private:
static bool isAttuned(Player* player)
{
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_1) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_2) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_3) == QUEST_STATUS_REWARDED)
return true;
return false;
}
public:
npc_naxx40_area_trigger() : CreatureScript("npc_naxx40_area_trigger") {}
struct npc_naxx40_area_triggerAI: public ScriptedAI
{
npc_naxx40_area_triggerAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisplayId(11686); // Invisible
}
void MoveInLineOfSight(Unit* who) override
{
if (who && me->GetDistance2d(who) < 5.0f)
{
if (Player* player = who->ToPlayer())
{
if (isAttuned(player))
{
player->SetRaidDifficulty(RAID_DIFFICULTY_10MAN_HEROIC);
player->TeleportTo(533, 3005.51f, -3434.64f, 304.195f, 6.2831f);
}
}
}
else if (who && me->GetDistance2d(who) < 20.0f)
{
if (Player* player = who->ToPlayer())
{
if (isAttuned(player))
{
GameObject* door = me->FindNearestGameObject(NAXX_STRATH_GATE, 100.0f);
if (door)
{
door->SetGoState(GO_STATE_ACTIVE);
}
}
}
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_naxx40_area_triggerAI(creature);
}
};
class boss_heigan_eye_stalk_40 : public CreatureScript
{
public:
boss_heigan_eye_stalk_40() : CreatureScript("boss_heigan_eye_stalk_40") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetNaxxramasAI<boss_heigan_eye_stalk_40AI>(creature);
}
struct boss_heigan_eye_stalk_40AI : public ScriptedAI
{
explicit boss_heigan_eye_stalk_40AI(Creature* creature) : ScriptedAI(creature)
{
timeSinceSpawn = 0;
haveSubmerged = false;
haveCastSubmerge = false;
}
uint32 timeSinceSpawn;
bool haveSubmerged;
bool haveCastSubmerge;
const uint32 SPELL_MIND_FLAY = 29407;
void Reset() override
{
me->SetNoCallAssistance(true);
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
}
void KilledUnit(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript())
{
me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0);
}
}
void MoveInLineOfSight(Unit* who) override
{
if (timeSinceSpawn < 3000)
return;
if (!who || !(who->GetDistance2d(me) <= 19.0f))
return;
if (me->HasReactState(REACT_AGGRESSIVE) && me->CanStartAttack(who))
{
if (!me->IsWithinLOSInMap(who))
{
return;
}
me->SetNoCallAssistance(true);
if (!me->GetVictim())
{
AttackStart(who);
}
else if (me->GetMap()->IsDungeon())
{
who->SetInCombatWith(me);
me->AddThreat(who, 0.0f);
}
}
}
void UpdateAI(uint32 diff) override
{
me->SetNoCallAssistance(true);
timeSinceSpawn += std::min(diff, std::numeric_limits<uint32>::max() - timeSinceSpawn);
if (haveSubmerged)
{
if (!haveCastSubmerge)
{
haveCastSubmerge = true;
me->CastSpell(me, 26234, false);
}
return;
}
if (!UpdateVictim())
return;
if (!me->IsNonMeleeSpellCast(false))
{
if (me->GetDistance(me->GetVictim()) < 35.0f)
{
int32 bp0 = 750; // damage
int32 bp1 = -20; // movement speed
me->CastCustomSpell(me->GetVictim(), SPELL_MIND_FLAY, &bp0, &bp1, 0, false, nullptr, nullptr, ObjectGuid::Empty);
}
else
{
DoStopAttack();
}
}
DoMeleeAttackIfReady();
}
};
};
void AddSC_custom_creatures_40()
{
new npc_naxx40_area_trigger();
new boss_heigan_eye_stalk_40();
}

View File

@@ -0,0 +1,52 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "naxxramas.h"
#include "IndividualProgression.h"
class gobject_naxx40_tele : public GameObjectScript
{
private:
static bool isAttuned(Player* player)
{
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_1) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_2) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_3) == QUEST_STATUS_REWARDED)
return true;
return false;
}
public:
gobject_naxx40_tele() : GameObjectScript("gobject_naxx40_tele") { }
struct gobject_naxx40_teleAI: GameObjectAI
{
explicit gobject_naxx40_teleAI(GameObject* object) : GameObjectAI(object) { };
};
GameObjectAI* GetAI(GameObject* object) const override
{
return new gobject_naxx40_teleAI(object);
}
bool OnGossipHello(Player* player, GameObject* /*go*/) override
{
if ((!sIndividualProgression->requireNaxxStrath || player->GetQuestStatus(NAXX40_ENTRANCE_FLAG) == QUEST_STATUS_REWARDED) && isAttuned(player))
{
player->SetRaidDifficulty(RAID_DIFFICULTY_10MAN_HEROIC);
player->TeleportTo(533, 3005.51f, -3434.64f, 304.195f, 6.2831f);
}
return true;
}
};
void AddSC_custom_gameobjects_40()
{
new gobject_naxx40_tele();
}

View File

@@ -0,0 +1,347 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
#include "naxxramas.h"
// 28785 - Locust Swarm
// Locust Swarm: Reduce damage ~1500 to ~1000, increase radius 25yd to 30yd
enum LocustSwarm
{
SPELL_LOCUST_SWARM = 28785,
SPELL_LOCUST_SWARM_TRIGGER = 28786, // periodic effect
};
class spell_anub_locust_swarm_aura_40 : public AuraScript
{
PrepareAuraScript(spell_anub_locust_swarm_aura_40);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_LOCUST_SWARM_TRIGGER });
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
int32 modifiedLocustSwarmDamage = 812;
CustomSpellValues values;
values.AddSpellMod(SPELLVALUE_BASE_POINT0, modifiedLocustSwarmDamage);
values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 3000); // 30yd
caster->CastCustomSpell(SPELL_LOCUST_SWARM_TRIGGER, values, caster, TRIGGERED_FULL_MASK, nullptr, nullptr, GetCasterGUID());
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_anub_locust_swarm_aura_40::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
// 28865 - Consumption
// add Naxx10HC damage
class spell_gen_consumption : public SpellScript
{
PrepareSpellScript(spell_gen_consumption);
void CalculateDamage(SpellEffIndex /*effIndex*/)
{
Map* map = GetCaster()->GetMap();
if (!map)
{
return;
}
int32 value = 0;
if (map->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) // NAXX25 N
{
value = urand(4500, 4700);
}
else if (map->GetId() == 533) // NAXX10 N
{
if (map->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL)
{
value = urand(3000, 3200);
}
else
{
value = urand(3960, 4840); // NAXX40
}
}
else if (map->GetId() == 532) // Karazhan
{
value = urand(1110, 1310);
}
if (value)
{
SetEffectValue(value);
}
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_gen_consumption::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
// 28241 - Poison Cloud
// poison damage by Poison Cloud ~3k to ~1k
class spell_grobbulus_poison_cloud_poison_damage_40 : public SpellScript
{
PrepareSpellScript(spell_grobbulus_poison_cloud_poison_damage_40);
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
SetEffectValue(urand(1110, 1290));
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_grobbulus_poison_cloud_poison_damage_40::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
// 29350 - Plague Cloud
enum PlagueCloud
{
SPELL_PLAGUE_CLOUD_TRIGGER = 30122,
};
class spell_heigan_plague_cloud_aura_40 : public AuraScript
{
PrepareAuraScript(spell_heigan_plague_cloud_aura_40);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PLAGUE_CLOUD_TRIGGER });
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
int32 bp0 = 4000;
caster->CastCustomSpell(caster, SPELL_PLAGUE_CLOUD_TRIGGER, &bp0, 0, 0, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_heigan_plague_cloud_aura_40::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
// 29371 - Eruption
class spell_heigan_eruption_40 : public SpellScript
{
PrepareSpellScript(spell_heigan_eruption_40);
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
SetEffectValue(urand(3500, 4500));
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_heigan_eruption_40::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
// 28819 - Submerge Visual
class spell_submerge_visual_aura : public AuraScript
{
PrepareAuraScript(spell_submerge_visual_aura);
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->SetStandState(UNIT_STAND_STATE_SUBMERGED);
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->SetStandState(UNIT_STAND_STATE_STAND);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_submerge_visual_aura::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_submerge_visual_aura::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
// 28457 - Dark Blast
class spell_kelthuzad_dark_blast_40 : public SpellScript
{
PrepareSpellScript(spell_kelthuzad_dark_blast_40);
void CalculateDamage(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
SetEffectValue(urand(1750,2250));
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_kelthuzad_dark_blast_40::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
// 29213 - Curse of the Plaguebringer
enum CurseOfThePlaguebringer
{
SPELL_REVENGE_OF_THE_PLAGUEBRINGER = 29214,
};
class spell_noth_curse_of_the_plaguebringer_aura_40 : public AuraScript
{
PrepareAuraScript(spell_noth_curse_of_the_plaguebringer_aura_40);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_REVENGE_OF_THE_PLAGUEBRINGER }); // Revenge of the Plaguebringer
}
void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
PreventDefaultAction();
CustomSpellValues values;
int32 bp0 = 1757; // instant damage
int32 bp1 = 874; // periodic damage
values.AddSpellMod(SPELLVALUE_BASE_POINT0, bp0);
values.AddSpellMod(SPELLVALUE_BASE_POINT1, bp1);
values.AddSpellMod(SPELLVALUE_RADIUS_MOD, 3500); // 35yd
GetTarget()->CastCustomSpell(SPELL_REVENGE_OF_THE_PLAGUEBRINGER, values, GetTarget(), TRIGGERED_NONE, nullptr, nullptr, GetCasterGUID());
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_noth_curse_of_the_plaguebringer_aura_40::HandleTriggerSpell, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
//
class spell_razuvious_disrupting_shout_40 : public SpellScript
{
PrepareSpellScript(spell_razuvious_disrupting_shout_40);
void PreventLaunchHit(SpellEffIndex effIndex)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
if (Unit* target = GetHitUnit())
{
// ignore los -> not ignore los
// radius 60yd -> 45yd
PreventHitDefaultEffect(effIndex);
if (!target->IsWithinLOSInMap(caster) || !target->IsWithinDist2d(caster, 45.0f))
{
SetEffectValue(0);
return;
}
Powers PowerType = POWER_MANA;
// int32 amountToDrain = urand(4050,4950);
int32 amountToDrain = urand(500,501);
int32 drainedAmount = -target->ModifyPower(PowerType, -amountToDrain);
SetEffectValue(drainedAmount);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_razuvious_disrupting_shout_40::PreventLaunchHit, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
class spell_unholy_staff_arcane_explosion_40 : public SpellScript
{
PrepareSpellScript(spell_unholy_staff_arcane_explosion_40);
void PreventLaunchHit(SpellEffIndex effIndex)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
if (Unit* target = GetHitUnit())
{
if (target->IsWithinDist2d(caster, 20.0f))
{
SetEffectValue(urand(1838, 2361));
}
else
{
PreventHitDefaultEffect(effIndex);
}
}
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_unholy_staff_arcane_explosion_40::PreventLaunchHit, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
class spell_disease_cloud_damage_40 : public SpellScript
{
PrepareSpellScript(spell_disease_cloud_damage_40);
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC))
{
return;
}
SetEffectValue(urand(278,322));
}
void Register() override
{
OnEffectLaunchTarget += SpellEffectFn(spell_disease_cloud_damage_40::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
void AddSC_custom_spells_40()
{
RegisterSpellScript(spell_anub_locust_swarm_aura_40);
RegisterSpellScript(spell_gen_consumption);
RegisterSpellScript(spell_grobbulus_poison_cloud_poison_damage_40);
RegisterSpellScript(spell_heigan_plague_cloud_aura_40);
RegisterSpellScript(spell_heigan_eruption_40);
RegisterSpellScript(spell_submerge_visual_aura);
RegisterSpellScript(spell_kelthuzad_dark_blast_40);
RegisterSpellScript(spell_noth_curse_of_the_plaguebringer_aura_40);
RegisterSpellScript(spell_razuvious_disrupting_shout_40);
RegisterSpellScript(spell_unholy_staff_arcane_explosion_40);
RegisterSpellScript(spell_disease_cloud_damage_40);
}

View File

@@ -25,7 +25,6 @@
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "GameObjectAI.h" #include "GameObjectAI.h"
#include "naxxramas.h" #include "naxxramas.h"
#include "IndividualProgression.h"
const float HeiganPos[2] = {2796, -3707}; const float HeiganPos[2] = {2796, -3707};
const float HeiganEruptionSlope[3] = const float HeiganEruptionSlope[3] =
@@ -74,6 +73,7 @@ public:
// NPCs // NPCs
PatchwerkRoomTrash.clear(); PatchwerkRoomTrash.clear();
HeiganBackRoomAdds.clear();
// Controls // Controls
_horsemanKilled = 0; _horsemanKilled = 0;
@@ -95,6 +95,7 @@ public:
} }
std::set<GameObject*> HeiganEruption[4]; std::set<GameObject*> HeiganEruption[4];
std::set<GameObject*> HeiganEruptionTunnel;
// GOs // GOs
ObjectGuid _patchwerkGateGUID; ObjectGuid _patchwerkGateGUID;
@@ -103,6 +104,7 @@ public:
ObjectGuid _nothExitGateGUID; ObjectGuid _nothExitGateGUID;
ObjectGuid _heiganGateGUID; ObjectGuid _heiganGateGUID;
ObjectGuid _heiganGateExitGUID; ObjectGuid _heiganGateExitGUID;
ObjectGuid _heiganGateExitOldGUID;
ObjectGuid _loathebGateGUID; ObjectGuid _loathebGateGUID;
ObjectGuid _anubGateGUID; ObjectGuid _anubGateGUID;
ObjectGuid _anubNextGateGUID; ObjectGuid _anubNextGateGUID;
@@ -136,6 +138,7 @@ public:
// NPCs // NPCs
GuidList PatchwerkRoomTrash; GuidList PatchwerkRoomTrash;
GuidList HeiganBackRoomAdds;
ObjectGuid _patchwerkGUID; ObjectGuid _patchwerkGUID;
ObjectGuid _thaddiusGUID; ObjectGuid _thaddiusGUID;
ObjectGuid _stalaggGUID; ObjectGuid _stalaggGUID;
@@ -179,6 +182,17 @@ public:
itr->SendCustomAnim(itr->GetGoAnimProgress()); itr->SendCustomAnim(itr->GetGoAnimProgress());
itr->CastSpell(nullptr, SPELL_ERUPTION); itr->CastSpell(nullptr, SPELL_ERUPTION);
} }
}
}
void HeiganEruptSectionsTunnel()
{
// doesn't work
for (auto itr : HeiganEruptionTunnel)
{
itr->SendCustomAnim(itr->GetGoAnimProgress());
itr->CastSpell(nullptr, SPELL_ERUPTION);
} }
} }
@@ -197,6 +211,15 @@ public:
switch(creature->GetEntry()) switch(creature->GetEntry())
{ {
case NPC_ROTTING_MAGGOT_40:
HeiganBackRoomAdds.push_back(creature->GetGUID());
return;
case NPC_DISEASED_MAGGOT_40:
HeiganBackRoomAdds.push_back(creature->GetGUID());
return;
case NPC_EYE_STALK_40:
HeiganBackRoomAdds.push_back(creature->GetGUID());
return;
case NPC_PATCHWERK: case NPC_PATCHWERK:
_patchwerkGUID = creature->GetGUID(); _patchwerkGUID = creature->GetGUID();
return; return;
@@ -314,6 +337,11 @@ public:
HeiganEruption[GetEruptionSection(pGo->GetPositionX(), pGo->GetPositionY())].insert(pGo); HeiganEruption[GetEruptionSection(pGo->GetPositionX(), pGo->GetPositionY())].insert(pGo);
return; return;
} }
if (pGo->GetGOInfo()->entry == 361001)
{
HeiganEruptionTunnel.insert(pGo);
return;
}
switch(pGo->GetEntry()) switch(pGo->GetEntry())
{ {
@@ -359,6 +387,13 @@ public:
pGo->SetGoState(GO_STATE_ACTIVE); pGo->SetGoState(GO_STATE_ACTIVE);
} }
break; break;
case GO_HEIGAN_EXIT_GATE_OLD:
_heiganGateExitOldGUID = pGo->GetGUID();
if (GetBossState(BOSS_HEIGAN) == DONE)
{
pGo->SetGoState(GO_STATE_ACTIVE);
}
break;
case GO_LOATHEB_GATE: case GO_LOATHEB_GATE:
_loathebGateGUID = pGo->GetGUID(); _loathebGateGUID = pGo->GetGUID();
if (GetBossState(BOSS_LOATHEB) == DONE) if (GetBossState(BOSS_LOATHEB) == DONE)
@@ -688,6 +723,9 @@ public:
case DATA_HEIGAN_ERUPTION: case DATA_HEIGAN_ERUPTION:
HeiganEruptSections(data); HeiganEruptSections(data);
return; return;
case DATA_HEIGAN_ERUPTION_TUNNEL:
HeiganEruptSectionsTunnel();
return;
case DATA_HAD_THADDIUS_GREET: case DATA_HAD_THADDIUS_GREET:
_hadThaddiusGreet = (data == 1); _hadThaddiusGreet = (data == 1);
default: default:
@@ -921,6 +959,13 @@ public:
} }
break; break;
case BOSS_HEIGAN: case BOSS_HEIGAN:
for (auto& mobGUID : HeiganBackRoomAdds)
{
if (Creature* mob = instance->GetCreature(mobGUID))
{
mob->DespawnOrUnsummon();
}
}
if (GameObject* go = instance->GetGameObject(_heiganGateGUID)) if (GameObject* go = instance->GetGameObject(_heiganGateGUID))
{ {
go->SetGoState(GO_STATE_ACTIVE); go->SetGoState(GO_STATE_ACTIVE);
@@ -929,6 +974,10 @@ public:
{ {
go->SetGoState(GO_STATE_ACTIVE); go->SetGoState(GO_STATE_ACTIVE);
} }
if (GameObject* go = instance->GetGameObject(_heiganGateExitOldGUID))
{
go->SetGoState(GO_STATE_ACTIVE);
}
break; break;
case BOSS_LOATHEB: case BOSS_LOATHEB:
if (GameObject* go = instance->GetGameObject(_loathebGateGUID)) if (GameObject* go = instance->GetGameObject(_loathebGateGUID))
@@ -1143,6 +1192,10 @@ public:
// GameObjects // GameObjects
case DATA_HEIGAN_ENTER_GATE: case DATA_HEIGAN_ENTER_GATE:
return _heiganGateGUID; return _heiganGateGUID;
case DATA_HEIGAN_EXIT_GATE_OLD:
return _heiganGateExitOldGUID;
case DATA_HEIGAN_EXIT_GATE:
return _heiganGateExitGUID;
case DATA_LOATHEB_GATE: case DATA_LOATHEB_GATE:
return _loathebGateGUID; return _loathebGateGUID;
case DATA_ANUB_GATE: case DATA_ANUB_GATE:
@@ -1203,6 +1256,7 @@ public:
} }
}; };
}; };
class boss_naxxramas_misc : public CreatureScript class boss_naxxramas_misc : public CreatureScript
{ {
public: public:
@@ -1274,112 +1328,11 @@ public:
}; };
}; };
class npc_naxx40_area_trigger : public CreatureScript
{
private:
static bool isAttuned(Player* player)
{
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_1) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_2) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_3) == QUEST_STATUS_REWARDED)
return true;
return false;
}
public:
npc_naxx40_area_trigger() : CreatureScript("npc_naxx40_area_trigger") {}
struct npc_naxx40_area_triggerAI: public ScriptedAI
{
npc_naxx40_area_triggerAI(Creature* creature) : ScriptedAI(creature)
{
me->SetDisplayId(11686); // Invisible
}
void MoveInLineOfSight(Unit* who) override
{
if (who && me->GetDistance2d(who) < 5.0f)
{
if (Player* player = who->ToPlayer())
{
if (isAttuned(player))
{
player->SetRaidDifficulty(RAID_DIFFICULTY_10MAN_HEROIC);
player->TeleportTo(533, 3005.51f, -3434.64f, 304.195f, 6.2831f);
}
}
}
else if (who && me->GetDistance2d(who) < 20.0f)
{
if (Player* player = who->ToPlayer())
{
if (isAttuned(player))
{
GameObject* door = me->FindNearestGameObject(NAXX_STRATH_GATE, 100.0f);
if (door)
{
door->SetGoState(GO_STATE_ACTIVE);
}
}
}
}
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_naxx40_area_triggerAI(creature);
}
};
class gobject_naxx40_tele : public GameObjectScript
{
private:
static bool isAttuned(Player* player)
{
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_1) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_2) == QUEST_STATUS_REWARDED)
return true;
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_3) == QUEST_STATUS_REWARDED)
return true;
return false;
}
public:
gobject_naxx40_tele() : GameObjectScript("gobject_naxx40_tele") { }
struct gobject_naxx40_teleAI: GameObjectAI
{
explicit gobject_naxx40_teleAI(GameObject* object) : GameObjectAI(object) { };
};
GameObjectAI* GetAI(GameObject* object) const override
{
return new gobject_naxx40_teleAI(object);
}
bool OnGossipHello(Player* player, GameObject* /*go*/) override
{
if ((!sIndividualProgression->requireNaxxStrath || player->GetQuestStatus(NAXX40_ENTRANCE_FLAG) == QUEST_STATUS_REWARDED) && isAttuned(player))
{
player->SetRaidDifficulty(RAID_DIFFICULTY_10MAN_HEROIC);
player->TeleportTo(533, 3005.51f, -3434.64f, 304.195f, 6.2831f);
}
return true;
}
};
class NaxxPlayerScript : public PlayerScript class NaxxPlayerScript : public PlayerScript
{ {
public: public:
NaxxPlayerScript() : PlayerScript("NaxxPlayerScript") { } NaxxPlayerScript() : PlayerScript("NaxxPlayerScript") { }
void OnBeforeChooseGraveyard(Player* player, TeamId /*teamId*/, bool /*nearCorpse*/, uint32& graveyardOverride) override void OnBeforeChooseGraveyard(Player* player, TeamId /*teamId*/, bool /*nearCorpse*/, uint32& graveyardOverride) override
{ {
if (player->GetMapId() == MAP_NAXX && player->GetMap()->GetSpawnMode() == RAID_DIFFICULTY_10MAN_HEROIC) if (player->GetMapId() == MAP_NAXX && player->GetMap()->GetSpawnMode() == RAID_DIFFICULTY_10MAN_HEROIC)
@@ -1419,7 +1372,8 @@ public:
player->TeleportTo(533, 2992.5f, -3434.42f, 293.94f, 3.13f); player->TeleportTo(533, 2992.5f, -3434.42f, 293.94f, 3.13f);
break; break;
} }
return true; } return true;
}
}; };
class naxx_exit_trigger : public AreaTriggerScript class naxx_exit_trigger : public AreaTriggerScript
@@ -1454,7 +1408,6 @@ public:
} }
}; };
const Position sapphironEntryTP = { 3498.300049f, -5349.490234f, 144.968002f, 1.3698910f }; const Position sapphironEntryTP = { 3498.300049f, -5349.490234f, 144.968002f, 1.3698910f };
class at_naxxramas_hub_portal : public AreaTriggerScript class at_naxxramas_hub_portal : public AreaTriggerScript
@@ -1491,10 +1444,7 @@ public:
class NaxxEntryFlag_AllMapScript : public AllMapScript class NaxxEntryFlag_AllMapScript : public AllMapScript
{ {
public: public:
NaxxEntryFlag_AllMapScript() NaxxEntryFlag_AllMapScript() : AllMapScript("NaxxEntryFlag_AllMapScript") { }
: AllMapScript("NaxxEntryFlag_AllMapScript")
{
}
void OnPlayerEnterAll(Map* map, Player* player) override void OnPlayerEnterAll(Map* map, Player* player) override
{ {
@@ -1521,12 +1471,10 @@ public:
void AddSC_instance_naxxramas_combined() void AddSC_instance_naxxramas_combined()
{ {
new instance_naxxramas_combined(); new instance_naxxramas_combined();
new npc_naxx40_area_trigger();
new NaxxPlayerScript(); new NaxxPlayerScript();
new naxx_exit_trigger(); new naxx_exit_trigger();
new naxx_northrend_entrance(); new naxx_northrend_entrance();
new at_naxxramas_hub_portal(); new at_naxxramas_hub_portal();
new NaxxEntryFlag_AllMapScript(); new NaxxEntryFlag_AllMapScript();
new gobject_naxx40_tele();
// new boss_naxxramas_misc(); // new boss_naxxramas_misc();
} }

View File

@@ -74,7 +74,10 @@ enum NXData
DATA_KELTHUZAD_PORTAL_1 = 126, DATA_KELTHUZAD_PORTAL_1 = 126,
DATA_KELTHUZAD_PORTAL_2 = 127, DATA_KELTHUZAD_PORTAL_2 = 127,
DATA_KELTHUZAD_PORTAL_3 = 128, DATA_KELTHUZAD_PORTAL_3 = 128,
DATA_KELTHUZAD_PORTAL_4 = 129 DATA_KELTHUZAD_PORTAL_4 = 129,
DATA_HEIGAN_EXIT_GATE_OLD = 130,
DATA_HEIGAN_EXIT_GATE = 131,
DATA_HEIGAN_ERUPTION_TUNNEL = 130
}; };
enum NXGOs enum NXGOs
@@ -85,6 +88,7 @@ enum NXGOs
GO_NOTH_EXIT_GATE = 181201, GO_NOTH_EXIT_GATE = 181201,
GO_HEIGAN_ENTRY_GATE = 181202, GO_HEIGAN_ENTRY_GATE = 181202,
GO_HEIGAN_EXIT_GATE = 181203, GO_HEIGAN_EXIT_GATE = 181203,
GO_HEIGAN_EXIT_GATE_OLD = 181496,
GO_LOATHEB_GATE = 181241, GO_LOATHEB_GATE = 181241,
GO_ANUB_GATE = 181126, GO_ANUB_GATE = 181126,
GO_ANUB_NEXT_GATE = 181195, GO_ANUB_NEXT_GATE = 181195,
@@ -200,6 +204,11 @@ enum NX40NPCs
NPC_SURGICAL_ASSIST_40 = 351025, NPC_SURGICAL_ASSIST_40 = 351025,
NPC_SLUDGE_BELCHER_40 = 351029, NPC_SLUDGE_BELCHER_40 = 351029,
// Heigan
NPC_ROTTING_MAGGOT_40 = 351034,
NPC_DISEASED_MAGGOT_40 = 351033,
NPC_EYE_STALK_40 = 351090,
NPC_ARCHMAGE_TARSIS = 16381, NPC_ARCHMAGE_TARSIS = 16381,
}; };