TrinityCore
Loading...
Searching...
No Matches
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#include "WorldSession.h"
39
77
79{
80 SPELL_LIGHT_TORCH = 18953, // channeled spell by Ranshalla while waiting for the torches / altar
81};
82
90
91enum GOs
92{
94 GO_ELUNE_FIRE = 177417,
95 GO_ELUNE_GEM = 177414, // is respawned in script
96 GO_ELUNE_LIGHT = 177415, // are respawned in script
97};
98
100{
102};
103
105{
106 NPC_PRIESTESS_DATA_1 = -1, // dummy member for the first priestess (right)
107 NPC_PRIESTESS_DATA_2 = -2, // dummy member for the second priestess (left)
108 DATA_MOVE_PRIESTESS = -3, // dummy member to check the priestess movement
109 DATA_EVENT_END = -4, // dummy member to indicate the event end
110
111 EVENT_RESUME = 1, // trigger rest of event
112};
113
114// DialogueHelper (imported from SD)
115
122
124{
125public:
126 // The array MUST be terminated by {0, 0, 0}
127 DialogueHelper(DialogueEntry const* dialogueArray) :
128 _dialogueArray(dialogueArray),
129 _currentEntry(nullptr),
130 _actionTimer(0)
131 { }
132 // The array MUST be terminated by {0, 0, 0, 0, 0}
133
136
138 {
139 // Find textEntry
140 bool found = false;
141
142 for (DialogueEntry const* entry = _dialogueArray; entry->TextEntry; ++entry)
143 {
144 if (entry->TextEntry == textEntry)
145 {
146 _currentEntry = entry;
147 found = true;
148 break;
149 }
150 }
151
152 if (!found)
153 return;
154
156 }
157
159 {
160 if (_actionTimer)
161 {
162 if (_actionTimer <= diff)
164 else
165 _actionTimer -= diff;
166 }
167 }
168
169protected:
171 virtual void JustDidDialogueStep(int32 /*entry*/) { }
173 virtual Creature* GetSpeakerByEntry(int32 /*entry*/) { return nullptr; }
174
175private:
177 {
178 // Last Dialogue Entry done?
180 {
181 _actionTimer = 0;
182 return;
183 }
184
185 // Get Text, SpeakerEntry and Timer
186 int32 textEntry = _currentEntry->TextEntry;
187 uint32 sayerEntry = _currentEntry->SayerEntry;
189
190 // Simulate Case
191 if (sayerEntry && textEntry >= 0)
192 {
193 // Use Speaker if directly provided
194 if (Creature* speaker = GetSpeakerByEntry(sayerEntry))
195 speaker->AI()->Talk(textEntry);
196 }
197
199
200 // Increment position
202 }
203
206
208};
209
211{
214 {NPC_RANSHALLA, 0, 0}, // start the altar channeling
218 {SAY_RANSHALLA_ALTAR_6, NPC_RANSHALLA, 4000}, // start the escort here
220 {SAY_PRIESTESS_ALTAR_8, NPC_PRIESTESS_DATA_2, 5000}, // show the gem
221 {GO_ELUNE_GEM, 0, 5000},
222 {SAY_PRIESTESS_ALTAR_9, NPC_PRIESTESS_DATA_1, 4000}, // move priestess 1 near me
223 {NPC_PRIESTESS_DATA_1, 0, 3000},
227 {SAY_PRIESTESS_ALTAR_13, NPC_PRIESTESS_DATA_1, 8000}, // summon voice and guard of elune
228 {NPC_VOICE_ELUNE, 0, 12000},
229 {SAY_VOICE_ALTAR_15, NPC_VOICE_ELUNE, 5000}, // move priestess 2 near me
230 {NPC_PRIESTESS_DATA_2, 0, 3000},
234 {SAY_PRIESTESS_ALTAR_19, NPC_PRIESTESS_DATA_1, 3000}, // move the owlbeast
235 {NPC_GUARDIAN_ELUNE, 0, 2000},
236 {SAY_PRIESTESS_ALTAR_20, NPC_PRIESTESS_DATA_1, 4000}, // move the first priestess up
237 {SAY_PRIESTESS_ALTAR_21, NPC_PRIESTESS_DATA_2, 10000}, // move second priestess up
238 {DATA_MOVE_PRIESTESS, 0, 6000}, // despawn the gem
239 {DATA_EVENT_END, 0, 2000}, // turn towards the player
241 {0, 0, 0},
242};
243
245{
246 {5515.98f, -4903.43f, 846.30f, 4.58f}, // 0 right priestess summon loc
247 {5501.94f, -4920.20f, 848.69f, 6.15f}, // 1 left priestess summon loc
248 {5497.35f, -4906.49f, 850.83f, 2.76f}, // 2 guard of elune summon loc
249 {5518.38f, -4913.47f, 845.57f, 0.00f}, // 3 right priestess move loc
250 {5510.36f, -4921.17f, 846.33f, 0.00f}, // 4 left priestess move loc
251 {5511.31f, -4913.82f, 847.17f, 0.00f}, // 5 guard of elune move loc
252 {5518.51f, -4917.56f, 845.23f, 0.00f}, // 6 right priestess second move loc
253 {5514.40f, -4921.16f, 845.49f, 0.00f} // 7 left priestess second move loc
254};
255
256/*#####
257# npc_ranshalla
258#####*/
259
260static constexpr uint32 PATH_ESCORT_RANSHALLA = 82402;
261
263{
264public:
265 npc_ranshalla() : CreatureScript("npc_ranshalla") { }
266
267 struct npc_ranshallaAI : public EscortAI, private DialogueHelper
268 {
270 {
271 Initialize();
272 }
273
275 {
276 _delayTimer = 0;
277 }
278
280
286
287 void Reset() override
288 {
289 Initialize();
290 }
291
292 // Called when the player activates the torch / altar
293 void DoContinueEscort(bool isAltarWaypoint = false)
294 {
296
297 if (isAltarWaypoint)
299 else
301
302 _delayTimer = 2000;
303 }
304
305 // Called when Ranshalla starts to channel on a torch / altar
306 void DoChannelTorchSpell(bool isAltarWaypoint = false)
307 {
308 // Check if we are using the fire or the altar and remove the no_interact flag
309 if (isAltarWaypoint)
310 {
312 {
313 go->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
315 _altarGUID = go->GetGUID();
316 }
317 }
319 go->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
320
321 // Yell and set escort to pause
324 SetEscortPaused(true);
326 }
327
329 {
330 // Summon 2 Elune priestess and make each of them move to a different spot
332 {
333 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[3].m_positionX, wingThicketLocations[3].m_positionY, wingThicketLocations[3].m_positionZ);
334 _firstPriestessGUID = priestess->GetGUID();
335 }
337 {
338 // Left priestess should have a distinct move point because she is the one who starts the dialogue at point reach
339 priestess->GetMotionMaster()->MovePoint(1, wingThicketLocations[4].m_positionX, wingThicketLocations[4].m_positionY, wingThicketLocations[4].m_positionZ);
340 _secondPriestessGUID = priestess->GetGUID();
341 }
342 }
343
344 void SummonedMovementInform(Creature* summoned, uint32 type, uint32 pointId)
345 {
346 if (type != POINT_MOTION_TYPE || summoned->GetEntry() != NPC_PRIESTESS_ELUNE || pointId != 1)
347 return;
348
349 // Start the dialogue when the priestess reach the altar (they should both reach the point in the same time)
351 }
352
353 void WaypointReached(uint32 pointId, uint32 /*pathId*/) override
354 {
355 switch (pointId)
356 {
357 case 3:
359 break;
360 case 10: // Cavern 1
361 case 15: // Cavern 2
362 case 20: // Cavern 3
363 case 25: // Cavern 4
364 case 36: // Cavern 5
366 break;
367 case 39:
369 SetEscortPaused(true);
370 break;
371 case 41:
372 {
373 // Search for all nearest lights and respawn them
374 std::list<GameObject*> eluneLights;
376 for (std::list<GameObject*>::const_iterator itr = eluneLights.begin(); itr != eluneLights.end(); ++itr)
377 {
378 if ((*itr)->isSpawned())
379 continue;
380
381 (*itr)->SetRespawnTime(115);
382 (*itr)->Refresh();
383 }
384
386 me->SetFacingToObject(altar);
387 break;
388 }
389 case 42:
390 // Summon the 2 priestess
391 SetEscortPaused(true);
395 break;
396 case 44:
397 // Stop the escort and turn towards the altar
398 SetEscortPaused(true);
400 me->SetFacingToObject(altar);
401 break;
402 }
403 }
404
405 void JustDidDialogueStep(int32 entry) override
406 {
407 switch (entry)
408 {
409 case NPC_RANSHALLA:
410 // Start the altar channeling
412 break;
414 SetEscortPaused(false);
415 break;
417 // make the gem respawn
418 if (GameObject* gem = GetClosestGameObjectWithEntry(me, GO_ELUNE_GEM, 10.0f, false))
419 {
420 if (gem->isSpawned())
421 break;
422
423 gem->SetRespawnTime(90);
424 gem->Refresh();
425 }
426 break;
428 // move near the escort npc
430 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[6].m_positionX, wingThicketLocations[6].m_positionY, wingThicketLocations[6].m_positionZ);
431 break;
433 // summon the Guardian of Elune
435 {
436 guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[5].m_positionX, wingThicketLocations[5].m_positionY, wingThicketLocations[5].m_positionZ);
437 _guardEluneGUID = guard->GetGUID();
438 }
439 // summon the Voice of Elune
441 {
442 if (Creature* voice = me->SummonCreature(NPC_VOICE_ELUNE, altar->GetPositionX(), altar->GetPositionY(), altar->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 30s))
443 _voiceEluneGUID = voice->GetGUID();
444 }
445 break;
447 // move near the escort npc and continue dialogue
449 {
450 priestess->AI()->Talk(SAY_PRIESTESS_ALTAR_14);
451 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[7].m_positionX, wingThicketLocations[7].m_positionY, wingThicketLocations[7].m_positionZ);
452 }
453 break;
455 // make the voice of elune leave
457 {
458 guard->GetMotionMaster()->MovePoint(0, wingThicketLocations[2].m_positionX, wingThicketLocations[2].m_positionY, wingThicketLocations[2].m_positionZ);
459 guard->DespawnOrUnsummon(4s);
460 }
461 break;
463 // make the first priestess leave
465 {
466 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[0].m_positionX, wingThicketLocations[0].m_positionY, wingThicketLocations[0].m_positionZ);
467 priestess->DespawnOrUnsummon(4s);
468 }
469 break;
471 // make the second priestess leave
473 {
474 priestess->GetMotionMaster()->MovePoint(0, wingThicketLocations[1].m_positionX, wingThicketLocations[1].m_positionY, wingThicketLocations[1].m_positionZ);
475 priestess->DespawnOrUnsummon(4s);
476 }
477 break;
478 case DATA_EVENT_END:
479 // Turn towards the player
480 if (Player* player = GetPlayerForEscort())
481 {
482 me->SetFacingToObject(player);
483 Talk(SAY_RANSHALLA_END_1, player);
484 }
485 break;
487 // Turn towards the altar and kneel - quest complete
489 {
490 me->SetFacingToObject(altar);
491 altar->ResetDoorOrButton();
492 }
494 if (Player* player = GetPlayerForEscort())
495 {
496 player->GroupEventHappens(QUEST_GUARDIANS_ALTAR, me);
497 Talk(SAY_RANSHALLA_END_2, player);
498 }
500 break;
501 }
502 }
503
505 {
506 switch (entry)
507 {
508 case NPC_RANSHALLA:
509 return me;
510 case NPC_VOICE_ELUNE:
516 default:
517 return nullptr;
518 }
519
520 }
521
522 void UpdateEscortAI(uint32 diff) override
523 {
524 DialogueUpdate(diff);
525
526 if (_delayTimer)
527 {
528 if (_delayTimer <= diff)
529 {
530 SetEscortPaused(false);
531 _delayTimer = 0;
532 }
533 else
534 _delayTimer -= diff;
535 }
536 events.Update(diff);
539
541 }
542
543 void OnQuestAccept(Player* player, Quest const* quest) override
544 {
545 if (quest->GetQuestId() == QUEST_GUARDIANS_ALTAR)
546 {
549
551 Start(false, player->GetGUID(), quest);
552 }
553 }
554
555 private:
557 };
558
559 CreatureAI* GetAI(Creature* creature) const override
560 {
561 return new npc_ranshallaAI(creature);
562 }
563};
564
565/*#####
566# go_elune_fire
567#####*/
568
570{
571public:
572 go_elune_fire() : GameObjectScript("go_elune_fire") { }
573
575 {
577
578 bool OnGossipHello(Player* /*player*/) override
579 {
580 // Check if we are using the torches or the altar
581 bool isAltar = false;
582
583 if (me->GetEntry() == GO_ELUNE_ALTAR)
584 isAltar = true;
585
586 if (Creature* ranshalla = GetClosestCreatureWithEntry(me, NPC_RANSHALLA, 10.0f))
587 {
588 if (npc_ranshalla::npc_ranshallaAI* escortAI = dynamic_cast<npc_ranshalla::npc_ranshallaAI*>(ranshalla->AI()))
589 escortAI->DoContinueEscort(isAltar);
590 }
592 return false;
593 }
594 };
595
596 GameObjectAI* GetAI(GameObject* go) const override
597 {
598 return new go_elune_fireAI(go);
599 }
600};
601
603{
604 new npc_ranshalla();
605 new go_elune_fire();
606}
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
@ POINT_MOTION_TYPE
@ TEMPSUMMON_TIMED_DESPAWN
@ TEMPSUMMON_CORPSE_DESPAWN
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:42
Creature *const me
Definition CreatureAI.h:82
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
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)
void Update(uint32 time)
Definition EventMap.h:67
EventId ExecuteEvent()
Definition EventMap.cpp:73
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
GameObject *const me
void SetFlag(GameObjectFlags flags)
Definition GameObject.h:171
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
uint32 GetQuestId() const
Definition QuestDef.h:229
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
void SetFaction(uint32 faction) override
Definition Unit.h:974
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3093
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13259
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10363
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:1992
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)
float m_positionZ
Definition Position.h:58
float m_positionX
Definition Position.h:56
float m_positionY
Definition Position.h:57
float GetOrientation() const
Definition Position.h:82
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