diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp index ef62d41ad..9866eb162 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_bronjahm.cpp @@ -32,7 +32,7 @@ enum Yells SAY_CORRUPT_SOUL = 4, }; -enum eSpells +enum Spells { SPELL_SOULSTORM_CHANNEL_OOC = 69008, @@ -51,7 +51,7 @@ enum eSpells SPELL_SOULSTORM = 68872, }; -enum eEvents +enum Events { EVENT_SPELL_SHADOW_BOLT = 1, EVENT_SPELL_FEAR, @@ -60,207 +60,171 @@ enum eEvents EVENT_START_SOULSTORM, }; -class boss_bronjahm : public CreatureScript +struct boss_bronjahm : public BossAI { -public: - boss_bronjahm() : CreatureScript("boss_bronjahm") { } + boss_bronjahm(Creature* creature) : BossAI(creature, DATA_BRONJAHM) { } - struct boss_bronjahmAI : public ScriptedAI + void JustReachedHome() override { - boss_bronjahmAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - pInstance = creature->GetInstanceScript(); - } + BossAI::JustReachedHome(); + DoCastSelf(SPELL_SOULSTORM_CHANNEL_OOC, true); + } - InstanceScript* pInstance; - EventMap events; - SummonList summons; - - void JustReachedHome() override - { - me->CastSpell(me, SPELL_SOULSTORM_CHANNEL_OOC, true); - } - - void Reset() override - { - me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->CastSpell(me, SPELL_SOULSTORM_CHANNEL_OOC, true); - events.Reset(); - summons.DespawnAll(); - if (pInstance) - pInstance->SetData(DATA_BRONJAHM, NOT_STARTED); - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - me->RemoveAurasDueToSpell(SPELL_SOULSTORM_CHANNEL_OOC); - - DoZoneInCombat(); - events.Reset(); - events.RescheduleEvent(EVENT_SPELL_SHADOW_BOLT, 2s); - events.RescheduleEvent(EVENT_SPELL_MAGICS_BANE, 5s, 10s); - events.RescheduleEvent(EVENT_SPELL_CORRUPT_SOUL, 14s, 20s); - - if (pInstance) - pInstance->SetData(DATA_BRONJAHM, IN_PROGRESS); - } - - void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override - { - if (!me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE) && me->HealthBelowPctDamaged(35, damage)) - { - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveIdle(); - me->CastSpell(me, SPELL_TELEPORT, false); - events.CancelEvent(EVENT_SPELL_CORRUPT_SOUL); - events.DelayEvents(6s); - events.RescheduleEvent(EVENT_SPELL_FEAR, 8s, 14s); - } - } - - void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override - { - if (spell->Id == SPELL_TELEPORT) - { - me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); - events.RescheduleEvent(EVENT_START_SOULSTORM, 1ms); - } - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - if (me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) - if (me->isAttackReady()) - me->SetFacingToObject(me->GetVictim()); - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_SHADOW_BOLT: - if (!me->IsWithinMeleeRange(me->GetVictim())) - me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false); - events.Repeat(2s); - break; - case EVENT_SPELL_FEAR: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 10.0f, true)) - me->CastCustomSpell(SPELL_FEAR, SPELLVALUE_MAX_TARGETS, 1, target, false); - events.Repeat(8s, 12s); - break; - case EVENT_SPELL_MAGICS_BANE: - me->CastSpell(me->GetVictim(), SPELL_MAGICS_BANE, false); - events.Repeat(10s, 15s); - break; - case EVENT_SPELL_CORRUPT_SOUL: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true)) - { - Talk(SAY_CORRUPT_SOUL); - me->CastSpell(target, SPELL_CORRUPT_SOUL, false); - } - events.Repeat(20s, 25s); - break; - case EVENT_START_SOULSTORM: - Talk(SAY_SOUL_STORM); - me->CastSpell(me, SPELL_SOULSTORM, false); - me->CastSpell(me, SPELL_TELEPORT_VISUAL, true); - me->CastSpell(me, SPELL_SOULSTORM_VISUAL, true); - - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEATH); - if (pInstance) - pInstance->SetData(DATA_BRONJAHM, DONE); - } - - void KilledUnit(Unit* who) override - { - if (who->IsPlayer()) - Talk(SAY_SLAY); - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - summon->SetReactState(REACT_PASSIVE); - } - - void EnterEvadeMode(EvadeReason why) override - { - me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); - ScriptedAI::EnterEvadeMode(why); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetForgeOfSoulsAI(creature); + BossAI::Reset(); + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); + DoCastSelf(SPELL_SOULSTORM_CHANNEL_OOC, true); + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + Talk(SAY_AGGRO); + me->RemoveAurasDueToSpell(SPELL_SOULSTORM_CHANNEL_OOC); + + events.RescheduleEvent(EVENT_SPELL_SHADOW_BOLT, 2s); + events.RescheduleEvent(EVENT_SPELL_MAGICS_BANE, 5s, 10s); + events.RescheduleEvent(EVENT_SPELL_CORRUPT_SOUL, 14s, 20s); + } + + void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override + { + if (!me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE) && me->HealthBelowPctDamaged(35, damage)) + { + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->MoveIdle(); + DoCastSelf(SPELL_TELEPORT); + events.CancelEvent(EVENT_SPELL_CORRUPT_SOUL); + events.DelayEvents(6s); + events.RescheduleEvent(EVENT_SPELL_FEAR, 8s, 14s); + } + } + + void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override + { + if (spell->Id == SPELL_TELEPORT) + { + DoCastSelf(SPELL_TELEPORT_VISUAL, true); + events.RescheduleEvent(EVENT_START_SOULSTORM, 1ms); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) + if (me->isAttackReady()) + me->SetFacingToObject(me->GetVictim()); + + switch (events.ExecuteEvent()) + { + case EVENT_SPELL_SHADOW_BOLT: + if (!me->IsWithinMeleeRange(me->GetVictim())) + DoCastVictim(SPELL_SHADOW_BOLT); + events.Repeat(2s); + break; + case EVENT_SPELL_FEAR: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 10.0f, true)) + me->CastCustomSpell(SPELL_FEAR, SPELLVALUE_MAX_TARGETS, 1, target); + events.Repeat(8s, 12s); + break; + case EVENT_SPELL_MAGICS_BANE: + DoCastVictim(SPELL_MAGICS_BANE); + events.Repeat(10s, 15s); + break; + case EVENT_SPELL_CORRUPT_SOUL: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true)) + { + Talk(SAY_CORRUPT_SOUL); + DoCast(target, SPELL_CORRUPT_SOUL); + } + events.Repeat(20s, 25s); + break; + case EVENT_START_SOULSTORM: + Talk(SAY_SOUL_STORM); + DoCastSelf(SPELL_SOULSTORM); + DoCastSelf(SPELL_TELEPORT_VISUAL, true); + DoCastSelf(SPELL_SOULSTORM_VISUAL, true); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + Talk(SAY_DEATH); + } + + void KilledUnit(Unit* who) override + { + if (who->IsPlayer()) + Talk(SAY_SLAY); + } + + void JustSummoned(Creature* summon) override + { + BossAI::JustSummoned(summon); + summon->SetReactState(REACT_PASSIVE); + } + + void EnterEvadeMode(EvadeReason why) override + { + me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); + BossAI::EnterEvadeMode(why); } }; -class npc_fos_corrupted_soul_fragment : public CreatureScript +struct npc_fos_corrupted_soul_fragment : public NullCreatureAI { -public: - npc_fos_corrupted_soul_fragment() : CreatureScript("npc_fos_corrupted_soul_fragment") { } - - struct npc_fos_corrupted_soul_fragmentAI : public NullCreatureAI + npc_fos_corrupted_soul_fragment(Creature* creature) : NullCreatureAI(creature) { - npc_fos_corrupted_soul_fragmentAI(Creature* creature) : NullCreatureAI(creature) - { - pInstance = me->GetInstanceScript(); - } + Instance = me->GetInstanceScript(); + } - uint32 timer; - InstanceScript* pInstance; + uint32 Timer = 0; + InstanceScript* Instance = nullptr; - void Reset() override - { - timer = 0; - } - - void UpdateAI(uint32 diff) override - { - if (pInstance) - if (Creature* b = pInstance->instance->GetCreature(pInstance->GetGuidData(DATA_BRONJAHM))) - { - if (me->GetExactDist2d(b) <= 2.0f) - { - me->GetMotionMaster()->MoveIdle(); - me->CastSpell(b, SPELL_CONSUME_SOUL, true); - me->DespawnOrUnsummon(1ms); - return; - } - - if (timer <= diff) - { - if (!me->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) - me->GetMotionMaster()->MovePoint(0, *b); - timer = 1000; - } - else - timer -= diff; - } - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void Reset() override { - return GetForgeOfSoulsAI(creature); + Timer = 0; + } + + void UpdateAI(uint32 diff) override + { + if (!Instance) + return; + + Creature* bronjahm = Instance->GetCreature(DATA_BRONJAHM); + if (!bronjahm) + return; + + if (me->GetExactDist2d(bronjahm) <= 2.0f) + { + me->GetMotionMaster()->MoveIdle(); + me->CastSpell(bronjahm, SPELL_CONSUME_SOUL, true); + me->DespawnOrUnsummon(1ms); + return; + } + + if (Timer <= diff) + { + if (!me->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + me->GetMotionMaster()->MovePoint(0, *bronjahm); + Timer = 1000; + } + else + Timer -= diff; } }; @@ -275,7 +239,7 @@ class spell_bronjahm_magic_bane : public SpellScript if (Unit* caster = GetCaster()) { - const int32 maxDamage = caster->GetMap()->GetSpawnMode() == 1 ? 15000 : 10000; + int32 const maxDamage = caster->GetMap()->GetSpawnMode() == 1 ? 15000 : 10000; int32 newDamage = GetHitDamage(); newDamage += GetHitUnit()->GetMaxPower(POWER_MANA) / 2; newDamage = std::min(maxDamage, newDamage); @@ -365,9 +329,8 @@ class spell_bronjahm_soulstorm_targeting : public SpellScript void AddSC_boss_bronjahm() { - new boss_bronjahm(); - new npc_fos_corrupted_soul_fragment(); - + RegisterForgeOfSoulsCreatureAI(boss_bronjahm); + RegisterForgeOfSoulsCreatureAI(npc_fos_corrupted_soul_fragment); RegisterSpellScript(spell_bronjahm_magic_bane); RegisterSpellScript(spell_bronjahm_soulstorm_channel_ooc_aura); RegisterSpellScript(spell_bronjahm_soulstorm_visual_aura); diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp index 102b87ed6..fec69d495 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/boss_devourer_of_souls.cpp @@ -24,7 +24,7 @@ #include "SpellScriptLoader.h" #include "forge_of_souls.h" -enum eTexts +enum Texts { SAY_FACE_AGGRO = 0, SAY_FACE_ANGER_SLAY = 1, @@ -38,7 +38,7 @@ enum eTexts SAY_FACE_WAILING_SOUL = 9, }; -enum eSpells +enum Spells { SPELL_PHANTOM_BLAST = 68982, SPELL_PHANTOM_BLAST_H = 70322, @@ -57,7 +57,7 @@ enum eSpells SPELL_WAILING_SOULS_DMG_H = 70324, // 100yd, 104.0 }; -enum eEvents +enum Events { EVENT_SPELL_PHANTOM_BLAST = 1, EVENT_SPELL_MIRRORED_SOUL, @@ -66,245 +66,214 @@ enum eEvents EVENT_SPELL_WAILING_SOULS, }; -enum eDisplayIds +enum ModelIds { - DISPLAY_ANGER = 30148, - DISPLAY_SORROW = 30149, - DISPLAY_DESIRE = 30150, + MODEL_ANGER = 30148, + MODEL_SORROW = 30149, + MODEL_DESIRE = 30150, }; -enum eMisc +enum Misc { NPC_CRUCIBLE_OF_SOULS = 37094, + NPC_UNLEASHED_SOUL = 36595, QUEST_TEMPERING_THE_BLADE_A = 24476, QUEST_TEMPERING_THE_BLADE_H = 24560, }; -class boss_devourer_of_souls : public CreatureScript +struct boss_devourer_of_souls : public BossAI { -public: - boss_devourer_of_souls() : CreatureScript("boss_devourer_of_souls") { } + boss_devourer_of_souls(Creature* creature) : BossAI(creature, DATA_DEVOURER) { } - struct boss_devourer_of_soulsAI : public ScriptedAI + bool AchievementCompleted = true; + + void Reset() override { - boss_devourer_of_soulsAI(Creature* creature) : ScriptedAI(creature), summons(me) - { - pInstance = creature->GetInstanceScript(); - } + BossAI::Reset(); + AchievementCompleted = true; + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + me->SetReactState(REACT_AGGRESSIVE); + } - InstanceScript* pInstance; - EventMap events; - SummonList summons; - bool bAchiev; - - void Reset() override - { - bAchiev = true; - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - me->SetReactState(REACT_AGGRESSIVE); - events.Reset(); - summons.DespawnAll(); - if (pInstance) - pInstance->SetData(DATA_DEVOURER, NOT_STARTED); - } - - uint32 GetData(uint32 id) const override - { - if (id == 1) - return bAchiev; - - return 0; - } - - void JustEngagedWith(Unit* /*who*/) override - { - Talk(SAY_FACE_AGGRO); - DoZoneInCombat(); - events.Reset(); - events.RescheduleEvent(EVENT_SPELL_PHANTOM_BLAST, 5s); - events.RescheduleEvent(EVENT_SPELL_MIRRORED_SOUL, 9s); - events.RescheduleEvent(EVENT_SPELL_WELL_OF_SOULS, 6s, 8s); - events.RescheduleEvent(EVENT_SPELL_UNLEASHED_SOULS, 18s, 20s); - events.RescheduleEvent(EVENT_SPELL_WAILING_SOULS, 65s); - - if (pInstance) - pInstance->SetData(DATA_DEVOURER, IN_PROGRESS); - - // Suport for Quest Tempering the Blade - Map::PlayerList const& pList = me->GetMap()->GetPlayers(); - for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) - { - Player* player = itr->GetSource(); - if ((player->GetTeamId() == TEAM_ALLIANCE && player->GetQuestStatus(QUEST_TEMPERING_THE_BLADE_A) == QUEST_STATUS_INCOMPLETE) || - (player->GetTeamId() == TEAM_HORDE && player->GetQuestStatus(QUEST_TEMPERING_THE_BLADE_H) == QUEST_STATUS_INCOMPLETE)) - { - if (!me->FindNearestCreature(NPC_CRUCIBLE_OF_SOULS, 100.0f)) - me->SummonCreature(NPC_CRUCIBLE_OF_SOULS, 5672.29f, 2520.69f, 713.44f, 0.96f); - } - } - } - - void SpellHitTarget(Unit* target, SpellInfo const* spell) override - { - if (spell->Id == SPELL_PHANTOM_BLAST_H) - bAchiev = false; - else if (spell->Id == SPELL_WAILING_SOULS_TARGETING) - { - me->SetOrientation(me->GetAngle(target)); - me->SetControlled(true, UNIT_STATE_ROOT); - me->DisableRotate(true); - me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); - me->SetReactState(REACT_PASSIVE); - me->GetMotionMaster()->Clear(false); - me->GetMotionMaster()->MoveIdle(); - me->StopMovingOnCurrentPos(); - - me->SetFacingToObject(target); - me->SendMovementFlagUpdate(); - me->CastSpell(me, SPELL_WAILING_SOULS, false); - } - } - - bool CanAIAttack(Unit const* target) const override { return target->GetPositionZ() > 706.5f; } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - if (Spell* s = me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - if (s->m_spellInfo->Id == SPELL_MIRRORED_SOUL) - { - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_PHANTOM_BLAST: - me->CastSpell(me->GetVictim(), SPELL_PHANTOM_BLAST, false); - events.Repeat(5s); - break; - default: - events.Repeat(1s); - break; - } - - if (!me->GetCurrentSpell(CURRENT_GENERIC_SPELL)) - { - me->ClearUnitState(UNIT_STATE_CASTING); - DoMeleeAttackIfReady(); - me->AddUnitState(UNIT_STATE_CASTING); - } - - return; - } - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - switch (events.ExecuteEvent()) - { - case 0: - break; - case EVENT_SPELL_PHANTOM_BLAST: - me->CastSpell(me->GetVictim(), SPELL_PHANTOM_BLAST, false); - events.Repeat(5s); - break; - case EVENT_SPELL_MIRRORED_SOUL: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 90.0f, true)) - { - me->CastSpell(target, SPELL_MIRRORED_SOUL, false); - me->setAttackTimer(BASE_ATTACK, 2500); - Talk(EMOTE_MIRRORED_SOUL); - } - events.Repeat(20s, 30s); - break; - case EVENT_SPELL_WELL_OF_SOULS: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true)) - me->CastSpell(target, SPELL_WELL_OF_SOULS, false); - events.Repeat(25s, 30s); - events.DelayEventsToMax(4s, 0); - break; - case EVENT_SPELL_UNLEASHED_SOULS: - me->CastSpell(me, SPELL_UNLEASHED_SOULS, false); - Talk(SAY_FACE_UNLEASH_SOUL); - Talk(EMOTE_UNLEASH_SOUL); - events.Repeat(30s, 40s); - events.DelayEventsToMax(5s, 0); - me->setAttackTimer(BASE_ATTACK, 5500); - break; - case EVENT_SPELL_WAILING_SOULS: - Talk(SAY_FACE_WAILING_SOUL); - Talk(EMOTE_WAILING_SOUL); - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - me->CastCustomSpell(SPELL_WAILING_SOULS_TARGETING, SPELLVALUE_MAX_TARGETS, 1, target, false); - events.Repeat(80s); - events.DelayEventsToMax(20s, 0); - break; - } - - DoMeleeAttackIfReady(); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_FACE_DEATH); - summons.DespawnAll(); - if (pInstance) - pInstance->SetData(DATA_DEVOURER, DONE); - } - - void KilledUnit(Unit* victim) override - { - if (!victim->IsPlayer()) - return; - - int32 textId = 0; - switch (me->GetDisplayId()) - { - case DISPLAY_ANGER: - textId = SAY_FACE_ANGER_SLAY; - break; - case DISPLAY_SORROW: - textId = SAY_FACE_SORROW_SLAY; - break; - case DISPLAY_DESIRE: - textId = SAY_FACE_DESIRE_SLAY; - break; - default: - break; - } - - if (textId) - Talk(textId); - } - - void JustSummoned(Creature* summon) override - { - if (summon->GetEntry() != NPC_CRUCIBLE_OF_SOULS) - summons.Summon(summon); - - if (summon->GetEntry() == 36595) - if (Player* plr = summon->SelectNearestPlayer(100.0f)) - { - summon->AddThreat(plr, 100000.0f); - summon->AI()->AttackStart(plr); - } - } - - void EnterEvadeMode(EvadeReason why) override - { - me->SetControlled(false, UNIT_STATE_ROOT); - me->DisableRotate(false); - ScriptedAI::EnterEvadeMode(why); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + uint32 GetData(uint32 id) const override { - return GetForgeOfSoulsAI(creature); + if (id == 1) + return AchievementCompleted; + + return 0; + } + + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); + Talk(SAY_FACE_AGGRO); + events.RescheduleEvent(EVENT_SPELL_PHANTOM_BLAST, 5s); + events.RescheduleEvent(EVENT_SPELL_MIRRORED_SOUL, 9s); + events.RescheduleEvent(EVENT_SPELL_WELL_OF_SOULS, 6s, 8s); + events.RescheduleEvent(EVENT_SPELL_UNLEASHED_SOULS, 18s, 20s); + events.RescheduleEvent(EVENT_SPELL_WAILING_SOULS, 65s); + + // Support for Quest Tempering the Blade + me->GetMap()->DoForAllPlayers([this](Player* player) + { + if (me->FindNearestCreature(NPC_CRUCIBLE_OF_SOULS, 100.0f)) + return; + + uint32 questId = player->GetTeamId() == TEAM_ALLIANCE ? QUEST_TEMPERING_THE_BLADE_A : QUEST_TEMPERING_THE_BLADE_H; + if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) + me->SummonCreature(NPC_CRUCIBLE_OF_SOULS, 5672.29f, 2520.69f, 713.44f, 0.96f); + }); + } + + void SpellHitTarget(Unit* target, SpellInfo const* spell) override + { + if (spell->Id == SPELL_PHANTOM_BLAST_H) + AchievementCompleted = false; + else if (spell->Id == SPELL_WAILING_SOULS_TARGETING) + { + me->SetOrientation(me->GetAngle(target)); + me->SetControlled(true, UNIT_STATE_ROOT); + me->DisableRotate(true); + me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveIdle(); + me->StopMovingOnCurrentPos(); + + me->SetFacingToObject(target); + me->SendMovementFlagUpdate(); + DoCastSelf(SPELL_WAILING_SOULS); + } + } + + bool CanAIAttack(Unit const* target) const override { return target->GetPositionZ() > 706.5f; } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (Spell* s = me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + if (s->m_spellInfo->Id == SPELL_MIRRORED_SOUL) + { + switch (events.ExecuteEvent()) + { + case EVENT_SPELL_PHANTOM_BLAST: + DoCastVictim(SPELL_PHANTOM_BLAST); + events.Repeat(5s); + break; + default: + events.Repeat(1s); + break; + } + + if (!me->GetCurrentSpell(CURRENT_GENERIC_SPELL)) + { + me->ClearUnitState(UNIT_STATE_CASTING); + DoMeleeAttackIfReady(); + me->AddUnitState(UNIT_STATE_CASTING); + } + + return; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SPELL_PHANTOM_BLAST: + DoCastVictim(SPELL_PHANTOM_BLAST); + events.Repeat(5s); + break; + case EVENT_SPELL_MIRRORED_SOUL: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 90.0f, true)) + { + DoCast(target, SPELL_MIRRORED_SOUL); + me->setAttackTimer(BASE_ATTACK, 2500); + Talk(EMOTE_MIRRORED_SOUL); + } + events.Repeat(20s, 30s); + break; + case EVENT_SPELL_WELL_OF_SOULS: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true)) + DoCast(target, SPELL_WELL_OF_SOULS); + events.Repeat(25s, 30s); + events.DelayEventsToMax(4s, 0); + break; + case EVENT_SPELL_UNLEASHED_SOULS: + DoCastSelf(SPELL_UNLEASHED_SOULS); + Talk(SAY_FACE_UNLEASH_SOUL); + Talk(EMOTE_UNLEASH_SOUL); + events.Repeat(30s, 40s); + events.DelayEventsToMax(5s, 0); + me->setAttackTimer(BASE_ATTACK, 5500); + break; + case EVENT_SPELL_WAILING_SOULS: + Talk(SAY_FACE_WAILING_SOUL); + Talk(EMOTE_WAILING_SOUL); + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) + me->CastCustomSpell(SPELL_WAILING_SOULS_TARGETING, SPELLVALUE_MAX_TARGETS, 1, target); + events.Repeat(80s); + events.DelayEventsToMax(20s, 0); + break; + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* killer) override + { + BossAI::JustDied(killer); + Talk(SAY_FACE_DEATH); + } + + void KilledUnit(Unit* victim) override + { + if (!victim->IsPlayer()) + return; + + uint8 textId = 0; + switch (me->GetDisplayId()) + { + case MODEL_ANGER: + textId = SAY_FACE_ANGER_SLAY; + break; + case MODEL_SORROW: + textId = SAY_FACE_SORROW_SLAY; + break; + case MODEL_DESIRE: + textId = SAY_FACE_DESIRE_SLAY; + break; + default: + break; + } + + if (textId) + Talk(textId); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_CRUCIBLE_OF_SOULS) + BossAI::JustSummoned(summon); + + if (summon->GetEntry() == NPC_UNLEASHED_SOUL) + if (Player* player = summon->SelectNearestPlayer(100.0f)) + { + summon->AddThreat(player, 100000.0f); + summon->AI()->AttackStart(player); + } + } + + void EnterEvadeMode(EvadeReason why) override + { + me->SetControlled(false, UNIT_STATE_ROOT); + me->DisableRotate(false); + BossAI::EnterEvadeMode(why); } }; @@ -317,7 +286,7 @@ class spell_wailing_souls_periodic_aura : public AuraScript return ValidateSpellInfo({ SPELL_WAILING_SOULS_DMG_N }); } - int8 dir; + int8 dir = 0; bool Load() override { @@ -328,31 +297,30 @@ class spell_wailing_souls_periodic_aura : public AuraScript void HandlePeriodicTick(AuraEffect const* aurEff) { PreventDefaultAction(); - if (Unit* t = GetTarget()) + if (Unit* target = GetTarget()) { if (aurEff->GetTickNumber() < 30) { - // spinning, casting, etc. float diff = (2 * M_PI) / (4 * 30); - float new_o = t->GetOrientation() + diff * dir; - if (new_o >= 2 * M_PI) - new_o -= 2 * M_PI; - else if (new_o < 0) - new_o += 2 * M_PI; - t->UpdateOrientation(new_o); - t->SetFacingTo(new_o); - t->CastSpell(t, SPELL_WAILING_SOULS_DMG_N, true); + float newOrientation = target->GetOrientation() + diff * dir; + if (newOrientation >= 2 * M_PI) + newOrientation -= 2 * M_PI; + else if (newOrientation < 0) + newOrientation += 2 * M_PI; + target->UpdateOrientation(newOrientation); + target->SetFacingTo(newOrientation); + target->CastSpell(target, SPELL_WAILING_SOULS_DMG_N, true); } else if (aurEff->GetTickNumber() == 33) { - t->SetControlled(false, UNIT_STATE_ROOT); - t->DisableRotate(false); - if (t->IsCreature()) - t->ToCreature()->SetReactState(REACT_AGGRESSIVE); - if (t->GetVictim()) + target->SetControlled(false, UNIT_STATE_ROOT); + target->DisableRotate(false); + if (target->IsCreature()) + target->ToCreature()->SetReactState(REACT_AGGRESSIVE); + if (target->GetVictim()) { - t->SetGuidValue(UNIT_FIELD_TARGET, t->GetVictim()->GetGUID()); - t->GetMotionMaster()->MoveChase(t->GetVictim()); + target->SetGuidValue(UNIT_FIELD_TARGET, target->GetVictim()->GetGUID()); + target->GetMotionMaster()->MoveChase(target->GetVictim()); } } else if (aurEff->GetTickNumber() >= 34) @@ -368,6 +336,6 @@ class spell_wailing_souls_periodic_aura : public AuraScript void AddSC_boss_devourer_of_souls() { - new boss_devourer_of_souls(); + RegisterForgeOfSoulsCreatureAI(boss_devourer_of_souls); RegisterSpellScript(spell_wailing_souls_periodic_aura); } diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h index e8ec81c40..117b04719 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/forge_of_souls.h @@ -30,6 +30,11 @@ enum Data DATA_BRONJAHM, DATA_DEVOURER, MAX_ENCOUNTER, + + DATA_LEADER_FIRST, + DATA_LEADER_SECOND, + DATA_GUARD_FIRST, + DATA_GUARD_SECOND, }; enum Creatures @@ -99,4 +104,6 @@ inline AI* GetForgeOfSoulsAI(T* obj) return GetInstanceAI(obj, ForgeOfSoulsScriptName); } +#define RegisterForgeOfSoulsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetForgeOfSoulsAI) + #endif diff --git a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp index 4646d90ae..e77fcda11 100644 --- a/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/ForgeOfSouls/instance_forge_of_souls.cpp @@ -21,12 +21,29 @@ #include "forge_of_souls.h" #include "Group.h" +enum Misc +{ + NPC_CORRUPTED_SOUL_FRAGMENT = 36535, + + ACHIEV_CRITERIA_SOUL_POWER = 12752, + ACHIEV_CRITERIA_THREE_FACED = 12976, + + SOUL_POWER_FRAGMENT_COUNT = 4, +}; + BossBoundaryData const boundaries = { { DATA_BRONJAHM, new CircleBoundary(Position(5297.3f, 2506.45f), 100.96) }, { DATA_DEVOURER, new ParallelogramBoundary(Position(5663.56f, 2570.53f), Position(5724.39f, 2520.45f), Position(5570.36f, 2461.42f)) } }; +static ObjectData const creatureData[] = +{ + { NPC_BRONJAHM, DATA_BRONJAHM }, + { NPC_DEVOURER, DATA_DEVOURER }, + { 0, 0 } +}; + class instance_forge_of_souls : public InstanceMapScript { public: @@ -42,38 +59,22 @@ public: instance_forge_of_souls_InstanceScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTER); + LoadObjectData(creatureData, nullptr); LoadBossBoundaries(boundaries); } - uint32 m_auiEncounter[MAX_ENCOUNTER]; - std::string str_data; - ObjectGuid NPC_BronjahmGUID; - ObjectGuid NPC_DevourerGUID; - - ObjectGuid NPC_LeaderFirstGUID; - ObjectGuid NPC_LeaderSecondGUID; - ObjectGuid NPC_GuardFirstGUID; - ObjectGuid NPC_GuardSecondGUID; - - void Initialize() override - { - memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); - } - - bool IsEncounterInProgress() const override - { - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (m_auiEncounter[i] == IN_PROGRESS) return true; - - return false; - } + ObjectGuid LeaderFirstGUID; + ObjectGuid LeaderSecondGUID; + ObjectGuid GuardFirstGUID; + ObjectGuid GuardSecondGUID; void OnPlayerEnter(Player* player) override { InstanceScript::OnPlayerEnter(player); // this will happen only after crash and loading the instance from db - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE && (!NPC_LeaderSecondGUID || !instance->GetCreature(NPC_LeaderSecondGUID))) + if (AllBossesDone() && (!LeaderSecondGUID || !instance->GetCreature(LeaderSecondGUID))) { Position pos = {5658.15f, 2502.564f, 708.83f, 0.885207f}; instance->SummonCreature(NPC_SYLVANAS_PART2, pos); @@ -82,44 +83,40 @@ public: void OnCreatureCreate(Creature* creature) override { + InstanceScript::OnCreatureCreate(creature); + switch (creature->GetEntry()) { - case NPC_BRONJAHM: - NPC_BronjahmGUID = creature->GetGUID(); - break; - case NPC_DEVOURER: - NPC_DevourerGUID = creature->GetGUID(); - break; case NPC_SYLVANAS_PART1: if (GetTeamIdInInstance() == TEAM_ALLIANCE) creature->UpdateEntry(NPC_JAINA_PART1); - NPC_LeaderFirstGUID = creature->GetGUID(); + LeaderFirstGUID = creature->GetGUID(); - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE) + if (AllBossesDone()) creature->SetVisible(false); break; case NPC_SYLVANAS_PART2: if (GetTeamIdInInstance() == TEAM_ALLIANCE) creature->UpdateEntry(NPC_JAINA_PART2); - NPC_LeaderSecondGUID = creature->GetGUID(); + LeaderSecondGUID = creature->GetGUID(); break; case NPC_LORALEN: if (GetTeamIdInInstance() == TEAM_ALLIANCE) creature->UpdateEntry(NPC_ELANDRA); - if (!NPC_GuardFirstGUID) + if (!GuardFirstGUID) { - NPC_GuardFirstGUID = creature->GetGUID(); - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE) + GuardFirstGUID = creature->GetGUID(); + if (AllBossesDone()) creature->SetVisible(false); } break; case NPC_KALIRA: if (GetTeamIdInInstance() == TEAM_ALLIANCE) creature->UpdateEntry(NPC_KORELN); - if (!NPC_GuardSecondGUID) + if (!GuardSecondGUID) { - NPC_GuardSecondGUID = creature->GetGUID(); - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE) + GuardSecondGUID = creature->GetGUID(); + if (AllBossesDone()) creature->SetVisible(false); } break; @@ -128,9 +125,9 @@ public: void HandleOutro() { - if (!NPC_LeaderSecondGUID || !instance->GetCreature(NPC_LeaderSecondGUID)) + if (!LeaderSecondGUID || !instance->GetCreature(LeaderSecondGUID)) if (Creature* leader = instance->SummonCreature(NPC_SYLVANAS_PART2, outroSpawnPoint)) - if (Creature* boss = instance->GetCreature(NPC_DevourerGUID)) + if (Creature* boss = GetCreature(DATA_DEVOURER)) { float angle = boss->GetAngle(leader); leader->GetMotionMaster()->MovePoint(1, boss->GetPositionX() + 10.0f * cos(angle), boss->GetPositionY() + 10.0f * std::sin(angle), boss->GetPositionZ()); @@ -144,69 +141,37 @@ public: } } - void SetData(uint32 type, uint32 data) override + bool SetBossState(uint32 type, EncounterState state) override { - switch (type) - { - case DATA_BRONJAHM: - m_auiEncounter[type] = data; - break; - case DATA_DEVOURER: - m_auiEncounter[type] = data; - if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE) - HandleOutro(); - break; - } + if (!InstanceScript::SetBossState(type, state)) + return false; - if (data == DONE) - SaveToDB(); - } + if (state == DONE && AllBossesDone()) + HandleOutro(); - ObjectGuid GetGuidData(uint32 type) const override - { - switch (type) - { - case DATA_BRONJAHM: - return NPC_BronjahmGUID; - } - - return ObjectGuid::Empty; + return true; } bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override { switch (criteria_id) { - case 12752: // Soul Power - if (Creature* c = instance->GetCreature(NPC_BronjahmGUID)) + case ACHIEV_CRITERIA_SOUL_POWER: + if (Creature* bronjahm = GetCreature(DATA_BRONJAHM)) { - std::list L; - uint8 count = 0; - c->GetCreaturesWithEntryInRange(L, 200.0f, 36535); // find all Corrupted Soul Fragment (36535) - for( std::list::const_iterator itr = L.begin(); itr != L.end(); ++itr ) - if ((*itr)->IsAlive()) - ++count; - return (count >= 4); + std::list fragments; + bronjahm->GetCreaturesWithEntryInRange(fragments, 200.0f, NPC_CORRUPTED_SOUL_FRAGMENT); + return std::count_if(fragments.begin(), fragments.end(), + [](Creature const* fragment) { return fragment->IsAlive(); }) >= SOUL_POWER_FRAGMENT_COUNT; } break; - case 12976: - if (Creature* c = instance->GetCreature(NPC_DevourerGUID)) - return (bool)c->AI()->GetData(1); + case ACHIEV_CRITERIA_THREE_FACED: + if (Creature* devourer = GetCreature(DATA_DEVOURER)) + return devourer->AI()->GetData(1) != 0; break; } return false; } - - void ReadSaveDataMore(std::istringstream& data) override - { - data >> m_auiEncounter[0]; - data >> m_auiEncounter[1]; - } - - void WriteSaveDataMore(std::ostringstream& data) override - { - data << m_auiEncounter[0] << ' ' << m_auiEncounter[1]; - } }; };