TrinityCore
Loading...
Searching...
No Matches
zone_blades_edge_mountains.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: Blades_Edge_Mountains
20SD%Complete: 90
21SDComment: Quest support: 10503, 10504, 10594, 10609, 10821. Ogri'la->Skettis Flight.
22SDCategory: Blade's Edge Mountains
23EndScriptData */
24
25/* ContentData
26npc_nether_drake
27go_legion_obelisk
28EndContentData */
29
30#include "ScriptMgr.h"
31#include "CellImpl.h"
32#include "CreatureAIImpl.h"
33#include "GameObjectAI.h"
34#include "GridNotifiersImpl.h"
35#include "MotionMaster.h"
36#include "ObjectAccessor.h"
37#include "ScriptedCreature.h"
38#include "ScriptedGossip.h"
39#include "SpellInfo.h"
40#include "SpellScript.h"
41#include "TemporarySummon.h"
42
43/*######
44## npc_nether_drake
45######*/
46
48{
49 //Used by 20021, 21817, 21820, 21821, 21823 but not existing in database
55
56 ENTRY_WHELP = 20021,
57 ENTRY_PROTO = 21821,
58 ENTRY_ADOLE = 21817,
59 ENTRY_MATUR = 21820,
60 ENTRY_NIHIL = 21823,
61
63
67};
68
70{
71public:
72 npc_nether_drake() : CreatureScript("npc_nether_drake") { }
73
75 {
76 npc_nether_drakeAI(Creature* creature) : ScriptedAI(creature)
77 {
78 Initialize();
79 }
80
82 {
83 IsNihil = false;
84 NihilSpeech_Timer = 3000;
86
87 ArcaneBlast_Timer = 7500;
88 ManaBurn_Timer = 10000;
90 }
91
92 bool IsNihil;
95
99
100 void Reset() override
101 {
102 Initialize();
103 }
104
105 void JustEngagedWith(Unit* /*who*/) override { }
106
107 void MoveInLineOfSight(Unit* who) override
108
109 {
111 return;
112
114 }
115
116 //in case Creature was not summoned (not expected)
117 void MovementInform(uint32 type, uint32 id) override
118 {
119 if (type != POINT_MOTION_TYPE)
120 return;
121
122 if (id == 0)
123 me->DespawnOrUnsummon(1ms);
124 }
125
126 void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override
127 {
128 Player* playerCaster = caster->ToPlayer();
129 if (!playerCaster)
130 return;
131
132 if (spellInfo->Id == SPELL_T_PHASE_MODULATOR)
133 {
134 const uint32 entry_list[4] = {ENTRY_PROTO, ENTRY_ADOLE, ENTRY_MATUR, ENTRY_NIHIL};
135 int cid = rand32() % (4 - 1);
136
137 if (entry_list[cid] == me->GetEntry())
138 ++cid;
139
140 //we are nihil, so say before transform
141 if (me->GetEntry() == ENTRY_NIHIL)
142 {
145 IsNihil = false;
146 }
147
148 if (me->UpdateEntry(entry_list[cid]))
149 {
150 if (entry_list[cid] == ENTRY_NIHIL)
151 {
154 IsNihil = true;
155 }
156 else
157 AttackStart(playerCaster);
158 }
159 }
160 }
161
162 void UpdateAI(uint32 diff) override
163 {
164 if (IsNihil)
165 {
166 if (NihilSpeech_Timer <= diff)
167 {
168 switch (NihilSpeech_Phase)
169 {
170 case 0:
173 break;
174 case 1:
177 break;
178 case 2:
181 break;
182 case 3:
185 break;
186 case 4:
187 me->SetUninteractible(true);
188 //take off to location above
191 break;
192 }
193 NihilSpeech_Timer = 5000;
194 } else NihilSpeech_Timer -=diff;
195
196 //anything below here is not interesting for Nihil, so skip it
197 return;
198 }
199
200 if (!UpdateVictim())
201 return;
202
203 if (IntangiblePresence_Timer <= diff)
204 {
206 IntangiblePresence_Timer = 15000 + rand32() % 15000;
207 } else IntangiblePresence_Timer -= diff;
208
209 if (ManaBurn_Timer <= diff)
210 {
211 Unit* target = me->GetVictim();
212 if (target && target->GetPowerType() == POWER_MANA)
213 DoCast(target, SPELL_MANA_BURN);
214 ManaBurn_Timer = 8000 + rand32() % 8000;
215 } else ManaBurn_Timer -= diff;
216
217 if (ArcaneBlast_Timer <= diff)
218 {
220 ArcaneBlast_Timer = 2500 + rand32() % 5000;
221 } else ArcaneBlast_Timer -= diff;
222 }
223 };
224
225 CreatureAI* GetAI(Creature* creature) const override
226 {
227 return new npc_nether_drakeAI(creature);
228 }
229};
230
231//Support for quest: You're Fired! (10821)
233
244
245/*######
246## go_legion_obelisk
247######*/
248
250{
251public:
252 go_legion_obelisk() : GameObjectScript("go_legion_obelisk") { }
253
255 {
257
258 bool OnGossipHello(Player* player) override
259 {
261 {
262 switch (me->GetEntry())
263 {
265 obelisk_one = true;
266 break;
268 obelisk_two = true;
269 break;
271 obelisk_three = true;
272 break;
274 obelisk_four = true;
275 break;
277 obelisk_five = true;
278 break;
279 }
280
281 if (obelisk_one == true && obelisk_two == true && obelisk_three == true && obelisk_four == true && obelisk_five == true)
282 {
283 me->SummonCreature(NPC_DOOMCRYER, 2943.40f, 4778.20f, 284.49f, 0.94f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2min);
284 //reset global var
285 obelisk_one = false;
286 obelisk_two = false;
287 obelisk_three = false;
288 obelisk_four = false;
289 obelisk_five = false;
290 }
291 }
292
293 return true;
294 }
295 };
296
297 GameObjectAI* GetAI(GameObject* go) const override
298 {
299 return new go_legion_obeliskAI(go);
300 }
301};
302
349
364
373
375{
376 public:
377 npc_simon_bunny() : CreatureScript("npc_simon_bunny") { }
378
380 {
381 npc_simon_bunnyAI(Creature* creature) : ScriptedAI(creature)
382 {
383 large = false;
384 listening = false;
385 gameLevel = 0;
386 fails = 0;
387 gameTicks = 0;
388 memset(clusterIds, 0, sizeof(clusterIds));
389 zCoordCorrection = 0.f;
390 searchDistance = 0.f;
391 }
392
393 bool large;
404
458
459 void DoAction(int32 action) override
460 {
461 switch (action)
462 {
464 listening = false;
468 if (gameLevel == 10)
469 ResetNode();
470 else
472 break;
474 gameLevel++;
476 break;
480 break;
481 }
482 }
483
484 // Called by color clusters script (go_simon_cluster) and used for knowing the button pressed by player
485 void SetData(uint32 type, uint32 /*data*/) override
486 {
487 if (!listening)
488 return;
489
490 uint8 pressedColor = SIMON_MAX_COLORS;
491
492 if (type == clusterIds[SIMON_RED])
493 pressedColor = SIMON_RED;
494 else if (type == clusterIds[SIMON_BLUE])
495 pressedColor = SIMON_BLUE;
496 else if (type == clusterIds[SIMON_GREEN])
497 pressedColor = SIMON_GREEN;
498 else if (type == clusterIds[SIMON_YELLOW])
499 pressedColor = SIMON_YELLOW;
500
501 PlayColor(pressedColor);
502 playerSequence.push_back(pressedColor);
505 }
506
507 // Used for getting involved player guid. Parameter id is used for defining if is a large(Monument) or small(Relic) node
508 void SetGUID(ObjectGuid const& guid, int32 id) override
509 {
510 me->SetCanFly(true);
511
512 large = id != 0;
513 playerGUID = guid;
514 StartGame();
515 }
516
517 /*
518 Resets all variables and also find the ids of the four closests color clusters, since every simon
519 node have diferent ids for clusters this is absolutely NECESSARY.
520 */
522 {
523 listening = false;
524 gameLevel = 0;
525 fails = 0;
526 gameTicks = 0;
527 zCoordCorrection = large ? 8.0f : 2.75f;
528 searchDistance = large ? 13.0f : 5.0f;
529 colorSequence.clear();
530 playableSequence.clear();
531 playerSequence.clear();
532 me->SetObjectScale(large ? 2.0f : 1.0f);
533
534 std::list<WorldObject*> ClusterList;
538
539 for (std::list<WorldObject*>::const_iterator i = ClusterList.begin(); i != ClusterList.end(); ++i)
540 {
541 if (GameObject* go = (*i)->ToGameObject())
542 {
543 // We are checking for displayid because all simon nodes have 4 clusters with different entries
544 if (large)
545 {
546 switch (go->GetGOInfo()->displayId)
547 {
549 clusterIds[SIMON_BLUE] = go->GetEntry();
550 break;
551
553 clusterIds[SIMON_RED] = go->GetEntry();
554 break;
555
557 clusterIds[SIMON_GREEN] = go->GetEntry();
558 break;
559
561 clusterIds[SIMON_YELLOW] = go->GetEntry();
562 break;
563 }
564 }
565 else
566 {
567 switch (go->GetGOInfo()->displayId)
568 {
570 clusterIds[SIMON_BLUE] = go->GetEntry();
571 break;
572
574 clusterIds[SIMON_RED] = go->GetEntry();
575 break;
576
578 clusterIds[SIMON_GREEN] = go->GetEntry();
579 break;
580
582 clusterIds[SIMON_YELLOW] = go->GetEntry();
583 break;
584 }
585 }
586 }
587 }
588
589 _events.Reset();
592
594 relic->SetFlag(GO_FLAG_NOT_SELECTABLE);
595 }
596
597 // Called when despawning the bunny. Sets all the node GOs to their default states.
599 {
601
602 for (uint32 clusterId = SIMON_BLUE; clusterId < SIMON_MAX_COLORS; clusterId++)
603 if (GameObject* cluster = me->FindNearestGameObject(clusterIds[clusterId], searchDistance))
604 cluster->SetFlag(GO_FLAG_NOT_SELECTABLE);
605
606 for (uint32 auraId = GO_AURA_BLUE; auraId <= GO_AURA_YELLOW; auraId++)
607 if (GameObject* auraGo = me->FindNearestGameObject(auraId, searchDistance))
608 auraGo->RemoveFromWorld();
609
611 relic->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
612
614 }
615
616 /*
617 Called on every button click of player. Adds the clicked color to the player created sequence and
618 checks if it corresponds to the AI created sequence. If so, incremente gameLevel and start a new
619 round, if not, give punishment and restart current level.
620 */
622 {
623 bool correct = true;
624 if (playerSequence.size() <= colorSequence.size())
625 for (std::list<uint8>::const_iterator i = playerSequence.begin(), j = colorSequence.begin(); i != playerSequence.end(); ++i, ++j)
626 if ((*i) != (*j))
627 correct = false;
628
629 if (correct && (playerSequence.size() == colorSequence.size()))
631 else if (!correct)
633 }
634
635 /*
636 Generates a random sequence of colors depending on the gameLevel. We also copy this sequence to
637 the playableSequence wich will be used when playing the sequence to the player.
638 */
640 {
641 colorSequence.clear();
642 for (uint8 i = 0; i <= gameLevel; i++)
644
645 for (std::list<uint8>::const_iterator i = colorSequence.begin(); i != colorSequence.end(); ++i)
646 playableSequence.push_back(*i);
647 }
648
649 // Remove any existant glowing auras over clusters and set clusters ready for interating with them.
650 void PrepareClusters(bool clustersOnly = false)
651 {
652 for (uint32 clusterId = SIMON_BLUE; clusterId < SIMON_MAX_COLORS; clusterId++)
653 if (GameObject* cluster = me->FindNearestGameObject(clusterIds[clusterId], searchDistance))
654 cluster->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
655
656 if (clustersOnly)
657 return;
658
659 for (uint32 auraId = GO_AURA_BLUE; auraId <= GO_AURA_YELLOW; auraId++)
660 if (GameObject* auraGo = me->FindNearestGameObject(auraId, searchDistance))
661 auraGo->RemoveFromWorld();
662 }
663
664 /*
665 Called when AI is playing the sequence for player. We cast the visual spell and then remove the
666 cast color from the casting sequence.
667 */
669 {
670 PlayColor(*playableSequence.begin());
671 playableSequence.erase(playableSequence.begin());
672 }
673
674 // Casts a spell and plays a sound depending on parameter color.
675 void PlayColor(uint8 color)
676 {
677 switch (color)
678 {
679 case SIMON_BLUE:
682 break;
683 case SIMON_GREEN:
686 break;
687 case SIMON_RED:
690 break;
691 case SIMON_YELLOW:
694 break;
695 }
696 }
697
698 /*
699 Creates the transparent glowing auras on every cluster of this node.
700 After calling this function bunny is teleported to the center of the node.
701 */
703 {
704 for (uint32 clusterId = SIMON_BLUE; clusterId < SIMON_MAX_COLORS; clusterId++)
705 {
706 if (GameObject* cluster = me->FindNearestGameObject(clusterIds[clusterId], 2.0f*searchDistance))
707 {
708 cluster->SetFlag(GO_FLAG_NOT_SELECTABLE);
709
710 // break since we don't need glowing auras for large clusters
711 if (large)
712 break;
713
714 float x, y, z, o;
715 cluster->GetPosition(x, y, z, o);
716 me->NearTeleportTo(x, y, z, o);
717
718 uint32 preGameSpellId;
719 if (cluster->GetEntry() == clusterIds[SIMON_RED])
720 preGameSpellId = SPELL_PRE_GAME_RED;
721 else if (cluster->GetEntry() == clusterIds[SIMON_BLUE])
722 preGameSpellId = SPELL_PRE_GAME_BLUE;
723 else if (cluster->GetEntry() == clusterIds[SIMON_GREEN])
724 preGameSpellId = SPELL_PRE_GAME_GREEN;
725 else if (cluster->GetEntry() == clusterIds[SIMON_YELLOW])
726 preGameSpellId = SPELL_PRE_GAME_YELLOW;
727 else break;
728
729 me->CastSpell(cluster, preGameSpellId, true);
730 }
731 }
732
734 {
735 float x, y, z, o;
736 relic->GetPosition(x, y, z, o);
737 me->NearTeleportTo(x, y, z + zCoordCorrection, o);
738 }
739
741 }
742
743 // Handles the spell rewards. The spells also have the QuestCompleteEffect, so quests credits are working.
745 {
746 uint32 rewSpell = 0;
747 switch (level)
748 {
749 case 6:
750 if (large)
752 else
753 rewSpell = SPELL_REWARD_BUFF_1;
754 break;
755 case 8:
756 rewSpell = SPELL_REWARD_BUFF_2;
757 break;
758 case 10:
759 rewSpell = SPELL_REWARD_BUFF_3;
760 break;
761 }
762
763 if (rewSpell)
765 DoCast(player, rewSpell, true);
766 }
767
768 /*
769 Depending on the number of failed pushes for player the damage of the spell scales, so we first
770 cast the spell on the target that hits for 50 and shows the visual and then forces the player
771 to cast the damaging spell on it self with the modified basepoints.
772 4 fails = death.
773 On large nodes punishment and reward are the same, summoning the Apexis Guardian.
774 */
776 {
777 if (large)
778 {
781 guardian->AI()->AttackStart(player);
782
783 ResetNode();
784 }
785 else
786 {
787 fails++;
788
790 DoCast(player, SPELL_BAD_PRESS_TRIGGER, true);
791
792 if (fails >= 4)
793 ResetNode();
794 }
795 }
796
797 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
798 {
799 Unit* unitTarget = target->ToUnit();
800 if (!unitTarget)
801 return;
802
803 // Cast SPELL_BAD_PRESS_DAMAGE with scaled basepoints when the visual hits the target.
804 // Need Fix: When SPELL_BAD_PRESS_TRIGGER hits target it triggers spell SPELL_BAD_PRESS_DAMAGE by itself
805 // so player gets damage equal to calculated damage dbc basepoints for SPELL_BAD_PRESS_DAMAGE (~50)
806 if (spellInfo->Id == SPELL_BAD_PRESS_TRIGGER)
807 {
808 int32 bp = (int32)((float)(fails) * 0.33f * unitTarget->GetMaxHealth());
810 }
811 }
812
813 // Checks if player has already die or has get too far from the current node
815 {
817 {
818 if (player->isDead())
819 return false;
820 if (player->GetDistance2d(me) >= 2.0f*searchDistance)
821 {
823 return false;
824 }
825 }
826 else
827 return false;
828
829 return true;
830 }
831 };
832
833 CreatureAI* GetAI(Creature* creature) const override
834 {
835 return new npc_simon_bunnyAI(creature);
836 }
837};
838
840{
841 public:
842 go_simon_cluster() : GameObjectScript("go_simon_cluster") { }
843
845 {
847
848 bool OnGossipHello(Player* player) override
849 {
850 if (Creature* bunny = me->FindNearestCreature(NPC_SIMON_BUNNY, 12.0f, true))
851 bunny->AI()->SetData(me->GetEntry(), 0);
852
853 player->CastSpell(player, me->GetGOInfo()->goober.spell, true);
854 me->AddUse();
855 return true;
856 }
857 };
858
859 GameObjectAI* GetAI(GameObject* go) const override
860 {
861 return new go_simon_clusterAI(go);
862 }
863};
864
874
876{
877 public:
878 go_apexis_relic() : GameObjectScript("go_apexis_relic") { }
879
881 {
883
884 bool OnGossipHello(Player* player) override
885 {
887 player->SendPreparedGossip(me);
888 return true;
889 }
890
891 bool OnGossipSelect(Player* player, uint32 /*menuId*/, uint32 /*gossipListId*/) override
892 {
893 CloseGossipMenuFor(player);
894
895 bool large = (me->GetEntry() == GO_APEXIS_MONUMENT);
896 if (player->HasItemCount(ITEM_APEXIS_SHARD, large ? 35 : 1))
897 {
898 player->CastSpell(player, large ? SPELL_TAKE_REAGENTS_GROUP : SPELL_TAKE_REAGENTS_SOLO, false);
899
901 bunny->AI()->SetGUID(player->GetGUID(), large);
902 }
903
904 return true;
905 }
906 };
907
908 GameObjectAI* GetAI(GameObject* go) const override
909 {
910 return new go_apexis_relicAI(go);
911 }
912};
913
914/*######
915## npc_oscillating_frequency_scanner_master_bunny used for quest 10594 "Gauging the Resonant Frequency"
916######*/
917
925
927{
928public:
929 npc_oscillating_frequency_scanner_master_bunny() : CreatureScript("npc_oscillating_frequency_scanner_master_bunny") { }
930
932 {
934 {
935 timer = 500;
936 }
937
952
953 void IsSummonedBy(WorldObject* summoner) override
954 {
955 if (summoner->IsPlayer())
956 playerGuid = summoner->GetGUID();
957 }
958
959 void UpdateAI(uint32 diff) override
960 {
961 if (timer <= diff)
962 {
965
966 timer = 3000;
967 }
968 else
969 timer -= diff;
970 }
971
972 private:
975 };
976
977 CreatureAI* GetAI(Creature* creature) const override
978 {
980 }
981};
982
983// 37408 - Oscillation Field
985{
986 public:
987 spell_oscillating_field() : SpellScriptLoader("spell_oscillating_field") { }
988
990 {
991 void HandleEffect(SpellEffIndex /*effIndex*/)
992 {
993 if (Player* player = GetHitPlayer())
994 if (player->GetAuraCount(SPELL_OSCILLATION_FIELD) == 5 && player->GetQuestStatus(QUEST_GAUGING_THE_RESONANT_FREQUENCY) == QUEST_STATUS_INCOMPLETE)
995 player->CompleteQuest(QUEST_GAUGING_THE_RESONANT_FREQUENCY);
996 }
997
1002 };
1003
1004 SpellScript* GetSpellScript() const override
1005 {
1007 }
1008};
1009
1010/*######
1011## Quest 10556: Scratches
1012######*/
1013
1018
1019// 37028 - Dispelling Analysis
1037
1038/*######
1039## Quest 10544: A Curse Upon Both of Your Clans!
1040######*/
1041
1046
1047// 32580 - Wicked Strong Fetish
1061
1076
1078{
1080 {
1081 // Neccessary hack to allow spell 38629 to hit the keg credit (visibility is checked against the summoner, not the caster)
1083 }
1084};
1085
1087{
1089
1090 void IsSummonedBy(WorldObject* summoner) override
1091 {
1092 summoner->CastSpell(me, SPELL_CHARM_REXXARS_RODENT, true);
1093 }
1094};
1095
1096// 38544 - Coax Marmot
1098{
1099 void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
1100 {
1101 // prevent loading the aura from db
1102 if (GetTarget()->GetCharmedGUID().IsEmpty())
1103 Remove();
1104 }
1105
1106 void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
1107 {
1108 if (Creature* marmot = Object::ToCreature(GetTarget()->GetCharmed()))
1109 if (marmot->m_unitData->CreatedBySpell == SPELL_COAX_MARMOT)
1110 marmot->DespawnOrUnsummon();
1111 }
1112
1118};
1119
1120// 38586 - [DND]Charm Rexxar's Rodent
1122{
1123 void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
1124 {
1125 if (Unit* caster = GetCaster())
1126 caster->RemoveAurasDueToSpell(SPELL_COAX_MARMOT);
1127
1128 if (Creature* creature = GetTarget()->ToCreature())
1129 creature->DespawnOrUnsummon(1ms);
1130 }
1131
1136};
1137
1138// 38629 - Poison Keg
1140{
1141 bool Validate(SpellInfo const* /*spellEntry*/) override
1142 {
1143 return ValidateSpellInfo(
1144 {
1148 });
1149 }
1150
1152 {
1153 if (Player* player = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself())
1154 {
1155 uint32 spellId = 0;
1156 switch (GetHitUnit()->GetEntry())
1157 {
1160 break;
1163 break;
1166 break;
1167 default:
1168 return;
1169 }
1170
1171 player->CastSpell(nullptr, spellId, true);
1172 }
1173 }
1174
1179};
1180
1181/*######
1182## Quest 11010: Bombing Run / 11102: Bombing Run / 11023: Bomb Them Again!
1183######*/
1184
1194
1195// 40109 - Knockdown Fel Cannon: The Bolt
1197{
1198 bool Validate(SpellInfo const* /*spellInfo*/) override
1199 {
1201 }
1202
1203 void HandleDummy(SpellEffIndex /*effIndex*/)
1204 {
1206 }
1207
1212};
1213
1214// 40113 - Knockdown Fel Cannon: The Aggro Check Aura
1216{
1217 void HandleTriggerSpell(AuraEffect const* /*aurEff*/)
1218 {
1219 if (Unit* target = GetTarget())
1220 // On trigger proccing
1221 target->CastSpell(target, SPELL_AGGRO_CHECK);
1222 }
1223
1228};
1229
1230// 40112 - Knockdown Fel Cannon: The Aggro Check
1232{
1233 void HandleDummy(SpellEffIndex /*effIndex*/)
1234 {
1235 if (Player* playerTarget = GetHitPlayer())
1236 // Check if found player target is on fly mount or using flying form
1237 if (playerTarget->HasAuraType(SPELL_AURA_FLY) || playerTarget->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
1238 playerTarget->CastSpell(playerTarget, SPELL_FLAK_CANNON_TRIGGER, TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE);
1239 }
1240
1245};
1246
1247// 40119 - Knockdown Fel Cannon: The Aggro Burst
1249{
1250 void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
1251 {
1252 if (Unit* target = GetTarget())
1253 // On each tick cast Choose Loc to trigger summon
1254 target->CastSpell(target, SPELL_CHOOSE_LOC);
1255 }
1256
1261};
1262
1263// 40056 - Knockdown Fel Cannon: Choose Loc
1265{
1266 void HandleDummy(SpellEffIndex /*effIndex*/)
1267 {
1268 Unit* caster = GetCaster();
1269 // Check for player that is in 65 y range
1270 std::vector<Player*> playerList;
1271 caster->GetPlayerListInGrid(playerList, 65.0f);
1272 for (Player* player : playerList)
1273 // Check if found player target is on fly mount or using flying form
1274 if (player->HasAuraType(SPELL_AURA_FLY) || player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED))
1275 // Summom Fel Cannon (bunny version) at found player
1276 caster->SummonCreature(NPC_FEL_CANNON2, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
1277 }
1278
1283};
1284
1285// 39844 - Skyguard Blasting Charge
1286// 40160 - Throw Bomb
1288{
1290 {
1291 Unit* caster = GetCaster();
1292 // This spell will be cast only if caster has one of these auras
1295 return SPELL_CAST_OK;
1296 }
1297
1302};
1303
1313
1314// 40623 - Apexis Vibrations
1315// 40625 - Apexis Emanations
1316// 40626 - Apexis Enlightenment
1352
1353/*######
1354## Quest 10525: Vision Guide
1355######*/
1356
1358{
1359 SPELL_VISION_GUIDE = 36573
1361
1362// 36587 - Vision Guide
1364{
1365 bool Validate(SpellInfo const* /*spellInfo*/) override
1366 {
1368 }
1369
1370 void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
1371 {
1373 }
1374
1379};
1380
1381/*######
1382## Quest 10714: On Spirit's Wings
1383######*/
1384
1389
1390// 38173 - Summon Spirit
1392{
1393 bool Validate(SpellInfo const* /*spellInfo*/) override
1394 {
1396 }
1397
1398 void HandleDummy(SpellEffIndex /*effIndex*/)
1399 {
1400 // This spell script requires sniff verification
1402 }
1403
1408};
1409
First const & RAND(First const &first, Second const &second, Rest const &... rest)
T GetEntry(std::unordered_map< uint32, T > const &map, CriteriaTreeEntry const *tree)
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
@ POINT_MOTION_TYPE
@ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
@ TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
@ TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN
@ QUEST_STATUS_INCOMPLETE
Definition QuestDef.h:146
uint32 rand32()
Definition Random.cpp:71
#define RegisterCreatureAI(ai_name)
Definition ScriptMgr.h:1392
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
Creature * GetClosestCreatureWithEntry(WorldObject *source, uint32 entry, float maxSearchRange, bool alive=true)
void CloseGossipMenuFor(Player *player)
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_APPLY_AURA
@ INVISIBILITY_UNK4
@ POWER_MANA
SpellCastResult
@ SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW
@ SPELL_CAST_OK
@ GO_FLAG_NOT_SELECTABLE
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_MOD_INVISIBILITY
@ SPELL_AURA_DUMMY
@ SPELL_AURA_FLY
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_PERIODIC_DUMMY
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
#define SpellCheckCastFn(F)
#define SpellEffectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
#define AuraEffectApplyFn(F, I, N, M)
#define AuraEffectRemoveFn(F, I, N, M)
@ UNIT_FLAG_NON_ATTACKABLE
HookList< EffectApplyHandler > AfterEffectRemove
HookList< EffectPeriodicHandler > OnEffectPeriodic
HookList< EffectApplyHandler > AfterEffectApply
Unit * GetCaster() const
Unit * GetTarget() const
uint32 GetId() const
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
bool IsPlayer() const
Definition BaseEntity.h:173
virtual void MoveInLineOfSight(Unit *)
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
void SetObjectScale(float scale) override
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
bool UpdateEntry(uint32 entry, CreatureData const *data=nullptr, bool updateLevel=true)
Definition Creature.cpp:591
void Update(uint32 time)
Definition EventMap.h:77
EventId ExecuteEvent()
Definition EventMap.cpp:77
void CancelEvent(EventId eventId)
Definition EventMap.cpp:156
void CancelEventGroup(GroupIndex group)
Definition EventMap.cpp:178
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:40
void Reset()
Definition EventMap.cpp:25
void AddFlag(FLAG_TYPE flag)
Definition Object.h:209
GameObject *const me
GameObjectTemplate const * GetGOInfo() const
Definition GameObject.h:209
void AddUse()
Definition GameObject.h:330
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={}, Optional< MovementFadeObject > fadeObject={}, Scripting::v2::ActionResultSetter< MovementStopReason > &&scriptResult={})
Player * ToPlayer()
Definition Object.h:126
GameObject * ToGameObject()
Definition Object.h:131
uint32 GetEntry() const
Definition Object.h:89
Creature * ToCreature()
Definition Object.h:121
Unit * ToUnit()
Definition Object.h:116
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition Player.cpp:9824
void SendPreparedGossip(WorldObject *source)
Definition Player.cpp:13985
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15929
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition Player.cpp:13884
uint32 const Id
Definition SpellInfo.h:328
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
HookList< CheckCastHandler > OnCheckCast
Player * GetHitPlayer() const
Unit * GetCaster() const
HookList< EffectHandler > OnEffectHit
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:172
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:81
Definition Unit.h:647
MotionMaster * GetMotionMaster()
Definition Unit.h:1750
Powers GetPowerType() const
Definition Unit.h:823
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:860
void SetUninteractible(bool apply)
Definition Unit.cpp:8583
uint64 GetMaxHealth() const
Definition Unit.h:801
bool SetCanFly(bool enable)
Definition Unit.cpp:13538
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4832
Unit * GetVictim() const
Definition Unit.h:738
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:13054
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:861
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3992
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:862
void GetPlayerListInGrid(Container &playerContainer, float maxSearchRange, bool alive=true) const
Definition Object.cpp:2683
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:1544
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
FlaggedValuesArray32< int32, uint64, InvisibilityType, TOTAL_INVISIBILITY_TYPES > m_invisibilityDetect
Definition Object.h:404
GameObject * SummonGameObject(uint32 entry, Position const &pos, QuaternionData const &rot, Seconds respawnTime, GOSummonType summonType=GO_SUMMON_TIMED_OR_CORPSE_DESPAWN)
Definition Object.cpp:1446
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1522
GameObjectAI * GetAI(GameObject *go) const override
GameObjectAI * GetAI(GameObject *go) const override
GameObjectAI * GetAI(GameObject *go) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
void HandleEffectPeriodic(AuraEffect const *)
void HandleTriggerSpell(AuraEffect const *)
void AfterRemove(AuraEffect const *, AuraEffectHandleModes)
bool Validate(SpellInfo const *) override
void OnRemove(AuraEffect const *, AuraEffectHandleModes)
void HandleEffectRemove(AuraEffect const *, AuraEffectHandleModes)
void HandleEffectApply(AuraEffect const *, AuraEffectHandleModes)
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void AfterApply(AuraEffect const *, AuraEffectHandleModes)
bool Validate(SpellInfo const *) override
SpellScript * GetSpellScript() const override
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
CastSpellExtraArgs & AddSpellBP0(SpellEffectValue val)
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:160
struct GameObjectTemplate::@199::@211 goober
struct GameObjectTemplate::@199::@203 questgiver
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
static QuaternionData fromOrientation(float orientation)
void AttackStart(Unit *) override
== Triggered Actions Requested ==================
ScriptedAI(Creature *creature, uint32 scriptId=0) noexcept
void DoPlaySoundToSet(WorldObject *source, uint32 soundId)
bool OnGossipSelect(Player *player, uint32, uint32) override
void SpellHit(WorldObject *caster, SpellInfo const *spellInfo) override
void MovementInform(uint32 type, uint32 id) override
void IsSummonedBy(WorldObject *summoner) override
void SetData(uint32 type, uint32) override
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void SetGUID(ObjectGuid const &guid, int32 id) override
@ SPELL_SWIFTNESS_APEXIS_EMANATIONS
@ SPELL_SWIFTNESS_APEXIS_VIBRATIONS
@ SPELL_SWIFTNESS_APEXIS_ENLIGHTENMENT
void AddSC_blades_edge_mountains()
@ EVENT_SIMON_PERIODIC_PLAYER_CHECK
@ ACTION_SIMON_CORRECT_FULL_SEQUENCE
@ GO_BLUE_CLUSTER_DISPLAY_LARGE
@ GO_GREEN_CLUSTER_DISPLAY_LARGE
@ SPELL_VISUAL_START_PLAYER_LEVEL
@ GO_YELLOW_CLUSTER_DISPLAY_LARGE
@ SPELL_FERMENTED_SEED_BEER_CREDIT
@ NPC_FERMENTED_SEED_BEER_KEG_CREDIT
@ NPC_OSCILLATING_FREQUENCY_SCANNER_TOP_BUNNY
@ GO_OSCILLATING_FREQUENCY_SCANNER
@ QUEST_GAUGING_THE_RESONANT_FREQUENCY