Projekt

Allgemein

Profil

Fehler #5295 » thekal_script.txt

doh - Rushor, 13.01.2017 10:40

 
1
/*
2
 * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
3
 * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
4
 *
5
 * This program is free software; you can redistribute it and/or modify it
6
 * under the terms of the GNU General Public License as published by the
7
 * Free Software Foundation; either version 2 of the License, or (at your
8
 * option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful, but WITHOUT
11
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
 * more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program. If not, see <http://www.gnu.org/licenses/>.
17
 */
18

    
19
/* ScriptData
20
SDName: Boss_Thekal
21
SD%Complete: 95
22
SDComment: Almost finished.
23
SDCategory: Zul'Gurub
24
EndScriptData */
25

    
26
#include "ScriptMgr.h"
27
#include "ScriptedCreature.h"
28
#include "zulgurub.h"
29

    
30
enum Says
31
{
32
    SAY_AGGRO                 = 0,
33
    SAY_DEATH                 = 1
34
};
35

    
36
enum Spells
37
{
38
    SPELL_MORTAL_CLEAVE       = 22859,
39
    SPELL_SILENCE             = 23207,
40
    SPELL_FRENZY              = 23128,
41
    SPELL_FORCE_PUNCH         = 24189,
42
    SPELL_CHARGE              = 24408,
43
    SPELL_ENRAGE              = 23537,
44
    SPELL_SUMMON_TIGERS       = 24183,
45
    SPELL_TIGER_FORM          = 24169,
46
    SPELL_RESURRECT           = 24173,
47

    
48
    // Zealot Lor'Khan Spells
49
    SPELL_SHIELD              = 25020,
50
    SPELL_BLOODLUST           = 24185,
51
    SPELL_GREATER_HEAL        = 24208,
52
    SPELL_DISARM              = 22691,
53

    
54
    // Zealot Zath Spells
55
    SPELL_SWEEPING_STRIKES    = 18765,
56
    SPELL_SINISTER_STRIKE     = 15667,
57
    SPELL_GOUGE               = 24698,
58
    SPELL_KICK                = 15614,
59
    SPELL_BLIND               = 21060
60
};
61

    
62
enum Actions
63
{
64
    ACTION_PREVENT_REVIVE     = 1
65
};
66

    
67
enum Phases
68
{
69
    PHASE_NORMAL              = 1,
70
    PHASE_FAKE_DEATH          = 2,
71
    PHASE_WAITING             = 3,
72
    PHASE_TIGER               = 4
73
};
74

    
75
// abstract base class for faking death
76
struct boss_thekalBaseAI : public ScriptedAI
77
{
78
    boss_thekalBaseAI(Creature* creature) : ScriptedAI(creature)
79
    {
80
        Phase = PHASE_NORMAL;
81
    }
82

    
83
    uint8 Phase;
84

    
85
    virtual void OnFakeingDeath() {}
86
    virtual void OnRevive() {}
87

    
88
    void DamageTaken(Unit* /*killer*/, uint32& damage) override
89
    {
90
        if (damage < me->GetHealth())
91
            return;
92

    
93
        // Prevent glitch if in fake death
94
        if (Phase == PHASE_FAKE_DEATH || Phase == PHASE_WAITING)
95
        {
96
            damage = 0;
97
            return;
98
        }
99

    
100
        // Only init fake in normal phase
101
        if (Phase != PHASE_NORMAL)
102
            return;
103

    
104
        damage = 0;
105

    
106
        me->InterruptNonMeleeSpells(true);
107
        me->SetHealth(0);
108
        me->StopMoving();
109
        me->ClearComboPointHolders();
110
        me->RemoveAllAurasOnDeath();
111
        me->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false);
112
        me->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false);
113
        me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
114
        me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE_PERCENT);
115
        me->RemoveAurasByType(SPELL_AURA_PERIODIC_DAMAGE);
116
        me->RemoveAurasByType(SPELL_AURA_PERIODIC_LEECH);
117
        me->ClearAllReactives();
