TrinityCore
instance_icecrown_citadel.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
18#include "icecrown_citadel.h"
19#include "AreaBoundary.h"
20#include "Creature.h"
21#include "CreatureAI.h"
22#include "EventMap.h"
23#include "InstanceScript.h"
24#include "Map.h"
25#include "ObjectMgr.h"
26#include "Player.h"
27#include "QuestPools.h"
28#include "ScriptMgr.h"
29#include "TemporarySummon.h"
30#include "Transport.h"
31#include "TransportMgr.h"
32#include <unordered_set>
33
35{
41 EVENT_QUAKE = 23437,
44};
45
47{
51};
52
54{
57};
58
60{
61 { DATA_LORD_MARROWGAR, new CircleBoundary(Position(-428.0f,2211.0f), 95.0) },
62 { DATA_LORD_MARROWGAR, new RectangleBoundary(-430.0f, -330.0f, 2110.0f, 2310.0f) },
63 { DATA_LADY_DEATHWHISPER, new RectangleBoundary(-670.0f, -520.0f, 2145.0f, 2280.0f) },
64 { DATA_DEATHBRINGER_SAURFANG, new RectangleBoundary(-565.0f, -465.0f, 2160.0f, 2260.0f) },
65 { DATA_ROTFACE, new RectangleBoundary(4385.0f, 4505.0f, 3082.0f, 3195.0f) },
66 { DATA_FESTERGUT, new RectangleBoundary(4205.0f, 4325.0f, 3082.0f, 3195.0f) },
67 { DATA_PROFESSOR_PUTRICIDE, new ParallelogramBoundary(Position(4356.0f, 3290.0f), Position(4435.0f, 3194.0f), Position(4280.0f, 3194.0f)) },
68 { DATA_PROFESSOR_PUTRICIDE, new RectangleBoundary(4280.0f, 4435.0f, 3150.0f, 4360.0f) },
69 { DATA_BLOOD_PRINCE_COUNCIL, new EllipseBoundary(Position(4660.95f, 2769.194f), 85.0, 60.0) },
70 { DATA_BLOOD_QUEEN_LANA_THEL, new CircleBoundary(Position(4595.93f, 2769.365f), 64.0) },
71 { DATA_BLOOD_QUEEN_LANA_THEL, new ZRangeBoundary(391.78f, 473.43f) },
72 { DATA_SISTER_SVALNA, new RectangleBoundary(4291.0f, 4423.0f, 2438.0f, 2653.0f) },
73 { DATA_VALITHRIA_DREAMWALKER, new RectangleBoundary(4112.5f, 4293.5f, 2385.0f, 2585.0f) },
74 { DATA_SINDRAGOSA, new EllipseBoundary(Position(4408.6f, 2484.0f), 100.0, 75.0) }
75};
76
78{
105};
106
108{
109 { DATA_LORD_MARROWGAR, {{ 1101 }} },
110 { DATA_LADY_DEATHWHISPER, {{ 1100 }} },
111 { DATA_ICECROWN_GUNSHIP_BATTLE, {{ 1099 }} },
112 { DATA_DEATHBRINGER_SAURFANG, {{ 1096 }} },
113 { DATA_FESTERGUT, {{ 1097 }} },
114 { DATA_ROTFACE, {{ 1104 }} },
115 { DATA_PROFESSOR_PUTRICIDE, {{ 1102 }} },
116 { DATA_BLOOD_PRINCE_COUNCIL, {{ 1095 }} },
117 { DATA_BLOOD_QUEEN_LANA_THEL, {{ 1103 }} },
118 { DATA_VALITHRIA_DREAMWALKER, {{ 1098 }} },
119 { DATA_SINDRAGOSA, {{ 1105 }} },
120 { DATA_THE_LICH_KING, {{ 1106 }} }
121};
122
123// NPCs spawned at Light's Hammer on Lich King dead
124Position const JainaSpawnPos = { -48.65278f, 2211.026f, 27.98586f, 3.124139f };
125Position const MuradinSpawnPos = { -47.34549f, 2208.087f, 27.98586f, 3.106686f };
126Position const UtherSpawnPos = { -26.58507f, 2211.524f, 30.19898f, 3.124139f };
127Position const SylvanasSpawnPos = { -41.45833f, 2222.891f, 27.98586f, 3.647738f };
128
130{
131 public:
133
135 {
137 {
144 SindragosaIntro = 1;
145 IsBonedEligible = true;
146 IsOozeDanceEligible = true;
147 IsNauseaEligible = true;
149 IsFactionBuffActive = true;
150 }
151
152 // A function to help reduce the number of lines for teleporter management.
153 void SetTeleporterState(GameObject* go, bool usable)
154 {
155 if (usable)
156 {
159 }
160 else
161 {
164 }
165 }
166
167 void OnPlayerEnter(Player* player) override
168 {
170 if (!instance->IsSpawnGroupActive(spawnGroupId))
171 instance->SpawnGroupSpawn(spawnGroupId);
172
174 SpawnGunship();
175
178 }
179
180 void OnPlayerLeave(Player* player) override
181 {
183 }
184
185 void OnCreatureCreate(Creature* creature) override
186 {
187 if (creature->IsGuardian() && creature->GetOwnerGUID().IsPlayer())
188 {
191 }
192
193 switch (creature->GetEntry())
194 {
196 {
197 uint8 group = (creature->GetPositionX() > -230.0f) ? 0 : 1;
198 nerubarBroodkeepersGUIDs[group].emplace_back(creature->GetGUID());
199 break;
200 }
202 LordMarrowgarGUID = creature->GetGUID();
203 break;
205 LadyDeahtwhisperGUID = creature->GetGUID();
206 break;
208 DeathbringerSaurfangGUID = creature->GetGUID();
209 break;
212 creature->SetControlled(true, UNIT_STATE_ROOT);
213 break;
217 break;
218 case NPC_FESTERGUT:
219 FestergutGUID = creature->GetGUID();
220 break;
221 case NPC_ROTFACE:
222 RotfaceGUID = creature->GetGUID();
223 break;
225 ProfessorPutricideGUID = creature->GetGUID();
226 break;
228 case NPC_GAS_CLOUD:
232 if (Creature* professorPutricide = instance->GetCreature(ProfessorPutricideGUID))
233 professorPutricide->AI()->JustSummoned(creature);
234 break;
236 BloodCouncilGUIDs[0] = creature->GetGUID();
237 break;
239 BloodCouncilGUIDs[1] = creature->GetGUID();
240 break;
242 BloodCouncilGUIDs[2] = creature->GetGUID();
243 break;
246 break;
249 break;
251 BloodQueenLanaThelGUID = creature->GetGUID();
252 break;
254 // keep him in air
256 creature->SetDisableGravity(true);
257 break;
259 CrokScourgebaneGUID = creature->GetGUID();
260 break;
261 // we can only do this because there are no gaps in their entries
266 CrokCaptainGUIDs[creature->GetEntry()-NPC_CAPTAIN_ARNATH] = creature->GetGUID();
267 break;
269 SisterSvalnaGUID = creature->GetGUID();
270 break;
272 ValithriaDreamwalkerGUID = creature->GetGUID();
273 break;
275 ValithriaLichKingGUID = creature->GetGUID();
276 break;
278 ValithriaTriggerGUID = creature->GetGUID();
279 break;
280 case NPC_SINDRAGOSA:
281 SindragosaGUID = creature->GetGUID();
282 break;
283 case NPC_SPINESTALKER:
284 SpinestalkerGUID = creature->GetGUID();
285 break;
286 case NPC_RIMEFANG:
287 RimefangGUID = creature->GetGUID();
288 break;
290 // Teleporter visual at center
291 if (creature->GetExactDist2d(4357.052f, 2769.421f) < 10.0f)
292 creature->CastSpell(creature, SPELL_ARTHAS_TELEPORTER_CEREMONY, false);
293 break;
295 TheLichKingGUID = creature->GetGUID();
296 break;
299 break;
302 TerenasMenethilGUID = creature->GetGUID();
303 break;
305 // Remove corpse as soon as it dies (and respawn 10 seconds later)
306 creature->SetCorpseDelay(0);
307 creature->SetReactState(REACT_PASSIVE);
308 break;
309 default:
310 break;
311 }
312 }
313
314 void OnCreatureRemove(Creature* creature) override
315 {
316 if (creature->GetEntry() == NPC_SINDRAGOSA)
318 }
319
320 // Weekly quest spawn prevention
321 uint32 GetCreatureEntry(ObjectGuid::LowType /*guidLow*/, CreatureData const* data) override
322 {
323 uint32 entry = data->id;
324 switch (entry)
325 {
333 return 0;
338 return 0;
339 break;
344 return 0;
345 break;
347 if (GameObjectTemplate const* go = sObjectMgr->GetGameObjectTemplate(GO_THE_SKYBREAKER_A))
348 if ((GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE && int32(data->mapId) == go->moTransport.SpawnMap) ||
349 (GetData(DATA_TEAM_IN_INSTANCE) == HORDE && int32(data->mapId) != go->moTransport.SpawnMap))
350 return entry;
351 return 0;
353 if ((GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE && data->spawnPoint.GetPositionX() > 10.0f) ||
355 return entry;
356 return 0;
361 case NPC_TORTUNOK:
369 case NPC_VOL_GUK:
377 default:
378 break;
379 }
380
381 return entry;
382 }
383
385 {
386 switch (entry)
387 {
393 return 0;
394 break;
400 return 0;
401 break;
402 default:
403 break;
404 }
405
406 return entry;
407 }
408
409 void OnUnitDeath(Unit* unit) override
410 {
411 Creature* creature = unit->ToCreature();
412 if (!creature)
413 return;
414
415 switch (creature->GetEntry())
416 {
423 crok->AI()->SetGUID(creature->GetGUID(), ACTION_VRYKUL_DEATH);
424 break;
426 if (FrostwyrmGUIDs.empty())
427 return;
428
429 if (creature->AI()->GetData(1/*DATA_FROSTWYRM_OWNER*/) == DATA_SPINESTALKER)
430 {
431 SpinestalkerTrash.erase(creature->GetSpawnId());
432 if (SpinestalkerTrash.empty())
433 if (Creature* spinestalk = instance->GetCreature(SpinestalkerGUID))
434 spinestalk->AI()->DoAction(ACTION_START_FROSTWYRM);
435 }
436 else
437 {
438 RimefangTrash.erase(creature->GetSpawnId());
439 if (RimefangTrash.empty())
440 if (Creature* spinestalk = instance->GetCreature(RimefangGUID))
441 spinestalk->AI()->DoAction(ACTION_START_FROSTWYRM);
442 }
443 break;
444 case NPC_RIMEFANG:
445 case NPC_SPINESTALKER:
446 {
448 return;
449
450 FrostwyrmGUIDs.erase(creature->GetSpawnId());
451 if (FrostwyrmGUIDs.empty())
452 {
455 boss->AI()->DoAction(ACTION_START_FROSTWYRM);
456 }
457 break;
458 }
459 default:
460 break;
461 }
462 }
463
465 {
466 switch (go->GetEntry())
467 {
469 case GO_ICEWALL:
487 case GO_ICE_WALL:
488 AddDoor(go, true);
489 break;
490 // these 2 gates are functional only on 25man modes
493 if (instance->Is25ManRaid())
494 AddDoor(go, true);
495 break;
499 {
502 }
503 break;
507 break;
517 break;
520 AddDoor(go, true);
521 break;
527 break;
532 break;
536 SetTeleporterState(go, false);
537 else
538 SetTeleporterState(go, true);
539 break;
543 break;
547 break;
551 break;
555 break;
559 break;
560 case GO_PLAGUE_SIGIL:
561 PlagueSigilGUID = go->GetGUID();
564 break;
569 break;
574 break;
579 break;
581 PutricideGateGUIDs[0] = go->GetGUID();
584 else if (GetBossState(DATA_FESTERGUT) == DONE)
586 break;
588 PutricideGateGUIDs[1] = go->GetGUID();
591 else if (GetBossState(DATA_ROTFACE) == DONE)
593 break;
595 PutricidePipeGUIDs[0] = go->GetGUID();
598 break;
600 PutricidePipeGUIDs[1] = go->GetGUID();
603 break;
604 case GO_DRINK_ME:
606 break;
612 go->SetTapList(valithria->GetTapList());
614 break;
617 break;
620 break;
623 break;
626 break;
629 break;
633 go->SetRespawnTime(7 * DAY);
634 break;
638 go->SetRespawnTime(7 * DAY);
639 break;
643 go->SetRespawnTime(7 * DAY);
644 break;
645 default:
646 break;
647 }
648 }
649
651 {
652 switch (go->GetEntry())
653 {
655 case GO_ICEWALL:
676 case GO_ICE_WALL:
677 AddDoor(go, false);
678 break;
682 break;
683 default:
684 break;
685 }
686 }
687
688 uint32 GetData(uint32 type) const override
689 {
690 switch (type)
691 {
693 return FrostwyrmGUIDs.size();
695 return SpinestalkerTrash.size();
696 case DATA_RIMEFANG:
697 return RimefangTrash.size();
699 return ColdflameJetsState;
703 return instance->GetTeamInInstance();
705 return BloodPrinceIntro;
707 return SindragosaIntro;
709 return IsFactionBuffActive ? 1 : 0;
710 default:
711 break;
712 }
713
714 return 0;
715 }
716
717 ObjectGuid GetGuidData(uint32 type) const override
718 {
719 switch (type)
720 {
722 return LordMarrowgarGUID;
726 return GunshipGUID;
728 return EnemyGunshipGUID;
735 case DATA_FESTERGUT:
736 return FestergutGUID;
737 case DATA_ROTFACE:
738 return RotfaceGUID;
742 return PutricideTableGUID;
744 return BloodCouncilGUIDs[0];
746 return BloodCouncilGUIDs[1];
748 return BloodCouncilGUIDs[2];
756 return CrokScourgebaneGUID;
763 return SisterSvalnaGUID;
770 case DATA_SINDRAGOSA:
771 return SindragosaGUID;
773 return SpinestalkerGUID;
774 case DATA_RIMEFANG:
775 return RimefangGUID;
777 return TheLichKingGUID;
781 return ArthasPlatformGUID;
783 return TerenasMenethilGUID;
784 default:
785 break;
786 }
787
788 return ObjectGuid::Empty;
789 }
790
791 bool SetBossState(uint32 type, EncounterState state) override
792 {
793 if (!InstanceScript::SetBossState(type, state))
794 return false;
795
796 switch (type)
797 {
799 {
800 if (state == DONE)
801 {
803 SetTeleporterState(teleporter, true);
805 SetTeleporterState(teleporter, true);
806 }
807 break;
808 }
810 {
811 if (state == DONE)
812 {
814 SetTeleporterState(teleporter, true);
815
817 {
818 elevator->SetGoState(GO_STATE_TRANSPORT_ACTIVE);
819 elevator->HandleCustomTypeCommand(GameObjectType::SetTransportAutoCycleBetweenStopFrames(true));
820 }
821
822 SpawnGunship();
823 }
824 break;
825 }
827 if (state == DONE)
828 {
830 SetTeleporterState(teleporter, true);
831
834 }
835 else if (state == FAIL)
836 Events.ScheduleEvent(EVENT_RESPAWN_GUNSHIP, 30s);
837 break;
839 switch (state)
840 {
841 case DONE:
842 {
844 {
846 loot->SetTapList(deathbringer->GetTapList());
848 }
849
851 SetTeleporterState(teleporter, true);
852
854 SetTeleporterState(teleporter, true);
855 break;
856 }
857 case NOT_STARTED:
858 {
860 SetTeleporterState(teleporter, true);
861 break;
862 }
863 case IN_PROGRESS:
864 {
866 SetTeleporterState(teleporter, false);
867 break;
868 }
869 default:
870 break;
871 }
872 break;
873 case DATA_FESTERGUT:
874 if (state == DONE)
875 {
877 {
880 go->SetGoState(GO_STATE_DESTROYED);
882 go->SetGoState(GO_STATE_DESTROYED);
883 }
884 else
887 }
888 break;
889 case DATA_ROTFACE:
890 if (state == DONE)
891 {
893 {
896 go->SetGoState(GO_STATE_DESTROYED);
898 go->SetGoState(GO_STATE_DESTROYED);
899 }
900 else
903 }
904 break;
907 if (state == DONE)
909 break;
912 if (state == DONE)
914 break;
916 if (state == DONE)
918 SetTeleporterState(teleporter, true);
919 break;
920 case DATA_SINDRAGOSA:
922 if (state == DONE)
924 break;
926 {
927 // set the platform as active object to dramatically increase visibility range
928 // note: "active" gameobjects do not block grid unloading
930 precipice->SetFarVisible(state == IN_PROGRESS);
931
933 platform->SetFarVisible(state == IN_PROGRESS);
934
935 if (state == DONE)
936 {
938 bolvar->SetRespawnTime(7 * DAY);
940 pillars->SetRespawnTime(7 * DAY);
942 pillars->SetRespawnTime(7 * DAY);
943
948 }
949 break;
950 }
951 default:
952 break;
953 }
954
955 return true;
956 }
957
959 {
960 if (!GunshipGUID)
961 {
964 if (Transport* gunship = sTransportMgr->CreateTransport(gunshipEntry, instance))
965 GunshipGUID = gunship->GetGUID();
966 }
967 }
968
969 void SetData(uint32 type, uint32 data) override
970 {
971 switch (type)
972 {
974 IsBonedEligible = data ? true : false;
975 break;
977 IsOozeDanceEligible = data ? true : false;
978 break;
980 IsNauseaEligible = data ? true : false;
981 break;
983 IsOrbWhispererEligible = data ? true : false;
984 break;
986 ColdflameJetsState = data;
987 break;
992 SetTeleporterState(go, true);
993 break;
995 BloodPrinceIntro = data;
996 break;
998 SindragosaIntro = data;
999 break;
1000 case DATA_FACTION_BUFF:
1001 IsFactionBuffActive = data ? true : false;
1004 break;
1006 {
1007 uint8 group = (data == AT_NERUBAR_BROODKEEPER) ? 0 : 1;
1008 for (ObjectGuid guid : nerubarBroodkeepersGUIDs[group])
1009 if (Creature* nerubar = instance->GetCreature(guid))
1010 nerubar->AI()->DoAction(ACTION_NERUBAR_FALL);
1011 break;
1012 }
1013 default:
1014 break;
1015 }
1016 }
1017
1018 void SetGuidData(uint32 type, ObjectGuid guid) override
1019 {
1020 switch (type)
1021 {
1023 FrostwyrmGUIDs.insert(guid.GetCounter());
1024 break;
1025 case DATA_SPINESTALKER:
1026 SpinestalkerTrash.insert(guid.GetCounter());
1027 break;
1028 case DATA_RIMEFANG:
1029 RimefangTrash.insert(guid.GetCounter());
1030 break;
1031 }
1032 }
1033
1034 bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* /*source*/, Unit const* /*target*/, uint32 /*miscvalue1*/) override
1035 {
1036 switch (criteria_id)
1037 {
1038 case CRITERIA_BONED_10N:
1039 case CRITERIA_BONED_25N:
1040 case CRITERIA_BONED_10H:
1041 case CRITERIA_BONED_25H:
1042 return IsBonedEligible;
1047 return IsOozeDanceEligible;
1052 return IsNauseaEligible;
1058 // Only one criteria for both modes, need to do it like this
1062 return instance->ToInstanceMap()->GetMaxPlayers() == 10;
1066 return instance->ToInstanceMap()->GetMaxPlayers() == 25;
1067 default:
1068 break;
1069 }
1070
1071 return false;
1072 }
1073
1074 bool CheckRequiredBosses(uint32 bossId, Player const* player = nullptr) const override
1075 {
1076 if (_SkipCheckRequiredBosses(player))
1077 return true;
1078
1079 switch (bossId)
1080 {
1081 case DATA_THE_LICH_KING:
1082 if (!CheckPlagueworks(bossId))
1083 return false;
1084 if (!CheckCrimsonHalls(bossId))
1085 return false;
1086 if (!CheckFrostwingHalls(bossId))
1087 return false;
1088 break;
1089 case DATA_SINDRAGOSA:
1091 if (!CheckFrostwingHalls(bossId))
1092 return false;
1093 break;
1096 if (!CheckCrimsonHalls(bossId))
1097 return false;
1098 break;
1099 case DATA_FESTERGUT:
1100 case DATA_ROTFACE:
1102 if (!CheckPlagueworks(bossId))
1103 return false;
1104 break;
1105 default:
1106 break;
1107 }
1108
1109 if (!CheckLowerSpire(bossId))
1110 return false;
1111
1112 return true;
1113 }
1114
1115 bool CheckPlagueworks(uint32 bossId) const
1116 {
1117 switch (bossId)
1118 {
1119 case DATA_THE_LICH_KING:
1121 return false;
1122 [[fallthrough]];
1125 return false;
1126 break;
1127 default:
1128 break;
1129 }
1130
1131 return true;
1132 }
1133
1134 bool CheckCrimsonHalls(uint32 bossId) const
1135 {
1136 switch (bossId)
1137 {
1138 case DATA_THE_LICH_KING:
1140 return false;
1141 [[fallthrough]];
1144 return false;
1145 break;
1146 default:
1147 break;
1148 }
1149
1150 return true;
1151 }
1152
1153 bool CheckFrostwingHalls(uint32 bossId) const
1154 {
1155 switch (bossId)
1156 {
1157 case DATA_THE_LICH_KING:
1159 return false;
1160 [[fallthrough]];
1161 case DATA_SINDRAGOSA:
1163 return false;
1164 break;
1165 default:
1166 break;
1167 }
1168
1169 return true;
1170 }
1171
1172 bool CheckLowerSpire(uint32 bossId) const
1173 {
1174 switch (bossId)
1175 {
1176 case DATA_THE_LICH_KING:
1177 case DATA_SINDRAGOSA:
1182 case DATA_ROTFACE:
1183 case DATA_FESTERGUT:
1185 return false;
1186 [[fallthrough]];
1189 return false;
1190 [[fallthrough]];
1193 return false;
1194 [[fallthrough]];
1197 return false;
1198 [[fallthrough]];
1200 default:
1201 break;
1202 }
1203
1204 return true;
1205 }
1206
1208 {
1210 {
1212 {
1213 teleporter->SetGoState(GO_STATE_ACTIVE);
1214
1215 std::list<Creature*> stalkers;
1216 teleporter->GetCreatureListWithEntryInGrid(stalkers, NPC_INVISIBLE_STALKER, 100.0f);
1217 if (stalkers.empty())
1218 return;
1219
1220 stalkers.sort(Trinity::ObjectDistanceOrderPred(teleporter));
1221 stalkers.front()->CastSpell(nullptr, SPELL_ARTHAS_TELEPORTER_CEREMONY, false);
1222 stalkers.pop_front();
1223 for (std::list<Creature*>::iterator itr = stalkers.begin(); itr != stalkers.end(); ++itr)
1224 (*itr)->AI()->Reset();
1225 }
1226 }
1227 }
1228
1229 void AfterDataLoad() override
1230 {
1232 {
1235 }
1236 }
1237
1238 void Update(uint32 diff) override
1239 {
1241 return;
1242
1243 Events.Update(diff);
1244
1245 while (uint32 eventId = Events.ExecuteEvent())
1246 {
1247 switch (eventId)
1248 {
1250 {
1252 platform->SetDestructibleState(GO_DESTRUCTIBLE_DAMAGED);
1254 edge->SetGoState(GO_STATE_ACTIVE);
1256 wind->SetGoState(GO_STATE_READY);
1258 warning->SetGoState(GO_STATE_READY);
1259 if (Creature* theLichKing = instance->GetCreature(TheLichKingGUID))
1260 theLichKing->AI()->DoAction(ACTION_RESTORE_LIGHT);
1261 break;
1262 }
1265 platform->SetDestructibleState(GO_DESTRUCTIBLE_REBUILDING);
1267 edge->SetGoState(GO_STATE_READY);
1269 wind->SetGoState(GO_STATE_ACTIVE);
1270 break;
1272 SpawnGunship();
1273 break;
1274 default:
1275 break;
1276 }
1277 }
1278 }
1279
1280 void ProcessEvent(WorldObject* source, uint32 eventId, WorldObject* /*invoker*/) override
1281 {
1282 switch (eventId)
1283 {
1286 source->AddObjectToRemoveList();
1287 break;
1290 captain->AI()->DoAction(ACTION_ENEMY_GUNSHIP_TALK);
1291 [[fallthrough]];
1294 if (GameObject* go = source->ToGameObject())
1295 if (Transport* transport = go->ToTransport())
1296 transport->EnableMovement(false);
1297 break;
1300 captain->AI()->DoAction(ACTION_EXIT_SHIP);
1301 if (GameObject* go = source->ToGameObject())
1302 if (Transport* transport = go->ToTransport())
1303 transport->EnableMovement(false);
1304 break;
1305 case EVENT_QUAKE:
1307 warning->SetGoState(GO_STATE_ACTIVE);
1308 Events.ScheduleEvent(EVENT_QUAKE_SHATTER, 5s);
1309 break;
1312 {
1313 platform->SetDestructibleState(GO_DESTRUCTIBLE_DESTROYED);
1314 Events.ScheduleEvent(EVENT_REBUILD_PLATFORM, 1500ms);
1315 }
1316 break;
1317 case EVENT_TELEPORT_TO_FROSTMOURNE: // Harvest Soul (normal mode)
1319 {
1320 terenas->AI()->DoAction(ACTION_FROSTMOURNE_INTRO);
1321 std::list<Creature*> triggers;
1322 terenas->GetCreatureListWithEntryInGrid(triggers, NPC_WORLD_TRIGGER_INFINITE_AOI, 100.0f);
1323 if (!triggers.empty())
1324 {
1325 triggers.sort(Trinity::ObjectDistanceOrderPred(terenas, false));
1326 Unit* visual = triggers.front();
1327 visual->CastSpell(visual, SPELL_FROSTMOURNE_TELEPORT_VISUAL, true);
1328 }
1329
1331 {
1332 terenas->AI()->AttackStart(warden);
1333 warden->GetThreatManager().AddThreat(terenas, 300000.0f, nullptr, true, true);
1334 }
1335 }
1336 break;
1337 default:
1338 break;
1339 }
1340 }
1341
1342 protected:
1352 ObjectGuid DeathbringerSaurfangEventGUID; // Muradin Bronzebeard or High Overlord Saurfang
1398 std::unordered_set<ObjectGuid::LowType> FrostwyrmGUIDs;
1399 std::unordered_set<ObjectGuid::LowType> SpinestalkerTrash;
1400 std::unordered_set<ObjectGuid::LowType> RimefangTrash;
1408 std::array<GuidVector, 2> nerubarBroodkeepersGUIDs;
1409 };
1410
1412 {
1414 }
1415};
1416
1418{
1420}
@ NPC_ALLIANCE_GUNSHIP_CANNON
@ NPC_HORDE_GUNSHIP_CANNON
@ DAY
Definition: Common.h:31
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
EncounterState
@ IN_PROGRESS
@ FAIL
@ DONE
@ NOT_STARTED
#define sObjectMgr
Definition: ObjectMgr.h:1946
@ EMOTE_ONESHOT_NONE
@ GO_DESTRUCTIBLE_DESTROYED
@ GO_DESTRUCTIBLE_REBUILDING
@ GO_DESTRUCTIBLE_DAMAGED
@ ALLIANCE
@ HORDE
@ GO_FLAG_NODESPAWN
@ GO_FLAG_NOT_SELECTABLE
@ GO_FLAG_LOCKED
@ GO_STATE_TRANSPORT_ACTIVE
@ GO_STATE_READY
@ GO_STATE_DESTROYED
@ GO_STATE_ACTIVE
#define sTransportMgr
Definition: TransportMgr.h:183
@ REACT_PASSIVE
Definition: UnitDefines.h:506
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ DATA_PRINCE_TALDARAM
Definition: ahnkahet.h:32
@ NPC_PRINCE_TALDARAM
Definition: ahnkahet.h:46
#define DataHeader
uint32 const EncounterCount
Position const SindragosaSpawnPos
Position const TerenasSpawn
Position const SpiritWardenSpawn
@ NPC_THE_LICH_KING
Definition: chapter5.cpp:162
void SetReactState(ReactStates st)
Definition: Creature.h:160
ObjectGuid::LowType GetSpawnId() const
Definition: Creature.h:98
void SetCorpseDelay(uint32 delay, bool ignoreCorpseDecayRatio=false)
Definition: Creature.h:104
CreatureAI * AI() const
Definition: Creature.h:214
void SetGoState(GOState state)
void RemoveFlag(GameObjectFlags flags)
Definition: GameObject.h:275
void HandleCustomTypeCommand(GameObjectTypeBase::CustomCommand const &command) const
void SetFlag(GameObjectFlags flags)
Definition: GameObject.h:274
void SetRespawnTime(int32 respawn)
Transport * ToTransport()
Definition: GameObject.h:397
void SetTapList(GuidUnorderedSet tapList)
Definition: GameObject.h:331
uint32 GetMaxPlayers() const
Definition: Map.cpp:3367
Team GetTeamInInstance() const
Definition: Map.h:883
void SetBossNumber(uint32 number)
virtual bool SetBossState(uint32 id, EncounterState state)
void DoRemoveAurasDueToSpellOnPlayers(uint32 spell, bool includePets=false, bool includeControlled=false)
void HandleGameObject(ObjectGuid guid, bool open, GameObject *go=nullptr)
void LoadDungeonEncounterData(T const &encounters)
void DoCastSpellOnPlayer(Player *player, uint32 spell, bool includePets=false, bool includeControlled=false)
InstanceMap * instance
EncounterState GetBossState(uint32 id) const
virtual void AddDoor(GameObject *door, bool add)
void LoadDoorData(DoorData const *data)
void DoRemoveAurasDueToSpellOnPlayer(Player *player, uint32 spell, bool includePets=false, bool includeControlled=false)
void LoadBossBoundaries(BossBoundaryData const &data)
bool _SkipCheckRequiredBosses(Player const *player=nullptr) const
void SetHeaders(std::string const &dataHeaders)
bool SpawnGroupSpawn(uint32 groupId, bool ignoreRespawn=false, bool force=false, std::vector< WorldObject * > *spawnedObjects=nullptr)
Definition: Map.cpp:2348
void LoadGrid(float x, float y)
Definition: Map.cpp:405
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:1836
bool Is25ManRaid() const
Definition: Map.cpp:3320
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3489
bool IsSpawnGroupActive(uint32 groupId) const
Definition: Map.cpp:2474
InstanceMap * ToInstanceMap()
Definition: Map.h:454
Creature * GetCreature(ObjectGuid const &guid)
Definition: Map.cpp:3479
LowType GetCounter() const
Definition: ObjectGuid.h:293
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsPlayer() const
Definition: ObjectGuid.h:326
uint64 LowType
Definition: ObjectGuid.h:278
void Clear()
Definition: ObjectGuid.h:286
static Creature * ToCreature(Object *o)
Definition: Object.h:219
static GameObject * ToGameObject(Object *o)
Definition: Object.h:231
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
virtual uint32 GetData(uint32) const
Definition: UnitAI.h:73
Definition: Unit.h:627
void SetControlled(bool apply, UnitState state)
Definition: Unit.cpp:10911
ObjectGuid GetOwnerGUID() const override
Definition: Unit.h:1170
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition: Unit.cpp:12725
void SetEmoteState(Emote emote)
Definition: Unit.h:852
bool IsGuardian() const
Definition: Unit.h:739
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
void AddObjectToRemoveList()
Definition: Object.cpp:1824
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition: Object.cpp:2148
InstanceScript * GetInstanceScript(InstanceMap *map) const override
@ DATA_TEAM_IN_INSTANCE
@ GO_ICE_WALL
@ SPELL_STRENGHT_OF_WRYNN
@ SPELL_ARTHAS_TELEPORTER_CEREMONY
@ SPELL_FROSTMOURNE_TELEPORT_VISUAL
@ SPELL_HELLSCREAMS_WARSONG
@ AT_NERUBAR_BROODKEEPER
@ GO_THE_SKYBREAKER_A
@ GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR
@ GO_SCIENTIST_AIRLOCK_DOOR_GREEN
@ GO_SCOURGE_TRANSPORTER_LICHKING
@ GO_THE_SKYBREAKER_H
@ GO_GREEN_PLAGUE_MONSTER_ENTRANCE
@ GO_SAURFANG_S_DOOR
@ GO_SCIENTIST_AIRLOCK_DOOR_COLLISION
@ GO_ORGRIMS_HAMMER_A
@ GO_DOODAD_ICECROWN_GREENTUBES02
@ GO_DEATHBRINGER_S_CACHE_10N
@ GO_CACHE_OF_THE_DREAMWALKER_25H
@ GO_FROZEN_LAVAMAN
@ GO_SCOURGE_TRANSPORTER_LIGHTSHAMMER
@ GO_GUNSHIP_ARMORY_H_10N
@ GO_BLOODWING_SIGIL
@ GO_SCOURGE_TRANSPORTER_RAMPART
@ GO_DEATHBRINGER_S_CACHE_25N
@ GO_LADY_DEATHWHISPER_ELEVATOR
@ GO_CACHE_OF_THE_DREAMWALKER_25N
@ GO_BLOOD_ELF_COUNCIL_DOOR_RIGHT
@ GO_GUNSHIP_ARMORY_A_10H
@ GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR
@ GO_DOODAD_ICECROWN_SNOWEDGEWARNING01
@ GO_GUNSHIP_ARMORY_A_25N
@ GO_SCOURGE_TRANSPORTER_UPPERSPIRE
@ GO_DOODAD_ICECROWN_ICEWALL02
@ GO_GUNSHIP_ARMORY_A_10N
@ GO_GUNSHIP_ARMORY_H_25H
@ GO_ICEWALL
@ GO_LAVAMAN_PILLARS_UNCHAINED
@ GO_GUNSHIP_ARMORY_H_25N
@ GO_ORATORY_OF_THE_DAMNED_ENTRANCE
@ GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04
@ GO_GUNSHIP_ARMORY_A_25H
@ GO_SCIENTIST_AIRLOCK_DOOR_ORANGE
@ GO_ARTHAS_PLATFORM
@ GO_CACHE_OF_THE_DREAMWALKER_10N
@ GO_GREEN_DRAGON_BOSS_EXIT
@ GO_ORGRIMS_HAMMER_H
@ GO_ORANGE_PLAGUE_MONSTER_ENTRANCE
@ GO_SCOURGE_TRANSPORTER_ORATORY
@ GO_PLAGUE_SIGIL
@ GO_DOODAD_ICECROWN_BLOODPRINCE_DOOR_01
@ GO_DEATHBRINGER_S_CACHE_10H
@ GO_DOODAD_ICECROWN_THRONEFROSTYWIND01
@ GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02
@ GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03
@ GO_SIGIL_OF_THE_FROSTWING
@ GO_SCOURGE_TRANSPORTER_SINDRAGOSA
@ GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01
@ GO_BLOOD_ELF_COUNCIL_DOOR
@ GO_DOODAD_ICECROWN_ORANGETUBES02
@ GO_DEATHBRINGER_S_CACHE_25H
@ GO_DOODAD_ICECROWN_GRATE_01
@ GO_LORD_MARROWGAR_S_ENTRANCE
@ GO_SCIENTIST_ENTRANCE
@ GO_LAVAMAN_PILLARS_CHAINED
@ GO_DRINK_ME
@ GO_SCOURGE_TRANSPORTER_DEATHBRINGER
@ GO_CRIMSON_HALL_DOOR
@ GO_DOODAD_ICECROWN_THRONEFROSTYEDGE01
@ GO_GUNSHIP_ARMORY_H_10H
@ GO_CACHE_OF_THE_DREAMWALKER_10H
@ GO_GREEN_DRAGON_BOSS_ENTRANCE
@ GO_SINDRAGOSA_ENTRANCE_DOOR
@ GO_ARTHAS_PRECIPICE
#define ICCScriptName
@ CRITERIA_BONED_25H
@ CRITERIA_BONED_10N
@ CRITERIA_NAUSEA_10H
@ CRITERIA_BONED_25N
@ CRITERIA_BONED_10H
@ CRITERIA_ONCE_BITTEN_TWICE_SHY_25V
@ CRITERIA_DANCES_WITH_OOZES_10H
@ CRITERIA_NAUSEA_10N
@ CRITERIA_NAUSEA_25N
@ CRITERIA_ONCE_BITTEN_TWICE_SHY_10V
@ CRITERIA_NAUSEA_25H
@ CRITERIA_ORB_WHISPERER_25H
@ CRITERIA_DANCES_WITH_OOZES_10N
@ CRITERIA_DANCES_WITH_OOZES_25H
@ CRITERIA_KILL_LANA_THEL_25M
@ CRITERIA_ONCE_BITTEN_TWICE_SHY_10N
@ CRITERIA_DANCES_WITH_OOZES_25N
@ CRITERIA_ORB_WHISPERER_25N
@ CRITERIA_KILL_LANA_THEL_10M
@ CRITERIA_ORB_WHISPERER_10N
@ CRITERIA_ORB_WHISPERER_10H
@ CRITERIA_ONCE_BITTEN_TWICE_SHY_25N
@ ACTION_FROSTMOURNE_INTRO
@ ACTION_ENEMY_GUNSHIP_TALK
@ ACTION_EXIT_SHIP
@ ACTION_VRYKUL_DEATH
@ ACTION_NERUBAR_FALL
@ ACTION_START_FROSTWYRM
@ ACTION_RESTORE_LIGHT
@ DATA_ORB_WHISPERER_ACHIEVEMENT
@ DATA_THE_LICH_KING
@ DATA_SINDRAGOSA_FROSTWYRMS
@ DATA_BLOOD_PRINCE_COUNCIL_INTRO
@ DATA_BLOOD_PRINCE_COUNCIL
@ DATA_PRINCE_VALANAR
@ DATA_DEATHBRINGER_SAURFANG
@ DATA_BLOOD_QUEEN_LANA_THEL_COUNCIL
also used by conditions
@ DATA_VALITHRIA_LICH_KING
@ DATA_OOZE_DANCE_ACHIEVEMENT
@ DATA_NAUSEA_ACHIEVEMENT
@ DATA_BLOOD_PRINCES_CONTROL
@ DATA_VALITHRIA_TRIGGER
@ DATA_TERENAS_MENETHIL
@ DATA_ICECROWN_GUNSHIP_BATTLE
@ DATA_SISTER_SVALNA
@ DATA_ROTFACE
@ DATA_CROK_SCOURGEBANE
@ DATA_SAURFANG_EVENT_NPC
@ DATA_VALITHRIA_DREAMWALKER
@ DATA_HIGHLORD_TIRION_FORDRING
@ DATA_FACTION_BUFF
@ DATA_SINDRAGOSA
@ DATA_LORD_MARROWGAR
@ DATA_UPPERSPIRE_TELE_ACT
@ DATA_SINDRAGOSA_INTRO
@ DATA_COLDFLAME_JETS
@ DATA_BLOOD_QUEEN_LANA_THEL
@ DATA_PROFESSOR_PUTRICIDE
@ DATA_PRINCE_KELESETH
@ DATA_ENEMY_GUNSHIP
@ DATA_CAPTAIN_RUPERT
@ DATA_PUTRICIDE_TABLE
@ DATA_CAPTAIN_ARNATH
@ DATA_NERUBAR_BROODKEEPER_EVENT
@ DATA_FESTERGUT
@ DATA_SPINESTALKER
@ DATA_LADY_DEATHWHISPER
@ DATA_BONED_ACHIEVEMENT
@ DATA_CAPTAIN_GRONDEL
@ DATA_CAPTAIN_BRANDON
@ DATA_ARTHAS_PLATFORM
@ NPC_THE_LICH_KING_VALITHRIA
@ NPC_HIGH_CAPTAIN_JUSTIN_BARTLETT
@ NPC_UVLUS_BANEFIRE
@ NPC_GREEN_DRAGON_COMBAT_TRIGGER
@ NPC_CAPTAIN_BRANDON
@ NPC_INFILTRATOR_MINCHAR_BQ
@ NPC_TERENAS_MENETHIL_FROSTMOURNE
@ NPC_SKY_REAVER_KORM_BLACKSCAR
@ NPC_IGB_MURADIN_BRONZEBEARD
@ NPC_PRINCE_VALANAR
@ NPC_YILI
@ NPC_VALITHRIA_DREAMWALKER
@ NPC_ALRIN_THE_AGILE
@ NPC_YMIRJAR_BATTLE_MAIDEN
@ NPC_ALLIANCE_COMMANDER
@ NPC_BLOOD_QUEEN_LANA_THEL_COUNCIL
@ NPC_TALAN_MOONSTRIKE
@ NPC_ALANA_MOONSTRIKE
@ NPC_UTHER_THE_LIGHTBRINGER_QUEST
@ NPC_ALCHEMIST_ADRIANNA
@ NPC_IKFIRUS_THE_VILE
@ NPC_DEATHBRINGER_SAURFANG
@ NPC_KING_VARIAN_WRYNN
@ NPC_KOR_KRON_GENERAL
@ NPC_SPIRIT_WARDEN
@ NPC_SINDRAGOSA
@ NPC_BLOOD_ORB_CONTROLLER
@ NPC_YMIRJAR_WARLORD
@ NPC_LADY_JAINA_PROUDMOORE_QUEST
@ NPC_MURADIN_BRONZEBEARD_QUEST
@ NPC_KOR_KRON_LIEUTENANT
@ NPC_SE_SKYBREAKER_MARINE
@ NPC_CAPTAIN_RUPERT
@ NPC_FESTERGUT
@ NPC_HARAGG_THE_UNSEEN
@ NPC_INFILTRATOR_MINCHAR
@ NPC_WICKED_SPIRIT
@ NPC_BLOOD_QUEEN_LANA_THEL
@ NPC_VOLATILE_OOZE
@ NPC_HIGHLORD_TIRION_FORDRING_LK
@ NPC_YMIRJAR_HUNTRESS
@ NPC_MALFUS_GRIMFROST
@ NPC_JEDEBIA
@ NPC_ROTFACE
@ NPC_SE_HIGH_OVERLORD_SAURFANG
@ NPC_MINCHAR_BEAM_STALKER
@ NPC_LADY_SYLVANAS_WINDRUNNER_QUEST
@ NPC_PROFESSOR_PUTRICIDE
@ NPC_NIBY_THE_ALMIGHTY
@ NPC_ZAFOD_BOOMBOX
@ NPC_VOL_GUK
@ NPC_CROK_SCOURGEBANE
@ NPC_IGB_HIGH_OVERLORD_SAURFANG
@ NPC_SE_KOR_KRON_REAVER
@ NPC_TORTUNOK
@ NPC_GAS_CLOUD
@ NPC_LADY_DEATHWHISPER
@ NPC_WORLD_TRIGGER_INFINITE_AOI
@ NPC_FROSTWING_WHELP
@ NPC_SISTER_SVALNA
@ NPC_SPINESTALKER
@ NPC_SKYBREAKER_DECKHAND
@ NPC_ORGRIMS_HAMMER_CREW
@ NPC_LORD_MARROWGAR
@ NPC_YMIRJAR_FROSTBINDER
@ NPC_GERARDO_THE_SUAVE
@ NPC_PRINCE_KELESETH
@ NPC_CAPTAIN_GRONDEL
@ NPC_SE_MURADIN_BRONZEBEARD
@ NPC_VALITHRIA_DREAMWALKER_QUEST
@ NPC_TERENAS_MENETHIL_FROSTMOURNE_H
@ NPC_CAPTAIN_ARNATH
@ NPC_INVISIBLE_STALKER
@ NPC_NERUBAR_BROODKEEPER
Position const UtherSpawnPos
@ SPAWN_GROUP_ALLIANCE_ROS
void AddSC_instance_icecrown_citadel()
DoorData const doorData[]
Position const SylvanasSpawnPos
@ EVENT_REBUILD_PLATFORM
BossBoundaryData const boundaries
@ EVENT_PLAYERS_GUNSHIP_SPAWN
@ EVENT_SECOND_REMORSELESS_WINTER
@ EVENT_ENEMY_GUNSHIP_DESPAWN
@ EVENT_PLAYERS_GUNSHIP_COMBAT
@ EVENT_TELEPORT_TO_FROSTMOURNE
@ EVENT_ENEMY_GUNSHIP_COMBAT
@ EVENT_PLAYERS_GUNSHIP_SAURFANG
Position const MuradinSpawnPos
DungeonEncounterData const encounters[]
Position const JainaSpawnPos
@ DATA_RIMEFANG
Definition: pit_of_saron.h:37
@ NPC_RIMEFANG
Definition: pit_of_saron.h:53
@ NPC_YMIRJAR_DEATHBRINGER
Definition: pit_of_saron.h:93
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
float GetExactDist2d(const float x, const float y) const
Definition: Position.h:106
uint32 id
Definition: SpawnData.h:104
Position spawnPoint
Definition: SpawnData.h:105
uint32 mapId
Definition: SpawnData.h:94
bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const *, Unit const *, uint32) override
void ProcessEvent(WorldObject *source, uint32 eventId, WorldObject *) override
uint32 GetCreatureEntry(ObjectGuid::LowType, CreatureData const *data) override
bool CheckRequiredBosses(uint32 bossId, Player const *player=nullptr) const override
@ NPC_GARROSH_HELLSCREAM