/* * 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 . */ /* Script Data Start SDName: Redridge Mountains SD%Complete: 0 SDComment: Script Data End */ #include "ScriptMgr.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 enum RedridgeSpellData { 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, }; 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 }; /*###### # npc_dumpy_and_keeshan "Used by entries 43249 and 43184" ######*/ class npc_dumpy_and_keeshan : public CreatureScript { public: npc_dumpy_and_keeshan() : CreatureScript("npc_dumpy_and_keeshan") { } struct npc_dumpy_and_keeshanAI : public ScriptedAI { npc_dumpy_and_keeshanAI(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _scheduler.Schedule(Seconds(1), [this](TaskContext targetSearch) { std::list bigEarlList; me->GetCreatureListWithEntryInGrid(bigEarlList, NPC_BIGEARL, 5.0f); for (Creature* bigEarl : bigEarlList) if ((bigEarl->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_3) && me->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_3)) || (bigEarl->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_4) && me->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_4))) AttackStart(bigEarl); if (!me->IsInCombat()) targetSearch.Repeat(); }); } void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if ((!who || who->GetTypeId() == TYPEID_UNIT) && me->HealthBelowPctDamaged(82, damage)) damage = 0; } void UpdateAI(uint32 diff) override { _scheduler.Update(diff); } private: TaskScheduler _scheduler; }; CreatureAI* GetAI(Creature* creature) const override { return new npc_dumpy_and_keeshanAI(creature); } }; /*###### # npc_big_earl "Used by entry 43248" ######*/ class npc_big_earl : public CreatureScript { public: npc_big_earl() : CreatureScript("npc_big_earl") { } struct npc_big_earlAI : public ScriptedAI { npc_big_earlAI(Creature* creature) : ScriptedAI(creature) { } void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override { if ((!who || who->GetTypeId() == TYPEID_UNIT) && me->HealthBelowPctDamaged(82, damage)) damage = 0; } }; CreatureAI* GetAI(Creature* creature) const override { return new npc_big_earlAI(creature); } }; enum RedridgeHugeBoulder { 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, }; 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 { npc_redridge_huge_boulder(Creature* creature) : CreatureAI(creature) { } void Reset() override { _events.Reset(); _oslowGUID.Clear(); _alexGUID.Clear(); _trentGUID.Clear(); _dmitriGUID.Clear(); _jessGUID.Clear(); _danielGUID.Clear(); _matthewGUID.Clear(); _events.ScheduleEvent(EVENT_STORE_GUIDS, 5s); } void SpellHit(WorldObject* /*caster*/, SpellInfo const* spell) override { if (spell->Id != SPELL_LIFT_BOULDER_RIDE) return; _events.Reset(); _events.ScheduleEvent(EVENT_REPOSITION, 0ms); } void UpdateAI(uint32 diff) override { _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_STORE_GUIDS: { 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 { _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 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 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; } } 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; } } } 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; } } 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 { 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 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); } }; /*###### # npc_redridge_citizen "Used by entries 43222 and 43247" ######*/ enum RedridgeCitizen { EVENT_DETERMINE_EVENT = 7, // Determine where npc is located by aura EVENT_PLAYEMOTE = 8, // Used by npc's in Lakeshire Inn EVENT_SAY_TEXT = 9, // Used by npc's in Lakeshire Townhall EVENT_LEAVE_TOWNHALL = 10, // Used by npc's in Lakeshire Townhall SAY_IN_TOWNHALL = 0, // Used by npc's in Lakeshire Townhall SAY_LEAVE_TOWNHALL = 1, // Used by npc's in Lakeshire Townhall }; const Emote EmoteID[6] = { EMOTE_ONESHOT_CHEER, EMOTE_ONESHOT_ROAR, EMOTE_ONESHOT_SHOUT, EMOTE_ONESHOT_POINT, EMOTE_ONESHOT_BATTLE_ROAR, EMOTE_ONESHOT_NO }; WaypointPath const TownhallPath = { 8, { { 0, -9221.39f, -2198.45f, 66.34846f }, { 1, -9221.39f, -2198.45f, 66.34846f }, { 2, -9226.39f, -2196.45f, 66.34846f }, { 3, -9231.64f, -2196.45f, 65.34846f }, { 4, -9231.39f, -2205.45f, 66.34846f }, { 5, -9231.64f, -2210.45f, 66.34846f }, { 6, -9244.14f, -2211.20f, 66.34846f }, { 7, -9255.31f, -2211.62f, 63.93340f } }, WaypointMoveType::Walk }; class npc_redridge_citizen : public CreatureScript { public: npc_redridge_citizen() : CreatureScript("npc_redridge_citizen") { } struct npc_redridge_citizenAI : public ScriptedAI { npc_redridge_citizenAI(Creature* creature) : ScriptedAI(creature) { } void Reset() override { _events.Reset(); _events.ScheduleEvent(EVENT_DETERMINE_EVENT, Seconds(2)); } void UpdateAI(uint32 diff) override { _events.Update(diff); if (!UpdateVictim()) { while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_DETERMINE_EVENT: // Determine where npc is located if (me->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_3) || me->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_4)) // Lakeshire Inn _events.ScheduleEvent(EVENT_PLAYEMOTE, Seconds(5), Seconds(15)); else if (me->HasAura(SPELL_APPLY_QUEST_INVIS_ZONE_19)) // Lakeshire Townhall _events.ScheduleEvent(EVENT_SAY_TEXT, Seconds(5), Seconds(30)); break; case EVENT_PLAYEMOTE: me->HandleEmoteCommand(EmoteID[urand(0, 5)]); _events.ScheduleEvent(EVENT_PLAYEMOTE, Seconds(10), Seconds(25)); break; case EVENT_SAY_TEXT: if (roll_chance_i(3)) { Talk(SAY_LEAVE_TOWNHALL); _events.ScheduleEvent(EVENT_LEAVE_TOWNHALL, Seconds(2)); break; } if (roll_chance_i(30)) Talk(SAY_IN_TOWNHALL); _events.Repeat(Seconds(30), Seconds(60)); break; case EVENT_LEAVE_TOWNHALL: me->GetMotionMaster()->MovePath(TownhallPath, false); me->DespawnOrUnsummon(Seconds(30), Seconds(60)); break; default: break; } } } } private: EventMap _events; }; CreatureAI* GetAI(Creature* creature) const override { return new npc_redridge_citizenAI(creature); } }; void AddSC_redridge_mountains() { new npc_big_earl(); new npc_dumpy_and_keeshan(); 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(); }