diff options
Diffstat (limited to 'src/server')
| -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();  }  | 
