diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index fc562f39b..2256c4e12 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -688,14 +688,14 @@ public: if (_instance->GetBossState(DATA_ICECROWN_GUNSHIP_BATTLE) != IN_PROGRESS) return; + // Blizzlike: ship wipes when all players are in cannons (vehicles) with nobody on deck + // See: azerothcore/azerothcore-wotlk#17856 bool playerOnDeck = false; me->GetMap()->DoForAllPlayers([&](Player* player) { if (!player->GetVehicle() && player->IsAlive()) playerOnDeck = true; }); - - // Wipe if no player is on the deck if (!playerOnDeck) { // Script runs on enemy ship. We want to kill our ship. diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp index 346997c48..b27e9008b 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_the_lich_king.cpp @@ -653,6 +653,8 @@ public: _lastTalkTimeBuff = 0; _bFrostmournePhase = false; _bFordringMustFallYell = false; + me->SetRegeneratingHealth(true); + me->SetIsCombatDisallowed(false); _Reset(); DoAction(ACTION_RESTORE_LIGHT); @@ -792,12 +794,15 @@ public: if (_phase == PHASE_THREE && HealthBelowPct(10) && !me->HasUnitState(UNIT_STATE_CASTING)) { _phase = PHASE_OUTRO; + me->SetRegeneratingHealth(false); + me->SetIsCombatDisallowed(true); EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); summons.DoAction(ACTION_TELEPORT_BACK, pred); events.Reset(); summons.DespawnAll(); me->SetReactState(REACT_PASSIVE); me->AttackStop(); + me->CombatStop(true); me->GetMap()->SetZoneMusic(AREA_THE_FROZEN_THRONE, MUSIC_FURY_OF_FROSTMOURNE); me->InterruptNonMeleeSpells(true); me->CastSpell((Unit*)nullptr, SPELL_FURY_OF_FROSTMOURNE, false); @@ -1253,6 +1258,9 @@ public: void EnterEvadeMode(EvadeReason why) override { + if (_phase == PHASE_OUTRO || _phase == PHASE_FROSTMOURNE) + return; + EntryCheckPredicate pred(NPC_STRANGULATE_VEHICLE); summons.DoAction(ACTION_TELEPORT_BACK, pred); instance->SetBossState(DATA_THE_LICH_KING, FAIL); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp index d700cb08c..6d497061c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -508,31 +508,26 @@ public: void Reset() override { - events.Reset(); - summons.DespawnAll(); - if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != DONE) - instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, NOT_STARTED); + _Reset(); me->SetReactState(REACT_PASSIVE); - checkTimer = 5000; } - void JustEngagedWith(Unit* target) override + void JustEnteredCombat(Unit* target) override { + if (IsEngaged()) + return; + if (!instance->CheckRequiredBosses(DATA_VALITHRIA_DREAMWALKER, target->ToPlayer())) { - me->setActive(true); - EnterEvadeMode(); + EnterEvadeMode(EVADE_REASON_SEQUENCE_BREAK); instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT); return; } - if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) == DONE) - { - me->CombatStop(); - return; - } + + EngagementStart(target); me->setActive(true); - me->SetInCombatWithZone(); + DoZoneInCombat(); instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, IN_PROGRESS); if (Creature* valithria = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VALITHRIA_DREAMWALKER))) valithria->AI()->DoAction(ACTION_ENTER_COMBAT); @@ -547,17 +542,6 @@ public: (*itr)->AI()->DoAction(ACTION_ENTER_COMBAT); } - void AttackStart(Unit* target) override - { - if (target->IsPlayer()) - BossAI::AttackStart(target); - } - - void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER) override - { - CreatureAI::EnterEvadeMode(why); - } - void MoveInLineOfSight(Unit* /*who*/) override {} bool CanAIAttack(Unit const* target) const override @@ -565,48 +549,27 @@ public: return target->IsPlayer(); } - void JustReachedHome() override + void JustExitedCombat() override { - if (instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != DONE) - DoAction(ACTION_DEATH); // setActive(false) in ValithriaDespawner - else - _JustReachedHome(); + EngagementOver(); + + me->setActive(false); + + if (!me->IsAlive()) + return; + DoAction(ACTION_DEATH); } void DoAction(int32 action) override { if (action == ACTION_DEATH) + { + instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, NOT_STARTED); me->m_Events.AddEventAtOffset(new ValithriaDespawner(me), 5s); - else if (action == ACTION_ENTER_COMBAT) - { - if (!me->IsInCombat()) - me->SetInCombatWithZone(); + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VALITHRIA_LICH_KING))) + lichKing->AI()->EnterEvadeMode(); } } - - void UpdateAI(uint32 diff) override - { - if (!me->IsInCombat()) - return; - - if (checkTimer <= diff) - { - checkTimer = 3000; - me->SetInCombatWithZone(); - for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList()) - { - if (Unit* target = ref->GetVictim()) - if (target->IsAlive() && target->IsPlayer() && me->GetExactDist(target) < 200.0f && !target->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_ALL)) - return; - } - EnterEvadeMode(); - } - else - checkTimer -= diff; - } - - private: - uint16 checkTimer; }; CreatureAI* GetAI(Creature* creature) const override @@ -712,7 +675,7 @@ public: struct npc_risen_archmageAI : public ScriptedAI { npc_risen_archmageAI(Creature* creature) : ScriptedAI(creature), - _instance(creature->GetInstanceScript()) + _instance(creature->GetInstanceScript()), _isInitialArchmage(false) { } @@ -725,23 +688,34 @@ public: { _events.Reset(); _events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5s, 15s); - _events.ScheduleEvent(EVENT_MANA_VOID, 15s, 25s); + _events.ScheduleEvent(EVENT_MANA_VOID, 20s, 25s); _events.ScheduleEvent(EVENT_COLUMN_OF_FROST, 10s, 20s); + _isInitialArchmage = me->GetSpawnId() != 0; } - void JustEngagedWith(Unit* /*target*/) override + void JustEnteredCombat(Unit* who) override { - me->FinishSpell(CURRENT_CHANNELED_SPELL, false); - me->SetInCombatWithZone(); - if (me->GetSpawnId()) + if (IsEngaged()) + return; + + me->InterruptNonMeleeSpells(false); + + EngagementStart(who); + + if (_isInitialArchmage) + { + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_LICH_KING))) + DoZoneInCombat(lichKing); + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_VALITHRIA_TRIGGER))) - trigger->AI()->DoAction(ACTION_ENTER_COMBAT); + DoZoneInCombat(trigger); + } } void DoAction(int32 action) override { - if (action == ACTION_ENTER_COMBAT && !me->IsInCombat()) - me->SetInCombatWithZone(); + if (action == ACTION_ENTER_COMBAT) + DoZoneInCombat(); } void JustSummoned(Creature* summon) override @@ -754,10 +728,8 @@ public: void UpdateAI(uint32 diff) override { - if (!me->IsInCombat()) - if (me->GetSpawnId()) - if (!me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - me->CastSpell(me, SPELL_CORRUPTION, true); + if (!me->IsInCombat() && me->IsAlive() && _isInitialArchmage && !me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + DoCastSelf(SPELL_CORRUPTION); if (!UpdateVictim()) return; @@ -796,6 +768,7 @@ public: private: EventMap _events; InstanceScript* _instance; + bool _isInitialArchmage; }; CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 77f6c7069..f471555c4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -345,11 +345,17 @@ public: return; } + uint32 corpseDelay = creature->GetCorpseDelay(); + uint32 respawnDelay = creature->GetRespawnDelay(); + creature->SetCorpseDelay(1); + creature->SetRespawnDelay(2); + if (CreatureData const* data = creature->GetCreatureData()) creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); creature->DespawnOrUnsummon(); - creature->SetRespawnTime(5); + creature->SetCorpseDelay(corpseDelay); + creature->SetRespawnDelay(respawnDelay); } }; @@ -730,7 +736,7 @@ public: { me->SetReactState(REACT_DEFENSIVE); _didUnderTenPercentText = false; - _wipeCheckTimer = 3000; + _wipeCheckTimer = 1000; _handledWP4 = false; _events.Reset(); @@ -868,6 +874,27 @@ public: void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override { + if (!_wipeCheckTimer) + { + _wipeCheckTimer = 1000; + Player* player = nullptr; + Acore::AnyPlayerInObjectRangeCheck check(me, 60.0f); + Acore::PlayerSearcher searcher(me, player, check); + Cell::VisitObjects(me, searcher, 60.0f); + // wipe + if (!player) + { + damage *= 100; + if (damage >= me->GetHealth()) + { + FrostwingGauntletRespawner respawner; + Acore::CreatureWorker worker(me, respawner); + Cell::VisitObjects(me, worker, 333.0f); + return; + } + } + } + if (HealthBelowPct(10)) { if (!_didUnderTenPercentText) @@ -885,37 +912,21 @@ public: } } - void UpdateEscortAI(uint32 /*diff*/) override {} + void UpdateEscortAI(uint32 diff) override + { + if (_wipeCheckTimer <= diff) + _wipeCheckTimer = 0; + else + _wipeCheckTimer -= diff; + } void UpdateAI(uint32 diff) override { npc_escortAI::UpdateAI(diff); - //Position pos = me->GetHomePosition(); - if (!me->isActiveObject()/* && me->GetExactDist(&pos) < 5.0f*/) // during event + if (!me->isActiveObject()) return; - if (_wipeCheckTimer <= diff) - { - _wipeCheckTimer = 3000; - - Player* player = nullptr; - Acore::AnyPlayerInObjectRangeCheck check(me, 140.0f); - Acore::PlayerSearcher searcher(me, player, check); - Cell::VisitObjects(me, searcher, 140.0f); - // wipe - if (!player || me->GetExactDist(4357.0f, 2606.0f, 350.0f) > 125.0f) - { - //Talk(SAY_CROK_DEATH); - FrostwingGauntletRespawner respawner; - Acore::CreatureWorker worker(me, respawner); - Cell::VisitObjects(me, worker, 333.0f); - return; - } - } - else - _wipeCheckTimer -= diff; - UpdateVictim(); _events.Update(diff); @@ -968,7 +979,7 @@ public: bool CanAIAttack(Unit const* target) const override { // do not see targets inside Frostwing Halls when we are not there - return !target->IsPlayer() && (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f) && target->GetEntry() != NPC_SINDRAGOSA; + return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f); } private: @@ -995,18 +1006,30 @@ public: struct boss_sister_svalnaAI : public BossAI { - boss_sister_svalnaAI(Creature* creature) : BossAI(creature, DATA_SISTER_SVALNA) + boss_sister_svalnaAI(Creature* creature) : BossAI(creature, DATA_SISTER_SVALNA), + _isEventInProgress(false) { } + void InitializeAI() override + { + if (!me->isDead()) + Reset(); + me->SetReactState(REACT_PASSIVE); + } + void Reset() override { _Reset(); - me->SetImmuneToAll(true); + me->SetReactState(REACT_DEFENSIVE); + _isEventInProgress = false; + } + + void JustReachedHome() override + { + _JustReachedHome(); me->SetReactState(REACT_PASSIVE); - me->SetCanFly(true); - me->SetDisableGravity(true); - me->SendMovementFlagUpdate(); + me->SetDisableGravity(false); } void JustDied(Unit* /*killer*/) override @@ -1080,6 +1103,8 @@ public: break; case ACTION_START_GAUNTLET: me->setActive(true); + me->SetImmuneToAll(true); + _isEventInProgress = true; events.ScheduleEvent(EVENT_SVALNA_START, 25s); break; case ACTION_RESURRECT_CAPTAINS: @@ -1106,16 +1131,21 @@ public: } } + void JustExitedCombat() override + { + if (_isEventInProgress) + return; + CreatureAI::JustExitedCombat(); + } + void MovementInform(uint32 type, uint32 id) override { if (type != EFFECT_MOTION_TYPE || id != POINT_LAND) return; - + _isEventInProgress = false; + me->setActive(false); me->SetImmuneToAll(false); - me->SetCanFly(false); me->SetDisableGravity(false); - me->SetReactState(REACT_AGGRESSIVE); - DoZoneInCombat(nullptr, 150.0f); } void SpellHitTarget(Unit* target, SpellInfo const* spell) override @@ -1140,43 +1170,51 @@ public: void UpdateAI(uint32 diff) override { - if (!me->isActiveObject()) + if (!UpdateVictim() && !_isEventInProgress) return; - UpdateVictim(); - events.Update(diff); if (me->HasUnitState(UNIT_STATE_CASTING)) return; - switch (events.ExecuteEvent()) + while (uint32 eventId = events.ExecuteEvent()) { - case EVENT_SVALNA_START: - Talk(SAY_SVALNA_EVENT_START); - break; - case EVENT_SVALNA_RESURRECT: - Talk(SAY_SVALNA_RESURRECT_CAPTAINS); - me->CastSpell(me, SPELL_REVIVE_CHAMPION, false); - break; - case EVENT_SVALNA_COMBAT: - Talk(SAY_SVALNA_AGGRO); - break; - case EVENT_IMPALING_SPEAR: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false, -SPELL_IMPALING_SPEAR)) - { - DoCast(me, SPELL_AETHER_SHIELD); - me->AddAura(70203, me); - DoCast(target, SPELL_IMPALING_SPEAR); - } - events.ScheduleEvent(EVENT_IMPALING_SPEAR, 20s, 25s); - break; - default: - break; + switch (eventId) + { + case EVENT_SVALNA_START: + Talk(SAY_SVALNA_EVENT_START); + break; + case EVENT_SVALNA_RESURRECT: + Talk(SAY_SVALNA_RESURRECT_CAPTAINS); + me->CastSpell(me, SPELL_REVIVE_CHAMPION, false); + break; + case EVENT_SVALNA_COMBAT: + me->SetReactState(REACT_DEFENSIVE); + Talk(SAY_SVALNA_AGGRO); + break; + case EVENT_IMPALING_SPEAR: + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false, -SPELL_IMPALING_SPEAR)) + { + DoCast(me, SPELL_AETHER_SHIELD); + me->AddAura(70203, me); + DoCast(target, SPELL_IMPALING_SPEAR); + } + events.ScheduleEvent(EVENT_IMPALING_SPEAR, 20s, 25s); + break; + default: + break; + } + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } DoMeleeAttackIfReady(); } + + private: + bool _isEventInProgress; }; CreatureAI* GetAI(Creature* creature) const override