TrinityCore
Loading...
Searching...
No Matches
boss_festergut.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "icecrown_citadel.h"
19#include "Containers.h"
20#include "InstanceScript.h"
21#include "Map.h"
22#include "ObjectAccessor.h"
23#include "Player.h"
24#include "ScriptedCreature.h"
25#include "ScriptMgr.h"
26#include "SpellAuras.h"
27#include "SpellScript.h"
28
42
44{
45 // Festergut
48 SPELL_GASTRIC_BLOAT = 72219, // 72214 is the proper way (with proc) but atm procs can't have cooldown for creatures
53
54 // Stinky
58};
59
60// Used for HasAura checks
61#define PUNGENT_BLIGHT_HELPER RAID_MODE<uint32>(69195, 71219, 73031, 73032)
62#define INOCULATED_HELPER RAID_MODE<uint32>(69291, 72101, 72102, 72103)
63
64uint32 const gaseousBlight[3] = {69157, 69162, 69164};
65uint32 const gaseousBlightVisual[3] = {69126, 69152, 69154};
66
78
79enum Misc
80{
82};
83
84struct boss_festergut : public BossAI
85{
87 {
90 }
91
92 void Reset() override
93 {
94 _Reset();
100 _inhaleCounter = 0;
102 if (Creature* gasDummy = me->FindNearestCreature(NPC_GAS_DUMMY, 100.0f, true))
103 {
104 _gasDummyGUID = gasDummy->GetGUID();
105 for (uint8 i = 0; i < 3; ++i)
106 {
108 gasDummy->RemoveAurasDueToSpell(gaseousBlightVisual[i]);
109 }
110 }
111 }
112
113 void JustEngagedWith(Unit* who) override
114 {
116 {
119 return;
120 }
121
122 me->setActive(true);
124 if (Creature* gasDummy = me->FindNearestCreature(NPC_GAS_DUMMY, 100.0f, true))
125 _gasDummyGUID = gasDummy->GetGUID();
127 professor->AI()->DoAction(ACTION_FESTERGUT_COMBAT);
129 }
130
131 void JustDied(Unit* /*killer*/) override
132 {
133 _JustDied();
136 professor->AI()->DoAction(ACTION_FESTERGUT_DEATH);
137
138 RemoveBlight();
139 }
140
141 void JustReachedHome() override
142 {
145 }
146
147 void EnterEvadeMode(EvadeReason why) override
148 {
151 professor->AI()->EnterEvadeMode();
152 }
153
154 void KilledUnit(Unit* victim) override
155 {
156 if (victim->GetTypeId() == TYPEID_PLAYER)
157 Talk(SAY_KILL);
158 }
159
160 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
161 {
162 Unit* unitTarget = target->ToUnit();
163 if (!unitTarget)
164 return;
165
166 if (spellInfo->Id == PUNGENT_BLIGHT_HELPER)
168 }
169
170 void UpdateAI(uint32 diff) override
171 {
172 if (!UpdateVictim())
173 return;
174
175 events.Update(diff);
176
178 return;
179
180 while (uint32 eventId = events.ExecuteEvent())
181 {
182 switch (eventId)
183 {
185 {
186 RemoveBlight();
187 if (_inhaleCounter == 3)
188 {
192 _inhaleCounter = 0;
194 professor->AI()->DoAction(ACTION_FESTERGUT_GAS);
196 }
197 else
198 {
200 // just cast and dont bother with target, conditions will handle it
202 if (_inhaleCounter < 3)
204 .SetOriginalCaster(me->GetGUID()));
205 }
206
208 break;
209 }
210 case EVENT_VILE_GAS:
211 {
212 std::list<Unit*> ranged, melee;
213 uint32 minTargets = RAID_MODE<uint32>(3, 8, 3, 8);
214 SelectTargetList(ranged, 25, SelectTargetMethod::Random, 0, -5.0f, true);
215 SelectTargetList(melee, 25, SelectTargetMethod::Random, 0, 5.0f, true);
216 while (ranged.size() < minTargets)
217 {
218 if (melee.empty())
219 break;
220
222 ranged.push_back(target);
223 melee.remove(target);
224 }
225
226 if (!ranged.empty())
227 {
228 Trinity::Containers::RandomResize(ranged, RAID_MODE<uint32>(1, 3, 1, 3));
229 for (std::list<Unit*>::iterator itr = ranged.begin(); itr != ranged.end(); ++itr)
230 DoCast(*itr, SPELL_VILE_GAS);
231 }
232
234 break;
235 }
236 case EVENT_GAS_SPORE:
239 me->CastSpell(me, SPELL_GAS_SPORE, CastSpellExtraArgs().AddSpellMod(SPELLVALUE_MAX_TARGETS, RAID_MODE<int32>(2, 3, 2, 3)));
242 break;
246 break;
247 case EVENT_BERSERK:
250 break;
251 default:
252 break;
253 }
254
256 return;
257 }
258 }
259
260 void SetData(uint32 type, uint32 data) override
261 {
262 if (type == DATA_INOCULATED_STACK && data > _maxInoculatedStack)
263 _maxInoculatedStack = data;
264 }
265
266 uint32 GetData(uint32 type) const override
267 {
268 if (type == DATA_INOCULATED_STACK)
270
271 return 0;
272 }
273
275 {
277 for (uint8 i = 0; i < 3; ++i)
278 {
280 gasDummy->RemoveAurasDueToSpell(gaseousBlightVisual[i]);
281 }
282 }
283
284private:
288};
289
291{
292 npc_stinky_icc(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
293
294 void Reset() override
295 {
296 _events.Reset();
299 }
300
301 void JustEngagedWith(Unit* /*target*/) override
302 {
304 }
305
306 void UpdateAI(uint32 diff) override
307 {
308 if (!UpdateVictim())
309 return;
310
311 _events.Update(diff);
312
314 return;
315
316 while (uint32 eventId = _events.ExecuteEvent())
317 {
318 switch (eventId)
319 {
320 case EVENT_DECIMATE:
323 break;
327 break;
328 default:
329 break;
330 }
331 }
332 }
333
334 void JustDied(Unit* /*killer*/) override
335 {
337 if (festergut->IsAlive())
338 festergut->AI()->Talk(SAY_STINKY_DEAD);
339 }
340
341private:
344};
345
346// 69195, 71219, 73031, 73032 - Pungent Blight
365
366// 72219, 72551, 72552, 72553 - Gastric Bloat
368{
369 bool Validate(SpellInfo const* /*spell*/) override
370 {
372 }
373
374 void HandleScript(SpellEffIndex /*effIndex*/)
375 {
376 Aura const* aura = GetHitUnit()->GetAura(GetSpellInfo()->Id);
377 if (!(aura && aura->GetStackAmount() == 10))
378 return;
379
382 }
383
388};
389
390// 69290, 71222, 73033, 73034 - Blighted Spores
392{
393 bool Validate(SpellInfo const* /*spell*/) override
394 {
396 }
397
398 void ExtraEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
399 {
401 if (InstanceScript* instance = GetTarget()->GetInstanceScript())
402 if (Creature* festergut = ObjectAccessor::GetCreature(*GetTarget(), instance->GetGuidData(DATA_FESTERGUT)))
403 festergut->AI()->SetData(DATA_INOCULATED_STACK, GetStackAmount());
404
406 }
407
409 {
410 Player* target = GetUnitOwner()->ToPlayer();
411 if (!target)
412 return;
413
415 return;
416
418 if (target->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE)
419 return;
420
422 }
423
428};
429
431{
432 public:
433 achievement_flu_shot_shortage() : AchievementCriteriaScript("achievement_flu_shot_shortage") { }
434
435 bool OnCheck(Player* /*source*/, Unit* target) override
436 {
437 if (target && target->GetTypeId() == TYPEID_UNIT)
438 return target->ToCreature()->AI()->GetData(DATA_INOCULATED_STACK) < 3;
439
440 return false;
441 }
442};
443
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
@ FAIL
@ TYPEID_UNIT
Definition ObjectGuid.h:43
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
Spells
Definition PlayerAI.cpp:32
@ QUEST_STATUS_INCOMPLETE
Definition QuestDef.h:150
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ EFFECT_2
@ SPELL_EFFECT_SCRIPT_EFFECT
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELLVALUE_MAX_TARGETS
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
#define SpellEffectFn(F, I, N)
#define AuraEffectRemoveFn(F, I, N, M)
EvadeReason
@ UNIT_STATE_CASTING
Definition Unit.h:276
uint32 const gaseousBlight[3]
#define INOCULATED_HELPER
@ DATA_INOCULATED_STACK
#define PUNGENT_BLIGHT_HELPER
@ SPELL_VILE_GAS
@ SPELL_PLAGUE_STENCH
@ SPELL_GASTRIC_EXPLOSION
@ SPELL_INHALE_BLIGHT
@ SPELL_GAS_SPORE
@ SPELL_GASTRIC_BLOAT
@ SPELL_INOCULATED
@ SPELL_DECIMATE
@ SPELL_MORTAL_WOUND
@ SPELL_PUNGENT_BLIGHT
@ SAY_DEATH
@ EMOTE_PUNGENT_BLIGHT
@ SAY_AGGRO
@ EMOTE_GAS_SPORE
@ SAY_PUNGENT_BLIGHT
@ EMOTE_WARN_GAS_SPORE
@ SAY_KILL
@ EMOTE_WARN_PUNGENT_BLIGHT
@ SAY_STINKY_DEAD
@ SAY_BERSERK
void AddSC_boss_festergut()
uint32 const gaseousBlightVisual[3]
@ EVENT_VILE_GAS
@ EVENT_MORTAL_WOUND
@ EVENT_GASTRIC_BLOAT
@ EVENT_BERSERK
@ EVENT_GAS_SPORE
@ EVENT_INHALE_BLIGHT
@ EVENT_DECIMATE
Unit * GetTarget() const
HookList< EffectApplyHandler > OnEffectRemove
Unit * GetUnitOwner() const
uint8 GetStackAmount() const
uint8 GetStackAmount() const
Definition SpellAuras.h:238
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
TypeID GetTypeId() const
Definition BaseEntity.h:166
InstanceScript *const instance
void _JustReachedHome()
EventMap events
void DoZoneInCombat()
Definition CreatureAI.h:169
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
CreatureAI * AI() const
Definition Creature.h:228
uint32 ExecuteEvent()
Definition EventMap.cpp:77
void Update(uint32 time)
Definition EventMap.h:61
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:40
void RescheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:56
void Reset()
Definition EventMap.cpp:25
virtual bool SetBossState(uint32 id, EncounterState state)
void DoCastSpellOnPlayers(uint32 spell, bool includePets=false, bool includeControlled=false)
virtual ObjectGuid GetGuidData(uint32 type) const override
virtual bool CheckRequiredBosses(uint32, Player const *=nullptr) const
bool Is25ManRaid() const
Definition Map.cpp:3349
Player * ToPlayer()
Definition Object.h:126
Creature * ToCreature()
Definition Object.h:121
Unit * ToUnit()
Definition Object.h:116
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15962
uint32 const Id
Definition SpellInfo.h:328
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Unit * GetCaster() const
int32 GetEffectValueAsInt() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
SpellInfo const * GetSpellInfo() const
SpellCastResult DoCastSelf(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.h:160
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:180
void SelectTargetList(std::list< Unit * > &targetList, uint32 num, SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:84
virtual uint32 GetData(uint32 id) const
Definition UnitAI.h:74
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4700
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 RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
Map * GetMap() const
Definition Object.h:411
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
void setActive(bool isActiveObject)
Definition Object.cpp:276
Creature * FindNearestCreature(uint32 entry, float range, bool alive=true) const
Definition Object.cpp:1517
bool OnCheck(Player *, Unit *target) override
void ExtraEffect(AuraEffect const *, AuraEffectHandleModes)
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
@ SPELL_ORANGE_BLIGHT_RESIDUE
@ SPELL_BERSERK2
@ LIGHT_S_HAMMER_TELEPORT
#define RegisterIcecrownCitadelCreatureAI(ai_name)
@ ACTION_FESTERGUT_DEATH
@ ACTION_FESTERGUT_GAS
@ ACTION_FESTERGUT_COMBAT
@ DATA_PROFESSOR_PUTRICIDE
@ DATA_FESTERGUT
@ NPC_GAS_DUMMY
@ QUEST_RESIDUE_RENDEZVOUS_10
@ QUEST_RESIDUE_RENDEZVOUS_25
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
void RandomResize(C &container, std::size_t requestedSize)
Definition Containers.h:67
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void UpdateAI(uint32 diff) override
void JustReachedHome() override
void KilledUnit(Unit *victim) override
uint32 GetData(uint32 type) const override
void SetData(uint32 type, uint32 data) override
void Reset() override
ObjectGuid _gasDummyGUID
void JustDied(Unit *) override
void EnterEvadeMode(EvadeReason why) override
void JustEngagedWith(Unit *who) override
boss_festergut(Creature *creature)
void Reset() override
void JustEngagedWith(Unit *) override
npc_stinky_icc(Creature *creature)
void JustDied(Unit *) override
void UpdateAI(uint32 diff) override
InstanceScript * _instance