TrinityCore
karazhan.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/* ScriptData
19SDName: Karazhan
20SD%Complete: 100
21SDComment: Support for Barnes (Opera controller) and Berthold (Doorman), Support for Quest 9645.
22SDCategory: Karazhan
23EndScriptData */
24
25/* ContentData
26npc_barnes
27npc_image_of_medivh
28EndContentData */
29
30#include "ScriptMgr.h"
31#include "InstanceScript.h"
32#include "karazhan.h"
33#include "Log.h"
34#include "Map.h"
35#include "MotionMaster.h"
36#include "ObjectAccessor.h"
37#include "Player.h"
38#include "ScriptedEscortAI.h"
39#include "ScriptedGossip.h"
40#include "TemporarySummon.h"
41
43{
44 // Barnes
46 SPELL_TUXEDO = 32616,
47
48 // Berthold
50
51 // Image of Medivh
55 SPELL_MANA_SHIELD = 31635
56};
57
59{
61 NPC_SPOTLIGHT = 19525
62};
63
64/*######
65# npc_barnesAI
66######*/
67
68enum Misc
69{
70 OZ_GOSSIP1_MID = 7421, // I'm not an actor.
72 OZ_GOSSIP2_MID = 7422, // Ok, I'll give it a try, then.
74};
75
76#define OZ_GM_GOSSIP1 "[GM] Change event to EVENT_OZ"
77#define OZ_GM_GOSSIP2 "[GM] Change event to EVENT_HOOD"
78#define OZ_GM_GOSSIP3 "[GM] Change event to EVENT_RAJ"
79
81{
84};
85
87{
88 {0, 6000},
89 {1, 18000},
90 {2, 9000},
91 {3, 15000}
92};
93
95{
96 {4, 6000},
97 {5, 10000},
98 {6, 14000},
99 {7, 15000}
100};
101
103{
104 {8, 5000},
105 {9, 7000},
106 {10, 14000},
107 {11, 14000}
108};
109
110// Entries and spawn locations for creatures in Oz event
111float Spawns[6][2]=
112{
113 {17535, -10896}, // Dorothee
114 {17546, -10891}, // Roar
115 {17547, -10884}, // Tinhead
116 {17543, -10902}, // Strawman
117 {17603, -10892}, // Grandmother
118 {17534, -10900}, // Julianne
119};
120
121#define SPAWN_Z 90.5f
122#define SPAWN_Y -1758
123#define SPAWN_O 4.738f
124
125static constexpr uint32 PATH_ESCORT_BARNES = 134498;
126
128{
129public:
130 npc_barnes() : CreatureScript("npc_barnes") { }
131
132 struct npc_barnesAI : public EscortAI
133 {
134 npc_barnesAI(Creature* creature) : EscortAI(creature)
135 {
136 Initialize();
137 RaidWiped = false;
138 m_uiEventId = 0;
139 instance = creature->GetInstanceScript();
140 }
141
143 {
145
146 TalkCount = 0;
147 TalkTimer = 2000;
148 WipeTimer = 5000;
149
150 PerformanceReady = false;
151 }
152
154
156
161
164
165 void Reset() override
166 {
167 Initialize();
168
170 }
171
173 {
175
176 //resets count for this event, in case earlier failed
177 if (m_uiEventId == EVENT_OZ)
179
181 Start(false);
182 }
183
184 void JustEngagedWith(Unit* /*who*/) override { }
185
186 void WaypointReached(uint32 waypointId, uint32 /*pathId*/) override
187 {
188 switch (waypointId)
189 {
190 case 0:
191 DoCast(me, SPELL_TUXEDO, false);
193 break;
194 case 4:
195 TalkCount = 0;
196 SetEscortPaused(true);
197
198 if (Creature* spotlight = me->SummonCreature(NPC_SPOTLIGHT,
199 me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0.0f,
201 {
202 spotlight->SetUninteractible(true);
203 spotlight->CastSpell(spotlight, SPELL_SPOTLIGHT, false);
204 m_uiSpotlightGUID = spotlight->GetGUID();
205 }
206 break;
207 case 8:
209 PerformanceReady = true;
210 break;
211 case 9:
214 break;
215 }
216 }
217
218 void Talk(uint32 count)
219 {
220 int32 text = 0;
221
222 switch (m_uiEventId)
223 {
224 case EVENT_OZ:
225 if (OzDialogue[count].textid)
226 text = OzDialogue[count].textid;
227 if (OzDialogue[count].timer)
228 TalkTimer = OzDialogue[count].timer;
229 break;
230
231 case EVENT_HOOD:
232 if (HoodDialogue[count].textid)
233 text = HoodDialogue[count].textid;
234 if (HoodDialogue[count].timer)
236 break;
237
238 case EVENT_RAJ:
239 if (RAJDialogue[count].textid)
240 text = RAJDialogue[count].textid;
241 if (RAJDialogue[count].timer)
242 TalkTimer = RAJDialogue[count].timer;
243 break;
244 }
245
246 if (text)
247 CreatureAI::Talk(text);
248 }
249
251 {
252 TC_LOG_DEBUG("scripts", "Barnes Opera Event - Introduction complete - preparing encounter {}", m_uiEventId);
253 uint8 index = 0;
254 uint8 count = 0;
255
256 switch (m_uiEventId)
257 {
258 case EVENT_OZ:
259 index = 0;
260 count = 4;
261 break;
262 case EVENT_HOOD:
263 index = 4;
264 count = index+1;
265 break;
266 case EVENT_RAJ:
267 index = 5;
268 count = index+1;
269 break;
270 }
271
272 for (; index < count; ++index)
273 {
274 uint32 entry = ((uint32)Spawns[index][0]);
275 float PosX = Spawns[index][1];
276
278 creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
279 }
280
281 RaidWiped = false;
282 }
283
284 void UpdateAI(uint32 diff) override
285 {
286 EscortAI::UpdateAI(diff);
287
289 {
290 if (TalkTimer <= diff)
291 {
292 if (TalkCount > 3)
293 {
295 pSpotlight->DespawnOrUnsummon();
296
297 SetEscortPaused(false);
298 return;
299 }
300
302 ++TalkCount;
303 } else TalkTimer -= diff;
304 }
305
307 {
308 if (!RaidWiped)
309 {
310 if (WipeTimer <= diff)
311 {
312 Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
313 if (PlayerList.isEmpty())
314 return;
315
316 RaidWiped = true;
317 for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
318 {
319 if (i->GetSource()->IsAlive() && !i->GetSource()->IsGameMaster())
320 {
321 RaidWiped = false;
322 break;
323 }
324 }
325
326 if (RaidWiped)
327 {
329 return;
330 }
331
332 WipeTimer = 15000;
333 } else WipeTimer -= diff;
334 }
335 }
336 }
337
338 bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
339 {
340 uint32 const action = player->PlayerTalkClass->GetGossipOptionAction(gossipListId);
341 ClearGossipMenuFor(player);
342
343 switch (action)
344 {
345 case GOSSIP_ACTION_INFO_DEF + 1:
348 SendGossipMenuFor(player, 8971, me->GetGUID());
349 break;
350 case GOSSIP_ACTION_INFO_DEF + 2:
351 CloseGossipMenuFor(player);
353 StartEvent();
354 break;
355 case GOSSIP_ACTION_INFO_DEF + 3:
356 CloseGossipMenuFor(player);
358 TC_LOG_DEBUG("scripts", "player ({}) manually set Opera event to EVENT_OZ", player->GetGUID().ToString());
359 break;
360 case GOSSIP_ACTION_INFO_DEF + 4:
361 CloseGossipMenuFor(player);
363 TC_LOG_DEBUG("scripts", "player ({}) manually set Opera event to EVENT_HOOD", player->GetGUID().ToString());
364 break;
365 case GOSSIP_ACTION_INFO_DEF + 5:
366 CloseGossipMenuFor(player);
368 TC_LOG_DEBUG("scripts", "player ({}) manually set Opera event to EVENT_RAJ", player->GetGUID().ToString());
369 break;
370 }
371
372 return true;
373 }
374
375 bool OnGossipHello(Player* player) override
376 {
378 // Check for death of Moroes and if opera event is not done already
380 {
382
383 if (player->IsGameMaster())
384 {
388 }
389
390 if (!RaidWiped)
391 SendGossipMenuFor(player, 8970, me->GetGUID());
392 else
393 SendGossipMenuFor(player, 8975, me->GetGUID());
394
395 return true;
396 }
397
398 SendGossipMenuFor(player, 8978, me->GetGUID());
399 return true;
400 }
401 };
402
403 CreatureAI* GetAI(Creature* creature) const override
404 {
405 return GetKarazhanAI<npc_barnesAI>(creature);
406 }
407};
408
409/*###
410# npc_image_of_medivh
411####*/
412
413enum
414{
425
426static float MedivPos[4] = {-11161.49f, -1902.24f, 91.48f, 1.94f};
427static float ArcanagosPos[4] = {-11169.75f, -1881.48f, 95.39f, 4.83f};
428
430{
431public:
432 npc_image_of_medivh() : CreatureScript("npc_image_of_medivh") { }
433
434 CreatureAI* GetAI(Creature* creature) const override
435 {
436 return GetKarazhanAI<npc_image_of_medivhAI>(creature);
437 }
438
440 {
442 {
443 Initialize();
444 Step = 0;
446 FireMedivhTimer = 0;
447 instance = creature->GetInstanceScript();
448 }
449
451 {
453 EventStarted = false;
454 YellTimer = 0;
455 }
456
458
460
465
467
468 void Reset() override
469 {
470 Initialize();
472
474 {
477 Step = 0;
478 }
479 else
480 {
482 }
483 }
484 void JustEngagedWith(Unit* /*who*/) override { }
485
486 void MovementInform(uint32 type, uint32 id) override
487 {
488 if (type != POINT_MOTION_TYPE)
489 return;
490 if (id == 1)
491 {
492 StartEvent();
495 }
496 }
497
499 {
500 Step = 1;
501 EventStarted = true;
503 if (!Arcanagos)
504 return;
505 ArcanagosGUID = Arcanagos->GetGUID();
506 Arcanagos->SetDisableGravity(true);
508 Arcanagos->SetOrientation(ArcanagosPos[3]);
510 YellTimer = 10000;
511 }
512
514 {
515 switch (step)
516 {
517 case 0: return 9999999;
518 case 1:
520 return 10000;
521 case 2:
523 arca->AI()->Talk(SAY_DIALOG_ARCANAGOS_2);
524 return 20000;
525 case 3:
527 return 10000;
528 case 4:
530 arca->AI()->Talk(SAY_DIALOG_ARCANAGOS_4);
531 return 20000;
532 case 5:
534 return 20000;
535 case 6:
537 arca->AI()->Talk(SAY_DIALOG_ARCANAGOS_6);
538 return 10000;
539 case 7:
540 FireArcanagosTimer = 500;
541 return 5000;
542 case 8:
543 FireMedivhTimer = 500;
545 return 10000;
546 case 9:
548 return 10000;
549 case 10:
551 DoCast(arca, SPELL_CONFLAGRATION_BLAST, false);
552 return 1000;
553 case 11:
555 arca->AI()->Talk(SAY_DIALOG_ARCANAGOS_8);
556 return 5000;
557 case 12:
559 {
560 arca->GetMotionMaster()->MovePoint(0, -11010.82f, -1761.18f, 156.47f);
561 arca->setActive(true);
562 arca->SetFarVisible(true);
563 arca->InterruptNonMeleeSpells(true);
564 arca->SetSpeedRate(MOVE_FLIGHT, 2.0f);
565 }
566 return 10000;
567 case 13:
569 return 10000;
570 case 14:
571 {
572 me->SetVisible(false);
573 me->ClearInCombat();
574
575 InstanceMap::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
576 for (InstanceMap::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
577 {
578 if (i->GetSource()->IsAlive())
579 {
580 if (i->GetSource()->GetQuestStatus(9645) == QUEST_STATUS_INCOMPLETE)
581 i->GetSource()->CompleteQuest(9645);
582 }
583 }
584 return 50000;
585 }
586 case 15:
588 arca->KillSelf();
589 return 5000;
590 default:
591 return 9999999;
592 }
593 }
594
595 void UpdateAI(uint32 diff) override
596 {
597 if (YellTimer <= diff)
598 {
599 if (EventStarted)
601 } else YellTimer -= diff;
602
603 if (Step >= 7 && Step <= 12)
604 {
606
607 if (FireArcanagosTimer <= diff)
608 {
609 if (arca)
610 arca->CastSpell(me, SPELL_FIRE_BALL, false);
611 FireArcanagosTimer = 6000;
612 } else FireArcanagosTimer -= diff;
613
614 if (FireMedivhTimer <= diff)
615 {
616 if (arca)
617 DoCast(arca, SPELL_FIRE_BALL);
618 FireMedivhTimer = 5000;
619 } else FireMedivhTimer -= diff;
620 }
621 }
622 };
623};
624
626{
627 new npc_barnes();
629}
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
@ IN_PROGRESS
@ DONE
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
@ POINT_MOTION_TYPE
@ TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
Definition: ObjectDefines.h:63
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
Definition: ObjectDefines.h:68
Spells
Definition: PlayerAI.cpp:32
@ QUEST_STATUS_INCOMPLETE
Definition: QuestDef.h:145
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
@ STATE_ESCORT_PAUSED
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
@ MOVE_FLIGHT
Definition: UnitDefines.h:123
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
Creature *const me
Definition: CreatureAI.h:61
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2415
virtual bool SetBossState(uint32 id, EncounterState state)
virtual ObjectGuid GetGuidData(uint32 type) const override
void DoUseDoorOrButton(ObjectGuid guid, uint32 withRestoreTime=0, bool useAlternativeState=false)
EncounterState GetBossState(uint32 id) const
bool isEmpty() const
Definition: LinkedList.h:110
iterator end()
Definition: MapRefManager.h:35
iterator begin()
Definition: MapRefManager.h:34
PlayerList const & GetPlayers() const
Definition: Map.h:367
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={})
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
void Clear()
Definition: ObjectGuid.h:286
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool IsGameMaster() const
Definition: Player.h:1178
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition: Player.h:2380
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
Definition: Unit.h:627
void SetVisible(bool x)
Definition: Unit.cpp:8351
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
bool SetDisableGravity(bool disable, bool updateAnimTier=true)
Definition: Unit.cpp:12725
void ClearInCombat()
Definition: Unit.h:1046
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:833
Map * GetMap() const
Definition: Object.h:624
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
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:2025
virtual uint32 GetData(uint32) const
Definition: ZoneScript.h:91
virtual void SetData(uint32, uint32)
Definition: ZoneScript.h:92
virtual void SetGuidData(uint32, ObjectGuid)
Definition: ZoneScript.h:84
CreatureAI * GetAI(Creature *creature) const override
Definition: karazhan.cpp:403
CreatureAI * GetAI(Creature *creature) const override
Definition: karazhan.cpp:434
Spawns
Definition: hyjalAI.cpp:36
static float ArcanagosPos[4]
Definition: karazhan.cpp:427
#define OZ_GM_GOSSIP2
Definition: karazhan.cpp:77
static float MedivPos[4]
Definition: karazhan.cpp:426
#define SPAWN_Y
Definition: karazhan.cpp:122
@ NPC_ARCANAGOS
Definition: karazhan.cpp:60
@ NPC_SPOTLIGHT
Definition: karazhan.cpp:61
static Dialogue HoodDialogue[]
Definition: karazhan.cpp:94
#define SPAWN_O
Definition: karazhan.cpp:123
@ OZ_GOSSIP2_MID
Definition: karazhan.cpp:72
@ OZ_GOSSIP1_OID
Definition: karazhan.cpp:71
@ OZ_GOSSIP2_OID
Definition: karazhan.cpp:73
@ OZ_GOSSIP1_MID
Definition: karazhan.cpp:70
@ SPELL_TUXEDO
Definition: karazhan.cpp:46
@ SPELL_FIRE_BALL
Definition: karazhan.cpp:52
@ SPELL_CONFLAGRATION_BLAST
Definition: karazhan.cpp:54
@ SPELL_MANA_SHIELD
Definition: karazhan.cpp:55
@ SPELL_TELEPORT
Definition: karazhan.cpp:49
@ SPELL_SPOTLIGHT
Definition: karazhan.cpp:45
@ SPELL_UBER_FIREBALL
Definition: karazhan.cpp:53
static Dialogue OzDialogue[]
Definition: karazhan.cpp:86
@ SAY_DIALOG_MEDIVH_1
Definition: karazhan.cpp:415
@ SAY_DIALOG_ARCANAGOS_8
Definition: karazhan.cpp:422
@ SAY_DIALOG_MEDIVH_9
Definition: karazhan.cpp:423
@ SAY_DIALOG_ARCANAGOS_4
Definition: karazhan.cpp:418
@ SAY_DIALOG_ARCANAGOS_2
Definition: karazhan.cpp:416
@ SAY_DIALOG_MEDIVH_5
Definition: karazhan.cpp:419
@ SAY_DIALOG_ARCANAGOS_6
Definition: karazhan.cpp:420
@ SAY_DIALOG_MEDIVH_3
Definition: karazhan.cpp:417
@ EMOTE_DIALOG_MEDIVH_7
Definition: karazhan.cpp:421
#define SPAWN_Z
Definition: karazhan.cpp:121
#define OZ_GM_GOSSIP3
Definition: karazhan.cpp:78
static constexpr uint32 PATH_ESCORT_BARNES
Definition: karazhan.cpp:125
static Dialogue RAJDialogue[]
Definition: karazhan.cpp:102
#define OZ_GM_GOSSIP1
Definition: karazhan.cpp:76
void AddSC_karazhan()
Definition: karazhan.cpp:625
@ EVENT_HOOD
Definition: karazhan.h:65
@ EVENT_OZ
Definition: karazhan.h:64
@ EVENT_RAJ
Definition: karazhan.h:66
@ DATA_GO_CURTAINS
Definition: karazhan.h:46
@ DATA_GO_STAGEDOORLEFT
Definition: karazhan.h:47
@ DATA_IMAGE_OF_MEDIVH
Definition: karazhan.h:55
@ DATA_MOROES
Definition: karazhan.h:31
@ DATA_OPERA_OZ_DEATHCOUNT
Definition: karazhan.h:43
@ DATA_OPERA_PERFORMANCE
Definition: karazhan.h:34
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
int32 textid
Definition: karazhan.cpp:82
uint32 timer
Definition: karazhan.cpp:83
void Start(bool isActiveAttacker=true, ObjectGuid playerGUID=ObjectGuid::Empty, Quest const *quest=nullptr, bool instantRespawn=false, bool canLoopPath=false)
void EnterEvadeMode(EvadeReason why) override
bool HasEscortState(uint32 escortState)
void LoadPath(uint32 pathId)
void SetEscortPaused(bool on)
void UpdateAI(uint32 diff) override
constexpr void SetOrientation(float orientation)
Definition: Position.h:71
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr float GetPositionZ() const
Definition: Position.h:78
void UpdateAI(uint32 diff) override
Definition: karazhan.cpp:284
void JustEngagedWith(Unit *) override
Definition: karazhan.cpp:184
bool OnGossipSelect(Player *player, uint32, uint32 gossipListId) override
Definition: karazhan.cpp:338
void Reset() override
Definition: karazhan.cpp:165
void WaypointReached(uint32 waypointId, uint32) override
Definition: karazhan.cpp:186
bool OnGossipHello(Player *player) override
Definition: karazhan.cpp:375
void Talk(uint32 count)
Definition: karazhan.cpp:218
InstanceScript * instance
Definition: karazhan.cpp:153
ObjectGuid m_uiSpotlightGUID
Definition: karazhan.cpp:155
npc_barnesAI(Creature *creature)
Definition: karazhan.cpp:134
void MovementInform(uint32 type, uint32 id) override
Definition: karazhan.cpp:486
void UpdateAI(uint32 diff) override
Definition: karazhan.cpp:595