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 "SmartEnum.h"
35#include "SpellScript.h"
37#include "TemporarySummon.h"
38#include <array>
39#include <unordered_map>
40#include <vector>
41
77
79{
80 // RP1: Arthas/Jaina/Uther, outside Stratholme gates
81 RP1_CHAIN_ARTHAS1 = 1, // Initial movement
82 RP1_CHAIN_UTHER1 = 1, // Initial movement
83 RP1_CHAIN_JAINA1 = 1, // Initial movement
84 RP1_CHAIN_ARTHAS2 = 2, // Arthas moves up the hill to look out over Stratholme
85 RP1_CHAIN_UTHER2 = 2, // Uther follows
86 RP1_CHAIN_JAINA2 = 2, // Jaina follows
87 RP1_CHAIN_UTHER3 = 3, // Uther leaves
88 RP1_CHAIN_JAINA3 = 3, // Jaina turns to leave, but is stopped by Arthas
89 RP1_CHAIN_JAINA4 = 4, // Jaina leaves for real
90 RP1_CHAIN_ARTHAS3 = 3, // Arthas moves down the hill to the bridge
91 RP1_CHAIN_ARTHAS4 = 4, // Arthas moves to the Stratholme entrance
92
93 // RP2: Arthas/Mal'ganis, at Stratholme gates
94 RP2_CHAIN_ARTHAS1 = 5, // Arthas enters Stratholme proper
95 RP2_CHAIN_CITIZEN1 = 1, // A Stratholme citizen greets Arthas
96 RP2_CHAIN_ARTHAS2 = 6, // Arthas advances towards the approaching citizen
97 RP2_CHAIN_ARTHAS3 = 7, // Arthas moves on to a nearby resident
98
99 // RP3: Arthas/Infinites, in Stratholme Town Hall
100 RP3_CHAIN_ARTHAS1 = 91, // Arthas enters Stratholme Town Hall
101 RP3_CHAIN_ARTHAS2 = 92, // Arthas approaches one of the disguised Infinites
102 RP3_CHAIN_ARTHAS3 = 95, // Arthas proceeds up the stairs
103 RP3_CHAIN_ARTHAS3_2 = 96, // Arthas encounters more Infinite resistance
104 RP3_CHAIN_ARTHAS4 = 97, // Arthas presses onward into a hallway
105 RP3_CHAIN_ARTHAS5 = 98, // Arthas advances into the boss room
106 RP3_CHAIN_EPOCH = 1, // Chrono-Lord Epoch advances out of the portal
107
108 // Spawn motions (all on 27742, infinite adversary)
121
122 // RP4: Arthas moving towards Gauntlet
123 RP4_CHAIN_ARTHAS1 = 101, // Arthas moves up to the bookcase
124 RP4_CHAIN_ARTHAS2 = 128, // Arthas advances to the start of the Gauntlet section
125 RP4_CHAIN_GAUNTLET1 = 1024, // Arthas charges to the halfway point of the Gauntlet
126 RP4_CHAIN_GAUNTLET2 = 1025, // Arthas continues to Market Row
127
128 // RP5: Arthas advances on Crusader Square and faces off against Mal'ganis
129 RP5_CHAIN_ARTHAS1 = 121, // Arthas moves into Crusader Square
130 RP5_CHAIN_ARTHAS2 = 124, // After Mal'ganis' defeat, Arthas attempts to chase him down
131 RP5_CHAIN_ARTHAS3 = 125, // Arthas departs...
132 RP5_CHAIN_ARTHAS4 = 127 // ...and then finally despawns
134
166
177
182
184{
215
244
246
285
290
298
314
316{
317 RP1_LINE_ARTHAS1 = 0, // Glad you could make it, Uther.
318 RP1_LINE_UTHER1 = 0, // Watch your tone with me, boy. You may be the prince, but I'm still your superior as a paladin!
319 RP1_LINE_ARTHAS2 = 1, // As if I could forget. Listen, Uther, there's something about the plague you should know...
320 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!
321 RP1_LINE_UTHER2 = 1, // What?
322 RP1_LINE_ARTHAS4 = 3, // This entire city must be purged.
323 RP1_LINE_UTHER3 = 2, // How can you even consider that? There's got to be some other way.
324 RP1_LINE_ARTHAS5 = 4, // Damn it, Uther! As your future king, I order you to purge this city!
325 RP1_LINE_UTHER4 = 3, // You are not my king yet, boy! Nor would I obey that command even if you were!
326 RP1_LINE_ARTHAS6 = 5, // Then I must consider this an act of treason.
327 RP1_LINE_UTHER5 = 4, // Treason? Have you lost your mind, Arthas?
328 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.
329 RP1_LINE_JAINA1 = 0, // Arthas! You can't just--
330 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!
331 RP1_LINE_UTHER6 = 5, // You've just crossed a terrible threshold, Arthas.
332 RP1_LINE_ARTHAS9 = 8, // Jaina?
333 RP1_LINE_JAINA2 = 1, // I'm sorry, Arthas. I can't watch you do this.
334 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!
335 RP1_LINE_ARTHAS11 = 40 // All officers should check in with me when their squads are ready. We'll enter Stratholme on my order.
337
339{
340 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.
341 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?
342 RP2_LINE_ARTHAS2 = 11, // I can only help you with a clean death.
343 RP2_LINE_CITIZEN2 = 1, // What? This can't be!
344 RP2_LINE_RESIDENT1 = 0, // Oh, no...
345 RP2_LINE_ARTHAS3 = 12, // That was just the beginning.
346 RP2_LINE_MALGANIS1 = 0, // Yes, this is the beginning. I've been waiting for you, young prince. I am Mal'Ganis.
347 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.
348 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!
349 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.
351
353{
354 RP3_LINE_ARTHAS1 = 16, // Follow me, I know the way through.
355 RP3_LINE_CITIZEN1 = 0, // Ah, you've finally arrived Prince Arthas. You're here just in the nick of time.
356 RP3_LINE_ARTHAS2 = 17, // Yes, I'm glad I could get to you before the plague.
357 RP3_LINE_ARTHAS3 = 18, // What is this sorcery?
358 RP3_LINE_CITIZEN2 = 1, // There's no need for you to understand, Arthas. All you need to do is die.
359 RP3_LINE_ARTHAS4 = 19, // Mal'Ganis appears to have more than Scourge in his arsenal. We should make haste.
360
361 RP3_LINE_ARTHAS10 = 20, // More vile sorcery! Be ready for anything!
362 RP3_LINE_ARTHAS11 = 21, // Let's move on.
363
364 RP3_LINE_ARTHAS20 = 22, // Watch your backs: they have us surrounded in this hall.
365 RP3_LINE_ARTHAS21 = 24, // Mal'ganis is not making this easy.
366
367 RP3_LINE_ARTHAS30 = 25, // They're very persistent.
368 RP3_LINE_ARTHAS31 = 26, // What else can he put in my way?
369 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.
370 RP3_LINE_ARTHAS32 = 27, // I do what I must for Lordaeron, and neither your words nor your actions will stop me.
371 RP3_LINE_EPOCH2 = 1 // We'll see about that, young prince.
373
375{
376 RP4_LINE_ARTHAS1 = 28, // The quickest path to Mal'Ganis lies behind that bookshelf ahead.
377 RP4_LINE_ARTHAS2 = 29, // This will only take a moment.
378 RP4_LINE_ARTHAS3 = 30, // I'm relieved this secret passage still works.
379
380 RP4_LINE_ARTHAS10 = 31, // Let's move through here as quickly as possible. If the undead don't kill us, the fires might.
381 RP4_LINE_ARTHAS11 = 32, // Rest a moment and clear your lungs, but we must move again soon.
382 RP4_LINE_ARTHAS12 = 33, // That's enough; we must move again. Mal'Ganis awaits.
383 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.
385
387{
388 RP5_LINE_ARTHAS1 = 35, // Justice will be done.
389 RP5_LINE_ARTHAS2 = 36, // We're going to finish this right now, Mal'Ganis. Just you... and me.
390 RP5_LINE_MALGANIS1 = 2, // This will be a fine test, Prince Arthas.
391 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.
392 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!
393 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.
394 RP5_LINE_CHROMIE0 = 0 // Why, hello again!
396
448
454
455// @todo sniff
456// All kinds of positions Arthas needs for RP events (there are a lot of these)
457static std::array<Position, NUM_POSITIONS> const ArthasPositions =
458{
459 {
460 { 1983.857f, 1287.043f, 145.5596f, 3.0892330f }, // RP1_ARTHAS_INITIAL
461 { 1783.843f, 1267.481f, 139.7800f, 0.2698664f }, // RP1_UTHER_SPAWN
462 { 1876.788f, 1305.723f, 146.2474f, 6.0737460f }, // RP1_JAINA_SPAWN
463
464 { 2047.948f, 1287.598f, 142.8568f, 3.176499f }, // ARTHAS_PURGE_PENDING_POS
465 { 2091.994f, 1277.257f, 140.4707f, 1.134464f }, // ARTHAS_WAVES_POS // @todo
466 { 2074.624f, 1282.958f, 141.6344f }, // RP2_PRIEST1_POS
467 { 2074.805f, 1292.172f, 141.6728f }, // RP2_PRIEST2_POS
468 { 2077.590f, 1284.609f, 141.5710f }, // RP2_FOOT1_POS
469 { 2078.365f, 1281.254f, 141.5182f }, // RP2_FOOT2_POS
470 { 2077.737f, 1290.441f, 141.5698f }, // RP2_FOOT3_POS
471 { 2078.055f, 1293.624f, 141.5544f }, // RP2_FOOT4_POS
472 { 2113.454f, 1287.986f, 136.3829f, 3.071779f }, // RP2_MALGANIS_POS
473
474 { 2366.240f, 1195.253f, 132.0441f, 3.159046f }, // ARTHAS_TOWN_HALL_POS
475 { 2433.154f, 1192.572f, 148.1547f, 5.542059f }, // RP3_SPAWN1_LOC1
476 { 2432.990f, 1192.760f, 148.1474f, 1.026526f }, // RP3_SPAWN1_LOC2
477 { 2432.824f, 1191.816f, 148.1556f, 4.927707f }, // RP3_SPAWN1_LOC3
478 { 2432.711f, 1192.857f, 148.1550f, 6.257423f }, // RP3_SPAWN1_LOC4
479 { 2433.357f, 1192.168f, 148.1593f, 3.001966f }, // RP3_SPAWN1_RIFT_SPAWN
480 { 2414.349f, 1136.075f, 148.1592f, 1.345922f }, // RP3_SPAWN2_LOC1
481 { 2403.961f, 1180.299f, 148.1587f, 5.139339f }, // RP3_SPAWN2_LOC2
482 { 2414.671f, 1136.262f, 148.1592f, 2.305776f }, // RP3_SPAWN2_LOC3
483 { 2403.908f, 1179.994f, 148.1586f, 4.654133f }, // RP3_SPAWN2_LOC4
484 { 2404.311f, 1178.306f, 148.1585f, 1.605703f }, // RP3_SPAWN2_RIFT1
485 { 2414.041f, 1136.068f, 148.1593f, 2.234021f }, // RP3_SPAWN2_RIFT2
486 { 2429.026f, 1102.693f, 148.1499f, 1.952652f }, // RP3_SPAWN3_LOC1
487 { 2441.173f, 1115.225f, 148.1264f, 2.302970f }, // RP3_SPAWN3_LOC2
488 { 2430.645f, 1104.685f, 148.1306f, 1.135255f }, // RP3_SPAWN3_LOC3
489 { 2439.649f, 1113.719f, 148.1298f, 3.111888f }, // RP3_SPAWN3_LOC4
490 { 2429.296f, 1102.007f, 148.1593f, 6.213372f }, // RP3_SPAWN3_RIFT1
491 { 2440.057f, 1114.226f, 148.1593f, 6.108652f }, // RP3_SPAWN3_RIFT2
492 { 2457.008f, 1113.929f, 150.0776f, 3.272437f }, // RP3_EPOCH_SPAWN
493 { 2456.058f, 1113.838f, 150.0917f, 1.745329f }, // RP3_EPOCH_RIFT
494 { 2425.898f, 1118.842f, 148.0759f, 6.073746f }, // ARTHAS_TOWN_HALL_END_POS
495
496 { 2534.988f, 1126.163f, 130.8621f, 2.844887f }, // ARTHAS_GAUNTLET_POS
497 { 2363.440f, 1404.906f, 128.7869f, 2.775074f }, // ARTHAS_GAUNTLET_END_POS
498
499 { 2296.862f, 1501.015f, 128.4456f, 5.131268f }, // RP5_MALGANIS_POS
500 { 2301.055f, 1478.977f, 128.1299f, 1.758816f }, // ARTHAS_FINAL_POS
501 { 2319.560f, 1506.408f, 152.0474f }, // RP5_CHROMIE_SPAWN
502 }
503};
504
505G3D::Vector3 const ChromieSplinePos[] =
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 }
911
912 void UpdateAI(uint32 diff) override
913 {
914 if (me->IsEngaged())
915 {
916 UpdateAICombat(diff);
917 return;
918 }
919
920 // EventMap is only used for RP handling. RP events are paused while in combat or leashing back to resume pos
921 if (!_progressRP)
922 return;
923
924 events.Update(diff);
925 while (uint32 event = events.ExecuteEvent())
926 {
927 uint32 talkerEntry = UINT_MAX, talkerLine = 0;
928 switch (event)
929 {
930 case RP1_EVENT_START1:
931 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
932 jaina->SetFacingToObject(me);
933 break;
934 case RP1_EVENT_START2:
935 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
936 {
937 uther->SetFacingToObject(me);
938 me->SetFacingToObject(uther);
939 }
940 break;
942 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS1;
943 break;
944 case RP1_EVENT_UTHER1:
945 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER1;
946 break;
948 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS2;
950 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
951 uther->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_UTHER2, RP1_CHAIN_UTHER2, true);
952 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
953 jaina->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_JAINA2, RP1_CHAIN_JAINA2, true);
954 break;
956 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
957 uther->SetFacingToObject(me);
958 break;
960 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
961 jaina->SetFacingToObject(me);
962 break;
964 {
965 me->SetFacingTo(6.248279f); // @todo migrate
966 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS3;
967 std::list<Creature*> troops;
972 for (Creature* unit : troops)
973 if (unit->IsAlive())
974 unit->SetFacingToObject(me);
975 break;
976 }
977 case RP1_EVENT_UTHER2:
978 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER2;
979 break;
981 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS4;
982 break;
983 case RP1_EVENT_UTHER3:
984 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER3;
985 break;
987 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
988 me->SetFacingToObject(uther);
989 break;
991 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS5;
992 break;
993 case RP1_EVENT_UTHER4:
994 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER4;
995 break;
997 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS6;
998 break;
999 case RP1_EVENT_UTHER5:
1000 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER5;
1001 break;
1002 case RP1_EVENT_ARTHAS7:
1003 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS7;
1004 break;
1005 case RP1_EVENT_JAINA1:
1006 talkerEntry = NPC_JAINA, talkerLine = RP1_LINE_JAINA1;
1007 break;
1008 case RP1_EVENT_ARTHAS8:
1009 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS8;
1010 break;
1013 break;
1014 case RP1_EVENT_UTHER6:
1015 talkerEntry = NPC_UTHER, talkerLine = RP1_LINE_UTHER6;
1016 break;
1018 if (Creature* uther = me->FindNearestCreature(NPC_UTHER, 100.0f, true))
1019 uther->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_UTHER3, RP1_CHAIN_UTHER3, true);
1020 break;
1022 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
1023 jaina->GetMotionMaster()->MoveAlongSplineChain(0, RP1_CHAIN_JAINA3, true);
1024 break;
1025 case RP1_EVENT_ARTHAS9:
1026 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS9;
1027 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
1028 me->SetFacingToObject(jaina);
1029 break;
1030 case RP1_EVENT_JAINA2:
1031 talkerEntry = NPC_JAINA, talkerLine = RP1_LINE_JAINA2;
1032 break;
1034 if (Creature* jaina = me->FindNearestCreature(NPC_JAINA, 100.0f, true))
1035 jaina->GetMotionMaster()->MoveAlongSplineChain(RP1_POINTID_JAINA4, RP1_CHAIN_JAINA4, true);
1036 break;
1039 break;
1040 case RP1_EVENT_ARTHAS10:
1041 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS10;
1042 me->SetFacingTo(3.141593f); // @todo migrate
1043 break;
1046 break;
1047 case RP1_EVENT_FINISHED:
1048 talkerEntry = 0, talkerLine = RP1_LINE_ARTHAS11;
1051 break;
1054 break;
1055 case RP2_EVENT_CITIZEN1:
1056 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN, 100.0f, true))
1057 {
1058 citizen->GetMotionMaster()->MoveAlongSplineChain(0, RP2_CHAIN_CITIZEN1, true);
1060 }
1061 break;
1062 case RP2_EVENT_ARTHAS2:
1063 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS2;
1064 break;
1067 break;
1068 case RP2_EVENT_CITIZEN2:
1069 talkerEntry = NPC_CITIZEN, talkerLine = RP2_LINE_CITIZEN2;
1070 break;
1071 case RP2_EVENT_KILL1:
1072 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN, 100.0f, true))
1074 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT, 100.0f, true))
1075 {
1076 resident->SetEmoteState(EMOTE_STATE_COWER);
1078 }
1079 break;
1082 break;
1083 case RP2_EVENT_KILL2:
1084 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT, 100.0f, true))
1086 break;
1087 case RP2_EVENT_REACT1:
1088 case RP2_EVENT_REACT2:
1089 case RP2_EVENT_REACT3:
1090 case RP2_EVENT_REACT4:
1091 case RP2_EVENT_REACT5:
1092 {
1093 std::list<Creature*> nearbyVictims;
1094 me->GetCreatureListWithEntryInGrid(nearbyVictims, urand(0, 1) ? NPC_CITIZEN : NPC_RESIDENT, 60.0f);
1095 if (!nearbyVictims.empty())
1096 {
1097 Emote emotes[] =
1098 {
1103 };
1104
1106 if (victim->IsAlive())
1108 }
1109 break;
1110 }
1112 me->SetFacingTo(2.234021f); // @todo
1113 break;
1114 case RP2_EVENT_ARTHAS3:
1115 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS3;
1116 break;
1118 if (Creature* bunny = me->FindNearestCreature(NPC_MALGANIS_BUNNY, 80.0f, true))
1119 bunny->CastSpell(bunny, SPELL_SHADOWSTEP_VISUAL);
1120
1122 {
1123 malganis->CastSpell(malganis, SPELL_SHADOWSTEP_VISUAL);
1124 malganis->AI()->Talk(RP2_LINE_MALGANIS1);
1125 }
1126 break;
1128 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1129 {
1130 std::list<Creature*> troops;
1133 for (Creature* unit : troops)
1134 if (unit->IsAlive())
1135 unit->SetFacingToObject(malganis);
1136 }
1137 break;
1139 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1140 me->SetFacingToObject(malganis);
1141 break;
1143 talkerEntry = NPC_MALGANIS, talkerLine = RP2_LINE_MALGANIS2;
1144 break;
1146 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1147 malganis->CastSpell(malganis, SPELL_SHADOWSTEP_VISUAL);
1148 break;
1150 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 80.0f, true))
1151 malganis->DespawnOrUnsummon();
1152 if (Creature* bunny = me->FindNearestCreature(NPC_MALGANIS_BUNNY, 80.0f, true))
1153 bunny->CastSpell(bunny, SPELL_SHADOWSTEP_VISUAL);
1154 break;
1155 case RP2_EVENT_ARTHAS4:
1156 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS4;
1157 break;
1160 break;
1161 case RP2_EVENT_ARTHAS5:
1162 talkerEntry = 0, talkerLine = RP2_LINE_ARTHAS5;
1163 break;
1167 break;
1170 break;
1174 break;
1176 if (Creature* infinite = me->FindNearestCreature(NPC_RESIDENT_INFINITE, 100.0f, true))
1177 infinite->SetFacingToObject(me);
1178 break;
1180 me->SetFacingTo(0.541052f); // @todo
1181 break;
1182 case RP3_EVENT_CITIZEN1:
1183 talkerEntry = NPC_CITIZEN_INFINITE, talkerLine = RP3_LINE_CITIZEN1;
1184 break;
1185 case RP3_EVENT_ARTHAS2:
1186 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS2;
1188 break;
1190 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN_INFINITE, 100.0f, true))
1191 DoCast(citizen, SPELL_CRUSADER_STRIKE);
1192 break;
1194 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN_INFINITE, 100.0f, true))
1195 citizen->HandleEmoteCommand(EMOTE_ONESHOT_LAUGH);
1196 break;
1197 case RP3_EVENT_ARTHAS3:
1198 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS3;
1199 break;
1200 case RP3_EVENT_CITIZEN2:
1201 talkerEntry = NPC_CITIZEN_INFINITE, talkerLine = RP3_LINE_CITIZEN2;
1202 break;
1205 if (Creature* citizen = me->FindNearestCreature(NPC_CITIZEN_INFINITE, 100.0f, true))
1206 {
1207 citizen->CastSpell(citizen, SPELL_TRANSFORM_VISUAL);
1208 citizen->UpdateEntry(NPC_INFINITE_HUNTER);
1209 }
1210 break;
1212 if (Creature* resident = me->FindNearestCreature(NPC_RESIDENT_INFINITE, 100.0f, true))
1213 {
1214 resident->CastSpell(resident, SPELL_TRANSFORM_VISUAL);
1215 resident->UpdateEntry(NPC_INFINITE_AGENT);
1216 }
1217 break;
1218 case RP3_EVENT_AGGRO:
1221 break;
1222 case RP3_EVENT_ARTHAS4:
1223 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS4;
1224 break;
1227 break;
1229 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS10;
1231 break;
1232 case RP3_EVENT_SPAWN1:
1233 {
1234 uint8 extra = urand(0, 2); // 0 = extra adversary, 1 = extra hunter, 2 = extra agent
1244 rift->DespawnOrUnsummon(Seconds(4));
1245 break;
1246 }
1250 {
1251 std::list<Creature*> infinites;
1255 for (Creature* target : infinites)
1256 if (target->IsAlive())
1257 target->SetFacingToObject(me);
1258 break;
1259 }
1263 break;
1264 case RP3_EVENT_ARTHAS11:
1265 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS11;
1266 break;
1269 break;
1270 case RP3_EVENT_ARTHAS20:
1271 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS20;
1272 break;
1273 case RP3_EVENT_SPAWN2:
1274 {
1275 uint8 extra = urand(0, 2); // 0 = extra adversary, 1 = extra hunter, 2 = extra agent
1285 rift1->DespawnOrUnsummon(Seconds(5));
1287 rift2->DespawnOrUnsummon(Seconds(5));
1288 break;
1289 }
1291 me->SetFacingTo(1.762783f); // @todo
1292 break;
1296 break;
1297 case RP3_EVENT_ARTHAS21:
1298 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS21;
1299 break;
1302 break;
1303 case RP3_EVENT_SPAWN3:
1304 {
1305 uint8 extra = urand(0, 2); // 0 = extra adversary, 1 = extra hunter, 2 = extra agent
1315 rift1->DespawnOrUnsummon(Seconds(5));
1317 rift2->DespawnOrUnsummon(Seconds(5));
1318 break;
1319 }
1320 case RP3_EVENT_ARTHAS30:
1321 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS30;
1322 break;
1326 break;
1329 epoch->GetMotionMaster()->MoveAlongSplineChain(0, RP3_CHAIN_EPOCH, false);
1331 rift->DespawnOrUnsummon(Seconds(27));
1332 break;
1333 case RP3_EVENT_ARTHAS31:
1334 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS31;
1335 me->SetFacingTo(6.073746f); // @todo
1336 break;
1338 if (Creature* epoch = me->FindNearestCreature(NPC_EPOCH, 100.0f, true))
1339 epoch->SetFacingToObject(me);
1340 break;
1341 case RP3_EVENT_EPOCH1:
1342 talkerEntry = NPC_EPOCH, talkerLine = RP3_LINE_EPOCH1;
1343 break;
1344 case RP3_EVENT_ARTHAS32:
1345 talkerEntry = 0, talkerLine = RP3_LINE_ARTHAS32;
1346 break;
1349 break;
1351 talkerEntry = NPC_EPOCH, talkerLine = RP3_LINE_EPOCH2;
1352 if (Creature* epoch = me->FindNearestCreature(NPC_EPOCH, 100.0f, true))
1353 {
1354 epoch->SetImmuneToAll(false);
1355 me->EngageWithTarget(epoch);
1356 epoch->EngageWithTarget(me);
1357 }
1359 break;
1360 case RP4_EVENT_ARTHAS2:
1361 me->SetFacingTo(0.226893f); // @todo
1362 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS2;
1363 break;
1365 if (GameObject* passage = me->FindNearestGameObject(GO_HIDDEN_PASSAGE, 100.0f))
1366 passage->SetGoState(GO_STATE_ACTIVE);
1367 break;
1368 case RP4_EVENT_ARTHAS3:
1369 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS3;
1371 break;
1375 break;
1378 break;
1379 case RP4_EVENT_ARTHAS11:
1380 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS11;
1381 break;
1383 me->SetFacingTo(1.780236f); // @todo
1384 break;
1385 case RP4_EVENT_ARTHAS12:
1386 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS12;
1387 break;
1390 break;
1391 case RP4_EVENT_ARTHAS13:
1392 talkerEntry = 0, talkerLine = RP4_LINE_ARTHAS13;
1394 break;
1398 break;
1399 case RP5_EVENT_ARTHAS2:
1400 talkerEntry = 0, talkerLine = RP5_LINE_ARTHAS2;
1401 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1402 me->SetFacingToObject(malganis);
1403 break;
1405 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1406 {
1407 malganis->AI()->Talk(RP5_LINE_MALGANIS1, ObjectAccessor::GetUnit(*malganis, _eventStarterGuid));
1408 malganis->SetImmuneToAll(false);
1409 me->EngageWithTarget(malganis);
1410 malganis->EngageWithTarget(me);
1411 }
1413 break;
1415 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1416 {
1417 malganis->SetFacingToObject(me);
1418 malganis->CastSpell(malganis, SPELL_MALGANIS_QUEST_CREDIT, true);
1419 malganis->CastSpell(malganis, SPELL_MALGANIS_KILL_CREDIT, true);
1421 chest->RemoveFlag(GO_FLAG_NOT_SELECTABLE);
1422 }
1435 break;
1437 talkerEntry = NPC_MALGANIS, talkerLine = RP5_LINE_MALGANIS12;
1438 break;
1440 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1441 malganis->CastSpell(malganis, SPELL_SHADOWSTEP_VISUAL);
1442 break;
1443 case RP5_EVENT_ARTHAS10:
1444 if (Creature* malganis = me->FindNearestCreature(NPC_MALGANIS, 100.0f, true))
1445 malganis->DespawnOrUnsummon();
1447 talkerEntry = 0, talkerLine = RP5_LINE_ARTHAS10;
1448 break;
1451 break;
1452 case RP5_EVENT_ARTHAS11:
1453 talkerEntry = 0, talkerLine = RP5_LINE_ARTHAS11;
1454 break;
1457 break;
1460 break;
1463 break;
1466 {
1467 chromie->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
1468 std::function<void(Movement::MoveSplineInit&)> initializer = [](Movement::MoveSplineInit& init)
1469 {
1470 init.SetFly();
1471 init.SetWalk(true);
1472 init.MovebyPath(ChromieSplinePos);
1473 };
1474 chromie->GetMotionMaster()->LaunchMoveSpline(std::move(initializer), 0, MOTION_PRIORITY_NORMAL, POINT_MOTION_TYPE);
1475 }
1476 break;
1478 if (Creature* chromie = me->FindNearestCreature(NPC_CHROMIE_3, 100.0f, true))
1479 chromie->SetAnimTier(AnimTier::Ground, true);
1480 break;
1482 if (Creature* chromie = me->FindNearestCreature(NPC_CHROMIE_3, 100.0f, true))
1483 {
1484 chromie->CastSpell(chromie, SPELL_CHROMIE_3_TRANSFORM);
1485 chromie->AI()->Talk(RP5_LINE_CHROMIE0);
1486 chromie->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
1487 }
1488 break;
1489 default:
1490 break;
1491 }
1492
1493 if (talkerEntry != UINT_MAX)
1494 {
1495 Creature* talker;
1496 if (talkerEntry)
1497 talker = me->FindNearestCreature(talkerEntry, 100.0f, true);
1498 else
1499 talker = me;
1500 if (talker)
1501 talker->AI()->Talk(talkerLine, ObjectAccessor::GetUnit(*talker, _eventStarterGuid));
1502 }
1503 }
1504 }
1505
1507 {
1508 std::list<Creature*> infinites;
1512 for (Creature* target : infinites)
1513 {
1514 target->SetImmuneToAll(false);
1515 me->EngageWithTarget(target);
1516 target->EngageWithTarget(me);
1517 }
1518 }
1519
1520 static void MoveInfiniteOnSpawn(Creature* infinite, SplineChains chainId)
1521 {
1522 if (std::vector<SplineChainLink> const* chain = sScriptSystemMgr->GetSplineChain(NPC_INFINITE_ADVERSARY, chainId))
1523 infinite->GetMotionMaster()->MoveAlongSplineChain(0, *chain, true);
1524 }
1525
1526 void KilledUnit(Unit* who) override
1527 {
1528 if (who && who->GetEntry() == NPC_RISEN_ZOMBIE)
1529 Talk(LINE_SLAY_ZOMBIE, who);
1530 }
1531
1532 void JustEngagedWith(Unit* who) override
1533 {
1534 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustEngagedWith: RP in progress? '{}'", _progressRP ? "YES" : "NO");
1535 if (_progressRP)
1536 {
1537 _progressRP = false;
1539
1541 if (!_resumeMovement.Empty())
1542 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustEngagedWith: spline chain motion paused");
1543 else
1544 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustEngagedWith: entered combat without pathing, pausing RP regardless");
1545 }
1547 }
1548
1549 void EnterEvadeMode(EvadeReason why) override
1550 {
1551 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::EnterEvadeMode: why = {} ", EnumUtils::ToConstant(why));
1553 }
1554
1555 void JustReachedHome() override
1556 {
1559
1560 _progressRP = true;
1561
1562 if (!_resumeMovement.Empty()) // WP motion was interrupted, resume
1563 {
1564 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustReachedHome: Resuming motion");
1567 }
1568 else
1569 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::JustReachedHome: Back at leash pos, resuming RP");
1570
1571 if (_afterCombat)
1572 {
1575 }
1576 }
1577
1578 void JustDied(Unit* /*killer*/) override
1579 {
1580 // Instance failure: regress back to last stable state
1582 me->DespawnOrUnsummon(5s);
1583 }
1584
1585 void JustAppeared() override
1586 {
1587 _progressRP = true;
1590 }
1591
1593 {
1595 instance->SetGuidData(command, cause->GetGUID());
1596 }
1597
1598 bool OnGossipSelect(Player* player, uint32 /*sender*/, uint32 listId) override
1599 {
1600 uint32 const action = GetGossipActionFor(player, listId);
1601 TC_LOG_TRACE("scripts.cos", "npc_arthas_stratholmeAI::GossipSelect: '{}' selects action '{}' on '{}'", player->GetGUID().ToString(), action, me->GetGUID().ToString());
1602
1608 return true;
1609 }
1610
1611 bool OnGossipHello(Player* /*player*/) override
1612 {
1613 return false;
1614 }
1615
1616 private:
1620 uint32 _exorcismCooldown; // no EventMap entry for this, it's reserved for RP handling
1621
1625 };
1626
1627 CreatureAI* GetAI(Creature* creature) const override
1628 {
1629 return GetCullingOfStratholmeAI<npc_arthas_stratholmeAI>(creature);
1630 }
1631};
1632
1634{
1635 auto itr = ArthasSnapbackPositions.find(state);
1636 if (itr == ArthasSnapbackPositions.end())
1637 itr = ArthasSnapbackPositions.begin();
1638 return *(itr->second.SnapbackPosition);
1639}
1640
1641// Arthas' AI is the one controlling everything, all this AI does is report any movementinforms back to Arthas AI
1643{
1645
1646 void MovementInform(uint32 type, uint32 id) override
1647 {
1648 if (type == POINT_MOTION_TYPE || type == EFFECT_MOTION_TYPE || type == SPLINE_CHAIN_MOTION_TYPE)
1649 if (TempSummon* self = me->ToTempSummon())
1650 ASSERT_NOTNULL(self->GetSummonerCreatureBase())->AI()->MovementInform(type, id);
1651 }
1652};
1653
1654// 50773 - Crusader Strike
1656{
1657 void HandleDummy(SpellEffIndex /*effIndex*/)
1658 {
1659 if (Unit* target = GetHitUnit())
1660 if (target->GetEntry() == NPC_CITIZEN || target->GetEntry() == NPC_RESIDENT)
1661 Unit::Kill(GetCaster(), target);
1662 }
1663
1668};
1669
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:28
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:82
@ DONE
#define TC_LOG_WARN(filterType__, message__,...)
Definition Log.h:187
#define TC_LOG_TRACE(filterType__, message__,...)
Definition Log.h:178
@ 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:1392
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
#define sScriptSystemMgr
uint32 GetGossipActionFor(Player *player, uint32 gossipListId)
SpellEffIndex
@ EFFECT_0
@ EMOTE_ONESHOT_POINT_NO_SHEATHE
@ EMOTE_ONESHOT_EXCLAMATION
@ EMOTE_STATE_COWER
@ EMOTE_ONESHOT_LAUGH
@ EMOTE_ONESHOT_ROAR
@ EMOTE_ONESHOT_RUDE
@ EMOTE_ONESHOT_TALK
@ SPELL_EFFECT_DUMMY
@ GO_FLAG_NOT_SELECTABLE
@ GO_STATE_ACTIVE
@ TRIGGERED_IGNORE_SET_FACING
Will not adjust facing to target (if any)
#define SpellEffectFn(F, I, N)
EvadeReason
ReactStates
@ REACT_DEFENSIVE
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ UNIT_NPC_FLAG_GOSSIP
@ UNIT_NPC_FLAG_QUESTGIVER
@ UNIT_STATE_CASTING
Definition Unit.h:276
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
virtual void JustEngagedWith(Unit *)
Definition CreatureAI.h:101
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
void SetHomePosition(float x, float y, float z, float o)
Definition Creature.h:386
void GetHomePosition(float &x, float &y, float &z, float &ori) const
Definition Creature.h:388
bool HasReactState(ReactStates state) const
Definition Creature.h:176
bool IsEngaged() const override
void SetReactState(ReactStates st)
Definition Creature.h:174
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
void SetImmuneToAll(bool apply) override
Definition Creature.h:181
CreatureAI * AI() const
Definition Creature.h:228
static char const * ToConstant(Enum value)
Definition SmartEnum.h:121
uint32 ExecuteEvent()
Definition EventMap.cpp:77
void Update(uint32 time)
Definition EventMap.h:61
bool Empty() const
Definition EventMap.h:89
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:40
virtual bool SetBossState(uint32 id, EncounterState state)
InstanceMap * instance
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, Milliseconds duration=0ms, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty, SmoothPhasingInfo const *smoothPhasingInfo=nullptr)
Definition Object.cpp:1186
void MoveAlongSplineChain(uint32 pointId, uint16 dbChainId, bool walk)
void ResumeSplineChain(SplineChainResumeInfo const &info)
std::string ToString() const
uint32 GetEntry() const
Definition Object.h:89
Unit * GetCaster() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
static void GetResumeInfo(SplineChainResumeInfo &info, Unit const *owner, Optional< uint32 > id={})
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:160
virtual bool CanAIAttack(Unit const *) const
Definition UnitAI.h:58
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:79
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
void SetVisible(bool x)
Definition Unit.cpp:8768
MotionMaster * GetMotionMaster()
Definition Unit.h:1723
void SetFacingToObject(WorldObject const *object, bool force=true)
Definition Unit.cpp:13307
bool IsAlive() const
Definition Unit.h:1185
void RemoveNpcFlag(NPCFlags flags)
Definition Unit.h:998
TempSummon * ToTempSummon()
Definition Unit.h:1828
void SetNpcFlag(NPCFlags flags)
Definition Unit.h:997
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8494
void SetFacingTo(float const ori, bool force=true)
Definition Unit.cpp:13289
void NearTeleportTo(TeleportLocation const &target, bool casting=false)
Definition Unit.cpp:12958
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
void HandleEmoteCommand(Emote emoteId, Player *target=nullptr, Trinity::IteratorPair< int32 const * > spellVisualKitIds={}, int32 sequenceVariation=0)
Definition Unit.cpp:1657
static void Kill(Unit *attacker, Unit *victim, bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition Unit.cpp:11225
GameObject * FindNearestGameObject(uint32 entry, float range, bool spawnedOnly=true) const
Definition Object.cpp:1539
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:2658
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:1398
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1517
virtual uint32 GetData(uint32) const
Definition ZoneScript.h:99
virtual void SetData(uint32, uint32)
Definition ZoneScript.h:100
virtual void SetGuidData(uint32, ObjectGuid)
Definition ZoneScript.h:92
CreatureAI * GetAI(Creature *creature) const override
@ 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
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
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
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
G3D::Vector3 const ChromieSplinePos[]
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
RPEventLines4
@ RP4_LINE_ARTHAS12
@ RP4_LINE_ARTHAS13
@ RP4_LINE_ARTHAS3
@ RP4_LINE_ARTHAS2
@ RP4_LINE_ARTHAS1
@ RP4_LINE_ARTHAS10
@ RP4_LINE_ARTHAS11
Data
@ DATA_RP_DUMMY_MOVED
float GetExactDist2d(const float x, const float y) const
Definition Position.h:117
float GetExactDist(float x, float y, float z) const
Definition Position.h:129
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
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)