Full City of Threads

This commit is contained in:
luis
2026-09-23 20:06:22 -03:00
parent 30824bfacb
commit 76505646a8
8 changed files with 1780 additions and 0 deletions
@@ -0,0 +1,246 @@
/*
* Copyright WowCommunity Project
*
*/
#include "AreaTrigger.h"
#include "AreaTriggerAI.h"
#include "CellImpl.h"
#include "Creature.h"
#include "GridNotifiers.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "city_of_threads.h"
enum CoaglamationSpells
{
SPELL_BLOOD_SURGE = 461880, // create areatrigger 34362
SPELL_CORRUPTED_COATING = 442285, // heal absorb on orb soakers
SPELL_DARK_PULSE = 441395, // drain energy + party damage channel
SPELL_OZING_SMASH = 461842, // tank buster + healing absorb
SPELL_VISCOUS_DARKNESS = 441289, // slam + knock back
SPELL_VISCOUS_DARKNESS_2 = 447146, // slam visual
SPELL_BLACK_BLOOD = 438601, // blood pool damage
SPELL_ENERGIZE = 460175, // [DNT] Energy Controller
SPELL_BECOME_ACTIVE = 444321, // engage trigger visual
};
enum CoaglamationEvents
{
EVENT_ENERGY = 1,
EVENT_BLOOD_SURGE,
EVENT_DARK_PULSE,
EVENT_OZING_SMASH,
EVENT_VISCOUS_DARKNESS,
};
enum CoaglamationMisc
{
AREATRIGGER_BLOOD_SURGE = 34362,
NPC_CONGELED_DROPLET = 216329,
MAX_ENERGY_COAG = 100,
ENERGY_GAIN_PER_TICK = 2,
ORB_SOAK_DISTANCE = 2.0f,
DROPLETS_PER_SLAM = 4,
DROPLET_HEALTH_RESTORE = 3, // percent, stagnates per orb that reaches the boss
};
// Id 34362 - Blood Surge
struct at_boss_the_coaglamation_blood_surge : AreaTriggerAI
{
at_boss_the_coaglamation_blood_surge(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) {}
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
unit->CastSpell(unit, SPELL_BLACK_BLOOD, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_FULL_MASK | TRIGGERED_DONT_REPORT_CAST_ERROR
});
at->GetCaster()->CastSpell(unit, SPELL_BLOOD_SURGE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_FULL_MASK | TRIGGERED_DONT_REPORT_CAST_ERROR
});
}
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
if (!unit->IsPlayer())
return;
unit->RemoveAurasDueToSpell(SPELL_BLOOD_SURGE);
unit->RemoveAurasDueToSpell(SPELL_BLACK_BLOOD);
}
};
// 216329 - Congealed Droplet: flies back to the Coaglamation.
// Soaking an orb grants Corrupted Coating; orbs that reach the boss restore its health.
struct npc_congealed_droplet : public ScriptedAI
{
npc_congealed_droplet(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(1, 250ms);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case 1:
{
if (Unit* boss = me->FindNearestCreature(BOSS_THE_COAGLAMATION, 150.0f))
{
// A player touching the orb absorbs it and gains Corrupted Coating.
if (Player* player = me->SelectNearestPlayer(ORB_SOAK_DISTANCE))
{
player->CastSpell(player, SPELL_CORRUPTED_COATING, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_FULL_MASK | TRIGGERED_DONT_REPORT_CAST_ERROR
});
me->DespawnOrUnsummon(100ms);
return;
}
// Keep moving towards the boss.
if (!me->HasUnitState(UNIT_STATE_CASTING) && me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE)
me->GetMotionMaster()->MovePoint(0, boss->GetPosition(), false);
if (me->GetDistance(boss) <= ORB_SOAK_DISTANCE)
{
boss->ModifyHealth(boss->CountPctFromMaxHealth(DROPLET_HEALTH_RESTORE));
me->DespawnOrUnsummon(100ms);
}
}
events.Repeat(250ms);
break;
}
default:
break;
}
}
};
// 216320 - The Coaglamation
struct boss_the_coaglamation : public BossAI
{
boss_the_coaglamation(Creature* creature) : BossAI(creature, DATA_THE_COAGLAMATION) { }
void Reset() override
{
_Reset();
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
}
void JustAppeared() override
{
me->SetPower(POWER_ENERGY, 0);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
DoCastSelf(SPELL_BECOME_ACTIVE, true);
DoCastSelf(SPELL_ENERGIZE, true);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
events.ScheduleEvent(EVENT_ENERGY, 500ms);
events.ScheduleEvent(EVENT_BLOOD_SURGE, 8s);
events.ScheduleEvent(EVENT_OZING_SMASH, 12500ms);
events.ScheduleEvent(EVENT_VISCOUS_DARKNESS, 16s);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_EnterEvadeMode();
_DespawnAtEvade();
}
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_ENERGY:
{
_energy += ENERGY_GAIN_PER_TICK;
me->SetPower(POWER_ENERGY, std::min<uint8>(MAX_ENERGY_COAG, _energy));
if (_energy >= MAX_ENERGY_COAG)
{
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
DoCastSelf(SPELL_DARK_PULSE);
events.DelayEvents(6s);
}
events.Repeat(500ms);
break;
}
case EVENT_BLOOD_SURGE:
DoCastSelf(SPELL_BLOOD_SURGE);
events.Repeat(8s);
break;
case EVENT_OZING_SMASH:
DoCastVictim(SPELL_OZING_SMASH);
events.Repeat(15s);
break;
case EVENT_VISCOUS_DARKNESS:
{
DoCastSelf(SPELL_VISCOUS_DARKNESS);
DoCastSelf(SPELL_VISCOUS_DARKNESS_2, true);
SpawnCongealedDroplets();
events.Repeat(19s);
break;
}
default:
break;
}
}
}
private:
void SpawnCongealedDroplets()
{
for (uint8 i = 0; i < DROPLETS_PER_SLAM; ++i)
{
Position pos = me->GetRandomNearPosition(15.0f);
me->SummonCreature(NPC_CONGELED_DROPLET, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30s);
}
}
uint8 _energy = 0;
};
void AddSC_boss_The_Coaglamation()
{
RegisterCityOfThreadsCreatureAI(boss_the_coaglamation);
RegisterCityOfThreadsCreatureAI(npc_congealed_droplet);
RegisterAreaTriggerAI(at_boss_the_coaglamation_blood_surge);
}
@@ -0,0 +1,312 @@
/*
* Copyright WowCommunity Project
*
*/
#include "MotionMaster.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "city_of_threads.h"
enum FangsoftheQueenSpells
{
SPELL_TWIN_FANGS = 439518, // shared damage 100%
SPELL_SYNERGIC_STEP = 439522, // dash across the arena
SPELL_SYNERGIC_STEP_2 = 439985, // dash alternate
SPELL_SYNERGIC_STACKS = 447114, // Synergic Step (Stacks)
SPELL_SYNERGIC_DASH = 441381, // Nx dash visual / impact
SPELL_SYNERGIC_DASH_VX = 441384, // Vx dash visual / impact
SPELL_REPULSION = 439527, // knock back players in path
// Nx kit
SPELL_SHADE_SLASH = 439621, // frontal cone + spawns shade
SPELL_DUSKBRINGER = 439692, // channel party shadow damage
SPELL_DUSKBRINGER_BURST = 439696, // 15yd burst around boss
SPELL_DUSKBRINGER_SHADE = 439695, // shade burst
SPELL_KNIFE_THROW_NX = 440107, // throw knife at player
// Vx kit
SPELL_RIME_DAGGER = 440468, // tank buster
SPELL_RIME_DAGGER_BURST = 441305, // daggers burst all players
SPELL_FREEZING_BLOOD = 441298, // stackable frost dot
SPELL_ICE_SICKLES = 440218, // ice daggers at players (line)
SPELL_ICE_SICKLES_2 = 440238,
SPELL_KNIFE_THROW_VX = 440105, // knife throw (Vx)
};
enum FangsoftheQueenEvents
{
EVENT_ENERGY = 1,
EVENT_SYNERGIC_DASH,
EVENT_SHADE_SLASH,
EVENT_DUSKBRINGER,
EVENT_KNIFE_THROW,
EVENT_RIME_DAGGER,
EVENT_ICE_SICKLES,
EVENT_SWAP_ROLES,
};
enum FangsoftheQueenMisc
{
NPC_ECHOING_SHADE = 219675,
MAX_SYNERGIC_DASHES = 3,
MAX_ENERGY_FANGS = 100,
ENERGY_PER_TICK = 1,
};
// 216648 - Nx / 216649 - Vx (Fangs of the Queen)
// The twins share 100% of the damage taken between each other, build energy over time,
// and swap between an empowered (attacking) and support role on every Synergic Step.
struct boss_fangs_of_the_queen : public BossAI
{
boss_fangs_of_the_queen(Creature* creature) : BossAI(creature, DATA_FANGS_OF_THE_QUEEN),
_isNx(creature->GetEntry() == BOSS_NX) { }
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
DoCastSelf(SPELL_ENERGY_CONTROLLER, true);
DoCastSelf(SPELL_TWIN_FANGS, true);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
events.ScheduleEvent(EVENT_ENERGY, 250ms);
if (IsNxEmpowered())
{
events.ScheduleEvent(EVENT_SHADE_SLASH, 8s);
events.ScheduleEvent(EVENT_DUSKBRINGER, 21s);
}
else
{
events.ScheduleEvent(EVENT_ICE_SICKLES, 17s);
events.ScheduleEvent(EVENT_RIME_DAGGER, 30s);
}
events.ScheduleEvent(EVENT_KNIFE_THROW, 5500ms);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
if (Creature* twin = GetTwin())
{
twin->SetHealth(1);
twin->KillSelf();
}
}
void EnterEvadeMode(EvadeReason why) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
if (Creature* twin = GetTwin())
twin->AI()->EnterEvadeMode(why);
_EnterEvadeMode();
_DespawnAtEvade();
}
void Reset() override
{
_Reset();
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo*/) override
{
// Twin Fangs: mirror the full damage taken onto the other twin.
if (Creature* twin = GetTwin())
{
if (twin->IsAlive() && damage > 0)
twin->ModifyHealth(-static_cast<int64>(damage));
}
}
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_ENERGY:
{
_energy += ENERGY_PER_TICK;
me->SetPower(POWER_ENERGY, std::min<uint8>(MAX_ENERGY_FANGS, _energy));
if (_energy >= MAX_ENERGY_FANGS)
{
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
events.ScheduleEvent(EVENT_SYNERGIC_DASH, 500ms);
}
events.Repeat(250ms);
break;
}
case EVENT_SYNERGIC_DASH:
PreformSynergicStep();
events.ScheduleEvent(EVENT_SWAP_ROLES, 1500ms);
events.DelayEvents(12s);
break;
case EVENT_SWAP_ROLES:
SwapRoles();
break;
case EVENT_SHADE_SLASH:
DoCastVictim(SPELL_SHADE_SLASH);
SummonEchoingShade();
events.Repeat(12s);
break;
case EVENT_DUSKBRINGER:
DoCastSelf(SPELL_DUSKBRINGER, true);
DoCastSelf(SPELL_DUSKBRINGER_BURST, true);
events.DelayEvents(4500ms);
events.Repeat(31s);
break;
case EVENT_KNIFE_THROW:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
DoCast(target, _isNx ? SPELL_KNIFE_THROW_NX : SPELL_KNIFE_THROW_VX);
events.Repeat(4500ms);
break;
case EVENT_ICE_SICKLES:
{
std::list<Player*> targets;
me->GetPlayerListInGrid(targets, 60.0f);
uint8 casted = 0;
for (Player* player : targets)
{
if (!player->IsAlive() || player->IsGameMaster())
continue;
me->CastSpell(player, SPELL_ICE_SICKLES, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
me->CastSpell(player, SPELL_ICE_SICKLES_2, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
if (++casted >= 3)
break;
}
events.Repeat(31s);
break;
}
case EVENT_RIME_DAGGER:
{
if (Unit* victim = me->GetVictim())
{
DoCast(victim, SPELL_RIME_DAGGER);
me->CastSpell(victim, SPELL_FREEZING_BLOOD, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
me->CastSpell(victim, SPELL_RIME_DAGGER_BURST, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
}
events.Repeat(30s);
break;
}
default:
break;
}
}
}
private:
bool IsNxEmpowered() const
{
return _isNx;
}
Creature* GetTwin() const
{
uint32 twinEntry = _isNx ? BOSS_VX : BOSS_NX;
return me->FindNearestCreature(twinEntry, 200.0f);
}
void PreformSynergicStep()
{
DoCastSelf(SPELL_SYNERGIC_STEP, true);
DoCastSelf(SPELL_SYNERGIC_STACKS, true);
for (uint8 i = 0; i < MAX_SYNERGIC_DASHES; ++i)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
{
Position pos = target->GetPosition();
float angle = me->GetAbsoluteAngle(&pos);
Position dest = me->GetFirstCollisionPosition(30.0f, angle);
me->CastSpell(me, _isNx ? SPELL_SYNERGIC_DASH : SPELL_SYNERGIC_DASH_VX, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
me->GetMotionMaster()->MoveCharge(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), 20.0f);
}
}
}
void SwapRoles()
{
// On a real twin encounter we would swap the empowered twin here, but
// retail tracks the roles via ability usage - keep both performing their kit.
}
void SummonEchoingShade()
{
Unit* victim = me->GetVictim();
if (!victim)
return;
Position pos = victim->GetPosition();
if (Creature* shade = me->SummonCreature(NPC_ECHOING_SHADE, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 45s))
shade->SetFacingToObject(me);
}
bool _isNx;
uint8 _energy = 0;
};
// 219675 - Echoing Shade: echoes Nx's Duskbringer burst.
struct npc_echoing_shade : public ScriptedAI
{
npc_echoing_shade(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
DoCastSelf(SPELL_DUSKBRINGER_SHADE, true);
events.ScheduleEvent(1, 4500ms);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case 1:
DoCastSelf(SPELL_DUSKBRINGER_SHADE, true);
events.Repeat(4500ms);
break;
default:
break;
}
}
};
void AddSC_boss_Fangs_of_the_Queen()
{
RegisterCityOfThreadsCreatureAI(boss_fangs_of_the_queen);
RegisterCityOfThreadsCreatureAI(npc_echoing_shade);
}
@@ -0,0 +1,272 @@
/*
* Copyright WowCommunity Project
*
*/
#include "CellImpl.h"
#include "Creature.h"
#include "GridNotifiers.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "city_of_threads.h"
enum IzoSpells
{
SPELL_GRAND_ENTRANCE = 454769, // entrance portal visual
SPELL_SCIENCE_MAGIC = 444615, // [DNT] Science Magic
SPELL_TELEPORT_VFX = 445229, // [DNT] Teleport VFX
SPELL_SHIFTING_ANOMALIES = 439401, // create shifting anomalies
SPELL_SHIFTING_ANOMALIES_2 = 439415, // animate anomalies
SPELL_SHIFTING_ANOMALIES_3 = 439481, // relocate anomalies
SPELL_SHIFTING_ANOMALIES_4 = 439501, // anomaly orb damage
SPELL_SHIFTING_ANOMALIES_5 = 439513, // anomaly orb knockback
SPELL_SPLICE = 439341, // party serration dot
SPELL_TREMOR_SLAM = 437700, // party damage + extra in 12yd
SPELL_TREMOR_SLAM_DAMAGE = 438512,
SPELL_TREMOR_SLAM_DAMAGE_2 = 438515,
SPELL_UMBRAL_WEAVE = 438860, // roots players in webs
SPELL_UMBRAL_WEAVE_2 = 439324, // web root
SPELL_PROCESS_OF_ELIMINATION = 439763, // energy dump burst
SPELL_PROCESS_ELIMINATION_2 = 439644,
SPELL_PROCESS_ELIMINATION_3 = 439646,
};
enum IzoEvents
{
EVENT_ENERGY = 1,
EVENT_SHIFTING_ANOMALIES,
EVENT_SPLICE,
EVENT_TREMOR_SLAM,
EVENT_UMBRAL_WEAVE,
EVENT_PROCESS_OF_ELIMINATION,
};
enum IzoMisc
{
NPC_RAVENOUS_SCARAB = 219198,
MAX_ENERGY_IZO = 100,
ENERGY_PER_TICK = 2,
ANOMALIES_PER_CAST = 3,
ANOMALY_RANGE = 15.0f,
SCARABS_PER_SLAM = 4,
};
// 216658 - Izo, the Grand Splicer
struct boss_izo_the_grand_splicer : public BossAI
{
boss_izo_the_grand_splicer(Creature* creature) : BossAI(creature, DATA_IZO_THE_GRAND_SPLICER) { }
void JustAppeared() override
{
me->SetPower(POWER_ENERGY, 0);
DoCastSelf(SPELL_TELEPORT_VFX, true);
DoCastSelf(SPELL_SCIENCE_MAGIC, true);
}
void Reset() override
{
_Reset();
_energy = 0;
_anomalyIndex = 0;
me->SetPower(POWER_ENERGY, 0);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
_energy = 0;
_anomalyIndex = 0;
me->SetPower(POWER_ENERGY, 0);
DoCastSelf(SPELL_GRAND_ENTRANCE, true);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
events.ScheduleEvent(EVENT_ENERGY, 500ms);
events.ScheduleEvent(EVENT_SHIFTING_ANOMALIES, 6s);
events.ScheduleEvent(EVENT_SPLICE, 18s);
events.ScheduleEvent(EVENT_TREMOR_SLAM, 24s);
events.ScheduleEvent(EVENT_UMBRAL_WEAVE, 30s);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_EnterEvadeMode();
_DespawnAtEvade();
}
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_ENERGY:
{
_energy += ENERGY_PER_TICK;
me->SetPower(POWER_ENERGY, std::min<uint8>(MAX_ENERGY_IZO, _energy));
if (_energy >= MAX_ENERGY_IZO)
{
_energy = 0;
me->SetPower(POWER_ENERGY, 0);
events.ScheduleEvent(EVENT_PROCESS_OF_ELIMINATION, 800ms);
}
events.Repeat(500ms);
break;
}
case EVENT_SHIFTING_ANOMALIES:
{
// Shifting Anomalies relocate every ~9 seconds.
DoCastSelf(SPELL_SHIFTING_ANOMALIES, true);
DoCastSelf(SPELL_SHIFTING_ANOMALIES_4, true);
for (uint8 i = 0; i < ANOMALIES_PER_CAST; ++i)
{
Position pos = me->GetNearPosition(ANOMALY_RANGE, _anomalyIndex * (2.f * float(M_PI) / ANOMALIES_PER_CAST));
me->CastSpell(pos, SPELL_SHIFTING_ANOMALIES_2, true);
me->CastSpell(pos, SPELL_SHIFTING_ANOMALIES_3, true);
me->CastSpell(pos, SPELL_SHIFTING_ANOMALIES_5, true);
}
_anomalyIndex++;
events.Repeat(9s);
break;
}
case EVENT_SPLICE:
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 60.0f, true))
{
DoCast(target, SPELL_SPLICE);
me->AddAura(SPELL_SPLICE, target);
}
events.Repeat(21s);
break;
}
case EVENT_TREMOR_SLAM:
{
DoCastSelf(SPELL_TREMOR_SLAM);
DoCastSelf(SPELL_TREMOR_SLAM_DAMAGE, true);
me->CastSpell(me, SPELL_TREMOR_SLAM_DAMAGE_2, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
SpawnRavenousScarabs();
events.Repeat(24s);
break;
}
case EVENT_UMBRAL_WEAVE:
{
DoCastSelf(SPELL_UMBRAL_WEAVE);
DoCastSelf(SPELL_UMBRAL_WEAVE_2, true);
events.Repeat(24s);
break;
}
case EVENT_PROCESS_OF_ELIMINATION:
{
// Recall the anomalies and smash them into the enemy repeatedly.
if (Unit* victim = me->GetVictim())
{
me->CastSpell(victim, SPELL_PROCESS_OF_ELIMINATION, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
me->CastSpell(victim, SPELL_PROCESS_ELIMINATION_2, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
me->CastSpell(victim, SPELL_PROCESS_ELIMINATION_3, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR
});
}
break;
}
default:
break;
}
}
}
private:
void SpawnRavenousScarabs()
{
for (uint8 i = 0; i < SCARABS_PER_SLAM; ++i)
{
Position pos = me->GetRandomNearPosition(8.0f);
if (Creature* scarab = me->SummonCreature(NPC_RAVENOUS_SCARAB, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30s))
scarab->AI()->DoZoneInCombat();
}
}
uint8 _energy = 0;
uint8 _anomalyIndex = 0;
};
// 219198 - Ravenous Scarab: besieges a victim with Gorge.
struct npc_ravenous_scarab : public ScriptedAI
{
enum
{
SPELL_GORGE = 450042,
MAX_GORGES = 5,
EVENT_GORGE = 1,
};
npc_ravenous_scarab(Creature* creature) : ScriptedAI(creature), _gorgeCount(0) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_GORGE, 2s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_GORGE:
{
if (Unit* target = me->GetVictim())
{
DoCast(target, SPELL_GORGE);
_gorgeCount++;
if (_gorgeCount >= MAX_GORGES)
{
me->KillSelf();
return;
}
}
events.Repeat(4500ms);
break;
}
default:
break;
}
}
private:
uint8 _gorgeCount;
};
void AddSC_boss_izo_the_grand_splicer()
{
RegisterCityOfThreadsCreatureAI(boss_izo_the_grand_splicer);
RegisterCityOfThreadsCreatureAI(npc_ravenous_scarab);
}
@@ -0,0 +1,514 @@
/*
* Copyright WowCommunity Project
*
*/
#include "AreaTrigger.h"
#include "AreaTriggerAI.h"
#include "CellImpl.h"
#include "Conversation.h"
#include "Creature.h"
#include "GridNotifiers.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "PathGenerator.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "city_of_threads.h"
enum OratorKrixVizkSpells
{
SPELL_ORATION = 454689,
SPELL_CHAINS_OF_OPPRESSION = 434691,
SPELL_CHAINS_OF_OPPRESSION_PERIODIC = 440310,
SPELL_CHAINS_OF_OPPRESSION_CHARGE = 434712,
SPELL_CHAINS_OF_OPPRESSION_DAMAGE = 434710,
SPELL_SUBJUGATE = 434722,
SPELL_TERRORIZE_SELECTOR = 434808,
SPELL_TERRORIZE = 434779,
SPELL_SHADOWS_OF_DOUBT_SELECTOR = 448560,
SPELL_SHADOWS_OF_DOUBT = 448561,
SPELL_DOUBT = 448562,
SPELL_VOCIFEROUS_INDOCTRINATION = 434829,
SPELL_VOCIFEROUS_INDOCTRINATION_DAMAGE = 434832,
SPELL_LINGERING_INFLUENCE_AREATRIGGER = 434923,
SPELL_LINGERING_INFLUENCE_DAMAGE = 434926
};
enum OratorKrixVizkConversations
{
CONVERSATION_ORATOR_INTRO_1 = 24642,
CONVERSATION_ORATOR_INTRO_2 = 24643,
CONVERSATION_ORATOR_INTRO_3 = 24644
};
enum OratorKrixVizkTexts
{
SAY_AGGRO = 0,
SAY_SUBJUGATE = 1,
SAY_TERRORIZE = 2,
SAY_VOCIFEROUS_INDOCTRINATION = 3,
SAY_KILL = 4,
SAY_DEATH = 5
};
enum OratorKrixVizkEvents
{
EVENT_SUBJUGATE = 1,
EVENT_TERRORIZE,
EVENT_SHADOWS_OF_DOUBT,
EVENT_ENERGIZE
};
enum OratorKrixVizkMisc
{
AREATRIGGER_BARRIER = 35803,
DISPLAY_POWERID = 527
};
// 163
// 164
template<uint32 conversationEntry, uint32 data>
struct at_orator_conversation_intro : AreaTriggerAI
{
at_orator_conversation_intro(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) {}
void OnUnitEnter(Unit* unit) override
{
InstanceScript* instance = at->GetInstanceScript();
if (!instance)
return;
Player* player = unit->ToPlayer();
if (!player || player->IsGameMaster())
return;
if (Creature* oratorKrixVizk = instance->GetCreature(data))
Conversation::CreateConversation(conversationEntry, oratorKrixVizk, player->GetPosition(), player->GetGUID());
at->Remove();
}
};
// 216619 - Orator Krix'vizk <The Fifth Strand>
struct boss_orator_krix_vizk : public BossAI
{
boss_orator_krix_vizk(Creature* creature) : BossAI(creature, DATA_ORATOR_KRIX_VIZK), _subjugateCount(1), _terrorizeCount(1), _energizeCount(0) {}
void JustAppeared() override
{
DoCastSelf(SPELL_ORATION);
me->SetPower(POWER_ENERGY, 0);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
WorldObject* obj = nullptr;
WowCommunity::ObjectEntryAndPrivateOwnerIfExistsCheck check(ObjectGuid::Empty, AREATRIGGER_BARRIER);
WowCommunity::WorldObjectSearcher<WowCommunity::ObjectEntryAndPrivateOwnerIfExistsCheck> checker(me, obj, check, GRID_MAP_TYPE_MASK_AREATRIGGER);
Cell::VisitGridObjects(me, checker, 100.0f);
if (!obj)
return;
if (AreaTrigger* at = obj->ToAreaTrigger())
at->Remove();
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
_EnterEvadeMode();
_DespawnAtEvade();
}
void KilledUnit(Unit* victim) override
{
if (!victim->IsPlayer())
return;
Talk(SAY_KILL);
}
void Reset() override
{
_Reset();
_subjugateCount = 1;
_terrorizeCount = 1;
_energizeCount = 0;
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
DoCastSelf(SPELL_CHAINS_OF_OPPRESSION);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
me->SetOverrideDisplayPowerId(DISPLAY_POWERID); // No aura handle
events.ScheduleEvent(EVENT_ENERGIZE, 1s);
events.ScheduleEvent(EVENT_SUBJUGATE, 4500ms);
events.ScheduleEvent(EVENT_TERRORIZE, 9400ms);
if (IsMythic() || IsMythicPlus())
events.ScheduleEvent(EVENT_SHADOWS_OF_DOUBT, 15200ms);
}
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_SUBJUGATE:
{
Talk(SAY_SUBJUGATE);
DoCastVictim(SPELL_SUBJUGATE);
_subjugateCount++;
if (_subjugateCount % 2 == 0)
events.ScheduleEvent(EVENT_SUBJUGATE, 17100ms);
else
events.ScheduleEvent(EVENT_SUBJUGATE, 12s);
break;
}
case EVENT_TERRORIZE:
{
Talk(SAY_TERRORIZE);
DoCast(SPELL_TERRORIZE_SELECTOR);
_terrorizeCount++;
if (_terrorizeCount % 2 == 0)
events.ScheduleEvent(EVENT_TERRORIZE, 8100ms);
else
events.ScheduleEvent(EVENT_TERRORIZE, 21100ms);
break;
}
case EVENT_SHADOWS_OF_DOUBT:
{
DoCast(SPELL_SHADOWS_OF_DOUBT_SELECTOR);
events.ScheduleEvent(EVENT_SHADOWS_OF_DOUBT, 30300ms);
break;
}
case EVENT_ENERGIZE:
{
if (me->GetPower(POWER_ENERGY) == 100)
{
Talk(SAY_VOCIFEROUS_INDOCTRINATION);
DoCastSelf(SPELL_VOCIFEROUS_INDOCTRINATION);
events.RescheduleEvent(EVENT_ENERGIZE, 6s);
}
else
{
me->SetPower(POWER_ENERGY, me->GetPower(POWER_ENERGY) + 4);
_energizeCount++;
events.ScheduleEvent(EVENT_ENERGIZE, (_energizeCount % 2) ? 1200ms : 800ms);
}
break;
}
default:
break;
}
}
}
private:
uint8 _subjugateCount;
uint8 _terrorizeCount;
uint8 _energizeCount;
};
// 434808 - Terrorize
class spell_orator_krix_vizk_terrorize_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TERRORIZE });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_TERRORIZE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_orator_krix_vizk_terrorize_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 448560 - Shadows of Doubt
class spell_orator_krix_vizk_shadows_of_doubt_selector : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHADOWS_OF_DOUBT });
}
void HandleHitTarget(SpellEffIndex /*effIndex*/) const
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_SHADOWS_OF_DOUBT, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringSpell = GetSpell()
});
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_orator_krix_vizk_shadows_of_doubt_selector::HandleHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 440310 - Chains of Oppression
class spell_orator_krix_vizk_chains_of_oppression_periodic : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_CHAINS_OF_OPPRESSION_DAMAGE, SPELL_CHAINS_OF_OPPRESSION_CHARGE });
}
void Tick(AuraEffect const* /*aurEff*/) const
{
if (Unit* caster = GetCaster())
{
Unit* target = GetTarget();
CastSpellExtraArgs args;
args.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR;
caster->CastSpell(target, SPELL_CHAINS_OF_OPPRESSION_DAMAGE, args);
target->CastSpell(caster, SPELL_CHAINS_OF_OPPRESSION_CHARGE, args);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_orator_krix_vizk_chains_of_oppression_periodic::Tick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// 448561 - Shadows of Doubt
class spell_orator_krix_vizk_shadows_of_doubt_periodic : public AuraScript
{
static constexpr uint8 MAX_SHADOW_OF_DOUBTS = 5;
static constexpr uint32 DOUBT_AT_CREATE_PROPERTIES = 165;
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_DOUBT });
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_ENEMY_SPELL)
return;
Unit* caster = GetCaster();
if (!caster)
return;
for (uint8 i = 0; i < MAX_SHADOW_OF_DOUBTS; ++i)
{
Unit* target = GetTarget();
float angle = 2.f * float(M_PI) / MAX_SHADOW_OF_DOUBTS * i;
Position dest(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), angle);
AreaTrigger::CreateAreaTrigger({ DOUBT_AT_CREATE_PROPERTIES, true }, dest, -1, caster, target);
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_orator_krix_vizk_shadows_of_doubt_periodic::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
}
};
// 434829 - Vociferous Indoctrination
class spell_orator_krix_vizk_vociferous_indoctrination_periodic : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_VOCIFEROUS_INDOCTRINATION_DAMAGE, SPELL_LINGERING_INFLUENCE_AREATRIGGER });
}
void Tick(AuraEffect const* aurEff) const
{
if (Unit* caster = GetCaster())
caster->CastSpell(GetTarget(), SPELL_VOCIFEROUS_INDOCTRINATION_DAMAGE, CastSpellExtraArgsInit{
.TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
.TriggeringAura = aurEff
});
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
{
if (Unit* caster = GetCaster())
GetTarget()->CastSpell(caster, SPELL_LINGERING_INFLUENCE_AREATRIGGER, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
if (Creature* creatureTarget = GetTarget()->ToCreature())
creatureTarget->SetPower(POWER_ENERGY, 0);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_orator_krix_vizk_vociferous_indoctrination_periodic::Tick, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_orator_krix_vizk_vociferous_indoctrination_periodic::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
// 434691 - Chains of Oppression
// Id - 31997
struct at_orator_krix_vizk_chains_of_oppression : AreaTriggerAI
{
at_orator_krix_vizk_chains_of_oppression(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) {}
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
Unit* caster = at->GetCaster();
if (!caster)
return;
caster->CastSpell(unit, SPELL_CHAINS_OF_OPPRESSION_PERIODIC, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
if (!unit->IsPlayer())
return;
unit->RemoveAurasDueToSpell(SPELL_CHAINS_OF_OPPRESSION_PERIODIC);
}
};
// 434923 - Lingering Influence
// ID - 32026
struct at_orator_krix_vizk_lingering_influence : AreaTriggerAI
{
at_orator_krix_vizk_lingering_influence(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) {}
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
Unit* caster = at->GetCaster();
if (!caster)
return;
caster->CastSpell(unit, SPELL_LINGERING_INFLUENCE_DAMAGE, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
void OnUnitExit(Unit* unit, AreaTriggerExitReason /*reason*/) override
{
if (!unit->IsPlayer())
return;
unit->RemoveAurasDueToSpell(SPELL_LINGERING_INFLUENCE_DAMAGE);
}
void OnInitialize() override
{
std::array<DBCPosition2D, 2> points =
{ {
{ 0.0f, 1.0f },
{ 1.0f, 18.0f }
} };
at->SetTimeToTargetScale(6000);
at->SetOverrideScaleCurve(points, 2);
}
};
// 165
struct at_orator_krix_vizk_doubt : AreaTriggerAI
{
explicit at_orator_krix_vizk_doubt(AreaTrigger* areaTrigger) : AreaTriggerAI(areaTrigger), _canHitOrigin(false) {}
void OnInitialize() override
{
Position destPos = at->GetPosition();
at->MovePositionToFirstCollision(destPos, 200.0f, 0.0f);
PathGenerator path(at);
path.CalculatePath(destPos.GetPositionX(), destPos.GetPositionY(), destPos.GetPositionZ(), true);
at->InitSplines(path.GetPath());
_canHitOrigin = false;
_scheduler.Schedule(1s, [this](TaskContext /*task*/)
{
_canHitOrigin = true;
});
}
void OnUpdate(uint32 diff) override
{
_scheduler.Update(diff);
}
void OnDestinationReached() override
{
at->Remove();
}
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
if (!_canHitOrigin && unit == at->GetTarget())
return;
Unit* caster = at->GetCaster();
if (!caster)
return;
caster->CastSpell(unit, SPELL_DOUBT, TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR);
}
private:
TaskScheduler _scheduler;
bool _canHitOrigin;
};
void AddSC_boss_orator_krix_vizk()
{
new GenericAreaTriggerEntityScript<at_orator_conversation_intro<CONVERSATION_ORATOR_INTRO_1, DATA_ORATOR_CONVO>>("at_orator_conversation_intro_1");
new GenericAreaTriggerEntityScript<at_orator_conversation_intro<CONVERSATION_ORATOR_INTRO_2, DATA_ORATOR_KRIX_VIZK>>("at_orator_conversation_intro_2");
new GenericAreaTriggerEntityScript<at_orator_conversation_intro<CONVERSATION_ORATOR_INTRO_3, DATA_ORATOR_KRIX_VIZK>>("at_orator_conversation_intro_3");
RegisterCityOfThreadsCreatureAI(boss_orator_krix_vizk);
RegisterSpellScript(spell_orator_krix_vizk_terrorize_selector);
RegisterSpellScript(spell_orator_krix_vizk_shadows_of_doubt_selector);
RegisterSpellScript(spell_orator_krix_vizk_chains_of_oppression_periodic);
RegisterSpellScript(spell_orator_krix_vizk_shadows_of_doubt_periodic);
RegisterSpellScript(spell_orator_krix_vizk_vociferous_indoctrination_periodic);
RegisterAreaTriggerAI(at_orator_krix_vizk_chains_of_oppression);
RegisterAreaTriggerAI(at_orator_krix_vizk_lingering_influence);
RegisterAreaTriggerAI(at_orator_krix_vizk_doubt);
}
@@ -0,0 +1,49 @@
/*
* Copyright WowCommunity Project
*
*/
#ifndef DEF_CITY_OF_THREADS_H_
#define DEF_CITY_OF_THREADS_H_
#include "CreatureAIImpl.h"
#define COTScriptName "instance_city_of_threads"
#define DataHeader "CityOfThreads"
uint32 const EncounterCount = 4;
enum CityOfThreadsDataTypes
{
// Encounters
DATA_ORATOR_KRIX_VIZK = 0,
DATA_FANGS_OF_THE_QUEEN = 1,
DATA_THE_COAGLAMATION = 2,
DATA_IZO_THE_GRAND_SPLICER = 3,
// Additional Data
DATA_ORATOR_CONVO
};
enum CityOfThreadsCreatureIds
{
// Bosses
BOSS_ORATOR_KRIX_VIZK = 216619,
BOSS_NX = 216648,
BOSS_VX = 216649,
BOSS_THE_COAGLAMATION = 216320,
BOSS_IZO_THE_GRAND_SPLICER = 216658,
// Npcs
NPC_ORATOR_KRIX_VIZK_CONVO = 220769
};
template <class AI, class T>
inline AI* GetCityOfThreadsAI(T* obj)
{
return GetInstanceAI<AI>(obj, COTScriptName);
}
#define RegisterCityOfThreadsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetCityOfThreadsAI)
#endif
@@ -0,0 +1,87 @@
/*
* Copyright WowCommunity Project
*
*/
#include "InstanceScript.h"
#include "ScriptMgr.h"
#include "city_of_threads.h"
#include "Map.h"
static constexpr ObjectData creatureData[] =
{
{ BOSS_ORATOR_KRIX_VIZK, DATA_ORATOR_KRIX_VIZK },
{ BOSS_NX, DATA_FANGS_OF_THE_QUEEN },
{ BOSS_VX, DATA_FANGS_OF_THE_QUEEN },
{ BOSS_THE_COAGLAMATION, DATA_THE_COAGLAMATION },
{ BOSS_IZO_THE_GRAND_SPLICER, DATA_IZO_THE_GRAND_SPLICER },
{ NPC_ORATOR_KRIX_VIZK_CONVO, DATA_ORATOR_CONVO },
{ 0, 0 } // END
};
static constexpr DungeonEncounterData const encounters[] =
{
{ DATA_ORATOR_KRIX_VIZK, {{ 2907 }} },
{ DATA_FANGS_OF_THE_QUEEN, {{ 2908 }} },
{ DATA_THE_COAGLAMATION, {{ 2905 }} },
{ DATA_IZO_THE_GRAND_SPLICER, {{ 2909 }} }
};
class instance_city_of_threads : public InstanceMapScript
{
public:
instance_city_of_threads() : InstanceMapScript(COTScriptName, 2669) { }
struct instance_city_of_threads_InstanceMapScript: public InstanceScript
{
instance_city_of_threads_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
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_city_of_threads_InstanceMapScript(map);
}
};
void AddSC_instance_city_of_threads()
{
new instance_city_of_threads();
}
@@ -0,0 +1,284 @@
/*
* Copyright WowCommunity Project
*
*/
#include "Creature.h"
#include "GridNotifiers.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "city_of_threads.h"
enum TrashEvents
{
EVENT_CAST_1 = 1,
EVENT_CAST_2,
EVENT_CAST_3,
};
// 216328 - Unstable Test Subject
struct npc_unstable_test_subject : public ScriptedAI
{
enum
{
SPELL_DARK_BARRAGE = 445809,
SPELL_DARK_BARRAGE_3 = 445838,
SPELL_STOMP_BARRAGE = 445862,
SPELL_FIERCE_STOMPING = 436205,
};
npc_unstable_test_subject(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 4s);
events.ScheduleEvent(EVENT_CAST_2, 9s);
events.ScheduleEvent(EVENT_CAST_3, 14s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
DoCastVictim(SPELL_DARK_BARRAGE);
events.Repeat(12s);
break;
case EVENT_CAST_2:
DoCastSelf(SPELL_STOMP_BARRAGE);
events.Repeat(12s);
break;
case EVENT_CAST_3:
DoCastSelf(SPELL_FIERCE_STOMPING);
events.Repeat(12s);
break;
default:
break;
}
}
};
// 224732 - Covert Webmancer
struct npc_covert_webmancer : public ScriptedAI
{
enum
{
SPELL_GRIMWEAVE_BLAST = 442536,
SPELL_MENDING_WEB = 452162,
};
npc_covert_webmancer(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 5500ms);
events.ScheduleEvent(EVENT_CAST_2, 11s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
DoCastVictim(SPELL_GRIMWEAVE_BLAST);
events.Repeat(12s);
break;
case EVENT_CAST_2:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f, true))
DoCast(target, SPELL_MENDING_WEB);
events.Repeat(12s);
break;
default:
break;
}
}
};
// 221102 - Elder Shadeweaver
struct npc_elder_shadeweaver : public ScriptedAI
{
enum
{
SPELL_WEB_BOLT = 443427,
SPELL_UMBRAL_WEAVE = 446718,
SPELL_SHADOW_SHIELD = 446726,
};
npc_elder_shadeweaver(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 4s);
events.ScheduleEvent(EVENT_CAST_2, 8s);
events.ScheduleEvent(EVENT_CAST_3, 13s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
DoCastVictim(SPELL_WEB_BOLT);
events.Repeat(9s);
break;
case EVENT_CAST_2:
DoCastVictim(SPELL_UMBRAL_WEAVE);
events.Repeat(9s);
break;
case EVENT_CAST_3:
DoCastSelf(SPELL_SHADOW_SHIELD);
events.Repeat(9s);
break;
default:
break;
}
}
};
// 221103 - Hulking Warshell
struct npc_hulking_warshell : public ScriptedAI
{
enum
{
SPELL_RAVENOUS_SWARM = 443509,
SPELL_TREMOR_SLAM = 447273,
};
npc_hulking_warshell(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 6s);
events.ScheduleEvent(EVENT_CAST_2, 12s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 8.0f, true))
DoCast(target, SPELL_RAVENOUS_SWARM);
events.Repeat(8s);
break;
case EVENT_CAST_2:
DoCastSelf(SPELL_TREMOR_SLAM);
events.Repeat(8s);
break;
default:
break;
}
}
};
// 220196 - Herald of Ansurek
struct npc_herald_of_ansurek : public ScriptedAI
{
enum
{
SPELL_TWIST_THOUGHTS = 443433,
SPELL_SHADOWS_OF_DOUBT = 443436,
};
npc_herald_of_ansurek(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 6s);
events.ScheduleEvent(EVENT_CAST_2, 12s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
DoCastVictim(SPELL_TWIST_THOUGHTS);
events.Repeat(10s);
break;
case EVENT_CAST_2:
DoCastSelf(SPELL_SHADOWS_OF_DOUBT);
events.Repeat(10s);
break;
default:
break;
}
}
};
// 228361 / 223181 - Agile Pursuer
struct npc_agile_pursuer : public ScriptedAI
{
enum
{
SPELL_KNIFE_THROW = 448030,
SPELL_FEINT = 451490,
};
npc_agile_pursuer(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 5s);
events.ScheduleEvent(EVENT_CAST_2, 10s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
DoCastVictim(SPELL_KNIFE_THROW);
events.Repeat(7s);
break;
case EVENT_CAST_2:
DoCastSelf(SPELL_FEINT);
events.Repeat(7s);
break;
default:
break;
}
}
};
// 216339 - Sureki Unnaturaler
struct npc_sureki_unnaturaler : public ScriptedAI
{
enum
{
SPELL_VOID_WAVE = 446086,
};
npc_sureki_unnaturaler(Creature* creature) : ScriptedAI(creature) { }
void ScheduleTasks() override
{
events.ScheduleEvent(EVENT_CAST_1, 6s);
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_CAST_1:
DoCastSelf(SPELL_VOID_WAVE);
events.Repeat(10s);
break;
default:
break;
}
}
};
void AddSC_city_of_threads_trash()
{
RegisterCityOfThreadsCreatureAI(npc_unstable_test_subject);
RegisterCityOfThreadsCreatureAI(npc_covert_webmancer);
RegisterCityOfThreadsCreatureAI(npc_elder_shadeweaver);
RegisterCityOfThreadsCreatureAI(npc_hulking_warshell);
RegisterCityOfThreadsCreatureAI(npc_herald_of_ansurek);
RegisterCityOfThreadsCreatureAI(npc_agile_pursuer);
RegisterCityOfThreadsCreatureAI(npc_sureki_unnaturaler);
}
@@ -38,6 +38,14 @@ void AddSC_boss_benk_buzzbee();
void AddSC_boss_goldie_baronbottom();
void AddSC_cinderbrew_meadery_trash();
//City of Threads
void AddSC_instance_city_of_threads();
void AddSC_boss_orator_krix_vizk();
void AddSC_boss_Fangs_of_the_Queen();
void AddSC_boss_The_Coaglamation();
void AddSC_boss_izo_the_grand_splicer();
void AddSC_city_of_threads_trash();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddWarWithinScripts()
@@ -70,4 +78,12 @@ void AddWarWithinScripts()
AddSC_boss_benk_buzzbee();
AddSC_boss_goldie_baronbottom();
AddSC_cinderbrew_meadery_trash();
//City of Threads
AddSC_instance_city_of_threads();
AddSC_boss_orator_krix_vizk();
AddSC_boss_Fangs_of_the_Queen();
AddSC_boss_The_Coaglamation();
AddSC_boss_izo_the_grand_splicer();
AddSC_city_of_threads_trash();
}