aboutsummaryrefslogtreecommitdiff
path: root/src/server/scripts/EasternKingdoms
diff options
context:
space:
mode:
authorJason Dove <1695733+jasongdove@users.noreply.github.com>2025-05-30 04:04:07 -0500
committerGitHub <noreply@github.com>2025-05-30 11:04:07 +0200
commita50e1c7ab3f6cdbb60509fab82c00a8eb6eb6f7d (patch)
tree1222391f1e09259c6677e21c54356bb356f137ba /src/server/scripts/EasternKingdoms
parente39dddec0b805db4f11e08dcf7e22e0f003ca0e1 (diff)
Scripts/RedridgeMountains: Implement Quest "Saving Foreman Oslow" (#30947)
Diffstat (limited to 'src/server/scripts/EasternKingdoms')
-rw-r--r--src/server/scripts/EasternKingdoms/zone_redridge_mountains.cpp689
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();
}