/* * This file is part of the AzerothCore 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 Affero General Public License as published by the * Free Software Foundation; either version 3 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 Affero General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "Common.h" #include "CreatureGroups.h" #include "CreatureScript.h" #include "GameEventMgr.h" #include "ObjectAccessor.h" #include "ScriptedCreature.h" enum COG_Paths { STORMWIND_PATH = 80500, GOLDSHIRE_PATH = 80501, WOODS_PATH = 80502, HOUSE_PATH = 80503, LISA_PATH = 80700 }; enum COG_Sounds { BANSHEE_DEATH = 1171, BANSHEEPREAGGRO = 1172, CTHUN_YOU_WILL_DIE = 8585, CTHUN_DEATH_IS_CLOSE = 8580, HUMAN_FEMALE_EMOTE_CRY = 6916, GHOSTDEATH = 3416 }; enum COG_Creatures { NPC_DANA = 804, NPC_CAMERON = 805, NPC_JOHN = 806, NPC_LISA = 807, NPC_AARON = 810, NPC_JOSE = 811 }; enum COG_Events { EVENT_WP_START_GOLDSHIRE = 1, EVENT_WP_START_WOODS = 2, EVENT_WP_START_HOUSE = 3, EVENT_WP_START_LISA = 4, EVENT_PLAY_SOUNDS = 5, EVENT_BEGIN_EVENT = 6, EVENT_RANDOM_MOVEMENT = 7 }; enum COG_GameEvent { GAME_EVENT_CHILDREN_OF_GOLDSHIRE = 74 }; struct npc_cameron : public ScriptedAI { npc_cameron(Creature* creature) : ScriptedAI(creature) { _started = false; } static uint32 SoundPicker() { return RAND( BANSHEE_DEATH, BANSHEEPREAGGRO, CTHUN_YOU_WILL_DIE, CTHUN_DEATH_IS_CLOSE, HUMAN_FEMALE_EMOTE_CRY, GHOSTDEATH ); } void MoveTheChildren() { std::vector MovePosPositions = { { -9373.521f, -67.71767f, 69.201965f, 1.117011f }, { -9374.94f, -62.51654f, 69.201965f, 5.201081f }, { -9371.013f, -71.20811f, 69.201965f, 1.937315f }, { -9368.419f, -66.47543f, 69.201965f, 3.141593f }, { -9372.376f, -65.49946f, 69.201965f, 4.206244f }, { -9377.477f, -67.8297f, 69.201965f, 0.296706f } }; Acore::Containers::RandomShuffle(MovePosPositions); // first we break formation because children will need to move on their own now for (auto& guid : _childrenGUIDs) if (Creature* child = ObjectAccessor::GetCreature(*me, guid)) if (child->GetFormation()) child->GetFormation()->RemoveMember(child); // Move each child to an random position for (uint32 i = 0; i < _childrenGUIDs.size(); ++i) { if (Creature* children = ObjectAccessor::GetCreature(*me, _childrenGUIDs[i])) { children->SetWalk(true); children->GetMotionMaster()->MovePoint(0, MovePosPositions[i], true, MovePosPositions[i].GetOrientation()); } } me->SetWalk(true); me->GetMotionMaster()->MovePoint(0, MovePosPositions.back(), true, MovePosPositions.back().GetOrientation()); } void PathEndReached(uint32 pathId) override { switch (pathId) { case STORMWIND_PATH: { _events.ScheduleEvent(EVENT_RANDOM_MOVEMENT, 2s); _events.ScheduleEvent(EVENT_WP_START_GOLDSHIRE, 11min); break; } case GOLDSHIRE_PATH: { _events.ScheduleEvent(EVENT_RANDOM_MOVEMENT, 2s); _events.ScheduleEvent(EVENT_WP_START_WOODS, 15min); break; } case WOODS_PATH: { _events.ScheduleEvent(EVENT_RANDOM_MOVEMENT, 2s); _events.ScheduleEvent(EVENT_WP_START_HOUSE, 6min); // 6 minutes _events.ScheduleEvent(EVENT_WP_START_LISA, 362s); break; } case HOUSE_PATH: { // Move childeren at last point MoveTheChildren(); // After 30 seconds a random sound should play _events.ScheduleEvent(EVENT_PLAY_SOUNDS, 30s); break; } } } void sOnGameEvent(bool start, uint16 eventId) override { if (start && eventId == GAME_EVENT_CHILDREN_OF_GOLDSHIRE) { // Start event at 7 am // Begin pathing _events.ScheduleEvent(EVENT_BEGIN_EVENT, 2s); _started = true; } else if (!start && eventId == GAME_EVENT_CHILDREN_OF_GOLDSHIRE) { // Reset event at 8 am _started = false; _events.Reset(); } } void UpdateAI(uint32 diff) override { if (!_started) return; _events.Update(diff); while (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_WP_START_GOLDSHIRE: me->GetMotionMaster()->MovePath(GOLDSHIRE_PATH, false); break; case EVENT_WP_START_WOODS: me->GetMotionMaster()->MovePath(WOODS_PATH, false); break; case EVENT_WP_START_HOUSE: me->GetMotionMaster()->MovePath(HOUSE_PATH, false); break; case EVENT_WP_START_LISA: for (uint32 i = 0; i < _childrenGUIDs.size(); ++i) { if (Creature* lisa = ObjectAccessor::GetCreature(*me, _childrenGUIDs[i])) { if (lisa->GetEntry() == NPC_LISA) { lisa->GetMotionMaster()->MovePath(LISA_PATH, false); break; } } } break; case EVENT_PLAY_SOUNDS: me->PlayDistanceSound(SoundPicker()); break; case EVENT_BEGIN_EVENT: { _childrenGUIDs.clear(); // Get all childeren's guid's. if (Creature* dana = me->FindNearestCreature(NPC_DANA, 25.0f)) _childrenGUIDs.push_back(dana->GetGUID()); if (Creature* john = me->FindNearestCreature(NPC_JOHN, 25.0f)) _childrenGUIDs.push_back(john->GetGUID()); if (Creature* lisa = me->FindNearestCreature(NPC_LISA, 25.0f)) _childrenGUIDs.push_back(lisa->GetGUID()); if (Creature* aaron = me->FindNearestCreature(NPC_AARON, 25.0f)) _childrenGUIDs.push_back(aaron->GetGUID()); if (Creature* jose = me->FindNearestCreature(NPC_JOSE, 25.0f)) _childrenGUIDs.push_back(jose->GetGUID()); // If Formation was disbanded, remake. if (!me->GetFormation()->IsFormed()) for (auto& guid : _childrenGUIDs) if (Creature* child = ObjectAccessor::GetCreature(*me, guid)) child->SearchFormation(); // Start movement me->GetMotionMaster()->MovePath(STORMWIND_PATH, false); break; } case EVENT_RANDOM_MOVEMENT: { me->GetMotionMaster()->MoveRandom(10.0f); break; } default: break; } } } private: EventMap _events; bool _started; GuidVector _childrenGUIDs; }; /*###### ## npc_supervisor_raelen ######*/ enum SupervisorRaelen { EVENT_FIND_PEASENTS = 8, EVENT_NEXT_PEASENT = 9, NPC_EASTVALE_PEASENT = 11328 }; struct npc_supervisor_raelen : public ScriptedAI { npc_supervisor_raelen(Creature* creature) : ScriptedAI(creature) {} void Reset() override { _PeasentId = 0; peasentGUIDs.clear(); _events.ScheduleEvent(EVENT_FIND_PEASENTS, 4s); } void SetData(uint32 /*type*/, uint32 data) override { if (data == 1) { ++_PeasentId; if (_PeasentId == 5) _PeasentId = 0; _events.ScheduleEvent(EVENT_NEXT_PEASENT, 2s, 6s); } } void CallPeasent() { if (Creature* peasent = ObjectAccessor::GetCreature(*me, peasentGUIDs[_PeasentId])) peasent->AI()->SetData(1, 1); } void UpdateAI(uint32 diff) override { _events.Update(diff); if (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_FIND_PEASENTS: { GuidVector tempGUIDs; std::list peasents; GetCreatureListWithEntryInGrid(peasents, me, NPC_EASTVALE_PEASENT, 100.f); for (Creature* peasent : peasents) { tempGUIDs.push_back(peasent->GetGUID()); } peasentGUIDs.push_back(tempGUIDs[2]); peasentGUIDs.push_back(tempGUIDs[3]); peasentGUIDs.push_back(tempGUIDs[0]); peasentGUIDs.push_back(tempGUIDs[1]); peasentGUIDs.push_back(tempGUIDs[4]); _events.ScheduleEvent(EVENT_NEXT_PEASENT, 1s); break; } case EVENT_NEXT_PEASENT: CallPeasent(); break; } } if (!UpdateVictim()) return; DoMeleeAttackIfReady(); } private: EventMap _events; uint8 _PeasentId; GuidVector peasentGUIDs; }; /*###### ## npc_eastvale_peasent ######*/ enum EastvalePeasent { EVENT_MOVETORAELEN = 10, EVENT_TALKTORAELEN1 = 11, EVENT_TALKTORAELEN2 = 12, EVENT_RAELENTALK = 13, EVENT_TALKTORAELEN3 = 14, EVENT_TALKTORAELEN4 = 15, EVENT_PATHBACK = 16, NPC_SUPERVISOR_RAELEN = 10616, PATH_PEASENT_0 = 813490, PATH_PEASENT_1 = 813480, PATH_PEASENT_2 = 812520, PATH_PEASENT_3 = 812490, PATH_PEASENT_4 = 812500, SAY_RAELEN = 0, SOUND_PEASENT_GREETING_1 = 6289, SOUND_PEASENT_GREETING_2 = 6288, SOUND_PEASENT_GREETING_3 = 6290, SOUND_PEASENT_LEAVING_1 = 6242, SOUND_PEASENT_LEAVING_2 = 6282, SOUND_PEASENT_LEAVING_3 = 6284, SOUND_PEASENT_LEAVING_4 = 6285, SOUND_PEASENT_LEAVING_5 = 6286, SPELL_TRANSFORM_PEASENT_WITH_WOOD = 9127 }; struct npc_eastvale_peasent : public ScriptedAI { npc_eastvale_peasent(Creature* creature) : ScriptedAI(creature) { Initialize(); } void Initialize() { _path = me->GetSpawnId() * 10; } void Reset() override {} void SetData(uint32 /*type*/, uint32 data) override { if (data == 1) { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); me->CastSpell(me, SPELL_TRANSFORM_PEASENT_WITH_WOOD); me->SetSpeed(MOVE_WALK, 1.0f); me->GetMotionMaster()->MovePath(_path, false); } } void PathEndReached(uint32 pathId) override { if (pathId == _path) { CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(me->GetEntry()); me->SetSpeed(MOVE_WALK, cinfo->speed_walk); me->RemoveAura(SPELL_TRANSFORM_PEASENT_WITH_WOOD); _events.ScheduleEvent(EVENT_MOVETORAELEN, 3s); } else if (pathId == _path + 1) { _events.ScheduleEvent(EVENT_TALKTORAELEN1, 1s); } else if (pathId == _path + 2) { me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_WORK_CHOPWOOD); } } void UpdateAI(uint32 diff) override { _events.Update(diff); if (uint32 eventId = _events.ExecuteEvent()) { switch (eventId) { case EVENT_MOVETORAELEN: me->GetMotionMaster()->MovePath(_path + 1, false); break; case EVENT_TALKTORAELEN1: if (Creature* realen = me->FindNearestCreature(NPC_SUPERVISOR_RAELEN, 2.0f, true)) { _realenGUID = realen->GetGUID(); me->SetFacingToObject(realen); switch (_path) { case PATH_PEASENT_0: me->PlayDirectSound(SOUND_PEASENT_GREETING_1); _events.ScheduleEvent(EVENT_TALKTORAELEN2, 2s); break; case PATH_PEASENT_1: case PATH_PEASENT_3: me->PlayDirectSound(SOUND_PEASENT_GREETING_3); _events.ScheduleEvent(EVENT_RAELENTALK, 2s); break; case PATH_PEASENT_2: case PATH_PEASENT_4: me->PlayDirectSound(SOUND_PEASENT_GREETING_2); _events.ScheduleEvent(EVENT_RAELENTALK, 2s); break; } } else { // Path back if realen cannot be found alive _events.ScheduleEvent(EVENT_PATHBACK, 2s); } break; case EVENT_TALKTORAELEN2: me->PlayDirectSound(SOUND_PEASENT_GREETING_2); _events.ScheduleEvent(EVENT_RAELENTALK, 2s); break; case EVENT_RAELENTALK: if (Creature* realen = ObjectAccessor::GetCreature(*me, _realenGUID)) { realen->AI()->Talk(SAY_RAELEN); _events.ScheduleEvent(EVENT_TALKTORAELEN3, 5s); } break; case EVENT_TALKTORAELEN3: { switch (_path) { case PATH_PEASENT_0: me->PlayDirectSound(SOUND_PEASENT_LEAVING_1); _events.ScheduleEvent(EVENT_PATHBACK, 2s); break; case PATH_PEASENT_1: case PATH_PEASENT_3: me->PlayDirectSound(SOUND_PEASENT_LEAVING_4); _events.ScheduleEvent(EVENT_TALKTORAELEN4, 2s); break; case PATH_PEASENT_2: me->PlayDirectSound(SOUND_PEASENT_LEAVING_3); _events.ScheduleEvent(EVENT_PATHBACK, 2s); break; case PATH_PEASENT_4: me->PlayDirectSound(SOUND_PEASENT_LEAVING_2); _events.ScheduleEvent(EVENT_PATHBACK, 2s); break; } } break; case EVENT_TALKTORAELEN4: me->PlayDirectSound(SOUND_PEASENT_LEAVING_5); _events.ScheduleEvent(EVENT_PATHBACK, 2s); break; case EVENT_PATHBACK: if (Creature* realen = ObjectAccessor::GetCreature(*me, _realenGUID)) realen->AI()->SetData(1, 1); me->GetMotionMaster()->MovePath(_path + 2, false); break; } } if (!UpdateVictim()) return; DoMeleeAttackIfReady(); } private: EventMap _events; ObjectGuid _realenGUID; uint32 _path; }; void AddSC_elwynn_forest() { RegisterCreatureAI(npc_cameron); RegisterCreatureAI(npc_supervisor_raelen); RegisterCreatureAI(npc_eastvale_peasent); }