118
        me->GetMotionMaster()->Clear();
119
        me->GetMotionMaster()->MoveIdle();
120
        me->SetStandState(UNIT_STAND_STATE_DEAD);
121

    
122
        Phase = PHASE_FAKE_DEATH;
123

    
124
        OnFakeingDeath();
125
    }
126

    
127
    void Revive(bool OnlyFlags = false)
128
    {
129
        me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
130
        me->SetStandState(UNIT_STAND_STATE_STAND);
131

    
132
        if (OnlyFlags)
133
            return;
134

    
135
        me->SetHealth(me->GetMaxHealth());
136
        Phase = PHASE_NORMAL;
137

    
138
        DoResetThreat();
139
        Reset();
140

    
141
        // Assume Attack
142
        if (me->GetVictim())
143
            me->GetMotionMaster()->MoveChase(me->GetVictim());
144

    
145
        OnRevive();
146
    }
147

    
148
    void PreventRevive()
149
    {
150
        if (me->IsNonMeleeSpellCast(true))
151
            me->InterruptNonMeleeSpells(true);
152

    
153
        Phase = PHASE_WAITING;
154
    }
155
};
156

    
157
class boss_thekal : public CreatureScript
158
{
159
    public:
160
        boss_thekal() : CreatureScript("boss_thekal") { }
161

    
162
        struct boss_thekalAI : public boss_thekalBaseAI
163
        {
164
            boss_thekalAI(Creature* creature) : boss_thekalBaseAI(creature)
165
            {
166
                instance = creature->GetInstanceScript();
167
            }
168
                            
169
            void Reset() override
170
            {
171
                MortalCleaveTimer     = 4 * IN_MILLISECONDS;
172
                SilenceTimer          = 9 * IN_MILLISECONDS;
173
                FrenzyTimer           = 30 * IN_MILLISECONDS;
174
                ForcePunchTimer       = 4 * IN_MILLISECONDS;
175
                ChargeTimer           = 12 * IN_MILLISECONDS;
176
                EnrageTimer           = 32 * IN_MILLISECONDS;
177
                SummonTigersTimer     = 25 * IN_MILLISECONDS;
178
                ResurrectTimer        = 10 * IN_MILLISECONDS;
179
                Phase                 = PHASE_NORMAL;
180
        
181
                Enraged = false;
182
        
183
                // remove fake death
184
                Revive(true);
185
            }
186
        
187
            void EnterCombat(Unit* /*who*/) override
188
            {
189
                Talk(SAY_AGGRO);
190
            }
191
        
192
            void JustDied(Unit* /*killer*/) override
193
            {
194
                Talk(SAY_DEATH);
195
        
196
                instance->SetBossState(DATA_THEKAL, DONE);
197
        
198
                // remove the two adds
199
                Unit* Lorkhan = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_LORKHAN));
200
                Unit* pZath = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_ZATH));
201
        
202
                if (!Lorkhan || !pZath)
203
                    return;
204
                Lorkhan->RemoveFromWorld();
205
                pZath->RemoveFromWorld();
206
            }
207
        
208
            void JustReachedHome() override
209
            {
210
                instance->SetBossState(DATA_THEKAL, FAIL);
211
            }
212

    
213
            void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
214
            {
215
                if (spell->Id == SPELL_RESURRECT)
216
                    Revive();
217
            }
218
        
219
            // Only call in context where m_pInstance is valid
220
            bool CanPreventAddsResurrect()
221
            {
222
                // If any add is alive, return false
223
                if (instance->GetBossState(DATA_ZATH) != SPECIAL || instance->GetBossState(DATA_LORKHAN) != SPECIAL)
224
                    return false;
225
        
226
                // Else Prevent them Resurrecting
227
                if (Creature* pLorkhan = me->FindNearestCreature(NPC_ZEALOT_LORKHAN, 500.0f))
228
                    pLorkhan->AI()->DoAction(ACTION_PREVENT_REVIVE);
229
        
230
                if (Creature* pzath = me->FindNearestCreature(NPC_ZEALOT_ZATH, 500.0f))
231
                    pzath->AI()->DoAction(ACTION_PREVENT_REVIVE);
232
        
233
                return true;
234
            }
