diff options
author | Jason Dove <1695733+jasongdove@users.noreply.github.com> | 2025-05-30 04:04:07 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-30 11:04:07 +0200 |
commit | a50e1c7ab3f6cdbb60509fab82c00a8eb6eb6f7d (patch) | |
tree | 1222391f1e09259c6677e21c54356bb356f137ba /src | |
parent | e39dddec0b805db4f11e08dcf7e22e0f003ca0e1 (diff) |
Scripts/RedridgeMountains: Implement Quest "Saving Foreman Oslow" (#30947)
Diffstat (limited to 'src')
-rw-r--r-- | src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp | 689 |
1 files changed, 560 insertions, 129 deletions
diff --git a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp index 19db563152d..299cd527fec 100644 --- a/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp +++ b/src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp @@ -22,17 +22,82 @@ SDComment: Script Data End */ #include "ScriptMgr.h" -#include "ScriptedCreature.h" +#include "Containers.h" +#include "G3DPosition.hpp" #include "MotionMaster.h" +#include "MoveSplineInit.h" #include "ObjectAccessor.h" +#include "Player.h" +#include "ScriptedCreature.h" +#include "SpellAuras.h" +#include "SpellInfo.h" +#include "SpellScript.h" +#include "TemporarySummon.h" #include "WaypointDefines.h" +#include "World.h" +#include <algorithm> -enum DumpyKeeshan +enum RedridgeSpellData { - NPC_BIGEARL = 43248, + SPELL_APPLY_QUEST_INVIS_ZONE_3 = 80815, // Used by npc's in Lakeshire Inn + SPELL_APPLY_QUEST_INVIS_ZONE_4 = 80816, // Used by npc's in Lakeshire Inn + + SPELL_APPLY_QUEST_INVIS_ZONE_19 = 82099, // Used by npc's in Lakeshire Townhall + + SPELL_CONTROL_ETTIN = 80704, + SPELL_CONTROL_ETTIN_2 = 80702, + SPELL_LIFT_HUGE_BOULDER = 80739, + SPELL_LIFT_BOULDER_RIDE = 82566, + SPELL_CANYON_ETTIN_SPAWN_SPELL = 82558, + SPELL_BOULDER_AURA = 82556, + SPELL_DESPAWN_KILL_CREDIT = 228623, + SPELL_EJECT_PASSENGER_1 = 80743, + SPELL_CANYON_ETTIN_DESPAWN = 82561, + SPELL_DESPAWN_ETTIN = 80707, +}; - SPELL_APPLY_QUEST_INVIS_ZONE_3 = 80815, // Used by npc's in Lakeshire Inn - SPELL_APPLY_QUEST_INVIS_ZONE_4 = 80816 // Used by npc's in Lakeshire Inn +enum RedridgeCreatureData +{ + NPC_FOREMAN_OSLOW = 341, + NPC_BRIDGE_WORKER_ALEX = 653, + NPC_BRIDGE_WORKER_TRENT = 648, + NPC_BRIDGE_WORKER_DMITRI = 649, + NPC_BRIDGE_WORKER_JESS = 650, + NPC_BRIDGE_WORKER_DANIEL = 651, + NPC_BRIDGE_WORKER_MATTHEW = 652, + NPC_CANYON_ETTIN = 43094, + NPC_SUBDUED_CANYON_ETTIN = 43197, + NPC_HUGE_BOULDER = 43196, + + NPC_BIGEARL = 43248, +}; + +enum RedridgeTalks +{ + TALK_OSLOW_IDLE = 0, + + TALK_ALEX_HEAVE = 1, + TALK_ALEX_DAMN = 2, + TALK_ALEX_PUSH = 4, + TALK_ALEX_SCARED = 5, + + TALK_WORKERS_HO = 0, + + TALK_MATTHEW_IM_PUSHING = 1, + TALK_MATTHEW_SCARED = 2, + + TALK_TRENT_SCARED = 1, + + TALK_DMITRI_SCARED = 1, + + TALK_JESS_SCARED = 1, + + TALK_DANIEL_SCARED = 1, + + TALK_NOT_SO_HEAVY = 0, + TALK_WHERE_THROW = 1, + TALK_THROW_IN_WATER = 2, + TALK_BYE = 3 }; /*###### @@ -112,148 +177,513 @@ public: } }; -/*###### -# npc_bridge_worker_alex "Used by entry 653" "Script not fully complete. Needs scripting added for move rock will be updated in future." -######*/ - -enum BridgeWorkerAlex +enum RedridgeHugeBoulder { - EVENT_STORE_GUIDS = 1, - EVENT_OSLOW_SAY = 2, - EVENT_ALEX_SAY = 3, - EVENT_WORKERS_SAY = 4, - EVENT_ALEX_SAY_PUSH = 5, - EVENT_MATTHEW_SAY = 6, - - NPC_OSLOW = 341, - NPC_TRENT = 648, - NPC_DIMITRI = 649, - NPC_JESS = 650, - NPC_DANIEL = 651, - NPC_MATTHEW = 652, - - SAY_OSLOW = 0, - SAY_ALEX_PUT = 0, - SAY_ALEX_HEAVE = 1, - SAY_ALEX_DAMN = 2, - SAY_ALEX_HANGON = 3, - SAY_ALEX_PUSH = 4, - SAY_WORKERS_HO = 0, - SAY_MATTHEW_IM_PUSHING = 1 + EVENT_STORE_GUIDS = 1, + EVENT_OSLOW_IDLE_TALK = 2, + EVENT_ALEX_IDLE_TALK = 3, + EVENT_WORKERS_RESPONSE = 4, + EVENT_ALEX_SAY_PUSH = 5, + EVENT_MATTHEW_PUSH_RESPONSE = 6, + EVENT_REPOSITION = 7, + EVENT_BRIDGE_WORKERS_COWER = 8, + EVENT_OSLOW_GET_UP = 9, + EVENT_OSLOW_STUN = 10, + EVENT_ETTIN_LINE_1 = 11, + EVENT_ETTIN_LINE_2 = 12, + EVENT_MOVE_TO_WATER = 13, + EVENT_THROW_BOULDER = 14, + EVENT_PATH_AWAY = 15, + EVENT_DONE, + + ACTION_OSLOW_GET_UP = 0, + ACTION_COWER = 1, + ACTION_DONE, + + PATH_ETTIN_TO_WATER = 4319700, + PATH_ETTIN_UP_HILL = 4319701, + + POINT_NEAR_BOULDER = 1, + POINT_NEAR_WATER = 2, + POINT_UP_PATH = 3, }; -class npc_bridge_worker_alex : public CreatureScript +constexpr Position TrentRepositionPos = { -9281.44f, -2285.27f, 67.5123f, 6.0213f }; +constexpr Position DmitriRepositionPos = { -9282.8f, -2293.28f, 67.5089f, 6.2657f }; +constexpr Position JessRepositionPos = { -9282.27f, -2290.95f, 67.5319f, 6.0737f }; +constexpr Position DanielRepositionPos = { -9281.77f, -2287.55f, 67.5869f, 6.0911f }; +constexpr Position MatthewRepositionPos = { -9280.71f, -2283.21f, 67.5747f, 6.0737f }; +constexpr Position AlexRepositionPos = { -9279.86f, -2281.42f, 67.5854f, 5.7421f }; + +// 43196 - Huge Boulder +struct npc_redridge_huge_boulder : public CreatureAI { -public: - npc_bridge_worker_alex() : CreatureScript("npc_bridge_worker_alex") { } + npc_redridge_huge_boulder(Creature* creature) : CreatureAI(creature) { } - struct npc_bridge_worker_alexAI : public ScriptedAI + void Reset() override { - npc_bridge_worker_alexAI(Creature* creature) : ScriptedAI(creature) { } + _events.Reset(); + _oslowGUID.Clear(); + _alexGUID.Clear(); + _trentGUID.Clear(); + _dmitriGUID.Clear(); + _jessGUID.Clear(); + _danielGUID.Clear(); + _matthewGUID.Clear(); + _events.ScheduleEvent(EVENT_STORE_GUIDS, 5s); + } - void Reset() override - { - _events.Reset(); - _oslowGUID.Clear(); - _trentGUID.Clear(); - _dimitriGUID.Clear(); - _jessGUID.Clear(); - _danielGUID.Clear(); - _matthewGUID.Clear(); - _events.ScheduleEvent(EVENT_STORE_GUIDS, Seconds(5)); - _events.ScheduleEvent(EVENT_OSLOW_SAY, Seconds(40), Seconds(50)); - _events.ScheduleEvent(EVENT_ALEX_SAY, Seconds(22), Seconds(30)); - } + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spell) override + { + if (spell->Id != SPELL_LIFT_BOULDER_RIDE) + return; - void UpdateAI(uint32 diff) override - { - _events.Update(diff); + _events.Reset(); + _events.ScheduleEvent(EVENT_REPOSITION, 0ms); + } - if (!UpdateVictim()) + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) { - while (uint32 eventId = _events.ExecuteEvent()) + case EVENT_STORE_GUIDS: { - switch (eventId) + if (Creature const* oslow = me->FindNearestCreature(NPC_FOREMAN_OSLOW, 10.0f, true)) + _oslowGUID = oslow->GetGUID(); + if (Creature const* alex = me->FindNearestCreature(NPC_BRIDGE_WORKER_ALEX, 10.0f, true)) + _alexGUID = alex->GetGUID(); + if (Creature const* trent = me->FindNearestCreature(NPC_BRIDGE_WORKER_TRENT, 10.0f, true)) + _trentGUID = trent->GetGUID(); + if (Creature const* dimitri = me->FindNearestCreature(NPC_BRIDGE_WORKER_DMITRI, 10.0f, true)) + _dmitriGUID = dimitri->GetGUID(); + if (Creature const* jess = me->FindNearestCreature(NPC_BRIDGE_WORKER_JESS, 10.0f, true)) + _jessGUID = jess->GetGUID(); + if (Creature const* daniel = me->FindNearestCreature(NPC_BRIDGE_WORKER_DANIEL, 10.0f, true)) + _danielGUID = daniel->GetGUID(); + if (Creature const* matthew = me->FindNearestCreature(NPC_BRIDGE_WORKER_MATTHEW, 10.0f, true)) + _matthewGUID = matthew->GetGUID(); + + if (!_oslowGUID || !_alexGUID || !_trentGUID || !_dmitriGUID || !_jessGUID || !_danielGUID || !_matthewGUID) + _events.Repeat(1s); + else { - case EVENT_STORE_GUIDS: - if (Creature* oslow = me->FindNearestCreature(NPC_OSLOW, 5.0f, true)) - _oslowGUID = oslow->GetGUID(); - if (Creature* trent = me->FindNearestCreature(NPC_TRENT, 5.0f, true)) - _trentGUID = trent->GetGUID(); - if (Creature* dimitri = me->FindNearestCreature(NPC_DIMITRI, 5.0f, true)) - _dimitriGUID = dimitri->GetGUID(); - if (Creature* jess = me->FindNearestCreature(NPC_JESS, 5.0f, true)) - _jessGUID = jess->GetGUID(); - if (Creature* daniel = me->FindNearestCreature(NPC_DANIEL, 5.0f, true)) - _danielGUID = daniel->GetGUID(); - if (Creature* matthew = me->FindNearestCreature(NPC_MATTHEW, 5.0f, true)) - _matthewGUID = matthew->GetGUID(); - break; - case EVENT_OSLOW_SAY: - if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID)) - oslow->AI()->Talk(SAY_OSLOW); - _events.Repeat(Seconds(40), Seconds(50)); - break; - case EVENT_ALEX_SAY: - switch (urand(0, 3)) + _events.ScheduleEvent(EVENT_OSLOW_IDLE_TALK, 45s, 60s); + _events.ScheduleEvent(EVENT_ALEX_IDLE_TALK, 20s, 30s); + } + break; + } + case EVENT_OSLOW_IDLE_TALK: + { + if (Creature const* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID)) + oslow->AI()->Talk(TALK_OSLOW_IDLE); + _events.Repeat(45s, 60s); + break; + } + case EVENT_ALEX_IDLE_TALK: + { + if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID)) + { + switch (uint32 text = urand(0, 3)) { - case 0: - Talk(SAY_ALEX_PUT); - break; - case 1: - Talk(SAY_ALEX_HEAVE); - _events.ScheduleEvent(EVENT_WORKERS_SAY, Seconds(2)); - break; - case 2: - Talk(SAY_ALEX_DAMN); - _events.ScheduleEvent(EVENT_ALEX_SAY_PUSH, Seconds(4)); - break; - case 3: - Talk(SAY_ALEX_HANGON); - break; + case TALK_ALEX_HEAVE: + alex->AI()->Talk(TALK_ALEX_HEAVE); + _events.ScheduleEvent(EVENT_WORKERS_RESPONSE, 1s); + break; + case TALK_ALEX_DAMN: + alex->AI()->Talk(TALK_ALEX_DAMN); + _events.ScheduleEvent(EVENT_ALEX_SAY_PUSH, 3s); + break; + default: + alex->AI()->Talk(text); + _events.Repeat(10s); + break; + } + } + break; + } + case EVENT_WORKERS_RESPONSE: + { + if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID)) + { + if (Creature const* trent = ObjectAccessor::GetCreature(*me, _trentGUID)) + trent->AI()->Talk(TALK_WORKERS_HO, alex); + if (Creature const* dmitri = ObjectAccessor::GetCreature(*me, _dmitriGUID)) + dmitri->AI()->Talk(TALK_WORKERS_HO, alex); + if (Creature const* jess = ObjectAccessor::GetCreature(*me, _jessGUID)) + jess->AI()->Talk(TALK_WORKERS_HO, alex); + if (Creature const* daniel = ObjectAccessor::GetCreature(*me, _danielGUID)) + daniel->AI()->Talk(TALK_WORKERS_HO, alex); + if (Creature const* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID)) + matthew->AI()->Talk(TALK_WORKERS_HO, alex); + } + _events.ScheduleEvent(EVENT_ALEX_IDLE_TALK, 20s, 30s); + break; + } + case EVENT_ALEX_SAY_PUSH: + { + if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID)) + alex->AI()->Talk(TALK_ALEX_PUSH); + _events.ScheduleEvent(EVENT_MATTHEW_PUSH_RESPONSE, 4s); + break; + } + case EVENT_MATTHEW_PUSH_RESPONSE: + { + if (Creature const* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID)) + { + if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID)) + matthew->AI()->Talk(TALK_MATTHEW_IM_PUSHING, alex); + } + _events.ScheduleEvent(EVENT_ALEX_IDLE_TALK, 20s, 30s); + break; + } + case EVENT_REPOSITION: + { + if (Creature* trent = ObjectAccessor::GetCreature(*me, _trentGUID)) + { + trent->SetAIAnimKitId(0); + trent->GetMotionMaster()->MovePoint(0, TrentRepositionPos, true, TrentRepositionPos.GetOrientation()); + } + + if (Creature* dmitri = ObjectAccessor::GetCreature(*me, _dmitriGUID)) + { + dmitri->SetAIAnimKitId(0); + dmitri->GetMotionMaster()->MovePoint(0, DmitriRepositionPos, true, DmitriRepositionPos.GetOrientation()); + } + + if (Creature* jess = ObjectAccessor::GetCreature(*me, _jessGUID)) + { + jess->SetAIAnimKitId(0); + jess->GetMotionMaster()->MovePoint(0, JessRepositionPos, true, JessRepositionPos.GetOrientation()); + } + + if (Creature* daniel = ObjectAccessor::GetCreature(*me, _danielGUID)) + { + daniel->SetAIAnimKitId(0); + daniel->GetMotionMaster()->MovePoint(0, DanielRepositionPos, true, DanielRepositionPos.GetOrientation()); + } + + if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID)) + { + matthew->SetAIAnimKitId(0); + matthew->GetMotionMaster()->MovePoint(0, MatthewRepositionPos, true, MatthewRepositionPos.GetOrientation()); + } + + if (Creature* alex = ObjectAccessor::GetCreature(*me, _alexGUID)) + { + alex->SetAIAnimKitId(0); + alex->GetMotionMaster()->MovePoint(0, AlexRepositionPos, true, AlexRepositionPos.GetOrientation()); + } + break; + } + case EVENT_BRIDGE_WORKERS_COWER: + { + // all workers should cower + std::vector<ObjectGuid> allWorkers = { _alexGUID, _matthewGUID, _trentGUID, _dmitriGUID, _jessGUID, _danielGUID }; + for (ObjectGuid const& workerGUID : allWorkers) + if (Creature* worker = ObjectAccessor::GetCreature(*me, workerGUID)) + worker->SetEmoteState(EMOTE_STATE_COWER); + + // pick two random workers to say random scared things + Trinity::Containers::RandomResize(allWorkers, 2); + + for (ObjectGuid const workerGUID : allWorkers) + { + Creature* worker = ObjectAccessor::GetCreature(*me, workerGUID); + if (!worker) + continue; + + switch (worker->GetEntry()) + { + case NPC_BRIDGE_WORKER_ALEX: + worker->AI()->Talk(TALK_ALEX_SCARED, me); + break; + case NPC_BRIDGE_WORKER_MATTHEW: + worker->AI()->Talk(TALK_MATTHEW_SCARED, me); + break; + case NPC_BRIDGE_WORKER_TRENT: + worker->AI()->Talk(TALK_TRENT_SCARED, me); + break; + case NPC_BRIDGE_WORKER_DMITRI: + worker->AI()->Talk(TALK_DMITRI_SCARED, me); + break; + case NPC_BRIDGE_WORKER_JESS: + worker->AI()->Talk(TALK_JESS_SCARED, me); + break; + case NPC_BRIDGE_WORKER_DANIEL: + worker->AI()->Talk(TALK_DANIEL_SCARED, me); + break; + default: + break; } - _events.Repeat(Seconds(22), Seconds(30)); - break; - case EVENT_WORKERS_SAY: - if (Creature* trent = ObjectAccessor::GetCreature(*me, _trentGUID)) - trent->AI()->Talk(SAY_WORKERS_HO); - if (Creature* dimitri = ObjectAccessor::GetCreature(*me, _dimitriGUID)) - dimitri->AI()->Talk(SAY_WORKERS_HO); - if (Creature* jess = ObjectAccessor::GetCreature(*me, _jessGUID)) - jess->AI()->Talk(SAY_WORKERS_HO); - if (Creature* daniel = ObjectAccessor::GetCreature(*me, _danielGUID)) - daniel->AI()->Talk(SAY_WORKERS_HO); - if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID)) - matthew->AI()->Talk(SAY_WORKERS_HO); - break; - case EVENT_ALEX_SAY_PUSH: - Talk(SAY_ALEX_PUSH); - _events.ScheduleEvent(EVENT_MATTHEW_SAY, Seconds(4)); - break; - case EVENT_MATTHEW_SAY: - if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID)) - matthew->AI()->Talk(SAY_MATTHEW_IM_PUSHING); - break; - default: - break; } + break; + } + case EVENT_OSLOW_GET_UP: + { + if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID)) + oslow->SetStandState(UNIT_STAND_STATE_STAND); + + _events.ScheduleEvent(EVENT_OSLOW_STUN, 2s); + break; + } + case EVENT_OSLOW_STUN: + { + if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID)) + oslow->SetEmoteState(EMOTE_STATE_STUN); + break; + } + case EVENT_DONE: + { + if (Creature* alex = ObjectAccessor::GetCreature(*me, _alexGUID)) + alex->DespawnOrUnsummon(); + if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID)) + matthew->DespawnOrUnsummon(); + if (Creature* trent = ObjectAccessor::GetCreature(*me, _trentGUID)) + trent->DespawnOrUnsummon(); + if (Creature* dmitri = ObjectAccessor::GetCreature(*me, _dmitriGUID)) + dmitri->DespawnOrUnsummon(); + if (Creature* jess = ObjectAccessor::GetCreature(*me, _jessGUID)) + jess->DespawnOrUnsummon(); + if (Creature* daniel = ObjectAccessor::GetCreature(*me, _danielGUID)) + daniel->DespawnOrUnsummon(); + if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID)) + oslow->DespawnOrUnsummon(); + + _events.Reset(); + me->DespawnOrUnsummon(); + break; } + default: + break; } } + } - private: - EventMap _events; - ObjectGuid _oslowGUID; - ObjectGuid _trentGUID; - ObjectGuid _dimitriGUID; - ObjectGuid _jessGUID; - ObjectGuid _danielGUID; - ObjectGuid _matthewGUID; - }; + void DoAction(int32 const param) override + { + switch (param) + { + case ACTION_OSLOW_GET_UP: + _events.ScheduleEvent(EVENT_OSLOW_GET_UP, 500ms); + + // in case player who started event disconnects + _events.ScheduleEvent(EVENT_DONE, 120s); + break; + case ACTION_COWER: + _events.ScheduleEvent(EVENT_BRIDGE_WORKERS_COWER, 3s); + break; + case ACTION_DONE: + _events.ScheduleEvent(EVENT_DONE, 0s); + break; + default: + break; + } + } - CreatureAI* GetAI(Creature* creature) const override +private: + EventMap _events; + ObjectGuid _oslowGUID; + ObjectGuid _alexGUID; + ObjectGuid _trentGUID; + ObjectGuid _dmitriGUID; + ObjectGuid _jessGUID; + ObjectGuid _danielGUID; + ObjectGuid _matthewGUID; +}; + +constexpr Position EttinNearBoulderPosition = { -9272.053f, -2291.7463f, 68.54081f }; + +// 43197 - Subdued Canyon Ettin +struct npc_redridge_subdued_canyon_ettin : public CreatureAI +{ + npc_redridge_subdued_canyon_ettin(Creature* creature) : CreatureAI(creature) { } + + void Reset() override + { + me->SetReactState(REACT_PASSIVE); + _events.Reset(); + } + + void OnDespawn() override + { + Unit* owner = me->GetOwner(); + if (!owner) + return; + + owner->RemoveAurasDueToSpell(SPELL_CANYON_ETTIN_SPAWN_SPELL); + } + + void SpellHit(WorldObject* caster, SpellInfo const* spell) override + { + if (!caster || !caster->IsPlayer()) + return; + + switch (spell->Id) + { + case SPELL_BOULDER_AURA: + me->GetMotionMaster()->MovePoint(POINT_NEAR_BOULDER, EttinNearBoulderPosition, true, {}, {}, MovementWalkRunSpeedSelectionMode::ForceWalk); + break; + case SPELL_DESPAWN_KILL_CREDIT: + if (Player* player = ObjectAccessor::GetPlayer(*me, caster->GetGUID())) + player->RewardPlayerAndGroupAtEvent(NPC_FOREMAN_OSLOW, player); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ETTIN_LINE_1: + Talk(TALK_NOT_SO_HEAVY); + _events.ScheduleEvent(EVENT_ETTIN_LINE_2, 3s); + break; + case EVENT_ETTIN_LINE_2: + Talk(TALK_WHERE_THROW); + + if (Creature* boulder = ObjectAccessor::GetCreature(*me, _boulderGUID)) + boulder->AI()->DoAction(ACTION_COWER); + + _events.ScheduleEvent(EVENT_MOVE_TO_WATER, 9s); + break; + case EVENT_MOVE_TO_WATER: + me->GetMotionMaster()->MovePath(PATH_ETTIN_TO_WATER, false); + Talk(TALK_THROW_IN_WATER); + break; + case EVENT_THROW_BOULDER: + me->CastSpell(nullptr, SPELL_EJECT_PASSENGER_1); + _events.ScheduleEvent(EVENT_PATH_AWAY, 6s); + break; + case EVENT_PATH_AWAY: + Talk(TALK_BYE); + + if (Creature* boulder = ObjectAccessor::GetCreature(*me, _boulderGUID)) + boulder->AI()->DoAction(ACTION_DONE); + + me->GetMotionMaster()->MovePath(PATH_ETTIN_UP_HILL, false); + break; + default: + break; + } + } + } + + void MovementInform(uint32 movementType, uint32 pointId) override + { + if (movementType != POINT_MOTION_TYPE) + return; + + if (pointId == POINT_NEAR_BOULDER) + { + if (Creature const* boulder = me->FindNearestCreature(NPC_HUGE_BOULDER, 5.0f, true)) + { + _boulderGUID = boulder->GetGUID(); + me->CastSpell(nullptr, SPELL_LIFT_HUGE_BOULDER, false); + + if (Creature const* daniel = me->FindNearestCreature(NPC_BRIDGE_WORKER_DANIEL, 20.0f, true)) + me->SetFacingToObject(daniel); + + _events.ScheduleEvent(EVENT_ETTIN_LINE_1, 2500ms); + boulder->AI()->DoAction(ACTION_OSLOW_GET_UP); + } + } + } + + void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override { - return new npc_bridge_worker_alexAI(creature); + if (pathId == PATH_ETTIN_TO_WATER) + { + _events.ScheduleEvent(EVENT_THROW_BOULDER, 0s); + } + else if (pathId == PATH_ETTIN_UP_HILL) + { + me->CastSpell(nullptr, SPELL_CANYON_ETTIN_DESPAWN); + me->CastSpell(nullptr, SPELL_DESPAWN_ETTIN); + } + } + +private: + EventMap _events; + ObjectGuid _boulderGUID; +}; + +// 80704 - Control Ettin +class spell_redridge_control_ettin : public SpellScript +{ + SpellCastResult CheckCast() + { + // check for a spawn spell with a valid caster (subdued ettin) + Aura const* spawnAura = GetCaster()->GetAura(SPELL_CANYON_ETTIN_SPAWN_SPELL, [](Aura const* aura) + { + return aura->GetCaster() != nullptr; + }); + + if (spawnAura != nullptr) + { + // fail if the subdued ettin is no longer alive + if (!spawnAura->GetCaster()->IsAlive()) + return SPELL_FAILED_BAD_IMPLICIT_TARGETS; + } + else + { + // no spawn spell, so require nearby canyon ettin + if (!GetCaster()->FindNearestCreature(NPC_CANYON_ETTIN, GetSpellInfo()->GetMaxRange(), true)) + return SPELL_FAILED_OUT_OF_RANGE; + } + + return SPELL_CAST_OK; + } + + void HandleScriptEffect(SpellEffIndex /*effIndex*/) const + { + if (Unit const* target = GetHitUnit()) + { + // conditions ensure this ettin is owned by player + if (target->GetEntry() == NPC_SUBDUED_CANYON_ETTIN) + { + GetCaster()->CastSpell(nullptr, SPELL_BOULDER_AURA, false); + GetCaster()->CastSpell(nullptr, SPELL_DESPAWN_KILL_CREDIT, false); + } + else + GetCaster()->CastSpell(nullptr, SPELL_CONTROL_ETTIN_2, false); + } + } + + void Register() override + { + OnCheckCast += SpellCheckCastFn(spell_redridge_control_ettin::CheckCast); + OnEffectHitTarget += SpellEffectFn(spell_redridge_control_ettin::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_DUMMY); + } +}; + +// 80702 - Control Ettin +class spell_redridge_control_ettin_2 : public SpellScript +{ + void HandleScriptEffect(SpellEffIndex /*effIndex*/) const + { + if (Creature* target = GetHitCreature()) + target->DespawnOrUnsummon(); + + // subdued ettin minion casts 82558 to player + std::list<TempSummon*> minionList; + GetCaster()->GetAllMinionsByEntry(minionList, NPC_SUBDUED_CANYON_ETTIN); + if (TempSummon* ettin = minionList.front()) + ettin->CastSpell(GetCaster(), SPELL_CANYON_ETTIN_SPAWN_SPELL, false); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_redridge_control_ettin_2::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); } }; @@ -270,8 +700,6 @@ enum RedridgeCitizen SAY_IN_TOWNHALL = 0, // Used by npc's in Lakeshire Townhall SAY_LEAVE_TOWNHALL = 1, // Used by npc's in Lakeshire Townhall - - SPELL_APPLY_QUEST_INVIS_ZONE_19 = 82099 // Used by npc's in Lakeshire Townhall }; const Emote EmoteID[6] = @@ -370,6 +798,9 @@ void AddSC_redridge_mountains() { new npc_big_earl(); new npc_dumpy_and_keeshan(); - new npc_bridge_worker_alex(); + RegisterCreatureAI(npc_redridge_huge_boulder); + RegisterCreatureAI(npc_redridge_subdued_canyon_ettin); + RegisterSpellScript(spell_redridge_control_ettin); + RegisterSpellScript(spell_redridge_control_ettin_2); new npc_redridge_citizen(); } |