TrinityCore
Loading...
Searching...
No Matches
culling_of_stratholme.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
19#include "AreaBoundary.h"
20#include "DBCStructure.h"
21#include "GameObject.h"
22#include "GameTime.h"
23#include "InstanceScript.h"
24#include "Map.h"
25#include "MotionMaster.h"
26#include "ObjectAccessor.h"
27#include "PassiveAI.h"
28#include "Player.h"
29#include "QuestDef.h"
30#include "ScriptedEscortAI.h"
31#include "ScriptedGossip.h"
32#include "SpellInfo.h"
33#include "SpellScript.h"
34#include "ScriptMgr.h"
36#include "TemporarySummon.h"
37#include <unordered_map>
38
40{
41 NPC_FORREST = 30551,
42 NPC_BELFAST = 30571,
43 NPC_JAMES = 30553,
44 NPC_FRAS = 30552,
45 NPC_MAL = 31017,
46 NPC_GRYAN = 30561
47};
48
50{
51 EVENT_FORREST_1 = 1, // This whole situation seems a bit paranoid, don't you think?
52 EVENT_JAMES_1, // Orders are orders. If the Prince says jump...
53 EVENT_FRAS_1, // It's a strange order, you can't deny. Suspicious food? Under that definition, you should arrest Belfast!
55 EVENT_BELFAST_1, // I HEARD THAT! No more ale for you! Not a drop!
56 EVENT_MAL_1, // Enough, Michael. Business is hurting enough with this scare as it is. We can use every copper.
57 EVENT_GRYAN_1, // The soldiers are doing important work. The safety of the people is more important, Mal, if you're interested in your customers living to spend another day.
58 EVENT_MAL_2, // Mal Corricks grudgingly nods.
59 EVENT_MAL_3, // I can't argue with that.
60 EVENT_JAMES_2, // Don't worry too much. By the time I went off duty, we hadn't found a scrap of befouled grain here.
61 EVENT_FORREST_2, // Thank the Light for that.
62 EVENT_FRAS_2 // Fras Siabi nods.
63};
64
84
90
92{
93 public:
94 npc_hearthsinger_forresten_cot() : CreatureScript("npc_hearthsinger_forresten_cot") { }
95
97 {
98 npc_hearthsinger_forresten_cotAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()), _hadBelfast(false), _hadTalk(false) { }
99
100 void UpdateAI(uint32 diff) override
101 {
102 _events.Update(diff);
103 while (uint32 eventId = _events.ExecuteEvent())
104 {
105 uint32 talkerEntry = UINT_MAX, line = 0;
106 switch (eventId)
107 {
108 case EVENT_FORREST_1:
109 talkerEntry = 0, line = LINE_FORREST_1;
110 break;
111 case EVENT_JAMES_1:
112 talkerEntry = NPC_JAMES, line = LINE_JAMES_1;
113 break;
114 case EVENT_FRAS_1:
115 talkerEntry = NPC_FRAS, line = LINE_FRAS_1;
116 break;
118 if (Creature* belfast = me->FindNearestCreature(NPC_BELFAST, 80.0f, true))
119 belfast->AI()->DoAction(EVENT_BELFAST_MOVE);
120 return;
121 case EVENT_BELFAST_1:
122 talkerEntry = NPC_BELFAST, line = LINE_BELFAST_1;
123 break;
124 case EVENT_MAL_1:
125 talkerEntry = NPC_MAL, line = LINE_MAL_1;
126 break;
127 case EVENT_GRYAN_1:
128 talkerEntry = NPC_GRYAN, line = LINE_GRYAN_1;
129 break;
130 case EVENT_MAL_2:
131 talkerEntry = NPC_MAL, line = LINE_MAL_2;
132 break;
133 case EVENT_MAL_3:
134 talkerEntry = NPC_MAL, line = LINE_MAL_3;
135 break;
136 case EVENT_JAMES_2:
137 talkerEntry = NPC_JAMES, line = LINE_JAMES_2;
138 break;
139 case EVENT_FORREST_2:
140 talkerEntry = 0, line = LINE_FORREST_2;
141 break;
142 case EVENT_FRAS_2:
143 talkerEntry = NPC_FRAS, line = LINE_FRAS_2;
144 break;
145 default:
146 break;
147 }
148
149 if (talkerEntry != UINT_MAX)
150 {
151 Creature* talker = me;
152 if (talkerEntry)
153 talker = me->FindNearestCreature(talkerEntry, 80.0f, true);
154 if (talker)
155 talker->AI()->Talk(line, ObjectAccessor::GetPlayer(*talker, _triggeringPlayer));
156 }
157 }
158 }
159
160 // Player has hit the Belfast stairs areatrigger, we are taking him over for a moment
161 void SetGUID(ObjectGuid const& guid, int32 /*id*/) override
162 {
163 if (_hadBelfast)
164 return;
165 _hadBelfast = true;
166 if (Creature* belfast = me->FindNearestCreature(NPC_BELFAST, 100.0f, true))
167 {
168 if (Player* invoker = ObjectAccessor::GetPlayer(*belfast, guid))
169 {
170 belfast->StopMoving();
171 belfast->SetFacingToObject(invoker);
172 belfast->AI()->Talk(LINE_BELFAST_0);
173 }
174 }
175 }
176
177 // Belfast SmartAI telling us it's reached the WP
189
190 void MoveInLineOfSight(Unit* unit) override
191 {
193 {
194 _hadTalk = true;
195 _triggeringPlayer = unit->GetGUID();
196 Seconds offset = Seconds(urand(10,30));
201 }
202 }
203
204 private:
210 };
211
212 CreatureAI* GetAI(Creature* creature) const override
213 {
214 return GetCullingOfStratholmeAI<npc_hearthsinger_forresten_cotAI>(creature);
215 }
216};
217
219{
220 public:
221 at_stratholme_inn_stairs_cot() : AreaTriggerScript("at_stratholme_inn_stairs_cot") { }
222
223 bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
224 {
225 if (InstanceScript* instance = player->GetInstanceScript())
226 if (instance->GetData(DATA_INSTANCE_PROGRESS) <= CRATES_IN_PROGRESS)
227 // Forrest's script will handle Belfast for this, since SmartAI lacks the features to do it (we can't pass a custom target)
228 if (Creature* forrest = player->FindNearestCreature(NPC_FORREST, 200.0f, true))
229 forrest->AI()->SetGUID(player->GetGUID());
230 return true;
231 }
232};
233
269
279
281{
282 public:
283 npc_chromie_start() : CreatureScript("npc_chromie_start") { }
284
286 {
287 npc_chromie_startAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { }
288
294
300
301 bool OnGossipHello(Player* player) override
302 {
303 if (me->IsQuestGiver())
304 player->PrepareQuestMenu(me->GetGUID());
305
306 if (InstanceScript* instance = me->GetInstanceScript())
307 {
309 if (player->CanBeGameMaster()) // GM instance state override menu
311
312 uint32 state = instance->GetData(DATA_INSTANCE_PROGRESS);
313 if (state < PURGE_STARTING)
314 {
316 {
317 bool shouldAddSkipGossip = true;
318 Map::PlayerList const& players = instance->instance->GetPlayers();
319 for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
320 {
321 if (Player* player = it->GetSource())
322 {
323 if (player->IsGameMaster())
324 continue;
325 if (!player->HasAchieved(instance->instance->GetSpawnMode() == DUNGEON_DIFFICULTY_HEROIC ? ACHIEVEMENT_HEROIC : ACHIEVEMENT_NORMAL))
326 {
327 shouldAddSkipGossip = false;
328 break;
329 }
330 }
331 }
332 if (shouldAddSkipGossip)
334 }
336 }
337 else
338 {
341 }
342 }
343 else // random fallback, this should really never happen
345 return true;
346 }
347
348 bool OnGossipSelect(Player* player, uint32 /*sender*/, uint32 listId) override
349 {
350 uint32 const action = GetGossipActionFor(player, listId);
351 ClearGossipMenuFor(player);
352 switch (action - GOSSIP_ACTION_INFO_DEF)
353 {
358 break;
363 break;
366 [[fallthrough]];
368 CloseGossipMenuFor(player);
370 break;
375 break;
381 break;
384 for (uint32 state = 1; state <= COMPLETE; state = state << 1)
385 {
386 if (GetStableStateFor(COSProgressStates(state)) == state)
388 }
389 for (uint32 state = 1; state <= COMPLETE; state = state << 1)
390 {
391 if (GetStableStateFor(COSProgressStates(state)) != state)
393 }
395 break;
397 CloseGossipMenuFor(player);
398 if (!player->CanBeGameMaster())
399 break;
400 if (InstanceScript* instance = me->GetInstanceScript())
401 instance->SetGuidData(DATA_GM_RECALL, player->GetGUID());
402 break;
403 default: // handle GM instance state switch
404 CloseGossipMenuFor(player);
405 if (!player->CanBeGameMaster())
406 break;
407 if (InstanceScript* instance = me->GetInstanceScript())
409 break;
410 }
411 return false;
412 }
413
414 void OnQuestAccept(Player* /*player*/, Quest const* quest) override
415 {
418 }
419
420 private:
422 };
423
424 CreatureAI* GetAI(Creature* creature) const override
425 {
426 return GetCullingOfStratholmeAI<npc_chromie_startAI>(creature);
427 }
428};
429
452
458
460{
461 public:
462 npc_chromie_middle() : CreatureScript("npc_chromie_middle") { }
463
465 {
466 npc_chromie_middleAI(Creature* creature) : NullCreatureAI(creature), Instance(creature->GetInstanceScript()), WhisperDelay(0) { }
467
468 void JustAppeared() override
469 {
472 }
473
474 void UpdateAI(uint32 diff) override
475 {
476 if (!WhisperDelay)
477 return;
478 if (WhisperDelay > diff)
479 WhisperDelay -= diff;
480 else
481 {
484 WhisperDelay = 0;
485 }
486 }
487
488 void MoveInLineOfSight(Unit* unit) override
489 {
490 if (Player* player = unit->ToPlayer())
491 {
493 {
494 time_t& whisperedTime = Whispered[player->GetGUID()];
495 time_t now = GameTime::GetGameTime();
496 if (!whisperedTime || (now - whisperedTime) > 15)
497 {
498 Talk(WHISPER_COME_TALK, player);
499 whisperedTime = now;
500 }
501 }
502 }
503 }
504
510
522
549
552 std::unordered_map<ObjectGuid, time_t> Whispered;
553 };
554
555 CreatureAI* GetAI(Creature* creature) const override
556 {
557 return GetCullingOfStratholmeAI<npc_chromie_middleAI>(creature);
558 }
559};
560
561// Generic data for crate fluff events
572
573// Crate fluff event #1
575{
576 NPC_MARTHA = 27884,
577 NPC_JENA = 27885,
578
589
590 LINE_JENA1 = 0, // Let's see, we had chicken last night.
591 LINE_JENA2 = 1, // I've got plenty of cured bacon, but he had some for breakfast.
592 LINE_JENA3 = 2, // I need to make something healthy for him, he's still not recovered from that illness from last week.
593 LINE_JENA4 = 3, // Strawberries! Oh wait, they're not in season.
594 LINE_JENA5 = 4, // Ah, I'll make him some fresh bread! I need to get some flour from Martha!
595 LINE_JENA6 = 5, // Martha, I'm out of flour for bread. You wouldn't happen to have any grain from that recent shipment, would you?
596 LINE_JENA7 = 6, // Thanks, Martha! I owe you one.
597 LINE_JENA8 = 7, // Oh, dear.
598 LINE_JENA9 = 8, // Martha, something's wrong with this grain! Some of the Prince's soldiers were looking for this. I'm going to go look for one.
599 LINE_MARTHA1= 0, // Oh hello, Jena. Of course you can borrow some grain. Help yourself.
600 LINE_MARTHA2= 1, // Oh, my.
601
611
612static float const marthaIdleOrientation1 = 3.159046f;
613static float const marthaIdleOrientation2 = 4.764749f;
614
616{
617 npc_martha_goslin() : CreatureScript("npc_martha_goslin") { }
618
620 {
622
630
631 void MovementInform(uint32 type, uint32 id) override
632 {
633 if (type == SPLINE_CHAIN_MOTION_TYPE)
634 {
635 switch (id)
636 {
637 case MOVEID_EVENT1:
640 Events.ScheduleEvent(EVENT_MARTHA_IDLE2, Seconds(9), Seconds(15));
641 break;
642 case MOVEID_EVENT2:
645 Events.ScheduleEvent(EVENT_MARTHA_IDLE1, Seconds(9), Seconds(15));
646 break;
647 default:
648 break;
649 }
650 }
651 }
652
653 void UpdateAI(uint32 diff) override
654 {
655 if (InterruptTimer)
656 {
657 if (InterruptTimer > diff)
658 {
659 InterruptTimer -= diff;
660 return;
661 }
662 diff -= InterruptTimer;
663 InterruptTimer = 0;
664 if (!ResumeInfo.Empty())
665 {
668 }
669
670 if (!diff)
671 return;
672 }
673
674 Events.Update(diff);
675 while (uint32 eventId = Events.ExecuteEvent())
676 {
677 switch (eventId)
678 {
682 break;
686 break;
687 default:
688 break;
689 }
690 }
691 }
692
693 void JustAppeared() override
694 {
696 Events.RescheduleEvent(EVENT_MARTHA_IDLE2, Seconds(5), Seconds(10));
697 }
698
702 };
703
704 CreatureAI* GetAI(Creature* creature) const override
705 {
706 return GetCullingOfStratholmeAI<npc_martha_goslinAI>(creature);
707 }
708};
709
711{
712 npc_jena_anderson() : CreatureScript("npc_jena_anderson") { }
713
714 static Creature* Find(Creature* helper)
715 {
716 return helper->FindNearestCreature(NPC_JENA, 45.0f, true);
717 }
718
720 {
721 npc_jena_andersonAI(Creature* creature) : NullCreatureAI(creature), Started(false) { }
722
723 void UpdateAI(uint32 diff) override
724 {
725 Events.Update(diff);
726 while (uint32 eventId = Events.ExecuteEvent())
727 {
728 switch (eventId)
729 {
730 case EVENT_JENA_IDLE1:
732 break;
733 case EVENT_JENA_IDLE2:
735 break;
736 case EVENT_JENA_START:
738 break;
739 case EVENT_MARTHA1:
740 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
741 {
742 martha->AI()->DoAction(0); // interrupt idle movement
743 martha->SetFacingToObject(me, true);
744 martha->AI()->Talk(LINE_MARTHA1, me);
745 }
746 break;
747 case EVENT_JENA7:
749 break;
750 case EVENT_JENA_MOVE2:
752 break;
753 case EVENT_JENA8:
754 {
756 Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true);
757 Talk(LINE_JENA8, martha);
758 Talk(LINE_JENA9, martha);
759 if (martha)
760 me->SetFacingToObject(martha);
761 break;
762 }
763 case EVENT_JENA_LEAVE:
764 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
765 {
766 martha->AI()->DoAction(0); // interrupt idle movement (again)
767 martha->SetFacingToObject(me, true);
768 martha->AI()->Talk(LINE_MARTHA2, me);
769 }
771 break;
772 default:
773 break;
774 }
775 }
776 }
777
778 void MovementInform(uint32 type, uint32 id) override
779 {
780 if (type == SPLINE_CHAIN_MOTION_TYPE)
781 {
782 switch (id)
783 {
784 case MOVEID_EVENT1: // IDLE1
785 if (Started)
786 Events.ScheduleEvent(EVENT_JENA_START, Seconds(1), Seconds(3));
787 else
788 Events.ScheduleEvent(EVENT_JENA_IDLE2, Milliseconds(200), Milliseconds(700));
789 break;
790 case MOVEID_EVENT2: // IDLE2
791 Events.ScheduleEvent(EVENT_JENA_IDLE1, Milliseconds(200), Milliseconds(700));
792 break;
793 case MOVEID_EVENT3:
794 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
795 {
796 me->SetFacingToObject(martha, true);
797 Talk(LINE_JENA6, martha);
798 }
799 Events.ScheduleEvent(EVENT_MARTHA1, Seconds(5) + Milliseconds(500));
800 Events.ScheduleEvent(EVENT_JENA7, Seconds(11));
801 Events.ScheduleEvent(EVENT_JENA_MOVE2, Seconds(16));
802 break;
803 case MOVEID_EVENT4:
805 Events.ScheduleEvent(EVENT_JENA8, Seconds(2));
806 Events.ScheduleEvent(EVENT_JENA_LEAVE, Seconds(8));
807 break;
808 case MOVEID_EVENT5:
810 break;
811 default:
812 break;
813 }
814 }
815 }
816
817 void DoAction(int32 action) override
818 {
819 if (action == ACTION_START_FLUFF)
820 Started = true;
821 }
822
823 void InitializeAI() override
824 {
825 if (me->isMoving())
826 return;
828 }
829
832 };
833
834 CreatureAI* GetAI(Creature* creature) const override
835 {
836 return GetCullingOfStratholmeAI<npc_jena_andersonAI>(creature);
837 }
838};
839
840// Crate fluff event #2
842{
844
850
852 LINE_BARTLEBY1 = 1, // Well, guess I should load everything back into the cart.
853 LINE_BARTLEBY2 = 2, // Oh, come on! My cart broke, my horse lost a shoe, and now the cargo goes bad!
854 LINE_BARTLEBY3 = 3, // I guess I'll go find the authorities. If I'm lucky they'll tell me it's the plague and that we're all going to die.
855
859
861{
862 npc_bartleby_battson() : CreatureScript("npc_bartleby_battson") { }
863
864 static Creature* Find(Creature* helper)
865 {
866 return helper->FindNearestCreature(NPC_BARTLEBY, 5.0f, true);
867 }
868
870 {
871 npc_bartleby_battsonAI(Creature* creature) : NullCreatureAI(creature), Started(false) { }
872
873 void InitializeAI() override
874 {
875 Events.ScheduleEvent(EVENT_BARTLEBY_IDLE, Minutes(1), Minutes(2));
876 }
877
878 void DoAction(int32 action) override
879 {
880 if (Started || action != ACTION_START_FLUFF)
881 return;
882 Started = true;
883 Events.CancelEvent(EVENT_BARTLEBY_IDLE);
884 Events.ScheduleEvent(EVENT_BARTLEBY1, Seconds(15), Seconds(30));
885 }
886
887 void MovementInform(uint32 type, uint32 id) override
888 {
889 if (type == SPLINE_CHAIN_MOTION_TYPE)
890 {
891 switch (id)
892 {
893 case MOVEID_EVENT1:
895 Events.ScheduleEvent(EVENT_BARTLEBY2, Seconds(4));
896 Events.ScheduleEvent(EVENT_BARTLEBY2_2, Seconds(6));
897 Events.ScheduleEvent(EVENT_BARTLEBY3, Seconds(12));
898 break;
899 case MOVEID_EVENT2:
901 break;
902 default:
903 break;
904 }
905 }
906 }
907
908 void UpdateAI(uint32 diff) override
909 {
910 Events.Update(diff);
911 while (uint32 eventId = Events.ExecuteEvent())
912 {
913 switch (eventId)
914 {
917 Events.Repeat(Minutes(2), Minutes(4));
918 break;
919 case EVENT_BARTLEBY1:
922 break;
923 case EVENT_BARTLEBY2:
925 break;
928 break;
929 case EVENT_BARTLEBY3:
933 break;
934 default:
935 break;
936 }
937 }
938 }
939
942 };
943
944 CreatureAI* GetAI(Creature* creature) const override
945 {
946 return GetCullingOfStratholmeAI<npc_bartleby_battsonAI>(creature);
947 }
948};
949
950// Crate fluff event #3
952{
953 NPC_MALCOLM = 27891,
954 NPC_SCRUFFY = 27892,
955
965
966 LINE_MALCOLM1 = 0, // Looks like a storm's coming in, Scruffy...
967 LINE_SCRUFFY1 = 0, // %s begins to growl...
968 LINE_MALCOLM2 = 1, // What's wrong, pal?
969 LINE_MALCOLM3 = 2, // What did you find, boy?
970 LINE_MALCOLM4 = 3, // This is no good, Scruffy. Stay here and guard the house, I need to go find a soldier.
971
978
980
981static Position const malcolmSpawn = { 1605.2420f, 805.4160f, 122.9956f, 5.284148f };
982static Position const scruffySpawn = { 1601.1030f, 805.3391f, 123.7677f, 5.471561f };
983static float const scruffyFacing2 = 5.734883f;
984static float const malcolmFacing3 = 2.303835f;
985static Position const scruffyPos3 = { 1629.004f, 810.138f, 120.4927f };
986static float const scruffyFacing4 = 5.445427f;
987
989{
990 npc_malcolm_moore() : CreatureScript("npc_malcolm_moore") { }
991
992 static void Spawn(Map* map)
993 {
995 }
996
998 {
999 npc_malcolm_mooreAI(Creature* creature) : NullCreatureAI(creature) { }
1000
1001 void InitializeAI() override
1002 {
1005 scruffy->GetMotionMaster()->MoveAlongSplineChain(0, CHAIN_SCRUFFY1, true);
1006 }
1007
1008 void MovementInform(uint32 type, uint32 id) override
1009 {
1010 if (type == SPLINE_CHAIN_MOTION_TYPE)
1011 {
1012 switch (id)
1013 {
1014 case MOVEID_EVENT1:
1017 break;
1018 case MOVEID_EVENT2:
1019 Events.ScheduleEvent(EVENT_SCRUFFY1, Seconds(0));
1020 Events.ScheduleEvent(EVENT_MALCOLM2, Seconds(1));
1021 Events.ScheduleEvent(EVENT_SCRUFFY_MOVE, Seconds(4));
1022 Events.ScheduleEvent(EVENT_MALCOLM_MOVE, Seconds(8));
1023 break;
1024 case MOVEID_EVENT3:
1025 Events.ScheduleEvent(EVENT_MALCOLM_FACE3, Seconds(0));
1026 Events.ScheduleEvent(EVENT_MALCOLM3, Seconds(1));
1027 Events.ScheduleEvent(EVENT_MALCOLM4, Seconds(6));
1028 Events.ScheduleEvent(EVENT_MALCOLM_MOVE2, Seconds(12));
1029 break;
1030 case MOVEID_EVENT4:
1032 break;
1033 case MOVEID_EVENT5:
1034 Events.ScheduleEvent(EVENT_SCRUFFY_EMOTE, Seconds(0));
1035 break;
1036 default:
1037 break;
1038 }
1039 }
1040 }
1041
1042 void UpdateAI(uint32 diff) override
1043 {
1044 Events.Update(diff);
1045 while (uint32 eventId = Events.ExecuteEvent())
1046 {
1047 switch (eventId)
1048 {
1049 case EVENT_SCRUFFY1:
1050 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1051 {
1052 scruffy->SetFacingTo(scruffyFacing2);
1053 scruffy->AI()->Talk(LINE_SCRUFFY1);
1054 }
1055 break;
1056 case EVENT_MALCOLM2:
1057 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1058 {
1059 Talk(LINE_MALCOLM2, scruffy);
1060 me->SetFacingToObject(scruffy);
1061 }
1062 break;
1063 case EVENT_SCRUFFY_MOVE:
1064 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1065 scruffy->GetMotionMaster()->MoveAlongSplineChain(MOVEID_EVENT5, CHAIN_SCRUFFY2, false);
1066 break;
1067 case EVENT_MALCOLM_MOVE:
1069 break;
1071 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1072 scruffy->HandleEmoteCommand(EMOTE_ONESHOT_CREATURE_SPECIAL);
1073 break;
1076 break;
1077 case EVENT_MALCOLM3:
1079 break;
1080 case EVENT_MALCOLM4:
1081 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1082 {
1083 me->SetFacingToObject(scruffy);
1084 Talk(LINE_MALCOLM4, scruffy);
1085 }
1086 break;
1089 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1090 scruffy->SetFacingTo(scruffyFacing4);
1091 break;
1092 default:
1093 break;
1094 }
1095 }
1096 }
1097
1099 };
1100
1101 CreatureAI* GetAI(Creature* creature) const override
1102 {
1103 return GetCullingOfStratholmeAI<npc_malcolm_mooreAI>(creature);
1104 }
1105};
1106
1107// Crate fluff event #4
1109{
1112
1113 EVENT_SERGEANT_IDLE1, // questioning
1123
1126 LINE_SERGEANT_START = 2, // You don't mind me checking out your merchandise for signs of tampering, do you?
1127 LINE_SERGEANT1 = 3, // Wait, what is this? You've been holding out on me, Perelli!
1128 LINE_SERGEANT2 = 4, // I'm confiscating this suspicious grain, Perelli. We were looking for signs of tampered food, and it would be in your best interest to stay put while Prince Arthas checks this out.
1129 LINE_SERGEANT3 = 5, // We'll see about that, Perelli. We'll see about that.
1132 LINE_PERELLI1 = 2, // What are you talking about, Sergeant!
1133 LINE_PERELLI2 = 3, // You have to believe me, I'm innocent!
1134
1136 CHAIN_SERGEANT2 = 2
1138
1140{
1141 npc_sergeant_morigan() : CreatureScript("npc_sergeant_morigan") { }
1142
1143 static Creature* Find(Creature* helper)
1144 {
1145 return helper->FindNearestCreature(NPC_SERGEANT, 15.0f, true);
1146 }
1147
1149 {
1150 npc_sergeant_moriganAI(Creature* creature) : NullCreatureAI(creature), Started(false), Question(0) { }
1151
1152 void InitializeAI() override
1153 {
1154 Events.RescheduleEvent(EVENT_SERGEANT_IDLE1, Seconds(5), Seconds(15));
1155 }
1156
1157 void DoAction(int32 id) override
1158 {
1159 if (id == ACTION_START_FLUFF)
1160 Started = true;
1161 }
1162
1163 void MovementInform(uint32 type, uint32 id) override
1164 {
1165 if (type == SPLINE_CHAIN_MOTION_TYPE)
1166 switch (id)
1167 {
1168 case MOVEID_EVENT1:
1170 Events.ScheduleEvent(EVENT_SERGEANT1, Seconds(1));
1171 Events.ScheduleEvent(EVENT_SERGEANT_STAND, Seconds(3));
1172 Events.ScheduleEvent(EVENT_PERELLI1, Seconds(7));
1173 Events.ScheduleEvent(EVENT_SERGEANT2, Seconds(12));
1174 Events.ScheduleEvent(EVENT_PERELLI2, Seconds(20));
1175 Events.ScheduleEvent(EVENT_SERGEANT3, Seconds(26));
1176 Events.ScheduleEvent(EVENT_SERGEANT_LEAVE, Seconds(31));
1177 break;
1178 case MOVEID_EVENT2:
1180 break;
1181 }
1182 }
1183
1184 void Perelli(uint32 line, float ori = 0.0f)
1185 {
1186 if (Creature* perelli = me->FindNearestCreature(NPC_PERELLI, 10.0f, true))
1187 {
1188 perelli->AI()->Talk(line, me);
1189 if (ori)
1190 perelli->SetFacingTo(ori);
1191 }
1192 }
1193
1194 void UpdateAI(uint32 diff) override
1195 {
1196 Events.Update(diff);
1197 while (uint32 eventId = Events.ExecuteEvent())
1198 {
1199 switch (eventId)
1200 {
1202 if (Started)
1203 {
1204 Question = 2;
1206 }
1207 else
1208 {
1209 Question = urand(0, 1); // 0 is question that's answered with "yes", 1 is question that's answered with "no"
1211 }
1212 Events.ScheduleEvent(EVENT_SERGEANT_IDLE2, Seconds(10));
1213 break;
1216 if (Question == 2)
1217 Events.ScheduleEvent(EVENT_SERGEANT_CHAIN1, Seconds(2));
1218 else
1219 Events.ScheduleEvent(EVENT_SERGEANT_IDLE1, Seconds(15), Seconds(30));
1220 break;
1223 break;
1224 case EVENT_SERGEANT1:
1226 break;
1228 me->SetFacingTo(2.617994f);
1230 break;
1231 case EVENT_PERELLI1:
1232 Perelli(LINE_PERELLI1, 5.916666f);
1233 break;
1234 case EVENT_SERGEANT2:
1236 break;
1237 case EVENT_PERELLI2:
1239 break;
1240 case EVENT_SERGEANT3:
1242 break;
1245 break;
1246 default:
1247 break;
1248 }
1249 }
1250 }
1251
1255 };
1256
1257 CreatureAI* GetAI(Creature* creature) const override
1258 {
1259 return GetCullingOfStratholmeAI<npc_sergeant_moriganAI>(creature);
1260 }
1261};
1262
1263// Crate fluff event #5
1265{
1266 NPC_ROGER = 27903,
1267
1277
1278 LINE_ROGER1 = 0, // Ok, enough work for now. Time for refreshments and a little conversation in the inn.
1279 LINE_ROGER2 = 1, // Wait, what's that smell?
1280 LINE_ROGER3 = 2, // Can't be me, I took a bath 3 days ago!
1281 LINE_ROGER4 = 3, // Oh, close call. It's just the grain here.
1282 LINE_ROGER5 = 4, // Wait a second. Grain isn't supposed to smell like THAT! I better go find a guard.
1283
1286 CHAIN_ROGER3 = 3
1288
1290{
1291 npc_roger_owens() : CreatureScript("npc_roger_owens") { }
1292
1293 static Creature* Find(Creature* helper)
1294 {
1295 return helper->FindNearestCreature(NPC_ROGER, 30.0f, true);
1296 }
1297
1299 {
1300 npc_roger_owensAI(Creature* creature) : NullCreatureAI(creature) { }
1301
1302 void DoAction(int32 action) override
1303 {
1304 if (action == ACTION_START_FLUFF)
1305 Events.ScheduleEvent(EVENT_ROGER_START, Seconds(5), Seconds(12));
1306 }
1307
1308 void MovementInform(uint32 type, uint32 id) override
1309 {
1310 if (type == SPLINE_CHAIN_MOTION_TYPE)
1311 {
1312 switch (id)
1313 {
1314 case MOVEID_EVENT1:
1316 Events.ScheduleEvent(EVENT_ROGER_FACE3, Seconds(5));
1317 Events.ScheduleEvent(EVENT_ROGER3, Seconds(6));
1318 Events.ScheduleEvent(EVENT_ROGER_FACE4, Seconds(12));
1319 Events.ScheduleEvent(EVENT_ROGER4, Seconds(14));
1320 Events.ScheduleEvent(EVENT_ROGER_MOVE2, Seconds(18));
1321 break;
1322 case MOVEID_EVENT2:
1323 me->SetFacingTo(1.134464f, true);
1325 Events.ScheduleEvent(EVENT_ROGER5_2, Seconds(3));
1326 Events.ScheduleEvent(EVENT_ROGER_LEAVE, Seconds(8));
1327 break;
1328 case MOVEID_EVENT3:
1330 break;
1331 default:
1332 break;
1333 }
1334 }
1335 }
1336
1337 void UpdateAI(uint32 diff) override
1338 {
1339 Events.Update(diff);
1340 while (uint32 eventId = Events.ExecuteEvent())
1341 {
1342 switch (eventId)
1343 {
1344 case EVENT_ROGER_START:
1346 me->SetFacingTo(1.53589f);
1348 Events.ScheduleEvent(EVENT_ROGER_MOVE1, Seconds(6));
1349 break;
1350 case EVENT_ROGER_MOVE1:
1352 break;
1353 case EVENT_ROGER_FACE3:
1354 me->SetFacingTo(6.265732f);
1355 break;
1356 case EVENT_ROGER3:
1358 break;
1359 case EVENT_ROGER_FACE4:
1360 me->SetFacingTo(4.520403f);
1361 break;
1362 case EVENT_ROGER4:
1364 break;
1365 case EVENT_ROGER_MOVE2:
1367 break;
1368 case EVENT_ROGER5_2:
1370 break;
1371 case EVENT_ROGER_LEAVE:
1373 break;
1374 default:
1375 break;
1376 }
1377 }
1378 }
1379
1381 };
1382
1383 CreatureAI* GetAI(Creature* creature) const override
1384 {
1385 return GetCullingOfStratholmeAI<npc_roger_owensAI>(creature);
1386 }
1387};
1388
1397
1399{
1400public:
1401 npc_crate_helper() : CreatureScript("npc_crate_helper_cot") { }
1402
1404 {
1406
1407 void ReplaceIfCloser(Creature* candidate, Creature*& current, float& currentDist) const
1408 {
1409 if (!candidate)
1410 return;
1411 float newDist = me->GetExactDist2dSq(candidate);
1412 if (newDist >= currentDist)
1413 return;
1414 currentDist = newDist;
1415 current = candidate;
1416 }
1417
1418 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
1419 {
1420 if (!_crateRevealed && spellInfo->Id == SPELL_ARCANE_DISRUPTION)
1421 {
1422 _crateRevealed = true;
1423 if (InstanceScript* instance = me->GetInstanceScript())
1424 {
1425 // Update world state
1426 instance->SetData(DATA_CRATE_REVEALED, 1);
1427
1428 // Replace suspicious crate with plagued crate
1430 {
1431 crate->SummonGameObject(GO_PLAGUED_CRATE, *crate, crate->GetWorldRotation(), 1_days);
1432 crate->Delete();
1433 }
1434 if (GameObject* highlight = me->FindNearestGameObject(GO_CRATE_HIGHLIGHT, 5.0f))
1435 highlight->Delete();
1436
1437 // Find nearest fluff event and initiate it
1438 Creature* closest = nullptr;
1439 float closestDist = INFINITY;
1440 ReplaceIfCloser(npc_jena_anderson::Find(me), closest, closestDist);
1441 ReplaceIfCloser(npc_bartleby_battson::Find(me), closest, closestDist);
1442 ReplaceIfCloser(npc_sergeant_morigan::Find(me), closest, closestDist);
1443 ReplaceIfCloser(npc_roger_owens::Find(me), closest, closestDist);
1444 if (closest)
1445 closest->AI()->DoAction(ACTION_START_FLUFF);
1446 else
1448 }
1449 }
1450 }
1451
1452 uint32 GetData(uint32 data) const override
1453 {
1454 if (data == DATA_CRATE_REVEALED)
1455 return _crateRevealed ? 1 : 0;
1456 return 0;
1457 }
1458
1459 private:
1461 };
1462
1463 CreatureAI* GetAI(Creature* creature) const override
1464 {
1465 return GetCullingOfStratholmeAI<npc_crate_helperAI>(creature);
1466 }
1467};
1468
1473
1474// 53435 - Teleport to CoT Stratholme Phase 4
1494
@ IN_MILLISECONDS
Definition Common.h:35
@ DUNGEON_DIFFICULTY_HEROIC
Definition DBCEnums.h:283
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:27
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:30
@ GOSSIP_ICON_INTERACT_1
Definition GossipDef.h:64
@ SPLINE_CHAIN_MOTION_TYPE
@ QUEST_STATUS_COMPLETE
Definition QuestDef.h:105
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1128
uint32 GetGossipActionFor(Player *player, uint32 gossipListId)
void SendGossipMenuFor(Player *player, uint32 npcTextID, ObjectGuid const &guid)
void AddGossipItemFor(Player *player, GossipOptionIcon icon, std::string const &text, uint32 sender, uint32 action)
void ClearGossipMenuFor(Player *player)
void InitGossipMenuFor(Player *player, uint32 menuId)
void CloseGossipMenuFor(Player *player)
@ GOSSIP_SENDER_MAIN
@ GOSSIP_ACTION_INFO_DEF
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_SCRIPT_EFFECT
@ EMOTE_ONESHOT_EXCLAMATION
@ EMOTE_ONESHOT_CREATURE_SPECIAL
@ EMOTE_ONESHOT_NONE
@ EMOTE_ONESHOT_TALK
@ EMOTE_STATE_USE_STANDING
#define SpellEffectFn(F, I, N)
@ UNIT_STAND_STATE_KNEEL
Definition UnitDefines.h:42
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:554
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Creature *const me
Definition CreatureAI.h:82
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
CreatureAI * AI() const
Definition Creature.h:154
void Update(uint32 time)
Definition EventMap.h:67
EventId ExecuteEvent()
Definition EventMap.cpp:73
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
iterator end()
iterator begin()
Definition Map.h:281
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, uint32 duration=0, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1852
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void ResumeSplineChain(SplineChainResumeInfo const &info)
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:180
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition Player.cpp:9763
bool HasAchieved(uint32 achievementId) const
Definition Player.cpp:24920
bool CanBeGameMaster() const
Definition Player.cpp:2253
bool IsGameMaster() const
Definition Player.h:998
void PrepareQuestMenu(ObjectGuid guid)
Definition Player.cpp:14270
uint32 GetQuestId() const
Definition QuestDef.h:229
uint32 Id
Definition SpellInfo.h:289
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
static void GetResumeInfo(SplineChainResumeInfo &info, Unit const *owner, Optional< uint32 > id={})
virtual void DoAction(int32)
Definition UnitAI.h:154
Definition Unit.h:769
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool IsQuestGiver() const
Definition Unit.h:1103
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13259
void SetEmoteState(Emote emote)
Definition Unit.h:967
bool isMoving() const
Definition Unit.h:1759
void HandleEmoteCommand(Emote emoteId)
Definition Unit.cpp:1568
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13250
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10363
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:2121
Map * GetMap() const
Definition Object.h:449
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1992
float GetDistance2d(WorldObject const *obj) const
Definition Object.cpp:1141
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:2099
virtual uint32 GetData(uint32) const
Definition ZoneScript.h:55
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:56
virtual void SetGuidData(uint32, ObjectGuid)
Definition ZoneScript.h:49
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
bool OnTrigger(Player *player, AreaTriggerEntry const *) override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
PrepareSpellScript(spell_cos_teleport_to_cot_stratholme_phase_4)
@ GOSSIP_MENU_EXPLAIN_3
@ GOSSIP_TEXT_EXPLAIN_3
@ GOSSIP_TEXT_EXPLAIN_2
@ GOSSIP_TEXT_TELEPORT
@ GOSSIP_OPTION_SKIP_1
@ GOSSIP_MENU_EXPLAIN_1
@ GOSSIP_OPTION_EXPLAIN_2
@ GOSSIP_OFFSET_SKIP_1
@ GOSSIP_TEXT_EXPLAIN_1
@ GOSSIP_OFFSET_TELEPORT
@ GOSSIP_OFFSET_EXPLAIN_1
@ GOSSIP_MENU_EXPLAIN_2
@ GOSSIP_OFFSET_OPEN_GM_MENU
@ GOSSIP_OPTION_EXPLAIN
@ GOSSIP_OFFSET_EXPLAIN_2
@ GOSSIP_TEXT_INITIAL
@ GOSSIP_OFFSET_GM_INITIAL
@ GOSSIP_OFFSET_EXPLAIN
@ GOSSIP_OPTION_EXPLAIN_1
@ GOSSIP_MENU_INITIAL
@ GOSSIP_OPTION_TELEPORT
static float const malcolmFacing3
@ EVENT_SCRUFFY_EMOTE
@ EVENT_MALCOLM_FACE3
@ EVENT_MALCOLM_MOVE2
static Position const malcolmSpawn
@ EVENT_SERGEANT_CHAIN1
@ LINE_SERGEANT_ASK_YES
static float const scruffyFacing4
static Position const scruffySpawn
static float const scruffyFacing2
@ WHISPER_CRATES_DONE
@ SPELL_ARCANE_DISRUPTION
@ ITEM_ARCANE_DISRUPTOR
@ QUEST_DISPELLING_ILLUSIONS
@ SPELL_SUMMON_ARCANE_DISRUPTOR
@ SPELL_TELEPORT_PLAYER
@ EVENT_BARTLEBY_IDLE
@ DATA_REQUEST_FACING
@ EVENT_BELFAST_MOVE
static Position const scruffyPos3
static float const marthaIdleOrientation2
@ SPELL_TELEPORT_TO_COT_STRATHOLME
void AddSC_culling_of_stratholme()
@ GOSSIP_OPTION_STEP2
@ GOSSIP_OFFSET_STEP1
@ GOSSIP_OFFSET_STEP3
@ GOSSIP_OFFSET_STEP2
@ GOSSIP_OPTION_STEP1
@ GOSSIP_OPTION_STEP3
static float const marthaIdleOrientation1
@ DATA_SKIP_TO_PURGE
@ DATA_INSTANCE_PROGRESS
@ DATA_GM_OVERRIDE
@ DATA_UTHER_START
@ DATA_CRATES_START
@ DATA_CRATE_REVEALED
COSProgressStates GetStableStateFor(COSProgressStates const state)
@ CRATES_IN_PROGRESS
@ PURGE_STARTING
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
float GetExactDist2dSq(const float x, const float y) const
Definition Position.h:100
void MovementInform(uint32 type, uint32 id) override
static Creature * Find(Creature *helper)
CreatureAI * GetAI(Creature *creature) const override
std::unordered_map< ObjectGuid, time_t > Whispered
bool OnGossipSelect(Player *player, uint32, uint32 listId) override
void OnQuestAccept(Player *, Quest const *quest) override
bool OnGossipSelect(Player *player, uint32, uint32 listId) override
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
uint32 GetData(uint32 data) const override
void ReplaceIfCloser(Creature *candidate, Creature *&current, float &currentDist) const
void MovementInform(uint32 type, uint32 id) override
static Creature * Find(Creature *helper)
CreatureAI * GetAI(Creature *creature) const override
void MovementInform(uint32 type, uint32 id) override
static void Spawn(Map *map)
CreatureAI * GetAI(Creature *creature) const override
void MovementInform(uint32 type, uint32 id) override
CreatureAI * GetAI(Creature *creature) const override
void MovementInform(uint32 type, uint32 id) override
static Creature * Find(Creature *helper)
CreatureAI * GetAI(Creature *creature) const override
void MovementInform(uint32 type, uint32 id) override
static Creature * Find(Creature *helper)
CreatureAI * GetAI(Creature *creature) const override