235
        
236
            void OnFakeingDeath()
237
            {
238
                ResurrectTimer = 10 * IN_MILLISECONDS;
239
        
240
                if (instance)
241
                {
242
                    instance->SetBossState(DATA_THEKAL, SPECIAL);
243
        
244
                    // If both Adds are already dead, don't wait 10 seconds
245
                    if (CanPreventAddsResurrect())
246
                        ResurrectTimer = 1 * IN_MILLISECONDS;
247
                }
248
            }
249
        
250
            void OnRevive()
251
            {
252
                if (!instance)
253
                    return;
254
        
255
                // Both Adds are 'dead' enter tiger phase
256
                if (CanPreventAddsResurrect())
257
                {
258
                    DoCast(me, SPELL_TIGER_FORM, true);
259
                    Phase = PHASE_TIGER;
260
                }
261
            }
262
        
263
            void UpdateAI(uint32 diff) override
264
            {
265
                if (!UpdateVictim())
266
                    return;
267
        
268
                switch (Phase)
269
                {
270
                    case PHASE_FAKE_DEATH:
271
                        if (ResurrectTimer < diff)
272
                        {
273
                            // resurrect him in any case
274
                            DoCast(me, SPELL_RESURRECT);                        
275
                    
276
                            Phase = PHASE_WAITING;
277
                            if (instance)
278
                            {
279
                                CanPreventAddsResurrect();
280
                                instance->SetBossState(DATA_THEKAL, IN_PROGRESS);
281
                            }
282
                        }
283
                        else
284
                            ResurrectTimer -= diff;
285
                    
286
                        // No break needed here
287
                    case PHASE_WAITING:
288
                        return;
289
                    
290
                    case PHASE_NORMAL:
291
                        if (MortalCleaveTimer < diff)
292
                        {
293
                            DoCastVictim(SPELL_MORTAL_CLEAVE);
294
                            MortalCleaveTimer = urand(15, 20) * IN_MILLISECONDS;
295
                        }
296
                        else
297
                            MortalCleaveTimer -= diff;
298
                    
299
                        if (SilenceTimer < diff)
300
                        {
301
                            DoCastVictim(SPELL_SILENCE, true);
302
                            SilenceTimer = urand(20, 25) * IN_MILLISECONDS;
303
                        }
304
                        else
305
                            SilenceTimer -= diff;
306
                    
307
                        break;
308
                    case PHASE_TIGER:
309
                        if (ChargeTimer < diff)
310
                        {
311
                            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
312
                            {
313
                                DoCast(target, SPELL_CHARGE);
314
                                DoResetThreat();
315
                                AttackStart(target);
316
                            }
317
                            ChargeTimer = urand(15, 22) * IN_MILLISECONDS;
318
                        }
319
                        else
320
                            ChargeTimer -= diff;
321
                    
322
                        if (FrenzyTimer < diff)
323
                        {
324
                            DoCast(me, SPELL_FRENZY, true);
325
                            FrenzyTimer = 30 * IN_MILLISECONDS;
326
                        }
327
                        else
328
                            FrenzyTimer -= diff;
329
                    
330
                        if (ForcePunchTimer < diff)
331
                        {
332
                            DoCast(me, SPELL_FORCE_PUNCH);
333
                            ForcePunchTimer = urand(16, 21) * IN_MILLISECONDS;
334
                        }
335
                        else
336
                            ForcePunchTimer -= diff;
337
                    
338
                        if (SummonTigersTimer < diff)
339
                        {
340
                            DoCast(me, SPELL_SUMMON_TIGERS);
341
                            SummonTigersTimer = 50 * IN_MILLISECONDS;
342
                        }
343
                        else
344
                            SummonTigersTimer -= diff;
345
                    
346
                        if (!Enraged && !HealthAbovePct(11))
347
                        {
348
                            DoCast(me, SPELL_ENRAGE);
349
                            Enraged = true;
350
                        }
351
                    
352
                        break;
353
                }
354
        
355
                DoMeleeAttackIfReady();
356
            }
