diff --git a/data/sql/updates/pending_db_world/rev_1763231123319424800.sql b/data/sql/updates/pending_db_world/rev_1763231123319424800.sql new file mode 100644 index 000000000..c9ea39499 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1763231123319424800.sql @@ -0,0 +1,2 @@ +DELETE FROM `smart_scripts` WHERE `entryorguid` = 27598 AND `source_type` = 0; +UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 27598; diff --git a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp index bf87541ef..277e95104 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/boss_novos.cpp @@ -77,198 +77,216 @@ std::unordered_map> const npcSummon = { ROOM_STAIRS, { NPC_CRYSTAL_CHANNEL_TARGET, { -378.40f, -813.13f, 59.74f, 0.0f } } }, }; -class boss_novos : public CreatureScript +// 26631 +struct boss_novos : public BossAI { -public: - boss_novos() : CreatureScript("boss_novos") { } - - struct boss_novosAI : public BossAI + boss_novos(Creature* creature) : BossAI(creature, DATA_NOVOS) { - boss_novosAI(Creature* creature) : BossAI(creature, DATA_NOVOS) - { - } - - void Reset() override - { - BossAI::Reset(); - instance->SetBossState(DATA_NOVOS_CRYSTALS, IN_PROGRESS); - instance->SetBossState(DATA_NOVOS_CRYSTALS, NOT_STARTED); - _crystalCounter = 0; - _summonTargetRightGUID.Clear(); - _summonTargetLeftGUID.Clear(); - _stage = 0; - - me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - - _achievement = true; - } - - uint32 GetData(uint32 data) const override - { - if (data == me->GetEntry()) - return uint32(_achievement); - return 0; - } - - void SetData(uint32 type, uint32) override - { - if (type == me->GetEntry()) - _achievement = false; - } - - void MoveInLineOfSight(Unit* /*who*/) override { } - - void JustEngagedWith(Unit* who) override - { - Talk(SAY_AGGRO); - BossAI::JustEngagedWith(who); - - events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s); - events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 9s); - events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s); - events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s); - events.ScheduleEvent(EVENT_CHECK_PHASE, 80s); - - me->CastSpell(me, SPELL_ARCANE_BLAST, true); - me->CastSpell(me, SPELL_ARCANE_FIELD, true); - me->CastSpell(me, SPELL_DESPAWN_CRYSTAL_HANDLER, true); - - for (auto& itr : npcSummon) - { - uint32 summonEntry; - Position summonPos; - std::tie(summonEntry, summonPos) = itr.second; - if (Creature* creature = me->SummonCreature(summonEntry, summonPos)) - switch (itr.first) - { - case ROOM_LEFT: - _summonTargetLeftGUID = creature->GetGUID(); - break; - case ROOM_RIGHT: - _summonTargetRightGUID = creature->GetGUID(); - break; - } - } - - me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); - me->RemoveAllAuras(); - me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - } - - void JustDied(Unit* killer) override - { - Talk(SAY_DEATH); - BossAI::JustDied(killer); - instance->SetBossState(DATA_NOVOS_CRYSTALS, DONE); - } - - void KilledUnit(Unit* /*victim*/) override - { - if (!events.HasTimeUntilEvent(EVENT_KILL_TALK)) - { - Talk(SAY_KILL); - events.ScheduleEvent(EVENT_KILL_TALK, 6s); - } - } - - void JustSummoned(Creature* summon) override - { - summons.Summon(summon); - if (me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) && summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET && summon->GetEntry() != NPC_CRYSTAL_HANDLER) - summon->SetReactState(REACT_DEFENSIVE); - else if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET) - summon->SetInCombatWithZone(); - } - - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - switch (events.ExecuteEvent()) - { - case EVENT_SUMMON_FETID_TROLL: - if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) - trigger->CastSpell(trigger, SPELL_SUMMON_FETID_TROLL_CORPSE, true, nullptr, nullptr, me->GetGUID()); - events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s); - break; - case EVENT_SUMMON_HULKING_CORPSE: - if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) - trigger->CastSpell(trigger, SPELL_SUMMON_HULKING_CORPSE, true, nullptr, nullptr, me->GetGUID()); - events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s); - break; - case EVENT_SUMMON_SHADOWCASTER: - if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) - trigger->CastSpell(trigger, SPELL_SUMMON_RISEN_SHADOWCASTER, true, nullptr, nullptr, me->GetGUID()); - events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 10s); - break; - case EVENT_SUMMON_CRYSTAL_HANDLER: - if (_crystalCounter++ < 4) - { - Talk(SAY_SUMMONING_ADDS); - Talk(EMOTE_SUMMONING_ADDS); - if (Creature* target = ObjectAccessor::GetCreature(*me, _stage ? _summonTargetLeftGUID : _summonTargetRightGUID)) - target->CastSpell(target, SPELL_SUMMON_CRYSTAL_HANDLER, true, nullptr, nullptr, me->GetGUID()); - _stage = _stage ? 0 : 1; - events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s); - } - break; - case EVENT_CHECK_PHASE: - if (me->HasAura(SPELL_BEAM_CHANNEL)) - { - events.ScheduleEvent(EVENT_CHECK_PHASE, 2s); - break; - } - events.Reset(); - events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 3s); - events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 10s); - me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); - me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); - me->InterruptNonMeleeSpells(false); - break; - case EVENT_CAST_OFFENSIVE_SPELL: - if (!me->HasUnitState(UNIT_STATE_CASTING)) - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) - me->CastSpell(target, RAND(SPELL_BLIZZARD, SPELL_FROSTBOLT, SPELL_TOUCH_OF_MISERY), false); - - events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 500ms); - break; - case EVENT_SPELL_SUMMON_MINIONS: - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - me->CastSpell(me, SPELL_SUMMON_MINIONS, false); - events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 15s); - break; - } - events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 500ms); - break; - } - } - - bool CheckEvadeIfOutOfCombatArea() const override - { - return !SelectTargetFromPlayerList(80.0f); - } - - private: - uint8 _crystalCounter; - uint8 _stage; - ObjectGuid _summonTargetRightGUID; - ObjectGuid _summonTargetLeftGUID; - - bool _achievement; - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetDraktharonKeepAI(creature); } + + void Reset() override + { + BossAI::Reset(); + instance->SetBossState(DATA_NOVOS_CRYSTALS, IN_PROGRESS); + instance->SetBossState(DATA_NOVOS_CRYSTALS, NOT_STARTED); + _crystalCounter = 0; + _summonTargetRightGUID.Clear(); + _summonTargetLeftGUID.Clear(); + _stage = 0; + + me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + + _achievement = true; + } + + uint32 GetData(uint32 data) const override + { + if (data == me->GetEntry()) + return uint32(_achievement); + return 0; + } + + void SetData(uint32 type, uint32) override + { + if (type == me->GetEntry()) + _achievement = false; + } + + void MoveInLineOfSight(Unit* /*who*/) override { } + + void JustEngagedWith(Unit* who) override + { + Talk(SAY_AGGRO); + BossAI::JustEngagedWith(who); + + events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s); + events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 9s); + events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s); + events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s); + events.ScheduleEvent(EVENT_CHECK_PHASE, 80s); + + me->CastSpell(me, SPELL_ARCANE_BLAST, true); + me->CastSpell(me, SPELL_ARCANE_FIELD, true); + me->CastSpell(me, SPELL_DESPAWN_CRYSTAL_HANDLER, true); + + for (auto& itr : npcSummon) + { + uint32 summonEntry; + Position summonPos; + std::tie(summonEntry, summonPos) = itr.second; + if (Creature* creature = me->SummonCreature(summonEntry, summonPos)) + switch (itr.first) + { + case ROOM_LEFT: + _summonTargetLeftGUID = creature->GetGUID(); + break; + case ROOM_RIGHT: + _summonTargetRightGUID = creature->GetGUID(); + break; + } + } + + me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty); + me->RemoveAllAuras(); + me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + } + + void JustDied(Unit* killer) override + { + Talk(SAY_DEATH); + BossAI::JustDied(killer); + instance->SetBossState(DATA_NOVOS_CRYSTALS, DONE); + } + + void KilledUnit(Unit* /*victim*/) override + { + if (!events.HasTimeUntilEvent(EVENT_KILL_TALK)) + { + Talk(SAY_KILL); + events.ScheduleEvent(EVENT_KILL_TALK, 6s); + } + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + + // Phase 1 + if (me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) + { + if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET && summon->GetEntry() != NPC_CRYSTAL_HANDLER) + summon->SetReactState(REACT_DEFENSIVE); + + if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE) + summon->GetMotionMaster()->MovePoint(1, -373.56f, -770.86f, 28.59f); + } + // Phase 2 + else if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET) + summon->SetInCombatWithZone(); + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE) + summon->DespawnOrUnsummon(10s); + } + + void SummonMovementInform(Creature* summon, uint32 movementType, uint32 pathId) override + { + if (movementType == POINT_MOTION_TYPE && pathId == 1) + { + if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE) + { + DoZoneInCombat(summon); + _achievement = false; + } + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + switch (events.ExecuteEvent()) + { + case EVENT_SUMMON_FETID_TROLL: + if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) + trigger->CastSpell(trigger, SPELL_SUMMON_FETID_TROLL_CORPSE, true, nullptr, nullptr, me->GetGUID()); + events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s); + break; + case EVENT_SUMMON_HULKING_CORPSE: + if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) + trigger->CastSpell(trigger, SPELL_SUMMON_HULKING_CORPSE, true, nullptr, nullptr, me->GetGUID()); + events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s); + break; + case EVENT_SUMMON_SHADOWCASTER: + if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET)) + trigger->CastSpell(trigger, SPELL_SUMMON_RISEN_SHADOWCASTER, true, nullptr, nullptr, me->GetGUID()); + events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 10s); + break; + case EVENT_SUMMON_CRYSTAL_HANDLER: + if (_crystalCounter++ < 4) + { + Talk(SAY_SUMMONING_ADDS); + Talk(EMOTE_SUMMONING_ADDS); + if (Creature* target = ObjectAccessor::GetCreature(*me, _stage ? _summonTargetLeftGUID : _summonTargetRightGUID)) + target->CastSpell(target, SPELL_SUMMON_CRYSTAL_HANDLER, true, nullptr, nullptr, me->GetGUID()); + _stage = _stage ? 0 : 1; + events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s); + } + break; + case EVENT_CHECK_PHASE: + if (me->HasAura(SPELL_BEAM_CHANNEL)) + { + events.ScheduleEvent(EVENT_CHECK_PHASE, 2s); + break; + } + events.Reset(); + events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 3s); + events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 10s); + me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE); + me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE); + me->InterruptNonMeleeSpells(false); + break; + case EVENT_CAST_OFFENSIVE_SPELL: + if (!me->HasUnitState(UNIT_STATE_CASTING)) + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true)) + me->CastSpell(target, RAND(SPELL_BLIZZARD, SPELL_FROSTBOLT, SPELL_TOUCH_OF_MISERY), false); + + events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 500ms); + break; + case EVENT_SPELL_SUMMON_MINIONS: + if (me->HasUnitState(UNIT_STATE_CASTING)) + { + me->CastSpell(me, SPELL_SUMMON_MINIONS, false); + events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 15s); + break; + } + events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 500ms); + break; + } + } + + bool CheckEvadeIfOutOfCombatArea() const override + { + return !SelectTargetFromPlayerList(80.0f); + } + +private: + uint8 _crystalCounter; + uint8 _stage; + ObjectGuid _summonTargetRightGUID; + ObjectGuid _summonTargetLeftGUID; + + bool _achievement; }; +// 51403 class spell_novos_despawn_crystal_handler : public SpellScript { PrepareSpellScript(spell_novos_despawn_crystal_handler); @@ -290,6 +308,7 @@ class spell_novos_despawn_crystal_handler : public SpellScript } }; +// 47336 class spell_novos_crystal_handler_death_aura : public AuraScript { PrepareAuraScript(spell_novos_crystal_handler_death_aura); @@ -307,6 +326,7 @@ class spell_novos_crystal_handler_death_aura : public AuraScript } }; +// 59910 class spell_novos_summon_minions : public SpellScript { PrepareSpellScript(spell_novos_summon_minions); @@ -328,6 +348,7 @@ class spell_novos_summon_minions : public SpellScript } }; +// 2057 class achievement_oh_novos : public AchievementCriteriaScript { public: @@ -341,7 +362,7 @@ public: void AddSC_boss_novos() { - new boss_novos(); + RegisterCreatureAIWithFactory(boss_novos, GetDraktharonKeepAI); RegisterSpellScript(spell_novos_despawn_crystal_handler); RegisterSpellScript(spell_novos_crystal_handler_death_aura); RegisterSpellScript(spell_novos_summon_minions); diff --git a/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h b/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h index e8f2722d0..dceeeafd8 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h +++ b/src/server/scripts/Northrend/DraktharonKeep/drak_tharon_keep.h @@ -39,6 +39,7 @@ enum Creatures NPC_KURZEL = 26664, NPC_DRAKKARI_GUARDIAN = 26620, NPC_RISEN_DRAKKARI_WARRIOR = 26635, + NPC_FETID_TROLL_CORPSE = 27598, }; enum GameObjects diff --git a/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp b/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp index 50be90a84..9547a1d69 100644 --- a/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp +++ b/src/server/scripts/Northrend/DraktharonKeep/instance_drak_tharon_keep.cpp @@ -31,50 +31,39 @@ DoorData const doorData[] = { 0, 0, DOOR_TYPE_ROOM } }; -class instance_drak_tharon_keep : public InstanceMapScript +struct instance_drak_tharon_keep : public InstanceScript { -public: - instance_drak_tharon_keep() : InstanceMapScript("instance_drak_tharon_keep", MAP_DRAK_THARON_KEEP) { } - - struct instance_drak_tharon_keep_InstanceScript : public InstanceScript + instance_drak_tharon_keep(Map* map) : InstanceScript(map) { - instance_drak_tharon_keep_InstanceScript(Map* map) : InstanceScript(map) - { - SetHeaders(DataHeader); - SetBossNumber(MAX_ENCOUNTERS); - LoadDoorData(doorData); - } + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTERS); + LoadDoorData(doorData); + } - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_NOVOS_CRYSTAL_1: - case GO_NOVOS_CRYSTAL_2: - case GO_NOVOS_CRYSTAL_3: - case GO_NOVOS_CRYSTAL_4: - AddDoor(go); - break; - } - } - - void OnGameObjectRemove(GameObject* go) override - { - switch (go->GetEntry()) - { - case GO_NOVOS_CRYSTAL_1: - case GO_NOVOS_CRYSTAL_2: - case GO_NOVOS_CRYSTAL_3: - case GO_NOVOS_CRYSTAL_4: - RemoveDoor(go); - break; - } - } - }; - - InstanceScript* GetInstanceScript(InstanceMap* map) const override + void OnGameObjectCreate(GameObject* go) override { - return new instance_drak_tharon_keep_InstanceScript(map); + switch (go->GetEntry()) + { + case GO_NOVOS_CRYSTAL_1: + case GO_NOVOS_CRYSTAL_2: + case GO_NOVOS_CRYSTAL_3: + case GO_NOVOS_CRYSTAL_4: + AddDoor(go); + break; + } + } + + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_NOVOS_CRYSTAL_1: + case GO_NOVOS_CRYSTAL_2: + case GO_NOVOS_CRYSTAL_3: + case GO_NOVOS_CRYSTAL_4: + RemoveDoor(go); + break; + } } }; @@ -121,7 +110,7 @@ class spell_dtk_summon_random_drakkari : public SpellScript void AddSC_instance_drak_tharon_keep() { - new instance_drak_tharon_keep(); + RegisterInstanceScript(instance_drak_tharon_keep, MAP_DRAK_THARON_KEEP); RegisterSpellScript(spell_dtk_raise_dead_aura); RegisterSpellScript(spell_dtk_summon_random_drakkari); }