Operation Floodgate

This commit is contained in:
luis
2026-09-24 21:10:56 -03:00
parent 1835f627f6
commit e4daabc3a1
7 changed files with 806 additions and 0 deletions
@@ -0,0 +1,150 @@
/*
* Copyright (C) WowCommunity Project
*
* This SourceCode is NOT free a software. Please hold everything Private
* and read our Terms
*/
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "operation_floodgate.h"
#include "GameObject.h"
#include "Map.h"
#include "TemporarySummon.h"
#include "CreatureAI.h"
enum Spells
{
SPELL_JUMPSTART = 460156,
SPELL_EXCESSIVE_ELECTRIFICATION = 473287,
SPELL_SONIC_BOOM = 473220,
SPELL_SONIC_BOOM_EXPLOSION = 473240,
SPELL_MOBILIZE_MECHADRONES = 471585,
SPELL_ELECTROCRUSH = 473351,
SPELL_KILL_O_BLOCK_BARRIER = 469981,
SPELL_MAXIMUM_DISTORTION = 1214780,
SPELL_SHOOT = 460393,
SPELL_DOOM_STORM = 472452
};
enum Events
{
EVENT_ELECTROCRUSH = 1,
EVENT_SONIC_BOOM,
EVENT_KILL_O_BLOCK_BARRIER,
EVENT_MOBILIZE_MECHADRONES,
EVENT_CHECK_MECHADRONES
};
struct boss_big_momma : public BossAI
{
boss_big_momma(Creature* creature) : BossAI(creature, DATA_BIG_MOMMA)
{
Initialize();
}
void Initialize()
{
_activeMechadrones = 0;
_jumpstartActive = false;
}
void Reset() override
{
_Reset();
Initialize();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_ELECTROCRUSH, 10s);
events.ScheduleEvent(EVENT_SONIC_BOOM, 15s);
events.ScheduleEvent(EVENT_KILL_O_BLOCK_BARRIER, 30s);
events.ScheduleEvent(EVENT_MOBILIZE_MECHADRONES, 5s);
events.ScheduleEvent(EVENT_CHECK_MECHADRONES, 2s);
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
if (summon->GetEntry() == NPC_DARKFUSE_MECHADRONE)
{
_activeMechadrones--;
if (_activeMechadrones == 0 && !_jumpstartActive)
{
_jumpstartActive = true;
DoCastSelf(SPELL_JUMPSTART);
scheduler.Schedule(12s, [this](TaskContext)
{
DoCastAOE(SPELL_EXCESSIVE_ELECTRIFICATION);
_jumpstartActive = false;
});
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ELECTROCRUSH:
DoCastVictim(SPELL_ELECTROCRUSH);
events.Repeat(20s);
break;
case EVENT_SONIC_BOOM:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
DoCast(target, SPELL_SONIC_BOOM);
events.Repeat(25s);
break;
case EVENT_KILL_O_BLOCK_BARRIER:
DoCastSelf(SPELL_KILL_O_BLOCK_BARRIER);
events.Repeat(45s);
break;
case EVENT_MOBILIZE_MECHADRONES:
DoCastAOE(SPELL_MOBILIZE_MECHADRONES);
SummonMechadrones();
events.Repeat(60s);
break;
case EVENT_CHECK_MECHADRONES:
events.Repeat(2s);
break;
default:
break;
}
}
}
private:
void SummonMechadrones()
{
for (uint8 i = 0; i < 4; ++i)
{
Position pos = me->GetRandomNearPosition(10.0f);
if (Creature* drone = me->SummonCreature(NPC_DARKFUSE_MECHADRONE, pos, TEMPSUMMON_CORPSE_DESPAWN))
{
_activeMechadrones++;
if (IsMythic())
drone->CastSpell(drone, SPELL_MAXIMUM_DISTORTION);
}
}
}
uint8 _activeMechadrones;
bool _jumpstartActive;
};
void AddSC_boss_big_momma()
{
RegisterOperationFloodgateCreatureAI(boss_big_momma);
}
@@ -0,0 +1,224 @@
/*
* Copyright (C) WowCommunity Project
*
* This SourceCode is NOT free a software. Please hold everything Private
* and read our Terms
*/
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "operation_floodgate.h"
#include "GameObject.h"
#include "Map.h"
#include "TemporarySummon.h"
#include "CreatureAI.h"
enum Spells
{
// Keeza
SPELL_QUICK_SHOT = 460602,
SPELL_BBBFG = 473594,
SPELL_BIG_BADA_BOOM = 460867,
SPELL_DEFLAGRATION = 460787,
SPELL_SHRAPNEL = 472755,
SPELL_KINETIC_GEL = 473690,
// Bront
SPELL_WALLOP = 459799,
SPELL_BARRELING_CHARGE = 459779,
SPELL_DIVIDED_DUO = 470090,
SPELL_DAMAGE_INCREASE = 470091
};
enum Events
{
// Keeza
EVENT_QUICK_SHOT = 1,
EVENT_BBBFG,
EVENT_BIG_BADA_BOOM,
EVENT_KINETIC_GEL,
// Bront
EVENT_WALLOP,
EVENT_BARRELING_CHARGE,
ACTION_PARTNER_DIED
};
struct boss_keeza_quickfuse : public BossAI
{
boss_keeza_quickfuse(Creature* creature) : BossAI(creature, DATA_DEMOLITION_DUO)
{
Initialize();
}
void Initialize()
{
_partnerDead = false;
}
void Reset() override
{
_Reset();
Initialize();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
if (Creature* bront = instance->GetCreature(DATA_BRONT))
DoZoneInCombat(bront);
events.ScheduleEvent(EVENT_QUICK_SHOT, 5s);
events.ScheduleEvent(EVENT_BBBFG, 15s);
events.ScheduleEvent(EVENT_BIG_BADA_BOOM, 20s);
if (IsMythic())
events.ScheduleEvent(EVENT_KINETIC_GEL, 25s);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
if (damage >= me->GetHealth())
{
if (Creature* bront = instance->GetCreature(DATA_BRONT))
{
if (bront->IsAlive())
{
bront->AI()->DoAction(ACTION_PARTNER_DIED);
_partnerDead = true;
}
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_QUICK_SHOT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
DoCast(target, SPELL_QUICK_SHOT);
events.Repeat(10s);
break;
case EVENT_BBBFG:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
DoCast(target, SPELL_BBBFG);
events.Repeat(25s);
break;
case EVENT_BIG_BADA_BOOM:
DoCastAOE(SPELL_BIG_BADA_BOOM);
events.Repeat(30s);
break;
case EVENT_KINETIC_GEL:
if (IsMythic())
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
DoCast(target, SPELL_KINETIC_GEL);
events.Repeat(35s);
break;
default:
break;
}
}
}
private:
bool _partnerDead;
};
struct boss_bront : public BossAI
{
boss_bront(Creature* creature) : BossAI(creature, DATA_BRONT)
{
Initialize();
}
void Initialize()
{
_partnerDead = false;
_increaseDamageTimer = 4000;
}
void Reset() override
{
_Reset();
Initialize();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_WALLOP, 8s);
events.ScheduleEvent(EVENT_BARRELING_CHARGE, 15s);
}
void DoAction(int32 action) override
{
if (action == ACTION_PARTNER_DIED)
{
_partnerDead = true;
DoCastSelf(SPELL_DIVIDED_DUO);
events.ScheduleEvent(EVENT_WALLOP, 3s);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (_partnerDead)
{
if (_increaseDamageTimer <= diff)
{
DoCastSelf(SPELL_DAMAGE_INCREASE);
_increaseDamageTimer = 4000;
}
else
_increaseDamageTimer -= diff;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_WALLOP:
DoCastVictim(SPELL_WALLOP);
events.Repeat(_partnerDead ? 5s : 15s);
break;
case EVENT_BARRELING_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
DoCast(target, SPELL_BARRELING_CHARGE);
events.Repeat(20s);
break;
default:
break;
}
}
}
private:
bool _partnerDead;
uint32 _increaseDamageTimer;
};
void AddSC_boss_demolition_duo()
{
RegisterOperationFloodgateCreatureAI(boss_keeza_quickfuse);
RegisterOperationFloodgateCreatureAI(boss_bront);
}
@@ -0,0 +1,131 @@
/*
* Copyright (C) WowCommunity Project
*
* This SourceCode is NOT free a software. Please hold everything Private
* and read our Terms
*/
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "operation_floodgate.h"
#include "GameObject.h"
#include "Map.h"
#include "TemporarySummon.h"
#include "CreatureAI.h"
enum Spells
{
SPELL_TURBO_CHARGE = 465456,
SPELL_TURBO_BOLT = 466088,
SPELL_DAM_WATER = 468261,
SPELL_SHOCK_WATER = 468661,
SPELL_DAM_RUBBLE = 468606,
SPELL_LEAPING_SPARKS = 468846,
SPELL_GIGAZAP = 468812,
SPELL_THUNDER_PUNCH = 466197
};
enum Events
{
EVENT_TURBO_CHARGE = 1,
EVENT_TURBO_BOLT,
EVENT_DAM_WATER,
EVENT_DAM_RUBBLE,
EVENT_LEAPING_SPARKS,
EVENT_GIGAZAP,
EVENT_THUNDER_PUNCH
};
struct boss_geezle_gigazap : public BossAI
{
boss_geezle_gigazap(Creature* creature) : BossAI(creature, DATA_GEEZLE_GIGAZAP)
{
electricityPower = 0;
}
void Reset() override
{
_Reset();
electricityPower = 0;
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_TURBO_CHARGE, 10s);
events.ScheduleEvent(EVENT_DAM_WATER, 15s);
events.ScheduleEvent(EVENT_DAM_RUBBLE, 20s);
events.ScheduleEvent(EVENT_THUNDER_PUNCH, 5s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_TURBO_CHARGE:
DoCast(SPELL_TURBO_CHARGE);
electricityPower += 10;
events.ScheduleEvent(EVENT_TURBO_CHARGE, 45s);
events.ScheduleEvent(EVENT_TURBO_BOLT, 2s);
break;
case EVENT_TURBO_BOLT:
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
DoCast(target, SPELL_TURBO_BOLT);
break;
case EVENT_DAM_WATER:
DoCast(SPELL_DAM_WATER);
events.ScheduleEvent(EVENT_DAM_WATER, 25s);
break;
case EVENT_DAM_RUBBLE:
DoCast(SPELL_DAM_RUBBLE);
events.ScheduleEvent(EVENT_DAM_RUBBLE, 30s);
break;
case EVENT_LEAPING_SPARKS:
if (electricityPower >= 40)
{
DoCast(SPELL_LEAPING_SPARKS);
electricityPower -= 40;
}
events.ScheduleEvent(EVENT_LEAPING_SPARKS, 35s);
break;
case EVENT_GIGAZAP:
if (electricityPower >= 20)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
DoCast(target, SPELL_GIGAZAP);
electricityPower -= 20;
}
events.ScheduleEvent(EVENT_GIGAZAP, 15s);
break;
case EVENT_THUNDER_PUNCH:
if (electricityPower >= 10)
{
DoCastVictim(SPELL_THUNDER_PUNCH);
electricityPower -= 10;
}
events.ScheduleEvent(EVENT_THUNDER_PUNCH, 8s);
break;
default:
break;
}
}
}
private:
uint8 electricityPower;
};
void AddSC_boss_geezle_gigazap()
{
RegisterCreatureAI(boss_geezle_gigazap);
}
@@ -0,0 +1,149 @@
/*
* Copyright (C) WowCommunity Project
*
* This SourceCode is NOT free a software. Please hold everything Private
* and read our Terms
*/
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "operation_floodgate.h"
#include "GameObject.h"
#include "Map.h"
#include "TemporarySummon.h"
#include "CreatureAI.h"
enum Spells
{
SPELL_SLUDGE_CLAWS = 469478,
SPELL_MUDSLIDE = 473112,
SPELL_AWAKEN_THE_SWAMP = 473070,
SPELL_SKEWERING_ROOT = 473047,
SPELL_RUSHING_TIDE = 473052,
SPELL_RAZORCHOKE_VINES = 470039
};
enum Events
{
EVENT_SLUDGE_CLAWS = 1,
EVENT_MUDSLIDE,
EVENT_AWAKEN_THE_SWAMP,
EVENT_RAZORCHOKE_VINES
};
struct boss_swampface : public BossAI
{
boss_swampface(Creature* creature) : BossAI(creature, DATA_SWAMPFACE)
{
Initialize();
}
void Initialize()
{
_awakenPhase = false;
}
void Reset() override
{
_Reset();
Initialize();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SLUDGE_CLAWS, 8s);
events.ScheduleEvent(EVENT_MUDSLIDE, 15s);
events.ScheduleEvent(EVENT_AWAKEN_THE_SWAMP, 30s);
if (IsMythic())
events.ScheduleEvent(EVENT_RAZORCHOKE_VINES, 20s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SLUDGE_CLAWS:
DoCastVictim(SPELL_SLUDGE_CLAWS);
events.Repeat(15s);
break;
case EVENT_MUDSLIDE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
{
me->SetFacingToObject(target);
DoCast(SPELL_MUDSLIDE);
}
events.Repeat(20s);
break;
}
case EVENT_AWAKEN_THE_SWAMP:
{
_awakenPhase = true;
DoCastAOE(SPELL_AWAKEN_THE_SWAMP);
// Schedule Skewering Roots
scheduler.Schedule(1s, 4s, [this](TaskContext context)
{
if (_awakenPhase)
{
Position pos = me->GetRandomNearPosition(20.0f);
me->CastSpell(pos, SPELL_SKEWERING_ROOT, true);
// Rushing Tide after root
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
{
me->CastSpell(target, SPELL_RUSHING_TIDE, true);
}
context.Repeat(1s);
}
});
scheduler.Schedule(4s, [this](TaskContext)
{
_awakenPhase = false;
});
events.Repeat(45s);
break;
}
case EVENT_RAZORCHOKE_VINES:
{
if (IsMythic())
{
// Select two random players for vines
if (Unit* first = SelectTarget(SelectTargetMethod::Random, 0, 40.0f))
if (Unit* second = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true, true, -SPELL_RAZORCHOKE_VINES))
{
first->CastSpell(second, SPELL_RAZORCHOKE_VINES, true);
second->CastSpell(first, SPELL_RAZORCHOKE_VINES, true);
}
}
events.Repeat(35s);
break;
}
default:
break;
}
}
}
private:
bool _awakenPhase;
};
void AddSC_boss_swampface()
{
RegisterOperationFloodgateCreatureAI(boss_swampface);
}
@@ -0,0 +1,89 @@
/*
* Copyright (C) WowCommunity Project
*
* This SourceCode is NOT free a software. Please hold everything Private
* and read our Terms
*/
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "operation_floodgate.h"
#include "GameObject.h"
#include "Map.h"
#include "TemporarySummon.h"
#include "CreatureAI.h"
static constexpr ObjectData creatureData[] =
{
{ BOSS_BIG_MOMMA, DATA_BIG_MOMMA },
{ BOSS_DEMOLITION_DUO, DATA_DEMOLITION_DUO },
{ BOSS_SWAMPFACE, DATA_SWAMPFACE },
{ BOSS_GEEZLE_GIGAZAP, DATA_GEEZLE_GIGAZAP },
{ 0, 0 } // END
};
static constexpr DungeonEncounterData const encounters[] =
{
{ DATA_BIG_MOMMA, {{ 3020 }} },
{ DATA_DEMOLITION_DUO, {{ 3019 }} },
{ DATA_SWAMPFACE, {{ 3053 }} },
{ DATA_GEEZLE_GIGAZAP, {{ 3054 }} },
};
class instance_operation_floodgate : public InstanceMapScript
{
public:
instance_operation_floodgate() : InstanceMapScript(OPFGScriptName, 2773) { }
struct instance_operation_floodgate_InstanceMapScript : public InstanceScript
{
instance_operation_floodgate_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, {});
LoadDungeonEncounterData(encounters);
}
void OnPlayerEnter(Player* player) override
{
if (!player->GetGroup() || !player->GetGroup()->GetLeaderGUID())
return;
ObjectGuid leaderguid = player->GetGroup()->GetLeaderGUID();
if (!leaderguid)
return;
if (Player* leader = ObjectAccessor::GetPlayer(*player, leaderguid))
{
if (leader->GetTeam() == HORDE)
faction_group = HORDE;
else if (leader->GetTeam() == ALLIANCE)
faction_group = ALLIANCE;
else
faction_group = HORDE;
}
player->GetGroup()->AddFollowerModeBots(player);
}
void OnPlayerExit(Player* player)
{
player->GetGroup()->DespawnFollowerModeBots(player);
}
private:
bool faction_group = HORDE;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_operation_floodgate_InstanceMapScript(map);
}
};
void AddSC_instance_operation_floodgate()
{
new instance_operation_floodgate();
}
@@ -0,0 +1,48 @@
/*
* Copyright (C) WowCommunity Project
*
* This SourceCode is NOT free a software. Please hold everything Private
* and read our Terms
*/
#ifndef DEF_OPERATION_FLOODGATE_H_
#define DEF_OPERATION_FLOODGATE_H_
#include "CreatureAIImpl.h"
#define OPFGScriptName "instance_operation_floodgate"
#define DataHeader "OPFG"
constexpr uint32 EncounterCount = 4;
enum OperationFloodgateDataTypes
{
// Encounters
DATA_BIG_MOMMA = 0,
DATA_DEMOLITION_DUO,
DATA_SWAMPFACE,
DATA_GEEZLE_GIGAZAP,
DATA_BRONT
};
enum OperationFloodgateCreatureIds
{
// Bosses
BOSS_BIG_MOMMA = 226398,
BOSS_DEMOLITION_DUO = 226403,
BOSS_SWAMPFACE = 226396,
BOSS_GEEZLE_GIGAZAP = 242255,
//creature
NPC_DARKFUSE_MECHADRONE = 228424,
};
template <class AI, class T>
inline AI* GetOperationFloodgateAI(T* obj)
{
return GetInstanceAI<AI>(obj, OPFGScriptName);
}
#define RegisterOperationFloodgateCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetOperationFloodgateAI)
#endif
@@ -53,6 +53,13 @@ void AddSC_boss_blazikon();
void AddSC_boss_the_candle_king(); void AddSC_boss_the_candle_king();
void AddSC_boss_the_darkness(); void AddSC_boss_the_darkness();
//Operation Floodgate
void AddSC_instance_operation_floodgate();
void AddSC_boss_big_momma();
void AddSC_boss_demolition_duo();
void AddSC_boss_geezle_gigazap();
void AddSC_boss_swampface();
// The name of this function should match: // The name of this function should match:
// void Add${NameOfDirectory}Scripts() // void Add${NameOfDirectory}Scripts()
void AddWarWithinScripts() void AddWarWithinScripts()
@@ -100,4 +107,12 @@ void AddWarWithinScripts()
AddSC_boss_blazikon(); AddSC_boss_blazikon();
AddSC_boss_the_candle_king(); AddSC_boss_the_candle_king();
AddSC_boss_the_darkness(); AddSC_boss_the_darkness();
//Operation Floodgate
AddSC_instance_operation_floodgate();
AddSC_boss_big_momma();
AddSC_boss_demolition_duo();
AddSC_boss_geezle_gigazap();
AddSC_boss_swampface();
} }