Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_professor_putricide.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "ObjectMgr.h"
7#include "ScriptMgr.h"
8#include "ScriptedCreature.h"
9#include "SpellAuraEffects.h"
10#include "Group.h"
11#include "Spell.h"
12#include "icecrown_citadel.h"
13#include "Vehicle.h"
14#include "GridNotifiers.h"
15
16enum Say
17{
18 // Festergut
21
22 // Rotface
25
26 // Professor Putricide
31 SAY_TRANSFORM_2 = 8, // always used for phase2 change, DO NOT GROUP WITH SAY_TRANSFORM_1
37};
38
40{
41 // Festergut
48
49 // Professor Putricide
53 SPELL_TEAR_GAS = 71617, // phase transition
59 SPELL_OOZE_TANK_PROTECTION = 71770, // protects the tank
69
70 // Slime Puddle
72 SPELL_GROW = 70347,
74
75 // Gas Cloud
80
81 // Volatile Ooze
86
87 // Choking Gas Bomb
90
91 // Mutated Abomination vehicle
96
97 // Unholy Infusion
99};
100
101#define SPELL_GASEOUS_BLOAT_HELPER RAID_MODE<uint32>(70672, 72455, 72832, 72833)
102
104{
105 // Festergut
108
109 // Rotface
112
113 // Professor Putricide
114 EVENT_BERSERK = 6, // all phases
115 EVENT_SLIME_PUDDLE = 7, // all phases
117 EVENT_TEAR_GAS = 9, // phase transition not heroic
124};
125
135
137{
140 POINT_TABLE = 366780
141};
142
143Position const festergutWatchPos = {4324.820f, 3166.03f, 389.3831f, 3.316126f}; //emote 432 (release gas)
144Position const rotfaceWatchPos = {4390.371f, 3164.50f, 389.3890f, 5.497787f}; //emote 432 (release ooze)
145Position const tablePos = {4356.190f, 3262.90f, 389.4820f, 1.483530f};
146
147// used in Rotface encounter
148uint32 const oozeFloodSpells[4] = {69782, 69796, 69798, 69801};
149
156
157#define EXPERIMENT_STATE_OOZE false
158#define EXPERIMENT_STATE_GAS true
159
161{
162 public:
163 explicit AbominationDespawner(Unit* owner) : _owner(owner) { }
164
166 {
167 if (Unit* summon = ObjectAccessor::GetUnit(*_owner, guid))
168 {
169 if (summon->GetEntry() == NPC_MUTATED_ABOMINATION_10 || summon->GetEntry() == NPC_MUTATED_ABOMINATION_25)
170 {
171 if (Vehicle* veh = summon->GetVehicleKit())
172 veh->RemoveAllPassengers(); // also despawns the vehicle
173
174 // Found unit is Mutated Abomination, remove it
175 return true;
176 }
177
178 // Found unit is not Mutated Abomintaion, leave it
179 return false;
180 }
181
182 // No unit found, remove from SummonList
183 return true;
184 }
185
186 private:
188};
189
191{
192 RotfaceHeightCheck(Creature* rotface) : _rotface(rotface) { }
193
194 bool operator()(Creature* stalker) const
195 {
196 return stalker->GetPositionZ() < _rotface->GetPositionZ() + 5.0f;
197 }
198
199private:
201};
202
204{
205 public:
206 boss_professor_putricide() : CreatureScript("boss_professor_putricide") { }
207
209 {
215
217 {
218 if (!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)))
220 instance->SetData(DATA_NAUSEA_ACHIEVEMENT, uint32(true));
221
222 events.Reset();
223 summons.DespawnAll();
226 me->SetReactState(REACT_DEFENSIVE);
227 me->SetWalk(false);
228 if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() == POINT_MOTION_TYPE)
229 me->GetMotionMaster()->MovementExpired();
230
231 if (instance->GetBossState(DATA_ROTFACE) == DONE && instance->GetBossState(DATA_FESTERGUT) == DONE)
233 }
234
236 {
237 if (events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT))
238 return;
239
240 if (!instance->CheckRequiredBosses(DATA_PROFESSOR_PUTRICIDE, who->ToPlayer()))
241 {
243 instance->DoCastSpellOnPlayers(LIGHT_S_HAMMER_TELEPORT);
244 return;
245 }
246
247 me->setActive(true);
248 events.Reset();
249 events.ScheduleEvent(EVENT_BERSERK, 600000);
250 events.ScheduleEvent(EVENT_SLIME_PUDDLE, 10000);
251 events.ScheduleEvent(EVENT_UNSTABLE_EXPERIMENT, std::rand() % 35000 + 30000);
252 if (IsHeroic())
253 events.ScheduleEvent(EVENT_UNBOUND_PLAGUE, 20000);
254
259
261 }
262
264 {
266 me->SetWalk(false);
267 if (events.IsInPhase(PHASE_COMBAT_1) || events.IsInPhase(PHASE_COMBAT_2) || events.IsInPhase(PHASE_COMBAT_3))
268 instance->SetBossState(DATA_PROFESSOR_PUTRICIDE, FAIL);
269 }
270
272 {
273 if (victim->GetTypeId() == TypeID::TYPEID_PLAYER)
274 Talk(SAY_KILL);
275 }
276
277 void JustDied(Unit* /*killer*/) OVERRIDE
278 {
279 _JustDied();
281
282 if (Is25ManRaid() && me->HasAura(SPELL_SHADOWS_FATE))
284
286 }
287
289 {
290 summons.Summon(summon);
291 switch (summon->GetEntry())
292 {
295 return;
297 summon->CastSpell(summon, SPELL_GROW_STACKER, true);
298 summon->CastSpell(summon, SPELL_SLIME_PUDDLE_AURA, true);
299 // blizzard casts this spell 7 times initially (confirmed in sniff)
300 for (uint8 i = 0; i < 7; ++i)
301 summon->CastSpell(summon, SPELL_GROW, true);
302 break;
303 case NPC_GAS_CLOUD:
304 // no possible aura seen in sniff adding the aurastate
305 summon->ModifyAuraState(AURA_STATE_UNKNOWN22, true);
306 summon->CastSpell(summon, SPELL_GASEOUS_BLOAT_PROC, true);
307 summon->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
308 summon->SetReactState(REACT_PASSIVE);
309 break;
311 // no possible aura seen in sniff adding the aurastate
312 summon->ModifyAuraState(AURA_STATE_UNKNOWN19, true);
313 summon->CastSpell(summon, SPELL_OOZE_ERUPTION_SEARCH_PERIODIC, true);
314 summon->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
315 summon->SetReactState(REACT_PASSIVE);
316 break;
318 summon->CastSpell(summon, SPELL_CHOKING_GAS_BOMB_PERIODIC, true);
319 summon->CastSpell(summon, SPELL_CHOKING_GAS_EXPLOSION_TRIGGER, true);
320 return;
323 return;
324 default:
325 break;
326 }
327
328 if (me->IsInCombat())
329 DoZoneInCombat(summon);
330 }
331
332 void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/) OVERRIDE
333 {
334 switch (_phase)
335 {
336 case PHASE_COMBAT_1:
337 if (HealthAbovePct(80))
338 return;
339 me->SetReactState(REACT_PASSIVE);
341 break;
342 case PHASE_COMBAT_2:
343 if (HealthAbovePct(35))
344 return;
345 me->SetReactState(REACT_PASSIVE);
347 break;
348 default:
349 break;
350 }
351 }
352
354 {
355 if (type != POINT_MOTION_TYPE)
356 return;
357 switch (id)
358 {
359 case POINT_FESTERGUT:
360 instance->SetBossState(DATA_FESTERGUT, IN_PROGRESS); // needed here for delayed gate close
361 me->SetSpeed(MOVE_RUN, _baseSpeed, true);
363 if (Creature* festergut = Unit::GetCreature(*me, instance->GetData64(DATA_FESTERGUT)))
364 festergut->CastSpell(festergut, SPELL_GASEOUS_BLIGHT_LARGE, false, NULL, NULL, festergut->GetGUID());
365 break;
366 case POINT_ROTFACE:
367 instance->SetBossState(DATA_ROTFACE, IN_PROGRESS); // needed here for delayed gate close
368 me->SetSpeed(MOVE_RUN, _baseSpeed, true);
370 events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000, 0, PHASE_ROTFACE);
371 break;
372 case POINT_TABLE:
373 // stop attack
374 me->GetMotionMaster()->MoveIdle();
375 me->SetSpeed(MOVE_RUN, _baseSpeed, true);
377 me->SetFacingToObject(table);
378 // operating on new phase already
379 switch (_phase)
380 {
381 case PHASE_COMBAT_2:
382 {
383 SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_CREATE_CONCOCTION);
385 events.ScheduleEvent(EVENT_PHASE_TRANSITION, sSpellMgr->GetSpellForDifficultyFromSpell(spell, me)->CalcCastTime() + 100);
386 break;
387 }
388 case PHASE_COMBAT_3:
389 {
390 SpellInfo const* spell = sSpellMgr->GetSpellInfo(SPELL_GUZZLE_POTIONS);
392 events.ScheduleEvent(EVENT_PHASE_TRANSITION, sSpellMgr->GetSpellForDifficultyFromSpell(spell, me)->CalcCastTime() + 100);
393 break;
394 }
395 default:
396 break;
397 }
398 break;
399 default:
400 break;
401 }
402 }
403
405 {
406 switch (action)
407 {
410 me->SetSpeed(MOVE_RUN, _baseSpeed*2.0f, true);
411 me->GetMotionMaster()->MovePoint(POINT_FESTERGUT, festergutWatchPos);
412 me->SetReactState(REACT_PASSIVE);
414 if (IsHeroic())
415 events.ScheduleEvent(EVENT_FESTERGUT_GOO, std::rand() % 18000 + 13000, 0, PHASE_FESTERGUT);
416 break;
420 break;
422 events.ScheduleEvent(EVENT_FESTERGUT_DIES, 4000, 0, PHASE_FESTERGUT);
423 break;
425 {
427 me->SetSpeed(MOVE_RUN, _baseSpeed*2.0f, true);
428 me->GetMotionMaster()->MovePoint(POINT_ROTFACE, rotfaceWatchPos);
429 me->SetReactState(REACT_PASSIVE);
430 _oozeFloodStage = 0;
432 // init random sequence of floods
433 if (Creature* rotface = Unit::GetCreature(*me, instance->GetData64(DATA_ROTFACE)))
434 {
435 std::list<Creature*> list;
437 list.remove_if(RotfaceHeightCheck(rotface));
438 if (list.size() > 4)
439 {
440 list.sort(Skyfire::ObjectDistanceOrderPred(rotface));
441 do
442 {
443 list.pop_back();
444 } while (list.size() > 4);
445 }
446
447 uint8 i = 0;
448 while (!list.empty())
449 {
450 std::list<Creature*>::iterator itr = list.begin();
451 std::advance(itr, std::rand() % (list.size()-1));
452 _oozeFloodDummyGUIDs[i++] = (*itr)->GetGUID();
453 list.erase(itr);
454 }
455 }
456 break;
457 }
461 dummy->CastSpell(dummy, oozeFloodSpells[_oozeFloodStage], true, NULL, NULL, me->GetGUID()); // cast from self for LoS (with prof's GUID for logs)
462 if (++_oozeFloodStage == 4)
463 _oozeFloodStage = 0;
464 break;
466 events.ScheduleEvent(EVENT_ROTFACE_DIES, 4500, 0, PHASE_ROTFACE);
467 break;
469 me->SetSpeed(MOVE_RUN, _baseSpeed*2.0f, true);
470 events.DelayEvents(30000);
471 me->AttackStop();
472 if (!IsHeroic())
473 {
475 events.ScheduleEvent(EVENT_TEAR_GAS, 2500);
476 }
477 else
478 {
482 // cast variables
483 if (Is25ManRaid())
484 {
485 std::list<Unit*> targetList;
486 {
487 const std::list<HostileReference*>& threatlist = me->getThreatManager().getThreatList();
488 for (std::list<HostileReference*>::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
489 if ((*itr)->getTarget()->GetTypeId() == TypeID::TYPEID_PLAYER)
490 targetList.push_back((*itr)->getTarget());
491 }
492
493 size_t half = targetList.size()/2;
494 // half gets ooze variable
495 while (half < targetList.size())
496 {
497 std::list<Unit*>::iterator itr = targetList.begin();
498 advance(itr, std::rand() % (targetList.size() - 1));
499 (*itr)->CastSpell(*itr, SPELL_OOZE_VARIABLE, true);
500 targetList.erase(itr);
501 }
502 // and half gets gas
503 for (std::list<Unit*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
504 (*itr)->CastSpell(*itr, SPELL_GAS_VARIABLE, true);
505 }
506 me->GetMotionMaster()->MovePoint(POINT_TABLE, tablePos);
507 }
508 switch (_phase)
509 {
510 case PHASE_COMBAT_1:
512 events.ScheduleEvent(EVENT_MALLEABLE_GOO, std::rand() % 26000 + 21000);
513 events.ScheduleEvent(EVENT_CHOKING_GAS_BOMB, std::rand() % 40000 + 35000);
514 break;
515 case PHASE_COMBAT_2:
517 events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 25000);
519 break;
520 default:
521 break;
522 }
523 break;
524 default:
525 break;
526 }
527 }
528
530 {
531 switch (type)
532 {
534 return _experimentState;
535 case DATA_PHASE:
536 return _phase;
537 case DATA_ABOMINATION:
539 default:
540 break;
541 }
542
543 return 0;
544 }
545
547 {
548 if (id == DATA_EXPERIMENT_STAGE)
549 _experimentState = bool(data);
550 }
551
553 {
554 if ((!(events.IsInPhase(PHASE_ROTFACE) || events.IsInPhase(PHASE_FESTERGUT)) && !UpdateVictim()) || !CheckInRoom())
555 return;
556
557 events.Update(diff);
558
559 if (me->HasUnitState(UNIT_STATE_CASTING))
560 return;
561
562 while (uint32 eventId = events.ExecuteEvent())
563 {
564 switch (eventId)
565 {
569 break;
571 me->CastCustomSpell(SPELL_MALLEABLE_GOO_SUMMON, SPELLVALUE_MAX_TARGETS, 1, NULL, true);
572 events.ScheduleEvent(EVENT_FESTERGUT_GOO, (Is25ManRaid() ? 10000 : 30000) + std::rand() % 5000, 0, PHASE_FESTERGUT);
573 break;
577 break;
580 events.ScheduleEvent(EVENT_ROTFACE_OOZE_FLOOD, 25000, 0, PHASE_ROTFACE);
581 break;
582 case EVENT_BERSERK:
585 break;
587 {
588 std::list<Unit*> targets;
589 SelectTargetList(targets, 2, SELECT_TARGET_RANDOM, 0.0f, true);
590 if (!targets.empty())
591 for (std::list<Unit*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
593 events.ScheduleEvent(EVENT_SLIME_PUDDLE, 35000);
594 break;
595 }
599 events.ScheduleEvent(EVENT_UNSTABLE_EXPERIMENT, std::rand() % 40000 + 35000);
600 break;
601 case EVENT_TEAR_GAS:
602 me->GetMotionMaster()->MovePoint(POINT_TABLE, tablePos);
604 break;
606 me->SetReactState(REACT_DEFENSIVE);
607 AttackStart(me->GetVictim());
608 // remove Tear Gas
609 me->RemoveAurasDueToSpell(SPELL_TEAR_GAS_PERIODIC_TRIGGER);
610 instance->DoRemoveAurasDueToSpellOnPlayers(71615);
612 instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_GAS_VARIABLE);
613 instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_OOZE_VARIABLE);
614 break;
616 if (Is25ManRaid())
617 {
618 std::list<Unit*> targets;
619 SelectTargetList(targets, 2, SELECT_TARGET_RANDOM, -7.0f, true);
620 if (!targets.empty())
621 {
623 for (std::list<Unit*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
625 }
626 }
627 else
628 {
629 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, -7.0f, true))
630 {
633 }
634 }
635 events.ScheduleEvent(EVENT_MALLEABLE_GOO, std::rand() % 30000 + 25000);
636 break;
640 events.ScheduleEvent(EVENT_CHOKING_GAS_BOMB, std::rand() % 40000 + 35000);
641 break;
644 {
647 }
648 events.ScheduleEvent(EVENT_UNBOUND_PLAGUE, 90000);
649 break;
652 events.ScheduleEvent(EVENT_MUTATED_PLAGUE, 10000);
653 break;
655 {
656 switch (_phase)
657 {
658 case PHASE_COMBAT_2:
659 if (Creature* face = me->FindNearestCreature(NPC_TEAR_GAS_TARGET_STALKER, 50.0f))
660 me->SetFacingToObject(face);
661 me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
663 events.ScheduleEvent(EVENT_RESUME_ATTACK, 5500, 0, PHASE_COMBAT_2);
664 break;
665 case PHASE_COMBAT_3:
666 if (Creature* face = me->FindNearestCreature(NPC_TEAR_GAS_TARGET_STALKER, 50.0f))
667 me->SetFacingToObject(face);
668 me->HandleEmoteCommand(EMOTE_ONESHOT_KNEEL);
670 summons.DespawnIf(AbominationDespawner(me));
671 events.ScheduleEvent(EVENT_RESUME_ATTACK, 8500, 0, PHASE_COMBAT_3);
672 break;
673 default:
674 break;
675 }
676 }
677 default:
678 break;
679 }
680 }
681
683 }
684
685 private:
686 void SetPhase(Phases newPhase)
687 {
688 _phase = newPhase;
689 events.SetPhase(newPhase);
690 }
691
693 Phases _phase; // external of EventMap because event phase gets reset on evade
694 float const _baseSpeed;
697 };
698
700 {
702 }
703};
704
706{
707 public:
708 npc_putricide_oozeAI(Creature* creature, uint32 hitTargetSpellId) : ScriptedAI(creature),
709 _hitTargetSpellId(hitTargetSpellId), _newTargetSelectTimer(0)
710 {
711 }
712
713 void SpellHitTarget(Unit* /*target*/, SpellInfo const* spell) OVERRIDE
714 {
715 if (!_newTargetSelectTimer && spell->Id == sSpellMgr->GetSpellIdForDifficulty(_hitTargetSpellId, me))
717 }
718
719 void SpellHit(Unit* /*caster*/, SpellInfo const* spell) OVERRIDE
720 {
721 if (spell->Id == SPELL_TEAR_GAS_CREATURE)
723 }
724
726 {
728 return;
729
730 if (!_newTargetSelectTimer && !me->IsNonMeleeSpellCasted(false, false, true, false, true))
732
734
736 return;
737
738 if (me->HasAura(SPELL_TEAR_GAS_CREATURE))
739 return;
740
741 if (_newTargetSelectTimer <= diff)
742 {
745 }
746 else
747 _newTargetSelectTimer -= diff;
748 }
749
750 virtual void CastMainSpell() = 0;
751
752 private:
755};
756
758{
759 public:
760 npc_volatile_ooze() : CreatureScript("npc_volatile_ooze") { }
761
763 {
767
769 {
770 me->CastSpell(me, SPELL_VOLATILE_OOZE_ADHESIVE, false);
771 }
772 };
773
775 {
777 }
778};
779
781{
782 public:
783 npc_gas_cloud() : CreatureScript("npc_gas_cloud") { }
784
786 {
791
793 {
794 me->CastCustomSpell(SPELL_GASEOUS_BLOAT, SPELLVALUE_AURA_STACK, 10, me, false);
795 }
796
797 private:
799 };
800
802 {
804 }
805};
806
808{
809 public:
810 spell_putricide_gaseous_bloat() : SpellScriptLoader("spell_putricide_gaseous_bloat") { }
811
832
837};
838
840{
841 public:
842 spell_putricide_ooze_channel() : SpellScriptLoader("spell_putricide_ooze_channel") { }
843
845 {
847
848 bool Validate(SpellInfo const* spell) OVERRIDE
849 {
850 if (!spell->ExcludeTargetAuraSpell)
851 return false;
852 if (!sSpellMgr->GetSpellInfo(spell->ExcludeTargetAuraSpell))
853 return false;
854 return true;
855 }
856
857 // set up initial variables and check if caster is creature
858 // this will let use safely use ToCreature() casts in entire script
860 {
861 _target = NULL;
863 }
864
865 void SelectTarget(std::list<WorldObject*>& targets)
866 {
867 if (targets.empty())
868 {
870 GetCaster()->ToCreature()->DespawnOrUnsummon(1); // despawn next update
871 return;
872 }
873
875 targets.clear();
876 targets.push_back(target);
877 _target = target;
878 }
879
880 void SetTarget(std::list<WorldObject*>& targets)
881 {
882 targets.clear();
883 if (_target)
884 targets.push_back(_target);
885 }
886
888 {
892 GetCaster()->AddThreat(GetHitUnit(), 500000000.0f); // value seen in sniff
893 }
894
902
904 };
905
910};
911
913{
914 public:
915 ExactDistanceCheck(Unit* source, float dist) : _source(source), _dist(dist) { }
916
917 bool operator()(WorldObject* unit) const
918 {
919 return _source->GetExactDist2d(unit) > _dist;
920 }
921
922 private:
924 float _dist;
925};
926
953
954// this is here only because on retail you dont actually enter HEROIC mode for ICC
956{
957 public:
958 spell_putricide_slime_puddle_aura() : SpellScriptLoader("spell_putricide_slime_puddle_aura") { }
959
961 {
963
965 {
966 if (Unit* target = GetHitUnit())
967 GetCaster()->AddAura((GetCaster()->GetMap()->GetSpawnMode() & 1) ? 72456 : 70346, target);
968 }
969
974 };
975
980};
981
983{
984 public:
985 spell_putricide_unstable_experiment() : SpellScriptLoader("spell_putricide_unstable_experiment") { }
986
988 {
990
992 {
993 PreventHitDefaultEffect(effIndex);
994 if (GetCaster()->GetTypeId() != TypeID::TYPEID_UNIT)
995 return;
996
997 Creature* creature = GetCaster()->ToCreature();
998
999 uint32 stage = creature->AI()->GetData(DATA_EXPERIMENT_STAGE);
1000 creature->AI()->SetData(DATA_EXPERIMENT_STAGE, stage ^ true);
1001
1002 Creature* target = NULL;
1003 std::list<Creature*> creList;
1005 // 2 of them are spawned at green place - weird trick blizz
1006 for (std::list<Creature*>::iterator itr = creList.begin(); itr != creList.end(); ++itr)
1007 {
1008 target = *itr;
1009 std::list<Creature*> tmp;
1011 if ((!stage && tmp.size() > 1) || (stage && tmp.size() == 1))
1012 break;
1013 }
1014
1015 GetCaster()->CastSpell(target, uint32(GetSpellInfo()->Effects[stage].CalcValue()), true, NULL, NULL, GetCaster()->GetGUID());
1016 }
1017
1022 };
1023
1028};
1029
1060
1062{
1063 public:
1064 spell_putricide_choking_gas_bomb() : SpellScriptLoader("spell_putricide_choking_gas_bomb") { }
1065
1067 {
1069
1070 void HandleScript(SpellEffIndex /*effIndex*/)
1071 {
1072 uint32 skipIndex = std::rand() % 2;
1073 for (uint32 i = 0; i < 3; ++i)
1074 {
1075 if (i == skipIndex)
1076 continue;
1077
1078 uint32 spellId = uint32(GetSpellInfo()->Effects[i].CalcValue());
1079 GetCaster()->CastSpell(GetCaster(), spellId, true, NULL, NULL, GetCaster()->GetGUID());
1080 }
1081 }
1082
1087 };
1088
1093};
1094
1096{
1097 public:
1098 spell_putricide_unbound_plague() : SpellScriptLoader("spell_putricide_unbound_plague") { }
1099
1101 {
1103
1104 bool Validate(SpellInfo const* /*spell*/) OVERRIDE
1105 {
1106 if (!sSpellMgr->GetSpellInfo(SPELL_UNBOUND_PLAGUE))
1107 return false;
1108 if (!sSpellMgr->GetSpellInfo(SPELL_UNBOUND_PLAGUE_SEARCHER))
1109 return false;
1110 return true;
1111 }
1112
1113 void FilterTargets(std::list<WorldObject*>& targets)
1114 {
1115 if (AuraEffect const* eff = GetCaster()->GetAuraEffect(SPELL_UNBOUND_PLAGUE_SEARCHER, EFFECT_0))
1116 {
1117 if (eff->GetTickNumber() < 2)
1118 {
1119 targets.clear();
1120 return;
1121 }
1122 }
1123
1124
1125 targets.remove_if(Skyfire::UnitAuraCheck(true, sSpellMgr->GetSpellIdForDifficulty(SPELL_UNBOUND_PLAGUE, GetCaster())));
1127 }
1128
1129 void HandleScript(SpellEffIndex /*effIndex*/)
1130 {
1131 if (!GetHitUnit())
1132 return;
1133
1135 if (!instance)
1136 return;
1137
1138 uint32 plagueId = sSpellMgr->GetSpellIdForDifficulty(SPELL_UNBOUND_PLAGUE, GetCaster());
1139
1140 if (!GetHitUnit()->HasAura(plagueId))
1141 {
1143 {
1144 if (Aura* oldPlague = GetCaster()->GetAura(plagueId, professor->GetGUID()))
1145 {
1146 if (Aura* newPlague = professor->AddAura(plagueId, GetHitUnit()))
1147 {
1148 newPlague->SetMaxDuration(oldPlague->GetMaxDuration());
1149 newPlague->SetDuration(oldPlague->GetDuration());
1150 oldPlague->Remove();
1154 professor->CastSpell(GetHitUnit(), SPELL_UNBOUND_PLAGUE_SEARCHER, true);
1155 }
1156 }
1157 }
1158 }
1159 }
1160
1166 };
1167
1172};
1173
1175{
1176 public:
1177 spell_putricide_eat_ooze() : SpellScriptLoader("spell_putricide_eat_ooze") { }
1178
1180 {
1182
1183 void SelectTarget(std::list<WorldObject*>& targets)
1184 {
1185 if (targets.empty())
1186 return;
1187
1189 WorldObject* target = targets.front();
1190 targets.clear();
1191 targets.push_back(target);
1192 }
1193
1194 void HandleScript(SpellEffIndex /*effIndex*/)
1195 {
1196 Creature* target = GetHitCreature();
1197 if (!target)
1198 return;
1199
1200 if (Aura* grow = target->GetAura(uint32(GetEffectValue())))
1201 {
1202 if (grow->GetStackAmount() < 3)
1203 {
1205 target->RemoveAura(grow);
1206 target->DespawnOrUnsummon(1);
1207 }
1208 else
1209 grow->ModStackAmount(-3);
1210 }
1211 }
1212
1218 };
1219
1224};
1225
1227{
1228 public:
1229 spell_putricide_mutated_plague() : SpellScriptLoader("spell_putricide_mutated_plague") { }
1230
1232 {
1234
1235 void HandleTriggerSpell(AuraEffect const* aurEff)
1236 {
1238 Unit* caster = GetCaster();
1239 if (!caster)
1240 return;
1241
1242 uint32 triggerSpell = GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell;
1243 SpellInfo const* spell = sSpellMgr->GetSpellInfo(triggerSpell);
1244 spell = sSpellMgr->GetSpellForDifficultyFromSpell(spell, caster);
1245
1246 int32 damage = spell->Effects[EFFECT_0].CalcValue(caster);
1247 float multiplier = 2.0f;
1248 if (GetTarget()->GetMap()->GetSpawnMode() & 1)
1249 multiplier = 3.0f;
1250
1251 damage *= int32(pow(multiplier, GetStackAmount()));
1252 damage = int32(damage * 1.5f);
1253
1254 GetTarget()->CastCustomSpell(triggerSpell, SPELLVALUE_BASE_POINT0, damage, GetTarget(), true, NULL, aurEff, GetCasterGUID());
1255 }
1256
1257 void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
1258 {
1259 uint32 healSpell = uint32(GetSpellInfo()->Effects[EFFECT_0].CalcValue());
1260 GetTarget()->CastSpell(GetTarget(), healSpell, true, NULL, NULL, GetCasterGUID());
1261 }
1262
1268 };
1269
1274};
1275
1277{
1278 public:
1279 spell_putricide_mutation_init() : SpellScriptLoader("spell_putricide_mutation_init") { }
1280
1282 {
1284
1286 {
1288 if (!instance)
1290
1292 if (!professor)
1294
1295 if (professor->AI()->GetData(DATA_PHASE) == PHASE_COMBAT_3 || !professor->IsAlive())
1296 {
1299 }
1300
1301 if (professor->AI()->GetData(DATA_ABOMINATION))
1302 {
1305 }
1306
1308 }
1309
1311 {
1312 if (!GetExplTargetUnit())
1314
1315 if (GetExplTargetUnit()->GetTypeId() != TypeID::TYPEID_PLAYER)
1317
1319 SpellCastResult result = CheckRequirementInternal(extension);
1320 if (result != SpellCastResult::SPELL_CAST_OK)
1321 {
1322 Spell::SendCastResult(GetExplTargetUnit()->ToPlayer(), GetSpellInfo(), 0, result, extension);
1323 return result;
1324 }
1325
1327 }
1328
1333 };
1334
1336 {
1338
1339 void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
1340 {
1341 uint32 spellId = 70311;
1342 if (GetTarget()->GetMap()->GetSpawnMode() & 1)
1343 spellId = 71503;
1344
1345 GetTarget()->CastSpell(GetTarget(), spellId, true);
1346 }
1347
1352 };
1353
1358
1363};
1364
1391
1393{
1394 public:
1395 spell_putricide_mutated_transformation() : SpellScriptLoader("spell_putricide_mutated_transformation") { }
1396
1398 {
1400
1402 {
1403 PreventHitDefaultEffect(effIndex);
1404 Unit* caster = GetOriginalCaster();
1405 if (!caster)
1406 return;
1407
1408 InstanceScript* instance = caster->GetInstanceScript();
1409 if (!instance)
1410 return;
1411
1413 if (!putricide)
1414 return;
1415
1416 if (putricide->AI()->GetData(DATA_ABOMINATION))
1417 {
1418 if (Player* player = caster->ToPlayer())
1420 return;
1421 }
1422
1423 uint32 entry = uint32(GetSpellInfo()->Effects[effIndex].MiscValue);
1424 SummonPropertiesEntry const* properties = sSummonPropertiesStore.LookupEntry(uint32(GetSpellInfo()->Effects[effIndex].MiscValueB));
1425 uint32 duration = uint32(GetSpellInfo()->GetDuration());
1426
1427 Position pos;
1428 caster->GetPosition(&pos);
1429 TempSummon* summon = caster->GetMap()->SummonCreature(entry, pos, properties, duration, caster, GetSpellInfo()->Id);
1430 if (!summon || !summon->IsVehicle())
1431 return;
1432
1433 summon->CastSpell(summon, SPELL_ABOMINATION_VEHICLE_POWER_DRAIN, true);
1434 summon->CastSpell(summon, SPELL_MUTATED_TRANSFORMATION_DAMAGE, true);
1435 caster->CastSpell(summon, SPELL_MUTATED_TRANSFORMATION_NAME, true);
1436
1437 caster->EnterVehicle(summon, 0); // VEHICLE_SPELL_RIDE_HARDCODED is used according to sniff, this is ok
1438 summon->SetCreatorGUID(caster->GetGUID());
1439 putricide->AI()->JustSummoned(summon);
1440 }
1441
1446 };
1447
1452};
1453
1480
1482{
1483 public:
1484 spell_putricide_regurgitated_ooze() : SpellScriptLoader("spell_putricide_regurgitated_ooze") { }
1485
1487 {
1489
1490 // the only purpose of this hook is to fail the achievement
1491 void ExtraEffect(SpellEffIndex /*effIndex*/)
1492 {
1493 if (InstanceScript* instance = GetCaster()->GetInstanceScript())
1494 instance->SetData(DATA_NAUSEA_ACHIEVEMENT, uint32(false));
1495 }
1496
1501 };
1502
1507};
1508
1509// Removes aura with id stored in effect value
1537
1538// Stinky and Precious spell, it's here because its used for both (Festergut and Rotface "pets")
1540{
1541 public:
1542 spell_stinky_precious_decimate() : SpellScriptLoader("spell_stinky_precious_decimate") { }
1543
1562
1567};
1568
const AuthHandler table[]
DBCStorage< SummonPropertiesEntry > sSummonPropertiesStore(SummonPropertiesfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define OVERRIDE
Definition Define.h:60
std::uint64_t uint64
Definition Define.h:76
@ IN_PROGRESS
@ FAIL
@ DONE
@ NOT_STARTED
@ POINT_MOTION_TYPE
@ TYPEID_PLAYER
Definition Object.h:55
@ TYPEID_UNIT
Definition Object.h:54
void GetCreatureListWithEntryInGrid(std::list< Creature * > &list, WorldObject *source, uint32 entry, float maxSearchRange)
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ EFFECT_2
@ EMOTE_ONESHOT_KNEEL
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_KNOCK_BACK
@ SPELL_EFFECT_APPLY_AURA
@ TARGET_UNIT_DEST_AREA_ENEMY
@ TARGET_UNIT_SRC_AREA_ALLY
@ TARGET_UNIT_SRC_AREA_ENEMY
@ TARGET_UNIT_DEST_AREA_ENTRY
@ IMMUNITY_EFFECT
SpellCustomErrors
@ SPELL_CUSTOM_ERROR_NONE
@ SPELL_CUSTOM_ERROR_TOO_MANY_ABOMINATIONS
@ SPELL_CUSTOM_ERROR_ALL_POTIONS_USED
@ AURA_STATE_UNKNOWN19
@ AURA_STATE_UNKNOWN22
SpellCastResult
@ SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_DUMMY
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
#define sSpellMgr
Definition SpellMgr.h:744
#define SpellCheckCastFn(F)
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
#define SpellHitFn(F)
#define AuraEffectRemoveFn(F, I, N, M)
@ SPELLVALUE_AURA_STACK
Definition Unit.h:119
@ SPELLVALUE_MAX_TARGETS
Definition Unit.h:118
@ SPELLVALUE_BASE_POINT0
Definition Unit.h:114
@ AURA_REMOVE_BY_ENEMY_SPELL
Definition Unit.h:409
@ UNIT_STATE_CASTING
Definition Unit.h:527
@ MOVE_RUN
Definition Unit.h:556
@ REACT_DEFENSIVE
Definition Unit.h:1157
@ REACT_PASSIVE
Definition Unit.h:1156
@ UNIT_FLAG_NOT_SELECTABLE
Definition Unit.h:650
@ UNIT_FLAG_IMMUNE_TO_PC
Definition Unit.h:633
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ UNIT_FIELD_FLAGS
@ SAY_BERSERK
#define SAY_DEATH
#define SAY_AGGRO
#define SAY_KILL
@ PHASE_NONE
@ SAY_TRANSFORM_1
@ SAY_TRANSFORM_2
@ EVENT_BERSERK
Position const festergutWatchPos
@ SPELL_UNBOUND_PLAGUE_PROTECTION
@ SPELL_UNBOUND_PLAGUE_SEARCHER
@ SPELL_OOZE_ERUPTION_SEARCH_PERIODIC
@ SPELL_CHOKING_GAS_BOMB_PERIODIC
@ SPELL_VOLATILE_OOZE_ADHESIVE
@ SPELL_SLIME_PUDDLE_AURA
@ SPELL_SLIME_PUDDLE_TRIGGER
@ SPELL_MUTATED_TRANSFORMATION
@ SPELL_GASEOUS_BLOAT_PROTECTION
@ SPELL_MUTATED_TRANSFORMATION_DAMAGE
@ SPELL_TEAR_GAS_CREATURE
@ SPELL_TEAR_GAS_PERIODIC_TRIGGER
@ SPELL_UNSTABLE_EXPERIMENT
@ SPELL_GASEOUS_BLOAT_PROC
@ SPELL_UNHOLY_INFUSION_CREDIT
@ SPELL_OOZE_TANK_PROTECTION
@ SPELL_ABOMINATION_VEHICLE_POWER_DRAIN
@ SPELL_VOLATILE_OOZE_PROTECTION
@ SPELL_CREATE_CONCOCTION
@ SPELL_MUTATED_TRANSFORMATION_NAME
@ SPELL_RELEASE_GAS_VISUAL
@ SPELL_GASEOUS_BLIGHT_LARGE
@ SPELL_GASEOUS_BLIGHT_MEDIUM
@ SPELL_GASEOUS_BLIGHT_SMALL
@ SPELL_MALLEABLE_GOO_SUMMON
@ SPELL_CHOKING_GAS_EXPLOSION_TRIGGER
@ SPELL_MUTATED_PLAGUE_CLEAR
Position const rotfaceWatchPos
Position const tablePos
@ SAY_PHASE_TRANSITION_HEROIC
@ SAY_FESTERGUT_GASEOUS_BLIGHT
@ EMOTE_UNSTABLE_EXPERIMENT
uint32 const oozeFloodSpells[4]
void AddSC_boss_professor_putricide()
#define EXPERIMENT_STATE_OOZE
@ EVENT_UNSTABLE_EXPERIMENT
uint32 GetEffIndex() const
void PreventDefaultAction()
HookList< EffectApplyHandler > AfterEffectRemove
HookList< EffectPeriodicHandler > OnEffectPeriodic
SpellInfo const * GetSpellInfo() const
uint64 GetCasterGUID() const
Unit * GetCaster() const
Unit * GetTarget() const
uint8 GetStackAmount() const
uint32 GetId() const
InstanceScript *const instance
void _JustReachedHome()
bool CheckInRoom()
SummonList summons
EventMap events
BossAI(Creature *creature, uint32 bossId)
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
virtual void JustSummoned(Creature *)
Definition CreatureAI.h:98
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
virtual void EnterEvadeMode()
void DespawnOrUnsummon(uint32 msTimeToDespawn=0)
CreatureAI * AI() const
Definition Creature.h:483
CreatureScript(const char *name)
ExactDistanceCheck(Unit *source, float dist)
bool operator()(WorldObject *unit) const
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=NULL, uint32 duration=0, Unit *summoner=NULL, uint32 spellId=0, uint32 vehId=0)
Definition Object.cpp:2564
static Creature * GetCreature(WorldObject const &u, uint64 guid)
static GameObject * GetGameObject(WorldObject const &u, uint64 guid)
static Unit * GetUnit(WorldObject const &, uint64 guid)
uint64 GetGUID() const
Definition Object.h:119
Player * ToPlayer()
Definition Object.h:204
TypeID GetTypeId() const
Definition Object.h:131
Creature * ToCreature()
Definition Object.h:207
uint32 TriggerSpell
Definition SpellInfo.h:108
int32 CalcValue(Unit const *caster=NULL, int32 const *basePoints=NULL, Unit const *target=NULL) const
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, Opcodes opcode=SMSG_CAST_FAILED)
Definition Spell.cpp:3874
SpellEffectInfo Effects[MAX_SPELL_EFFECTS]
Definition SpellInfo.h:255
Creature * GetHitCreature()
Unit * GetExplTargetUnit()
HookList< CheckCastHandler > OnCheckCast
HookList< HitHandler > AfterHit
void FinishCast(SpellCastResult result)
SpellInfo const * GetSpellInfo()
HookList< HitHandler > OnHit
HookList< EffectHandler > OnEffectHit
void PreventHitDefaultEffect(SpellEffIndex effIndex)
HookList< EffectHandler > OnEffectHitTarget
Unit * GetHitUnit()
int32 GetEffectValue()
Unit * GetOriginalCaster()
Unit * GetCaster()
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
SpellScriptLoader(const char *name)
virtual void SetData(uint32, uint32)
Definition UnitAI.h:128
void SelectTargetList(std::list< Unit * > &targetList, uint32 num, SelectAggroTarget targetType, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:71
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:28
void DoCast(uint32 spellId)
Definition UnitAI.cpp:110
virtual uint32 GetData(uint32) const
Definition UnitAI.h:127
Unit * SelectTarget(SelectAggroTarget targetType, uint32 position=0, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:66
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:176
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:16
Definition Unit.h:1367
void EnterVehicle(Unit *base, int8 seatId=-1)
Definition Unit.cpp:8234
void ClearUnitState(uint32 f)
Definition Unit.h:1489
bool IsVehicle() const
Definition Unit.h:1523
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
void CastSpell(SpellCastTargets const &targets, SpellInfo const *spellInfo, CustomSpellValues const *value, TriggerCastFlags triggerFlags=TRIGGERED_NONE, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
void RemoveAurasDueToSpell(uint32 spellId, uint64 casterGUID=0, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
void AddThreat(Unit *victim, float fThreat, SpellSchoolMask schoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellInfo const *threatSpell=NULL)
Definition Unit.cpp:4463
void SetCreatorGUID(uint64 creator)
Definition Unit.h:2059
Aura * GetAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
uint32 GetMaxHealth() const
Definition Unit.h:1604
Aura * AddAura(uint32 spellId, Unit *target)
void RemoveAuraFromStack(uint32 spellId, uint64 casterGUID=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
bool IsAlive() const
Definition Unit.h:2032
void SetHealth(uint32 val)
Definition Unit.cpp:5162
bool HasAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
void DeleteThreatList()
Definition Unit.cpp:4472
void CastCustomSpell(Unit *victim, uint32 spellId, int32 const *bp0, int32 const *bp1, int32 const *bp2, bool triggered, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
Map * GetMap() const
Definition Object.h:740
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
virtual uint64 GetData64(uint32) const
Definition ZoneScript.h:32
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
void SpellHitTarget(Unit *, SpellInfo const *spell) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
npc_putricide_oozeAI(Creature *creature, uint32 hitTargetSpellId)
virtual void CastMainSpell()=0
void SpellHit(Unit *, SpellInfo const *spell) OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
PrepareSpellScript(spell_putricide_eat_ooze_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
AuraScript * GetAuraScript() const OVERRIDE
AuraScript * GetAuraScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
AuraScript * GetAuraScript() const OVERRIDE
PrepareSpellScript(spell_putricide_ooze_channel_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
PrepareSpellScript(spell_putricide_slime_puddle_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
SpellScript * GetSpellScript() const OVERRIDE
@ NPC_TEAR_GAS_TARGET_STALKER
@ NPC_ABOMINATION_WING_MAD_SCIENTIST_STALKER
@ NPC_MUTATED_ABOMINATION_25
@ NPC_CHOKING_GAS_BOMB
@ NPC_MALLEABLE_OOZE_STALKER
@ NPC_VOLATILE_OOZE
@ NPC_PUDDLE_STALKER
@ NPC_GAS_CLOUD
@ NPC_MUTATED_ABOMINATION_10
@ NPC_GROWING_OOZE_PUDDLE
CreatureAI * GetIcecrownCitadelAI(Creature *creature)
@ ACTION_CHANGE_PHASE
@ ACTION_ROTFACE_COMBAT
@ ACTION_FESTERGUT_DEATH
@ ACTION_ROTFACE_DEATH
@ ACTION_ROTFACE_OOZE
@ ACTION_FESTERGUT_GAS
@ ACTION_FESTERGUT_COMBAT
@ LIGHT_S_HAMMER_TELEPORT
@ SPELL_SHADOWS_FATE
@ SPELL_BERSERK2
@ DATA_NAUSEA_ACHIEVEMENT
@ DATA_ROTFACE
@ DATA_PROFESSOR_PUTRICIDE
@ DATA_PUTRICIDE_TABLE
@ DATA_FESTERGUT
void RandomResizeList(std::list< T > &list, uint32 size)
Definition Containers.h:19
C::value_type const & SelectRandomContainerElement(C const &container)
Definition Containers.h:48
float GetPositionZ() const
Definition Object.h:330
void GetPosition(float &x, float &y) const
Definition Object.h:333
bool operator()(Creature *stalker) const
RotfaceHeightCheck(Creature *rotface)
bool IsHeroic() const
Creature * me
bool HealthAbovePct(uint32 pct) const
ScriptedAI(Creature *creature)
bool Is25ManRaid() const
void AttackStart(Unit *) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
@ SPELL_GROW