Full City of Threads
This commit is contained in:
@@ -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_boss_goldie_baronbottom();
|
||||||
void AddSC_cinderbrew_meadery_trash();
|
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:
|
// The name of this function should match:
|
||||||
// void Add${NameOfDirectory}Scripts()
|
// void Add${NameOfDirectory}Scripts()
|
||||||
void AddWarWithinScripts()
|
void AddWarWithinScripts()
|
||||||
@@ -70,4 +78,12 @@ void AddWarWithinScripts()
|
|||||||
AddSC_boss_benk_buzzbee();
|
AddSC_boss_benk_buzzbee();
|
||||||
AddSC_boss_goldie_baronbottom();
|
AddSC_boss_goldie_baronbottom();
|
||||||
AddSC_cinderbrew_meadery_trash();
|
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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user