/* * This file is part of the AzerothCore 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 Affero General Public License as published by the * Free Software Foundation; either version 3 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 Affero 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 . */ #include "CombatAI.h" #include "CreatureScript.h" #include "CreatureTextMgr.h" #include "GameObjectScript.h" #include "MoveSplineInit.h" #include "ObjectMgr.h" #include "PassiveAI.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedEscortAI.h" #include "ScriptedGossip.h" #include "SpellInfo.h" #include "SpellScript.h" #include "SpellScriptLoader.h" #include "Vehicle.h" /*###### ## npc_eye_of_acherus ######*/ enum EyeOfAcherusMisc { SPELL_THE_EYE_OF_ACHERUS = 51852, SPELL_EYE_OF_ACHERUS_VISUAL = 51892, SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST = 51923, SPELL_EYE_OF_ACHERUS_FLIGHT = 51890, SPELL_ROOT_SELF = 51860, EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION = 1, EVENT_UNROOT = 2, EVENT_LAUNCH_TOWARDS_DESTINATION = 3, EVENT_GRANT_CONTROL = 4, SAY_LAUNCH_TOWARDS_DESTINATION = 0, SAY_EYE_UNDER_CONTROL = 1, POINT_NEW_AVALON = 1, EYE_POINT_DESTINATION_0 = 0, EYE_POINT_DESTINATION_1 = 1, EYE_POINT_DESTINATION_2 = 2, EYE_POINT_DESTINATION_3 = 3 }; struct npc_eye_of_acherus : public ScriptedAI { npc_eye_of_acherus(Creature* creature) : ScriptedAI(creature) { creature->SetDisplayFromModel(0); creature->SetReactState(REACT_PASSIVE); } void InitializeAI() override { DoCastSelf(SPELL_ROOT_SELF); DoCastSelf(SPELL_EYE_OF_ACHERUS_VISUAL); _events.ScheduleEvent(EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION, 400ms); } void OnCharmed(bool apply) override { if (!apply) { me->GetCharmerOrOwner()->RemoveAurasDueToSpell(SPELL_THE_EYE_OF_ACHERUS); me->GetCharmerOrOwner()->RemoveAurasDueToSpell(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST); } } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION: if (Unit* owner = me->GetCharmerOrOwner()) { Talk(SAY_LAUNCH_TOWARDS_DESTINATION, owner); } _events.ScheduleEvent(EVENT_UNROOT, 400ms); break; case EVENT_UNROOT: me->RemoveAurasDueToSpell(SPELL_ROOT_SELF); DoCastSelf(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST); _events.ScheduleEvent(EVENT_LAUNCH_TOWARDS_DESTINATION, 1s + 200ms); break; case EVENT_LAUNCH_TOWARDS_DESTINATION: { Position const EYE_DESTINATION_1 = { 2361.21f, -5660.45f, 496.744f, 0.0f }; Position const EYE_DESTINATION_2 = { 2341.571f, -5672.797f, 538.3942f, 0.0f }; Position const EYE_DESTINATION_3 = { 1957.4f, -5844.1f, 273.867f, 0.0f }; Position const EYE_DESTINATION_4 = { 1758.01f, -5876.79f, 166.867f, 0.0f }; Movement::MoveSplineInit init(me); init.SetFly(); if (Unit* owner = me->GetCharmerOrOwner()) { init.SetVelocity(owner->GetSpeed(MOVE_RUN)); } me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_0, EYE_DESTINATION_1); me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_1, EYE_DESTINATION_2); me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_2, EYE_DESTINATION_3); me->GetMotionMaster()->MovePoint(EYE_POINT_DESTINATION_3, EYE_DESTINATION_4); _events.ScheduleEvent(EVENT_GRANT_CONTROL, 22s); break; } case EVENT_GRANT_CONTROL: if (Unit* owner = me->GetCharmerOrOwner()) { Talk(SAY_EYE_UNDER_CONTROL, owner); } me->RemoveAurasDueToSpell(SPELL_ROOT_SELF); DoCastSelf(SPELL_EYE_OF_ACHERUS_FLIGHT); me->RemoveAurasDueToSpell(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST); break; default: break; } } } void MovementInform(uint32 movementType, uint32 pointId) override { if (movementType != POINT_MOTION_TYPE) return; switch (pointId) { case POINT_NEW_AVALON: DoCastSelf(SPELL_ROOT_SELF); break; default: break; } } private: EventMap _events; }; class spell_q12641_death_comes_from_on_high_summon_ghouls : public SpellScriptLoader { public: spell_q12641_death_comes_from_on_high_summon_ghouls() : SpellScriptLoader("spell_q12641_death_comes_from_on_high_summon_ghouls") { } class spell_q12641_death_comes_from_on_high_summon_ghouls_SpellScript : public SpellScript { PrepareSpellScript(spell_q12641_death_comes_from_on_high_summon_ghouls_SpellScript); void HandleScriptEffect(SpellEffIndex effIndex) { PreventHitEffect(effIndex); if (Unit* target = GetHitUnit()) GetCaster()->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 54522, true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_q12641_death_comes_from_on_high_summon_ghouls_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const override { return new spell_q12641_death_comes_from_on_high_summon_ghouls_SpellScript(); } }; enum deathsChallenge { SPELL_DUEL = 52996, //SPELL_DUEL_TRIGGERED = 52990, SPELL_DUEL_VICTORY = 52994, SPELL_DUEL_FLAG = 52991, SAY_DUEL = 0, QUEST_DEATH_CHALLENGE = 12733, DATA_IN_PROGRESS = 0, EVENT_SPEAK = 1, // 1 - 6 EVENT_DUEL_LOST = 7, // 7 - 8 }; class npc_death_knight_initiate : public CreatureScript { public: npc_death_knight_initiate() : CreatureScript("npc_death_knight_initiate") { } bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override { ClearGossipMenuFor(player); if (action == GOSSIP_ACTION_INFO_DEF) { CloseGossipMenuFor(player); if (player->IsInCombat() || creature->IsInCombat()) return true; if (creature->AI()->GetData(DATA_IN_PROGRESS)) return true; creature->SetImmuneToPC(false); creature->RemoveUnitFlag(UNIT_FLAG_SWIMMING); player->CastSpell(creature, SPELL_DUEL, false); player->CastSpell(player, SPELL_DUEL_FLAG, true); } return true; } bool OnGossipHello(Player* player, Creature* creature) override { if (player->GetQuestStatus(QUEST_DEATH_CHALLENGE) == QUEST_STATUS_INCOMPLETE && creature->IsFullHealth()) { if (player->HealthBelowPct(10)) return true; if (player->IsInCombat() || creature->IsInCombat()) return true; if (!creature->AI()->GetGUID(player->GetGUID().GetCounter())) AddGossipItemFor(player, 9765, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID()); } return true; } CreatureAI* GetAI(Creature* creature) const override { return new npc_death_knight_initiateAI(creature); } struct npc_death_knight_initiateAI : public CombatAI { npc_death_knight_initiateAI(Creature* creature) : CombatAI(creature) { } bool _duelInProgress; ObjectGuid _duelGUID; EventMap events; std::set playerGUIDs; uint32 timer = 0; uint32 GetData(uint32 data) const override { if (data == DATA_IN_PROGRESS) return _duelInProgress; return playerGUIDs.find(data) != playerGUIDs.end(); } void Reset() override { _duelInProgress = false; _duelGUID.Clear(); me->RestoreFaction(); CombatAI::Reset(); me->SetUnitFlag(UNIT_FLAG_SWIMMING); } void SpellHit(Unit* caster, SpellInfo const* pSpell) override { if (!_duelInProgress && pSpell->Id == SPELL_DUEL) { playerGUIDs.insert(caster->GetGUID().GetCounter()); _duelGUID = caster->GetGUID(); _duelInProgress = true; timer = 600000; // clear playerGUIDs after 10 minutes if no one initiates a duel me->GetMotionMaster()->MoveFollow(caster, 2.0f, 0.0f); events.ScheduleEvent(EVENT_SPEAK, 3s); events.ScheduleEvent(EVENT_SPEAK + 1, 7s); events.ScheduleEvent(EVENT_SPEAK + 2, 8s); events.ScheduleEvent(EVENT_SPEAK + 3, 9s); events.ScheduleEvent(EVENT_SPEAK + 4, 10s); events.ScheduleEvent(EVENT_SPEAK + 5, 11s); } } void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override { if (attacker && _duelInProgress && attacker->IsControlledByPlayer()) { if (attacker->GetCharmerOrOwnerOrOwnGUID() != _duelGUID) damage = 0; else if (damage >= me->GetHealth()) { damage = 0; events.ScheduleEvent(EVENT_DUEL_LOST, 2s); events.ScheduleEvent(EVENT_DUEL_LOST + 1, 6s); _duelGUID.Clear(); _duelInProgress = 0; attacker->RemoveGameObject(SPELL_DUEL_FLAG, true); attacker->AttackStop(); me->CombatStop(false); me->RemoveAllAuras(); me->CastSpell(attacker, SPELL_DUEL_VICTORY, true); me->RestoreFaction(); } } } void UpdateAI(uint32 diff) override { if (timer != 0) { if (timer <= diff) { timer = 0; playerGUIDs.clear(); } else { timer -= diff; } } events.Update(diff); switch (events.ExecuteEvent()) { case EVENT_SPEAK: Talk(SAY_DUEL, ObjectAccessor::GetPlayer(*me, _duelGUID)); break; case EVENT_SPEAK+1: Talk(SAY_DUEL + 1, ObjectAccessor::GetPlayer(*me, _duelGUID)); break; case EVENT_SPEAK+2: Talk(SAY_DUEL + 2, ObjectAccessor::GetPlayer(*me, _duelGUID)); break; case EVENT_SPEAK+3: Talk(SAY_DUEL + 3, ObjectAccessor::GetPlayer(*me, _duelGUID)); break; case EVENT_SPEAK+4: Talk(SAY_DUEL + 4, ObjectAccessor::GetPlayer(*me, _duelGUID)); break; case EVENT_SPEAK+5: me->SetFaction(FACTION_UNDEAD_SCOURGE_2); if (Player* player = ObjectAccessor::GetPlayer(*me, _duelGUID)) AttackStart(player); return; case EVENT_DUEL_LOST: me->CastSpell(me, 7267, true); break; case EVENT_DUEL_LOST+1: EnterEvadeMode(); return; } if (!events.Empty() || !UpdateVictim()) return; if (_duelInProgress) { if (me->GetVictim()->GetGUID() == _duelGUID && me->GetVictim()->HealthBelowPct(10)) { me->GetVictim()->CastSpell(me->GetVictim(), 7267, true); // beg me->GetVictim()->RemoveGameObject(SPELL_DUEL_FLAG, true); EnterEvadeMode(); return; } } CombatAI::UpdateAI(diff); } }; }; enum GiftOfTheHarvester { NPC_GHOUL = 28845, MAX_GHOULS = 5, SPELL_GHOUL_EMERGE = 50142, SPELL_SUMMON_SCARLET_GHOST = 52505, SPELL_GHOUL_SUBMERGE = 26234, EVENT_GHOUL_RESTORE_STATE = 1, EVENT_GHOUL_CHECK_COMBAT = 2, EVENT_GHOUL_EMOTE = 3, EVENT_GHOUL_MOVE_TO_PIT = 4, SAY_GOTHIK_PIT = 0 }; class spell_item_gift_of_the_harvester : public SpellScriptLoader { public: spell_item_gift_of_the_harvester() : SpellScriptLoader("spell_item_gift_of_the_harvester") { } class spell_item_gift_of_the_harvester_SpellScript : public SpellScript { PrepareSpellScript(spell_item_gift_of_the_harvester_SpellScript); SpellCastResult CheckRequirement() { std::list ghouls; GetCaster()->GetAllMinionsByEntry(ghouls, NPC_GHOUL); if (ghouls.size() >= MAX_GHOULS) { SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_TOO_MANY_GHOULS); return SPELL_FAILED_CUSTOM_ERROR; } return SPELL_CAST_OK; } void Register() override { OnCheckCast += SpellCheckCastFn(spell_item_gift_of_the_harvester_SpellScript::CheckRequirement); } }; SpellScript* GetSpellScript() const override { return new spell_item_gift_of_the_harvester_SpellScript(); } }; class spell_q12698_the_gift_that_keeps_on_giving : public SpellScriptLoader { public: spell_q12698_the_gift_that_keeps_on_giving() : SpellScriptLoader("spell_q12698_the_gift_that_keeps_on_giving") { } class spell_q12698_the_gift_that_keeps_on_giving_SpellScript : public SpellScript { PrepareSpellScript(spell_q12698_the_gift_that_keeps_on_giving_SpellScript); void HandleScriptEffect(SpellEffIndex /*effIndex*/) { if (GetOriginalCaster() && GetHitUnit()) GetOriginalCaster()->CastSpell(GetHitUnit(), urand(0, 1) ? GetEffectValue() : SPELL_SUMMON_SCARLET_GHOST, true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_q12698_the_gift_that_keeps_on_giving_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; SpellScript* GetSpellScript() const override { return new spell_q12698_the_gift_that_keeps_on_giving_SpellScript(); } }; class npc_scarlet_ghoul : public CreatureScript { public: npc_scarlet_ghoul() : CreatureScript("npc_scarlet_ghoul") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_scarlet_ghoulAI(creature); } struct npc_scarlet_ghoulAI : public ScriptedAI { npc_scarlet_ghoulAI(Creature* creature) : ScriptedAI(creature) { } EventMap events; ObjectGuid gothikGUID; void InitializeAI() override { me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE); ScriptedAI::InitializeAI(); me->SetReactState(REACT_PASSIVE); events.ScheduleEvent(EVENT_GHOUL_EMOTE, 1ms); events.ScheduleEvent(EVENT_GHOUL_RESTORE_STATE, 3500ms); } void OwnerAttackedBy(Unit* attacker) override { if (!me->IsInCombat() && me->GetReactState() == REACT_DEFENSIVE) AttackStart(attacker); } void SetGUID(ObjectGuid guid, int32) override { gothikGUID = guid; events.ScheduleEvent(EVENT_GHOUL_MOVE_TO_PIT, 3s); me->GetMotionMaster()->Clear(false); } void MovementInform(uint32 type, uint32 point) override { if (type == POINT_MOTION_TYPE && point == 1) { me->DespawnOrUnsummon(1500); me->CastSpell(me, SPELL_GHOUL_SUBMERGE, true); } } void UpdateAI(uint32 diff) override { events.Update(diff); switch (events.ExecuteEvent()) { case EVENT_GHOUL_MOVE_TO_PIT: me->GetMotionMaster()->MovePoint(1, 2364.77f, -5776.14f, 151.36f); if (Creature* gothik = ObjectAccessor::GetCreature(*me, gothikGUID)) gothik->AI()->DoAction(SAY_GOTHIK_PIT); break; case EVENT_GHOUL_EMOTE: me->CastSpell(me, SPELL_GHOUL_EMERGE, true); break; case EVENT_GHOUL_RESTORE_STATE: me->SetReactState(REACT_DEFENSIVE); me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE); if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, frand(0.0f, 2 * M_PI)); events.ScheduleEvent(EVENT_GHOUL_CHECK_COMBAT, 1s); return; case EVENT_GHOUL_CHECK_COMBAT: if (!me->IsInCombat()) if (Player* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself()) if (owner->GetVictim()) AttackStart(owner->GetVictim()); events.RepeatEvent(1000); return; } if (!UpdateVictim()) return; DoMeleeAttackIfReady(); } }; }; class npc_dkc1_gothik : public CreatureScript { public: npc_dkc1_gothik() : CreatureScript("npc_dkc1_gothik") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_dkc1_gothikAI(creature); } struct npc_dkc1_gothikAI : public ScriptedAI { npc_dkc1_gothikAI(Creature* creature) : ScriptedAI(creature) { spoken = 0; } int32 spoken; void DoAction(int32 action) override { if (action == SAY_GOTHIK_PIT && spoken <= 0) { spoken = 5000; Talk(SAY_GOTHIK_PIT); } } void MoveInLineOfSight(Unit* who) override { ScriptedAI::MoveInLineOfSight(who); if (!who->IsImmuneToNPC() && who->GetEntry() == NPC_GHOUL && me->IsWithinDistInMap(who, 10.0f)) if (Unit* owner = who->GetOwner()) if (Player* player = owner->ToPlayer()) { Creature* creature = who->ToCreature(); if (player->GetQuestStatus(12698) == QUEST_STATUS_INCOMPLETE) creature->CastSpell(owner, 52517, true); creature->AI()->SetGUID(me->GetGUID()); creature->SetImmuneToAll(true); } } void UpdateAI(uint32 diff) override { if (spoken > 0) spoken -= diff; ScriptedAI::UpdateAI(diff); } }; }; class npc_scarlet_cannon : public CreatureScript { public: npc_scarlet_cannon() : CreatureScript("npc_scarlet_cannon") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_scarlet_cannonAI(creature); } struct npc_scarlet_cannonAI : public VehicleAI { npc_scarlet_cannonAI(Creature* creature) : VehicleAI(creature) { summonAttackers = 0; } uint32 summonAttackers; void PassengerBoarded(Unit* /*passenger*/, int8 /*seatId*/, bool apply) override { summonAttackers = apply ? 8000 : 0; } void UpdateAI(uint32 diff) override { VehicleAI::UpdateAI(diff); if (summonAttackers) { summonAttackers += diff; if (summonAttackers >= 15000) { for (uint8 i = 0; i < 15; ++i) if (Creature* summon = me->SummonCreature(28834 /*NPC_SCARLET_FLEET_DEFENDER*/, 2192.56f + irand(-10, 10), -6147.90f + irand(-10, 10), 5.2f, 4.7f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 45000)) { summon->SetHomePosition(me->GetHomePosition()); summon->AI()->AttackStart(me); } summonAttackers = 1; } } } }; }; // Theirs /*###### ##Quest 12848 ######*/ #define GCD_CAST 1 enum UnworthyInitiate { SPELL_SOUL_PRISON_CHAIN = 54612, SPELL_DK_INITIATE_VISUAL = 51519, SPELL_ICY_TOUCH = 52372, SPELL_PLAGUE_STRIKE = 52373, SPELL_BLOOD_STRIKE = 52374, SPELL_DEATH_COIL = 52375, SAY_EVENT_START = 0, SAY_EVENT_ATTACK = 1, EVENT_ICY_TOUCH = 1, EVENT_PLAGUE_STRIKE = 2, EVENT_BLOOD_STRIKE = 3, EVENT_DEATH_COIL = 4 }; enum UnworthyInitiatePhase { PHASE_CHAINED, PHASE_TO_EQUIP, PHASE_EQUIPING, PHASE_TO_ATTACK, PHASE_ATTACKING, }; uint32 acherus_soul_prison[12] = { 191577, 191580, 191581, 191582, 191583, 191584, 191585, 191586, 191587, 191588, 191589, 191590 }; //uint32 acherus_unworthy_initiate[5] = //{ // 29519, // 29520, // 29565, // 29566, // 29567 //}; class npc_unworthy_initiate : public CreatureScript { public: npc_unworthy_initiate() : CreatureScript("npc_unworthy_initiate") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_unworthy_initiateAI(creature); } struct npc_unworthy_initiateAI : public ScriptedAI { npc_unworthy_initiateAI(Creature* creature) : ScriptedAI(creature) { me->SetReactState(REACT_PASSIVE); if (!me->GetCurrentEquipmentId()) me->SetCurrentEquipmentId(me->GetOriginalEquipmentId()); } ObjectGuid playerGUID; UnworthyInitiatePhase phase; uint32 wait_timer; float anchorX, anchorY; ObjectGuid anchorGUID; EventMap events; void Reset() override { anchorGUID.Clear(); phase = PHASE_CHAINED; events.Reset(); me->SetFaction(FACTION_CREATURE); me->SetImmuneToPC(true); me->SetUInt32Value(UNIT_FIELD_BYTES_1, 8); me->LoadEquipment(0, true); } void JustEngagedWith(Unit* /*who*/) override { events.ScheduleEvent(EVENT_ICY_TOUCH, 1s, GCD_CAST); events.ScheduleEvent(EVENT_PLAGUE_STRIKE, 3s, GCD_CAST); events.ScheduleEvent(EVENT_BLOOD_STRIKE, 2s, GCD_CAST); events.ScheduleEvent(EVENT_DEATH_COIL, 5s, GCD_CAST); } void MovementInform(uint32 type, uint32 id) override { if (type != POINT_MOTION_TYPE) return; if (id == 1) { wait_timer = 5000; me->LoadEquipment(1); me->CastSpell(me, SPELL_DK_INITIATE_VISUAL, true); if (Player* starter = ObjectAccessor::GetPlayer(*me, playerGUID)) Talk(SAY_EVENT_ATTACK, starter); phase = PHASE_TO_ATTACK; } } void EventStart(Creature* anchor, Player* target) { wait_timer = 5000; phase = PHASE_TO_EQUIP; me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); me->RemoveAurasDueToSpell(SPELL_SOUL_PRISON_CHAIN); float z; anchor->GetContactPoint(me, anchorX, anchorY, z, 1.0f); playerGUID = target->GetGUID(); Talk(SAY_EVENT_START, target); } void UpdateAI(uint32 diff) override { switch (phase) { case PHASE_CHAINED: if (!anchorGUID) { if (Creature* anchor = me->FindNearestCreature(29521, 30)) { anchor->AI()->SetGUID(me->GetGUID()); anchor->CastSpell(me, SPELL_SOUL_PRISON_CHAIN, true); anchorGUID = anchor->GetGUID(); } float dist = 99.0f; GameObject* prison = nullptr; for (uint8 i = 0; i < 12; ++i) { if (GameObject* temp_prison = me->FindNearestGameObject(acherus_soul_prison[i], 100)) { if (me->IsWithinDist(temp_prison, dist, false)) { dist = me->GetDistance2d(temp_prison); prison = temp_prison; } } } if (prison) prison->ResetDoorOrButton(); } break; case PHASE_TO_EQUIP: if (wait_timer) { if (wait_timer > diff) wait_timer -= diff; else { me->GetMotionMaster()->MovePoint(1, anchorX, anchorY, me->GetPositionZ()); //LOG_DEBUG("scripts.ai", "npc_unworthy_initiateAI: move to {} {} {}", anchorX, anchorY, me->GetPositionZ()); phase = PHASE_EQUIPING; wait_timer = 0; } } break; case PHASE_TO_ATTACK: if (wait_timer) { if (wait_timer > diff) wait_timer -= diff; else { me->SetFaction(FACTION_MONSTER); me->SetImmuneToPC(false); phase = PHASE_ATTACKING; if (Player* target = ObjectAccessor::GetPlayer(*me, playerGUID)) AttackStart(target); wait_timer = 0; } } break; case PHASE_ATTACKING: if (!UpdateVictim()) return; events.Update(diff); while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { case EVENT_ICY_TOUCH: DoCastVictim(SPELL_ICY_TOUCH); events.DelayEvents(1000, GCD_CAST); events.ScheduleEvent(EVENT_ICY_TOUCH, 5s, GCD_CAST); break; case EVENT_PLAGUE_STRIKE: DoCastVictim(SPELL_PLAGUE_STRIKE); events.DelayEvents(1000, GCD_CAST); events.ScheduleEvent(EVENT_PLAGUE_STRIKE, 5s, GCD_CAST); break; case EVENT_BLOOD_STRIKE: DoCastVictim(SPELL_BLOOD_STRIKE); events.DelayEvents(1000, GCD_CAST); events.ScheduleEvent(EVENT_BLOOD_STRIKE, 5s, GCD_CAST); break; case EVENT_DEATH_COIL: DoCastVictim(SPELL_DEATH_COIL); events.DelayEvents(1000, GCD_CAST); events.ScheduleEvent(EVENT_DEATH_COIL, 5s, GCD_CAST); break; } } DoMeleeAttackIfReady(); break; default: break; } } }; }; class npc_unworthy_initiate_anchor : public CreatureScript { public: npc_unworthy_initiate_anchor() : CreatureScript("npc_unworthy_initiate_anchor") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_unworthy_initiate_anchorAI(creature); } struct npc_unworthy_initiate_anchorAI : public PassiveAI { npc_unworthy_initiate_anchorAI(Creature* creature) : PassiveAI(creature) {} ObjectGuid prisonerGUID; void SetGUID(ObjectGuid guid, int32 /*id*/) override { if (!prisonerGUID) prisonerGUID = guid; } ObjectGuid GetGUID(int32 /*id*/) const override { return prisonerGUID; } }; }; class go_acherus_soul_prison : public GameObjectScript { public: go_acherus_soul_prison() : GameObjectScript("go_acherus_soul_prison") { } bool OnGossipHello(Player* player, GameObject* go) override { if (Creature* anchor = go->FindNearestCreature(29521, 15)) if (ObjectGuid prisonerGUID = anchor->AI()->GetGUID()) if (Creature* prisoner = ObjectAccessor::GetCreature(*player, prisonerGUID)) CAST_AI(npc_unworthy_initiate::npc_unworthy_initiateAI, prisoner->AI())->EventStart(anchor, player); return false; } }; /*#### ## npc_scarlet_miner_cart ####*/ enum Spells_SM { SPELL_CART_CHECK = 54173, SPELL_CART_DRAG = 52465 }; class npc_scarlet_miner_cart : public CreatureScript { public: npc_scarlet_miner_cart() : CreatureScript("npc_scarlet_miner_cart") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_scarlet_miner_cartAI(creature); } struct npc_scarlet_miner_cartAI : public PassiveAI { npc_scarlet_miner_cartAI(Creature* creature) : PassiveAI(creature) { me->SetImmuneToAll(true); me->SetFaction(FACTION_FRIENDLY); me->SetDisplayFromModel(0); // Modelid2 is a horse. } ObjectGuid minerGUID; void SetGUID(ObjectGuid guid, int32 /*id*/) override { minerGUID = guid; } void DoAction(int32 /*param*/) override { if (Creature* miner = ObjectAccessor::GetCreature(*me, minerGUID)) { me->SetWalk(false); //Not 100% correct, but movement is smooth. Sometimes miner walks faster //than normal, this speed is fast enough to keep up at those times. me->SetSpeed(MOVE_RUN, 1.25f); me->GetMotionMaster()->MoveFollow(miner, 1.0f, 0); me->ReplaceAllUnitFlags(UNIT_FLAG_NON_ATTACKABLE); me->SetImmuneToAll(true); me->SetFaction(FACTION_FRIENDLY); } } void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override { who->SetVisible(!apply); if (!apply) if (Creature* miner = ObjectAccessor::GetCreature(*me, minerGUID)) miner->DisappearAndDie(); } }; }; /*#### ## npc_scarlet_miner ####*/ enum Says_SM { SAY_SCARLET_MINER_0 = 0, SAY_SCARLET_MINER_1 = 1 }; class npc_scarlet_miner : public CreatureScript { public: npc_scarlet_miner() : CreatureScript("npc_scarlet_miner") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_scarlet_minerAI(creature); } struct npc_scarlet_minerAI : public npc_escortAI { npc_scarlet_minerAI(Creature* creature) : npc_escortAI(creature) { me->SetReactState(REACT_PASSIVE); } uint32 IntroTimer; uint32 IntroPhase; ObjectGuid carGUID; void Reset() override { carGUID.Clear(); IntroTimer = 0; IntroPhase = 0; } void InitWaypoint() { AddWaypoint(1, 2389.03f, -5902.74f, 109.014f, 5000); AddWaypoint(2, 2341.812012f, -5900.484863f, 102.619743f); AddWaypoint(3, 2308.34f, -5904.2f, 91.1099f); AddWaypoint(4, 2300.69f, -5912.99f, 86.1572f); AddWaypoint(5, 2294.142090f, -5927.274414f, 75.316849f); AddWaypoint(6, 2286.984375f, -5944.955566f, 63.714966f); AddWaypoint(7, 2280.001709f, -5961.186035f, 54.228283f); AddWaypoint(8, 2259.389648f, -5974.197754f, 42.359348f); AddWaypoint(9, 2242.882812f, -5984.642578f, 32.827850f); AddWaypoint(10, 2239.79f, -5989.31f, 30.4453f); AddWaypoint(11, 2236.52f, -5994.28f, 27.4829f); AddWaypoint(12, 2232.61f, -6000.23f, 23.1281f); AddWaypoint(13, 2228.69f, -6006.46f, 17.6638f); AddWaypoint(14, 2225.2f, -6012.39f, 12.9487f); AddWaypoint(15, 2217.265625f, -6028.959473f, 7.675705f); AddWaypoint(16, 2202.595947f, -6061.325684f, 5.882018f); AddWaypoint(17, 2188.974609f, -6080.866699f, 3.370027f); if (urand(0, 1)) { AddWaypoint(18, 2176.483887f, -6110.407227f, 1.855181f); AddWaypoint(19, 2172.516602f, -6146.752441f, 1.074235f); AddWaypoint(20, 2138.918457f, -6158.920898f, 1.342926f); AddWaypoint(21, 2129.866699f, -6174.107910f, 4.380779f); AddWaypoint(22, 2125.250001f, -6181.230001f, 9.91997f); AddWaypoint(23, 2117.709473f, -6193.830078f, 13.3542f, 10000); } else { AddWaypoint(18, 2184.190186f, -6166.447266f, 0.968877f); AddWaypoint(19, 2234.265625f, -6163.741211f, 0.916021f); AddWaypoint(20, 2268.071777f, -6158.750977f, 1.822252f); AddWaypoint(21, 2270.028320f, -6176.505859f, 6.340538f); AddWaypoint(22, 2270.350001f, -6182.410001f, 10.42431f); AddWaypoint(23, 2271.739014f, -6195.401855f, 13.3542f, 10000); } } void InitCartQuest(Player* who) { carGUID = who->GetVehicleBase()->GetGUID(); InitWaypoint(); Start(false, false, who->GetGUID()); SetDespawnAtFar(false); } void WaypointReached(uint32 waypointId) override { switch (waypointId) { case 1: if (Unit* car = ObjectAccessor::GetCreature(*me, carGUID)) { me->SetFacingToObject(car); // xinef: add some flags car->ReplaceAllUnitFlags(UNIT_FLAG_NON_ATTACKABLE); car->SetImmuneToAll(true); car->SetFaction(FACTION_FRIENDLY); } Talk(SAY_SCARLET_MINER_0); SetRun(true); IntroTimer = 4000; IntroPhase = 1; break; case 23: if (Creature* car = ObjectAccessor::GetCreature(*me, carGUID)) { car->SetPosition(car->GetPositionX(), car->GetPositionY(), me->GetPositionZ() + 1, car->GetOrientation()); car->StopMovingOnCurrentPos(); me->SetFacingToObject(car); car->RemoveAura(SPELL_CART_DRAG); } Talk(SAY_SCARLET_MINER_1); break; default: break; } } void UpdateAI(uint32 diff) override { if (IntroPhase) { if (IntroTimer <= diff) { if (IntroPhase == 1) { if (Creature* car = ObjectAccessor::GetCreature(*me, carGUID)) DoCast(car, SPELL_CART_DRAG); IntroTimer = 800; IntroPhase = 2; } else { if (Creature* car = ObjectAccessor::GetCreature(*me, carGUID)) car->AI()->DoAction(0); IntroPhase = 0; } } else IntroTimer -= diff; } npc_escortAI::UpdateAI(diff); } }; }; /*###### ## go_inconspicuous_mine_car ######*/ enum Spells_Cart { SPELL_CART_SUMM = 52463 }; class go_inconspicuous_mine_car : public GameObjectScript { public: go_inconspicuous_mine_car() : GameObjectScript("go_inconspicuous_mine_car") { } bool OnGossipHello(Player* player, GameObject* /*go*/) override { if (player->GetQuestStatus(12701) == QUEST_STATUS_INCOMPLETE) { // Hack Why Trinity Dont Support Custom Summon Location if (Creature* miner = player->SummonCreature(28841, 2383.869629f, -5900.312500f, 107.996086f, player->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 1)) { player->CastSpell(player, SPELL_CART_SUMM, true); if (Creature* car = player->GetVehicleCreatureBase()) { if (car->GetEntry() == 28817) { car->AI()->SetGUID(miner->GetGUID()); CAST_AI(npc_scarlet_miner::npc_scarlet_minerAI, miner->AI())->InitCartQuest(player); } } } } return true; } }; class spell_death_knight_initiate_visual : public SpellScript { PrepareSpellScript(spell_death_knight_initiate_visual); void HandleScriptEffect(SpellEffIndex /* effIndex */) { Creature* target = GetHitCreature(); if (!target) return; uint32 spellId; switch (target->GetDisplayId()) { case 25369: spellId = 51552; break; // bloodelf female case 25373: spellId = 51551; break; // bloodelf male case 25363: spellId = 51542; break; // draenei female case 25357: spellId = 51541; break; // draenei male case 25361: spellId = 51537; break; // dwarf female case 25356: spellId = 51538; break; // dwarf male case 25372: spellId = 51550; break; // forsaken female case 25367: spellId = 51549; break; // forsaken male case 25362: spellId = 51540; break; // gnome female case 25359: spellId = 51539; break; // gnome male case 25355: spellId = 51534; break; // human female case 25354: spellId = 51520; break; // human male case 25360: spellId = 51536; break; // nightelf female case 25358: spellId = 51535; break; // nightelf male case 25368: spellId = 51544; break; // orc female case 25364: spellId = 51543; break; // orc male case 25371: spellId = 51548; break; // tauren female case 25366: spellId = 51547; break; // tauren male case 25370: spellId = 51545; break; // troll female case 25365: spellId = 51546; break; // troll male default: return; } target->CastSpell(target, spellId, true); target->LoadEquipment(); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_death_knight_initiate_visual::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; void AddSC_the_scarlet_enclave_c1() { // Ours RegisterCreatureAI(npc_eye_of_acherus); new spell_q12641_death_comes_from_on_high_summon_ghouls(); new npc_death_knight_initiate(); new spell_item_gift_of_the_harvester(); new spell_q12698_the_gift_that_keeps_on_giving(); new npc_scarlet_ghoul(); new npc_dkc1_gothik(); new npc_scarlet_cannon(); // Theirs new npc_unworthy_initiate(); new npc_unworthy_initiate_anchor(); new go_acherus_soul_prison(); new npc_scarlet_miner(); new npc_scarlet_miner_cart(); new go_inconspicuous_mine_car(); RegisterSpellScript(spell_death_knight_initiate_visual); }