357

    
358
            private:
359
                InstanceScript* instance;
360

    
361
                uint32 MortalCleaveTimer;
362
                uint32 SilenceTimer;
363
                uint32 FrenzyTimer;
364
                uint32 ForcePunchTimer;
365
                uint32 ChargeTimer;
366
                uint32 EnrageTimer;
367
                uint32 SummonTigersTimer;
368
                uint32 ResurrectTimer;
369

    
370
                bool Enraged;
371
        };
372

    
373
        CreatureAI* GetAI(Creature* creature) const override
374
        {
375
            return GetInstanceAI<boss_thekalAI>(creature);
376
        }
377
};
378

    
379
/*######
380
## npc_zealot_lorkhan
381
######*/
382

    
383
class npc_zealot_lorkhan : public CreatureScript
384
{
385
    public:
386
        npc_zealot_lorkhan() : CreatureScript("npc_zealot_lorkhan") { }
387

    
388
        struct npc_zealot_lorkhanAI : public boss_thekalBaseAI
389
        {
390
            npc_zealot_lorkhanAI(Creature* creature) : boss_thekalBaseAI(creature)
391
            {
392
                instance = creature->GetInstanceScript();
393
            }
394
                            
395
            void Reset() override
396
            {
397
                ShieldTimer      = 1 * IN_MILLISECONDS;
398
                BloodLustTimer   = 16 * IN_MILLISECONDS;
399
                GreaterHealTimer = 32 * IN_MILLISECONDS;
400
                DisarmTimer      = 6 * IN_MILLISECONDS;
401
                Phase            = PHASE_NORMAL;
402
        
403
                instance->SetBossState(DATA_LORKHAN, NOT_STARTED);
404
        
405
                Revive(true);
406
            }
407
        
408
            void EnterCombat(Unit* /*who*/) override
409
            {
410
                instance->SetBossState(DATA_LORKHAN, IN_PROGRESS);
411
            }
412
        
413
            void OnFakeingDeath()
414
            {
415
                ResurrectTimer = 10 * IN_MILLISECONDS;
416
                instance->SetBossState(DATA_LORKHAN, SPECIAL);
417
            }
418

    
419
            void DoAction(int32 actionId) override
420
            {
421
                if (actionId == ACTION_PREVENT_REVIVE)
422
                {
423
                    if (me->IsNonMeleeSpellCast(true))
424
                        me->InterruptNonMeleeSpells(true);
425

    
426
                    Phase = PHASE_WAITING;
427
                }
428
            }
429

    
430
            void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
431
            {
432
                if (spell->Id == SPELL_RESURRECT)
433
                    Revive();
434
            }
435
        
436
            void UpdateAI(uint32 diff) override
437
            {
438
                if (!UpdateVictim())
439
                    return;
440
        
441
                switch (Phase)
442
                {
443
                    case PHASE_FAKE_DEATH:
444
                        if (ResurrectTimer < diff)
445
                        {
446
                            if (instance->GetBossState(DATA_THEKAL) != SPECIAL || instance->GetBossState(DATA_ZATH) != SPECIAL)
447
                            {
448
                                DoCast(me, SPELL_RESURRECT);
449
                                instance->SetBossState(DATA_LORKHAN, IN_PROGRESS);
450
                            }
451
                    
452
                            Phase = PHASE_WAITING;
453
                        }
454
                        else
455
                            ResurrectTimer -= diff;
456
                    
457
                        // no break needed here
458
                    case PHASE_WAITING:
459
                        return;
460
                    
461
                    case PHASE_NORMAL:
462
                        // Shield_Timer
463
                        if (ShieldTimer < diff)
464
                        {
465
                            DoCast(me, SPELL_SHIELD);
466
                            ShieldTimer = 61 * IN_MILLISECONDS;
467
                        }
468
                        else
469
                            ShieldTimer -= diff;
470
                    
471
                        // BloodLust_Timer
472
                        if (BloodLustTimer < diff)
473
                        {
474
                            // ToDo: research if this should be cast on Thekal or Zath
475
                            DoCast(me, SPELL_BLOODLUST);
476
                            BloodLustTimer = urand(20, 28) * IN_MILLISECONDS;
477
                        }
478
                        else
479
                            BloodLustTimer -= diff;
480
                    
481
                        // Casting Greaterheal to Thekal or Zath if they are in meele range.
482
                        // TODO - why this range check?
483
                        if (GreaterHealTimer < diff)
484
                        {
485
                            if (instance)
486
                            {
487
                                Unit* pThekal = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_THEKAL));
488
                                Unit* pZath = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_ZATH));
489
                    
490
                                if (!pThekal || !pZath)
491
                                    return;
492
                    
493
                                switch (urand(0, 1))
494
                                {
495
                                    case 0:
496
                                        if (me->IsWithinMeleeRange(pThekal))
497
                                            DoCast(pThekal, SPELL_GREATER_HEAL);
498
                                        break;
499
                                    case 1:
500
                                        if (me->IsWithinMeleeRange(pZath))
501
                                            DoCast(pZath, SPELL_GREATER_HEAL);
502
                                        break;
503
                                }
504
                            }
505
                    
506
                            GreaterHealTimer = urand(15, 20) * IN_MILLISECONDS;
507
                        }
