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 "EventMap.h"
21#include "DB2Structure.h"
22#include "GameObject.h"
23#include "GameTime.h"
24#include "InstanceScript.h"
25#include "Map.h"
26#include "MotionMaster.h"
27#include "ObjectAccessor.h"
28#include "PassiveAI.h"
29#include "Player.h"
30#include "QuestDef.h"
31#include "ScriptedGossip.h"
32#include "ScriptMgr.h"
33#include "SpellInfo.h"
35#include "StringFormat.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
91
93{
94 public:
95 npc_hearthsinger_forresten_cot() : CreatureScript("npc_hearthsinger_forresten_cot") { }
96
98 {
99 npc_hearthsinger_forresten_cotAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()), _hadBelfast(false), _hadTalk(false) { }
100
101 void UpdateAI(uint32 diff) override
102 {
103 _events.Update(diff);
104 while (uint32 eventId = _events.ExecuteEvent())
105 {
106 uint32 talkerEntry = UINT_MAX, line = 0;
107 switch (eventId)
108 {
109 case EVENT_FORREST_1:
110 talkerEntry = 0, line = LINE_FORREST_1;
111 break;
112 case EVENT_JAMES_1:
113 talkerEntry = NPC_JAMES, line = LINE_JAMES_1;
114 break;
115 case EVENT_FRAS_1:
116 talkerEntry = NPC_FRAS, line = LINE_FRAS_1;
117 break;
119 if (Creature* belfast = me->FindNearestCreature(NPC_BELFAST, 80.0f, true))
120 belfast->AI()->DoAction(EVENT_BELFAST_MOVE);
121 return;
122 case EVENT_BELFAST_1:
123 talkerEntry = NPC_BELFAST, line = LINE_BELFAST_1;
124 break;
125 case EVENT_MAL_1:
126 talkerEntry = NPC_MAL, line = LINE_MAL_1;
127 break;
128 case EVENT_GRYAN_1:
129 talkerEntry = NPC_GRYAN, line = LINE_GRYAN_1;
130 break;
131 case EVENT_MAL_2:
132 talkerEntry = NPC_MAL, line = LINE_MAL_2;
133 break;
134 case EVENT_MAL_3:
135 talkerEntry = NPC_MAL, line = LINE_MAL_3;
136 break;
137 case EVENT_JAMES_2:
138 talkerEntry = NPC_JAMES, line = LINE_JAMES_2;
139 break;
140 case EVENT_FORREST_2:
141 talkerEntry = 0, line = LINE_FORREST_2;
142 break;
143 case EVENT_FRAS_2:
144 talkerEntry = NPC_FRAS, line = LINE_FRAS_2;
145 break;
146 default:
147 break;
148 }
149
150 if (talkerEntry != UINT_MAX)
151 {
152 Creature* talker = me;
153 if (talkerEntry)
154 talker = me->FindNearestCreature(talkerEntry, 80.0f, true);
155 if (talker)
156 talker->AI()->Talk(line, ObjectAccessor::GetPlayer(*talker, _triggeringPlayer));
157 }
158 }
159 }
160
161 // Player has hit the Belfast stairs areatrigger, we are taking him over for a moment
162 void SetGUID(ObjectGuid const& guid, int32 id) override
163 {
165 return;
166
167 if (_hadBelfast)
168 return;
169 _hadBelfast = true;
170 if (Creature* belfast = me->FindNearestCreature(NPC_BELFAST, 100.0f, true))
171 {
172 if (Player* invoker = ObjectAccessor::GetPlayer(*belfast, guid))
173 {
174 belfast->StopMoving();
175 belfast->SetFacingToObject(invoker);
176 belfast->AI()->Talk(LINE_BELFAST_0);
177 }
178 }
179 }
180
181 // Belfast SmartAI telling us it's reached the WP
193
194 void MoveInLineOfSight(Unit* unit) override
195 {
197 {
198 _hadTalk = true;
199 _triggeringPlayer = unit->GetGUID();
200 Seconds offset = Seconds(urand(10,30));
205 }
206 }
207
208 private:
214 };
215
216 CreatureAI* GetAI(Creature* creature) const override
217 {
218 return GetCullingOfStratholmeAI<npc_hearthsinger_forresten_cotAI>(creature);
219 }
220};
221
223{
224 public:
225 at_stratholme_inn_stairs_cot() : AreaTriggerScript("at_stratholme_inn_stairs_cot") { }
226
227 bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
228 {
229 if (InstanceScript* instance = player->GetInstanceScript())
230 if (instance->GetData(DATA_INSTANCE_PROGRESS) <= CRATES_IN_PROGRESS)
231 // Forrest's script will handle Belfast for this, since SmartAI lacks the features to do it (we can't pass a custom target)
232 if (Creature* forrest = player->FindNearestCreature(NPC_FORREST, 200.0f, true))
233 forrest->AI()->SetGUID(player->GetGUID(), DATA_INVOKING_PLAYER_GUID);
234 return true;
235 }
236};
237
273
283
285{
286 public:
287 npc_chromie_start() : CreatureScript("npc_chromie_start") { }
288
290 {
291 npc_chromie_startAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { }
292
298
304
305 bool OnGossipHello(Player* player) override
306 {
307 if (me->IsQuestGiver())
308 player->PrepareQuestMenu(me->GetGUID());
309
310 if (InstanceScript* instance = me->GetInstanceScript())
311 {
313 if (player->CanBeGameMaster()) // GM instance state override menu
315
316 uint32 state = instance->GetData(DATA_INSTANCE_PROGRESS);
317 if (state < PURGE_STARTING)
318 {
320 {
321 bool shouldAddSkipGossip = true;
322 Map::PlayerList const& players = instance->instance->GetPlayers();
323 for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
324 {
325 if (Player* player = it->GetSource())
326 {
327 if (player->IsGameMaster())
328 continue;
329 if (!player->HasAchieved(instance->instance->IsHeroic() ? ACHIEVEMENT_HEROIC : ACHIEVEMENT_NORMAL))
330 {
331 shouldAddSkipGossip = false;
332 break;
333 }
334 }
335 }
336 if (shouldAddSkipGossip)
338 }
340 }
341 else
342 {
345 }
346 }
347 else // random fallback, this should really never happen
349 return true;
350 }
351
352 bool OnGossipSelect(Player* player, uint32 /*sender*/, uint32 listId) override
353 {
354 uint32 const action = GetGossipActionFor(player, listId);
355 ClearGossipMenuFor(player);
356 switch (action - GOSSIP_ACTION_INFO_DEF)
357 {
362 break;
367 break;
370 [[fallthrough]];
372 CloseGossipMenuFor(player);
374 break;
379 break;
385 break;
388 for (uint32 state = 1; state <= COMPLETE; state = state << 1)
389 {
390 if (GetStableStateFor(COSProgressStates(state)) == state)
392 }
393 for (uint32 state = 1; state <= COMPLETE; state = state << 1)
394 {
395 if (GetStableStateFor(COSProgressStates(state)) != state)
397 }
399 break;
401 CloseGossipMenuFor(player);
402 if (!player->CanBeGameMaster())
403 break;
404 if (InstanceScript* instance = me->GetInstanceScript())
405 instance->SetGuidData(DATA_GM_RECALL, player->GetGUID());
406 break;
407 default: // handle GM instance state switch
408 CloseGossipMenuFor(player);
409 if (!player->CanBeGameMaster())
410 break;
411 if (InstanceScript* instance = me->GetInstanceScript())
413 break;
414 }
415 return false;
416 }
417
418 void OnQuestAccept(Player* /*player*/, Quest const* quest) override
419 {
422 }
423
424 private:
426 };
427
428 CreatureAI* GetAI(Creature* creature) const override
429 {
430 return GetCullingOfStratholmeAI<npc_chromie_startAI>(creature);
431 }
432};
433
456
462
464{
465 public:
466 npc_chromie_middle() : CreatureScript("npc_chromie_middle") { }
467
469 {
470 npc_chromie_middleAI(Creature* creature) : NullCreatureAI(creature), Instance(creature->GetInstanceScript()), WhisperDelay(0) { }
471
472 void JustAppeared() override
473 {
476 }
477
478 void UpdateAI(uint32 diff) override
479 {
480 if (!WhisperDelay)
481 return;
482 if (WhisperDelay > diff)
483 WhisperDelay -= diff;
484 else
485 {
488 WhisperDelay = 0;
489 }
490 }
491
492 void MoveInLineOfSight(Unit* unit) override
493 {
494 if (Player* player = unit->ToPlayer())
495 {
497 {
498 time_t& whisperedTime = Whispered[player->GetGUID()];
499 time_t now = GameTime::GetGameTime();
500 if (!whisperedTime || (now - whisperedTime) > 15)
501 {
502 Talk(WHISPER_COME_TALK, player);
503 whisperedTime = now;
504 }
505 }
506 }
507 }
508
514
526
553
556 std::unordered_map<ObjectGuid, time_t> Whispered;
557 };
558
559 CreatureAI* GetAI(Creature* creature) const override
560 {
561 return GetCullingOfStratholmeAI<npc_chromie_middleAI>(creature);
562 }
563};
564
565// Generic data for crate fluff events
576
577// Crate fluff event #1
579{
580 NPC_MARTHA = 27884,
581 NPC_JENA = 27885,
582
593
594 LINE_JENA1 = 0, // Let's see, we had chicken last night.
595 LINE_JENA2 = 1, // I've got plenty of cured bacon, but he had some for breakfast.
596 LINE_JENA3 = 2, // I need to make something healthy for him, he's still not recovered from that illness from last week.
597 LINE_JENA4 = 3, // Strawberries! Oh wait, they're not in season.
598 LINE_JENA5 = 4, // Ah, I'll make him some fresh bread! I need to get some flour from Martha!
599 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?
600 LINE_JENA7 = 6, // Thanks, Martha! I owe you one.
601 LINE_JENA8 = 7, // Oh, dear.
602 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.
603 LINE_MARTHA1= 0, // Oh hello, Jena. Of course you can borrow some grain. Help yourself.
604 LINE_MARTHA2= 1, // Oh, my.
605
615
616static constexpr float marthaIdleOrientation1 = 3.159046f;
617static constexpr float marthaIdleOrientation2 = 4.764749f;
618
620{
621 npc_martha_goslin() : CreatureScript("npc_martha_goslin") { }
622
624 {
626
634
635 void MovementInform(uint32 type, uint32 id) override
636 {
637 if (type == SPLINE_CHAIN_MOTION_TYPE)
638 {
639 switch (id)
640 {
641 case MOVEID_EVENT1:
644 Events.ScheduleEvent(EVENT_MARTHA_IDLE2, Seconds(9), Seconds(15));
645 break;
646 case MOVEID_EVENT2:
649 Events.ScheduleEvent(EVENT_MARTHA_IDLE1, Seconds(9), Seconds(15));
650 break;
651 default:
652 break;
653 }
654 }
655 }
656
657 void UpdateAI(uint32 diff) override
658 {
659 if (InterruptTimer)
660 {
661 if (InterruptTimer > diff)
662 {
663 InterruptTimer -= diff;
664 return;
665 }
666 diff -= InterruptTimer;
667 InterruptTimer = 0;
668 if (!ResumeInfo.Empty())
669 {
672 }
673
674 if (!diff)
675 return;
676 }
677
678 Events.Update(diff);
679 while (uint32 eventId = Events.ExecuteEvent())
680 {
681 switch (eventId)
682 {
686 break;
690 break;
691 default:
692 break;
693 }
694 }
695 }
696
697 void JustAppeared() override
698 {
700 Events.RescheduleEvent(EVENT_MARTHA_IDLE2, Seconds(5), Seconds(10));
701 }
702
706 };
707
708 CreatureAI* GetAI(Creature* creature) const override
709 {
710 return GetCullingOfStratholmeAI<npc_martha_goslinAI>(creature);
711 }
712};
713
715{
716 npc_jena_anderson() : CreatureScript("npc_jena_anderson") { }
717
718 static Creature* Find(Creature* helper)
719 {
720 return helper->FindNearestCreature(NPC_JENA, 45.0f, true);
721 }
722
724 {
725 npc_jena_andersonAI(Creature* creature) : NullCreatureAI(creature), Started(false) { }
726
727 void UpdateAI(uint32 diff) override
728 {
729 Events.Update(diff);
730 while (uint32 eventId = Events.ExecuteEvent())
731 {
732 switch (eventId)
733 {
734 case EVENT_JENA_IDLE1:
736 break;
737 case EVENT_JENA_IDLE2:
739 break;
740 case EVENT_JENA_START:
742 break;
743 case EVENT_MARTHA1:
744 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
745 {
746 martha->AI()->DoAction(0); // interrupt idle movement
747 martha->SetFacingToObject(me, true);
748 martha->AI()->Talk(LINE_MARTHA1, me);
749 }
750 break;
751 case EVENT_JENA7:
753 break;
754 case EVENT_JENA_MOVE2:
756 break;
757 case EVENT_JENA8:
758 {
760 Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true);
761 Talk(LINE_JENA8, martha);
762 Talk(LINE_JENA9, martha);
763 if (martha)
764 me->SetFacingToObject(martha);
765 break;
766 }
767 case EVENT_JENA_LEAVE:
768 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
769 {
770 martha->AI()->DoAction(0); // interrupt idle movement (again)
771 martha->SetFacingToObject(me, true);
772 martha->AI()->Talk(LINE_MARTHA2, me);
773 }
775 break;
776 default:
777 break;
778 }
779 }
780 }
781
782 void MovementInform(uint32 type, uint32 id) override
783 {
784 if (type == SPLINE_CHAIN_MOTION_TYPE)
785 {
786 switch (id)
787 {
788 case MOVEID_EVENT1: // IDLE1
789 if (Started)
790 Events.ScheduleEvent(EVENT_JENA_START, Seconds(1), Seconds(3));
791 else
792 Events.ScheduleEvent(EVENT_JENA_IDLE2, Milliseconds(200), Milliseconds(700));
793 break;
794 case MOVEID_EVENT2: // IDLE2
795 Events.ScheduleEvent(EVENT_JENA_IDLE1, Milliseconds(200), Milliseconds(700));
796 break;
797 case MOVEID_EVENT3:
798 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
799 {
800 me->SetFacingToObject(martha, true);
801 Talk(LINE_JENA6, martha);
802 }
803 Events.ScheduleEvent(EVENT_MARTHA1, Seconds(5) + Milliseconds(500));
804 Events.ScheduleEvent(EVENT_JENA7, Seconds(11));
805 Events.ScheduleEvent(EVENT_JENA_MOVE2, Seconds(16));
806 break;
807 case MOVEID_EVENT4:
809 Events.ScheduleEvent(EVENT_JENA8, Seconds(2));
810 Events.ScheduleEvent(EVENT_JENA_LEAVE, Seconds(8));
811 break;
812 case MOVEID_EVENT5:
814 break;
815 default:
816 break;
817 }
818 }
819 }
820
821 void DoAction(int32 action) override
822 {
823 if (action == ACTION_START_FLUFF)
824 Started = true;
825 }
826
827 void InitializeAI() override
828 {
829 if (me->isMoving())
830 return;
832 }
833
836 };
837
838 CreatureAI* GetAI(Creature* creature) const override
839 {
840 return GetCullingOfStratholmeAI<npc_jena_andersonAI>(creature);
841 }
842};
843
844// Crate fluff event #2
846{
848
854
856 LINE_BARTLEBY1 = 1, // Well, guess I should load everything back into the cart.
857 LINE_BARTLEBY2 = 2, // Oh, come on! My cart broke, my horse lost a shoe, and now the cargo goes bad!
858 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.
859
863
865{
866 npc_bartleby_battson() : CreatureScript("npc_bartleby_battson") { }
867
868 static Creature* Find(Creature* helper)
869 {
870 return helper->FindNearestCreature(NPC_BARTLEBY, 5.0f, true);
871 }
872
874 {
875 npc_bartleby_battsonAI(Creature* creature) : NullCreatureAI(creature), Started(false) { }
876
877 void InitializeAI() override
878 {
879 Events.ScheduleEvent(EVENT_BARTLEBY_IDLE, Minutes(1), Minutes(2));
880 }
881
882 void DoAction(int32 action) override
883 {
884 if (Started || action != ACTION_START_FLUFF)
885 return;
886 Started = true;
887 Events.CancelEvent(EVENT_BARTLEBY_IDLE);
888 Events.ScheduleEvent(EVENT_BARTLEBY1, Seconds(15), Seconds(30));
889 }
890
891 void MovementInform(uint32 type, uint32 id) override
892 {
893 if (type == SPLINE_CHAIN_MOTION_TYPE)
894 {
895 switch (id)
896 {
897 case MOVEID_EVENT1:
899 Events.ScheduleEvent(EVENT_BARTLEBY2, Seconds(4));
900 Events.ScheduleEvent(EVENT_BARTLEBY2_2, Seconds(6));
901 Events.ScheduleEvent(EVENT_BARTLEBY3, Seconds(12));
902 break;
903 case MOVEID_EVENT2:
905 break;
906 default:
907 break;
908 }
909 }
910 }
911
912 void UpdateAI(uint32 diff) override
913 {
914 Events.Update(diff);
915 while (uint32 eventId = Events.ExecuteEvent())
916 {
917 switch (eventId)
918 {
921 Events.Repeat(Minutes(2), Minutes(4));
922 break;
923 case EVENT_BARTLEBY1:
926 break;
927 case EVENT_BARTLEBY2:
929 break;
932 break;
933 case EVENT_BARTLEBY3:
937 break;
938 default:
939 break;
940 }
941 }
942 }
943
946 };
947
948 CreatureAI* GetAI(Creature* creature) const override
949 {
950 return GetCullingOfStratholmeAI<npc_bartleby_battsonAI>(creature);
951 }
952};
953
954// Crate fluff event #3
956{
957 NPC_MALCOLM = 27891,
958 NPC_SCRUFFY = 27892,
959
969
970 LINE_MALCOLM1 = 0, // Looks like a storm's coming in, Scruffy...
971 LINE_SCRUFFY1 = 0, // %s begins to growl...
972 LINE_MALCOLM2 = 1, // What's wrong, pal?
973 LINE_MALCOLM3 = 2, // What did you find, boy?
974 LINE_MALCOLM4 = 3, // This is no good, Scruffy. Stay here and guard the house, I need to go find a soldier.
975
982
984
985static constexpr Position malcolmSpawn = { 1605.2420f, 805.4160f, 122.9956f, 5.284148f };
986static constexpr Position scruffySpawn = { 1601.1030f, 805.3391f, 123.7677f, 5.471561f };
987static constexpr float scruffyFacing2 = 5.734883f;
988static constexpr float malcolmFacing3 = 2.303835f;
989static constexpr float scruffyFacing4 = 5.445427f;
990
992{
993 npc_malcolm_moore() : CreatureScript("npc_malcolm_moore") { }
994
995 static void Spawn(Map* map)
996 {
998 }
999
1001 {
1003
1004 void InitializeAI() override
1005 {
1008 scruffy->GetMotionMaster()->MoveAlongSplineChain(0, CHAIN_SCRUFFY1, true);
1009 }
1010
1011 void MovementInform(uint32 type, uint32 id) override
1012 {
1013 if (type == SPLINE_CHAIN_MOTION_TYPE)
1014 {
1015 switch (id)
1016 {
1017 case MOVEID_EVENT1:
1020 break;
1021 case MOVEID_EVENT2:
1022 Events.ScheduleEvent(EVENT_SCRUFFY1, Seconds(0));
1023 Events.ScheduleEvent(EVENT_MALCOLM2, Seconds(1));
1024 Events.ScheduleEvent(EVENT_SCRUFFY_MOVE, Seconds(4));
1025 Events.ScheduleEvent(EVENT_MALCOLM_MOVE, Seconds(8));
1026 break;
1027 case MOVEID_EVENT3:
1028 Events.ScheduleEvent(EVENT_MALCOLM_FACE3, Seconds(0));
1029 Events.ScheduleEvent(EVENT_MALCOLM3, Seconds(1));
1030 Events.ScheduleEvent(EVENT_MALCOLM4, Seconds(6));
1031 Events.ScheduleEvent(EVENT_MALCOLM_MOVE2, Seconds(12));
1032 break;
1033 case MOVEID_EVENT4:
1035 break;
1036 case MOVEID_EVENT5:
1037 Events.ScheduleEvent(EVENT_SCRUFFY_EMOTE, Seconds(0));
1038 break;
1039 default:
1040 break;
1041 }
1042 }
1043 }
1044
1045 void UpdateAI(uint32 diff) override
1046 {
1047 Events.Update(diff);
1048 while (uint32 eventId = Events.ExecuteEvent())
1049 {
1050 switch (eventId)
1051 {
1052 case EVENT_SCRUFFY1:
1053 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1054 {
1055 scruffy->SetFacingTo(scruffyFacing2);
1056 scruffy->AI()->Talk(LINE_SCRUFFY1);
1057 }
1058 break;
1059 case EVENT_MALCOLM2:
1060 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1061 {
1062 Talk(LINE_MALCOLM2, scruffy);
1063 me->SetFacingToObject(scruffy);
1064 }
1065 break;
1066 case EVENT_SCRUFFY_MOVE:
1067 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1068 scruffy->GetMotionMaster()->MoveAlongSplineChain(MOVEID_EVENT5, CHAIN_SCRUFFY2, false);
1069 break;
1070 case EVENT_MALCOLM_MOVE:
1072 break;
1074 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1075 scruffy->HandleEmoteCommand(EMOTE_ONESHOT_CREATURE_SPECIAL);
1076 break;
1079 break;
1080 case EVENT_MALCOLM3:
1082 break;
1083 case EVENT_MALCOLM4:
1084 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1085 {
1086 me->SetFacingToObject(scruffy);
1087 Talk(LINE_MALCOLM4, scruffy);
1088 }
1089 break;
1092 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1093 scruffy->SetFacingTo(scruffyFacing4);
1094 break;
1095 default:
1096 break;
1097 }
1098 }
1099 }
1100
1102 };
1103
1104 CreatureAI* GetAI(Creature* creature) const override
1105 {
1106 return GetCullingOfStratholmeAI<npc_malcolm_mooreAI>(creature);
1107 }
1108};
1109
1110// Crate fluff event #4
1112{
1115
1116 EVENT_SERGEANT_IDLE1, // questioning
1126
1129 LINE_SERGEANT_START = 2, // You don't mind me checking out your merchandise for signs of tampering, do you?
1130 LINE_SERGEANT1 = 3, // Wait, what is this? You've been holding out on me, Perelli!
1131 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.
1132 LINE_SERGEANT3 = 5, // We'll see about that, Perelli. We'll see about that.
1135 LINE_PERELLI1 = 2, // What are you talking about, Sergeant!
1136 LINE_PERELLI2 = 3, // You have to believe me, I'm innocent!
1137
1139 CHAIN_SERGEANT2 = 2
1141
1143{
1144 npc_sergeant_morigan() : CreatureScript("npc_sergeant_morigan") { }
1145
1146 static Creature* Find(Creature* helper)
1147 {
1148 return helper->FindNearestCreature(NPC_SERGEANT, 15.0f, true);
1149 }
1150
1152 {
1153 npc_sergeant_moriganAI(Creature* creature) : NullCreatureAI(creature), Started(false), Question(0) { }
1154
1155 void InitializeAI() override
1156 {
1157 Events.RescheduleEvent(EVENT_SERGEANT_IDLE1, Seconds(5), Seconds(15));
1158 }
1159
1160 void DoAction(int32 id) override
1161 {
1162 if (id == ACTION_START_FLUFF)
1163 Started = true;
1164 }
1165
1166 void MovementInform(uint32 type, uint32 id) override
1167 {
1168 if (type == SPLINE_CHAIN_MOTION_TYPE)
1169 switch (id)
1170 {
1171 case MOVEID_EVENT1:
1173 Events.ScheduleEvent(EVENT_SERGEANT1, Seconds(1));
1174 Events.ScheduleEvent(EVENT_SERGEANT_STAND, Seconds(3));
1175 Events.ScheduleEvent(EVENT_PERELLI1, Seconds(7));
1176 Events.ScheduleEvent(EVENT_SERGEANT2, Seconds(12));
1177 Events.ScheduleEvent(EVENT_PERELLI2, Seconds(20));
1178 Events.ScheduleEvent(EVENT_SERGEANT3, Seconds(26));
1179 Events.ScheduleEvent(EVENT_SERGEANT_LEAVE, Seconds(31));
1180 break;
1181 case MOVEID_EVENT2:
1183 break;
1184 }
1185 }
1186
1187 void Perelli(uint32 line, float ori = 0.0f)
1188 {
1189 if (Creature* perelli = me->FindNearestCreature(NPC_PERELLI, 10.0f, true))
1190 {
1191 perelli->AI()->Talk(line, me);
1192 if (ori)
1193 perelli->SetFacingTo(ori);
1194 }
1195 }
1196
1197 void UpdateAI(uint32 diff) override
1198 {
1199 Events.Update(diff);
1200 while (uint32 eventId = Events.ExecuteEvent())
1201 {
1202 switch (eventId)
1203 {
1205 if (Started)
1206 {
1207 Question = 2;
1209 }
1210 else
1211 {
1212 Question = urand(0, 1); // 0 is question that's answered with "yes", 1 is question that's answered with "no"
1214 }
1215 Events.ScheduleEvent(EVENT_SERGEANT_IDLE2, Seconds(10));
1216 break;
1219 if (Question == 2)
1220 Events.ScheduleEvent(EVENT_SERGEANT_CHAIN1, Seconds(2));
1221 else
1222 Events.ScheduleEvent(EVENT_SERGEANT_IDLE1, Seconds(15), Seconds(30));
1223 break;
1226 break;
1227 case EVENT_SERGEANT1:
1229 break;
1231 me->SetFacingTo(2.617994f);
1233 break;
1234 case EVENT_PERELLI1:
1235 Perelli(LINE_PERELLI1, 5.916666f);
1236 break;
1237 case EVENT_SERGEANT2:
1239 break;
1240 case EVENT_PERELLI2:
1242 break;
1243 case EVENT_SERGEANT3:
1245 break;
1248 break;
1249 default:
1250 break;
1251 }
1252 }
1253 }
1254
1258 };
1259
1260 CreatureAI* GetAI(Creature* creature) const override
1261 {
1262 return GetCullingOfStratholmeAI<npc_sergeant_moriganAI>(creature);
1263 }
1264};
1265
1266// Crate fluff event #5
1268{
1269 NPC_ROGER = 27903,
1270
1280
1281 LINE_ROGER1 = 0, // Ok, enough work for now. Time for refreshments and a little conversation in the inn.
1282 LINE_ROGER2 = 1, // Wait, what's that smell?
1283 LINE_ROGER3 = 2, // Can't be me, I took a bath 3 days ago!
1284 LINE_ROGER4 = 3, // Oh, close call. It's just the grain here.
1285 LINE_ROGER5 = 4, // Wait a second. Grain isn't supposed to smell like THAT! I better go find a guard.
1286
1289 CHAIN_ROGER3 = 3
1291
1293{
1294 npc_roger_owens() : CreatureScript("npc_roger_owens") { }
1295
1296 static Creature* Find(Creature* helper)
1297 {
1298 return helper->FindNearestCreature(NPC_ROGER, 30.0f, true);
1299 }
1300
1302 {
1303 npc_roger_owensAI(Creature* creature) : NullCreatureAI(creature) { }
1304
1305 void DoAction(int32 action) override
1306 {
1307 if (action == ACTION_START_FLUFF)
1308 Events.ScheduleEvent(EVENT_ROGER_START, Seconds(5), Seconds(12));
1309 }
1310
1311 void MovementInform(uint32 type, uint32 id) override
1312 {
1313 if (type == SPLINE_CHAIN_MOTION_TYPE)
1314 {
1315 switch (id)
1316 {
1317 case MOVEID_EVENT1:
1319 Events.ScheduleEvent(EVENT_ROGER_FACE3, Seconds(5));
1320 Events.ScheduleEvent(EVENT_ROGER3, Seconds(6));
1321 Events.ScheduleEvent(EVENT_ROGER_FACE4, Seconds(12));
1322 Events.ScheduleEvent(EVENT_ROGER4, Seconds(14));
1323 Events.ScheduleEvent(EVENT_ROGER_MOVE2, Seconds(18));
1324 break;
1325 case MOVEID_EVENT2:
1326 me->SetFacingTo(1.134464f, true);
1328 Events.ScheduleEvent(EVENT_ROGER5_2, Seconds(3));
1329 Events.ScheduleEvent(EVENT_ROGER_LEAVE, Seconds(8));
1330 break;
1331 case MOVEID_EVENT3:
1333 break;
1334 default:
1335 break;
1336 }
1337 }
1338 }
1339
1340 void UpdateAI(uint32 diff) override
1341 {
1342 Events.Update(diff);
1343 while (uint32 eventId = Events.ExecuteEvent())
1344 {
1345 switch (eventId)
1346 {
1347 case EVENT_ROGER_START:
1349 me->SetFacingTo(1.53589f);
1351 Events.ScheduleEvent(EVENT_ROGER_MOVE1, Seconds(6));
1352 break;
1353 case EVENT_ROGER_MOVE1:
1355 break;
1356 case EVENT_ROGER_FACE3:
1357 me->SetFacingTo(6.265732f);
1358 break;
1359 case EVENT_ROGER3:
1361 break;
1362 case EVENT_ROGER_FACE4:
1363 me->SetFacingTo(4.520403f);
1364 break;
1365 case EVENT_ROGER4:
1367 break;
1368 case EVENT_ROGER_MOVE2:
1370 break;
1371 case EVENT_ROGER5_2:
1373 break;
1374 case EVENT_ROGER_LEAVE:
1376 break;
1377 default:
1378 break;
1379 }
1380 }
1381 }
1382
1384 };
1385
1386 CreatureAI* GetAI(Creature* creature) const override
1387 {
1388 return GetCullingOfStratholmeAI<npc_roger_owensAI>(creature);
1389 }
1390};
1391
1400
1402{
1403public:
1404 npc_crate_helper() : CreatureScript("npc_crate_helper_cot") { }
1405
1407 {
1409
1410 void ReplaceIfCloser(Creature* candidate, Creature*& current, float& currentDist) const
1411 {
1412 if (!candidate)
1413 return;
1414 float newDist = me->GetExactDist2dSq(candidate);
1415 if (newDist >= currentDist)
1416 return;
1417 currentDist = newDist;
1418 current = candidate;
1419 }
1420
1421 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
1422 {
1423 if (!_crateRevealed && spellInfo->Id == SPELL_ARCANE_DISRUPTION)
1424 {
1425 _crateRevealed = true;
1426 if (InstanceScript* instance = me->GetInstanceScript())
1427 {
1428 // Update world state
1429 instance->SetData(DATA_CRATE_REVEALED, 1);
1430
1431 // Replace suspicious crate with plagued crate
1433 {
1434 crate->SummonGameObject(GO_PLAGUED_CRATE, *crate, crate->GetWorldRotation(), 1_days);
1435 crate->Delete();
1436 }
1437 if (GameObject* highlight = me->FindNearestGameObject(GO_CRATE_HIGHLIGHT, 5.0f))
1438 highlight->Delete();
1439
1440 // Find nearest fluff event and initiate it
1441 Creature* closest = nullptr;
1442 float closestDist = INFINITY;
1443 ReplaceIfCloser(npc_jena_anderson::Find(me), closest, closestDist);
1444 ReplaceIfCloser(npc_bartleby_battson::Find(me), closest, closestDist);
1445 ReplaceIfCloser(npc_sergeant_morigan::Find(me), closest, closestDist);
1446 ReplaceIfCloser(npc_roger_owens::Find(me), closest, closestDist);
1447 if (closest)
1448 closest->AI()->DoAction(ACTION_START_FLUFF);
1449 else
1451 }
1452 }
1453 }
1454
1455 uint32 GetData(uint32 data) const override
1456 {
1457 if (data == DATA_CRATE_REVEALED)
1458 return _crateRevealed ? 1 : 0;
1459 return 0;
1460 }
1461
1462 private:
1464 };
1465
1466 CreatureAI* GetAI(Creature* creature) const override
1467 {
1468 return GetCullingOfStratholmeAI<npc_crate_helperAI>(creature);
1469 }
1470};
1471
1473{
1476
1477 new npc_chromie_start();
1478 new npc_chromie_middle();
1479
1480 new npc_jena_anderson();
1481 new npc_martha_goslin();
1483 new npc_malcolm_moore();
1485 new npc_roger_owens();
1486 new npc_crate_helper();
1487}
@ IN_MILLISECONDS
Definition Common.h:38
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:28
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:32
@ SPLINE_CHAIN_MOTION_TYPE
@ QUEST_STATUS_COMPLETE
Definition QuestDef.h:148
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
uint32 GetGossipActionFor(Player *player, uint32 gossipListId)
void AddGossipItemFor(Player *player, GossipOptionNpc optionNpc, std::string text, uint32 sender, uint32 action)
void SendGossipMenuFor(Player *player, uint32 npcTextID, ObjectGuid const &guid)
void ClearGossipMenuFor(Player *player)
void InitGossipMenuFor(Player *player, uint32 menuId)
void CloseGossipMenuFor(Player *player)
@ GOSSIP_SENDER_MAIN
@ GOSSIP_ACTION_INFO_DEF
@ EMOTE_ONESHOT_EXCLAMATION
@ EMOTE_ONESHOT_CREATURE_SPECIAL
@ EMOTE_ONESHOT_NONE
@ EMOTE_ONESHOT_TALK
@ EMOTE_STATE_USE_STANDING
@ UNIT_STAND_STATE_KNEEL
Definition UnitDefines.h:50
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:42
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Creature *const me
Definition CreatureAI.h:63
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
CreatureAI * AI() const
Definition Creature.h:228
uint32 ExecuteEvent()
Definition EventMap.cpp:77
void Update(uint32 time)
Definition EventMap.h:61
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:40
Definition Map.h:225
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, Milliseconds duration=0ms, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty, SmoothPhasingInfo const *smoothPhasingInfo=nullptr)
Definition Object.cpp:1186
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void ResumeSplineChain(SplineChainResumeInfo const &info)
Player * ToPlayer()
Definition Object.h:126
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition Player.cpp:9904
bool HasAchieved(uint32 achievementId) const
Definition Player.cpp:27572
bool CanBeGameMaster() const
Definition Player.cpp:2105
bool IsGameMaster() const
Definition Player.h:1309
void PrepareQuestMenu(ObjectGuid guid)
Definition Player.cpp:14376
uint32 GetQuestId() const
Definition QuestDef.h:637
iterator end()
Definition RefManager.h:36
iterator begin()
Definition RefManager.h:35
uint32 const Id
Definition SpellInfo.h:328
static void GetResumeInfo(SplineChainResumeInfo &info, Unit const *owner, Optional< uint32 > id={})
virtual void DoAction(int32 param)
Definition UnitAI.h:73
Definition Unit.h:635
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10731
MotionMaster * GetMotionMaster()
Definition Unit.h:1723
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition Unit.cpp:13307
bool IsQuestGiver() const
Definition Unit.h:1009
void SetEmoteState(Emote emote)
Definition Unit.h:865
bool isMoving() const
Definition Unit.h:1804
void SetFacingTo(float const ori, bool force=true)
Definition Unit.cpp:13289
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition Unit.cpp:1657
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:1539
Map * GetMap() const
Definition Object.h:411
InstanceScript * GetInstanceScript() const
Definition Object.cpp:396
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
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:1398
float GetDistance2d(WorldObject const *obj) const
Definition Object.cpp:450
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1517
virtual uint32 GetData(uint32) const
Definition ZoneScript.h:99
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:100
virtual void SetGuidData(uint32, ObjectGuid)
Definition ZoneScript.h:92
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
static constexpr float marthaIdleOrientation1
@ 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
@ EVENT_SCRUFFY_EMOTE
@ EVENT_MALCOLM_FACE3
@ EVENT_MALCOLM_MOVE2
static constexpr float scruffyFacing4
@ EVENT_SERGEANT_CHAIN1
@ LINE_SERGEANT_ASK_YES
@ WHISPER_CRATES_DONE
static constexpr float marthaIdleOrientation2
@ SPELL_ARCANE_DISRUPTION
static constexpr float malcolmFacing3
@ ITEM_ARCANE_DISRUPTOR
@ QUEST_DISPELLING_ILLUSIONS
@ SPELL_SUMMON_ARCANE_DISRUPTOR
@ SPELL_TELEPORT_PLAYER
@ EVENT_BARTLEBY_IDLE
static constexpr float scruffyFacing2
static constexpr Position scruffySpawn
@ DATA_INVOKING_PLAYER_GUID
@ DATA_REQUEST_FACING
@ EVENT_BELFAST_MOVE
static constexpr Position malcolmSpawn
void AddSC_culling_of_stratholme()
@ GOSSIP_OPTION_STEP2
@ GOSSIP_OFFSET_STEP1
@ GOSSIP_OFFSET_STEP3
@ GOSSIP_OFFSET_STEP2
@ GOSSIP_OPTION_STEP1
@ GOSSIP_OPTION_STEP3
@ 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:52
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
constexpr float GetExactDist2dSq(const float x, const float y) const
Definition Position.h:108
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