/* * 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 . */ #include "CreatureAIImpl.h" #include "ScriptMgr.h" #include "CharmInfo.h" #include "CombatAI.h" #include "CreatureTextMgr.h" #include "G3DPosition.hpp" #include "GameObject.h" #include "GameObjectAI.h" #include "Log.h" #include "Map.h" #include "MotionMaster.h" #include "MoveSplineInit.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "PassiveAI.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" #include "SpellMgr.h" #include "SpellScript.h" #include "SpellInfo.h" #include "TemporarySummon.h" #include "Vehicle.h" /*###### ##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, }; enum UnworthyInitiateData { DATA_PRISONER_GUID = 0 }; 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") { } struct npc_unworthy_initiateAI : public ScriptedAI { npc_unworthy_initiateAI(Creature* creature) : ScriptedAI(creature) { Initialize(); me->SetReactState(REACT_PASSIVE); if (!me->GetCurrentEquipmentId()) me->SetCurrentEquipmentId(me->GetOriginalEquipmentId()); wait_timer = 0; anchorX = 0.f; anchorY = 0.f; } void Initialize() { anchorGUID.Clear(); phase = PHASE_CHAINED; } ObjectGuid playerGUID; UnworthyInitiatePhase phase; uint32 wait_timer; float anchorX, anchorY; ObjectGuid anchorGUID; EventMap events; void Reset() override { Initialize(); events.Reset(); me->SetFaction(FACTION_CREATURE); me->SetImmuneToPC(true); me->SetStandState(UNIT_STAND_STATE_KNEEL); 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->SetStandState(UNIT_STAND_STATE_STAND); 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(), DATA_PRISONER_GUID); anchor->CastSpell(me, SPELL_SOUL_PRISON_CHAIN, true); anchorGUID = anchor->GetGUID(); } else TC_LOG_ERROR("scripts", "npc_unworthy_initiateAI: unable to find anchor!"); float dist = 99.0f; GameObject* prison = nullptr; for (uint8 i = 0; i < 12; ++i) { if (GameObject* temp_prison = me->FindNearestGameObject(acherus_soul_prison[i], 30)) { if (me->IsWithinDist(temp_prison, dist, false)) { dist = me->GetDistance2d(temp_prison); prison = temp_prison; } } } if (prison) prison->ResetDoorOrButton(); else TC_LOG_ERROR("scripts", "npc_unworthy_initiateAI: unable to find prison!"); } break; case PHASE_TO_EQUIP: if (wait_timer) { if (wait_timer > diff) wait_timer -= diff; else { me->GetMotionMaster()->MovePoint(1, anchorX, anchorY, me->GetPositionZ()); //TC_LOG_DEBUG("scripts", "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); me->SetReactState(REACT_AGGRESSIVE); 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(1s, GCD_CAST); events.ScheduleEvent(EVENT_ICY_TOUCH, 5s, GCD_CAST); break; case EVENT_PLAGUE_STRIKE: DoCastVictim(SPELL_PLAGUE_STRIKE); events.DelayEvents(1s, GCD_CAST); events.ScheduleEvent(EVENT_PLAGUE_STRIKE, 5s, GCD_CAST); break; case EVENT_BLOOD_STRIKE: DoCastVictim(SPELL_BLOOD_STRIKE); events.DelayEvents(1s, GCD_CAST); events.ScheduleEvent(EVENT_BLOOD_STRIKE, 5s, GCD_CAST); break; case EVENT_DEATH_COIL: DoCastVictim(SPELL_DEATH_COIL); events.DelayEvents(1s, GCD_CAST); events.ScheduleEvent(EVENT_DEATH_COIL, 5s, GCD_CAST); break; } } break; default: break; } } }; CreatureAI* GetAI(Creature* creature) const override { return new npc_unworthy_initiateAI(creature); } }; 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 const& guid, int32 id) override { if (id != DATA_PRISONER_GUID) return; 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") { } struct go_acherus_soul_prisonAI : public GameObjectAI { go_acherus_soul_prisonAI(GameObject* go) : GameObjectAI(go) { } bool OnGossipHello(Player* player) override { if (Creature* anchor = me->FindNearestCreature(29521, 15)) { ObjectGuid prisonerGUID = anchor->AI()->GetGUID(DATA_PRISONER_GUID); if (!prisonerGUID.IsEmpty()) if (Creature* prisoner = ObjectAccessor::GetCreature(*player, prisonerGUID)) ENSURE_AI(npc_unworthy_initiate::npc_unworthy_initiateAI, prisoner->AI())->EventStart(anchor, player); } return false; } }; GameObjectAI* GetAI(GameObject* go) const override { return new go_acherus_soul_prisonAI(go); } }; // 51519 - Death Knight Initiate Visual class spell_death_knight_initiate_visual : public SpellScript { 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, GetSpell()); target->LoadEquipment(); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_death_knight_initiate_visual::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; /*###### ## 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 }; static constexpr uint8 const EyeOfAcherusPathSize = 4; G3D::Vector3 const EyeOfAcherusPath[EyeOfAcherusPathSize] = { { 2361.21f, -5660.45f, 496.744f }, { 2341.571f, -5672.797f, 538.3942f }, { 1957.4f, -5844.1f, 273.867f }, { 1758.01f, -5876.79f, 166.867f } }; struct npc_eye_of_acherus : public ScriptedAI { npc_eye_of_acherus(Creature* creature) : ScriptedAI(creature) { creature->SetDisplayFromModel(0); creature->SetReactState(REACT_PASSIVE); if (creature->GetCharmInfo()) creature->GetCharmInfo()->InitPossessCreateSpells(); } void InitializeAI() override { DoCastSelf(SPELL_ROOT_SELF); DoCastSelf(SPELL_EYE_OF_ACHERUS_VISUAL); _events.ScheduleEvent(EVENT_ANNOUNCE_LAUNCH_TO_DESTINATION, 7s); } 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, 1s + 200ms); 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: { std::function initializer = [=, me = me](Movement::MoveSplineInit& init) { Movement::PointsArray path(EyeOfAcherusPath, EyeOfAcherusPath + EyeOfAcherusPathSize); init.MovebyPath(path); init.SetFly(); if (Unit* owner = me->GetCharmerOrOwner()) init.SetVelocity(owner->GetSpeed(MOVE_RUN)); }; me->GetMotionMaster()->LaunchMoveSpline(std::move(initializer), POINT_NEW_AVALON, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE); break; } case EVENT_GRANT_CONTROL: me->RemoveAurasDueToSpell(SPELL_ROOT_SELF); DoCastSelf(SPELL_EYE_OF_ACHERUS_FLIGHT); me->RemoveAurasDueToSpell(SPELL_EYE_OF_ACHERUS_FLIGHT_BOOST); if (Unit* owner = me->GetCharmerOrOwner()) Talk(SAY_EYE_UNDER_CONTROL, owner); 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); _events.ScheduleEvent(EVENT_GRANT_CONTROL, 2s + 500ms); break; default: break; } } private: EventMap _events; }; /*###### ## npc_death_knight_initiate ######*/ enum Spells_DKI { SPELL_DUEL = 52996, //SPELL_DUEL_TRIGGERED = 52990, SPELL_DUEL_VICTORY = 52994, SPELL_DUEL_FLAG = 52991, SPELL_GROVEL = 7267, }; enum Says_VBM { SAY_DUEL = 0, }; enum Misc_VBN { QUEST_DEATH_CHALLENGE = 12733 }; enum Paths_VBN { PATH_DEATH_KNIGHT_INITIATE = 10361360, PATH_DEATH_KNIGHT_INITIATE2 = 10361440, PATH_DEATH_KNIGHT_INITIATE3 = 10362320, PATH_DEATH_KNIGHT_INITIATE4 = 10362400, PATH_DEATH_KNIGHT_INITIATE5 = 10362480, PATH_DEATH_KNIGHT_INITIATE6 = 10363520, PATH_DEATH_KNIGHT_INITIATE7 = 10363680, PATH_DEATH_KNIGHT_INITIATE8 = 10363760, }; class npc_death_knight_initiate : public CreatureScript { public: npc_death_knight_initiate() : CreatureScript("npc_death_knight_initiate") { } struct npc_death_knight_initiateAI : public CombatAI { npc_death_knight_initiateAI(Creature* creature) : CombatAI(creature) { Initialize(); } void Initialize() { m_uiDuelerGUID.Clear(); m_uiDuelTimer = 5000; m_bIsDuelInProgress = false; lose = false; } bool lose; ObjectGuid m_uiDuelerGUID; uint32 m_uiDuelTimer; bool m_bIsDuelInProgress; void Reset() override { Initialize(); me->RestoreFaction(); CombatAI::Reset(); me->SetUnitFlag(UNIT_FLAG_CAN_SWIM); } void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override { if (!m_bIsDuelInProgress && spellInfo->Id == SPELL_DUEL) { m_uiDuelerGUID = caster->GetGUID(); Talk(SAY_DUEL, caster); m_bIsDuelInProgress = true; } } void DamageTaken(Unit* pDoneBy, uint32 &uiDamage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if (m_bIsDuelInProgress && pDoneBy && pDoneBy->IsControlledByPlayer()) { if (pDoneBy->GetGUID() != m_uiDuelerGUID && pDoneBy->GetOwnerGUID() != m_uiDuelerGUID) // other players cannot help uiDamage = 0; else if (uiDamage >= me->GetHealth()) { uiDamage = 0; if (!lose) { pDoneBy->RemoveGameObject(SPELL_DUEL_FLAG, true); pDoneBy->AttackStop(); me->CastSpell(pDoneBy, SPELL_DUEL_VICTORY, true); lose = true; me->CastSpell(me, SPELL_GROVEL, true); me->RestoreFaction(); } } } } void UpdateAI(uint32 uiDiff) override { if (!UpdateVictim()) { if (m_bIsDuelInProgress) { if (m_uiDuelTimer <= uiDiff) { me->SetFaction(FACTION_UNDEAD_SCOURGE_2); if (Unit* unit = ObjectAccessor::GetUnit(*me, m_uiDuelerGUID)) AttackStart(unit); } else m_uiDuelTimer -= uiDiff; } return; } if (m_bIsDuelInProgress) { if (lose) { if (!me->HasAura(SPELL_GROVEL)) EnterEvadeMode(); return; } else if (me->GetVictim() && me->EnsureVictim()->GetTypeId() == TYPEID_PLAYER && me->EnsureVictim()->HealthBelowPct(10)) { me->EnsureVictim()->CastSpell(me->GetVictim(), SPELL_GROVEL, true); // beg me->EnsureVictim()->RemoveGameObject(SPELL_DUEL_FLAG, true); EnterEvadeMode(); return; } } /// @todo spells CombatAI::UpdateAI(uiDiff); } bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override { uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId); ClearGossipMenuFor(player); if (action == GOSSIP_ACTION_INFO_DEF) { CloseGossipMenuFor(player); if (player->IsInCombat() || me->IsInCombat()) return true; if (m_bIsDuelInProgress) return true; me->SetImmuneToPC(false); me->RemoveUnitFlag(UNIT_FLAG_CAN_SWIM); player->CastSpell(me, SPELL_DUEL, false); player->CastSpell(player, SPELL_DUEL_FLAG, true); } return true; } bool OnGossipHello(Player* player) override { uint32 gossipMenuId = player->GetGossipMenuForSource(me); InitGossipMenuFor(player, gossipMenuId); if (player->GetQuestStatus(QUEST_DEATH_CHALLENGE) == QUEST_STATUS_INCOMPLETE && me->IsFullHealth()) { if (player->HealthBelowPct(10)) return true; if (player->IsInCombat() || me->IsInCombat()) return true; AddGossipItemFor(player, player->GetGossipMenuForSource(me), 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF); SendGossipMenuFor(player, player->GetGossipTextId(me), me->GetGUID()); } return true; } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { switch (pathId) { case PATH_DEATH_KNIGHT_INITIATE: case PATH_DEATH_KNIGHT_INITIATE2: case PATH_DEATH_KNIGHT_INITIATE3: case PATH_DEATH_KNIGHT_INITIATE4: case PATH_DEATH_KNIGHT_INITIATE5: case PATH_DEATH_KNIGHT_INITIATE6: case PATH_DEATH_KNIGHT_INITIATE7: case PATH_DEATH_KNIGHT_INITIATE8: me->DespawnOrUnsummon(1s); break; default: break; } } }; CreatureAI* GetAI(Creature* creature) const override { return new npc_death_knight_initiateAI(creature); } }; /*###### ## npc_dark_rider_of_acherus ######*/ enum DarkRiderOfAcherus { SAY_DARK_RIDER = 0, EVENT_START_MOVING = 1, EVENT_DESPAWN_HORSE = 2, EVENT_END_SCRIPT = 3, SPELL_DESPAWN_HORSE = 52267 }; struct npc_dark_rider_of_acherus : public ScriptedAI { npc_dark_rider_of_acherus(Creature* creature) : ScriptedAI(creature) { } void JustAppeared() override { if (TempSummon* summon = me->ToTempSummon()) _horseGUID = summon->GetSummonerGUID(); _events.ScheduleEvent(EVENT_START_MOVING, 1s); } void Reset() override { _events.Reset(); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_START_MOVING: me->SetTarget(_horseGUID); if (Creature* horse = ObjectAccessor::GetCreature(*me, _horseGUID)) me->GetMotionMaster()->MoveChase(horse); _events.ScheduleEvent(EVENT_DESPAWN_HORSE, 5s); break; case EVENT_DESPAWN_HORSE: Talk(SAY_DARK_RIDER); if (Creature* horse = ObjectAccessor::GetCreature(*me, _horseGUID)) DoCast(horse, SPELL_DESPAWN_HORSE, true); _events.ScheduleEvent(EVENT_END_SCRIPT, 2s); break; case EVENT_END_SCRIPT: me->DespawnOrUnsummon(); break; default: break; } } } void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override { if (spellInfo->Id == SPELL_DESPAWN_HORSE && target->GetGUID() == _horseGUID) if (Creature* creature = target->ToCreature()) creature->DespawnOrUnsummon(2s); } private: ObjectGuid _horseGUID; EventMap _events; }; /*###### ## npc_salanar_the_horseman ######*/ enum SalanarTheHorseman { SALANAR_SAY = 0, QUEST_INTO_REALM_OF_SHADOWS = 12687, SPELL_EFFECT_STOLEN_HORSE = 52263, SPELL_DELIVER_STOLEN_HORSE = 52264, SPELL_CALL_DARK_RIDER = 52266, SPELL_EFFECT_OVERTAKE = 52349, SPELL_REALM_OF_SHADOWS = 52693 }; class npc_salanar_the_horseman : public CreatureScript { public: npc_salanar_the_horseman() : CreatureScript("npc_salanar_the_horseman") { } struct npc_salanar_the_horsemanAI : public ScriptedAI { npc_salanar_the_horsemanAI(Creature* creature) : ScriptedAI(creature) { } void MoveInLineOfSight(Unit* who) override { ScriptedAI::MoveInLineOfSight(who); if (who->GetTypeId() == TYPEID_UNIT && who->IsVehicle() && me->IsWithinDistInMap(who, 5.0f)) { if (Unit* charmer = who->GetCharmer()) { if (Player* player = charmer->ToPlayer()) { if (player->GetQuestStatus(QUEST_INTO_REALM_OF_SHADOWS) == QUEST_STATUS_INCOMPLETE) { player->GroupEventHappens(QUEST_INTO_REALM_OF_SHADOWS, me); Talk(SALANAR_SAY); charmer->RemoveAurasDueToSpell(SPELL_EFFECT_OVERTAKE); if (Creature* creature = who->ToCreature()) { creature->DespawnOrUnsummon(); //creature->Respawn(true); } } player->RemoveAurasDueToSpell(SPELL_REALM_OF_SHADOWS); } } } } }; CreatureAI* GetAI(Creature* creature) const override { return new npc_salanar_the_horsemanAI(creature); } }; enum HorseSeats { SEAT_ID_0 = 0 }; // 52265 - Repo class spell_stable_master_repo : public AuraScript { void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { Creature* creature = GetTarget()->ToCreature(); if (!creature) return; if (Vehicle* vehicleKit = creature->GetVehicleKit()) if (Unit* passenger = vehicleKit->GetPassenger(SEAT_ID_0)) GetCaster()->EngageWithTarget(passenger); creature->DespawnOrUnsummon(1s); } void Register() override { AfterEffectApply += AuraEffectApplyFn(spell_stable_master_repo::AfterApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); } }; // 52264 - Deliver Stolen Horse class spell_deliver_stolen_horse : public SpellScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_DELIVER_STOLEN_HORSE, SPELL_EFFECT_STOLEN_HORSE }); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { Unit* target = GetHitUnit(); target->RemoveAurasDueToSpell(SPELL_EFFECT_STOLEN_HORSE); Unit* caster = GetCaster(); caster->RemoveAurasDueToSpell(SPELL_EFFECT_STOLEN_HORSE); caster->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); caster->SetFaction(FACTION_FRIENDLY); caster->CastSpell(caster, SPELL_CALL_DARK_RIDER, true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_deliver_stolen_horse::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_KILL_CREDIT2); } }; /*###### ## npc_ros_dark_rider ######*/ class npc_ros_dark_rider : public CreatureScript { public: npc_ros_dark_rider() : CreatureScript("npc_ros_dark_rider") { } CreatureAI* GetAI(Creature* creature) const override { return new npc_ros_dark_riderAI(creature); } struct npc_ros_dark_riderAI : public ScriptedAI { npc_ros_dark_riderAI(Creature* creature) : ScriptedAI(creature) { } void JustEngagedWith(Unit* /*who*/) override { me->ExitVehicle(); } void Reset() override { Creature* deathcharger = me->FindNearestCreature(28782, 30); if (!deathcharger) return; deathcharger->RestoreFaction(); deathcharger->RemoveNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); deathcharger->SetUninteractible(true); if (!me->GetVehicle() && deathcharger->IsVehicle() && deathcharger->GetVehicleKit()->HasEmptySeat(0)) me->EnterVehicle(deathcharger); } void JustDied(Unit* killer) override { Creature* deathcharger = me->FindNearestCreature(28782, 30); if (!deathcharger || !killer) return; if (killer->GetTypeId() == TYPEID_PLAYER && deathcharger->GetTypeId() == TYPEID_UNIT && deathcharger->IsVehicle()) { deathcharger->SetNpcFlag(UNIT_NPC_FLAG_SPELLCLICK); deathcharger->SetUninteractible(false); deathcharger->SetFaction(FACTION_SCARLET_CRUSADE_2); } } }; }; // correct way: 52312 52314 52555 ... enum TheGiftThatKeepsOnGiving { SAY_LINE_0 = 0, NPC_GHOULS = 28845, NPC_GHOSTS = 28846, }; 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) { } void MoveInLineOfSight(Unit* who) override { ScriptedAI::MoveInLineOfSight(who); if (who->GetEntry() == NPC_GHOULS && 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); /// @todo Creatures must not be removed, but, must instead // stand next to Gothik and be commanded into the pit // and dig into the ground. creature->DespawnOrUnsummon(); if (player->GetQuestStatus(12698) == QUEST_STATUS_COMPLETE) owner->RemoveAllMinionsByEntry(NPC_GHOSTS); } } } } }; }; struct npc_scarlet_ghoul : public ScriptedAI { npc_scarlet_ghoul(Creature* creature) : ScriptedAI(creature) { me->SetReactState(REACT_DEFENSIVE); } void JustAppeared() override { CreatureAI::JustAppeared(); if (urand(0, 1)) if (Unit* owner = me->GetOwner()) Talk(SAY_LINE_0, owner); } void FindMinions(Unit* owner) { std::list MinionList; owner->GetAllMinionsByEntry(MinionList, NPC_GHOULS); if (!MinionList.empty()) { for (Creature* creature : MinionList) { if (creature->GetOwner()->GetGUID() == me->GetOwner()->GetGUID()) { if (creature->IsInCombat() && creature->getAttackerForHelper()) { AttackStart(creature->getAttackerForHelper()); } } } } } void UpdateAI(uint32 /*diff*/) override { if (!me->IsInCombat()) { if (Unit* owner = me->GetOwner()) { Player* plrOwner = owner->ToPlayer(); if (plrOwner && plrOwner->IsInCombat()) { Unit* newTarget = plrOwner->getAttackerForHelper(); if (newTarget && newTarget->GetEntry() == NPC_GHOSTS) AttackStart(newTarget); else FindMinions(owner); } } } if (!UpdateVictim()) return; } bool CanAIAttack(Unit const* target) const override { return target->GetEntry() == NPC_GHOSTS; } }; enum GiftOfTheHarvester { SPELL_GHOUL_TRANFORM = 52490, SPELL_GHOST_TRANSFORM = 52505 }; // 52479 - Gift of the Harvester class spell_gift_of_the_harvester : public SpellScript { bool Validate(SpellInfo const* /*spell*/) override { return ValidateSpellInfo( { SPELL_GHOUL_TRANFORM, SPELL_GHOST_TRANSFORM }); } void HandleScriptEffect(SpellEffIndex /*effIndex*/) { Unit* originalCaster = GetOriginalCaster(); Unit* target = GetHitUnit(); if (originalCaster && target) originalCaster->CastSpell(target, RAND(SPELL_GHOUL_TRANFORM, SPELL_GHOST_TRANSFORM), true); } void Register() override { OnEffectHitTarget += SpellEffectFn(spell_gift_of_the_harvester::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; /*###### ## Quest 12842: Runeforging: Preparation For Battle ######*/ enum Runeforging { SPELL_RUNEFORGING_CREDIT = 54586, QUEST_RUNEFORGING = 12842 }; /* 53343 - Rune of Razorice 53344 - Rune of the Fallen Crusader 62158 - Rune of the Stoneskin Gargoyle 326805 - Rune of Sanguination 326855 - Rune of Spellwarding 326911 - Rune of Hysteria 326977 - Rune of Unending Thirst 327082 - Rune of the Apocalypse */ class spell_chapter1_runeforging_credit : public SpellScript { bool Validate(SpellInfo const* /*spellInfo*/) override { return ValidateSpellInfo({ SPELL_RUNEFORGING_CREDIT }) && sObjectMgr->GetQuestTemplate(QUEST_RUNEFORGING); } void HandleDummy(SpellEffIndex /*effIndex*/) { if (Player* caster = GetCaster()->ToPlayer()) if (caster->GetQuestStatus(QUEST_RUNEFORGING) == QUEST_STATUS_INCOMPLETE) caster->CastSpell(caster, SPELL_RUNEFORGING_CREDIT); } void Register() override { OnEffectHit += SpellEffectFn(spell_chapter1_runeforging_credit::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY); } }; enum HearthglenCrusaderPaths : uint32 { PATH_HEARTHGLEN_CRUSADER_DESPAWN = 10445360, PATH_HEARTHGLEN_CRUSADER_DESPAWN2 = 10445600, PATH_HEARTHGLEN_CRUSADER_DESPAWN3 = 10448640, PATH_HEARTHGLEN_CRUSADER_DESPAWN4 = 10449200, PATH_HEARTHGLEN_CRUSADER_DESPAWN5 = 10452240, PATH_HEARTHGLEN_CRUSADER_DESPAWN6 = 10452880, PATH_HEARTHGLEN_CRUSADER_DESPAWN7 = 10452960, PATH_HEARTHGLEN_CRUSADER_DESPAWN8 = 10453040, PATH_HEARTHGLEN_CRUSADER_DESPAWN9 = 10453520, PATH_HEARTHGLEN_CRUSADER_DESPAWN10 = 10453680, PATH_HEARTHGLEN_CRUSADER_DESPAWN11 = 10454000, PATH_HEARTHGLEN_CRUSADER_DESPAWN12 = 10454080, PATH_HEARTHGLEN_CRUSADER_DESPAWN13 = 10454160, PATH_HEARTHGLEN_CRUSADER_DESPAWN14 = 10454320, PATH_HEARTHGLEN_CRUSADER_DESPAWN15 = 10454560, PATH_HEARTHGLEN_CRUSADER_DESPAWN16 = 10459440, PATH_HEARTHGLEN_CRUSADER_DESPAWN17 = 10460320, PATH_HEARTHGLEN_CRUSADER_DESPAWN18 = 10463040, PATH_HEARTHGLEN_CRUSADER_DESPAWN19 = 10463120, PATH_HEARTHGLEN_CRUSADER_DESPAWN20 = 10463280, PATH_HEARTHGLEN_CRUSADER_DESPAWN21 = 10463360, PATH_HEARTHGLEN_CRUSADER_DESPAWN22 = 10463520, PATH_HEARTHGLEN_CRUSADER_DESPAWN23 = 10463680, PATH_HEARTHGLEN_CRUSADER_DESPAWN24 = 10463840, PATH_HEARTHGLEN_CRUSADER_DESPAWN25 = 10464080, PATH_HEARTHGLEN_CRUSADER_DESPAWN26 = 10464160, PATH_HEARTHGLEN_CRUSADER_DESPAWN27 = 10464240, PATH_HEARTHGLEN_CRUSADER_DESPAWN28 = 10464320, PATH_HEARTHGLEN_CRUSADER_DESPAWN29 = 10464400, PATH_HEARTHGLEN_CRUSADER_DESPAWN30 = 10464480, PATH_HEARTHGLEN_CRUSADER_DESPAWN31 = 10464720, PATH_HEARTHGLEN_CRUSADER_DESPAWN32 = 10464800, PATH_HEARTHGLEN_CRUSADER_DESPAWN33 = 10464880, PATH_HEARTHGLEN_CRUSADER_DESPAWN34 = 10464960, PATH_HEARTHGLEN_CRUSADER_DESPAWN35 = 10465040, PATH_HEARTHGLEN_CRUSADER_DESPAWN36 = 10465520, PATH_HEARTHGLEN_CRUSADER_DESPAWN37 = 10465600, PATH_HEARTHGLEN_CRUSADER_DESPAWN38 = 10466000, PATH_HEARTHGLEN_CRUSADER_DESPAWN39 = 10466160, PATH_HEARTHGLEN_CRUSADER_DESPAWN40 = 10466320, PATH_HEARTHGLEN_CRUSADER_DESPAWN41 = 10466400, }; // 29102 - Hearthglen Crusader // 29103 - Tirisfal Crusader struct npc_hearthglen_crusader : public ScriptedAI { npc_hearthglen_crusader(Creature* creature) : ScriptedAI(creature), _minimumRange(0) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(creature->m_spells[0], creature->GetMap()->GetDifficultyID()); if (!spellInfo) return; _minimumRange = spellInfo->GetMinRange(false); if (!_minimumRange) _minimumRange = MELEE_RANGE; creature->m_CombatDistance = spellInfo->GetMaxRange(false); creature->m_SightDistance = creature->m_CombatDistance; } void AttackStart(Unit* who) override { if (!who) return; if (me->IsWithinCombatRange(who, _minimumRange)) { if (me->Attack(who, true) && !who->IsFlying()) me->GetMotionMaster()->MoveChase(who); } else { if (me->Attack(who, false) && !who->IsFlying()) me->GetMotionMaster()->MoveChase(who, me->m_CombatDistance); } if (who->IsFlying()) me->GetMotionMaster()->MoveIdle(); } void UpdateAI(uint32 /*diff*/) override { if (!UpdateVictim()) return; if (!me->IsWithinCombatRange(me->GetVictim(), _minimumRange)) DoSpellAttackIfReady(me->m_spells[0]); } void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { switch (pathId) { case PATH_HEARTHGLEN_CRUSADER_DESPAWN: case PATH_HEARTHGLEN_CRUSADER_DESPAWN2: case PATH_HEARTHGLEN_CRUSADER_DESPAWN3: case PATH_HEARTHGLEN_CRUSADER_DESPAWN4: case PATH_HEARTHGLEN_CRUSADER_DESPAWN5: case PATH_HEARTHGLEN_CRUSADER_DESPAWN6: case PATH_HEARTHGLEN_CRUSADER_DESPAWN7: case PATH_HEARTHGLEN_CRUSADER_DESPAWN8: case PATH_HEARTHGLEN_CRUSADER_DESPAWN9: case PATH_HEARTHGLEN_CRUSADER_DESPAWN10: case PATH_HEARTHGLEN_CRUSADER_DESPAWN11: case PATH_HEARTHGLEN_CRUSADER_DESPAWN12: case PATH_HEARTHGLEN_CRUSADER_DESPAWN13: case PATH_HEARTHGLEN_CRUSADER_DESPAWN14: case PATH_HEARTHGLEN_CRUSADER_DESPAWN15: case PATH_HEARTHGLEN_CRUSADER_DESPAWN16: case PATH_HEARTHGLEN_CRUSADER_DESPAWN17: case PATH_HEARTHGLEN_CRUSADER_DESPAWN18: case PATH_HEARTHGLEN_CRUSADER_DESPAWN19: case PATH_HEARTHGLEN_CRUSADER_DESPAWN20: case PATH_HEARTHGLEN_CRUSADER_DESPAWN21: case PATH_HEARTHGLEN_CRUSADER_DESPAWN22: case PATH_HEARTHGLEN_CRUSADER_DESPAWN23: case PATH_HEARTHGLEN_CRUSADER_DESPAWN24: case PATH_HEARTHGLEN_CRUSADER_DESPAWN25: case PATH_HEARTHGLEN_CRUSADER_DESPAWN26: case PATH_HEARTHGLEN_CRUSADER_DESPAWN27: case PATH_HEARTHGLEN_CRUSADER_DESPAWN28: case PATH_HEARTHGLEN_CRUSADER_DESPAWN29: case PATH_HEARTHGLEN_CRUSADER_DESPAWN30: case PATH_HEARTHGLEN_CRUSADER_DESPAWN31: case PATH_HEARTHGLEN_CRUSADER_DESPAWN32: case PATH_HEARTHGLEN_CRUSADER_DESPAWN33: case PATH_HEARTHGLEN_CRUSADER_DESPAWN34: case PATH_HEARTHGLEN_CRUSADER_DESPAWN35: case PATH_HEARTHGLEN_CRUSADER_DESPAWN36: case PATH_HEARTHGLEN_CRUSADER_DESPAWN37: case PATH_HEARTHGLEN_CRUSADER_DESPAWN38: case PATH_HEARTHGLEN_CRUSADER_DESPAWN39: case PATH_HEARTHGLEN_CRUSADER_DESPAWN40: case PATH_HEARTHGLEN_CRUSADER_DESPAWN41: me->DespawnOrUnsummon(1s); break; default: break; } } private: float _minimumRange; }; void AddSC_the_scarlet_enclave_c1() { new npc_unworthy_initiate(); new npc_unworthy_initiate_anchor(); new go_acherus_soul_prison(); RegisterSpellScript(spell_death_knight_initiate_visual); RegisterCreatureAI(npc_eye_of_acherus); new npc_death_knight_initiate(); RegisterCreatureAI(npc_dark_rider_of_acherus); new npc_salanar_the_horseman(); RegisterSpellScript(spell_stable_master_repo); RegisterSpellScript(spell_deliver_stolen_horse); new npc_ros_dark_rider(); new npc_dkc1_gothik(); RegisterCreatureAI(npc_scarlet_ghoul); RegisterSpellScript(spell_gift_of_the_harvester); RegisterSpellScript(spell_chapter1_runeforging_credit); RegisterCreatureAI(npc_hearthglen_crusader); }