508
                        else
509
                            GreaterHealTimer -= diff;
510
                      
511
                        // Disarm_Timer
512
                        if (DisarmTimer < diff)
513
                        {
514
                            DoCastVictim(SPELL_DISARM);
515
                            DisarmTimer = urand(15, 25) * IN_MILLISECONDS;
516
                        }
517
                        else
518
                            DisarmTimer -= diff;
519
                    
520
                        break;
521
                }
522
        
523
                DoMeleeAttackIfReady();
524
            }
525

    
526
            private:
527
                InstanceScript* instance;
528

    
529
                uint32 ShieldTimer;
530
                uint32 BloodLustTimer;
531
                uint32 GreaterHealTimer;
532
                uint32 DisarmTimer;
533
                uint32 ResurrectTimer;
534
        };
535

    
536
        CreatureAI* GetAI(Creature* creature) const override
537
        {
538
            return GetInstanceAI<npc_zealot_lorkhanAI>(creature);
539
        }
540
};
541

    
542
/*######
543
## npc_zealot_zath
544
######*/
545

    
546
class npc_zealot_zath : public CreatureScript
547
{
548
    public:
549
        npc_zealot_zath() : CreatureScript("npc_zealot_zath") { }
550

    
551
        struct npc_zealot_zathAI : public boss_thekalBaseAI
552
        {
553
            npc_zealot_zathAI(Creature* creature) : boss_thekalBaseAI(creature)
554
            {
555
                instance = creature->GetInstanceScript();
556
            }
557
                            
558
            void Reset() override
559
            {
560
                SweepingStrikesTimer = 13 * IN_MILLISECONDS;
561
                SinisterStrikeTimer  = 8 * IN_MILLISECONDS;
562
                GougeTimer           = 25 * IN_MILLISECONDS;
563
                KickTimer            = 18 * IN_MILLISECONDS;
564
                BlindTimer           = 5 * IN_MILLISECONDS;
565
                Phase                = PHASE_NORMAL;
566
        
567
                instance->SetBossState(DATA_ZATH, NOT_STARTED);
568
        
569
                Revive(true);
570
            }
571
        
572
            void EnterCombat(Unit* /*who*/) override
573
            {
574
                instance->SetBossState(DATA_ZATH, IN_PROGRESS);
575
            }
576
        
577
            void OnFakeingDeath()
578
            {
579
                ResurrectTimer = 10 * IN_MILLISECONDS;
580
        
581
                instance->SetBossState(DATA_ZATH, SPECIAL);
582
            }
583

    
584
            void DoAction(int32 actionId) override
585
            {
586
                if (actionId == ACTION_PREVENT_REVIVE)
587
                {
588
                    if (me->IsNonMeleeSpellCast(true))
589
                        me->InterruptNonMeleeSpells(true);
590

    
591
                    Phase = PHASE_WAITING;
592
                }
593
            }
594

    
595
            void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) override
596
            {
597
                if (spell->Id == SPELL_RESURRECT)
598
                    Revive();
599
            }
600
        
601
            void UpdateAI(uint32 diff) override
602
            {
603
                if (!UpdateVictim())
604
                    return;
605
        
606
                switch (Phase)
607
                {
608
                    case PHASE_FAKE_DEATH:
609
                        if (ResurrectTimer < diff)
610
                        {
611
                            if (instance->GetBossState(DATA_THEKAL) != SPECIAL || instance->GetBossState(DATA_LORKHAN) != SPECIAL)
612
                            {
613
                                DoCast(me, SPELL_RESURRECT);
614
                                instance->SetBossState(DATA_ZATH, IN_PROGRESS);
615
                            }
616
                    
617
                            Phase = PHASE_WAITING;
618
                        }
619
                        else
620
                            ResurrectTimer -= diff;
621
                    
622
                        // no break needed here
623
                    case PHASE_WAITING:
624
                        return;
625
                    
626
                    case PHASE_NORMAL:
627
                        // SweepingStrikes_Timer
628
                        if (SweepingStrikesTimer < diff)
629
                        {
630
                            DoCastVictim(SPELL_SWEEPING_STRIKES);
631
                            SweepingStrikesTimer = urand(22, 26) * IN_MILLISECONDS;
632
                        }
633
                        else
634
                            SweepingStrikesTimer -= diff;
635
                    
636
                        // SinisterStrike_Timer
637
                        if (SinisterStrikeTimer < diff)
638
                        {
639
                            DoCastVictim(SPELL_SINISTER_STRIKE);
640
                            SinisterStrikeTimer = urand(8, 16) * IN_MILLISECONDS;
641
                        }
642
                        else
643
                            SinisterStrikeTimer -= diff;
644
                    
645
                        // Gouge_Timer
646
                        if (GougeTimer < diff)
647
                        {
648
                            DoCastVictim(SPELL_GOUGE);
649
                    
650
                            if (DoGetThreat(me->GetVictim()))
651
                                DoModifyThreatPercent(me->GetVictim(), -100);
652
                    
653
                            GougeTimer = urand(17, 27) * IN_MILLISECONDS;
654
                        }
655
                        else
656
                            GougeTimer -= diff;
657
                    
658
                        // Kick_Timer
659
                        if (KickTimer < diff)
660
                        {
661
                            DoCastVictim(SPELL_KICK);
662
                            KickTimer = urand(15, 25) * IN_MILLISECONDS;
663
                        }
664
                        else
665
                            KickTimer -= diff;
666
                    
667
                        // Blind_Timer
668
                        if (BlindTimer < diff)
669
                        {
670
                            DoCastVictim(SPELL_BLIND);
671
                            BlindTimer = urand(10, 20) * IN_MILLISECONDS;
672
                        }
673
                        else
674
                            BlindTimer -= diff;
675
                    
676
                        break;
677
                }
678
        
679
                DoMeleeAttackIfReady();
680
            }
681

    
682
            private:
683
                uint32 SweepingStrikesTimer;
684
                uint32 SinisterStrikeTimer;
685
                uint32 GougeTimer;
686
                uint32 KickTimer;
687
                uint32 BlindTimer;
688
                uint32 ResurrectTimer;
689

    
690
                InstanceScript* instance;
691
        };
692

    
693
        CreatureAI* GetAI(Creature* creature) const override
694
        {
695
            return GetInstanceAI<npc_zealot_zathAI>(creature);
696
        }
697
};
698

    
699
void AddSC_boss_thekal()
700
{
701
    new boss_thekal();
702
    new npc_zealot_lorkhan();
703
    new npc_zealot_zath();
704
}
    (1-1/1)