TrinityCore
zone_winterspring.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: Winterspring
20SD%Complete: Almost Completely Emptied
21SDComment: Quest Support 4901
22SDCategory: Winterspring
23EndScriptData */
24
25/* ContentData
26npc_ranshalla
27go_elune_fire
28EndContentData */
29
30#include "ScriptMgr.h"
31#include "GameObject.h"
32#include "GameObjectAI.h"
33#include "MotionMaster.h"
34#include "ObjectAccessor.h"
35#include "Player.h"
36#include "ScriptedEscortAI.h"
37#include "TemporarySummon.h"
38
39enum Says
40{
41 // Escort texts
48
49 // After lighting the altar cinematic
73
75};
76
78{
79 SPELL_LIGHT_TORCH = 18953, // channeled spell by Ranshalla while waiting for the torches / altar
80};
81
82enum NPCs
83{
88};
89
90enum GOs
91{
93 GO_ELUNE_FIRE = 177417,
94 GO_ELUNE_GEM = 177414, // is respawned in script
95 GO_ELUNE_LIGHT = 177415, // are respawned in script
96};
97
99{
101};
102
104{
105 NPC_PRIESTESS_DATA_1 = -1, // dummy member for the first priestess (right)
106 NPC_PRIESTESS_DATA_2 = -2, // dummy member for the second priestess (left)
107 DATA_MOVE_PRIESTESS = -3, // dummy member to check the priestess movement
108 DATA_EVENT_END = -4, // dummy member to indicate the event end
109
110 EVENT_RESUME = 1, // trigger rest of event
111};
112
113// DialogueHelper (imported from SD)
114
116{
120};
121
123{
124public:
125 // The array MUST be terminated by {0, 0, 0}
126 DialogueHelper(DialogueEntry const* dialogueArray) :
127 _dialogueArray(dialogueArray),
128 _currentEntry(nullptr),
129 _actionTimer(0)
130 { }
131 // The array MUST be terminated by {0, 0, 0, 0, 0}
132
135
137 {
138 // Find textEntry
139 bool found = false;
140
141 for (DialogueEntry const* entry = _dialogueArray; entry->TextEntry; ++entry)
142 {
143 if (entry->TextEntry == textEntry)
144 {
145 _currentEntry = entry;
146 found = true;
147 break;
148 }
149 }
150
151 if (!found)
152 return;
153
155 }
156
158 {
159 if (_actionTimer)
160 {
161 if (_actionTimer <= diff)
163 else
164 _actionTimer -= diff;
165 }
166 }
167
168protected:
170 virtual void JustDidDialogueStep(int32 /*entry*/) { }
172 virtual Creature* GetSpeakerByEntry(int32 /*entry*/) { return nullptr; }
173
174private:
176 {
177 // Last Dialogue Entry done?
179 {
180 _actionTimer = 0;
181 return;
182 }
183
184 // Get Text, SpeakerEntry and Timer
185 int32 textEntry = _currentEntry->TextEntry;
186 uint32 sayerEntry = _currentEntry->SayerEntry;
188
189 // Simulate Case
190 if (sayerEntry && textEntry >= 0)
191 {
192 // Use Speaker if directly provided
193 if (Creature* speaker = GetSpeakerByEntry(sayerEntry))
194 speaker->AI()->Talk(textEntry);
195 }
196
198
199 // Increment position
201 }
202
205
207};
208
210{
213 {NPC_RANSHALLA, 0, 0}, // start the altar channeling
217 {SAY_RANSHALLA_ALTAR_6, NPC_RANSHALLA, 4000}, // start the escort here
219 {SAY_PRIESTESS_ALTAR_8, NPC_PRIESTESS_DATA_2, 5000}, // show the gem
220 {GO_ELUNE_GEM, 0, 5000},
221 {SAY_PRIESTESS_ALTAR_9, NPC_PRIESTESS_DATA_1, 4000}, // move priestess 1 near me
222 {NPC_PRIESTESS_DATA_1, 0, 3000},
226 {SAY_PRIESTESS_ALTAR_13, NPC_PRIESTESS_DATA_1, 8000}, // summon voice and guard of elune
227 {NPC_VOICE_ELUNE, 0, 12000},
228 {SAY_VOICE_ALTAR_15, NPC_VOICE_ELUNE, 5000}, // move priestess 2 near me
229 {NPC_PRIESTESS_DATA_2, 0, 3000},
233 {SAY_PRIESTESS_ALTAR_19, NPC_PRIESTESS_DATA_1, 3000}, // move the owlbeast
234 {NPC_GUARDIAN_ELUNE, 0, 2000},
235 {SAY_PRIESTESS_ALTAR_20, NPC_PRIESTESS_DATA_1, 4000}, // move the first priestess up
236 {SAY_PRIESTESS_ALTAR_21, NPC_PRIESTESS_DATA_2, 10000}, // move second priestess up
237 {DATA_MOVE_PRIESTESS, 0, 6000}, // despawn the gem
238 {DATA_EVENT_END, 0, 2000}, // turn towards the player
240 {0, 0, 0},
241};
242
244{
245 {5515.98f, -4903.43f, 846.30f, 4.58f}, // 0 right priestess summon loc
246 {5501.94f, -4920.20f, 848.69f, 6.15f}, // 1 left priestess summon loc
247 {5497.35f, -4906.49f, 850.83f, 2.76f}, // 2 guard of elune summon loc
248 {5518.38f, -4913.47f, 845.57f, 0.00f}, // 3 right priestess move loc
249 {5510.36f, -4921.17f, 846.33f, 0.00f}, // 4 left priestess move loc
250 {5511.31f, -4913.82f, 847.17f, 0.00f}, // 5 guard of elune move loc
251 {5518.51f, -4917.56f, 845.23f, 0.00f}, // 6 right priestess second move loc
252 {5514.40f, -4921.16f, 845.49f, 0.00f} // 7 left priestess second move loc
253};
254
255/*#####
256# npc_ranshalla
257#####*/
258
259static constexpr uint32 PATH_ESCORT_RANSHALLA = 82402;
260
262{
263public:
264 npc_ranshalla() : CreatureScript("npc_ranshalla") { }
265
266 struct npc_ranshallaAI : public EscortAI, private DialogueHelper
267 {
269 {
270 Initialize();
271 }
272
274 {
275 _delayTimer = 0;
276 }
277
279
285
286 void Reset() override
287 {
288 Initialize();
289 }
290
291 // Called when the player activates the torch / altar
292 void DoContinueEscort(bool isAltarWaypoint = false)
293 {
295
296 if (isAltarWaypoint)
298 else
300
301 _delayTimer = 2000;
302 }
303
304 // Called when Ranshalla starts to channel on a torch / altar
305 void DoChannelTorchSpell(bool isAltarWaypoint = false)
306 {
307 // Check if we are using the fire or the altar and remove the no_interact flag
308 if (isAltarWaypoint)
309 {
311 {
312 go->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
314 _altarGUID = go->GetGUID();
315 }
316 }
318 go->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
319
320 // Yell and set escort to pause
323 SetEscortPaused(true);
325 }
326
328 {
329 // Summon 2 Elune priestess and make each of them move to a different spot
331 {
332 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[3]);
333 _firstPriestessGUID = priestess->GetGUID();
334 }
336 {
337 // Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach
338 priestess->GetMotionMaster()->MovePoint(1, wingThicketLocations[4]);
339 _secondPriestessGUID = priestess->GetGUID();
340 }
341 }
342
343 void SummonedMovementInform(Creature* summoned, uint32 type, uint32 pointId)
344 {
345 if (type != POINT_MOTION_TYPE || summoned->GetEntry() != NPC_PRIESTESS_ELUNE || pointId != 1)
346 return;
347
348 // Start the dialogue when the priestess reach the altar (they should both reach the point in the same time)
350 }
351
352 void WaypointReached(uint32 pointId, uint32 /*pathId*/) override
353 {
354 switch (pointId)
355 {
356 case 3:
358 break;
359 case 10: // Cavern 1
360 case 15: // Cavern 2
361 case 20: // Cavern 3
362 case 25: // Cavern 4
363 case 36: // Cavern 5
365 break;
366 case 39:
368 SetEscortPaused(true);
369 break;
370 case 41:
371 {
372 // Search for all nearest lights and respawn them
373 std::list<GameObject*> eluneLights;
375 for (std::list<GameObject*>::const_iterator itr = eluneLights.begin(); itr != eluneLights.end(); ++itr)
376 {
377 if ((*itr)->isSpawned())
378 continue;
379
380 (*itr)->SetRespawnTime(115);
381 (*itr)->Refresh();
382 }
383
385 me->SetFacingToObject(altar);
386 break;
387 }
388 case 42:
389 // Summon the 2 priestess
390 SetEscortPaused(true);
394 break;
395 case 44:
396 // Stop the escort and turn towards the altar
397 SetEscortPaused(true);
399 me->SetFacingToObject(altar);
400 break;
401 }
402 }
403
404 void JustDidDialogueStep(int32 entry) override
405 {
406 switch (entry)
407 {
408 case NPC_RANSHALLA:
409 // Start the altar channeling
411 break;
413 SetEscortPaused(false);
414 break;
416 // make the gem respawn
417 if (GameObject* gem = GetClosestGameObjectWithEntry(me, GO_ELUNE_GEM, 10.0f, false))
418 {
419 if (gem->isSpawned())
420 break;
421
422 gem->SetRespawnTime(90);
423 gem->Refresh();
424 }
425 break;
427 // move near the escort npc
429 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[6]);
430 break;
432 // summon the Guardian of Elune
434 {
435 guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[5]);
436 _guardEluneGUID = guard->GetGUID();
437 }
438 // summon the Voice of Elune
440 {
442 _voiceEluneGUID = voice->GetGUID();
443 }
444 break;
446 // move near the escort npc and continue dialogue
448 {
449 priestess->AI()->Talk(SAY_PRIESTESS_ALTAR_14);
450 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[7]);
451 }
452 break;
454 // make the voice of elune leave
456 {
457 guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[2]);
458 guard->DespawnOrUnsummon(4s);
459 }
460 break;
462 // make the first priestess leave
464 {
465 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[0]);
466 priestess->DespawnOrUnsummon(4s);
467 }
468 break;
470 // make the second priestess leave
472 {
473 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[1]);
474 priestess->DespawnOrUnsummon(4s);
475 }
476 break;
477 case DATA_EVENT_END:
478 // Turn towards the player
479 if (Player* player = GetPlayerForEscort())
480 {
481 me->SetFacingToObject(player);
482 Talk(SAY_RANSHALLA_END_1, player);
483 }
484 break;
486 // Turn towards the altar and kneel - quest complete
488 {
489 me->SetFacingToObject(altar);
490 altar->ResetDoorOrButton();
491 }
493 if (Player* player = GetPlayerForEscort())
494 {
495 player->GroupEventHappens(QUEST_GUARDIANS_ALTAR, me);
496 Talk(SAY_RANSHALLA_END_2, player);
497 }
499 break;
500 }
501 }
502
504 {
505 switch (entry)
506 {
507 case NPC_RANSHALLA:
508 return me;
509 case NPC_VOICE_ELUNE:
515 default:
516 return nullptr;
517 }
518
519 }
520
521 void UpdateEscortAI(uint32 diff) override
522 {
523 DialogueUpdate(diff);
524
525 if (_delayTimer)
526 {
527 if (_delayTimer <= diff)
528 {
529 SetEscortPaused(false);
530 _delayTimer = 0;
531 }
532 else
533 _delayTimer -= diff;
534 }
535 events.Update(diff);
538
540 }
541
542 void OnQuestAccept(Player* player, Quest const* quest) override
543 {
544 if (quest->GetQuestId() == QUEST_GUARDIANS_ALTAR)
545 {
548
550 Start(false, player->GetGUID(), quest);
551 }
552 }
553
554 private:
556 };
557
558 CreatureAI* GetAI(Creature* creature) const override
559 {
560 return new npc_ranshallaAI(creature);
561 }
562};
563
564/*#####
565# go_elune_fire
566#####*/
567
569{
570public:
571 go_elune_fire() : GameObjectScript("go_elune_fire") { }
572
574 {
576
577 bool OnGossipHello(Player* /*player*/) override
578 {
579 // Check if we are using the torches or the altar
580 bool isAltar = false;
581
582 if (me->GetEntry() == GO_ELUNE_ALTAR)
583 isAltar = true;
584
585 if (Creature* ranshalla = GetClosestCreatureWithEntry(me, NPC_RANSHALLA, 10.0f))
586 {
587 if (npc_ranshalla::npc_ranshallaAI* escortAI = dynamic_cast<npc_ranshalla::npc_ranshallaAI*>(ranshalla->AI()))
588 escortAI->DoContinueEscort(isAltar);
589 }
591 return false;
592 }
593 };
594
595 GameObjectAI* GetAI(GameObject* go) const override
596 {
597 return new go_elune_fireAI(go);
598 }
599};
600
602{
603 new npc_ranshalla();
604 new go_elune_fire();
605}
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
@ POINT_MOTION_TYPE
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
@ TEMPSUMMON_CORPSE_DESPAWN
Definition: ObjectDefines.h:67
Spells
Definition: PlayerAI.cpp:32
GameObject * GetClosestGameObjectWithEntry(WorldObject *source, uint32 entry, float maxSearchRange, bool spawnedOnly=true)
Creature * GetClosestCreatureWithEntry(WorldObject *source, uint32 entry, float maxSearchRange, bool alive=true)
void GetGameObjectListWithEntryInGrid(Container &container, WorldObject *source, uint32 entry, float maxSearchRange)
@ GO_FLAG_NOT_SELECTABLE
@ FACTION_ESCORTEE_A_NEUTRAL_PASSIVE
@ UNIT_STAND_STATE_KNEEL
Definition: UnitDefines.h:50
Says
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
DialogueHelper(DialogueEntry const *dialogueArray)
DialogueEntry const * _dialogueArray
virtual Creature * GetSpeakerByEntry(int32)
Will be called to get a speaker, MUST be implemented if not used in instances.
virtual void JustDidDialogueStep(int32)
Will be called when a dialogue step was done.
DialogueEntry const * _currentEntry
void DialogueUpdate(uint32 diff)
void StartNextDialogueText(int32 textEntry)
uint32 ExecuteEvent()
Definition: EventMap.cpp:73
void Update(uint32 time)
Definition: EventMap.h:56
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition: EventMap.cpp:36
GameObject *const me
Definition: GameObjectAI.h:50
void SetFlag(GameObjectFlags flags)
Definition: GameObject.h:274
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
uint32 GetQuestId() const
Definition: QuestDef.h:587
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10100
void SetFaction(uint32 faction) override
Definition: Unit.h:859
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition: Unit.cpp:12671
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
GameObjectAI * GetAI(GameObject *go) const override
CreatureAI * GetAI(Creature *creature) const override
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
int32 TextEntry
To be said text entry.
int32 SayerEntry
Entry of the mob who should say.
uint32 SayTimer
Time delay until next text of array is said (0 stops)
void Start(bool isActiveAttacker=true, ObjectGuid playerGUID=ObjectGuid::Empty, Quest const *quest=nullptr, bool instantRespawn=false, bool canLoopPath=false)
virtual void UpdateEscortAI(uint32 diff)
void LoadPath(uint32 pathId)
Player * GetPlayerForEscort()
void SetEscortPaused(bool on)
bool OnGossipHello(Player *) override
void SummonedMovementInform(Creature *summoned, uint32 type, uint32 pointId)
void OnQuestAccept(Player *player, Quest const *quest) override
void JustDidDialogueStep(int32 entry) override
Will be called when a dialogue step was done.
void WaypointReached(uint32 pointId, uint32) override
Creature * GetSpeakerByEntry(int32 entry) override
Will be called to get a speaker, MUST be implemented if not used in instances.
void DoChannelTorchSpell(bool isAltarWaypoint=false)
void DoContinueEscort(bool isAltarWaypoint=false)
void UpdateEscortAI(uint32 diff) override
@ GO_ELUNE_LIGHT
@ GO_ELUNE_ALTAR
@ GO_ELUNE_FIRE
@ GO_ELUNE_GEM
@ SAY_RANSHALLA_END_2
@ SAY_PRIESTESS_ALTAR_16
@ SAY_PRIESTESS_ALTAR_20
@ SAY_PRIESTESS_ALTAR_14
@ SAY_REACH_TORCH
@ SAY_PRIESTESS_ALTAR_17
@ EMOTE_CHANT_SPELL
@ SAY_PRIESTESS_ALTAR_7
@ SAY_REACH_ALTAR_1
@ SAY_PRIESTESS_ALTAR_18
@ SAY_RANSHALLA_ALTAR_6
@ SAY_RANSHALLA_ALTAR_2
@ SAY_VOICE_ALTAR_15
@ SAY_RANSHALLA_END_1
@ SAY_ENTER_OWL_THICKET
@ SAY_PRIESTESS_ALTAR_13
@ SAY_PRIESTESS_ALTAR_3
@ SAY_PRIESTESS_ALTAR_8
@ SAY_PRIESTESS_ALTAR_19
@ SAY_PRIESTESS_ALTAR_11
@ SAY_PRIESTESS_ALTAR_21
@ SAY_RANSHALLA_ALTAR_1
@ SAY_QUEST_START
@ SAY_AFTER_TORCH
@ SAY_PRIESTESS_ALTAR_12
@ SAY_PRIESTESS_ALTAR_9
@ SAY_PRIESTESS_ALTAR_4
@ SAY_REACH_ALTAR_2
@ SAY_PRIESTESS_ALTAR_10
@ SAY_RANSHALLA_ALTAR_5
@ NPC_PRIESTESS_DATA_1
@ DATA_EVENT_END
@ NPC_PRIESTESS_DATA_2
@ DATA_MOVE_PRIESTESS
@ EVENT_RESUME
@ QUEST_GUARDIANS_ALTAR
@ SPELL_LIGHT_TORCH
@ NPC_RANSHALLA
@ NPC_GUARDIAN_ELUNE
@ NPC_VOICE_ELUNE
@ NPC_PRIESTESS_ELUNE
const DialogueEntry introDialogue[]
static Position wingThicketLocations[]
void AddSC_winterspring()
static constexpr uint32 PATH_ESCORT_RANSHALLA