TrinityCore
Loading...
Searching...
No Matches
npc_arthas.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
19#include "Containers.h"
20#include "GameObject.h"
21#include "InstanceScript.h"
22#include "Log.h"
23#include "Map.h"
24#include "MotionMaster.h"
25#include "MoveSplineInit.h"
26#include "ObjectAccessor.h"
27#include "PassiveAI.h"
28#include "Player.h"
29#include "Random.h"
30#include "ScriptedCreature.h"
31#include "ScriptedGossip.h"
32#include "ScriptMgr.h"
33#include "ScriptSystem.h"
34#include "SpellScript.h"
36#include "TemporarySummon.h"
37#include <array>
38#include <unordered_map>
39#include <vector>
40
76
78{
79 // RP1: Arthas/Jaina/Uther, outside Stratholme gates
80 RP1_CHAIN_ARTHAS1 = 1, // Initial movement
81 RP1_CHAIN_UTHER1 = 1, // Initial movement
82 RP1_CHAIN_JAINA1 = 1, // Initial movement
83 RP1_CHAIN_ARTHAS2 = 2, // Arthas moves up the hill to look out over Stratholme
84 RP1_CHAIN_UTHER2 = 2, // Uther follows
85 RP1_CHAIN_JAINA2 = 2, // Jaina follows
86 RP1_CHAIN_UTHER3 = 3, // Uther leaves
87 RP1_CHAIN_JAINA3 = 3, // Jaina turns to leave, but is stopped by Arthas
88 RP1_CHAIN_JAINA4 = 4, // Jaina leaves for real
89 RP1_CHAIN_ARTHAS3 = 3, // Arthas moves down the hill to the bridge
90 RP1_CHAIN_ARTHAS4 = 4, // Arthas moves to the Stratholme entrance
91
92 // RP2: Arthas/Mal'ganis, at Stratholme gates
93 RP2_CHAIN_ARTHAS1 = 5, // Arthas enters Stratholme proper
94 RP2_CHAIN_CITIZEN1 = 1, // A Stratholme citizen greets Arthas
95 RP2_CHAIN_ARTHAS2 = 6, // Arthas advances towards the approaching citizen
96 RP2_CHAIN_ARTHAS3 = 7, // Arthas moves on to a nearby resident
97
98 // RP3: Arthas/Infinites, in Stratholme Town Hall
99 RP3_CHAIN_ARTHAS1 = 91, // Arthas enters Stratholme Town Hall
100 RP3_CHAIN_ARTHAS2 = 92, // Arthas approaches one of the disguised Infinites
101 RP3_CHAIN_ARTHAS3 = 95, // Arthas proceeds up the stairs
102 RP3_CHAIN_ARTHAS3_2 = 96, // Arthas encounters more Infinite resistance
103 RP3_CHAIN_ARTHAS4 = 97, // Arthas presses onward into a hallway
104 RP3_CHAIN_ARTHAS5 = 98, // Arthas advances into the boss room
105 RP3_CHAIN_EPOCH = 1, // Chrono-Lord Epoch advances out of the portal
106
107 // Spawn motions (all on 27742, infinite adversary)
120
121 // RP4: Arthas moving towards Gauntlet
122 RP4_CHAIN_ARTHAS1 = 101, // Arthas moves up to the bookcase
123 RP4_CHAIN_ARTHAS2 = 128, // Arthas advances to the start of the Gauntlet section
124 RP4_CHAIN_GAUNTLET1 = 1024, // Arthas charges to the halfway point of the Gauntlet
125 RP4_CHAIN_GAUNTLET2 = 1025, // Arthas continues to Market Row
126
127 // RP5: Arthas advances on Crusader Square and faces off against Mal'ganis
128 RP5_CHAIN_ARTHAS1 = 121, // Arthas moves into Crusader Square
129 RP5_CHAIN_ARTHAS2 = 124, // After Mal'ganis' defeat, Arthas attempts to chase him down
130 RP5_CHAIN_ARTHAS3 = 125, // Arthas departs...
131 RP5_CHAIN_ARTHAS4 = 127 // ...and then finally despawns
133
165
176
181
183{
214
243
245
284
289
297
313
315{
316 RP1_LINE_ARTHAS1 = 0, // Glad you could make it, Uther.
317 RP1_LINE_UTHER1 = 0, // Watch your tone with me, boy. You may be the prince, but I'm still your superior as a paladin!
318 RP1_LINE_ARTHAS2 = 1, // As if I could forget. Listen, Uther, there's something about the plague you should know...
319 RP1_LINE_ARTHAS3 = 2, // Oh, no. We're too late. These people have all been infected! They may look fine now, but it's just a matter of time before they turn into the undead!
320 RP1_LINE_UTHER2 = 1, // What?
321 RP1_LINE_ARTHAS4 = 3, // This entire city must be purged.
322 RP1_LINE_UTHER3 = 2, // How can you even consider that? There's got to be some other way.
323 RP1_LINE_ARTHAS5 = 4, // Damn it, Uther! As your future king, I order you to purge this city!
324 RP1_LINE_UTHER4 = 3, // You are not my king yet, boy! Nor would I obey that command even if you were!
325 RP1_LINE_ARTHAS6 = 5, // Then I must consider this an act of treason.
326 RP1_LINE_UTHER5 = 4, // Treason? Have you lost your mind, Arthas?
327 RP1_LINE_ARTHAS7 = 6, // Have I? Lord Uther, by my right of succession and the sovereignty of my crown, I hereby relieve you of your command and suspend your paladins from service.
328 RP1_LINE_JAINA1 = 0, // Arthas! You can't just--
329 RP1_LINE_ARTHAS8 = 7, // It's done! Those of you who have the will to save this land, follow me! The rest of you... get out of my sight!
330 RP1_LINE_UTHER6 = 5, // You've just crossed a terrible threshold, Arthas.
331 RP1_LINE_ARTHAS9 = 8, // Jaina?
332 RP1_LINE_JAINA2 = 1, // I'm sorry, Arthas. I can't watch you do this.
333 RP1_LINE_ARTHAS10 = 9, // Take position here, and I will lead a small force inside Stratholme to begin the culling. We must contain and purge the infected for the sake of all of Lordaeron!
334 RP1_LINE_ARTHAS11 = 40 // All officers should check in with me when their squads are ready. We'll enter Stratholme on my order.
336
338{
339 RP2_LINE_ARTHAS1 = 10, // Everyone looks ready. Remember, these people are all infected with the plague and will die soon. We must purge Stratholme to protect the remainder of Lordaeron from the Scourge. Let's go.
340 RP2_LINE_CITIZEN1 = 0, // Prince Arthas, may the light be praised! Many people in the town have begun to fall seriously ill, can you help us?
341 RP2_LINE_ARTHAS2 = 11, // I can only help you with a clean death.
342 RP2_LINE_CITIZEN2 = 1, // What? This can't be!
343 RP2_LINE_RESIDENT1 = 0, // Oh, no...
344 RP2_LINE_ARTHAS3 = 12, // That was just the beginning.
345 RP2_LINE_MALGANIS1 = 0, // Yes, this is the beginning. I've been waiting for you, young prince. I am Mal'Ganis.
346 RP2_LINE_MALGANIS2 = 1, // As you can see, your people are now mine. I will now turn this city household by household, until the flame of life has been snuffed out... forever.
347 RP2_LINE_ARTHAS4 = 13, // I won't allow it, Mal'Ganis! Better that these people die by my hand than serve as your slaves in death!
348 RP2_LINE_ARTHAS5 = 14 // Mal'Ganis will send out some of his Scourge minions to interfere with us. Those of you with the strongest steel and magic shall go forth and destroy them. I will lead the rest of my forces in purging Stratholme of the infected.
350
352{
353 RP3_LINE_ARTHAS1 = 16, // Follow me, I know the way through.
354 RP3_LINE_CITIZEN1 = 0, // Ah, you've finally arrived Prince Arthas. You're here just in the nick of time.
355 RP3_LINE_ARTHAS2 = 17, // Yes, I'm glad I could get to you before the plague.
356 RP3_LINE_ARTHAS3 = 18, // What is this sorcery?
357 RP3_LINE_CITIZEN2 = 1, // There's no need for you to understand, Arthas. All you need to do is die.
358 RP3_LINE_ARTHAS4 = 19, // Mal'Ganis appears to have more than Scourge in his arsenal. We should make haste.
359
360 RP3_LINE_ARTHAS10 = 20, // More vile sorcery! Be ready for anything!
361 RP3_LINE_ARTHAS11 = 21, // Let's move on.
362
363 RP3_LINE_ARTHAS20 = 22, // Watch your backs: they have us surrounded in this hall.
364 RP3_LINE_ARTHAS21 = 24, // Mal'ganis is not making this easy.
365
366 RP3_LINE_ARTHAS30 = 25, // They're very persistent.
367 RP3_LINE_ARTHAS31 = 26, // What else can he put in my way?
368 RP3_LINE_EPOCH1 = 0, // Prince Arthas Menethil, on this day, a powerful darkness has taken hold of your soul. The death you are destined to visit upon others will this day be your own.
369 RP3_LINE_ARTHAS32 = 27, // I do what I must for Lordaeron, and neither your words nor your actions will stop me.
370 RP3_LINE_EPOCH2 = 1 // We'll see about that, young prince.
372
374{
375 RP4_LINE_ARTHAS1 = 28, // The quickest path to Mal'Ganis lies behind that bookshelf ahead.
376 RP4_LINE_ARTHAS2 = 29, // This will only take a moment.
377 RP4_LINE_ARTHAS3 = 30, // I'm relieved this secret passage still works.
378
379 RP4_LINE_ARTHAS10 = 31, // Let's move through here as quickly as possible. If the undead don't kill us, the fires might.
380 RP4_LINE_ARTHAS11 = 32, // Rest a moment and clear your lungs, but we must move again soon.
381 RP4_LINE_ARTHAS12 = 33, // That's enough; we must move again. Mal'Ganis awaits.
382 RP4_LINE_ARTHAS13 = 34 // At last some good luck. Market Row has not caught fire yet. Mal'Ganis is supposed to be in Crusaders' Square, which is just ahead. Tell me when you're ready to move forward.
384
386{
387 RP5_LINE_ARTHAS1 = 35, // Justice will be done.
388 RP5_LINE_ARTHAS2 = 36, // We're going to finish this right now, Mal'Ganis. Just you... and me.
389 RP5_LINE_MALGANIS1 = 2, // This will be a fine test, Prince Arthas.
390 RP5_LINE_MALGANIS12 = 10, // Your journey has just begun, young prince. Gather your forces and meet me in the arctic land of Northrend. It is there that we shall settle the score between us. It is there that your true destiny will unfold.
391 RP5_LINE_ARTHAS10 = 37, // I'll hunt you to the ends of the earth if I have to! Do you hear me? To the ends of the earth!
392 RP5_LINE_ARTHAS11 = 38, // You performed well this day. Anything that Mal'Ganis has left behind is yours. Take it as your reward. I must now begin plans for an expedition to Northrend.
393 RP5_LINE_CHROMIE0 = 0 // Why, hello again!
395
447
453
454// @todo sniff
455// All kinds of positions Arthas needs for RP events (there are a lot of these)
456static std::array<Position, NUM_POSITIONS> const ArthasPositions =
457{
458 {
459 { 1983.857f, 1287.043f, 145.5596f, 3.0892330f }, // RP1_ARTHAS_INITIAL
460 { 1783.843f, 1267.481f, 139.7800f, 0.2698664f }, // RP1_UTHER_SPAWN
461 { 1876.788f, 1305.723f, 146.2474f, 6.0737460f }, // RP1_JAINA_SPAWN
462
463 { 2047.948f, 1287.598f, 142.8568f, 3.176499f }, // ARTHAS_PURGE_PENDING_POS
464 { 2091.994f, 1277.257f, 140.4707f, 1.134464f }, // ARTHAS_WAVES_POS // @todo
465 { 2074.624f, 1282.958f, 141.6344f }, // RP2_PRIEST1_POS
466 { 2074.805f, 1292.172f, 141.6728f }, // RP2_PRIEST2_POS
467 { 2077.590f, 1284.609f, 141.5710f }, // RP2_FOOT1_POS
468 { 2078.365f, 1281.254f, 141.5182f }, // RP2_FOOT2_POS
469 { 2077.737f, 1290.441f, 141.5698f }, // RP2_FOOT3_POS
470 { 2078.055f, 1293.624f, 141.5544f }, // RP2_FOOT4_POS
471 { 2113.454f, 1287.986f, 136.3829f, 3.071779f }, // RP2_MALGANIS_POS
472
473 { 2366.240f, 1195.253f, 132.0441f, 3.159046f }, // ARTHAS_TOWN_HALL_POS
474 { 2433.154f, 1192.572f, 148.1547f, 5.542059f }, // RP3_SPAWN1_LOC1
475 { 2432.990f, 1192.760f, 148.1474f, 1.026526f }, // RP3_SPAWN1_LOC2
476 { 2432.824f, 1191.816f, 148.1556f, 4.927707f }, // RP3_SPAWN1_LOC3
477 { 2432.711f, 1192.857f, 148.1550f, 6.257423f }, // RP3_SPAWN1_LOC4
478 { 2433.357f, 1192.168f, 148.1593f, 3.001966f }, // RP3_SPAWN1_RIFT_SPAWN
479 { 2414.349f, 1136.075f, 148.1592f, 1.345922f }, // RP3_SPAWN2_LOC1
480 { 2403.961f, 1180.299f, 148.1587f, 5.139339f }, // RP3_SPAWN2_LOC2
481 { 2414.671f, 1136.262f, 148.1592f, 2.305776f }, // RP3_SPAWN2_LOC3
482 { 2403.908f, 1179.994f, 148.1586f, 4.654133f }, // RP3_SPAWN2_LOC4
483 { 2404.311f, 1178.306f, 148.1585f, 1.605703f }, // RP3_SPAWN2_RIFT1
484 { 2414.041f, 1136.068f, 148.1593f, 2.234021f }, // RP3_SPAWN2_RIFT2
485 { 2429.026f, 1102.693f, 148.1499f, 1.952652f }, // RP3_SPAWN3_LOC1
486 { 2441.173f, 1115.225f, 148.1264f, 2.302970f }, // RP3_SPAWN3_LOC2
487 { 2430.645f, 1104.685f, 148.1306f, 1.135255f }, // RP3_SPAWN3_LOC3
488 { 2439.649f, 1113.719f, 148.1298f, 3.111888f }, // RP3_SPAWN3_LOC4
489 { 2429.296f, 1102.007f, 148.1593f, 6.213372f }, // RP3_SPAWN3_RIFT1
490 { 2440.057f, 1114.226f, 148.1593f, 6.108652f }, // RP3_SPAWN3_RIFT2
491 { 2457.008f, 1113.929f, 150.0776f, 3.272437f }, // RP3_EPOCH_SPAWN
492 { 2456.058f, 1113.838f, 150.0917f, 1.745329f }, // RP3_EPOCH_RIFT
493 { 2425.898f, 1118.842f, 148.0759f, 6.073746f }, // ARTHAS_TOWN_HALL_END_POS
494
495 { 2534.988f, 1126.163f, 130.8621f, 2.844887f }, // ARTHAS_GAUNTLET_POS
496 { 2363.440f, 1404.906f, 128.7869f, 2.775074f }, // ARTHAS_GAUNTLET_END_POS
497
498 { 2296.862f, 1501.015f, 128.4456f, 5.131268f }, // RP5_MALGANIS_POS
499 { 2301.055f, 1478.977f, 128.1299f, 1.758816f }, // ARTHAS_FINAL_POS
500 { 2319.560f, 1506.408f, 152.0474f }, // RP5_CHROMIE_SPAWN
501 }
502};
503
506{
507 { 2320.632f, 1507.193f, 152.5081f },
508 { 2319.823f, 1506.605f, 152.5081f },
509 { 2306.770f, 1496.780f, 128.3620f }
510};
511
512static float const ArthasSnapbackDistanceThreshold = 5.0f; // how far we can be from where we're supposed at start of phase to be before we snap back
513
515{
517 bool const HasGossip;
519};
520
521// Positions Arthas should be at when starting a given phase
522static std::unordered_map<uint32, SnapbackInfo> const ArthasSnapbackPositions =
523{
541};
542
544{
545public:
546 npc_arthas_stratholme() : CreatureScript("npc_arthas_stratholme") { }
547
549 {
550 npc_arthas_stratholmeAI(Creature* creature) : ScriptedAI(creature), instance(creature->GetInstanceScript()), _exorcismCooldown(urandms(7, 14)), _progressRP(true), _afterCombat(ACTION_NONE) { }
551
556
558 {
559 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::AdvanceToState: advancing to 0x{:X}", newState);
560 if (!_progressRP)
561 {
562 TC_LOG_WARN("scripts.cos", "npc_arthas_stratholmeAI::AdvanceToState: advancing to instance state 0x{:X}, but RP is paused. Overriding!", newState);
563 _progressRP = true;
564 }
565
566 auto itr = ArthasSnapbackPositions.find(newState);
567 if (itr != ArthasSnapbackPositions.end())
568 {
569 SnapbackInfo const& target = itr->second;
570
571 // Adjust react state and npc flags based on current state
572 me->SetReactState(target.ReactState);
573 if (target.ReactState == REACT_PASSIVE)
574 me->SetImmuneToAll(true, false);
575 else
576 me->SetImmuneToAll(false);
577
578 // Adjust gossip flag based on whether we have a gossip menu or not
579 if (target.HasGossip)
581 else
583
584 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::AdvanceToState: has snapback for this state, distance = {}", target.SnapbackPosition->GetExactDist(me));
585 // Snapback handling - if we're too far from where we're supposed to be, teleport there
588 }
589
590 switch (newState)
591 {
592 case WAVES_DONE:
594 break;
595 case UTHER_TALK:
597 {
598 uther->setActive(true);
599 uther->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_UTHER1, RP1_CHAIN_UTHER1, false);
600 }
602 {
603 jaina->setActive(true);
604 jaina->GetMotionMaster()->MoveAlongSplineChain(0, RP1_CHAIN_JAINA1, true);
605 }
607 break;
610 break;
611 case COMPLETE:
612 if (events.Empty())
613 {
614 // This must be instance loading into COMPLETE state, spawn chromie
618 me->SetVisible(false);
619 }
620 break;
621 default:
622 break;
623 }
624 }
625
626 // Will happen immediately (if OOC) or on reached home (if IC)
628 {
629 if (_progressRP)
630 DoAction(action);
631 else
632 _afterCombat = action;
633 }
634
673
674 void SetGUID(ObjectGuid const& guid, int32 type) override
675 {
676 _eventStarterGuid = guid;
677
679 switch (type)
680 {
682 Talk(RP2_LINE_ARTHAS1, talkTarget);
684 break;
686 Talk(RP3_LINE_ARTHAS1, talkTarget);
688 break;
690 Talk(RP4_LINE_ARTHAS1, talkTarget);
692 break;
694 Talk(RP4_LINE_ARTHAS10, talkTarget);
696 break;
698 Talk(RP5_LINE_ARTHAS1, talkTarget);
701 break;
702 default:
703 break;
704 }
705 }
706
707 void MovementInform(uint32 type, uint32 id) override
708 {
709 if (!_progressRP)
710 return;
711 if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE && type != SPLINE_CHAIN_MOTION_TYPE)
712 return;
713 switch (id)
714 {
721 break;
724 break;
727 break;
749 break;
751 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 500.0f, true))
752 uther->DespawnOrUnsummon();
753 break;
755 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 500.0f, true))
756 jaina->DespawnOrUnsummon();
757 break;
761 break;
764 break;
766 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN, 100.0f, true))
767 citizen->SetFacingToObject(me);
768 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT, 100.0f, true))
769 resident->SetFacingToObject(me);
773 break;
778 break;
801 break;
803 {
804 std::list<Creature*> infinites;
806 for (Creature* infinite : infinites)
807 infinite->SetFacingToObject(me);
812 break;
813 }
823 break;
829 break;
836 break;
842 break;
845 events.ScheduleEvent(RP4_EVENT_HIDDEN_PASSAGE, 4s); // @todo sniff timer
847 break;
850 break;
856 break;
860 break;
864 break;
867 break;
870 break;
871 default:
872 break;
873 }
874 }
875
876 bool CanAIAttack(Unit const* who) const override
877 {
879 {
880 Position const& relativePos = me->IsEngaged() ? me->GetHomePosition() : me->GetPosition();
881 // Don't let us chase too far from home
882 if (relativePos.GetExactDist2d(who) > 30.0f)
883 return false;
884 }
885 return ScriptedAI::CanAIAttack(who);
886 }
887
889 {
891 return;
892
893 if (!UpdateVictim())
894 return;
895
896 if (HealthBelowPct(40))
898 if (_exorcismCooldown <= diff)
899 {
902 else if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
903 {
904 DoCast(target, SPELL_EXORCISM);
905 _exorcismCooldown = urandms(7, 14);
906 }
907 }
908 else
909 _exorcismCooldown -= diff;
910
912 }
913
914 void UpdateAI(uint32 diff) override
915 {
916 if (me->IsEngaged())
917 {
918 UpdateAICombat(diff);
919 return;
920 }
921
922 // EventMap is only used for RP handling. RP events are paused while in combat or leashing back to resume pos
923 if (!_progressRP)
924 return;
925
926 events.Update(diff);
927 while (uint32 event = events.ExecuteEvent())
928 {
929 uint32 talkerEntry = UINT_MAX, talkerLine = 0;
930 switch (event)
931 {
932 case RP1_EVENT_START1:
933 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
934 jaina->SetFacingToObject(me);
935 break;
936 case RP1_EVENT_START2:
937 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
938 {
939 uther->SetFacingToObject(me);
940 me->SetFacingToObject(uther);
941 }
942 break;
944 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS1;
945 break;
946 case RP1_EVENT_UTHER1:
947 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER1;
948 break;
950 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS2;
952 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
953 uther->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_UTHER2, RP1_CHAIN_UTHER2, true);
954 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
955 jaina->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_JAINA2, RP1_CHAIN_JAINA2, true);
956 break;
958 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
959 uther->SetFacingToObject(me);
960 break;
962 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
963 jaina->SetFacingToObject(me);
964 break;
966 {
967 me->SetFacingTo(6.248279f); // @todo migrate
968 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS3;
969 std::list<Creature*> troops;
974 for (Creature* unit : troops)
975 if (unit->IsAlive())
976 unit->SetFacingToObject(me);
977 break;
978 }
979 case RP1_EVENT_UTHER2:
980 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER2;
981 break;
983 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS4;
984 break;
985 case RP1_EVENT_UTHER3:
986 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER3;
987 break;
989 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
990 me->SetFacingToObject(uther);
991 break;
993 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS5;
994 break;
995 case RP1_EVENT_UTHER4:
996 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER4;
997 break;
999 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS6;
1000 break;
1001 case RP1_EVENT_UTHER5:
1002 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER5;
1003 break;
1004 case RP1_EVENT_ARTHAS7:
1005 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS7;
1006 break;
1007 case RP1_EVENT_JAINA1:
1008 talkerEntry = NPC_JAINA, talkerLine = RP1_LINE_JAINA1;
1009 break;
1010 case RP1_EVENT_ARTHAS8:
1011 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS8;
1012 break;
1015 break;
1016 case RP1_EVENT_UTHER6:
1017 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER6;
1018 break;
1020 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
1021 uther->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_UTHER3, RP1_CHAIN_UTHER3, true);
1022 break;
1024 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
1025 jaina->GetMotionMaster()->MoveAlongSplineChain(0, RP1_CHAIN_JAINA3, true);
1026 break;
1027 case RP1_EVENT_ARTHAS9:
1028 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS9;
1029 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
1030 me->SetFacingToObject(jaina);
1031 break;
1032 case RP1_EVENT_JAINA2:
1033 talkerEntry = NPC_JAINA, talkerLine = RP1_LINE_JAINA2;
1034 break;
1036 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
1037 jaina->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_JAINA4, RP1_CHAIN_JAINA4, true);
1038 break;
1041 break;
1042 case RP1_EVENT_ARTHAS10:
1043 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS10;
1044 me->SetFacingTo(3.141593f); // @todo migrate
1045 break;
1048 break;
1049 case RP1_EVENT_FINISHED:
1050 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS11;
1053 break;
1056 break;
1057 case RP2_EVENT_CITIZEN1:
1058 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN, 100.0f, true))
1059 {
1060 citizen->GetMotionMaster()->MoveAlongSplineChain(0, RP2_CHAIN_CITIZEN1, true);
1062 }
1063 break;
1064 case RP2_EVENT_ARTHAS2:
1065 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS2;
1066 break;
1069 break;
1070 case RP2_EVENT_CITIZEN2:
1071 talkerEntry = NPC_CITIZEN, talkerLine = RP2_LINE_CITIZEN2;
1072 break;
1073 case RP2_EVENT_KILL1:
1074 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN, 100.0f, true))
1076 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT, 100.0f, true))
1077 {
1078 resident->SetEmoteState(EMOTE_STATE_COWER);
1080 }
1081 break;
1084 break;
1085 case RP2_EVENT_KILL2:
1086 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT, 100.0f, true))
1088 break;
1089 case RP2_EVENT_REACT1:
1090 case RP2_EVENT_REACT2:
1091 case RP2_EVENT_REACT3:
1092 case RP2_EVENT_REACT4:
1093 case RP2_EVENT_REACT5:
1094 {
1095 std::list<Creature*> nearbyVictims;
1096 me->GetCreatureListWithEntryInGrid(nearbyVictims, urand(0, 1) ? NPC_CITIZEN : NPC_RESIDENT, 60.0f);
1097 if (!nearbyVictims.empty())
1098 {
1099 Emote emotes[] =
1100 {
1105 };
1106
1108 if (victim->IsAlive())
1110 }
1111 break;
1112 }
1114 me->SetFacingTo(2.234021f); // @todo
1115 break;
1116 case RP2_EVENT_ARTHAS3:
1117 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS3;
1118 break;
1120 if (Creature* bunny = me->FindNearestCreature(NPC_MALGANIS_BUNNY, 80.0f, true))
1121 bunny->CastSpell(bunny, SPELL_SHADOWSTEP_VISUAL);
1122
1124 {
1125 malganis->CastSpell(malganis, SPELL_SHADOWSTEP_VISUAL);
1126 malganis->AI()->Talk(RP2_LINE_MALGANIS1);
1127 }
1128 break;
1130 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1131 {
1132 std::list<Creature*> troops;
1135 for (Creature* unit : troops)
1136 if (unit->IsAlive())
1137 unit->SetFacingToObject(malganis);
1138 }
1139 break;
1141 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1142 me->SetFacingToObject(malganis);
1143 break;
1145 talkerEntry = NPC_MALGANIS, talkerLine = RP2_LINE_MALGANIS2;
1146 break;
1148 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1149 malganis->CastSpell(malganis, SPELL_SHADOWSTEP_VISUAL);
1150 break;
1152 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1153 malganis->DespawnOrUnsummon();
1154 if (Creature* bunny = me->FindNearestCreature(NPC_MALGANIS_BUNNY, 80.0f, true))
1155 bunny->CastSpell(bunny, SPELL_SHADOWSTEP_VISUAL);
1156 break;
1157 case RP2_EVENT_ARTHAS4:
1158 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS4;
1159 break;
1162 break;
1163 case RP2_EVENT_ARTHAS5:
1164 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS5;
1165 break;
1169 break;
1172 break;
1176 break;
1178 if (Creature* infinite = me->FindNearestCreature(NPC_RESIDENT_INFINITE, 100.0f, true))
1179 infinite->SetFacingToObject(me);
1180 break;
1182 me->SetFacingTo(0.541052f); // @todo
1183 break;
1184 case RP3_EVENT_CITIZEN1:
1185 talkerEntry = NPC_CITIZEN_INFINITE, talkerLine = RP3_LINE_CITIZEN1;
1186 break;
1187 case RP3_EVENT_ARTHAS2:
1188 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS2;
1190 break;
1192 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN_INFINITE, 100.0f, true))
1193 DoCast(citizen, SPELL_CRUSADER_STRIKE);
1194 break;
1196 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN_INFINITE, 100.0f, true))
1197 citizen->HandleEmoteCommand(EMOTE_ONESHOT_LAUGH);
1198 break;
1199 case RP3_EVENT_ARTHAS3:
1200 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS3;
1201 break;
1202 case RP3_EVENT_CITIZEN2:
1203 talkerEntry = NPC_CITIZEN_INFINITE, talkerLine = RP3_LINE_CITIZEN2;
1204 break;
1207 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN_INFINITE, 100.0f, true))
1208 {
1209 citizen->CastSpell(citizen, SPELL_TRANSFORM_VISUAL);
1210 citizen->UpdateEntry(NPC_INFINITE_HUNTER);
1211 }
1212 break;
1214 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT_INFINITE, 100.0f, true))
1215 {
1216 resident->CastSpell(resident, SPELL_TRANSFORM_VISUAL);
1217 resident->UpdateEntry(NPC_INFINITE_AGENT);
1218 }
1219 break;
1220 case RP3_EVENT_AGGRO:
1223 break;
1224 case RP3_EVENT_ARTHAS4:
1225 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS4;
1226 break;
1229 break;
1231 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS10;
1233 break;
1234 case RP3_EVENT_SPAWN1:
1235 {
1236 uint8 extra = urand(0, 2); // 0 = extra adversary, 1 = extra hunter, 2 = extra agent
1246 rift->DespawnOrUnsummon(Seconds(4));
1247 break;
1248 }
1252 {
1253 std::list<Creature*> infinites;
1257 for (Creature* target : infinites)
1258 if (target->IsAlive())
1259 target->SetFacingToObject(me);
1260 break;
1261 }
1265 break;
1266 case RP3_EVENT_ARTHAS11:
1267 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS11;
1268 break;
1271 break;
1272 case RP3_EVENT_ARTHAS20:
1273 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS20;
1274 break;
1275 case RP3_EVENT_SPAWN2:
1276 {
1277 uint8 extra = urand(0, 2); // 0 = extra adversary, 1 = extra hunter, 2 = extra agent
1287 rift1->DespawnOrUnsummon(Seconds(5));
1289 rift2->DespawnOrUnsummon(Seconds(5));
1290 break;
1291 }
1293 me->SetFacingTo(1.762783f); // @todo
1294 break;
1298 break;
1299 case RP3_EVENT_ARTHAS21:
1300 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS21;
1301 break;
1304 break;
1305 case RP3_EVENT_SPAWN3:
1306 {
1307 uint8 extra = urand(0, 2); // 0 = extra adversary, 1 = extra hunter, 2 = extra agent
1317 rift1->DespawnOrUnsummon(Seconds(5));
1319 rift2->DespawnOrUnsummon(Seconds(5));
1320 break;
1321 }
1322 case RP3_EVENT_ARTHAS30:
1323 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS30;
1324 break;
1328 break;
1331 epoch->GetMotionMaster()->MoveAlongSplineChain(0, RP3_CHAIN_EPOCH, false);
1333 rift->DespawnOrUnsummon(Seconds(27));
1334 break;
1335 case RP3_EVENT_ARTHAS31:
1336 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS31;
1337 me->SetFacingTo(6.073746f); // @todo
1338 break;
1340 if (Creature* epoch = me->FindNearestCreature(NPC_EPOCH, 100.0f, true))
1341 epoch->SetFacingToObject(me);
1342 break;
1343 case RP3_EVENT_EPOCH1:
1344 talkerEntry = NPC_EPOCH, talkerLine = RP3_LINE_EPOCH1;
1345 break;
1346 case RP3_EVENT_ARTHAS32:
1347 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS32;
1348 break;
1351 break;
1353 talkerEntry = NPC_EPOCH, talkerLine = RP3_LINE_EPOCH2;
1354 if (Creature* epoch = me->FindNearestCreature(NPC_EPOCH, 100.0f, true))
1355 {
1356 epoch->SetImmuneToAll(false);
1357 me->EngageWithTarget(epoch);
1358 epoch->EngageWithTarget(me);
1359 }
1361 break;
1362 case RP4_EVENT_ARTHAS2:
1363 me->SetFacingTo(0.226893f); // @todo
1364 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS2;
1365 break;
1367 if (GameObject* passage = me->FindNearestGameObject(GO_HIDDEN_PASSAGE, 100.0f))
1368 passage->SetGoState(GO_STATE_ACTIVE);
1369 break;
1370 case RP4_EVENT_ARTHAS3:
1371 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS3;
1373 break;
1377 break;
1380 break;
1381 case RP4_EVENT_ARTHAS11:
1382 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS11;
1383 break;
1385 me->SetFacingTo(1.780236f); // @todo
1386 break;
1387 case RP4_EVENT_ARTHAS12:
1388 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS12;
1389 break;
1392 break;
1393 case RP4_EVENT_ARTHAS13:
1394 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS13;
1396 break;
1400 break;
1401 case RP5_EVENT_ARTHAS2:
1402 talkerEntry = 0, talkerLine = RP5_LINE_ARTHAS2;
1403 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1404 me->SetFacingToObject(malganis);
1405 break;
1407 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1408 {
1409 malganis->AI()->Talk(RP5_LINE_MALGANIS1, ObjectAccessor::GetUnit(*malganis, _eventStarterGuid));
1410 malganis->SetImmuneToAll(false);
1411 me->EngageWithTarget(malganis);
1412 malganis->EngageWithTarget(me);
1413 }
1415 break;
1417 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1418 {
1419 malganis->SetFacingToObject(me);
1420 malganis->CastSpell(malganis, SPELL_MALGANIS_QUEST_CREDIT, true);
1421 malganis->CastSpell(malganis, SPELL_MALGANIS_KILL_CREDIT, true);
1423 chest->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
1424 }
1437 break;
1439 talkerEntry = NPC_MALGANIS, talkerLine = RP5_LINE_MALGANIS12;
1440 break;
1442 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1443 malganis->CastSpell(malganis, SPELL_SHADOWSTEP_VISUAL);
1444 break;
1445 case RP5_EVENT_ARTHAS10:
1446 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1447 malganis->DespawnOrUnsummon();
1449 talkerEntry = 0, talkerLine = RP5_LINE_ARTHAS10;
1450 break;
1453 break;
1454 case RP5_EVENT_ARTHAS11:
1455 talkerEntry = 0, talkerLine = RP5_LINE_ARTHAS11;
1456 break;
1459 break;
1462 break;
1465 break;
1468 {
1469 chromie->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
1470 std::function<void(Movement::MoveSplineInit&)> initializer = [](Movement::MoveSplineInit& init)
1471 {
1473 init.SetFly();
1474 init.SetWalk(true);
1475 init.MovebyPath(path, 0);
1476 };
1477 chromie->GetMotionMaster()->LaunchMoveSpline(std::move(initializer), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE);
1478 }
1479 break;
1481 if (Creature* chromie = me->FindNearestCreature(NPC_CHROMIE_3, 100.0f, true))
1482 chromie->SetAnimTier(AnimTier::Ground);
1483 break;
1485 if (Creature* chromie = me->FindNearestCreature(NPC_CHROMIE_3, 100.0f, true))
1486 {
1487 chromie->CastSpell(chromie, SPELL_CHROMIE_3_TRANSFORM);
1488 chromie->AI()->Talk(RP5_LINE_CHROMIE0);
1489 chromie->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
1490 }
1491 break;
1492 default:
1493 break;
1494 }
1495
1496 if (talkerEntry != UINT_MAX)
1497 {
1498 Creature* talker;
1499 if (talkerEntry)
1500 talker = me->FindNearestCreature(talkerEntry, 100.0f, true);
1501 else
1502 talker = me;
1503 if (talker)
1504 talker->AI()->Talk(talkerLine, ObjectAccessor::GetUnit(*talker, _eventStarterGuid));
1505 }
1506 }
1507 }
1508
1510 {
1511 std::list<Creature*> infinites;
1515 for (Creature* target : infinites)
1516 {
1517 target->SetImmuneToAll(false);
1518 me->EngageWithTarget(target);
1519 target->EngageWithTarget(me);
1520 }
1521 }
1522
1523 static void MoveInfiniteOnSpawn(Creature* infinite, SplineChains chainId)
1524 {
1525 if (std::vector<SplineChainLink> const* chain = sScriptSystemMgr->GetSplineChain(NPC_INFINITE_ADVERSARY, chainId))
1526 infinite->GetMotionMaster()->MoveAlongSplineChain(0, *chain, true);
1527 }
1528
1529 void KilledUnit(Unit* who) override
1530 {
1531 if (who && who->GetEntry() == NPC_RISEN_ZOMBIE)
1532 Talk(LINE_SLAY_ZOMBIE, who);
1533 }
1534
1535 void JustEngagedWith(Unit* who) override
1536 {
1537 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustEngagedWith: RP in progress? '{}'", _progressRP ? "YES" : "NO");
1538 if (_progressRP)
1539 {
1540 _progressRP = false;
1542
1544 if (!_resumeMovement.Empty())
1545 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustEngagedWith: spline chain motion paused");
1546 else
1547 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustEngagedWith: entered combat without pathing, pausing RP regardless");
1548 }
1550 }
1551
1552 void EnterEvadeMode(EvadeReason why) override
1553 {
1554 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::EnterEvadeMode: why = {} ", why);
1556 }
1557
1558 void JustReachedHome() override
1559 {
1562
1563 _progressRP = true;
1564
1565 if (!_resumeMovement.Empty()) // WP motion was interrupted, resume
1566 {
1567 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustReachedHome: Resuming motion");
1570 }
1571 else
1572 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustReachedHome: Back at leash pos, resuming RP");
1573
1574 if (_afterCombat)
1575 {
1578 }
1579 }
1580
1581 void JustDied(Unit* /*killer*/) override
1582 {
1583 // Instance failure: regress back to last stable state
1585 me->DespawnOrUnsummon(5s);
1586 }
1587
1588 void JustAppeared() override
1589 {
1590 _progressRP = true;
1593 }
1594
1596 {
1598 instance->SetGuidData(command, cause->GetGUID());
1599 }
1600
1601 bool OnGossipSelect(Player* player, uint32 /*sender*/, uint32 listId) override
1602 {
1603 uint32 const action = GetGossipActionFor(player, listId);
1604 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::GossipSelect: '{}' selects action '{}' on '{}'", player->GetGUID().ToString(), action, me->GetGUID().ToString());
1605
1611 return true;
1612 }
1613
1614 bool OnGossipHello(Player* /*player*/) override
1615 {
1616 return false;
1617 }
1618
1619 private:
1623 uint32 _exorcismCooldown; // no EventMap entry for this, it's reserved for RP handling
1624
1628 };
1629
1630 CreatureAI* GetAI(Creature* creature) const override
1631 {
1632 return GetCullingOfStratholmeAI<npc_arthas_stratholmeAI>(creature);
1633 }
1634};
1635
1637{
1638 auto itr = ArthasSnapbackPositions.find(state);
1639 if (itr == ArthasSnapbackPositions.end())
1640 itr = ArthasSnapbackPositions.begin();
1641 return *(itr->second.SnapbackPosition);
1642}
1643
1644// Arthas' AI is the one controlling everything, all this AI does is report any movementinforms back to Arthas AI
1646{
1648
1649 void MovementInform(uint32 type, uint32 id) override
1650 {
1651 if (type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE || type == SPLINE_CHAIN_MOTION_TYPE)
1652 if (TempSummon* self = me->ToTempSummon())
1653 ASSERT_NOTNULL(self->GetSummonerCreatureBase())->AI()->MovementInform(type, id);
1654 }
1655};
1656
1657// 50773 - Crusader Strike
1659{
1661
1662 void HandleDummy(SpellEffIndex /*effIndex*/)
1663 {
1664 if (Unit* target = GetHitUnit())
1665 if (target->GetEntry() == NPC_CITIZEN || target->GetEntry() == NPC_RESIDENT)
1666 Unit::Kill(GetCaster(), target);
1667 }
1668
1673};
1674
Actions
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:27
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
@ DONE
#define TC_LOG_WARN(filterType__,...)
Definition Log.h:162
#define TC_LOG_TRACE(filterType__,...)
Definition Log.h:153
@ MOTION_PRIORITY_NORMAL
@ SPLINE_CHAIN_MOTION_TYPE
@ POINT_MOTION_TYPE
@ EFFECT_MOTION_TYPE
@ TEMPSUMMON_MANUAL_DESPAWN
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
uint32 urandms(uint32 min, uint32 max)
Definition Random.cpp:49
#define RegisterCreatureAI(ai_name)
Definition ScriptMgr.h:1139
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1128
#define sScriptSystemMgr
uint32 GetGossipActionFor(Player *player, uint32 gossipListId)
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_DUMMY
@ EMOTE_ONESHOT_POINT_NO_SHEATHE
@ EMOTE_ONESHOT_EXCLAMATION
@ EMOTE_STATE_COWER
@ EMOTE_ONESHOT_LAUGH
@ EMOTE_ONESHOT_ROAR
@ EMOTE_ONESHOT_RUDE
@ EMOTE_ONESHOT_TALK
@ GO_FLAG_NOT_SELECTABLE
@ GO_STATE_ACTIVE
@ TRIGGERED_IGNORE_SET_FACING
Will ignore interruptible aura's at cast.
#define SpellEffectFn(F, I, N)
ReactStates
@ REACT_DEFENSIVE
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_NPC_FLAG_GOSSIP
@ UNIT_NPC_FLAG_QUESTGIVER
@ UNIT_STATE_CASTING
Definition Unit.h:235
Data
virtual void JustEngagedWith(Unit *)
Definition CreatureAI.h:127
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
virtual void EnterEvadeMode(EvadeReason why=EVADE_REASON_OTHER)
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:293
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:295
bool HasReactState(ReactStates state) const
Definition Creature.h:121
bool IsEngaged() const override
void SetReactState(ReactStates st)
Definition Creature.h:119
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
void SetImmuneToAll(bool apply) override
Definition Creature.h:126
CreatureAI * AI() const
Definition Creature.h:154
void Update(uint32 time)
Definition EventMap.h:67
bool Empty() const
Definition EventMap.h:95
EventId ExecuteEvent()
Definition EventMap.cpp:73
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
virtual bool SetBossState(uint32 id, EncounterState state)
InstanceMap * instance
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, uint32 duration=0, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1852
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void ResumeSplineChain(SplineChainResumeInfo const &info)
std::string ToString() const
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
Unit * GetCaster() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
static void GetResumeInfo(SplineChainResumeInfo &info, Unit const *owner, Optional< uint32 > id={})
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:54
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:241
virtual bool CanAIAttack(Unit const *) const
Definition UnitAI.h:139
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:96
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
void SetVisible(bool x)
Definition Unit.cpp:8513
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool IsAlive() const
Definition Unit.h:1234
void RemoveNpcFlag(NPCFlags flags)
Definition Unit.h:1098
TempSummon * ToTempSummon()
Definition Unit.h:1794
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4535
void SetFacingToObject(WorldObject const *object, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13259
void SetNpcFlag(NPCFlags flags)
Definition Unit.h:1097
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8292
void NearTeleportTo(Position const &pos, bool casting=false)
Definition Unit.cpp:12832
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
void HandleEmoteCommand(Emote emoteId)
Definition Unit.cpp:1568
void SetFacingTo(float ori, bool force=true, uint32 movementId=EVENT_FACE)
Definition Unit.cpp:13250
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true)
Definition Unit.cpp:10930
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:2121
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:3153
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
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:2099
virtual uint32 GetData(uint32) const
Definition ZoneScript.h:55
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:56
virtual void SetGuidData(uint32, ObjectGuid)
Definition ZoneScript.h:49
CreatureAI * GetAI(Creature *creature) const override
PrepareSpellScript(spell_stratholme_crusader_strike)
@ DATA_START_MALGANIS
@ DATA_INSTANCE_PROGRESS
@ DATA_ARTHAS_DIED
@ DATA_GAUNTLET_DONE
@ DATA_MALGANIS_DONE
@ DATA_TO_GAUNTLET
@ DATA_START_GAUNTLET
@ DATA_START_WAVES
@ DATA_TOWN_HALL_DONE
@ DATA_REACH_TOWN_HALL
@ DATA_START_TOWN_HALL
@ DATA_GAUNTLET_REACHED
@ DATA_START_PURGE
@ DATA_UTHER_FINISHED
@ ACTION_START_RP_EVENT2
@ ACTION_PROGRESS_UPDATE
@ ACTION_START_RP_EVENT3
@ ACTION_START_RP_EVENT4_2
@ ACTION_START_RP_EVENT4_1
@ ACTION_START_RP_EVENT5
@ TOWN_HALL_COMPLETE
@ CRATES_IN_PROGRESS
@ GAUNTLET_IN_PROGRESS
@ TOWN_HALL_PENDING
@ GAUNTLET_PENDING
@ MALGANIS_IN_PROGRESS
@ WAVES_IN_PROGRESS
@ GAUNTLET_TRANSITION
@ PURGE_PENDING
@ PURGE_STARTING
@ GAUNTLET_COMPLETE
@ GO_HIDDEN_PASSAGE
std::vector< Vector3 > PointsArray
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition Containers.h:108
Position const & GetArthasSnapbackFor(COSProgressStates state)
@ GO_CHEST_NORMAL
@ NPC_RESIDENT
@ NPC_TIME_RIFT_LARGE
@ SPELL_EXORCISM
@ GO_CHEST_HEROIC
@ NPC_EPOCH
@ SPELL_MALGANIS_KILL_CREDIT
@ NPC_PRIEST
@ NPC_INFINITE_ADVERSARY
@ SPELL_SHADOWSTEP_VISUAL
@ NPC_UTHER
@ NPC_TIME_RIFT
@ NPC_MALGANIS
@ NPC_SORCERESS
@ SPELL_CRUSADER_STRIKE
@ NPC_FOOTMAN
@ NPC_CITIZEN_INFINITE
@ NPC_KNIGHT
@ NPC_CITIZEN
@ SPELL_DEVOTION_AURA
@ NPC_JAINA
@ SPELL_MALGANIS_QUEST_CREDIT
@ SPELL_TRANSFORM_VISUAL
@ SPELL_CHROMIE_3_TRANSFORM
@ NPC_RESIDENT_INFINITE
@ NPC_CHROMIE_3
@ NPC_RISEN_ZOMBIE
@ NPC_INFINITE_AGENT
@ NPC_INFINITE_HUNTER
@ SPELL_HOLY_LIGHT
@ NPC_MALGANIS_BUNNY
SplineChains
@ RP1_CHAIN_UTHER2
@ RP2_CHAIN_ARTHAS3
@ RP3_CHAIN_SPAWN3_LOC3
@ RP3_CHAIN_SPAWN2_LOC4
@ RP5_CHAIN_ARTHAS3
@ RP3_CHAIN_SPAWN3_LOC1
@ RP3_CHAIN_SPAWN3_LOC4
@ RP1_CHAIN_ARTHAS2
@ RP3_CHAIN_SPAWN1_LOC2
@ RP2_CHAIN_ARTHAS2
@ RP1_CHAIN_JAINA4
@ RP3_CHAIN_SPAWN1_LOC3
@ RP5_CHAIN_ARTHAS2
@ RP5_CHAIN_ARTHAS4
@ RP1_CHAIN_ARTHAS4
@ RP3_CHAIN_ARTHAS4
@ RP3_CHAIN_SPAWN2_LOC2
@ RP1_CHAIN_JAINA3
@ RP3_CHAIN_SPAWN2_LOC3
@ RP1_CHAIN_UTHER3
@ RP4_CHAIN_GAUNTLET1
@ RP2_CHAIN_CITIZEN1
@ RP1_CHAIN_UTHER1
@ RP3_CHAIN_SPAWN1_LOC1
@ RP3_CHAIN_ARTHAS2
@ RP4_CHAIN_ARTHAS1
@ RP1_CHAIN_ARTHAS3
@ RP3_CHAIN_ARTHAS3
@ RP5_CHAIN_ARTHAS1
@ RP3_CHAIN_ARTHAS5
@ RP3_CHAIN_ARTHAS3_2
@ RP3_CHAIN_SPAWN2_LOC1
@ RP3_CHAIN_SPAWN3_LOC2
@ RP1_CHAIN_JAINA1
@ RP3_CHAIN_EPOCH
@ RP4_CHAIN_GAUNTLET2
@ RP3_CHAIN_ARTHAS1
@ RP2_CHAIN_ARTHAS1
@ RP4_CHAIN_ARTHAS2
@ RP3_CHAIN_SPAWN1_LOC4
@ RP1_CHAIN_ARTHAS1
@ RP1_CHAIN_JAINA2
RPEventLines2
@ RP2_LINE_MALGANIS1
@ RP2_LINE_ARTHAS5
@ RP2_LINE_MALGANIS2
@ RP2_LINE_ARTHAS3
@ RP2_LINE_ARTHAS2
@ RP2_LINE_ARTHAS4
@ RP2_LINE_RESIDENT1
@ RP2_LINE_CITIZEN1
@ RP2_LINE_ARTHAS1
@ RP2_LINE_CITIZEN2
RPEvents
@ RP3_EVENT_ARTHAS11
@ RP2_EVENT_REACT5
@ RP5_EVENT_MALGANIS12
@ RP4_EVENT_ARTHAS12
@ RP1_EVENT_JAINA_LEAVE
@ RP3_EVENT_SPAWN2_FACE
@ RP4_EVENT_GAUNTLET_DONE
@ RP3_EVENT_TRANSFORM2
@ RP1_EVENT_ARTHAS3
@ RP5_EVENT_ARTHAS10_2
@ RP3_EVENT_ARTHAS30
@ RP1_EVENT_JAINA_LEAVE2
@ RP1_EVENT_ARTHAS7
@ RP1_EVENT_UTHER_FACE
@ RP2_EVENT_REACT3
@ RP1_EVENT_ARTHAS2
@ RP3_EVENT_SPAWN2
@ RP1_EVENT_START2
@ RP5_EVENT_ARTHAS_LEAVE2
@ RP2_EVENT_ARTHAS5_2
@ RP4_EVENT_ARTHAS2
@ RP1_EVENT_ARTHAS5
@ RP3_EVENT_ARTHAS2
@ RP4_EVENT_ARTHAS13
@ RP5_EVENT_ARTHAS_LEAVE
@ RP3_EVENT_RESIDENT_FACE
@ RP2_EVENT_REACT2
@ RP5_EVENT_ARTHAS10
@ RP1_EVENT_UTHER3
@ RP2_EVENT_TROOPS_FACE
@ RP2_EVENT_ARTHAS_MOVE_2
@ RP1_EVENT_UTHER6
@ RP3_EVENT_ARTHAS4
@ RP2_EVENT_ARTHAS2
@ RP1_EVENT_UTHER4
@ RP4_EVENT_HIDDEN_PASSAGE
@ RP3_EVENT_TRANSFORM3
@ RP3_EVENT_INFINITE_LAUGH
@ RP3_EVENT_ARTHAS3
@ RP1_EVENT_ARTHAS_LEAVE2
@ RP3_EVENT_SPAWN1_FACE
@ RP3_EVENT_ARTHAS32
@ RP3_EVENT_ARTHAS_MOVE_1_2
@ RP2_EVENT_KILL1
@ RP3_EVENT_SPAWN1
@ RP4_EVENT_ARTHAS11
@ RP3_EVENT_ARTHAS_FACE
@ RP3_EVENT_CITIZEN2
@ RP3_EVENT_EPOCH_FACE
@ RP1_EVENT_JAINA1
@ RP1_EVENT_UTHER_LEAVE
@ RP5_EVENT_ARTHAS11_2
@ RP3_EVENT_EPOCH_SPAWN
@ RP3_EVENT_ARTHAS_MOVE_3
@ RP2_EVENT_ARTHAS4
@ RP1_EVENT_ARTHAS9
@ RP2_EVENT_ARTHAS5_3
@ RP2_EVENT_ARTHAS5
@ RP1_EVENT_UTHER1
@ RP2_EVENT_REACT4
@ RP5_EVENT_MALGANIS_LEAVE
@ RP4_EVENT_GAUNTLET_REACHED
@ RP4_EVENT_GAUNTLET_RESUME
@ RP3_EVENT_ARTHAS31
@ RP4_EVENT_ARTHAS_MOVE
@ RP1_EVENT_START1
@ RP1_EVENT_ARTHAS4
@ RP3_EVENT_SPAWN3_AGGRO
@ RP4_EVENT_ARTHAS_FACE
@ RP5_EVENT_CHROMIE_SPAWN
@ RP2_EVENT_WAVE_START
@ RP3_EVENT_ARTHAS_MOVE_2
@ RP1_EVENT_JAINA_FACE
@ RP3_EVENT_EPOCH1
@ RP2_EVENT_MALGANIS_LEAVE1
@ RP1_EVENT_JAINA2
@ RP3_EVENT_ARTHAS_MOVE_1
@ RP3_EVENT_SPAWN3
@ RP5_EVENT_MALGANIS1
@ RP2_EVENT_CITIZEN1
@ RP1_EVENT_ARTHAS_TURN
@ RP2_EVENT_MALGANIS2
@ RP5_EVENT_CHROMIE_TRANSFORM
@ RP3_EVENT_TRANSFORM1
@ RP1_EVENT_ARTHAS6
@ RP1_EVENT_ARTHAS8
@ RP2_EVENT_ARTHAS_FACE
@ RP3_EVENT_AGGRO
@ RP2_EVENT_ARTHAS_MOVE_3
@ RP1_EVENT_FINISHED
@ RP2_EVENT_ARTHAS4_2
@ RP3_EVENT_ARTHAS_FACE2
@ RP2_EVENT_ARTHAS_MOVE_4
@ RP2_EVENT_ARTHAS_MOVE_1
@ RP3_EVENT_SPAWN2_AGGRO
@ RP5_EVENT_CHROMIE_LAND
@ RP3_EVENT_ARTHAS20
@ RP2_EVENT_CITIZEN2
@ RP2_EVENT_ARTHAS3
@ RP2_EVENT_KILL2
@ RP3_EVENT_SPAWN3_FACE
@ RP2_EVENT_MALGANIS1
@ RP3_EVENT_SPAWN1_AGGRO
@ RP1_EVENT_UTHER5
@ RP2_EVENT_REACT1
@ RP1_EVENT_ARTHAS8_2
@ RP2_EVENT_ARTHAS_MOVE_5
@ RP5_EVENT_MALGANIS_DONE
@ RP4_EVENT_ARTHAS3
@ RP1_EVENT_ARTHAS1
@ RP5_EVENT_ARTHAS11
@ RP3_EVENT_ARTHAS32_2
@ RP3_EVENT_CITIZEN1
@ RP1_EVENT_ARTHAS10
@ EVENT_TOWN_HALL_REACHED
@ RP3_EVENT_ARTHAS_KILL
@ RP3_EVENT_ARTHAS21
@ RP2_EVENT_MALGANIS_LEAVE2
@ RP1_EVENT_ARTHAS_LEAVE
@ RP1_EVENT_UTHER2
@ RP5_EVENT_ARTHAS2
@ RP3_EVENT_EPOCH_AGGRO
uint32 const chromiePathSize
RPEventLines3
@ RP3_LINE_EPOCH2
@ RP3_LINE_EPOCH1
@ RP3_LINE_ARTHAS30
@ RP3_LINE_ARTHAS11
@ RP3_LINE_CITIZEN2
@ RP3_LINE_ARTHAS4
@ RP3_LINE_ARTHAS20
@ RP3_LINE_ARTHAS21
@ RP3_LINE_ARTHAS10
@ RP3_LINE_ARTHAS32
@ RP3_LINE_ARTHAS2
@ RP3_LINE_ARTHAS3
@ RP3_LINE_ARTHAS31
@ RP3_LINE_CITIZEN1
@ RP3_LINE_ARTHAS1
Actions
@ RP3_ACTION_AFTER_SPAWN1
@ RP5_ACTION_AFTER_MALGANIS
@ RP3_ACTION_AFTER_SPAWN2
@ ACTION_NONE
@ RP3_ACTION_AFTER_SPAWN3
@ RP3_ACTION_AFTER_INITIAL
@ RP3_ACTION_AFTER_EPOCH
RPEventLines1
@ RP1_LINE_ARTHAS8
@ RP1_LINE_ARTHAS11
@ RP1_LINE_ARTHAS3
@ RP1_LINE_ARTHAS7
@ RP1_LINE_ARTHAS6
@ RP1_LINE_UTHER5
@ RP1_LINE_ARTHAS9
@ RP1_LINE_UTHER6
@ RP1_LINE_UTHER4
@ RP1_LINE_UTHER2
@ RP1_LINE_ARTHAS1
@ RP1_LINE_ARTHAS5
@ RP1_LINE_JAINA2
@ RP1_LINE_UTHER3
@ RP1_LINE_UTHER1
@ RP1_LINE_JAINA1
@ RP1_LINE_ARTHAS10
@ RP1_LINE_ARTHAS4
@ RP1_LINE_ARTHAS2
static std::unordered_map< uint32, SnapbackInfo > const ArthasSnapbackPositions
RPEventLines5
@ RP5_LINE_MALGANIS1
@ RP5_LINE_ARTHAS2
@ RP5_LINE_ARTHAS10
@ RP5_LINE_MALGANIS12
@ RP5_LINE_CHROMIE0
@ RP5_LINE_ARTHAS1
@ RP5_LINE_ARTHAS11
OtherLines
@ LINE_SLAY_ZOMBIE
@ LINE_TOWN_HALL_PENDING
void AddSC_npc_arthas_stratholme()
PointIDs
@ RP1_POINTID_ARTHAS4
@ RP5_POINTID_ARTHAS3
@ RP5_POINTID_ARTHAS1
@ RP1_POINTID_UTHER2
@ RP2_POINTID_ARTHAS3
@ RP4_POINTID_ARTHAS1
@ RP1_POINTID_UTHER3
@ RP1_POINTID_JAINA2
@ RP2_POINTID_ARTHAS1
@ RP3_POINTID_ARTHAS2
@ RP4_POINTID_GAUNTLET1
@ RP3_POINTID_TOWN_HALL
@ RP5_POINTID_ARTHAS4
@ RP4_POINTID_ARTHAS2
@ RP2_POINTID_ARTHAS2
@ RP1_POINTID_JAINA4
@ RP3_POINTID_ARTHAS4
@ RP4_POINTID_GAUNTLET2
@ RP3_POINTID_ARTHAS1
@ RP3_POINTID_ARTHAS5
@ RP1_POINTID_UTHER1
@ RP3_POINTID_ARTHAS3
@ RP1_POINTID_ARTHAS3
@ RP1_POINTID_ARTHAS2
static float const ArthasSnapbackDistanceThreshold
static std::array< Position, NUM_POSITIONS > const ArthasPositions
PositionIndices
@ RP2_FOOT4_POS
@ RP1_UTHER_SPAWN
@ RP3_SPAWN2_LOC2
@ RP3_SPAWN2_RIFT2
@ RP1_JAINA_SPAWN
@ RP3_SPAWN1_LOC2
@ NUM_POSITIONS
@ RP3_SPAWN3_LOC1
@ ARTHAS_GAUNTLET_POS
@ RP3_SPAWN3_RIFT1
@ RP3_EPOCH_RIFT
@ RP3_SPAWN1_LOC1
@ ARTHAS_FINAL_POS
@ RP3_SPAWN3_LOC2
@ RP1_ARTHAS_INITIAL
@ ARTHAS_GAUNTLET_END_POS
@ RP3_SPAWN1_LOC3
@ RP3_SPAWN1_LOC4
@ RP3_SPAWN2_LOC3
@ ARTHAS_PURGE_PENDING_POS
@ RP3_SPAWN2_LOC4
@ RP2_PRIEST2_POS
@ RP2_MALGANIS_POS
@ RP3_SPAWN3_LOC4
@ RP3_SPAWN2_RIFT1
@ RP2_FOOT1_POS
@ RP3_SPAWN3_RIFT2
@ RP3_SPAWN3_LOC3
@ RP5_CHROMIE_SPAWN
@ RP5_MALGANIS_POS
@ RP2_FOOT2_POS
@ ARTHAS_TOWN_HALL_POS
@ RP3_SPAWN1_RIFT
@ RP2_FOOT3_POS
@ RP2_PRIEST1_POS
@ RP3_SPAWN2_LOC1
@ ARTHAS_TOWN_HALL_END_POS
@ ARTHAS_WAVES_POS
@ RP3_EPOCH_SPAWN
G3D::Vector3 const ChromieSplinePos[chromiePathSize]
RPEventLines4
@ RP4_LINE_ARTHAS12
@ RP4_LINE_ARTHAS13
@ RP4_LINE_ARTHAS3
@ RP4_LINE_ARTHAS2
@ RP4_LINE_ARTHAS1
@ RP4_LINE_ARTHAS10
@ RP4_LINE_ARTHAS11
@ DATA_RP_DUMMY_MOVED
float GetExactDist2d(const float x, const float y) const
Definition Position.h:109
float GetExactDist(float x, float y, float z) const
Definition Position.h:121
void GetPosition(float &x, float &y) const
Definition Position.h:84
T const & RAID_MODE(T const &normal10, T const &normal25) const
bool HealthBelowPct(uint32 pct) const
ReactStates const ReactState
bool const HasGossip
Position const *const SnapbackPosition
bool CanAIAttack(Unit const *who) const override
static void MoveInfiniteOnSpawn(Creature *infinite, SplineChains chainId)
bool OnGossipSelect(Player *player, uint32, uint32 listId) override
void AdvanceDungeon(Player *cause, COSProgressStates from, COSInstanceData command)
void MovementInform(uint32 type, uint32 id) override
void EnterEvadeMode(EvadeReason why) override
void SetGUID(ObjectGuid const &guid, int32 type) override
void AdvanceToState(COSProgressStates newState)
void MovementInform(uint32 type, uint32 id) override
npc_stratholme_rp_dummy(Creature *creature)