diff options
Diffstat (limited to 'src')
14 files changed, 1321 insertions, 33 deletions
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.h b/src/server/game/AI/ScriptedAI/ScriptedCreature.h index 6c304ecd346..84e02ae169e 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.h +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.h @@ -180,6 +180,9 @@ struct ScriptedAI : public CreatureAI // return the dungeon or raid difficulty Difficulty getDifficulty() { return m_difficulty; } + // return true for 25 man or 25 man heroic mode + bool Is25ManRaid() { return m_difficulty & 1; } + template<class T> inline const T& DUNGEON_MODE(const T& normal5, const T& heroic10) { diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index ba69b702b21..c2b01a4032b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8681,6 +8681,16 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig if (!pVictim->HasAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, procSpell, this)) return false; break; + // Deathbringer Saurfang - Rune of Blood + case 72408: + // can proc only if target is marked with rune + if (!pVictim->HasAura(72410)) + return false; + break; + // Deathbringer Saurfang - Blood Beast's Blood Link + case 72176: + basepoints0 = 3; + break; } // Blade Barrier @@ -8868,6 +8878,10 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, AuraEffect* trig return false; break; } + // Deathbringer Saurfang - Blood Link + case 72202: + target = FindNearestCreature(37813, 75.0f); // NPC_DEATHBRINGER_SAURFANG = 37813 + break; } if (cooldown && GetTypeId() == TYPEID_PLAYER && ToPlayer()->HasSpellCooldown(trigger_spell_id)) diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index 4cc20680cd9..d010780bccb 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -76,6 +76,7 @@ void Vehicle::Install() switch (m_vehicleInfo->m_powerType) { case POWER_STEAM: + case POWER_BLOOD: me->setPowerType(POWER_ENERGY); me->SetMaxPower(POWER_ENERGY, 100); break; diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index 93464b3699e..cbce5fb2f4b 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -29,6 +29,7 @@ enum PowerType { POWER_STEAM = 61, POWER_PYRITE = 41, + POWER_BLOOD = 121, }; struct VehicleSeat diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 362f9f7e986..f68c14031f9 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -427,6 +427,7 @@ void AddSC_boss_falric(); void AddSC_boss_marwyn(); void AddSC_boss_lord_marrowgar(); // Icecrown Citadel void AddSC_boss_lady_deathwhisper(); +void AddSC_boss_deathbringer_saurfang(); void AddSC_instance_icecrown_citadel(); void AddSC_dalaran(); @@ -1100,6 +1101,7 @@ void AddNorthrendScripts() AddSC_boss_marwyn(); AddSC_boss_lord_marrowgar(); // Icecrown Citadel AddSC_boss_lady_deathwhisper(); + AddSC_boss_deathbringer_saurfang(); AddSC_instance_icecrown_citadel(); AddSC_dalaran(); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 43e1febeaed..ad19e45b170 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -2268,14 +2268,6 @@ void AuraEffect::TriggerSpell(Unit * target, Unit * caster) const case 39857: triggerSpellId = 39856; break; // Personalized Weather case 46736: triggerSpellId = 46737; break; - // Mana Barrier - Lady Deathwhisper - case 70842: - { - int32 missingHealth = caster->GetMaxHealth() - caster->GetHealth(); - caster->ModifyHealth(missingHealth); - caster->ModifyPower(POWER_MANA, -missingHealth); - return; - } } break; } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 9b53c31b814..6e3aa21e258 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1413,7 +1413,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask, bool if (unit->GetTypeId() == TYPEID_PLAYER) { unit->ToPlayer()->GetAchievementMgr().StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id); - unit->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id); + unit->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, m_caster); unit->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2, m_spellInfo->Id); } @@ -2805,6 +2805,18 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur) case 59725: // Improved Spell Reflection - aoe aura unitList.remove(m_caster); break; + case 72255: // Mark of the Fallen Champion (Deathbringer Saurfang) + case 72444: + case 72445: + case 72446: + for (std::list<Unit*>::iterator itr = unitList.begin() ; itr != unitList.end();) + { + if (!(*itr)->HasAura(72293)) + itr = unitList.erase(itr); + else + ++itr; + } + break; } // Death Pact if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 7bd4924c8a6..7980ad125af 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -1847,8 +1847,10 @@ void Spell::EffectForceCast(uint32 i) case 52349: // Overtake unitTarget->CastCustomSpell(unitTarget, spellInfo->Id, &damage, NULL, NULL, true, NULL, NULL, m_originalCasterGUID); return; - //case 72378: // Blood Nova - //case 73058: // Blood Nova + case 72378: // Blood Nova + case 73058: // Blood Nova + spellInfo = sSpellMgr.GetSpellForDifficultyFromSpell(spellInfo, m_caster); + break; } } Unit * caster = GetTriggeredSpellCaster(spellInfo, m_caster, unitTarget); @@ -2629,7 +2631,9 @@ void Spell::EffectHealthLeech(uint32 i) // Do not apply multiplier to damage if it's Death Coil int32 new_damage; - if (m_spellInfo->SpellFamilyFlags[0] & 0x80000) + if (m_spellInfo->SpellFamilyFlags[0] & 0x80000 || + m_spellInfo->Id == 72409 || m_spellInfo->Id == 72447 || // ...or Deathbringer Saurfang's Rune of Blood + m_spellInfo->Id == 72448 || m_spellInfo->Id == 72449) new_damage = damage; else new_damage = int32(damage * multiplier); diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 6912cb18787..7a030614469 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -280,12 +280,12 @@ class AuraScript : public _SpellScript public: bool _Validate(SpellEntry const * entry, const char * scriptname); bool _Load(Aura * aura); - void _ResetDefault() { m_default = true; } - bool _IsDefaultActionPrevented(SpellEffIndex /*effIndex*/) {return !m_default;}; - void PreventDefaultAction() { m_default = false; }; + void _ResetDefault() { m_defaultPreventedEffectsMask = 0; } + bool _IsDefaultActionPrevented(SpellEffIndex effIndex) { return m_defaultPreventedEffectsMask & (1 << effIndex); } + void PreventDefaultAction(SpellEffIndex effIndex) { m_defaultPreventedEffectsMask |= 1 << effIndex; } private: Aura * m_aura; - bool m_default; + uint8 m_defaultPreventedEffectsMask; public: // // AuraScript interface diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp new file mode 100644 index 00000000000..1bb5c3b2587 --- /dev/null +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_deathbringer_saurfang.cpp @@ -0,0 +1,1120 @@ +/* + * Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ScriptPCH.h" +#include "icecrown_citadel.h" + +enum eScriptTexts +{ + SAY_INTRO_ALLIANCE_1 = -1631029, + SAY_INTRO_ALLIANCE_2 = -1631030, + SAY_INTRO_ALLIANCE_3 = -1631031, + SAY_INTRO_ALLIANCE_4 = -1631032, + SAY_INTRO_ALLIANCE_5 = -1631033, + SAY_INTRO_ALLIANCE_6 = -1631034, + SAY_INTRO_ALLIANCE_7 = -1631035, + + SAY_INTRO_HORDE_1 = -1631036, + SAY_INTRO_HORDE_2 = -1631037, + SAY_INTRO_HORDE_3 = -1631038, + SAY_INTRO_HORDE_4 = -1631039, + SAY_INTRO_HORDE_5 = -1631040, + SAY_INTRO_HORDE_6 = -1631041, + SAY_INTRO_HORDE_7 = -1631042, + SAY_INTRO_HORDE_8 = -1631043, + SAY_INTRO_HORDE_9 = -1631044, + + SAY_AGGRO = -1631045, + SAY_MARK_OF_THE_FALLEN_CHAMPION = -1631046, + SAY_BLOOD_BEASTS = -1631047, + SAY_KILL_1 = -1631048, + SAY_KILL_2 = -1631049, + SAY_FRENZY = -1631050, + SAY_BERSERK = -1631051, + SAY_DEATH = -1631052, + + SAY_OUTRO_ALLIANCE_1 = -1631053, // TODO ALLIANCE OUTRO + SAY_OUTRO_ALLIANCE_2 = -1631054, + SAY_OUTRO_ALLIANCE_3 = -1631055, + SAY_OUTRO_ALLIANCE_4 = -1631056, + SAY_OUTRO_ALLIANCE_5 = -1631057, + SAY_OUTRO_ALLIANCE_6 = -1631058, + SAY_OUTRO_ALLIANCE_7 = -1631059, + SAY_OUTRO_ALLIANCE_8 = -1631060, + SAY_OUTRO_ALLIANCE_9 = -1631061, + SAY_OUTRO_ALLIANCE_10 = -1631062, + SAY_OUTRO_ALLIANCE_11 = -1631063, + SAY_OUTRO_ALLIANCE_12 = -1631064, // kneel after WP reached + SAY_OUTRO_ALLIANCE_13 = -1631065, + SAY_OUTRO_ALLIANCE_14 = -1631066, + SAY_OUTRO_ALLIANCE_15 = -1631067, + SAY_OUTRO_ALLIANCE_16 = -1631068, + SAY_OUTRO_ALLIANCE_17 = -1631069, + SAY_OUTRO_ALLIANCE_18 = -1631070, + SAY_OUTRO_ALLIANCE_19 = -1631071, + SAY_OUTRO_ALLIANCE_20 = -1631072, + SAY_OUTRO_ALLIANCE_21 = -1631073, + + SAY_OUTRO_HORDE_1 = -1631074, + SAY_OUTRO_HORDE_2 = -1631075, + SAY_OUTRO_HORDE_3 = -1631076, + SAY_OUTRO_HORDE_4 = -1631077 +}; + +enum eSpells +{ + // Deathbringer Saurfang + SPELL_ZERO_POWER = 72242, + SPELL_GRIP_OF_AGONY = 70572, // Intro + SPELL_BLOOD_LINK = 72178, + SPELL_MARK_OF_THE_FALLEN_CHAMPION_S = 72256, + SPELL_RUNE_OF_BLOOD_S = 72408, + + SPELL_SUMMON_BLOOD_BEAST = 72172, + SPELL_SUMMON_BLOOD_BEAST_25_MAN = 72356, // Additional cast, does not replace + SPELL_FRENZY = 72737, + SPELL_BLOOD_NOVA_TRIGGER = 72378, + SPELL_BLOOD_NOVA = 72380, + SPELL_BLOOD_POWER = 72371, + SPELL_BLOOD_LINK_POWER = 72195, + SPELL_BLOOD_LINK_DUMMY = 72202, + SPELL_MARK_OF_THE_FALLEN_CHAMPION = 72293, + SPELL_BOILING_BLOOD = 72385, + SPELL_RUNE_OF_BLOOD = 72410, + + // Blood Beast + SPELL_BLOOD_LINK_BEAST = 72176, + SPELL_RESISTANT_SKIN = 72723, + SPELL_SCENT_OF_BLOOD = 72769, // Heroic only + + SPELL_RIDE_VEHICLE = 70640 // Outro +}; + +// Helper to get id of the aura on different modes (HasAura(baseId) wont work) +#define BOILING_BLOOD_HELPER RAID_MODE(72385,72441,72442,72443) + +enum eEvents +{ + EVENT_INTRO_ALLIANCE_1 = 1, + EVENT_INTRO_ALLIANCE_2 = 2, + EVENT_INTRO_ALLIANCE_3 = 3, + EVENT_INTRO_ALLIANCE_4 = 4, + EVENT_INTRO_ALLIANCE_5 = 5, + EVENT_INTRO_ALLIANCE_6 = 6, + EVENT_INTRO_ALLIANCE_7 = 7, + + EVENT_INTRO_HORDE_1 = 8, + EVENT_INTRO_HORDE_2 = 9, + EVENT_INTRO_HORDE_3 = 10, + EVENT_INTRO_HORDE_4 = 11, + EVENT_INTRO_HORDE_5 = 12, + EVENT_INTRO_HORDE_6 = 13, + EVENT_INTRO_HORDE_7 = 14, + EVENT_INTRO_HORDE_8 = 15, + EVENT_INTRO_HORDE_9 = 16, + + EVENT_INTRO_FINISH = 17, + + EVENT_BERSERK = 18, + EVENT_SUMMON_BLOOD_BEAST = 19, + EVENT_BOILING_BLOOD = 20, + EVENT_BLOOD_NOVA = 21, + EVENT_RUNE_OF_BLOOD = 22, + + EVENT_OUTRO_ALLIANCE_1 = 23, + EVENT_OUTRO_ALLIANCE_2 = 24, + EVENT_OUTRO_ALLIANCE_3 = 25, + EVENT_OUTRO_ALLIANCE_4 = 26, + EVENT_OUTRO_ALLIANCE_5 = 27, + EVENT_OUTRO_ALLIANCE_6 = 28, + EVENT_OUTRO_ALLIANCE_7 = 29, + EVENT_OUTRO_ALLIANCE_8 = 30, + EVENT_OUTRO_ALLIANCE_9 = 31, + EVENT_OUTRO_ALLIANCE_10 = 32, + EVENT_OUTRO_ALLIANCE_11 = 33, + EVENT_OUTRO_ALLIANCE_12 = 34, + EVENT_OUTRO_ALLIANCE_13 = 35, + EVENT_OUTRO_ALLIANCE_14 = 36, + EVENT_OUTRO_ALLIANCE_15 = 37, + EVENT_OUTRO_ALLIANCE_16 = 38, + EVENT_OUTRO_ALLIANCE_17 = 39, + EVENT_OUTRO_ALLIANCE_18 = 40, + EVENT_OUTRO_ALLIANCE_19 = 41, + EVENT_OUTRO_ALLIANCE_20 = 42, + EVENT_OUTRO_ALLIANCE_21 = 43, + + EVENT_OUTRO_HORDE_1 = 44, + EVENT_OUTRO_HORDE_2 = 45, + EVENT_OUTRO_HORDE_3 = 46, + EVENT_OUTRO_HORDE_4 = 47, + EVENT_OUTRO_HORDE_5 = 48, + EVENT_OUTRO_HORDE_6 = 49, + EVENT_OUTRO_HORDE_7 = 50, + EVENT_OUTRO_HORDE_8 = 51 +}; + +enum ePhases +{ + PHASE_INTRO_A = 1, + PHASE_INTRO_H = 2, + PHASE_COMBAT = 3, + + PHASE_INTRO_MASK = (1 << PHASE_INTRO_A) | (1 << PHASE_INTRO_H), +}; + +enum eActions +{ + ACTION_START_EVENT = -3781300, + ACTION_CONTINUE_INTRO = -3781301, + ACTION_CHARGE = -3781302, + ACTION_START_OUTRO = -3781303, + ACTION_DESPAWN = -3781304, + ACTION_MARK_OF_THE_FALLEN_CHAMPION = -72293, +}; + +#define DATA_MADE_A_MESS 45374613 // 4537, 4613 are achievement IDs + +enum eMovePoints +{ + POINT_SAURFANG = 3781300, + POINT_FIRST_STEP = 3781301, + POINT_CHARGE = 3781302, + POINT_CHOKE = 3781303, + POINT_CORPSE = 3781304, + POINT_FINAL = 3781305 +}; + +static const Position deathbringerPos = {-496.3542f, 2211.33f, 541.1138f, 0.0f}; +static const Position firstStepPos = {-541.3177f, 2211.365f, 539.2921f, 0.0f}; + +static const Position chargePos[6] = +{ + {-509.6505f, 2211.377f, 539.2872f, 0.0f}, // High Overlord Saurfang/Muradin Bronzebeard + {-508.7480f, 2211.897f, 539.2870f, 0.0f}, // front left + {-509.2929f, 2211.411f, 539.2870f, 0.0f}, // front right + {-506.6607f, 2211.367f, 539.2870f, 0.0f}, // back middle + {-506.1137f, 2213.306f, 539.2870f, 0.0f}, // back left + {-509.0040f, 2211.743f, 539.2870f, 0.0f} // back right +}; + +static const Position chokePos[6] = +{ + {-514.4834f, 2211.334f, 549.2887f, 0.0f}, // High Overlord Saurfang/Muradin Bronzebeard + {-510.1081f, 2211.592f, 546.3773f, 0.0f}, // front left + {-513.3210f, 2211.396f, 551.2882f, 0.0f}, // front right + {-507.3684f, 2210.353f, 545.7497f, 0.0f}, // back middle + {-507.0486f, 2212.999f, 545.5512f, 0.0f}, // back left + {-510.7041f, 2211.069f, 546.5298f, 0.0f} // back right +}; + +static const Position finalPos = {-563.7552f, 2211.328f, 538.7848f, 0.0f}; + +class boss_deathbringer_saurfang : public CreatureScript +{ + public: + boss_deathbringer_saurfang() : CreatureScript("boss_deathbringer_saurfang") { } + + struct boss_deathbringer_saurfangAI : public ScriptedAI + { + boss_deathbringer_saurfangAI(Creature* pCreature) : ScriptedAI(pCreature), summons(pCreature) + { + ASSERT(pCreature->GetVehicleKit()); // we dont actually use it, just check if exists + pInstance = pCreature->GetInstanceScript(); + bIntroDone = false; + uiFallenChampionCount = 0; + } + + void Reset() + { + events.Reset(); + events.SetPhase(PHASE_COMBAT); + bFrenzy = false; + me->SetPower(POWER_ENERGY, 0); + DoCast(me, SPELL_ZERO_POWER, true); + DoCast(me, SPELL_BLOOD_LINK, true); + DoCast(me, SPELL_MARK_OF_THE_FALLEN_CHAMPION_S, true); + DoCast(me, SPELL_RUNE_OF_BLOOD_S, true); + me->RemoveAurasDueToSpell(SPELL_BERSERK); + me->RemoveAurasDueToSpell(SPELL_FRENZY); + me->RemoveAurasDueToSpell(SPELL_BLOOD_POWER); + uiFallenChampionCount = 0; + summons.DespawnAll(); + if (pInstance) + pInstance->SetData(DATA_DEATHBRINGER_SAURFANG, NOT_STARTED); + } + + void EnterCombat(Unit* /*who*/) + { + DoScriptText(SAY_AGGRO, me); + events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 30000, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BERSERK, 480000, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BOILING_BLOOD, 15500, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_BLOOD_NOVA, 17000, 0, PHASE_COMBAT); + events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, 20000, 0, PHASE_COMBAT); + + if (pInstance) + pInstance->SetData(DATA_DEATHBRINGER_SAURFANG, IN_PROGRESS); + } + + void JustDied(Unit* /*killer*/) + { + DoScriptText(SAY_DEATH, me); + + if (pInstance) + { + pInstance->SetData(DATA_DEATHBRINGER_SAURFANG, DONE); + if (Creature* creature = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_SAURFANG_EVENT_NPC))) + creature->AI()->DoAction(ACTION_START_OUTRO); + } + } + + void MoveInLineOfSight(Unit* /*who*/) + { + // not calling CreatureAI::MoveInLineOfSight to prevent entering combat + } + + void AttackStart(Unit* victim) + { + if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE)) + return; + + ScriptedAI::AttackStart(victim); + } + + void EnterEvadeMode() + { + ScriptedAI::EnterEvadeMode(); + if (bIntroDone) + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + } + + void JustReachedHome() + { + if(pInstance) + pInstance->SetData(DATA_DEATHBRINGER_SAURFANG, FAIL); + } + + void KilledUnit(Unit *victim) + { + if (victim->GetTypeId() == TYPEID_PLAYER) + DoScriptText(RAND(SAY_KILL_1, SAY_KILL_2), me); + } + + void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) + { + if (!bFrenzy && HealthBelowPct(31)) // AT 30%, not below + { + bFrenzy = true; + DoCast(me, SPELL_FRENZY); + DoScriptText(SAY_FRENZY, me); + } + } + + void JustSummoned(Creature* summon) + { + if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 1)) + summon->AI()->AttackStart(pTarget); + + if (IsHeroic()) + DoCast(summon, SPELL_SCENT_OF_BLOOD); + + summon->AI()->DoCast(summon, SPELL_BLOOD_LINK_BEAST, true); + summon->AI()->DoCast(summon, SPELL_RESISTANT_SKIN, true); + summons.Summon(summon); + } + + void SummonedCreatureDespawn(Creature* summon) + { + summons.Despawn(summon); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE && id != POINT_SAURFANG) + return; + + if (pInstance) + pInstance->HandleGameObject(pInstance->GetData64(DATA_SAURFANG_DOOR), false); + } + + void SpellHitTarget(Unit* target, const SpellEntry* spell) + { + switch (spell->Id) + { + case SPELL_MARK_OF_THE_FALLEN_CHAMPION: + DoScriptText(SAY_MARK_OF_THE_FALLEN_CHAMPION, me); + break; + case 72255: // Mark of the Fallen Champion, triggered id + case 72444: + case 72445: + case 72446: + if (me->GetPower(POWER_ENERGY) != me->GetMaxPower(POWER_ENERGY)) + target->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 1, me, true); + break; + default: + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_INTRO_MASK)) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_ALLIANCE_2: + DoScriptText(SAY_INTRO_ALLIANCE_2, me); + break; + case EVENT_INTRO_ALLIANCE_3: + DoScriptText(SAY_INTRO_ALLIANCE_3, me); + break; + case EVENT_INTRO_ALLIANCE_6: + DoScriptText(SAY_INTRO_ALLIANCE_6, me); + DoScriptText(SAY_INTRO_ALLIANCE_7, me); + DoCast(me, SPELL_GRIP_OF_AGONY); + break; + case EVENT_INTRO_HORDE_2: + DoScriptText(SAY_INTRO_HORDE_2, me); + break; + case EVENT_INTRO_HORDE_4: + DoScriptText(SAY_INTRO_HORDE_4, me); + break; + case EVENT_INTRO_HORDE_9: + DoCast(me, SPELL_GRIP_OF_AGONY); + DoScriptText(SAY_INTRO_HORDE_9, me); + break; + case EVENT_INTRO_FINISH: + events.SetPhase(PHASE_COMBAT); + bIntroDone = true; + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); + break; + case EVENT_SUMMON_BLOOD_BEAST: + for (uint8 i10 = 0; i10 < 2; ++i10) + DoCast(me, SPELL_SUMMON_BLOOD_BEAST+i10); + if (Is25ManRaid()) + for (uint8 i25 = 0; i25 < 3; ++i25) + DoCast(me, SPELL_SUMMON_BLOOD_BEAST_25_MAN+i25); + DoScriptText(SAY_BLOOD_BEASTS, me); + events.ScheduleEvent(EVENT_SUMMON_BLOOD_BEAST, 40000, 0, PHASE_COMBAT); + break; + case EVENT_BLOOD_NOVA: + { + // select at range only + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, -10.0f, true); + if (!target) + target = SelectTarget(SELECT_TARGET_RANDOM, 1, 10.0f, true); // noone? select melee + if (target) + DoCast(target, SPELL_BLOOD_NOVA_TRIGGER); + events.ScheduleEvent(EVENT_BLOOD_NOVA, urand(20000, 25000), 0, PHASE_COMBAT); + break; + } + case EVENT_RUNE_OF_BLOOD: + DoCastVictim(SPELL_RUNE_OF_BLOOD); + events.ScheduleEvent(EVENT_RUNE_OF_BLOOD, urand(20000, 25000), 0, PHASE_COMBAT); + break; + case EVENT_BOILING_BLOOD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -BOILING_BLOOD_HELPER)) + DoCast(target, SPELL_BOILING_BLOOD); + events.ScheduleEvent(EVENT_BOILING_BLOOD, urand(15000, 20000), 0, PHASE_COMBAT); + break; + case EVENT_BERSERK: + DoCast(me, SPELL_BERSERK); + DoScriptText(SAY_BERSERK, me); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + uint32 GetData(uint32 type) + { + if (type == DATA_MADE_A_MESS) + if (uiFallenChampionCount < RAID_MODE<uint32>(3, 5, 3, 5)) + return 1; + + return 0; + } + + // intro setup + void DoAction(const int32 action) + { + if (action == PHASE_INTRO_A || action == PHASE_INTRO_H) + { + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + // controls what events will execute + events.SetPhase(uint32(action)); + + me->SetHomePosition(deathbringerPos.GetPositionX(), deathbringerPos.GetPositionY(), deathbringerPos.GetPositionZ(), me->GetOrientation()); + me->GetMotionMaster()->MovePoint(POINT_SAURFANG, deathbringerPos.GetPositionX(), deathbringerPos.GetPositionY(), deathbringerPos.GetPositionZ()); + + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_2, 2500, 0, PHASE_INTRO_A); + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_3, 20000, 0, PHASE_INTRO_A); + + events.ScheduleEvent(EVENT_INTRO_HORDE_2, 5000, 0, PHASE_INTRO_H); + } + else if (action == ACTION_CONTINUE_INTRO) + { + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_6, 6500+500, 0, PHASE_INTRO_A); + events.ScheduleEvent(EVENT_INTRO_FINISH, 8000, 0, PHASE_INTRO_A); + + events.ScheduleEvent(EVENT_INTRO_HORDE_4, 6500, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_HORDE_9, 46700+1000+500, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_FINISH, 46700+1000+8000, 0, PHASE_INTRO_H); + } + else if (action == ACTION_MARK_OF_THE_FALLEN_CHAMPION) + { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_MARK_OF_THE_FALLEN_CHAMPION)) + { + ++uiFallenChampionCount; + me->RemoveAurasDueToSpell(SPELL_BLOOD_POWER); + DoCast(target, SPELL_MARK_OF_THE_FALLEN_CHAMPION); + me->SetPower(POWER_ENERGY, 0); + } + } + else + ASSERT(false); + } + + private: + EventMap events; + InstanceScript* pInstance; + SummonList summons; + bool bIntroDone; + bool bFrenzy; // faster than iterating all auras to find Frenzy + uint32 uiFallenChampionCount; + }; + + CreatureAI* GetAI(Creature* pCreature) const + { + return new boss_deathbringer_saurfangAI(pCreature); + } +}; + +class npc_high_overlord_saurfang_icc : public CreatureScript +{ + public: + npc_high_overlord_saurfang_icc() : CreatureScript("npc_high_overlord_saurfang_icc") { } + + struct npc_high_overlord_saurfangAI : public ScriptedAI + { + npc_high_overlord_saurfangAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(pCreature->GetVehicleKit()) + { + ASSERT(vehicle); + pInstance = me->GetInstanceScript(); + } + + void Reset() + { + events.Reset(); + } + + void DoAction(const int32 action) + { + if (action == ACTION_START_EVENT) + { + GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_KOR_KRON_REAVER, 20.0f); + guardList.sort(Trinity::ObjectDistanceOrderPred(me)); + uint32 x = 1; + for (std::list<Creature*>::iterator itr = guardList.begin(); itr != guardList.end(); ++x, ++itr) + (*itr)->AI()->SetData(0, x); + + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + DoScriptText(SAY_INTRO_HORDE_1, me); + events.SetPhase(PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_HORDE_3, 18500, 0, PHASE_INTRO_H); + if (pInstance) + { + uiDeathbringerSaurfangGUID = pInstance->GetData64(DATA_DEATHBRINGER_SAURFANG); + pInstance->HandleGameObject(pInstance->GetData64(DATA_SAURFANG_DOOR), true); + } + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + deathbringer->AI()->DoAction(PHASE_INTRO_H); + } + else if (action == ACTION_START_OUTRO) + { + me->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); + DoScriptText(SAY_OUTRO_HORDE_1, me); + events.ScheduleEvent(EVENT_OUTRO_HORDE_2, 10000); // say + events.ScheduleEvent(EVENT_OUTRO_HORDE_3, 18000); // say + events.ScheduleEvent(EVENT_OUTRO_HORDE_4, 24000); // cast + events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 30000); // move + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f); + me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f); + for (std::list<Creature*>::iterator itr = guardList.begin(); itr != guardList.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_DESPAWN); + } + } + + void SpellHit(Unit* /*caster*/, SpellEntry const* spell) + { + if (spell->Id == SPELL_GRIP_OF_AGONY) + { + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[0]); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + + if (id == POINT_FIRST_STEP) + { + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + DoScriptText(SAY_INTRO_HORDE_3, me); + events.ScheduleEvent(EVENT_INTRO_HORDE_5, 15500, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_HORDE_6, 29500, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_HORDE_7, 43800, 0, PHASE_INTRO_H); + events.ScheduleEvent(EVENT_INTRO_HORDE_8, 47000, 0, PHASE_INTRO_H); + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + deathbringer->AI()->DoAction(ACTION_CONTINUE_INTRO); + } + //else if (id == EVENT_FALL_GROUND) + // me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + else if (id == POINT_CORPSE) + { + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + { + deathbringer->CastSpell(me, SPELL_RIDE_VEHICLE, true); // for the packet logs. + deathbringer->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + deathbringer->setDeathState(ALIVE); + deathbringer->EnterVehicle(vehicle, 0); + } + events.ScheduleEvent(EVENT_OUTRO_HORDE_5, 1000); // move + events.ScheduleEvent(EVENT_OUTRO_HORDE_6, 4000); // say + } + else if (id == POINT_FINAL) + { + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + deathbringer->ForcedDespawn(); + me->ForcedDespawn(); + } + } + + void UpdateAI(const uint32 diff) + { + events.Update(diff); + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_HORDE_3: + me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(POINT_FIRST_STEP, firstStepPos.GetPositionX(), firstStepPos.GetPositionY(), firstStepPos.GetPositionZ()); + break; + case EVENT_INTRO_HORDE_5: + DoScriptText(SAY_INTRO_HORDE_5, me); + break; + case EVENT_INTRO_HORDE_6: + DoScriptText(SAY_INTRO_HORDE_6, me); + break; + case EVENT_INTRO_HORDE_7: + DoScriptText(SAY_INTRO_HORDE_7, me); + break; + case EVENT_INTRO_HORDE_8: + DoScriptText(SAY_INTRO_HORDE_8, me); + for (std::list<Creature*>::iterator itr = guardList.begin(); itr != guardList.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_CHARGE); + me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); + break; + case EVENT_OUTRO_HORDE_2: // say + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + me->SetFacingToObject(deathbringer); + DoScriptText(SAY_OUTRO_HORDE_2, me); + break; + case EVENT_OUTRO_HORDE_3: // say + DoScriptText(SAY_OUTRO_HORDE_3, me); + break; + case EVENT_OUTRO_HORDE_4: // move + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + { + float x, y, z; + deathbringer->GetClosePoint(x, y, z, deathbringer->GetObjectSize()); + me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(POINT_CORPSE ,x, y, z); + } + break; + case EVENT_OUTRO_HORDE_5: // move + me->GetMotionMaster()->MovePoint(POINT_FINAL, finalPos); + break; + case EVENT_OUTRO_HORDE_6: // say + DoScriptText(SAY_OUTRO_HORDE_4, me); + break; + } + } + } + + private: + EventMap events; + InstanceScript* pInstance; + Vehicle* vehicle; + uint64 uiDeathbringerSaurfangGUID; + std::list<Creature*> guardList; + }; + + bool OnGossipHello(Player* pPlayer, Creature* pCreature) + { + if (pCreature->GetPositionZ() < 530.0f) + return false; + + InstanceScript* pInstance = pCreature->GetInstanceScript(); + if (pInstance && pInstance->GetData(DATA_DEATHBRINGER_SAURFANG) != DONE) + { + pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Let it begin...", 631, -ACTION_START_EVENT); + pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetGUID()); + } + + return true; + } + + bool OnGossipSelect(Player* /*pPlayer*/, Creature* pCreature, uint32 /*sender*/, uint32 action) + { + if (action == -ACTION_START_EVENT) + pCreature->AI()->DoAction(ACTION_START_EVENT); + + return true; + } + + CreatureAI* GetAI(Creature* pCreature) const + { + return new npc_high_overlord_saurfangAI(pCreature); + } +}; + +class npc_muradin_bronzebeard_icc : public CreatureScript +{ + public: + npc_muradin_bronzebeard_icc() : CreatureScript("npc_muradin_bronzebeard_icc") { } + + struct npc_muradin_bronzebeard_iccAI : public ScriptedAI + { + npc_muradin_bronzebeard_iccAI(Creature* pCreature) : ScriptedAI(pCreature) + { + pInstance = me->GetInstanceScript(); + } + + void Reset() + { + events.Reset(); + } + + void DoAction(const int32 action) + { + if (action == ACTION_START_EVENT) + { + GetCreatureListWithEntryInGrid(guardList, me, NPC_SE_SKYBREAKER_MARINE, 20.0f); + guardList.sort(Trinity::ObjectDistanceOrderPred(me)); + uint32 x = 1; + for (std::list<Creature*>::iterator itr = guardList.begin(); itr != guardList.end(); ++x, ++itr) + (*itr)->AI()->SetData(0, x); + + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + DoScriptText(SAY_INTRO_ALLIANCE_1, me); + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_4, 2500+17500+9500, 0, PHASE_INTRO_A); + events.SetPhase(PHASE_INTRO_A); + if (pInstance) + { + uiDeathbringerSaurfangGUID = pInstance->GetData64(DATA_DEATHBRINGER_SAURFANG); + pInstance->HandleGameObject(pInstance->GetData64(DATA_SAURFANG_DOOR), true); + } + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + deathbringer->AI()->DoAction(PHASE_INTRO_A); + } + else if (action == ACTION_START_OUTRO) + { + me->RemoveAurasDueToSpell(SPELL_GRIP_OF_AGONY); + DoScriptText(SAY_OUTRO_ALLIANCE_1, me); + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SendMovementFlagUpdate(); + me->Relocate(me->GetPositionX(), me->GetPositionY(), 539.2917f); + me->SendMonsterMove(me->GetPositionX(), me->GetPositionY(), 539.2917f, SPLINEFLAG_FALLING, 0, 0.0f); + for (std::list<Creature*>::iterator itr = guardList.begin(); itr != guardList.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_DESPAWN); + } + } + + void SpellHit(Unit* /*caster*/, SpellEntry const* spell) + { + if (spell->Id == SPELL_GRIP_OF_AGONY) + { + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[0]); + } + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE || id != POINT_FIRST_STEP) + return; + + me->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING); + DoScriptText(SAY_INTRO_ALLIANCE_4, me); + events.ScheduleEvent(EVENT_INTRO_ALLIANCE_5, 5000, 0, PHASE_INTRO_A); + if (Creature* deathbringer = ObjectAccessor::GetCreature(*me, uiDeathbringerSaurfangGUID)) + deathbringer->AI()->DoAction(ACTION_CONTINUE_INTRO); + } + + void UpdateAI(const uint32 diff) + { + events.Update(diff); + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_ALLIANCE_4: + me->AddUnitMovementFlag(MOVEMENTFLAG_WALKING); + me->GetMotionMaster()->MovePoint(POINT_FIRST_STEP, firstStepPos.GetPositionX(), firstStepPos.GetPositionY(), firstStepPos.GetPositionZ()); + break; + case EVENT_INTRO_ALLIANCE_5: + DoScriptText(SAY_INTRO_ALLIANCE_5, me); + for (std::list<Creature*>::iterator itr = guardList.begin(); itr != guardList.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_CHARGE); + me->GetMotionMaster()->MoveCharge(chargePos[0].GetPositionX(), chargePos[0].GetPositionY(), chargePos[0].GetPositionZ(), 8.5f, POINT_CHARGE); + break; + } + } + } + + private: + EventMap events; + InstanceScript* pInstance; + uint64 uiDeathbringerSaurfangGUID; + std::list<Creature*> guardList; + }; + + bool OnGossipHello(Player* pPlayer, Creature* pCreature) + { + if (pCreature->GetPositionZ() < 530.0f) + return false; + + InstanceScript* pInstance = pCreature->GetInstanceScript(); + if (pInstance && pInstance->GetData(DATA_DEATHBRINGER_SAURFANG) != DONE) + { + pPlayer->ADD_GOSSIP_ITEM(0, "Let it begin...", 631, -ACTION_START_EVENT+1); + pPlayer->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, pCreature->GetGUID()); + } + + return true; + } + + bool OnGossipSelect(Player* /*pPlayer*/, Creature* pCreature, uint32 /*sender*/, uint32 action) + { + if (action == -ACTION_START_EVENT+1) + pCreature->AI()->DoAction(ACTION_START_EVENT); + + return true; + } + + CreatureAI* GetAI(Creature* pCreature) const + { + return new npc_muradin_bronzebeard_iccAI(pCreature); + } +}; + +class npc_saurfang_event : public CreatureScript +{ + public: + npc_saurfang_event() : CreatureScript("npc_saurfang_event") { } + + struct npc_saurfang_eventAI : public ScriptedAI + { + npc_saurfang_eventAI(Creature* pCreature) : ScriptedAI(pCreature) + { + uiNPCindex = 0; + } + + void SetData(uint32 type, uint32 data) + { + ASSERT(!type && data && data < 6); + uiNPCindex = data; + } + + void SpellHit(Unit* /*caster*/, SpellEntry const* spell) + { + if (spell->Id == SPELL_GRIP_OF_AGONY) + { + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->GetMotionMaster()->MovePoint(POINT_CHOKE, chokePos[uiNPCindex]); + } + } + + void DoAction(const int32 action) + { + if (action == ACTION_CHARGE && uiNPCindex) + me->GetMotionMaster()->MoveCharge(chargePos[uiNPCindex].GetPositionX(), chargePos[uiNPCindex].GetPositionY(), chargePos[uiNPCindex].GetPositionZ(), 13.0f, POINT_CHARGE); + else if (action == ACTION_DESPAWN) + me->ForcedDespawn(); + } + + private: + EventMap events; + uint32 uiNPCindex; + }; + + CreatureAI* GetAI(Creature* pCreature) const + { + return new npc_saurfang_eventAI(pCreature); + } +}; + +class spell_deathbringer_blood_link : public SpellScriptLoader +{ + public: + spell_deathbringer_blood_link() : SpellScriptLoader("spell_deathbringer_blood_link") { } + + class spell_deathbringer_blood_link_SpellScript : public SpellScript + { + bool Validate(SpellEntry const* /*spellInfo*/) + { + if (!sSpellStore.LookupEntry(SPELL_BLOOD_LINK_POWER)) + return false; + if (!sSpellStore.LookupEntry(SPELL_BLOOD_POWER)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_POWER, SPELLVALUE_BASE_POINT0, GetEffectValue(), GetHitUnit(), true); + if (!GetHitUnit()->HasAura(SPELL_BLOOD_POWER)) + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_BLOOD_POWER, true); + else if (Aura* bloodPower = GetHitUnit()->GetAura(SPELL_BLOOD_POWER)) + bloodPower->RecalculateAmountOfEffects(); + PreventHitDefaultEffect(EFFECT_0); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_deathbringer_blood_link_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + + bool Load() + { + if (GetSpellInfo()->Id != SPELL_BLOOD_LINK_DUMMY) + return false; + return true; + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_deathbringer_blood_link_SpellScript(); + } +}; + +class spell_deathbringer_blood_link_aura : public SpellScriptLoader +{ + public: + spell_deathbringer_blood_link_aura() : SpellScriptLoader("spell_deathbringer_blood_link_aura") { } + + class spell_deathbringer_blood_link_AuraScript : public AuraScript + { + bool Validate(SpellEntry const* /*spellInfo*/) + { + if (!sSpellStore.LookupEntry(SPELL_MARK_OF_THE_FALLEN_CHAMPION)) + return false; + return true; + } + + void HandlePeriodicTick(AuraEffect const * /*aurEff*/, AuraApplication const * /*aurApp*/) + { + if (GetUnitOwner()->getPowerType() == POWER_ENERGY && GetUnitOwner()->GetPower(POWER_ENERGY) == GetUnitOwner()->GetMaxPower(POWER_ENERGY)) + if (Creature* saurfang = GetUnitOwner()->ToCreature()) + saurfang->AI()->DoAction(ACTION_MARK_OF_THE_FALLEN_CHAMPION); + } + + void Register() + { + PreventDefaultAction(EFFECT_1); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_deathbringer_blood_link_AuraScript::HandlePeriodicTick, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + } + + bool Load() + { + if (GetSpellProto()->Id != SPELL_BLOOD_LINK) + return false; + return true; + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_deathbringer_blood_link_AuraScript(); + } +}; + +class spell_deathbringer_blood_power : public SpellScriptLoader +{ + public: + spell_deathbringer_blood_power() : SpellScriptLoader("spell_deathbringer_blood_power") { } + + class spell_deathbringer_blood_power_SpellScript : public SpellScript + { + void ModAuraValue() + { + if (Aura* aura = GetHitAura()) + aura->RecalculateAmountOfEffects(); + } + + void Register() + { + AfterHit += SpellHitFn(spell_deathbringer_blood_power_SpellScript::ModAuraValue); + } + }; + + class spell_deathbringer_blood_power_AuraScript : public AuraScript + { + void RecalculateHook(AuraEffect const* /*aurEffect*/, int32& amount, bool& canBeRecalculated) + { + amount = GetUnitOwner()->GetPower(POWER_ENERGY); + canBeRecalculated = true; + } + + void Register() + { + OnEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_0, SPELL_AURA_MOD_SCALE); + OnEffectCalcAmount += AuraEffectCalcAmountFn(spell_deathbringer_blood_power_AuraScript::RecalculateHook, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + } + + bool Load() + { + if (GetUnitOwner()->getPowerType() != POWER_ENERGY) + return false; + return true; + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_deathbringer_blood_power_SpellScript(); + } + + AuraScript* GetAuraScript() const + { + return new spell_deathbringer_blood_power_AuraScript(); + } +}; + +class spell_deathbringer_rune_of_blood : public SpellScriptLoader +{ + public: + spell_deathbringer_rune_of_blood() : SpellScriptLoader("spell_deathbringer_rune_of_blood") { } + + class spell_deathbringer_rune_of_blood_SpellScript : public SpellScript + { + bool Validate(SpellEntry const* /*spellInfo*/) + { + if (!sSpellStore.LookupEntry(SPELL_BLOOD_LINK_DUMMY)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetCaster()->GetPower(POWER_ENERGY) != GetCaster()->GetMaxPower(POWER_ENERGY)) + GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 1, GetCaster(), true); + } + + void Register() + { + PreventHitDefaultEffect(EFFECT_1); // make this the default handler + OnEffect += SpellEffectFn(spell_deathbringer_rune_of_blood_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_deathbringer_rune_of_blood_SpellScript(); + } +}; + +class spell_deathbringer_blood_nova : public SpellScriptLoader +{ + public: + spell_deathbringer_blood_nova() : SpellScriptLoader("spell_deathbringer_blood_nova") { } + + class spell_deathbringer_blood_nova_SpellScript : public SpellScript + { + bool Validate(SpellEntry const* /*spellInfo*/) + { + if (!sSpellStore.LookupEntry(SPELL_BLOOD_LINK_DUMMY)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetCaster()->GetPower(POWER_ENERGY) != GetCaster()->GetMaxPower(POWER_ENERGY)) + GetHitUnit()->CastCustomSpell(SPELL_BLOOD_LINK_DUMMY, SPELLVALUE_BASE_POINT0, 2, GetCaster(), true); + } + + void Register() + { + PreventHitDefaultEffect(EFFECT_1); // make this the default handler + OnEffect += SpellEffectFn(spell_deathbringer_blood_nova_SpellScript::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_deathbringer_blood_nova_SpellScript(); + } +}; + +class achievement_ive_gone_and_made_a_mess : public AchievementCriteriaScript +{ + public: + achievement_ive_gone_and_made_a_mess() : AchievementCriteriaScript("achievement_ive_gone_and_made_a_mess") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + if (Creature* saurfang = target->ToCreature()) + if (saurfang->AI()->GetData(DATA_MADE_A_MESS)) + return true; + + return false; + } +}; + +void AddSC_boss_deathbringer_saurfang() +{ + new boss_deathbringer_saurfang(); + new npc_high_overlord_saurfang_icc(); + new npc_muradin_bronzebeard_icc(); + new npc_saurfang_event(); + new spell_deathbringer_blood_link(); + new spell_deathbringer_blood_link_aura(); + new spell_deathbringer_blood_power(); + new spell_deathbringer_rune_of_blood(); + new spell_deathbringer_blood_nova(); + new achievement_ive_gone_and_made_a_mess(); +} diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index 8517af8a658..130cfe4f026 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -748,6 +748,34 @@ class npc_vengeful_shade : public CreatureScript } }; +class spell_deathwhisper_mana_barrier : public SpellScriptLoader +{ + public: + spell_deathwhisper_mana_barrier() : SpellScriptLoader("spell_deathwhisper_mana_barrier") { } + + class spell_deathwhisper_mana_barrier_AuraScript : public AuraScript + { + void HandlePeriodicTick(AuraEffect const * aurEff, AuraApplication const * aurApp) + { + PreventDefaultAction(EFFECT_0); + Unit* caster = GetCaster(); + int32 missingHealth = caster->GetMaxHealth() - caster->GetHealth(); + caster->ModifyHealth(missingHealth); + caster->ModifyPower(POWER_MANA, -missingHealth); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_deathwhisper_mana_barrier_AuraScript::HandlePeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_deathwhisper_mana_barrier_AuraScript(); + } +}; + class spell_cultist_dark_martyrdom : public SpellScriptLoader { public: @@ -794,5 +822,6 @@ void AddSC_boss_lady_deathwhisper() new npc_cult_fanatic(); new npc_cult_adherent(); new npc_vengeful_shade(); + new spell_deathwhisper_mana_barrier(); new spell_cultist_dark_martyrdom(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index bb66a727bb4..ad7147ee58c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -19,6 +19,7 @@ #include "ScriptPCH.h" #include "icecrown_citadel.h" #include "MapManager.h" +#include "Spell.h" enum eScriptTexts { @@ -85,6 +86,7 @@ class boss_lord_marrowgar : public CreatureScript fBaseSpeed = pCreature->GetSpeedRate(MOVE_RUN); bIntroDone = false; pInstance = pCreature->GetInstanceScript(); + coldflameLastPos.Relocate(pCreature); } void Reset() @@ -161,6 +163,7 @@ class boss_lord_marrowgar : public CreatureScript events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(25000, 35000)); break; case EVENT_COLDFLAME: + coldflameLastPos.Relocate(me); if (!me->HasAura(SPELL_BONE_STORM)) DoCast(me, SPELL_COLDFLAME_NORMAL); else @@ -230,6 +233,11 @@ class boss_lord_marrowgar : public CreatureScript DoStartNoMovement(me->getVictim()); } + const Position* GetLastColdflamePosition() const + { + return &coldflameLastPos; + } + private: EventMap events; @@ -238,6 +246,7 @@ class boss_lord_marrowgar : public CreatureScript uint32 uiBoneStormDuration; float fBaseSpeed; bool bBoneSlice; + Position coldflameLastPos; }; CreatureAI* GetAI(Creature* pCreature) const @@ -283,7 +292,8 @@ class npc_coldflame : public CreatureScript else { me->GetPosition(x, y, z); - float ang = me->GetAngle(owner) - static_cast<float>(M_PI); + Position const* ownerPos = CAST_AI(boss_lord_marrowgar::boss_lord_marrowgarAI, owner->ToCreature()->AI())->GetLastColdflamePosition(); + float ang = me->GetAngle(ownerPos) - static_cast<float>(M_PI); MapManager::NormalizeOrientation(ang); x += 50.0f * cosf(ang); y += 50.0f * sinf(ang); @@ -407,12 +417,24 @@ class spell_marrowgar_coldflame : public SpellScriptLoader { void HandleScriptEffect(SpellEffIndex effIndex) { + Unit* caster = GetCaster(); uint8 count = 1; if (GetSpellInfo()->Id == 72705) count = 4; + SpellCastTargets targets; + targets.setUnitTarget(caster); + targets.setDst(*caster); + + Spell* spell = NULL; + SpellEntry const* spellInfo = NULL; + for (uint8 i = 0; i < count; ++i) - GetCaster()->CastSpell(GetCaster(), SpellMgr::CalculateSpellEffectAmount(GetSpellInfo(), EFFECT_0)+i, true); + { + spellInfo = sSpellStore.LookupEntry(GetEffectValue()+i); + spell = new Spell(caster, spellInfo, true); + spell->prepare(&targets); + } } void Register() @@ -450,8 +472,8 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader { // select any unit but not the tank Unit* target = marrowgarAI->SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true, -SPELL_IMPALED); - if (!target) - target = marrowgarAI->SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_IMPALED); // or the tank if its solo + if (!target && !i) + target = marrowgarAI->SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_IMPALED); if (!target) break; yell = true; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 3ef6729ace3..132a3ff9b4c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -39,25 +39,36 @@ enum eData DATA_SINDRAGOSA = 10, DATA_THE_LICH_KING = 11, - COMMAND_FAIL_BONED + COMMAND_FAIL_BONED, + DATA_SAURFANG_EVENT_NPC, + DATA_SAURFANG_DOOR, }; #define MAX_ENCOUNTER 12 enum eCreatures { - NPC_LORD_MARROWGAR = 36612, - NPC_COLDFLAME = 36672, - NPC_BONE_SPIKE = 36619, + NPC_LORD_MARROWGAR = 36612, + NPC_COLDFLAME = 36672, + NPC_BONE_SPIKE = 36619, - NPC_LADY_DEATHWHISPER = 36855, - NPC_CULT_FANATIC = 37890, - NPC_DEFORMED_FANATIC = 38135, - NPC_REANIMATED_FANATIC = 38009, - NPC_CULT_ADHERENT = 37949, - NPC_EMPOWERED_ADHERENT = 38136, - NPC_REANIMATED_ADHERENT = 38010, - NPC_VENGEFUL_SHADE = 38222, + NPC_LADY_DEATHWHISPER = 36855, + NPC_CULT_FANATIC = 37890, + NPC_DEFORMED_FANATIC = 38135, + NPC_REANIMATED_FANATIC = 38009, + NPC_CULT_ADHERENT = 37949, + NPC_EMPOWERED_ADHERENT = 38136, + NPC_REANIMATED_ADHERENT = 38010, + NPC_VENGEFUL_SHADE = 38222, + + NPC_DEATHBRINGER_SAURFANG = 37813, + NPC_BLOOD_BEAST = 38508, + NPC_SE_JAINA_PROUDMOORE = 37188, // SE means Saurfang Event + NPC_SE_MURADIN_BRONZEBEARD = 37200, + NPC_SE_KING_VARIAN_WRYNN = 37879, + NPC_SE_HIGH_OVERLORD_SAURFANG = 37187, + NPC_SE_KOR_KRON_REAVER = 37920, + NPC_SE_SKYBREAKER_MARINE = 37830, }; enum eGameobjects @@ -67,6 +78,11 @@ enum eGameobjects LORD_MARROWGAR_S_ENTRANCE = 201857, ORATORY_OF_THE_DAMNED_ENTRANCE = 201563, LADY_DEATHWHISPER_ELEVATOR = 202220, + SAURFANG_S_DOOR = 201825, + DEATHBRINGER_S_CACHE_10N = 202239, + DEATHBRINGER_S_CACHE_25N = 202240, + DEATHBRINGER_S_CACHE_10H = 202238, + DEATHBRINGER_S_CACHE_25H = 202241, }; enum eAchievementCriteria diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 8ab824442b2..7b4d1b0e1ee 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -33,7 +33,11 @@ class instance_icecrown_citadel : public InstanceMapScript uiMarrowgarEntrance = 0; uiLadyDeathwisperElevator = 0; uiOratoryDoor = 0; - isBonedEligible = true; + uiDeathbringerSaurfang = 0; + uiSaurfangDoor = 0; + uiSaurfangEventNPC = 0; + uiDeathbringersCache = 0; + isBonedEligible = false; } bool IsEncounterInProgress() const @@ -45,6 +49,36 @@ class instance_icecrown_citadel : public InstanceMapScript return false; } + void OnCreatureCreate(Creature* creature, bool add) + { + Map::PlayerList const &players = instance->GetPlayers(); + uint32 TeamInInstance = 0; + + if (!players.isEmpty()) + { + if (Player* pPlayer = players.begin()->getSource()) + TeamInInstance = pPlayer->GetTeam(); + } + + switch (creature->GetEntry()) + { + case NPC_DEATHBRINGER_SAURFANG: + uiDeathbringerSaurfang = creature->GetGUID(); + break; + case NPC_SE_HIGH_OVERLORD_SAURFANG: + if (TeamInInstance == ALLIANCE) + creature->UpdateEntry(NPC_SE_MURADIN_BRONZEBEARD, ALLIANCE); + case NPC_SE_MURADIN_BRONZEBEARD: + uiSaurfangEventNPC = creature->GetGUID(); + creature->LastUsedScriptID = creature->GetScriptId(); + break; + case NPC_SE_KOR_KRON_REAVER: + if (TeamInInstance == ALLIANCE) + creature->UpdateEntry(NPC_SE_SKYBREAKER_MARINE, ALLIANCE); + break; + } + } + void OnGameObjectCreate(GameObject* pGo, bool add) { switch (pGo->GetEntry()) @@ -77,6 +111,15 @@ class instance_icecrown_citadel : public InstanceMapScript pGo->SetGoState(GO_STATE_READY); } break; + case SAURFANG_S_DOOR: + uiSaurfangDoor = pGo->GetGUID(); + break; + case DEATHBRINGER_S_CACHE_10N: + case DEATHBRINGER_S_CACHE_25N: + case DEATHBRINGER_S_CACHE_10H: + case DEATHBRINGER_S_CACHE_25H: + uiDeathbringersCache = pGo->GetGUID(); + break; } } @@ -102,6 +145,21 @@ class instance_icecrown_citadel : public InstanceMapScript return 0; } + uint64 GetData64(uint32 type) + { + switch (type) + { + case DATA_DEATHBRINGER_SAURFANG: + return uiDeathbringerSaurfang; + case DATA_SAURFANG_EVENT_NPC: + return uiSaurfangEventNPC; + case DATA_SAURFANG_DOOR: + return uiSaurfangDoor; + } + + return 0; + } + void SetData(uint32 type, uint32 data) { switch (type) @@ -130,6 +188,8 @@ class instance_icecrown_citadel : public InstanceMapScript switch(data) { case DONE: + // TEMPORARY, UNCOMMMENT IF YOU WANT TO DO SAURFANG AND SKIP GUNSHIP + //uiEncounterState[DATA_GUNSHIP_EVENT] = DONE; HandleGameObject(uiOratoryDoor, true); if (GameObject* elevator = instance->GetGameObject(uiLadyDeathwisperElevator)) { @@ -146,7 +206,15 @@ class instance_icecrown_citadel : public InstanceMapScript } break; case DATA_GUNSHIP_EVENT: + uiEncounterState[type] = data; + break; case DATA_DEATHBRINGER_SAURFANG: + uiEncounterState[type] = data; + if (data == DONE) + if (GameObject* lootCache = instance->GetGameObject(uiDeathbringersCache)) + if (!lootCache->isSpawned()) + lootCache->SetRespawnTime(7*DAY); + break; case DATA_FESTERGUT: case DATA_ROTFACE: case DATA_PROFESSOR_PUTRICIDE: @@ -230,6 +298,10 @@ class instance_icecrown_citadel : public InstanceMapScript uint64 uiMarrowgarEntrance; uint64 uiLadyDeathwisperElevator; uint64 uiOratoryDoor; + uint64 uiDeathbringerSaurfang; + uint64 uiSaurfangDoor; + uint64 uiSaurfangEventNPC; // Muradin Bronzebeard or High Overlord Saurfang + uint64 uiDeathbringersCache; bool isBonedEligible; }; |