diff --git a/src/naxx40Scripts/npc_omarion.cpp b/src/naxx40Scripts/Omarion.cpp similarity index 99% rename from src/naxx40Scripts/npc_omarion.cpp rename to src/naxx40Scripts/Omarion.cpp index 5f44617..3eb7c73 100644 --- a/src/naxx40Scripts/npc_omarion.cpp +++ b/src/naxx40Scripts/Omarion.cpp @@ -1,4 +1,3 @@ - #include "Player.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" @@ -117,7 +116,6 @@ class npc_omarion : public CreatureScript public: npc_omarion() : CreatureScript("npc_omarion_gossip") { } - bool OnGossipHello(Player* player, Creature* creature) override { ClearGossipMenuFor(player); @@ -311,7 +309,7 @@ public: } }; -void AddSC_npc_omarion() +void AddSC_omarion_40() { new npc_omarion(); } diff --git a/src/naxx40Scripts/boss_anubrekhan_40.cpp b/src/naxx40Scripts/boss_anubrekhan_40.cpp index 991190a..3e79b84 100644 --- a/src/naxx40Scripts/boss_anubrekhan_40.cpp +++ b/src/naxx40Scripts/boss_anubrekhan_40.cpp @@ -37,9 +37,9 @@ enum Spells { SPELL_IMPALE = 28783, 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_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 }; @@ -243,7 +243,7 @@ public: } case EVENT_SPAWN_GUARD: me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000); - break; + break; case EVENT_BERSERK: me->CastSpell(me, SPELL_BERSERK, true); 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() { new boss_anubrekhan_40(); - new spell_anub_locust_swarm_40(); } diff --git a/src/naxx40Scripts/boss_four_horsemen_40.cpp b/src/naxx40Scripts/boss_four_horsemen_40.cpp index 2c3eaa4..08c78b1 100644 --- a/src/naxx40Scripts/boss_four_horsemen_40.cpp +++ b/src/naxx40Scripts/boss_four_horsemen_40.cpp @@ -24,29 +24,25 @@ 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 - SPELL_MARK_OF_KORTHAZZ = 28832, - SPELL_MARK_OF_BLAUMEUX = 28833, - SPELL_MARK_OF_MOGRAINE = 28834, // TODO: Requires Spell DBC Edit - SPELL_MARK_OF_ZELIEK = 28835, - SPELL_MARK_DAMAGE = 28836, + SPELL_MARK_OF_KORTHAZZ = 28832, + SPELL_MARK_OF_BLAUMEUX = 28833, + SPELL_MARK_OF_MOGRAINE = 28834, // TODO: Requires Spell DBC Edit + SPELL_MARK_OF_ZELIEK = 28835, + SPELL_MARK_DAMAGE = 28836, // Korth'azz - SPELL_KORTHAZZ_METEOR_10 = 28884, - SPELL_KORTHAZZ_METEOR_25 = 57467, + SPELL_KORTHAZZ_METEOR = 28884, // Blaumeux - SPELL_BLAUMEUX_SHADOW_BOLT_10 = 57374, - SPELL_BLAUMEUX_SHADOW_BOLT_25 = 57464, - SPELL_BLAUMEUX_VOID_ZONE_10 = 28863, - SPELL_BLAUMEUX_VOID_ZONE_25 = 57463, + SPELL_BLAUMEUX_SHADOW_BOLT = 57374, + SPELL_BLAUMEUX_VOID_ZONE = 28863, // Zeliek - SPELL_ZELIEK_HOLY_WRATH_10 = 28883, - SPELL_ZELIEK_HOLY_WRATH_25 = 57466, - SPELL_ZELIEK_HOLY_BOLT_10 = 57376, - SPELL_ZELIEK_HOLY_BOLT_25 = 57465, + SPELL_ZELIEK_HOLY_WRATH = 28883, + SPELL_ZELIEK_HOLY_BOLT = 57376, // Mograine - SPELL_RIVENDARE_UNHOLY_SHADOW_10 = 28882, - SPELL_RIVENDARE_UNHOLY_SHADOW_25 = 57369 + SPELL_RIVENDARE_UNHOLY_SHADOW = 28882, }; enum Events @@ -54,15 +50,12 @@ enum Events EVENT_MARK_CAST = 1, EVENT_PRIMARY_SPELL = 2, EVENT_SECONDARY_SPELL = 3, - EVENT_BERSERK = 4 + EVENT_BERSERK = 4, + EVENT_HEALTH_CHECK = 5 }; enum Misc { - // Movement - MOVE_PHASE_NONE = 0, - MOVE_PHASE_STARTED = 1, - MOVE_PHASE_FINISHED = 2, // Horseman HORSEMAN_ZELIEK = 0, HORSEMAN_BLAUMEUX = 1, @@ -70,6 +63,20 @@ enum Misc 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 { SAY_AGGRO = 0, @@ -82,26 +89,8 @@ enum FourHorsemen // MARKS const uint32 TABLE_SPELL_MARK[4] = {SPELL_MARK_OF_ZELIEK, SPELL_MARK_OF_BLAUMEUX, SPELL_MARK_OF_MOGRAINE, SPELL_MARK_OF_KORTHAZZ}; - -const Position WaypointPositions[12] = -{ - // 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} -}; +// SPIRITS +const uint32 TABLE_SPELL_SUMMON_SPIRIT[4] = {SPELL_SUMMON_SPIRIT_ZELIEK, SPELL_SUMMON_SPIRIT_BLAUMEUX, SPELL_SUMMON_SPIRIT_MOGRAINE, SPELL_SUMMON_SPIRIT_KORTHAZZ}; class boss_four_horsemen_40 : public CreatureScript { @@ -137,29 +126,8 @@ public: EventMap events; InstanceScript* pInstance; - uint8 currentWaypoint{}; - uint8 movementPhase{}; uint8 horsemanId; - - 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 doneFirstShieldWall; bool IsInRoom() { @@ -175,12 +143,13 @@ public: { BossAI::Reset(); me->SetPosition(me->GetHomePosition()); - movementPhase = MOVE_PHASE_NONE; - currentWaypoint = 0; + me->SetReactState(REACT_AGGRESSIVE); + doneFirstShieldWall = false; events.Reset(); - events.RescheduleEvent(EVENT_MARK_CAST, 24000); + events.RescheduleEvent(EVENT_MARK_CAST, 20000); events.RescheduleEvent(EVENT_BERSERK, 600000); + summons.DespawnAll(); // despawn spirits if ((me->GetEntry() != NPC_LADY_BLAUMEUX_40 && me->GetEntry() != NPC_SIR_ZELIEK_40)) { 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 { 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 { BossAI::JustDied(killer); @@ -261,6 +197,14 @@ public: { 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 (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource()) @@ -276,22 +220,30 @@ public: go->SetGoState(GO_STATE_ACTIVE); } } + else + { + // Prevent spawning if last horseman killed + DoCastSelf(TABLE_SPELL_SUMMON_SPIRIT[horsemanId], true); + } } Talk(SAY_DEATH); } + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + summons.DoZoneInCombat(); + summon->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + } + void JustEngagedWith(Unit* who) override { BossAI::JustEngagedWith(who); - if (movementPhase == MOVE_PHASE_NONE) - { - Talk(SAY_AGGRO); - me->SetReactState(REACT_PASSIVE); - movementPhase = MOVE_PHASE_STARTED; - me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true); - MoveToCorner(); - } + Talk(SAY_AGGRO); + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); if (pInstance) + events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s); { if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE))) { @@ -302,18 +254,18 @@ public: void UpdateAI(uint32 diff) override { - if (movementPhase == MOVE_PHASE_STARTED && currentWaypoint) - { - me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]); - currentWaypoint = 0; - } - if (!IsInRoom()) return; - if (movementPhase < MOVE_PHASE_FINISHED || !UpdateVictim()) + if (!UpdateVictim()) return; + if (Unit* victim = me->GetVictim()) + { + if (!me->IsWithinDistInMap(victim, VISIBILITY_DISTANCE_NORMAL)) + me->CastSpell(victim, SPELL_SUMMON_PLAYER, true); + } + events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -322,7 +274,7 @@ public: { case EVENT_MARK_CAST: 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; case EVENT_BERSERK: Talk(SAY_SPECIAL); @@ -333,22 +285,22 @@ public: if (horsemanId == HORSEMAN_ZELIEK) { 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) { 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) { // 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 { 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); return; @@ -359,159 +311,102 @@ public: CustomSpellValues values; values.AddSpellMod(SPELLVALUE_BASE_POINT0, bp0); 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 { - me->CastSpell(me->GetVictim(), SPELL_BLAUMEUX_VOID_ZONE_10, false); + me->CastSpell(me->GetVictim(), SPELL_BLAUMEUX_VOID_ZONE, false); } events.RepeatEvent(15000); return; - } - - 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) + case EVENT_HEALTH_CHECK: + if (!doneFirstShieldWall && me->GetHealthPct() <= 50.0f) { - 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); + DoCastSelf(SPELL_SHIELDWALL, true); + 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 - me->CastCustomSpell(me->GetVictim(), SPELL_BLAUMEUX_SHADOW_BOLT_10, &bp0, 0, 0, false); + if (!me->HasAura(SPELL_SHIELDWALL)) // prevent refresh of first shield wall + { + DoCastSelf(SPELL_SHIELDWALL, true); + } + break; } - } - } - else - { - DoMeleeAttackIfReady(); + events.Repeat(1s); + return; } + DoMeleeAttackIfReady(); } }; }; -class spell_four_horsemen_mark : public SpellScriptLoader +class spell_four_horsemen_mark_aura : public AuraScript { -public: - spell_four_horsemen_mark() : SpellScriptLoader("spell_four_horsemen_mark") { } + PrepareAuraScript(spell_four_horsemen_mark_aura); - class spell_four_horsemen_mark_AuraScript : public AuraScript + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { - PrepareAuraScript(spell_four_horsemen_mark_AuraScript); - - void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + if (Unit* caster = GetCaster()) { - 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()) { - 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; + case 1: damage = 0; break; + case 2: damage = 250; break; + case 3: damage = 1000; break; + case 4: damage = 3000; break; default: - damage = 20000 + 1000 * (GetStackAmount() - 7); + damage = 1000 * GetStackAmount(); 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 - { - 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) + if (damage) { - 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 { - 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() { new boss_four_horsemen_40(); - new spell_four_horsemen_mark(); - RegisterSpellScript(spell_gen_consumption); + RegisterSpellScript(spell_four_horsemen_mark_aura); } diff --git a/src/naxx40Scripts/boss_gluth_40.cpp b/src/naxx40Scripts/boss_gluth_40.cpp index 65b314a..e7b968f 100644 --- a/src/naxx40Scripts/boss_gluth_40.cpp +++ b/src/naxx40Scripts/boss_gluth_40.cpp @@ -179,7 +179,6 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - switch (events.ExecuteEvent()) { case EVENT_BERSERK: @@ -251,49 +250,38 @@ public: }; }; -class spell_gluth_decimate : public SpellScriptLoader +class spell_gluth_decimate : public SpellScript { -public: - spell_gluth_decimate() : SpellScriptLoader("spell_gluth_decimate") { } + PrepareSpellScript(spell_gluth_decimate); - class spell_gluth_decimate_SpellScript : public SpellScript + void HandleScriptEffect(SpellEffIndex /*effIndex*/) { - PrepareSpellScript(spell_gluth_decimate_SpellScript); - - void HandleScriptEffect(SpellEffIndex /*effIndex*/) + if (Unit* unitTarget = GetHitUnit()) { - 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)); - if (damage <= 0) - return; - - if (Creature* cTarget = unitTarget->ToCreature()) - { - 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); + 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); } + } - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } - }; - - SpellScript* GetSpellScript() const override + void Register() override { - return new spell_gluth_decimate_SpellScript(); + OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; void AddSC_boss_gluth_40() { new boss_gluth_40(); - new spell_gluth_decimate(); + RegisterSpellScript(spell_gluth_decimate); } diff --git a/src/naxx40Scripts/boss_gothik_40.cpp b/src/naxx40Scripts/boss_gothik_40.cpp index 0f2f5c7..24c79c0 100644 --- a/src/naxx40Scripts/boss_gothik_40.cpp +++ b/src/naxx40Scripts/boss_gothik_40.cpp @@ -684,29 +684,18 @@ public: }; }; -class spell_gothik_shadow_bolt_volley : public SpellScriptLoader +class spell_gothik_shadow_bolt_volley : public SpellScript { -public: - spell_gothik_shadow_bolt_volley() : SpellScriptLoader("spell_gothik_shadow_bolt_volley") { } + PrepareSpellScript(spell_gothik_shadow_bolt_volley); - class spell_gothik_shadow_bolt_volley_SpellScript : public SpellScript + void FilterTargets(std::list& targets) { - PrepareSpellScript(spell_gothik_shadow_bolt_volley_SpellScript); + targets.remove_if(Acore::UnitAuraCheck(false, SPELL_SHADOW_MARK)); + } - void FilterTargets(std::list& targets) - { - 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 + void Register() 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 npc_boss_gothik_minion_40(); -// new spell_gothik_shadow_bolt_volley(); + // RegisterSpellScript(spell_gothik_shadow_bolt_volley); } diff --git a/src/naxx40Scripts/boss_grobbulus_40.cpp b/src/naxx40Scripts/boss_grobbulus_40.cpp index d207f62..d7b8ade 100644 --- a/src/naxx40Scripts/boss_grobbulus_40.cpp +++ b/src/naxx40Scripts/boss_grobbulus_40.cpp @@ -241,140 +241,77 @@ public: }; }; -class spell_grobbulus_poison : public SpellScriptLoader +class spell_grobbulus_poison : public SpellScript { -public: - spell_grobbulus_poison() : SpellScriptLoader("spell_grobbulus_poison") { } + PrepareSpellScript(spell_grobbulus_poison); - class spell_grobbulus_poison_SpellScript : public SpellScript + void FilterTargets(std::list& targets) { - PrepareSpellScript(spell_grobbulus_poison_SpellScript); - - void FilterTargets(std::list& targets) + std::list tmplist; + for (auto& target : targets) { - std::list tmplist; - for (auto& target : targets) + if (GetCaster()->IsWithinDist3d(target, 0.0f)) { - if (GetCaster()->IsWithinDist3d(target, 0.0f)) - { - tmplist.push_back(target); - } - } - targets.clear(); - for (auto& itr : tmplist) - { - targets.push_back(itr); + tmplist.push_back(target); } } - - void Register() override + targets.clear(); + 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 -class spell_grobbulus_mutating_injection_40 : public SpellScriptLoader +class spell_grobbulus_mutating_injection_aura : public AuraScript { - public: - spell_grobbulus_mutating_injection_40() : SpellScriptLoader("spell_grobbulus_mutating_injection") { } + PrepareAuraScript(spell_grobbulus_mutating_injection_aura); - 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); - - bool Validate(SpellInfo const* /*spellInfo*/) override - { - return ValidateSpellInfo({ SPELL_MUTATING_EXPLOSION }); - } - - void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - switch (GetTargetApplication()->GetRemoveMode()) + case AURA_REMOVE_BY_ENEMY_SPELL: + case AURA_REMOVE_BY_EXPIRE: + if (auto caster = GetCaster()) { - case AURA_REMOVE_BY_ENEMY_SPELL: - case AURA_REMOVE_BY_EXPIRE: - if (auto caster = GetCaster()) - { - if (caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC) - { - int32 modifiedMutatingExplosionDamage = 2379; - caster->CastCustomSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, &modifiedMutatingExplosionDamage, 0, 0, true); - } - else - { - caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true); - } - } - break; - default: - return; + if (caster->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_HEROIC) + { + int32 modifiedMutatingExplosionDamage = 2379; + caster->CastCustomSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, &modifiedMutatingExplosionDamage, 0, 0, true); + } + else + { + caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true); + } } - } - - void Register() override - { - 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(); + break; + default: + return; } -}; + } - -class spell_grobbulus_poison_cloud_poison_40 : public SpellScriptLoader -{ - 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 Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_grobbulus_mutating_injection_aura::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } }; void AddSC_boss_grobbulus_40() { new boss_grobbulus_40(); new boss_grobbulus_poison_cloud_40(); - new spell_grobbulus_mutating_injection_40(); -// new spell_grobbulus_poison(); - new spell_grobbulus_poison_cloud_poison_40(); + // RegisterSpellScript(spell_grobbulus_poison); + RegisterSpellScript(spell_grobbulus_mutating_injection_aura); } diff --git a/src/naxx40Scripts/boss_heigan_40.cpp b/src/naxx40Scripts/boss_heigan_40.cpp index 462d4e8..355222f 100644 --- a/src/naxx40Scripts/boss_heigan_40.cpp +++ b/src/naxx40Scripts/boss_heigan_40.cpp @@ -38,11 +38,12 @@ enum Says 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_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 @@ -52,7 +53,8 @@ enum Events EVENT_ERUPT_SECTION = 3, EVENT_SWITCH_PHASE = 4, EVENT_SAFETY_DANCE = 5, - EVENT_PLAGUE_CLOUD = 6 + EVENT_PLAGUE_CLOUD = 6, + EVENT_TELEPORT_PLAYER = 7 }; enum Misc @@ -61,14 +63,38 @@ enum Misc 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 { public: boss_heigan_40() : CreatureScript("boss_heigan_40") { } - CreatureAI* GetAI(Creature* pCreature) const override + CreatureAI* GetAI(Creature* creature) const override { - return GetNaxxramasAI(pCreature); + return GetNaxxramasAI(creature); } struct boss_heigan_40AI : public BossAI @@ -83,6 +109,7 @@ public: uint8 currentPhase{}; uint8 currentSection{}; bool moveRight{}; + GuidList portedPlayersThisPhase; void Reset() override { @@ -90,6 +117,8 @@ public: events.Reset(); currentPhase = 0; currentSection = 3; + portedPlayersThisPhase.clear(); + KillPlayersInTheTunnel(); moveRight = true; if (pInstance) { @@ -97,6 +126,11 @@ public: { 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); } + // 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); } @@ -147,6 +191,8 @@ public: events.ScheduleEvent(EVENT_DECEPIT_FEVER, 17000); events.ScheduleEvent(EVENT_ERUPT_SECTION, 15000); events.ScheduleEvent(EVENT_SWITCH_PHASE, 90000); + events.ScheduleEvent(EVENT_TELEPORT_PLAYER, 40000); + portedPlayersThisPhase.clear(); } else // if (phase == PHASE_FAST_DANCE) { @@ -176,6 +222,60 @@ public: 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 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 { if (!IsInRoom(me)) @@ -184,12 +284,17 @@ public: if (!UpdateVictim()) return; + if (Unit* victim = me->GetVictim()) + { + if (!me->IsWithinDistInMap(victim, VISIBILITY_DISTANCE_NORMAL)) + me->CastSpell(victim, SPELL_SUMMON_PLAYER, true); + } events.Update(diff); switch (events.ExecuteEvent()) { case EVENT_DISRUPTION: - me->CastSpell(me, SPELL_SPELL_DISRUPTION, false); + me->CastCustomSpell(SPELL_DISRUPTION, SPELLVALUE_RADIUS_MOD, 2500, me, false); // 25yd events.RepeatEvent(10000); break; case EVENT_DECEPIT_FEVER: @@ -216,6 +321,11 @@ public: case EVENT_ERUPT_SECTION: if (pInstance) { + if (currentPhase == PHASE_FAST_DANCE) + { + if (currentSection >= 1) + KillPlayersInTheTunnel(); + } pInstance->SetData(DATA_HEIGAN_ERUPTION, currentSection); if (currentSection == 3) { @@ -248,85 +358,16 @@ public: events.RepeatEvent(5000); return; } + case EVENT_TELEPORT_PLAYER: + DoEventTeleportPlayer(); + break; } 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() { new boss_heigan_40(); - new spell_heigan_plague_cloud_40(); - new spell_heigan_eruption_40(); } diff --git a/src/naxx40Scripts/boss_kelthuzad_40.cpp b/src/naxx40Scripts/boss_kelthuzad_40.cpp index 0d64133..28b5c44 100644 --- a/src/naxx40Scripts/boss_kelthuzad_40.cpp +++ b/src/naxx40Scripts/boss_kelthuzad_40.cpp @@ -662,103 +662,60 @@ public: }; }; -class spell_kelthuzad_frost_blast : public SpellScriptLoader +class spell_kelthuzad_frost_blast : public SpellScript { -public: - spell_kelthuzad_frost_blast() : SpellScriptLoader("spell_kelthuzad_frost_blast") { } + PrepareSpellScript(spell_kelthuzad_frost_blast); - class spell_kelthuzad_frost_blast_SpellScript : public SpellScript - { - PrepareSpellScript(spell_kelthuzad_frost_blast_SpellScript); - - void FilterTargets(std::list& targets) - { - Unit* caster = GetCaster(); - if (!caster || !caster->ToCreature()) - return; - - std::list 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*/) + void FilterTargets(std::list& targets) { Unit* caster = GetCaster(); - if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC)) - { + if (!caster || !caster->ToCreature()) return; + + std::list 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 { - 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_minion_40(); -// new spell_kelthuzad_frost_blast(); -// new spell_kelthuzad_detonate_mana(); - RegisterSpellScript(spell_kelthuzad_dark_blast); + // RegisterSpellScript(spell_kelthuzad_frost_blast); + // RegisterSpellScript(spell_kelthuzad_detonate_mana_aura); } diff --git a/src/naxx40Scripts/boss_maexxna_40.cpp b/src/naxx40Scripts/boss_maexxna_40.cpp index d16b174..a837d50 100644 --- a/src/naxx40Scripts/boss_maexxna_40.cpp +++ b/src/naxx40Scripts/boss_maexxna_40.cpp @@ -15,32 +15,37 @@ * with this program. If not, see . */ -#include "PassiveAI.h" +#include "CreatureScript.h" #include "Player.h" -#include "ScriptMgr.h" +#include "PassiveAI.h" #include "ScriptedCreature.h" -#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" #include "naxxramas.h" enum Spells { - SPELL_WEB_WRAP = 28622, - SPELL_WEB_SPRAY = 29484, - SPELL_POISON_SHOCK = 28741, - SPELL_NECROTIC_POISON = 54121, - SPELL_FRENZY = 54123, + SPELL_WEB_SPRAY = 29484, + SPELL_POISON_SHOCK = 28741, + SPELL_NECROTIC_POISON = 54121, + 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 { - EVENT_WEB_SPRAY = 1, - EVENT_POISON_SHOCK = 2, - EVENT_NECROTIC_POISON = 3, - EVENT_WEB_WRAP = 4, - EVENT_HEALTH_CHECK = 5, - EVENT_SUMMON_SPIDERLINGS = 6 + EVENT_WEB_SPRAY = 1, + EVENT_POISON_SHOCK = 2, + EVENT_NECROTIC_POISON = 3, + EVENT_WEB_WRAP = 4, + EVENT_HEALTH_CHECK = 5, + EVENT_SUMMON_SPIDERLINGS = 6, + EVENT_WEB_WRAP_APPLY_STUN = 7 }; - enum Emotes { EMOTE_SPIDERS = 0, @@ -54,11 +59,33 @@ enum Misc NPC_MAEXXNA_SPIDERLING = 351088 }; -const Position PosWrap[3] = +const Position PosWrap[7] = { - {3546.796f, -3869.082f, 296.450f, 0.0f}, - {3531.271f, -3847.424f, 299.450f, 0.0f}, - {3497.067f, -3843.384f, 302.384f, 0.0f} + {3496.615f, -3834.182f, 320.7863f}, + {3509.108f, -3833.922f, 320.4750f}, + {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 @@ -81,6 +108,7 @@ public: InstanceScript* pInstance; EventMap events; SummonList summons; + GuidList wraps; bool IsInRoom() { @@ -110,12 +138,12 @@ public: { BossAI::JustEngagedWith(who); me->SetInCombatWithZone(); - events.ScheduleEvent(EVENT_WEB_WRAP, 20000); - events.ScheduleEvent(EVENT_WEB_SPRAY, 40000); - events.ScheduleEvent(EVENT_POISON_SHOCK, 10000); - events.ScheduleEvent(EVENT_NECROTIC_POISON, 5000); - events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); - events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30000); + events.ScheduleEvent(EVENT_WEB_WRAP, 20s); + events.ScheduleEvent(EVENT_WEB_SPRAY, 40s); + events.ScheduleEvent(EVENT_POISON_SHOCK, 10s); + events.ScheduleEvent(EVENT_NECROTIC_POISON, 5s); + events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s); + events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30s); if (pInstance) { if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE))) @@ -149,7 +177,55 @@ public: void JustDied(Unit* killer) override { BossAI::JustDied(killer); - summons.DespawnAll(); + } + + void DoCastWebWrap() + { + std::list candidates; + SelectTargetList(candidates, 2, SelectTargetMethod::Random, 0, WebTargetSelector(me)); + + std::vector 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 @@ -200,59 +276,48 @@ public: break; case EVENT_WEB_WRAP: Talk(EMOTE_WEB_WRAP); - for (uint8 i = 0; i < 2; ++i) - { - 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); - } - } - } + DoCastWebWrap(); events.Repeat(40s); 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(); } }; }; - -class boss_maexxna_webwrap40 : public CreatureScript +class boss_maexxna_webwrap_40 : public CreatureScript { public: - boss_maexxna_webwrap40() : CreatureScript("boss_maexxna_webwrap40") { } + boss_maexxna_webwrap_40() : CreatureScript("boss_maexxna_webwrap40") { } CreatureAI* GetAI(Creature* pCreature) const override { - return GetNaxxramasAI(pCreature); + return GetNaxxramasAI(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; - void SetGUID(ObjectGuid guid, int32 /*param*/) override + void IsSummonedBy(WorldObject* summoner) override { - victimGUID = guid; - - if (victimGUID) - { - 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()); - } - } - } + if (!summoner) + return; + victimGUID = summoner->GetGUID(); } void JustDied(Unit* /*killer*/) override @@ -261,15 +326,55 @@ public: { 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() { new boss_maexxna_40(); - new boss_maexxna_webwrap40(); + new boss_maexxna_webwrap_40(); + RegisterSpellScript(spell_web_wrap_damage); } diff --git a/src/naxx40Scripts/boss_noth_40.cpp b/src/naxx40Scripts/boss_noth_40.cpp index 6b7068e..88d29f4 100644 --- a/src/naxx40Scripts/boss_noth_40.cpp +++ b/src/naxx40Scripts/boss_noth_40.cpp @@ -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() { new boss_noth_40(); - new spell_gothik_curse_of_the_plaguebringer_40(); } diff --git a/src/naxx40Scripts/boss_razuvious_40.cpp b/src/naxx40Scripts/boss_razuvious_40.cpp index 3f5dbf1..0dc2a80 100644 --- a/src/naxx40Scripts/boss_razuvious_40.cpp +++ b/src/naxx40Scripts/boss_razuvious_40.cpp @@ -17,6 +17,8 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellScriptLoader.h" #include "naxxramas.h" enum Says @@ -73,13 +75,12 @@ public: void SpawnHelpers() { + // 10man 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); - if (Is25ManRaid()) - { - 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); - } + // 25man + 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); } void JustSummoned(Creature* cr) override @@ -136,7 +137,8 @@ public: BossAI::JustEngagedWith(who); Talk(SAY_AGGRO); 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 summons.DoZoneInCombat(); } @@ -157,17 +159,9 @@ public: events.RepeatEvent(20000); break; case EVENT_DISRUPTING_SHOUT: - { - // TODO: Custom patch needed to implement power burn, or remove visual effect - // 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); + me->CastSpell(me, SPELL_DISRUPTING_SHOUT, false); + events.RepeatEvent(10000); break; - } case EVENT_JAGGED_KNIFE: if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f)) { diff --git a/src/naxx40Scripts/boss_sapphiron_40.cpp b/src/naxx40Scripts/boss_sapphiron_40.cpp index 810108e..7268978 100644 --- a/src/naxx40Scripts/boss_sapphiron_40.cpp +++ b/src/naxx40Scripts/boss_sapphiron_40.cpp @@ -469,50 +469,39 @@ public: }; // 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: - spell_sapphiron_frost_explosion_40() : SpellScriptLoader("spell_sapphiron_frost_explosion") { } + PrepareSpellScript(spell_sapphiron_frost_explosion); - class spell_sapphiron_frost_explosion_40_SpellScript : public SpellScript + void FilterTargets(std::list& targets) { - PrepareSpellScript(spell_sapphiron_frost_explosion_40_SpellScript); + Unit* caster = GetCaster(); + if (!caster || !caster->ToCreature()) + return; - void FilterTargets(std::list& targets) + std::list tmplist; + for (auto& target : targets) { - Unit* caster = GetCaster(); - if (!caster || !caster->ToCreature()) - return; - - std::list tmplist; - for (auto& target : targets) + if (CAST_AI(boss_sapphiron_40::boss_sapphiron_40AI, caster->ToCreature()->AI())->IsValidExplosionTarget(target)) { - if (CAST_AI(boss_sapphiron_40::boss_sapphiron_40AI, caster->ToCreature()->AI())->IsValidExplosionTarget(target)) - { - tmplist.push_back(target); - } - } - targets.clear(); - for (auto& itr : tmplist) - { - targets.push_back(itr); + tmplist.push_back(target); } } - - void Register() override + targets.clear(); + 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() { new boss_sapphiron_40(); - new spell_sapphiron_frost_explosion_40(); + RegisterSpellScript(spell_sapphiron_frost_explosion); } diff --git a/src/naxx40Scripts/boss_thaddius_40.cpp b/src/naxx40Scripts/boss_thaddius_40.cpp index d56878b..274c08d 100644 --- a/src/naxx40Scripts/boss_thaddius_40.cpp +++ b/src/naxx40Scripts/boss_thaddius_40.cpp @@ -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 -class spell_thaddius_pos_neg_charge_40 : public SpellScriptLoader +class spell_thaddius_pos_neg_charge : public SpellScript { -public: - spell_thaddius_pos_neg_charge_40() : SpellScriptLoader("spell_thaddius_pos_neg_charge") { } + PrepareSpellScript(spell_thaddius_pos_neg_charge); - class spell_thaddius_pos_neg_charge_40_SpellScript : public SpellScript + void HandleTargets(std::list& targets) { - PrepareSpellScript(spell_thaddius_pos_neg_charge_40_SpellScript); - - void HandleTargets(std::list& targets) + uint8 count = 0; + for (auto& ihit : targets) { - uint8 count = 0; - for (auto& ihit : targets) + if (ihit->GetGUID() != GetCaster()->GetGUID()) { - 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()) - 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); - } + uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK; + GetCaster()->SetAuraStack(spellId, GetCaster(), count); } + } - void Register() override - { - 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 + void HandleDamage(SpellEffIndex /*effIndex*/) { - 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: - spell_thaddius_polarity_shift() : SpellScriptLoader("spell_thaddius_polarity_shift") { } + PrepareSpellScript(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 (Unit* target = GetHitUnit()) + if (Creature* caster = GetCaster()->ToCreature()) { - 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 HandleAfterCast() - { - if (GetCaster()) - { - if (Creature* caster = GetCaster()->ToCreature()) + if (caster->GetEntry() == NPC_THADDIUS_40) { - 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 - { - 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 + void Register() 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: - spell_feugen_static_field_40() : SpellScriptLoader("spell_feugen_static_field") { } + PrepareSpellScript(spell_feugen_static_field); - class spell_feugen_static_field_40_SpellScript : public SpellScript + void HandleDamageCalc(SpellEffIndex /*effIndex*/) { - PrepareSpellScript(spell_feugen_static_field_40_SpellScript); - - void HandleDamageCalc(SpellEffIndex /*effIndex*/) + Unit* caster = GetCaster(); + if (!caster || (caster->GetMap()->GetDifficulty() != RAID_DIFFICULTY_10MAN_HEROIC)) { - Unit* caster = GetCaster(); - 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); - } + return; } - - void Register() override + if (Unit* target = GetHitUnit()) { - 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_summon_40(); // new npc_tesla(); - new spell_thaddius_pos_neg_charge_40(); -// new spell_thaddius_polarity_shift(); + RegisterSpellScript(spell_thaddius_pos_neg_charge); + // RegisterSpellScript(spell_thaddius_polarity_shift); // new at_thaddius_entrance(); - new spell_feugen_static_field_40(); + RegisterSpellScript(spell_feugen_static_field); } diff --git a/src/naxx40Scripts/custom_creatures_40.cpp b/src/naxx40Scripts/custom_creatures_40.cpp new file mode 100644 index 0000000..58ab2a5 --- /dev/null +++ b/src/naxx40Scripts/custom_creatures_40.cpp @@ -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(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::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(); +} diff --git a/src/naxx40Scripts/custom_gameobjects_40.cpp b/src/naxx40Scripts/custom_gameobjects_40.cpp new file mode 100644 index 0000000..6824760 --- /dev/null +++ b/src/naxx40Scripts/custom_gameobjects_40.cpp @@ -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(); +} diff --git a/src/naxx40Scripts/custom_spells_40.cpp b/src/naxx40Scripts/custom_spells_40.cpp new file mode 100644 index 0000000..a58e409 --- /dev/null +++ b/src/naxx40Scripts/custom_spells_40.cpp @@ -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); +} diff --git a/src/naxx40Scripts/instance_naxxramas.cpp b/src/naxx40Scripts/instance_naxxramas.cpp index 5cfe1c7..8974aba 100644 --- a/src/naxx40Scripts/instance_naxxramas.cpp +++ b/src/naxx40Scripts/instance_naxxramas.cpp @@ -25,7 +25,6 @@ #include "ObjectMgr.h" #include "GameObjectAI.h" #include "naxxramas.h" -#include "IndividualProgression.h" const float HeiganPos[2] = {2796, -3707}; const float HeiganEruptionSlope[3] = @@ -74,6 +73,7 @@ public: // NPCs PatchwerkRoomTrash.clear(); + HeiganBackRoomAdds.clear(); // Controls _horsemanKilled = 0; @@ -95,6 +95,7 @@ public: } std::set HeiganEruption[4]; + std::set HeiganEruptionTunnel; // GOs ObjectGuid _patchwerkGateGUID; @@ -103,6 +104,7 @@ public: ObjectGuid _nothExitGateGUID; ObjectGuid _heiganGateGUID; ObjectGuid _heiganGateExitGUID; + ObjectGuid _heiganGateExitOldGUID; ObjectGuid _loathebGateGUID; ObjectGuid _anubGateGUID; ObjectGuid _anubNextGateGUID; @@ -136,6 +138,7 @@ public: // NPCs GuidList PatchwerkRoomTrash; + GuidList HeiganBackRoomAdds; ObjectGuid _patchwerkGUID; ObjectGuid _thaddiusGUID; ObjectGuid _stalaggGUID; @@ -179,6 +182,17 @@ public: itr->SendCustomAnim(itr->GetGoAnimProgress()); 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()) { + 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: _patchwerkGUID = creature->GetGUID(); return; @@ -314,6 +337,11 @@ public: HeiganEruption[GetEruptionSection(pGo->GetPositionX(), pGo->GetPositionY())].insert(pGo); return; } + if (pGo->GetGOInfo()->entry == 361001) + { + HeiganEruptionTunnel.insert(pGo); + return; + } switch(pGo->GetEntry()) { @@ -359,6 +387,13 @@ public: pGo->SetGoState(GO_STATE_ACTIVE); } 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: _loathebGateGUID = pGo->GetGUID(); if (GetBossState(BOSS_LOATHEB) == DONE) @@ -688,6 +723,9 @@ public: case DATA_HEIGAN_ERUPTION: HeiganEruptSections(data); return; + case DATA_HEIGAN_ERUPTION_TUNNEL: + HeiganEruptSectionsTunnel(); + return; case DATA_HAD_THADDIUS_GREET: _hadThaddiusGreet = (data == 1); default: @@ -921,6 +959,13 @@ public: } break; case BOSS_HEIGAN: + for (auto& mobGUID : HeiganBackRoomAdds) + { + if (Creature* mob = instance->GetCreature(mobGUID)) + { + mob->DespawnOrUnsummon(); + } + } if (GameObject* go = instance->GetGameObject(_heiganGateGUID)) { go->SetGoState(GO_STATE_ACTIVE); @@ -929,6 +974,10 @@ public: { go->SetGoState(GO_STATE_ACTIVE); } + if (GameObject* go = instance->GetGameObject(_heiganGateExitOldGUID)) + { + go->SetGoState(GO_STATE_ACTIVE); + } break; case BOSS_LOATHEB: if (GameObject* go = instance->GetGameObject(_loathebGateGUID)) @@ -1143,6 +1192,10 @@ public: // GameObjects case DATA_HEIGAN_ENTER_GATE: return _heiganGateGUID; + case DATA_HEIGAN_EXIT_GATE_OLD: + return _heiganGateExitOldGUID; + case DATA_HEIGAN_EXIT_GATE: + return _heiganGateExitGUID; case DATA_LOATHEB_GATE: return _loathebGateGUID; case DATA_ANUB_GATE: @@ -1203,6 +1256,7 @@ public: } }; }; + class boss_naxxramas_misc : public CreatureScript { 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 { public: NaxxPlayerScript() : PlayerScript("NaxxPlayerScript") { } - void OnBeforeChooseGraveyard(Player* player, TeamId /*teamId*/, bool /*nearCorpse*/, uint32& graveyardOverride) override { 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); break; } - return true; } + return true; + } }; class naxx_exit_trigger : public AreaTriggerScript @@ -1454,7 +1408,6 @@ public: } }; - const Position sapphironEntryTP = { 3498.300049f, -5349.490234f, 144.968002f, 1.3698910f }; class at_naxxramas_hub_portal : public AreaTriggerScript @@ -1491,10 +1444,7 @@ public: class NaxxEntryFlag_AllMapScript : public AllMapScript { public: - NaxxEntryFlag_AllMapScript() - : AllMapScript("NaxxEntryFlag_AllMapScript") - { - } + NaxxEntryFlag_AllMapScript() : AllMapScript("NaxxEntryFlag_AllMapScript") { } void OnPlayerEnterAll(Map* map, Player* player) override { @@ -1521,12 +1471,10 @@ public: void AddSC_instance_naxxramas_combined() { new instance_naxxramas_combined(); - new npc_naxx40_area_trigger(); new NaxxPlayerScript(); new naxx_exit_trigger(); new naxx_northrend_entrance(); new at_naxxramas_hub_portal(); new NaxxEntryFlag_AllMapScript(); - new gobject_naxx40_tele(); // new boss_naxxramas_misc(); } diff --git a/src/naxx40Scripts/naxxramas.h b/src/naxx40Scripts/naxxramas.h index b2a9de6..5de0bb2 100644 --- a/src/naxx40Scripts/naxxramas.h +++ b/src/naxx40Scripts/naxxramas.h @@ -74,7 +74,10 @@ enum NXData DATA_KELTHUZAD_PORTAL_1 = 126, DATA_KELTHUZAD_PORTAL_2 = 127, 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 @@ -85,6 +88,7 @@ enum NXGOs GO_NOTH_EXIT_GATE = 181201, GO_HEIGAN_ENTRY_GATE = 181202, GO_HEIGAN_EXIT_GATE = 181203, + GO_HEIGAN_EXIT_GATE_OLD = 181496, GO_LOATHEB_GATE = 181241, GO_ANUB_GATE = 181126, GO_ANUB_NEXT_GATE = 181195, @@ -200,6 +204,11 @@ enum NX40NPCs NPC_SURGICAL_ASSIST_40 = 351025, 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, };