/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * 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 . */ /* ScriptData SDName: Netherstorm SD%Complete: 80 SDComment: Quest support: 10337, 10652 (special flight paths), 10198, 10191 SDCategory: Netherstorm EndScriptData */ /* ContentData npc_commander_dawnforge EndContentData */ #include "ScriptMgr.h" #include "Containers.h" #include "Log.h" #include "ObjectAccessor.h" #include "Player.h" #include "ScriptedCreature.h" #include "SpellScript.h" /*###### ## npc_commander_dawnforge ######*/ // The Speech of Dawnforge, Ardonis & Pathaleon enum CommanderDawnforgeData { SAY_COMMANDER_DAWNFORGE_1 = 0, SAY_COMMANDER_DAWNFORGE_2 = 1, SAY_COMMANDER_DAWNFORGE_3 = 2, SAY_COMMANDER_DAWNFORGE_4 = 3, SAY_COMMANDER_DAWNFORGE_5 = 4, SAY_ARCANIST_ARDONIS_1 = 0, SAY_ARCANIST_ARDONIS_2 = 1, SAY_PATHALEON_CULATOR_IMAGE_1 = 0, SAY_PATHALEON_CULATOR_IMAGE_2 = 1, SAY_PATHALEON_CULATOR_IMAGE_2_1 = 2, SAY_PATHALEON_CULATOR_IMAGE_2_2 = 3, QUEST_INFO_GATHERING = 10198, SPELL_SUNFURY_DISGUISE = 34603, }; // Entries of Arcanist Ardonis, Commander Dawnforge, Pathaleon the Curators Image const uint32 CreatureEntry[3] = { 19830, // Ardonis 19831, // Dawnforge 21504 // Pathaleon }; class npc_commander_dawnforge : public CreatureScript { public: npc_commander_dawnforge() : CreatureScript("npc_commander_dawnforge") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_commander_dawnforgeAI(creature); } struct npc_commander_dawnforgeAI : public ScriptedAI { npc_commander_dawnforgeAI(Creature* creature) : ScriptedAI(creature) { Initialize(); } void Initialize() { PlayerGUID.Clear(); ardonisGUID.Clear(); pathaleonGUID.Clear(); Phase = 1; PhaseSubphase = 0; Phase_Timer = 4000; isEvent = false; } ObjectGuid PlayerGUID; ObjectGuid ardonisGUID; ObjectGuid pathaleonGUID; uint32 Phase; uint32 PhaseSubphase; uint32 Phase_Timer; bool isEvent; void Reset() override { Initialize(); } void JustEngagedWith(Unit* /*who*/) override { } void JustSummoned(Creature* summoned) override { pathaleonGUID = summoned->GetGUID(); } // Emote Ardonis and Pathaleon void Turn_to_Pathaleons_Image() { Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID); Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID); if (!ardonis || !pathaleon) return; // Turn Dawnforge me->SetFacingToObject(pathaleon); // Turn Ardonis ardonis->SetFacingToObject(pathaleon); //Set them to kneel me->SetStandState(UNIT_STAND_STATE_KNEEL); ardonis->SetStandState(UNIT_STAND_STATE_KNEEL); } //Set them back to each other void Turn_to_eachother() { if (Unit* ardonis = ObjectAccessor::GetUnit(*me, ardonisGUID)) { // Turn Dawnforge me->SetFacingToObject(ardonis); // Turn Ardonis ardonis->SetFacingToObject(me); //Set state me->SetStandState(UNIT_STAND_STATE_STAND); ardonis->SetStandState(UNIT_STAND_STATE_STAND); } } bool CanStartEvent(Player* player) { if (!isEvent) { Creature* ardonis = me->FindNearestCreature(CreatureEntry[0], 10.0f); if (!ardonis) return false; ardonisGUID = ardonis->GetGUID(); PlayerGUID = player->GetGUID(); isEvent = true; Turn_to_eachother(); return true; } TC_LOG_DEBUG("scripts", "npc_commander_dawnforge event already in progress, need to wait."); return false; } void UpdateAI(uint32 diff) override { //Is event even running? if (!isEvent) return; //Phase timing if (Phase_Timer >= diff) { Phase_Timer -= diff; return; } Creature* ardonis = ObjectAccessor::GetCreature(*me, ardonisGUID); Creature* pathaleon = ObjectAccessor::GetCreature(*me, pathaleonGUID); Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID); if (!ardonis || !player) { Reset(); return; } if (Phase > 4 && !pathaleon) { Reset(); return; } //Phase 1 Dawnforge say switch (Phase) { case 1: Talk(SAY_COMMANDER_DAWNFORGE_1); ++Phase; Phase_Timer = 16000; break; //Phase 2 Ardonis say case 2: ardonis->AI()->Talk(SAY_ARCANIST_ARDONIS_1); ++Phase; Phase_Timer = 16000; break; //Phase 3 Dawnforge say case 3: Talk(SAY_COMMANDER_DAWNFORGE_2); ++Phase; Phase_Timer = 16000; break; //Phase 4 Pathaleon spawns up to phase 9 case 4: //spawn pathaleon's image me->SummonCreature(CreatureEntry[2], 2325.851563f, 2799.534668f, 133.084229f, 6.038996f, TEMPSUMMON_TIMED_DESPAWN, 90s); ++Phase; Phase_Timer = 500; break; //Phase 5 Pathaleon say case 5: pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_1); ++Phase; Phase_Timer = 6000; break; //Phase 6 case 6: switch (PhaseSubphase) { //Subphase 1: Turn Dawnforge and Ardonis case 0: Turn_to_Pathaleons_Image(); ++PhaseSubphase; Phase_Timer = 8000; break; //Subphase 2 Dawnforge say case 1: Talk(SAY_COMMANDER_DAWNFORGE_3); PhaseSubphase = 0; ++Phase; Phase_Timer = 8000; break; } break; //Phase 7 Pathaleons say 3 Sentence, every sentence need a subphase case 7: switch (PhaseSubphase) { //Subphase 1 case 0: pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2); ++PhaseSubphase; Phase_Timer = 12000; break; //Subphase 2 case 1: pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2_1); ++PhaseSubphase; Phase_Timer = 16000; break; //Subphase 3 case 2: pathaleon->AI()->Talk(SAY_PATHALEON_CULATOR_IMAGE_2_2); PhaseSubphase = 0; ++Phase; Phase_Timer = 10000; break; } break; //Phase 8 Dawnforge & Ardonis say case 8: Talk(SAY_COMMANDER_DAWNFORGE_4); ardonis->AI()->Talk(SAY_ARCANIST_ARDONIS_2); ++Phase; Phase_Timer = 4000; break; //Phase 9 Pathaleons Despawn, Reset Dawnforge & Ardonis angle case 9: Turn_to_eachother(); //hide pathaleon, unit will despawn shortly pathaleon->SetVisible(false); PhaseSubphase = 0; ++Phase; Phase_Timer = 3000; break; //Phase 10 Dawnforge say case 10: Talk(SAY_COMMANDER_DAWNFORGE_5); player->AreaExploredOrEventHappens(QUEST_INFO_GATHERING); Reset(); break; } } }; }; class at_commander_dawnforge : public AreaTriggerScript { public: at_commander_dawnforge() : AreaTriggerScript("at_commander_dawnforge") { } bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override { //if player lost aura or not have at all, we should not try start event. if (!player->HasAura(SPELL_SUNFURY_DISGUISE)) return false; if (player->IsAlive() && player->GetQuestStatus(QUEST_INFO_GATHERING) == QUEST_STATUS_INCOMPLETE) { Creature* Dawnforge = player->FindNearestCreature(CreatureEntry[1], 30.0f); if (!Dawnforge) return false; if (ENSURE_AI(npc_commander_dawnforge::npc_commander_dawnforgeAI, Dawnforge->AI())->CanStartEvent(player)) return true; } return false; } }; /*###### ## npc_phase_hunter ######*/ enum PhaseHunterData { QUEST_RECHARGING_THE_BATTERIES = 10190, NPC_PHASE_HUNTER_ENTRY = 18879, NPC_DRAINED_PHASE_HUNTER_ENTRY = 19595, EMOTE_WEAK = 0, // Spells SPELL_RECHARGING_BATTERY = 34219, SPELL_PHASE_SLIP = 36574, SPELL_MANA_BURN = 13321, SPELL_MATERIALIZE = 34804, SPELL_DE_MATERIALIZE = 34814, }; class npc_phase_hunter : public CreatureScript { public: npc_phase_hunter() : CreatureScript("npc_phase_hunter") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_phase_hunterAI(creature); } struct npc_phase_hunterAI : public ScriptedAI { npc_phase_hunterAI(Creature* creature) : ScriptedAI(creature) { Weak = false; Materialize = false; Drained = false; WeakPercent = 25; ManaBurnTimer = 5000; } bool Weak; bool Materialize; bool Drained; uint8 WeakPercent; ObjectGuid PlayerGUID; uint32 ManaBurnTimer; void Reset() override { Weak = false; Materialize = false; Drained = false; WeakPercent = 25 + (rand32() % 16); // 25-40 PlayerGUID.Clear(); ManaBurnTimer = 5000 + (rand32() % 3 * 1000); // 5-8 sec cd if (me->GetEntry() == NPC_DRAINED_PHASE_HUNTER_ENTRY) me->UpdateEntry(NPC_PHASE_HUNTER_ENTRY); } void JustEngagedWith(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER) PlayerGUID = who->GetGUID(); } void UpdateAI(uint32 diff) override { if (!Materialize) { DoCast(me, SPELL_MATERIALIZE); Materialize = true; } if (me->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || me->HasUnitState(UNIT_STATE_ROOT)) // if the mob is rooted/slowed by spells eg.: Entangling Roots, Frost Nova, Hamstring, Crippling Poison, etc. => remove it DoCast(me, SPELL_PHASE_SLIP); if (!UpdateVictim()) return; // some code to cast spell Mana Burn on random target which has mana if (ManaBurnTimer <= diff) { std::list UnitsWithMana; for (auto* ref : me->GetThreatManager().GetUnsortedThreatList()) if (ref->GetVictim()->GetPower(POWER_MANA)) UnitsWithMana.push_back(ref->GetVictim()); if (!UnitsWithMana.empty()) { DoCast(Trinity::Containers::SelectRandomContainerElement(UnitsWithMana), SPELL_MANA_BURN); ManaBurnTimer = urand(8000, 18000); // 8-18 sec cd } else ManaBurnTimer = 3500; } else ManaBurnTimer -= diff; if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) // start: support for quest 10190 { if (!Weak && HealthBelowPct(WeakPercent) && player->GetQuestStatus(QUEST_RECHARGING_THE_BATTERIES) == QUEST_STATUS_INCOMPLETE) { Talk(EMOTE_WEAK); Weak = true; } if (Weak && !Drained && me->HasAura(SPELL_RECHARGING_BATTERY)) { Drained = true; int32 uHpPct = int32(me->GetHealthPct()); me->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY); me->SetHealth(me->CountPctFromMaxHealth(uHpPct)); me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth()); me->SetInCombatWith(player); } } // end: support for quest 10190 } }; }; /*###### ## Quest 10857: Teleport This! ######*/ enum DetonateTeleporter { SPELL_TELEPORTER_KILL_CREDIT_1 = 38982, // 22348 SPELL_TELEPORTER_KILL_CREDIT_2 = 38983, // 22351 SPELL_TELEPORTER_KILL_CREDIT_3 = 38984, // 22350 NPC_WESTERN_TELEPORTER_CREDIT = 22348, NPC_EASTERN_TELEPORTER_CREDIT = 22351, NPC_CENTRAL_TELEPORTER_CREDIT = 22350 }; // 38920 - Detonate Teleporter class spell_detonate_teleporter : public SpellScript { bool Load() override { return GetCaster()->GetTypeId() == TYPEID_UNIT; } bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo( { SPELL_TELEPORTER_KILL_CREDIT_1, SPELL_TELEPORTER_KILL_CREDIT_2, SPELL_TELEPORTER_KILL_CREDIT_3 }); } void HandleScript(SpellEffIndex /*effIndex*/) { if (Creature* creature = GetHitCreature()) { if (Unit* charmer = GetCaster()->GetCharmerOrOwner()) { if (Player* player = charmer->ToPlayer()) { uint32 spellId = 0; switch (creature->GetEntry()) { case NPC_WESTERN_TELEPORTER_CREDIT: spellId = SPELL_TELEPORTER_KILL_CREDIT_1; break; case NPC_EASTERN_TELEPORTER_CREDIT: spellId = SPELL_TELEPORTER_KILL_CREDIT_2; break; case NPC_CENTRAL_TELEPORTER_CREDIT: spellId = SPELL_TELEPORTER_KILL_CREDIT_3; break; default: return; } player->CastSpell(player, spellId); } } } } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_detonate_teleporter::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); } }; void AddSC_netherstorm() { new npc_commander_dawnforge(); new at_commander_dawnforge(); new npc_phase_hunter(); RegisterSpellScript(spell_detonate_teleporter); }