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"
34#include "SpellScript.h"
36#include "StringFormat.h"
37#include "TemporarySummon.h"
38#include <unordered_map>
39
41{
42 NPC_FORREST = 30551,
43 NPC_BELFAST = 30571,
44 NPC_JAMES = 30553,
45 NPC_FRAS = 30552,
46 NPC_MAL = 31017,
47 NPC_GRYAN = 30561
48};
49
51{
52 EVENT_FORREST_1 = 1, // This whole situation seems a bit paranoid, don't you think?
53 EVENT_JAMES_1, // Orders are orders. If the Prince says jump...
54 EVENT_FRAS_1, // It's a strange order, you can't deny. Suspicious food? Under that definition, you should arrest Belfast!
56 EVENT_BELFAST_1, // I HEARD THAT! No more ale for you! Not a drop!
57 EVENT_MAL_1, // Enough, Michael. Business is hurting enough with this scare as it is. We can use every copper.
58 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.
59 EVENT_MAL_2, // Mal Corricks grudgingly nods.
60 EVENT_MAL_3, // I can't argue with that.
61 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.
62 EVENT_FORREST_2, // Thank the Light for that.
63 EVENT_FRAS_2 // Fras Siabi nods.
64};
65
85
92
94{
95 public:
96 npc_hearthsinger_forresten_cot() : CreatureScript("npc_hearthsinger_forresten_cot") { }
97
99 {
100 npc_hearthsinger_forresten_cotAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()), _hadBelfast(false), _hadTalk(false) { }
101
102 void UpdateAI(uint32 diff) override
103 {
104 _events.Update(diff);
105 while (uint32 eventId = _events.ExecuteEvent())
106 {
107 uint32 talkerEntry = UINT_MAX, line = 0;
108 switch (eventId)
109 {
110 case EVENT_FORREST_1:
111 talkerEntry = 0, line = LINE_FORREST_1;
112 break;
113 case EVENT_JAMES_1:
114 talkerEntry = NPC_JAMES, line = LINE_JAMES_1;
115 break;
116 case EVENT_FRAS_1:
117 talkerEntry = NPC_FRAS, line = LINE_FRAS_1;
118 break;
120 if (Creature* belfast = me->FindNearestCreature(NPC_BELFAST, 80.0f, true))
121 belfast->AI()->DoAction(EVENT_BELFAST_MOVE);
122 return;
123 case EVENT_BELFAST_1:
124 talkerEntry = NPC_BELFAST, line = LINE_BELFAST_1;
125 break;
126 case EVENT_MAL_1:
127 talkerEntry = NPC_MAL, line = LINE_MAL_1;
128 break;
129 case EVENT_GRYAN_1:
130 talkerEntry = NPC_GRYAN, line = LINE_GRYAN_1;
131 break;
132 case EVENT_MAL_2:
133 talkerEntry = NPC_MAL, line = LINE_MAL_2;
134 break;
135 case EVENT_MAL_3:
136 talkerEntry = NPC_MAL, line = LINE_MAL_3;
137 break;
138 case EVENT_JAMES_2:
139 talkerEntry = NPC_JAMES, line = LINE_JAMES_2;
140 break;
141 case EVENT_FORREST_2:
142 talkerEntry = 0, line = LINE_FORREST_2;
143 break;
144 case EVENT_FRAS_2:
145 talkerEntry = NPC_FRAS, line = LINE_FRAS_2;
146 break;
147 default:
148 break;
149 }
150
151 if (talkerEntry != UINT_MAX)
152 {
153 Creature* talker = me;
154 if (talkerEntry)
155 talker = me->FindNearestCreature(talkerEntry, 80.0f, true);
156 if (talker)
157 talker->AI()->Talk(line, ObjectAccessor::GetPlayer(*talker, _triggeringPlayer));
158 }
159 }
160 }
161
162 // Player has hit the Belfast stairs areatrigger, we are taking him over for a moment
163 void SetGUID(ObjectGuid const& guid, int32 id) override
164 {
166 return;
167
168 if (_hadBelfast)
169 return;
170 _hadBelfast = true;
171 if (Creature* belfast = me->FindNearestCreature(NPC_BELFAST, 100.0f, true))
172 {
173 if (Player* invoker = ObjectAccessor::GetPlayer(*belfast, guid))
174 {
175 belfast->StopMoving();
176 belfast->SetFacingToObject(invoker);
177 belfast->AI()->Talk(LINE_BELFAST_0);
178 }
179 }
180 }
181
182 // Belfast SmartAI telling us it's reached the WP
194
195 void MoveInLineOfSight(Unit* unit) override
196 {
198 {
199 _hadTalk = true;
200 _triggeringPlayer = unit->GetGUID();
201 Seconds offset = Seconds(urand(10,30));
206 }
207 }
208
209 private:
215 };
216
217 CreatureAI* GetAI(Creature* creature) const override
218 {
219 return GetCullingOfStratholmeAI<npc_hearthsinger_forresten_cotAI>(creature);
220 }
221};
222
224{
225 public:
226 at_stratholme_inn_stairs_cot() : AreaTriggerScript("at_stratholme_inn_stairs_cot") { }
227
228 bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
229 {
230 if (InstanceScript* instance = player->GetInstanceScript())
231 if (instance->GetData(DATA_INSTANCE_PROGRESS) <= CRATES_IN_PROGRESS)
232 // Forrest's script will handle Belfast for this, since SmartAI lacks the features to do it (we can't pass a custom target)
233 if (Creature* forrest = player->FindNearestCreature(NPC_FORREST, 200.0f, true))
234 forrest->AI()->SetGUID(player->GetGUID(), DATA_INVOKING_PLAYER_GUID);
235 return true;
236 }
237};
238
274
284
286{
287 public:
288 npc_chromie_start() : CreatureScript("npc_chromie_start") { }
289
291 {
292 npc_chromie_startAI(Creature* creature) : NullCreatureAI(creature), _instance(creature->GetInstanceScript()) { }
293
299
305
306 bool OnGossipHello(Player* player) override
307 {
308 if (me->IsQuestGiver())
309 player->PrepareQuestMenu(me->GetGUID());
310
311 if (InstanceScript* instance = me->GetInstanceScript())
312 {
314 if (player->CanBeGameMaster()) // GM instance state override menu
316
317 uint32 state = instance->GetData(DATA_INSTANCE_PROGRESS);
318 if (state < PURGE_STARTING)
319 {
321 {
322 bool shouldAddSkipGossip = true;
323 Map::PlayerList const& players = instance->instance->GetPlayers();
324 for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
325 {
326 if (Player* player = it->GetSource())
327 {
328 if (player->IsGameMaster())
329 continue;
330 if (!player->HasAchieved(instance->instance->IsHeroic() ? ACHIEVEMENT_HEROIC : ACHIEVEMENT_NORMAL))
331 {
332 shouldAddSkipGossip = false;
333 break;
334 }
335 }
336 }
337 if (shouldAddSkipGossip)
339 }
341 }
342 else
343 {
346 }
347 }
348 else // random fallback, this should really never happen
350 return true;
351 }
352
353 bool OnGossipSelect(Player* player, uint32 /*sender*/, uint32 listId) override
354 {
355 uint32 const action = GetGossipActionFor(player, listId);
356 ClearGossipMenuFor(player);
357 switch (action - GOSSIP_ACTION_INFO_DEF)
358 {
363 break;
368 break;
371 [[fallthrough]];
373 CloseGossipMenuFor(player);
375 break;
380 break;
386 break;
389 for (uint32 state = 1; state <= COMPLETE; state = state << 1)
390 {
391 if (GetStableStateFor(COSProgressStates(state)) == state)
393 }
394 for (uint32 state = 1; state <= COMPLETE; state = state << 1)
395 {
396 if (GetStableStateFor(COSProgressStates(state)) != state)
398 }
400 break;
402 CloseGossipMenuFor(player);
403 if (!player->CanBeGameMaster())
404 break;
405 if (InstanceScript* instance = me->GetInstanceScript())
406 instance->SetGuidData(DATA_GM_RECALL, player->GetGUID());
407 break;
408 default: // handle GM instance state switch
409 CloseGossipMenuFor(player);
410 if (!player->CanBeGameMaster())
411 break;
412 if (InstanceScript* instance = me->GetInstanceScript())
414 break;
415 }
416 return false;
417 }
418
419 void OnQuestAccept(Player* /*player*/, Quest const* quest) override
420 {
423 }
424
425 private:
427 };
428
429 CreatureAI* GetAI(Creature* creature) const override
430 {
431 return GetCullingOfStratholmeAI<npc_chromie_startAI>(creature);
432 }
433};
434
457
463
465{
466 public:
467 npc_chromie_middle() : CreatureScript("npc_chromie_middle") { }
468
470 {
471 npc_chromie_middleAI(Creature* creature) : NullCreatureAI(creature), Instance(creature->GetInstanceScript()), WhisperDelay(0) { }
472
473 void JustAppeared() override
474 {
477 }
478
479 void UpdateAI(uint32 diff) override
480 {
481 if (!WhisperDelay)
482 return;
483 if (WhisperDelay > diff)
484 WhisperDelay -= diff;
485 else
486 {
489 WhisperDelay = 0;
490 }
491 }
492
493 void MoveInLineOfSight(Unit* unit) override
494 {
495 if (Player* player = unit->ToPlayer())
496 {
498 {
499 time_t& whisperedTime = Whispered[player->GetGUID()];
500 time_t now = GameTime::GetGameTime();
501 if (!whisperedTime || (now - whisperedTime) > 15)
502 {
503 Talk(WHISPER_COME_TALK, player);
504 whisperedTime = now;
505 }
506 }
507 }
508 }
509
515
527
554
557 std::unordered_map<ObjectGuid, time_t> Whispered;
558 };
559
560 CreatureAI* GetAI(Creature* creature) const override
561 {
562 return GetCullingOfStratholmeAI<npc_chromie_middleAI>(creature);
563 }
564};
565
566// Generic data for crate fluff events
577
578// Crate fluff event #1
580{
581 NPC_MARTHA = 27884,
582 NPC_JENA = 27885,
583
594
595 LINE_JENA1 = 0, // Let's see, we had chicken last night.
596 LINE_JENA2 = 1, // I've got plenty of cured bacon, but he had some for breakfast.
597 LINE_JENA3 = 2, // I need to make something healthy for him, he's still not recovered from that illness from last week.
598 LINE_JENA4 = 3, // Strawberries! Oh wait, they're not in season.
599 LINE_JENA5 = 4, // Ah, I'll make him some fresh bread! I need to get some flour from Martha!
600 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?
601 LINE_JENA7 = 6, // Thanks, Martha! I owe you one.
602 LINE_JENA8 = 7, // Oh, dear.
603 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.
604 LINE_MARTHA1= 0, // Oh hello, Jena. Of course you can borrow some grain. Help yourself.
605 LINE_MARTHA2= 1, // Oh, my.
606
616
617static constexpr float marthaIdleOrientation1 = 3.159046f;
618static constexpr float marthaIdleOrientation2 = 4.764749f;
619
621{
622 npc_martha_goslin() : CreatureScript("npc_martha_goslin") { }
623
625 {
627
635
636 void MovementInform(uint32 type, uint32 id) override
637 {
638 if (type == SPLINE_CHAIN_MOTION_TYPE)
639 {
640 switch (id)
641 {
642 case MOVEID_EVENT1:
645 Events.ScheduleEvent(EVENT_MARTHA_IDLE2, Seconds(9), Seconds(15));
646 break;
647 case MOVEID_EVENT2:
650 Events.ScheduleEvent(EVENT_MARTHA_IDLE1, Seconds(9), Seconds(15));
651 break;
652 default:
653 break;
654 }
655 }
656 }
657
658 void UpdateAI(uint32 diff) override
659 {
660 if (InterruptTimer)
661 {
662 if (InterruptTimer > diff)
663 {
664 InterruptTimer -= diff;
665 return;
666 }
667 diff -= InterruptTimer;
668 InterruptTimer = 0;
669 if (!ResumeInfo.Empty())
670 {
673 }
674
675 if (!diff)
676 return;
677 }
678
679 Events.Update(diff);
680 while (uint32 eventId = Events.ExecuteEvent())
681 {
682 switch (eventId)
683 {
687 break;
691 break;
692 default:
693 break;
694 }
695 }
696 }
697
698 void JustAppeared() override
699 {
701 Events.RescheduleEvent(EVENT_MARTHA_IDLE2, Seconds(5), Seconds(10));
702 }
703
707 };
708
709 CreatureAI* GetAI(Creature* creature) const override
710 {
711 return GetCullingOfStratholmeAI<npc_martha_goslinAI>(creature);
712 }
713};
714
716{
717 npc_jena_anderson() : CreatureScript("npc_jena_anderson") { }
718
719 static Creature* Find(Creature* helper)
720 {
721 return helper->FindNearestCreature(NPC_JENA, 45.0f, true);
722 }
723
725 {
726 npc_jena_andersonAI(Creature* creature) : NullCreatureAI(creature), Started(false) { }
727
728 void UpdateAI(uint32 diff) override
729 {
730 Events.Update(diff);
731 while (uint32 eventId = Events.ExecuteEvent())
732 {
733 switch (eventId)
734 {
735 case EVENT_JENA_IDLE1:
737 break;
738 case EVENT_JENA_IDLE2:
740 break;
741 case EVENT_JENA_START:
743 break;
744 case EVENT_MARTHA1:
745 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
746 {
747 martha->AI()->DoAction(0); // interrupt idle movement
748 martha->SetFacingToObject(me, true);
749 martha->AI()->Talk(LINE_MARTHA1, me);
750 }
751 break;
752 case EVENT_JENA7:
754 break;
755 case EVENT_JENA_MOVE2:
757 break;
758 case EVENT_JENA8:
759 {
761 Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true);
762 Talk(LINE_JENA8, martha);
763 Talk(LINE_JENA9, martha);
764 if (martha)
765 me->SetFacingToObject(martha);
766 break;
767 }
768 case EVENT_JENA_LEAVE:
769 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
770 {
771 martha->AI()->DoAction(0); // interrupt idle movement (again)
772 martha->SetFacingToObject(me, true);
773 martha->AI()->Talk(LINE_MARTHA2, me);
774 }
776 break;
777 default:
778 break;
779 }
780 }
781 }
782
783 void MovementInform(uint32 type, uint32 id) override
784 {
785 if (type == SPLINE_CHAIN_MOTION_TYPE)
786 {
787 switch (id)
788 {
789 case MOVEID_EVENT1: // IDLE1
790 if (Started)
791 Events.ScheduleEvent(EVENT_JENA_START, Seconds(1), Seconds(3));
792 else
793 Events.ScheduleEvent(EVENT_JENA_IDLE2, Milliseconds(200), Milliseconds(700));
794 break;
795 case MOVEID_EVENT2: // IDLE2
796 Events.ScheduleEvent(EVENT_JENA_IDLE1, Milliseconds(200), Milliseconds(700));
797 break;
798 case MOVEID_EVENT3:
799 if (Creature* martha = me->FindNearestCreature(NPC_MARTHA, 100.0f, true))
800 {
801 me->SetFacingToObject(martha, true);
802 Talk(LINE_JENA6, martha);
803 }
804 Events.ScheduleEvent(EVENT_MARTHA1, Seconds(5) + Milliseconds(500));
805 Events.ScheduleEvent(EVENT_JENA7, Seconds(11));
806 Events.ScheduleEvent(EVENT_JENA_MOVE2, Seconds(16));
807 break;
808 case MOVEID_EVENT4:
810 Events.ScheduleEvent(EVENT_JENA8, Seconds(2));
811 Events.ScheduleEvent(EVENT_JENA_LEAVE, Seconds(8));
812 break;
813 case MOVEID_EVENT5:
815 break;
816 default:
817 break;
818 }
819 }
820 }
821
822 void DoAction(int32 action) override
823 {
824 if (action == ACTION_START_FLUFF)
825 Started = true;
826 }
827
828 void InitializeAI() override
829 {
830 if (me->isMoving())
831 return;
833 }
834
837 };
838
839 CreatureAI* GetAI(Creature* creature) const override
840 {
841 return GetCullingOfStratholmeAI<npc_jena_andersonAI>(creature);
842 }
843};
844
845// Crate fluff event #2
847{
849
855
857 LINE_BARTLEBY1 = 1, // Well, guess I should load everything back into the cart.
858 LINE_BARTLEBY2 = 2, // Oh, come on! My cart broke, my horse lost a shoe, and now the cargo goes bad!
859 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.
860
864
866{
867 npc_bartleby_battson() : CreatureScript("npc_bartleby_battson") { }
868
869 static Creature* Find(Creature* helper)
870 {
871 return helper->FindNearestCreature(NPC_BARTLEBY, 5.0f, true);
872 }
873
875 {
876 npc_bartleby_battsonAI(Creature* creature) : NullCreatureAI(creature), Started(false) { }
877
878 void InitializeAI() override
879 {
880 Events.ScheduleEvent(EVENT_BARTLEBY_IDLE, Minutes(1), Minutes(2));
881 }
882
883 void DoAction(int32 action) override
884 {
885 if (Started || action != ACTION_START_FLUFF)
886 return;
887 Started = true;
888 Events.CancelEvent(EVENT_BARTLEBY_IDLE);
889 Events.ScheduleEvent(EVENT_BARTLEBY1, Seconds(15), Seconds(30));
890 }
891
892 void MovementInform(uint32 type, uint32 id) override
893 {
894 if (type == SPLINE_CHAIN_MOTION_TYPE)
895 {
896 switch (id)
897 {
898 case MOVEID_EVENT1:
900 Events.ScheduleEvent(EVENT_BARTLEBY2, Seconds(4));
901 Events.ScheduleEvent(EVENT_BARTLEBY2_2, Seconds(6));
902 Events.ScheduleEvent(EVENT_BARTLEBY3, Seconds(12));
903 break;
904 case MOVEID_EVENT2:
906 break;
907 default:
908 break;
909 }
910 }
911 }
912
913 void UpdateAI(uint32 diff) override
914 {
915 Events.Update(diff);
916 while (uint32 eventId = Events.ExecuteEvent())
917 {
918 switch (eventId)
919 {
922 Events.Repeat(Minutes(2), Minutes(4));
923 break;
924 case EVENT_BARTLEBY1:
927 break;
928 case EVENT_BARTLEBY2:
930 break;
933 break;
934 case EVENT_BARTLEBY3:
938 break;
939 default:
940 break;
941 }
942 }
943 }
944
947 };
948
949 CreatureAI* GetAI(Creature* creature) const override
950 {
951 return GetCullingOfStratholmeAI<npc_bartleby_battsonAI>(creature);
952 }
953};
954
955// Crate fluff event #3
957{
958 NPC_MALCOLM = 27891,
959 NPC_SCRUFFY = 27892,
960
970
971 LINE_MALCOLM1 = 0, // Looks like a storm's coming in, Scruffy...
972 LINE_SCRUFFY1 = 0, // %s begins to growl...
973 LINE_MALCOLM2 = 1, // What's wrong, pal?
974 LINE_MALCOLM3 = 2, // What did you find, boy?
975 LINE_MALCOLM4 = 3, // This is no good, Scruffy. Stay here and guard the house, I need to go find a soldier.
976
983
985
986static constexpr Position malcolmSpawn = { 1605.2420f, 805.4160f, 122.9956f, 5.284148f };
987static constexpr Position scruffySpawn = { 1601.1030f, 805.3391f, 123.7677f, 5.471561f };
988static constexpr float scruffyFacing2 = 5.734883f;
989static constexpr float malcolmFacing3 = 2.303835f;
990static constexpr float scruffyFacing4 = 5.445427f;
991
993{
994 npc_malcolm_moore() : CreatureScript("npc_malcolm_moore") { }
995
996 static void Spawn(Map* map)
997 {
999 }
1000
1002 {
1004
1005 void InitializeAI() override
1006 {
1009 scruffy->GetMotionMaster()->MoveAlongSplineChain(0, CHAIN_SCRUFFY1, true);
1010 }
1011
1012 void MovementInform(uint32 type, uint32 id) override
1013 {
1014 if (type == SPLINE_CHAIN_MOTION_TYPE)
1015 {
1016 switch (id)
1017 {
1018 case MOVEID_EVENT1:
1021 break;
1022 case MOVEID_EVENT2:
1023 Events.ScheduleEvent(EVENT_SCRUFFY1, Seconds(0));
1024 Events.ScheduleEvent(EVENT_MALCOLM2, Seconds(1));
1025 Events.ScheduleEvent(EVENT_SCRUFFY_MOVE, Seconds(4));
1026 Events.ScheduleEvent(EVENT_MALCOLM_MOVE, Seconds(8));
1027 break;
1028 case MOVEID_EVENT3:
1029 Events.ScheduleEvent(EVENT_MALCOLM_FACE3, Seconds(0));
1030 Events.ScheduleEvent(EVENT_MALCOLM3, Seconds(1));
1031 Events.ScheduleEvent(EVENT_MALCOLM4, Seconds(6));
1032 Events.ScheduleEvent(EVENT_MALCOLM_MOVE2, Seconds(12));
1033 break;
1034 case MOVEID_EVENT4:
1036 break;
1037 case MOVEID_EVENT5:
1038 Events.ScheduleEvent(EVENT_SCRUFFY_EMOTE, Seconds(0));
1039 break;
1040 default:
1041 break;
1042 }
1043 }
1044 }
1045
1046 void UpdateAI(uint32 diff) override
1047 {
1048 Events.Update(diff);
1049 while (uint32 eventId = Events.ExecuteEvent())
1050 {
1051 switch (eventId)
1052 {
1053 case EVENT_SCRUFFY1:
1054 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1055 {
1056 scruffy->SetFacingTo(scruffyFacing2);
1057 scruffy->AI()->Talk(LINE_SCRUFFY1);
1058 }
1059 break;
1060 case EVENT_MALCOLM2:
1061 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1062 {
1063 Talk(LINE_MALCOLM2, scruffy);
1064 me->SetFacingToObject(scruffy);
1065 }
1066 break;
1067 case EVENT_SCRUFFY_MOVE:
1068 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1069 scruffy->GetMotionMaster()->MoveAlongSplineChain(MOVEID_EVENT5, CHAIN_SCRUFFY2, false);
1070 break;
1071 case EVENT_MALCOLM_MOVE:
1073 break;
1075 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1076 scruffy->HandleEmoteCommand(EMOTE_ONESHOT_CREATURE_SPECIAL);
1077 break;
1080 break;
1081 case EVENT_MALCOLM3:
1083 break;
1084 case EVENT_MALCOLM4:
1085 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1086 {
1087 me->SetFacingToObject(scruffy);
1088 Talk(LINE_MALCOLM4, scruffy);
1089 }
1090 break;
1093 if (Creature* scruffy = me->FindNearestCreature(NPC_SCRUFFY, 100.0f, true))
1094 scruffy->SetFacingTo(scruffyFacing4);
1095 break;
1096 default:
1097 break;
1098 }
1099 }
1100 }
1101
1103 };
1104
1105 CreatureAI* GetAI(Creature* creature) const override
1106 {
1107 return GetCullingOfStratholmeAI<npc_malcolm_mooreAI>(creature);
1108 }
1109};
1110
1111// Crate fluff event #4
1113{
1116
1117 EVENT_SERGEANT_IDLE1, // questioning
1127
1130 LINE_SERGEANT_START = 2, // You don't mind me checking out your merchandise for signs of tampering, do you?
1131 LINE_SERGEANT1 = 3, // Wait, what is this? You've been holding out on me, Perelli!
1132 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.
1133 LINE_SERGEANT3 = 5, // We'll see about that, Perelli. We'll see about that.
1136 LINE_PERELLI1 = 2, // What are you talking about, Sergeant!
1137 LINE_PERELLI2 = 3, // You have to believe me, I'm innocent!
1138
1140 CHAIN_SERGEANT2 = 2
1142
1144{
1145 npc_sergeant_morigan() : CreatureScript("npc_sergeant_morigan") { }
1146
1147 static Creature* Find(Creature* helper)
1148 {
1149 return helper->FindNearestCreature(NPC_SERGEANT, 15.0f, true);
1150 }
1151
1153 {
1154 npc_sergeant_moriganAI(Creature* creature) : NullCreatureAI(creature), Started(false), Question(0) { }
1155
1156 void InitializeAI() override
1157 {
1158 Events.RescheduleEvent(EVENT_SERGEANT_IDLE1, Seconds(5), Seconds(15));
1159 }
1160
1161 void DoAction(int32 id) override
1162 {
1163 if (id == ACTION_START_FLUFF)
1164 Started = true;
1165 }
1166
1167 void MovementInform(uint32 type, uint32 id) override
1168 {
1169 if (type == SPLINE_CHAIN_MOTION_TYPE)
1170 switch (id)
1171 {
1172 case MOVEID_EVENT1:
1174 Events.ScheduleEvent(EVENT_SERGEANT1, Seconds(1));
1175 Events.ScheduleEvent(EVENT_SERGEANT_STAND, Seconds(3));
1176 Events.ScheduleEvent(EVENT_PERELLI1, Seconds(7));
1177 Events.ScheduleEvent(EVENT_SERGEANT2, Seconds(12));
1178 Events.ScheduleEvent(EVENT_PERELLI2, Seconds(20));
1179 Events.ScheduleEvent(EVENT_SERGEANT3, Seconds(26));
1180 Events.ScheduleEvent(EVENT_SERGEANT_LEAVE, Seconds(31));
1181 break;
1182 case MOVEID_EVENT2:
1184 break;
1185 }
1186 }
1187
1188 void Perelli(uint32 line, float ori = 0.0f)
1189 {
1190 if (Creature* perelli = me->FindNearestCreature(NPC_PERELLI, 10.0f, true))
1191 {
1192 perelli->AI()->Talk(line, me);
1193 if (ori)
1194 perelli->SetFacingTo(ori);
1195 }
1196 }
1197
1198 void UpdateAI(uint32 diff) override
1199 {
1200 Events.Update(diff);
1201 while (uint32 eventId = Events.ExecuteEvent())
1202 {
1203 switch (eventId)
1204 {
1206 if (Started)
1207 {
1208 Question = 2;
1210 }
1211 else
1212 {
1213 Question = urand(0, 1); // 0 is question that's answered with "yes", 1 is question that's answered with "no"
1215 }
1216 Events.ScheduleEvent(EVENT_SERGEANT_IDLE2, Seconds(10));
1217 break;
1220 if (Question == 2)
1221 Events.ScheduleEvent(EVENT_SERGEANT_CHAIN1, Seconds(2));
1222 else
1223 Events.ScheduleEvent(EVENT_SERGEANT_IDLE1, Seconds(15), Seconds(30));
1224 break;
1227 break;
1228 case EVENT_SERGEANT1:
1230 break;
1232 me->SetFacingTo(2.617994f);
1234 break;
1235 case EVENT_PERELLI1:
1236 Perelli(LINE_PERELLI1, 5.916666f);
1237 break;
1238 case EVENT_SERGEANT2:
1240 break;
1241 case EVENT_PERELLI2:
1243 break;
1244 case EVENT_SERGEANT3:
1246 break;
1249 break;
1250 default:
1251 break;
1252 }
1253 }
1254 }
1255
1259 };
1260
1261 CreatureAI* GetAI(Creature* creature) const override
1262 {
1263 return GetCullingOfStratholmeAI<npc_sergeant_moriganAI>(creature);
1264 }
1265};
1266
1267// Crate fluff event #5
1269{
1270 NPC_ROGER = 27903,
1271
1281
1282 LINE_ROGER1 = 0, // Ok, enough work for now. Time for refreshments and a little conversation in the inn.
1283 LINE_ROGER2 = 1, // Wait, what's that smell?
1284 LINE_ROGER3 = 2, // Can't be me, I took a bath 3 days ago!
1285 LINE_ROGER4 = 3, // Oh, close call. It's just the grain here.
1286 LINE_ROGER5 = 4, // Wait a second. Grain isn't supposed to smell like THAT! I better go find a guard.
1287
1290 CHAIN_ROGER3 = 3
1292
1294{
1295 npc_roger_owens() : CreatureScript("npc_roger_owens") { }
1296
1297 static Creature* Find(Creature* helper)
1298 {
1299 return helper->FindNearestCreature(NPC_ROGER, 30.0f, true);
1300 }
1301
1303 {
1304 npc_roger_owensAI(Creature* creature) : NullCreatureAI(creature) { }
1305
1306 void DoAction(int32 action) override
1307 {
1308 if (action == ACTION_START_FLUFF)
1309 Events.ScheduleEvent(EVENT_ROGER_START, Seconds(5), Seconds(12));
1310 }
1311
1312 void MovementInform(uint32 type, uint32 id) override
1313 {
1314 if (type == SPLINE_CHAIN_MOTION_TYPE)
1315 {
1316 switch (id)
1317 {
1318 case MOVEID_EVENT1:
1320 Events.ScheduleEvent(EVENT_ROGER_FACE3, Seconds(5));
1321 Events.ScheduleEvent(EVENT_ROGER3, Seconds(6));
1322 Events.ScheduleEvent(EVENT_ROGER_FACE4, Seconds(12));
1323 Events.ScheduleEvent(EVENT_ROGER4, Seconds(14));
1324 Events.ScheduleEvent(EVENT_ROGER_MOVE2, Seconds(18));
1325 break;
1326 case MOVEID_EVENT2:
1327 me->SetFacingTo(1.134464f, true);
1329 Events.ScheduleEvent(EVENT_ROGER5_2, Seconds(3));
1330 Events.ScheduleEvent(EVENT_ROGER_LEAVE, Seconds(8));
1331 break;
1332 case MOVEID_EVENT3:
1334 break;
1335 default:
1336 break;
1337 }
1338 }
1339 }
1340
1341 void UpdateAI(uint32 diff) override
1342 {
1343 Events.Update(diff);
1344 while (uint32 eventId = Events.ExecuteEvent())
1345 {
1346 switch (eventId)
1347 {
1348 case EVENT_ROGER_START:
1350 me->SetFacingTo(1.53589f);
1352 Events.ScheduleEvent(EVENT_ROGER_MOVE1, Seconds(6));
1353 break;
1354 case EVENT_ROGER_MOVE1:
1356 break;
1357 case EVENT_ROGER_FACE3:
1358 me->SetFacingTo(6.265732f);
1359 break;
1360 case EVENT_ROGER3:
1362 break;
1363 case EVENT_ROGER_FACE4:
1364 me->SetFacingTo(4.520403f);
1365 break;
1366 case EVENT_ROGER4:
1368 break;
1369 case EVENT_ROGER_MOVE2:
1371 break;
1372 case EVENT_ROGER5_2:
1374 break;
1375 case EVENT_ROGER_LEAVE:
1377 break;
1378 default:
1379 break;
1380 }
1381 }
1382 }
1383
1385 };
1386
1387 CreatureAI* GetAI(Creature* creature) const override
1388 {
1389 return GetCullingOfStratholmeAI<npc_roger_owensAI>(creature);
1390 }
1391};
1392
1401
1403{
1404public:
1405 npc_crate_helper() : CreatureScript("npc_crate_helper_cot") { }
1406
1408 {
1410
1411 void ReplaceIfCloser(Creature* candidate, Creature*& current, float& currentDist) const
1412 {
1413 if (!candidate)
1414 return;
1415 float newDist = me->GetExactDist2dSq(candidate);
1416 if (newDist >= currentDist)
1417 return;
1418 currentDist = newDist;
1419 current = candidate;
1420 }
1421
1422 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
1423 {
1424 if (!_crateRevealed && spellInfo->Id == SPELL_ARCANE_DISRUPTION)
1425 {
1426 _crateRevealed = true;
1427 if (InstanceScript* instance = me->GetInstanceScript())
1428 {
1429 // Update world state
1430 instance->SetData(DATA_CRATE_REVEALED, 1);
1431
1432 // Replace suspicious crate with plagued crate
1434 {
1435 crate->SummonGameObject(GO_PLAGUED_CRATE, *crate, crate->GetWorldRotation(), 1_days);
1436 crate->Delete();
1437 }
1438 if (GameObject* highlight = me->FindNearestGameObject(GO_CRATE_HIGHLIGHT, 5.0f))
1439 highlight->Delete();
1440
1441 // Find nearest fluff event and initiate it
1442 Creature* closest = nullptr;
1443 float closestDist = INFINITY;
1444 ReplaceIfCloser(npc_jena_anderson::Find(me), closest, closestDist);
1445 ReplaceIfCloser(npc_bartleby_battson::Find(me), closest, closestDist);
1446 ReplaceIfCloser(npc_sergeant_morigan::Find(me), closest, closestDist);
1447 ReplaceIfCloser(npc_roger_owens::Find(me), closest, closestDist);
1448 if (closest)
1449 closest->AI()->DoAction(ACTION_START_FLUFF);
1450 else
1452 }
1453 }
1454 }
1455
1456 uint32 GetData(uint32 data) const override
1457 {
1458 if (data == DATA_CRATE_REVEALED)
1459 return _crateRevealed ? 1 : 0;
1460 return 0;
1461 }
1462
1463 private:
1465 };
1466
1467 CreatureAI* GetAI(Creature* creature) const override
1468 {
1469 return GetCullingOfStratholmeAI<npc_crate_helperAI>(creature);
1470 }
1471};
1472
1477
1478// 53435 - Teleport to CoT Stratholme Phase 4
1496
@ 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:144
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:43
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
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
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: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:235
void Update(uint32 time)
Definition EventMap.h:77
EventId ExecuteEvent()
Definition EventMap.cpp:77
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:40
Definition Map.h:227
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:1191
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:9824
bool HasAchieved(uint32 achievementId) const
Definition Player.cpp:27516
bool CanBeGameMaster() const
Definition Player.cpp:2016
bool IsGameMaster() const
Definition Player.h:1293
void PrepareQuestMenu(ObjectGuid guid)
Definition Player.cpp:14333
uint32 GetQuestId() const
Definition QuestDef.h:633
iterator end()
Definition RefManager.h:36
iterator begin()
Definition RefManager.h:35
uint32 const Id
Definition SpellInfo.h:328
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
static void GetResumeInfo(SplineChainResumeInfo &info, Unit const *owner, Optional< uint32 > id={})
virtual void DoAction(int32 param)
Definition UnitAI.h:73
Definition Unit.h:647
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10804
MotionMaster * GetMotionMaster()
Definition Unit.h:1750
bool IsQuestGiver() const
Definition Unit.h:1024
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13394
void SetEmoteState(Emote emote)
Definition Unit.h:880
bool isMoving() const
Definition Unit.h:1820
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13385
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition Unit.cpp:1662
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:1544
Map * GetMap() const
Definition Object.h:411
InstanceScript * GetInstanceScript() const
Definition Object.cpp:394
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
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:1403
float GetDistance2d(WorldObject const *obj) const
Definition Object.cpp:448
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1522
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
@ SPELL_TELEPORT_TO_COT_STRATHOLME
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