diff options
Diffstat (limited to 'src')
11 files changed, 704 insertions, 40 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b5658267d6b..b88021cbb50 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5758,6 +5758,13 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, AuraEffect* trigger triggered_spell_id = 70701; break; } + case 70871: + { + target = this; + triggered_spell_id = 70872; + basepoints0 = int32(damage) * triggerAmount / 100; + break; + } } break; } diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 65a22002534..d2b1cfc6bdb 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -470,6 +470,7 @@ void AddSC_boss_festergut(); void AddSC_boss_rotface(); void AddSC_boss_professor_putricide(); void AddSC_boss_blood_prince_council(); +void AddSC_boss_blood_queen_lana_thel(); void AddSC_icecrown_citadel_teleport(); void AddSC_instance_icecrown_citadel(); @@ -1155,6 +1156,7 @@ void AddNorthrendScripts() AddSC_boss_rotface(); AddSC_boss_professor_putricide(); AddSC_boss_blood_prince_council(); + AddSC_boss_blood_queen_lana_thel(); AddSC_icecrown_citadel_teleport(); AddSC_instance_icecrown_citadel(); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a8d1a44528a..9bff6b85ab1 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -2800,6 +2800,32 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur) ++itr; } break; + case 71390: // Pact of the Darkfallen + { + for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end();) + { + if (!(*itr)->HasAura(71340)) + itr = unitList.erase(itr); + else + ++itr; + } + bool remove = true; + // we can do this, unitList is MAX 4 in size + for (std::list<Unit*>::const_iterator itr = unitList.begin(); itr != unitList.end() && remove; ++itr) + { + if (!m_caster->IsWithinDist(*itr, 5.0f, false)) + remove = false; + + for (std::list<Unit*>::const_iterator itr2 = unitList.begin(); itr2 != unitList.end() && remove; ++itr2) + if (itr != itr2 && !(*itr2)->IsWithinDist(*itr, 5.0f, false)) + remove = false; + } + + if (remove) + for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr) + (*itr)->RemoveAura(71340); + break; + } } // Death Pact if (m_spellInfo->SpellFamilyName == SPELLFAMILY_DEATHKNIGHT && m_spellInfo->SpellFamilyFlags[0] & 0x00080000) diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 1fa668bd18d..fe2d1dbe28c 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3624,6 +3624,8 @@ void SpellMgr::LoadSpellCustomAttr() case 69782: case 69796: // Ooze Flood case 69798: case 69801: // Ooze Flood case 69538: case 69553: case 69610: // Ooze Combine + case 71447: case 71481: // Bloodbolt Splash + case 71482: case 71483: // Bloodbolt Splash mSpellCustomAttr[i] |= SPELL_ATTR_CU_EXCLUDE_SELF; count++; break; @@ -3951,6 +3953,10 @@ void SpellMgr::LoadSpellCustomAttr() spellInfo->AttributesEx3 |= SPELL_ATTR_EX3_NO_DONE_BONUS; count++; break; + case 71340: // Pact of the Darkfallen + spellInfo->DurationIndex = 21; + count++; + break; default: break; } diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 6de8a63ff1c..cad76883781 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -152,6 +152,7 @@ set(scripts_STAT_SRCS Northrend/IcecrownCitadel/boss_rotface.cpp Northrend/IcecrownCitadel/boss_professor_putricide.cpp Northrend/IcecrownCitadel/boss_blood_prince_council.cpp + Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp Northrend/zuldrak.cpp Northrend/icecrown.cpp Northrend/Gundrak/boss_slad_ran.cpp diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index 00545783ec0..65254996eca 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -299,10 +299,12 @@ class boss_blood_council_controller : public CreatureScript } if (newPrince) + { newPrince->SetHealth(me->GetHealth()); + newPrince->AI()->Talk(invocationOrder[invocationStage].textId); + } DoCast(me, invocationOrder[invocationStage].spellId); - Talk(invocationOrder[invocationStage].textId); events.ScheduleEvent(EVENT_INVOCATION_OF_BLOOD, 30000); break; } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp new file mode 100644 index 00000000000..4b45ad1643e --- /dev/null +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp @@ -0,0 +1,576 @@ +/* + * Copyright (C) 2008-2010 TrinityCore <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, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "Spell.h" +#include "SpellAuraEffects.h" +#include "icecrown_citadel.h" + +enum eTexts +{ + SAY_AGGRO = 0, + SAY_VAMPIRIC_BITE = 1, + SAY_MIND_CONTROL = 2, + EMOTE_BLOODTHIRST = 3, + SAY_SWARMING_SHADOWS = 4, + EMOTE_SWARMING_SHADOWS = 5, + SAY_PACT_OF_THE_DARKFALLEN = 6, + SAY_AIR_PHASE = 7, + SAY_KILL = 8, + SAY_WIPE = 9, + SAY_BERSERK = 10, + SAY_DEATH = 11, +}; + +enum eSpells +{ + SPELL_SHROUD_OF_SORROW = 70986, + SPELL_FRENZIED_BLOODTHIRST_VISUAL = 71949, + SPELL_VAMPIRIC_BITE = 71726, + SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR = 70879, + SPELL_FRENZIED_BLOODTHIRST = 70877, + SPELL_UNCONTROLLABLE_FRENZY = 70923, + SPELL_PRESENCE_OF_THE_DARKFALLEN = 71952, + SPELL_BLOOD_MIRROR_DAMAGE = 70821, + SPELL_BLOOD_MIRROR_VISUAL = 71510, + SPELL_BLOOD_MIRROR_DUMMY = 70838, + SPELL_DELIRIOUS_SLASH = 71623, + SPELL_PACT_OF_THE_DARKFALLEN_TARGET = 71336, + SPELL_PACT_OF_THE_DARKFALLEN = 71340, + SPELL_SWARMING_SHADOWS = 71264, + SPELL_TWILIGHT_BLOODBOLT_TARGET = 71445, + SPELL_TWILIGHT_BLOODBOLT = 71446, + SPELL_INCITE_TERROR = 73070, + SPELL_BLOODBOLT_WHIRL = 71772, +}; + +static const uint32 vampireAuras[3][MAX_DIFFICULTY] = +{ + {70867, 71473, 71532, 71533}, + {70879, 71525, 71530, 71531}, + {70877, 71474, 70877, 71474}, +}; + +#define ESSENCE_OF_BLOOD_QUEEN RAID_MODE<uint32>(70867,71473,71532,71533) +#define ESSENCE_OF_BLOOD_QUEEN_PLR RAID_MODE<uint32>(70879,71525,71530,71531) +#define FRENZIED_BLOODTHIRST RAID_MODE<uint32>(70877,71474,70877,71474) + +enum eEvents +{ + EVENT_BERSERK = 1, + EVENT_VAMPIRIC_BITE = 2, + EVENT_BLOOD_MIRROR = 3, + EVENT_DELIRIOUS_SLASH = 4, + EVENT_PACT_OF_THE_DARKFALLEN = 5, + EVENT_SWARMING_SHADOWS = 6, + EVENT_TWILIGHT_BLOODBOLT = 7, + EVENT_AIR_PHASE = 8, + EVENT_AIR_START_FLYING = 9, + EVENT_AIR_FLY_DOWN = 10, + + EVENT_GROUP_NORMAL = 1, + EVENT_GROUP_CANCELLABLE = 2, +}; + +#define GUID_VAMPIRE 1 + +enum ePoints +{ + POINT_CENTER = 1, + POINT_AIR = 2, + POINT_GROUND = 3, +}; + +static const Position centerPos = {4595.7090f, 2769.4190f, 400.6368f, 0.0000f}; +static const Position airPos = {4595.7090f, 2769.4190f, 422.3893f, 0.0000f}; + +bool IsVampire(Unit const* unit) +{ + for (uint8 i = 0; i < 3; ++i) + if (unit->HasAura(vampireAuras[i][unit->GetMap()->GetSpawnMode()])) + return true; + return false; +} + +class VampiricBiteTargetSelector : public std::unary_function<Unit*, bool> +{ + public: + VampiricBiteTargetSelector() { } + + bool operator() (Unit const* target) + { + if (!target) + return false; + + if (target->GetTypeId() != TYPEID_PLAYER) + return false; + + if (IsVampire(target)) + return false; + + return true; + } +}; + +class boss_blood_queen_lana_thel : public CreatureScript +{ + public: + boss_blood_queen_lana_thel() : CreatureScript("boss_blood_queen_lana_thel") { } + + struct boss_blood_queen_lana_thelAI : public BossAI + { + boss_blood_queen_lana_thelAI(Creature* creature) : BossAI(creature, DATA_BLOOD_QUEEN_LANA_THEL) + { + } + + void InitializeAI() + { + if (!instance || static_cast<InstanceMap*>(me->GetMap())->GetScriptId() != GetScriptId(ICCScriptName)) + me->IsAIEnabled = false; + else if (!me->isDead()) + Reset(); + } + + void Reset() + { + events.Reset(); + events.ScheduleEvent(EVENT_BERSERK, 330000); + events.ScheduleEvent(EVENT_VAMPIRIC_BITE, 15000); + events.ScheduleEvent(EVENT_BLOOD_MIRROR, 2500, EVENT_GROUP_CANCELLABLE); + events.ScheduleEvent(EVENT_DELIRIOUS_SLASH, urand(20000, 24000), EVENT_GROUP_NORMAL); + events.ScheduleEvent(EVENT_PACT_OF_THE_DARKFALLEN, 15000, EVENT_GROUP_NORMAL); + events.ScheduleEvent(EVENT_SWARMING_SHADOWS, 30500, EVENT_GROUP_NORMAL); + events.ScheduleEvent(EVENT_TWILIGHT_BLOODBOLT, urand(20000, 25000), EVENT_GROUP_NORMAL); + events.ScheduleEvent(EVENT_AIR_PHASE, 124000 + (Is25ManRaid() ? 3000 : 0)); + me->SetSpeed(MOVE_FLIGHT, 0.642857f, true); + offtank = NULL; + vampires.clear(); + + instance->SetBossState(DATA_BLOOD_QUEEN_LANA_THEL, NOT_STARTED); + } + + void EnterCombat(Unit* /*who*/) + { + DoZoneInCombat(); + Talk(SAY_AGGRO); + instance->SetBossState(DATA_BLOOD_QUEEN_LANA_THEL, IN_PROGRESS); + + DoCast(me, SPELL_SHROUD_OF_SORROW, true); + DoCast(me, SPELL_FRENZIED_BLOODTHIRST_VISUAL, true); + } + + void JustDied(Unit* /*killer*/) + { + Talk(SAY_DEATH); + instance->DoRemoveAurasDueToSpellOnPlayers(ESSENCE_OF_BLOOD_QUEEN); + instance->DoRemoveAurasDueToSpellOnPlayers(ESSENCE_OF_BLOOD_QUEEN_PLR); + instance->DoRemoveAurasDueToSpellOnPlayers(FRENZIED_BLOODTHIRST); + instance->SetBossState(DATA_BLOOD_QUEEN_LANA_THEL, DONE); + } + + void JustReachedHome() + { + Talk(SAY_WIPE); + instance->SetBossState(DATA_BLOOD_QUEEN_LANA_THEL, FAIL); + } + + void KilledUnit(Unit* victim) + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_KILL); + } + + void SetGUID(const uint64& guid, int32 type = 0) + { + if (type == GUID_VAMPIRE) + vampires.insert(guid); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_CENTER: + DoCast(me, SPELL_INCITE_TERROR); + events.ScheduleEvent(EVENT_AIR_PHASE, 100000 + (Is25ManRaid() ? 0 : 20000)); + events.RescheduleEvent(EVENT_SWARMING_SHADOWS, 30500, EVENT_GROUP_NORMAL); + events.RescheduleEvent(EVENT_PACT_OF_THE_DARKFALLEN, 25500, EVENT_GROUP_NORMAL); + events.ScheduleEvent(EVENT_AIR_START_FLYING, 5000); + break; + case POINT_AIR: + DoCast(me, SPELL_BLOODBOLT_WHIRL); + Talk(SAY_AIR_PHASE); + events.ScheduleEvent(EVENT_AIR_FLY_DOWN, 10000); + break; + case POINT_GROUND: + me->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, 0x01); + me->SetFlying(false); + me->SetReactState(REACT_AGGRESSIVE); + AttackStart(me->getVictim()); + events.ScheduleEvent(EVENT_BLOOD_MIRROR, 2500, EVENT_GROUP_CANCELLABLE); + break; + default: + break; + } + } + + void UpdateAI(const uint32 diff) + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + if (me->hasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_BERSERK: + DoScriptText(EMOTE_GENERIC_BERSERK_RAID, me); + Talk(SAY_BERSERK); + DoCast(me, SPELL_BERSERK); + break; + case EVENT_VAMPIRIC_BITE: + if (Player* target = SelectRandomTarget(false)) + { + DoCast(target, SPELL_VAMPIRIC_BITE); + Talk(SAY_VAMPIRIC_BITE); + vampires.insert(target->GetGUID()); + } + break; + case EVENT_BLOOD_MIRROR: + { + Player* newOfftank = SelectRandomTarget(true); + if (offtank != newOfftank) + { + offtank = newOfftank; + offtank->CastSpell(me->getVictim(), SPELL_BLOOD_MIRROR_DAMAGE, true); + me->getVictim()->CastSpell(offtank, SPELL_BLOOD_MIRROR_DUMMY, true); + DoCastVictim(SPELL_BLOOD_MIRROR_VISUAL); + } + events.ScheduleEvent(EVENT_BLOOD_MIRROR, 2500, EVENT_GROUP_CANCELLABLE); + break; + } + case EVENT_DELIRIOUS_SLASH: + if (offtank && !me->HasByteFlag(UNIT_FIELD_BYTES_1, 3, 0x03)) + DoCast(offtank, SPELL_DELIRIOUS_SLASH); + events.ScheduleEvent(EVENT_DELIRIOUS_SLASH, urand(20000, 24000), EVENT_GROUP_NORMAL); + break; + case EVENT_PACT_OF_THE_DARKFALLEN: + { + std::list<Player*> targets; + SelectRandomTarget(false, &targets); + uint32 targetCount = 2; + if (IsHeroic()) + ++targetCount; + if (Is25ManRaid()) + ++targetCount; + Trinity::RandomResizeList<Player*>(targets, targetCount); + if (targets.size() > 1) + { + Talk(SAY_PACT_OF_THE_DARKFALLEN); + for (std::list<Player*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + DoCast(*itr, SPELL_PACT_OF_THE_DARKFALLEN); + } + events.ScheduleEvent(EVENT_PACT_OF_THE_DARKFALLEN, 30500, EVENT_GROUP_NORMAL); + break; + } + case EVENT_SWARMING_SHADOWS: + if (Player* target = SelectRandomTarget(false)) + { + Talk(EMOTE_SWARMING_SHADOWS, target->GetGUID()); + Talk(SAY_SWARMING_SHADOWS); + DoCast(target, SPELL_SWARMING_SHADOWS); + } + events.ScheduleEvent(EVENT_SWARMING_SHADOWS, 30500, EVENT_GROUP_NORMAL); + break; + case EVENT_TWILIGHT_BLOODBOLT: + { + std::list<Player*> targets; + SelectRandomTarget(false, &targets); + Trinity::RandomResizeList<Player*>(targets, Is25ManRaid() ? 4 : 2); + for (std::list<Player*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) + DoCast(*itr, SPELL_TWILIGHT_BLOODBOLT); + DoCast(me, SPELL_TWILIGHT_BLOODBOLT_TARGET); + events.ScheduleEvent(EVENT_TWILIGHT_BLOODBOLT, urand(10000, 15000), EVENT_GROUP_NORMAL); + break; + } + case EVENT_AIR_PHASE: + DoStopAttack(); + me->SetReactState(REACT_PASSIVE); + events.DelayEvents(7000, EVENT_GROUP_NORMAL); + events.CancelEventsByGCD(EVENT_GROUP_CANCELLABLE); + me->GetMotionMaster()->MovePoint(POINT_CENTER, centerPos); + break; + case EVENT_AIR_START_FLYING: + me->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, 0x01); + me->SetFlying(true); + me->GetMotionMaster()->MovePoint(POINT_AIR, airPos); + break; + case EVENT_AIR_FLY_DOWN: + me->GetMotionMaster()->MovePoint(POINT_GROUND, centerPos); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + bool WasVampire(uint64 guid) + { + return vampires.count(guid) != 0; + } + + private: + // offtank for this encounter is the player standing closest to main tank + Player* SelectRandomTarget(bool includeOfftank, std::list<Player*>* targetList = NULL) + { + const std::list<HostileReference*> &threatlist = me->getThreatManager().getThreatList(); + std::list<Player*> tempTargets; + + if (threatlist.empty()) + return NULL; + + for (std::list<HostileReference*>::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr) + if (Unit* refTarget = (*itr)->getTarget()) + if (refTarget != me->getVictim() && refTarget->GetTypeId() == TYPEID_PLAYER && (includeOfftank ? true : (refTarget != offtank))) + tempTargets.push_back(refTarget->ToPlayer()); + + if (tempTargets.empty()) + return NULL; + + if (targetList) + { + *targetList = tempTargets; + return NULL; + } + + if (includeOfftank) + { + tempTargets.sort(Trinity::ObjectDistanceOrderPred(me->getVictim())); + return tempTargets.front(); + } + + std::list<Player*>::iterator itr = tempTargets.begin(); + std::advance(itr, urand(1, tempTargets.size()-1)); + return *itr; + } + + Player* offtank; + std::set<uint64> vampires; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new boss_blood_queen_lana_thelAI(creature); + } +}; + +// helper for shortened code +typedef boss_blood_queen_lana_thel::boss_blood_queen_lana_thelAI LanaThelAI; + +class spell_blood_queen_vampiric_bite : public SpellScriptLoader +{ + public: + spell_blood_queen_vampiric_bite() : SpellScriptLoader("spell_blood_queen_vampiric_bite") { } + + class spell_blood_queen_vampiric_bite_SpellScript : public SpellScript + { + PrepareSpellScript(spell_blood_queen_vampiric_bite_SpellScript); + + bool Validate(SpellEntry const* /*spell*/) + { + if (!sSpellStore.LookupEntry(SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR)) + return false; + if (!sSpellStore.LookupEntry(SPELL_FRENZIED_BLOODTHIRST)) + return false; + if (!sSpellStore.LookupEntry(SPELL_PRESENCE_OF_THE_DARKFALLEN)) + return false; + return true; + } + + void OnCast() + { + if (GetCaster()->GetTypeId() != TYPEID_PLAYER) + return; + + if (IsVampire(GetHitUnit())) + { + PreventHitDamage(); + PreventHitDefaultEffect(EFFECT_1); + Spell::SendCastResult(GetCaster()->ToPlayer(), GetSpellInfo(), 0, SPELL_FAILED_BAD_TARGETS); + return; + } + + SpellEntry const* spell = sSpellStore.LookupEntry(SPELL_FRENZIED_BLOODTHIRST); + spell = sSpellMgr.GetSpellForDifficultyFromSpell(spell, GetCaster()); + GetCaster()->RemoveAura(spell->Id, 0, 0, AURA_REMOVE_BY_ENEMY_SPELL); + GetCaster()->CastSpell(GetCaster(), SPELL_ESSENCE_OF_THE_BLOOD_QUEEN_PLR, true); + if (GetCaster()->GetMap()->IsHeroic()) + GetCaster()->CastSpell(GetCaster(), SPELL_PRESENCE_OF_THE_DARKFALLEN, true); + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* bloodQueen = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_BLOOD_QUEEN_LANA_THEL))) + bloodQueen->AI()->SetGUID(GetHitUnit()->GetGUID(), GUID_VAMPIRE); + } + + void Register() + { + BeforeHit += SpellHitFn(spell_blood_queen_vampiric_bite_SpellScript::OnCast); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_blood_queen_vampiric_bite_SpellScript(); + } +}; + +class spell_blood_queen_frenzied_bloodthirst : public SpellScriptLoader +{ + public: + spell_blood_queen_frenzied_bloodthirst() : SpellScriptLoader("spell_blood_queen_frenzied_bloodthirst") { } + + class spell_blood_queen_frenzied_bloodthirst_AuraScript : public AuraScript + { + PrepareAuraScript(spell_blood_queen_frenzied_bloodthirst_AuraScript); + + void OnApply(AuraEffect const* /*aurEff*/, AuraApplication const* aurApp, AuraEffectHandleModes /*mode*/) + { + if (InstanceScript* instance = aurApp->GetTarget()->GetInstanceScript()) + if (Creature* bloodQueen = ObjectAccessor::GetCreature(*aurApp->GetTarget(), instance->GetData64(DATA_BLOOD_QUEEN_LANA_THEL))) + bloodQueen->AI()->Talk(EMOTE_BLOODTHIRST); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraApplication const* aurApp, AuraEffectHandleModes /*mode*/) + { + if (!aurApp) + return; + + Unit* target = aurApp->GetTarget(); + if (aurApp->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* bloodQueen = ObjectAccessor::GetCreature(*target, instance->GetData64(DATA_BLOOD_QUEEN_LANA_THEL))) + { + // this needs to be done BEFORE charm aura or we hit an assert in Unit::SetCharmedBy + if (target->GetVehicleKit()) + target->RemoveVehicleKit(); + + bloodQueen->AI()->Talk(SAY_MIND_CONTROL); + bloodQueen->CastSpell(target, SPELL_UNCONTROLLABLE_FRENZY, true); + } + } + + void Register() + { + OnEffectRemove += AuraEffectRemoveFn(spell_blood_queen_frenzied_bloodthirst_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_OVERRIDE_SPELLS, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_blood_queen_frenzied_bloodthirst_AuraScript(); + } +}; + +class spell_blood_queen_bloodbolt : public SpellScriptLoader +{ + public: + spell_blood_queen_bloodbolt() : SpellScriptLoader("spell_blood_queen_bloodbolt") { } + + class spell_blood_queen_bloodbolt_SpellScript : public SpellScript + { + PrepareSpellScript(spell_blood_queen_bloodbolt_SpellScript); + + bool Validate(SpellEntry const* /*spell*/) + { + if (!sSpellStore.LookupEntry(SPELL_TWILIGHT_BLOODBOLT)) + return false; + return true; + } + + void HandleDummy() + { + if (GetHitUnit()->GetTypeId() == TYPEID_PLAYER) + GetCaster()->CastSpell(GetHitUnit(), SPELL_TWILIGHT_BLOODBOLT, true); + } + + void Register() + { + AfterHit += SpellHitFn(spell_blood_queen_bloodbolt_SpellScript::HandleDummy); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_blood_queen_bloodbolt_SpellScript(); + } +}; + +class achievement_once_bitten_twice_shy_n : public AchievementCriteriaScript +{ + public: + achievement_once_bitten_twice_shy_n() : AchievementCriteriaScript("achievement_once_bitten_twice_shy_n") { } + + bool OnCheck(Player* source, Unit* target) + { + if (!target) + return false; + + if (LanaThelAI* lanaThelAI = CAST_AI(LanaThelAI, target->GetAI())) + return !lanaThelAI->WasVampire(source->GetGUID()); + return false; + } +}; + +class achievement_once_bitten_twice_shy_v : public AchievementCriteriaScript +{ + public: + achievement_once_bitten_twice_shy_v() : AchievementCriteriaScript("achievement_once_bitten_twice_shy_v") { } + + bool OnCheck(Player* source, Unit* target) + { + if (!target) + return false; + + if (LanaThelAI* lanaThelAI = CAST_AI(LanaThelAI, target->GetAI())) + return lanaThelAI->WasVampire(source->GetGUID()); + return false; + } +}; + +void AddSC_boss_blood_queen_lana_thel() +{ + new boss_blood_queen_lana_thel(); + new spell_blood_queen_vampiric_bite(); + new spell_blood_queen_frenzied_bloodthirst(); + new spell_blood_queen_bloodbolt(); + new achievement_once_bitten_twice_shy_n(); + new achievement_once_bitten_twice_shy_v(); +} diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp index ff406537c93..f607977340c 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp @@ -180,7 +180,6 @@ class boss_lady_deathwhisper : public CreatureScript void Reset() { - me->SetReactState(REACT_DEFENSIVE); me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA)); me->SetLastManaUse(0xFFFFFFFF); // hacky, but no other way atm to prevent mana regen events.Reset(); @@ -211,8 +210,6 @@ class boss_lady_deathwhisper : public CreatureScript events.ScheduleEvent(EVENT_INTRO_7, 58000, 0, PHASE_INTRO); events.ScheduleEvent(EVENT_INTRO_FINISH, 76000, 0, PHASE_INTRO); } - - BossAI::MoveInLineOfSight(who); } void AttackStart(Unit* victim) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 154da5c9192..51cffb4442d 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -367,6 +367,12 @@ class npc_bone_spike : public CreatureScript trappedGUID = 0; } + void KilledUnit(Unit* victim) + { + if (TempSummon* summ = me->ToTempSummon()) + summ->UnSummon(); + } + void IsSummonedBy(Unit* summoner) { trappedGUID = summoner->GetGUID(); @@ -375,11 +381,13 @@ class npc_bone_spike : public CreatureScript events.ScheduleEvent(EVENT_FAIL_BONED, 8000); } - void UpdateAI(const uint32 /*diff*/) + void UpdateAI(const uint32 diff) { if (!trappedGUID) return; + events.Update(diff); + if (events.ExecuteEvent() == EVENT_FAIL_BONED) if (InstanceScript* instance = me->GetInstanceScript()) instance->SetData(DATA_BONED_ACHIEVEMENT, uint32(false)); @@ -439,7 +447,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader { PrepareSpellScript(spell_marrowgar_bone_spike_graveyard_SpellScript); - void HandleScript(SpellEffIndex effIndex) + void HandleSpikes(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); if (Creature* marrowgar = GetCaster()->ToCreature()) @@ -466,7 +474,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader void Register() { - OnEffect += SpellEffectFn(spell_marrowgar_bone_spike_graveyard_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffect += SpellEffectFn(spell_marrowgar_bone_spike_graveyard_SpellScript::HandleSpikes, EFFECT_1, SPELL_EFFECT_APPLY_AURA); } }; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 0b5a120fe24..14c4bfa6d06 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -136,6 +136,9 @@ enum eCreatures NPC_KINETIC_BOMB_TARGET = 38458, NPC_KINETIC_BOMB = 38454, NPC_SHOCK_VORTEX = 38422, + + // Blood-Queen Lana'thel + NPC_BLOOD_QUEEN_LANA_THEL = 37955, }; enum eGameobjects @@ -190,28 +193,36 @@ enum eGameobjects enum eAchievementCriteria { // Lord Marrowgar - CRITERIA_BONED_10N = 12775, - CRITERIA_BONED_25N = 12962, - CRITERIA_BONED_10H = 13393, - CRITERIA_BONED_25H = 13394, + CRITERIA_BONED_10N = 12775, + CRITERIA_BONED_25N = 12962, + CRITERIA_BONED_10H = 13393, + CRITERIA_BONED_25H = 13394, // Rotface - CRITERIA_DANCES_WITH_OOZES_10N = 12984, - CRITERIA_DANCES_WITH_OOZES_25N = 12966, - CRITERIA_DANCES_WITH_OOZES_10H = 12985, - CRITERIA_DANCES_WITH_OOZES_25H = 12983, + CRITERIA_DANCES_WITH_OOZES_10N = 12984, + CRITERIA_DANCES_WITH_OOZES_25N = 12966, + CRITERIA_DANCES_WITH_OOZES_10H = 12985, + CRITERIA_DANCES_WITH_OOZES_25H = 12983, // Professor Putricide - CRITERIA_NAUSEA_10N = 12987, - CRITERIA_NAUSEA_25N = 12968, - CRITERIA_NAUSEA_10H = 12988, - CRITERIA_NAUSEA_25H = 12981, + CRITERIA_NAUSEA_10N = 12987, + CRITERIA_NAUSEA_25N = 12968, + CRITERIA_NAUSEA_10H = 12988, + CRITERIA_NAUSEA_25H = 12981, // Blood Prince Council - CRITERIA_ORB_WHISPERER_10N = 13033, - CRITERIA_ORB_WHISPERER_25N = 12969, - CRITERIA_ORB_WHISPERER_10H = 13034, - CRITERIA_ORB_WHISPERER_25H = 13032, + CRITERIA_ORB_WHISPERER_10N = 13033, + CRITERIA_ORB_WHISPERER_25N = 12969, + CRITERIA_ORB_WHISPERER_10H = 13034, + CRITERIA_ORB_WHISPERER_25H = 13032, + + // Blood-Queen Lana'thel + CRITERIA_KILL_LANA_THEL_10M = 13340, + CRITERIA_KILL_LANA_THEL_25M = 13360, + CRITERIA_ONCE_BITTEN_TWICE_SHY_10N = 12780, + CRITERIA_ONCE_BITTEN_TWICE_SHY_25N = 13012, + CRITERIA_ONCE_BITTEN_TWICE_SHY_10V = 13011, + CRITERIA_ONCE_BITTEN_TWICE_SHY_25V = 13013, }; enum eSharedActions diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index f92bff6b9dc..a0ad03265d9 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -18,6 +18,8 @@ #include "ObjectMgr.h" #include "ScriptMgr.h" #include "InstanceScript.h" +#include "ScriptedCreature.h" +#include "Map.h" #include "icecrown_citadel.h" static const DoorData doorData[] = @@ -53,6 +55,7 @@ class instance_icecrown_citadel : public InstanceMapScript { SetBossNumber(MAX_ENCOUNTER); LoadDoorData(doorData); + teamInInstance = 0; ladyDeathwisperElevator = 0; deathbringerSaurfang = 0; saurfangDoor = 0; @@ -68,73 +71,82 @@ class instance_icecrown_citadel : public InstanceMapScript putricideTable = 0; memset(bloodCouncil, 0, 3*sizeof(uint64)); bloodCouncilController = 0; + bloodQueenLanaThel = 0; isBonedEligible = true; isOozeDanceEligible = true; isNauseaEligible = true; isOrbWhispererEligible = true; } - void OnCreatureCreate(Creature* creature, bool /*add*/) + void OnPlayerEnter(Player* player) { - Map::PlayerList const &players = instance->GetPlayers(); - uint32 TeamInInstance = 0; + if (!teamInInstance) + teamInInstance = player->GetTeam(); + } + + void OnCreatureCreate(Creature* creature, bool add) + { + if (!add) + return; - if (!players.isEmpty()) + if (!teamInInstance) { - if (Player* pPlayer = players.begin()->getSource()) - TeamInInstance = pPlayer->GetTeam(); + Map::PlayerList const &players = instance->GetPlayers(); + if (!players.isEmpty()) + if (Player* player = players.begin()->getSource()) + teamInInstance = player->GetTeam(); } switch (creature->GetEntry()) { case NPC_KOR_KRON_GENERAL: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_ALLIANCE_COMMANDER, ALLIANCE); break; case NPC_KOR_KRON_LIEUTENANT: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_SKYBREAKER_LIEUTENANT, ALLIANCE); break; case NPC_TORTUNOK: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_ALANA_MOONSTRIKE, ALLIANCE); break; case NPC_GERARDO_THE_SUAVE: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_TALAN_MOONSTRIKE, ALLIANCE); break; case NPC_UVLUS_BANEFIRE: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_MALFUS_GRIMFROST, ALLIANCE); break; case NPC_IKFIRUS_THE_VILE: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_YILI, ALLIANCE); break; case NPC_VOL_GUK: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_JEDEBIA, ALLIANCE); break; case NPC_HARAGG_THE_UNSEEN: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_NIBY_THE_ALMIGHTY, ALLIANCE); break; case NPC_GARROSH_HELLSCREAM: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_KING_VARIAN_WRYNN, ALLIANCE); break; case NPC_DEATHBRINGER_SAURFANG: deathbringerSaurfang = creature->GetGUID(); break; case NPC_SE_HIGH_OVERLORD_SAURFANG: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_SE_MURADIN_BRONZEBEARD, ALLIANCE); case NPC_SE_MURADIN_BRONZEBEARD: saurfangEventNPC = creature->GetGUID(); creature->LastUsedScriptID = creature->GetScriptId(); break; case NPC_SE_KOR_KRON_REAVER: - if (TeamInInstance == ALLIANCE) + if (teamInInstance == ALLIANCE) creature->UpdateEntry(NPC_SE_SKYBREAKER_MARINE, ALLIANCE); break; case NPC_FESTERGUT: @@ -158,6 +170,9 @@ class instance_icecrown_citadel : public InstanceMapScript case NPC_BLOOD_ORB_CONTROLLER: bloodCouncilController = creature->GetGUID(); break; + case NPC_BLOOD_QUEEN_LANA_THEL: + bloodQueenLanaThel = creature->GetGUID(); + break; default: break; } @@ -271,6 +286,8 @@ class instance_icecrown_citadel : public InstanceMapScript return bloodCouncil[2]; case DATA_BLOOD_PRINCES_CONTROL: return bloodCouncilController; + case DATA_BLOOD_QUEEN_LANA_THEL: + return bloodQueenLanaThel; default: break; } @@ -400,6 +417,15 @@ class instance_icecrown_citadel : public InstanceMapScript case CRITERIA_ORB_WHISPERER_10H: case CRITERIA_ORB_WHISPERER_25H: return isOrbWhispererEligible; + // Only one criteria for both modes, need to do it like this + case CRITERIA_KILL_LANA_THEL_10M: + case CRITERIA_ONCE_BITTEN_TWICE_SHY_10N: + case CRITERIA_ONCE_BITTEN_TWICE_SHY_10V: + return CAST_INST(InstanceMap, instance)->GetMaxPlayers() == 10; + case CRITERIA_KILL_LANA_THEL_25M: + case CRITERIA_ONCE_BITTEN_TWICE_SHY_25N: + case CRITERIA_ONCE_BITTEN_TWICE_SHY_25V: + return CAST_INST(InstanceMap, instance)->GetMaxPlayers() == 25; default: break; } @@ -449,6 +475,7 @@ class instance_icecrown_citadel : public InstanceMapScript } private: + uint32 teamInInstance; uint64 ladyDeathwisperElevator; uint64 deathbringerSaurfang; uint64 saurfangDoor; @@ -464,6 +491,7 @@ class instance_icecrown_citadel : public InstanceMapScript uint64 putricideTable; uint64 bloodCouncil[3]; uint64 bloodCouncilController; + uint64 bloodQueenLanaThel; bool isBonedEligible; bool isOozeDanceEligible; bool isNauseaEligible; |