fix(Core/TempleOfAhnQiraj): Twin emperors rewrite (#12855)
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
--
|
||||||
|
UPDATE `creature_template_addon` SET `bytes1` = 54432 WHERE `entry` = 15963;
|
||||||
|
UPDATE `creature_template_addon` SET `auras` = '18943' WHERE `entry` = 15275;
|
||||||
|
|
||||||
|
DELETE FROM `areatrigger_scripts` WHERE `ScriptName` = 'at_twin_emperors';
|
||||||
|
INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES
|
||||||
|
(4047, 'at_twin_emperors');
|
||||||
|
|
||||||
|
DELETE FROM `creature_text` WHERE `CreatureID` IN (15275, 15276) AND `GroupID` IN (0, 1, 2, 3, 4, 5, 6);
|
||||||
|
DELETE FROM `creature_text` WHERE `CreatureID` = 15963;
|
||||||
|
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||||
|
(15275, 0, 0, 'Where are your manners, brother. Let us properly welcome our guests.', 14, 0, 100, 6, 0, 0, 11706, 0, 'Emperor Vek\'nilash INTRO_0'),
|
||||||
|
(15275, 1, 0, 'Oh so much pain...', 14, 0, 100, 5, 0, 0, 11708, 0, 'Emperor Vek\'nilash INTRO_1'),
|
||||||
|
(15275, 2, 0, 'The feast of souls begins now...', 14, 0, 100, 0, 0, 0, 11710, 0, 'Emperor Vek\'nilash INTRO_2'),
|
||||||
|
(15275, 3, 0, 'Your fate is sealed!', 14, 0, 100, 0, 0, 8635, 11455, 0, 'Emperor Vek\'nilash KILL'),
|
||||||
|
(15275, 4, 0, 'Vek\'lor, I feel your pain!', 14, 0, 100, 0, 0, 8636, 11454, 0, 'Emperor Vek\'nilash DEATH'),
|
||||||
|
(15276, 0, 0, 'Only flesh and bone. Mortals are such easy prey...', 14, 0, 100, 1, 0, 0, 11702, 0, 'Emperor Vek\'lor INTRO_0'),
|
||||||
|
(15276, 1, 0, 'There will be pain...', 14, 0, 100, 273, 0, 0, 11707, 0, 'Emperor Vek\'lor INTRO_1'),
|
||||||
|
(15276, 2, 0, 'Come, little ones.', 14, 0, 100, 0, 0, 0, 11709, 0, 'Emperor Vek\'lor INTRO_2'),
|
||||||
|
(15276, 3, 0, 'You will not escape death!', 14, 0, 100, 0, 0, 8629, 11453, 0, 'Emperor Vek\'lor KILL'),
|
||||||
|
(15276, 4, 0, 'My brother, no!', 14, 0, 100, 0, 0, 8625, 11452, 0, 'Emperor Vek\'lor DEATH'),
|
||||||
|
(15276, 5, 0, '%s goes into a berserker rage!', 16, 0, 100, 0, 0, 0, 34057, 0, 'Emperor Vek\'lor ENRAGE'),
|
||||||
|
(15963, 0, 0, 'The massive floating eyeball in the center of the chamber turns its gaze upon you. You stand before a god.', 16, 0, 100, 0, 0, 0, 11700, 1, 'Masters Eye - On Areatrigger');
|
||||||
|
|
||||||
|
UPDATE `creature_template_movement` SET `Ground` = 2, `Flight` = 1 WHERE `CreatureId` = 15963;
|
||||||
|
|
||||||
|
UPDATE `creature_template` SET `unit_flags` = `unit_flags`|512|256 WHERE `entry` = 15963;
|
||||||
|
UPDATE `creature_template` SET `spell_school_immune_mask` = `spell_school_immune_mask`|1 WHERE `entry` = 15276; -- Vek'lor immunity to phys
|
||||||
|
UPDATE `creature_template` SET `spell_school_immune_mask` = `spell_school_immune_mask`|4|8|16|32|64 WHERE `entry` = 15275; -- Vek'nilash immunity to everything but holy and phys
|
||||||
|
|
||||||
|
DELETE FROM `spell_script_names` WHERE `spell_id` IN (802, 804);
|
||||||
|
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||||
|
(802, 'spell_mutate_explode_bug'),
|
||||||
|
(804, 'spell_mutate_explode_bug');
|
||||||
|
|
||||||
|
UPDATE `creature` SET `spawntimesecs` = 300 WHERE `id1` IN (15316, 15317);
|
||||||
|
|
||||||
|
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (15316, 15317);
|
||||||
|
|
||||||
|
DELETE FROM `smart_scripts` WHERE (`entryorguid` IN (15316, 15317)) AND (`source_type` = 0) AND (`id` IN (0));
|
||||||
|
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||||
|
(15317, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 2, 311, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Qiraji Scorpion - On Reset - Set Faction 311'),
|
||||||
|
(15316, 0, 0, 0, 25, 0, 100, 0, 0, 0, 0, 0, 0, 2, 311, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Qiraji Scarab - On Reset - Set Faction 311');
|
||||||
@@ -19518,6 +19518,11 @@ bool Unit::CanSwim() const
|
|||||||
return HasUnitFlag(UNIT_FLAG_RENAME | UNIT_FLAG_SWIMMING);
|
return HasUnitFlag(UNIT_FLAG_RENAME | UNIT_FLAG_SWIMMING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Unit::NearTeleportTo(Position& pos, bool casting /*= false*/, bool vehicleTeleport /*= false*/, bool withPet /*= false*/, bool removeTransport /*= false*/)
|
||||||
|
{
|
||||||
|
NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), casting, vehicleTeleport, withPet, removeTransport);
|
||||||
|
}
|
||||||
|
|
||||||
void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool casting /*= false*/, bool vehicleTeleport /*= false*/, bool withPet /*= false*/, bool removeTransport /*= false*/)
|
void Unit::NearTeleportTo(float x, float y, float z, float orientation, bool casting /*= false*/, bool vehicleTeleport /*= false*/, bool withPet /*= false*/, bool removeTransport /*= false*/)
|
||||||
{
|
{
|
||||||
DisableSpline();
|
DisableSpline();
|
||||||
|
|||||||
@@ -1731,6 +1731,7 @@ public:
|
|||||||
void SendSpellDamageResist(Unit* target, uint32 spellId);
|
void SendSpellDamageResist(Unit* target, uint32 spellId);
|
||||||
void SendSpellDamageImmune(Unit* target, uint32 spellId);
|
void SendSpellDamageImmune(Unit* target, uint32 spellId);
|
||||||
|
|
||||||
|
void NearTeleportTo(Position& pos, bool casting = false, bool vehicleTeleport = false, bool withPet = false, bool removeTransport = false);
|
||||||
void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false, bool vehicleTeleport = false, bool withPet = false, bool removeTransport = false);
|
void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false, bool vehicleTeleport = false, bool withPet = false, bool removeTransport = false);
|
||||||
void SendTameFailure(uint8 result);
|
void SendTameFailure(uint8 result);
|
||||||
void SendTeleportPacket(Position& pos);
|
void SendTeleportPacket(Position& pos);
|
||||||
|
|||||||
@@ -15,368 +15,283 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ScriptData
|
#include "Player.h"
|
||||||
SDName: Boss_Twinemperors
|
|
||||||
SD%Complete: 95
|
|
||||||
SDComment:
|
|
||||||
SDCategory: Temple of Ahn'Qiraj
|
|
||||||
EndScriptData */
|
|
||||||
|
|
||||||
#include "Item.h"
|
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "ScriptedCreature.h"
|
#include "ScriptedCreature.h"
|
||||||
#include "Spell.h"
|
#include "SpellScript.h"
|
||||||
#include "WorldPacket.h"
|
#include "TaskScheduler.h"
|
||||||
#include "temple_of_ahnqiraj.h"
|
#include "temple_of_ahnqiraj.h"
|
||||||
|
|
||||||
enum Spells
|
enum Spells
|
||||||
{
|
{
|
||||||
|
// Both
|
||||||
|
SPELL_TWIN_EMPATHY = 1177,
|
||||||
|
SPELL_TWIN_TELEPORT_1 = 800,
|
||||||
|
SPELL_TWIN_TELEPORT_VISUAL = 26638,
|
||||||
SPELL_HEAL_BROTHER = 7393,
|
SPELL_HEAL_BROTHER = 7393,
|
||||||
SPELL_TWIN_TELEPORT = 800, // CTRA watches for this spell to start its teleport timer
|
// Vek'lor
|
||||||
SPELL_TWIN_TELEPORT_VISUAL = 26638, // visual
|
SPELL_SHADOW_BOLT = 26006,
|
||||||
SPELL_EXPLODEBUG = 804,
|
SPELL_BLIZZARD = 26607,
|
||||||
SPELL_MUTATE_BUG = 802,
|
SPELL_FRENZY = 27897,
|
||||||
SPELL_BERSERK = 26662,
|
SPELL_ARCANE_BURST = 568,
|
||||||
|
SPELL_EXPLODE_BUG = 804,
|
||||||
|
SPELL_TWIN_TELEPORT_0 = 799,
|
||||||
|
// Vek'nilash
|
||||||
SPELL_UPPERCUT = 26007,
|
SPELL_UPPERCUT = 26007,
|
||||||
SPELL_UNBALANCING_STRIKE = 26613,
|
SPELL_UNBALANCING_STRIKE = 26613,
|
||||||
SPELL_SHADOWBOLT = 26006,
|
SPELL_BERSERK = 27680,
|
||||||
SPELL_BLIZZARD = 26607,
|
SPELL_MUTATE_BUG = 802,
|
||||||
SPELL_ARCANEBURST = 568,
|
// Bugs
|
||||||
|
SPELL_VIRULENT_POISON_PROC = 22413
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Sound
|
enum Actions
|
||||||
{
|
{
|
||||||
SOUND_VL_AGGRO = 8657, //8657 - Aggro - To Late
|
ACTION_START_INTRO = 0,
|
||||||
SOUND_VL_KILL = 8658, //8658 - Kill - You will not
|
ACTION_CANCEL_INTRO = 1,
|
||||||
SOUND_VL_DEATH = 8659, //8659 - Death
|
ACTION_AFTER_TELEPORT = 2
|
||||||
SOUND_VN_DEATH = 8660, //8660 - Death - Feel
|
};
|
||||||
SOUND_VN_AGGRO = 8661, //8661 - Aggro - Let none
|
|
||||||
SOUND_VN_KILL = 8662, //8661 - Kill - your fate
|
enum Say
|
||||||
|
{
|
||||||
|
SAY_INTRO_0 = 0,
|
||||||
|
SAY_INTRO_1 = 1,
|
||||||
|
SAY_INTRO_2 = 2,
|
||||||
|
SAY_KILL = 3,
|
||||||
|
SAY_DEATH = 4,
|
||||||
|
EMOTE_ENRAGE = 5,
|
||||||
|
|
||||||
|
EMOTE_MASTERS_EYE_AT = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Sounds
|
||||||
|
{
|
||||||
|
SOUND_VK_AGGRO = 8657,
|
||||||
|
SOUND_VN_AGGRO = 8661
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Misc
|
enum Misc
|
||||||
{
|
{
|
||||||
PULL_RANGE = 50,
|
GROUP_INTRO = 0,
|
||||||
ABUSE_BUG_RANGE = 20,
|
|
||||||
VEKLOR_DIST = 20, // VL will not come to melee when attacking
|
NPC_QIRAJI_SCARAB = 15316,
|
||||||
TELEPORTTIME = 30000
|
NPC_QIRAJI_SCORPION = 15317,
|
||||||
|
|
||||||
|
FACTION_HOSTILE = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr float veklorOrientationIntro = 2.241519f;
|
||||||
|
constexpr float veknilashOrientationIntro = 1.144451f;
|
||||||
|
|
||||||
struct boss_twinemperorsAI : public BossAI
|
struct boss_twinemperorsAI : public BossAI
|
||||||
{
|
{
|
||||||
boss_twinemperorsAI(Creature* creature): BossAI(creature, DATA_TWIN_EMPERORS) { }
|
boss_twinemperorsAI(Creature* creature): BossAI(creature, DATA_TWIN_EMPERORS), _introDone(false)
|
||||||
|
|
||||||
uint32 Heal_Timer;
|
|
||||||
uint32 Teleport_Timer;
|
|
||||||
bool AfterTeleport;
|
|
||||||
uint32 AfterTeleportTimer;
|
|
||||||
bool DontYellWhenDead;
|
|
||||||
uint32 Abuse_Bug_Timer, BugsTimer;
|
|
||||||
bool tspellcast;
|
|
||||||
uint32 EnrageTimer;
|
|
||||||
|
|
||||||
virtual bool IAmVeklor() = 0;
|
|
||||||
void Reset() override = 0;
|
|
||||||
virtual void CastSpellOnBug(Creature* target) = 0;
|
|
||||||
|
|
||||||
void TwinReset()
|
|
||||||
{
|
{
|
||||||
Heal_Timer = 0; // first heal immediately when they get close together
|
me->SetStandState(UNIT_STAND_STATE_KNEEL);
|
||||||
Teleport_Timer = TELEPORTTIME;
|
|
||||||
AfterTeleport = false;
|
|
||||||
tspellcast = false;
|
|
||||||
AfterTeleportTimer = 0;
|
|
||||||
Abuse_Bug_Timer = urand(10000, 17000);
|
|
||||||
BugsTimer = 2000;
|
|
||||||
me->ClearUnitState(UNIT_STATE_STUNNED);
|
|
||||||
DontYellWhenDead = false;
|
|
||||||
EnrageTimer = 15 * 60000;
|
|
||||||
|
|
||||||
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_1), true);
|
_scheduler.SetValidator([this]
|
||||||
}
|
|
||||||
|
|
||||||
Creature* GetOtherBoss()
|
|
||||||
{
|
|
||||||
return ObjectAccessor::GetCreature(*me, instance->GetGuidData(IAmVeklor() ? DATA_VEKNILASH : DATA_VEKLOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
|
||||||
{
|
|
||||||
Unit* pOtherBoss = GetOtherBoss();
|
|
||||||
if (pOtherBoss)
|
|
||||||
{
|
|
||||||
float dPercent = ((float)damage) / ((float)me->GetMaxHealth());
|
|
||||||
int odmg = (int)(dPercent * ((float)pOtherBoss->GetMaxHealth()));
|
|
||||||
int ohealth = pOtherBoss->GetHealth() - odmg;
|
|
||||||
pOtherBoss->SetHealth(ohealth > 0 ? ohealth : 0);
|
|
||||||
if (ohealth <= 0)
|
|
||||||
{
|
{
|
||||||
pOtherBoss->setDeathState(JUST_DIED);
|
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||||
pOtherBoss->SetDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Creature* GetTwin()
|
||||||
|
{
|
||||||
|
return instance->GetCreature(IAmVeklor() ? DATA_VEKNILASH : DATA_VEKLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||||
|
{
|
||||||
|
if (attacker)
|
||||||
|
{
|
||||||
|
if (attacker->GetEntry() == NPC_VEKLOR || attacker->GetEntry() == NPC_VEKNILASH)
|
||||||
|
{
|
||||||
|
me->LowerPlayerDamageReq(damage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Creature* twin = GetTwin())
|
||||||
|
{
|
||||||
|
float dmgPct = damage / (float)me->GetMaxHealth();
|
||||||
|
int32 actualDmg = dmgPct * twin->GetMaxHealth();
|
||||||
|
twin->CastCustomSpell(twin, SPELL_TWIN_EMPATHY, &actualDmg, nullptr, nullptr, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void JustDied(Unit* /*killer*/) override
|
void KilledUnit(Unit* victim) override
|
||||||
{
|
{
|
||||||
Creature* pOtherBoss = GetOtherBoss();
|
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
|
||||||
if (pOtherBoss)
|
Talk(SAY_KILL);
|
||||||
{
|
|
||||||
pOtherBoss->SetHealth(0);
|
|
||||||
pOtherBoss->setDeathState(JUST_DIED);
|
|
||||||
pOtherBoss->SetDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
|
||||||
CAST_AI(boss_twinemperorsAI, pOtherBoss->AI())->DontYellWhenDead = true;
|
|
||||||
}
|
|
||||||
if (!DontYellWhenDead) // I hope AI is not threaded
|
|
||||||
DoPlaySoundToSet(me, IAmVeklor() ? SOUND_VL_DEATH : SOUND_VN_DEATH);
|
|
||||||
|
|
||||||
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_1), true);
|
|
||||||
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_2), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KilledUnit(Unit* /*victim*/) override
|
void EnterEvadeMode(EvadeReason why) override
|
||||||
{
|
{
|
||||||
DoPlaySoundToSet(me, IAmVeklor() ? SOUND_VL_KILL : SOUND_VN_KILL);
|
BossAI::EnterEvadeMode(why);
|
||||||
|
|
||||||
|
if (Creature* twin = GetTwin())
|
||||||
|
if (!twin->IsInEvadeMode())
|
||||||
|
twin->AI()->EnterEvadeMode(why);
|
||||||
|
|
||||||
|
_scheduler.CancelAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
if (Creature* twin = GetTwin())
|
||||||
|
if (twin->IsAlive())
|
||||||
|
Unit::Kill(me, twin);
|
||||||
|
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoAction(int32 action) override
|
||||||
|
{
|
||||||
|
if (action == ACTION_CANCEL_INTRO)
|
||||||
|
{
|
||||||
|
_introDone = true;
|
||||||
|
_scheduler.CancelGroup(GROUP_INTRO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == ACTION_AFTER_TELEPORT)
|
||||||
|
{
|
||||||
|
DoResetThreat();
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
DoCastSelf(SPELL_TWIN_TELEPORT_VISUAL, true);
|
||||||
|
_scheduler.DelayAll(2300ms);
|
||||||
|
_scheduler.Schedule(2s, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->SetControlled(false, UNIT_STATE_ROOT);
|
||||||
|
if (Unit* victim = me->SelectNearestTarget())
|
||||||
|
{
|
||||||
|
me->AddThreat(victim, 200000.f);
|
||||||
|
AttackStart(victim);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action != ACTION_START_INTRO)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_scheduler.Schedule(5s, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||||
|
me->LoadEquipment(1, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (IAmVeklor())
|
||||||
|
{
|
||||||
|
_scheduler
|
||||||
|
.Schedule(12s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
Talk(SAY_INTRO_0);
|
||||||
|
})
|
||||||
|
.Schedule(20s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
Talk(SAY_INTRO_1);
|
||||||
|
})
|
||||||
|
.Schedule(28s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
|
||||||
|
})
|
||||||
|
.Schedule(30s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->SetFacingTo(veklorOrientationIntro);
|
||||||
|
Talk(SAY_INTRO_2);
|
||||||
|
})
|
||||||
|
.Schedule(33s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
||||||
|
_introDone = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_scheduler
|
||||||
|
.Schedule(17s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
Talk(SAY_INTRO_0);
|
||||||
|
})
|
||||||
|
.Schedule(23s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
Talk(SAY_INTRO_1);
|
||||||
|
})
|
||||||
|
.Schedule(28s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR);
|
||||||
|
})
|
||||||
|
.Schedule(32s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->SetFacingTo(veknilashOrientationIntro);
|
||||||
|
Talk(SAY_INTRO_2);
|
||||||
|
})
|
||||||
|
.Schedule(33s, GROUP_INTRO, [this](TaskContext /*context*/)
|
||||||
|
{
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
|
||||||
|
_introDone = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnterCombat(Unit* who) override
|
void EnterCombat(Unit* who) override
|
||||||
{
|
{
|
||||||
DoZoneInCombat();
|
BossAI::EnterCombat(who);
|
||||||
Creature* pOtherBoss = GetOtherBoss();
|
|
||||||
if (pOtherBoss)
|
if (!_introDone)
|
||||||
{
|
{
|
||||||
/// @todo we should activate the other boss location so he can start attackning even if nobody
|
DoAction(ACTION_CANCEL_INTRO);
|
||||||
// is near I dont know how to do that
|
if (Creature* twin = GetTwin())
|
||||||
ScriptedAI* otherAI = CAST_AI(ScriptedAI, pOtherBoss->AI());
|
twin->AI()->DoAction(ACTION_CANCEL_INTRO);
|
||||||
if (!pOtherBoss->IsInCombat())
|
}
|
||||||
|
|
||||||
|
if (Creature* twin = GetTwin())
|
||||||
|
if (!twin->IsInCombat())
|
||||||
|
twin->AI()->AttackStart(who);
|
||||||
|
|
||||||
|
_scheduler
|
||||||
|
.Schedule(15min, [this](TaskContext /*context*/)
|
||||||
{
|
{
|
||||||
DoPlaySoundToSet(me, IAmVeklor() ? SOUND_VL_AGGRO : SOUND_VN_AGGRO);
|
if (IAmVeklor())
|
||||||
otherAI->AttackStart(who);
|
|
||||||
otherAI->DoZoneInCombat();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_1), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpellHit(Unit* caster, SpellInfo const* entry) override
|
|
||||||
{
|
|
||||||
if (caster == me)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Creature* pOtherBoss = GetOtherBoss();
|
|
||||||
if (entry->Id != SPELL_HEAL_BROTHER || !pOtherBoss)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// add health so we keep same percentage for both brothers
|
|
||||||
uint32 mytotal = me->GetMaxHealth(), histotal = pOtherBoss->GetMaxHealth();
|
|
||||||
float mult = ((float)mytotal) / ((float)histotal);
|
|
||||||
if (mult < 1)
|
|
||||||
mult = 1.0f / mult;
|
|
||||||
#define HEAL_BROTHER_AMOUNT 30000.0f
|
|
||||||
uint32 largerAmount = (uint32)((HEAL_BROTHER_AMOUNT * mult) - HEAL_BROTHER_AMOUNT);
|
|
||||||
|
|
||||||
if (mytotal > histotal)
|
|
||||||
{
|
|
||||||
uint32 h = me->GetHealth() + largerAmount;
|
|
||||||
me->SetHealth(std::min(mytotal, h));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uint32 h = pOtherBoss->GetHealth() + largerAmount;
|
|
||||||
pOtherBoss->SetHealth(std::min(histotal, h));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TryHealBrother(uint32 diff)
|
|
||||||
{
|
|
||||||
if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (Heal_Timer <= diff)
|
|
||||||
{
|
|
||||||
Unit* pOtherBoss = GetOtherBoss();
|
|
||||||
if (pOtherBoss && pOtherBoss->IsWithinDist(me, 60))
|
|
||||||
{
|
|
||||||
DoCast(pOtherBoss, SPELL_HEAL_BROTHER);
|
|
||||||
Heal_Timer = 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else Heal_Timer -= diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TeleportToMyBrother()
|
|
||||||
{
|
|
||||||
Teleport_Timer = TELEPORTTIME;
|
|
||||||
|
|
||||||
if (IAmVeklor())
|
|
||||||
return; // mechanics handled by veknilash so they teleport exactly at the same time and to correct coordinates
|
|
||||||
|
|
||||||
Creature* pOtherBoss = GetOtherBoss();
|
|
||||||
if (pOtherBoss)
|
|
||||||
{
|
|
||||||
//me->Yell("Teleporting ...", LANG_UNIVERSAL);
|
|
||||||
Position thisPos;
|
|
||||||
thisPos.Relocate(me);
|
|
||||||
Position otherPos;
|
|
||||||
otherPos.Relocate(pOtherBoss);
|
|
||||||
pOtherBoss->SetPosition(thisPos);
|
|
||||||
me->SetPosition(otherPos);
|
|
||||||
|
|
||||||
SetAfterTeleport();
|
|
||||||
CAST_AI(boss_twinemperorsAI, pOtherBoss->AI())->SetAfterTeleport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetAfterTeleport()
|
|
||||||
{
|
|
||||||
me->InterruptNonMeleeSpells(false);
|
|
||||||
DoStopAttack();
|
|
||||||
DoResetThreat();
|
|
||||||
DoCast(me, SPELL_TWIN_TELEPORT_VISUAL);
|
|
||||||
me->AddUnitState(UNIT_STATE_STUNNED);
|
|
||||||
AfterTeleport = true;
|
|
||||||
AfterTeleportTimer = 2000;
|
|
||||||
tspellcast = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TryActivateAfterTTelep(uint32 diff)
|
|
||||||
{
|
|
||||||
if (AfterTeleport)
|
|
||||||
{
|
|
||||||
if (!tspellcast)
|
|
||||||
{
|
|
||||||
me->ClearUnitState(UNIT_STATE_STUNNED);
|
|
||||||
DoCast(me, SPELL_TWIN_TELEPORT);
|
|
||||||
me->AddUnitState(UNIT_STATE_STUNNED);
|
|
||||||
}
|
|
||||||
|
|
||||||
tspellcast = true;
|
|
||||||
|
|
||||||
if (AfterTeleportTimer <= diff)
|
|
||||||
{
|
|
||||||
AfterTeleport = false;
|
|
||||||
me->ClearUnitState(UNIT_STATE_STUNNED);
|
|
||||||
if (Unit* nearu = me->SelectNearestTarget(100))
|
|
||||||
{
|
{
|
||||||
//DoYell(nearu->GetName(), LANG_UNIVERSAL);
|
DoCastSelf(SPELL_FRENZY, true);
|
||||||
AttackStart(nearu);
|
Talk(EMOTE_ENRAGE);
|
||||||
me->AddThreat(nearu, 10000);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AfterTeleportTimer -= diff;
|
|
||||||
// update important timers which would otherwise get skipped
|
|
||||||
if (EnrageTimer > diff)
|
|
||||||
EnrageTimer -= diff;
|
|
||||||
else
|
|
||||||
EnrageTimer = 0;
|
|
||||||
if (Teleport_Timer > diff)
|
|
||||||
Teleport_Timer -= diff;
|
|
||||||
else
|
|
||||||
Teleport_Timer = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveInLineOfSight(Unit* who) override
|
|
||||||
{
|
|
||||||
if (!who || me->GetVictim())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (me->CanCreatureAttack(who))
|
|
||||||
{
|
|
||||||
if (me->IsWithinDistInMap(who, PULL_RANGE, true, false) && me->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/)
|
|
||||||
{
|
|
||||||
//if (who->HasStealthAura())
|
|
||||||
// who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
|
|
||||||
AttackStart(who);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Creature* RespawnNearbyBugsAndGetOne()
|
|
||||||
{
|
|
||||||
std::list<Creature*> lUnitList;
|
|
||||||
me->GetCreatureListWithEntryInGrid(lUnitList, 15316, 150.0f);
|
|
||||||
me->GetCreatureListWithEntryInGrid(lUnitList, 15317, 150.0f);
|
|
||||||
|
|
||||||
if (lUnitList.empty())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
Creature* nearb = nullptr;
|
|
||||||
|
|
||||||
for (std::list<Creature*>::const_iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter)
|
|
||||||
{
|
|
||||||
Creature* c = *iter;
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
if (c->isDead())
|
|
||||||
{
|
|
||||||
c->Respawn();
|
|
||||||
c->SetFaction(FACTION_CREATURE);
|
|
||||||
c->RemoveAllAuras();
|
|
||||||
}
|
|
||||||
if (c->IsWithinDistInMap(me, ABUSE_BUG_RANGE))
|
|
||||||
{
|
|
||||||
if (!nearb || (rand() % 4) == 0)
|
|
||||||
nearb = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nearb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HandleBugs(uint32 diff)
|
|
||||||
{
|
|
||||||
if (BugsTimer < diff || Abuse_Bug_Timer <= diff)
|
|
||||||
{
|
|
||||||
Creature* c = RespawnNearbyBugsAndGetOne();
|
|
||||||
if (Abuse_Bug_Timer <= diff)
|
|
||||||
{
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
CastSpellOnBug(c);
|
|
||||||
Abuse_Bug_Timer = urand(10000, 17000);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
DoCastSelf(SPELL_BERSERK, true);
|
||||||
Abuse_Bug_Timer = 1000;
|
})
|
||||||
}
|
.Schedule(3600ms, [this](TaskContext context) // according to sniffs it should be casted by both emperors.
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Abuse_Bug_Timer -= diff;
|
if (Creature* twin = GetTwin())
|
||||||
}
|
{
|
||||||
BugsTimer = 2000;
|
if (me->IsWithinDist(twin, 60.f))
|
||||||
}
|
DoCast(twin, SPELL_HEAL_BROTHER, true);
|
||||||
else
|
}
|
||||||
{
|
|
||||||
BugsTimer -= diff;
|
context.Repeat();
|
||||||
Abuse_Bug_Timer -= diff;
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckEnrage(uint32 diff)
|
void UpdateAI(uint32 diff) override
|
||||||
{
|
{
|
||||||
if (EnrageTimer <= diff)
|
if (!UpdateVictim() && _introDone)
|
||||||
{
|
return;
|
||||||
if (!me->IsNonMeleeSpellCast(true))
|
|
||||||
|
_scheduler.Update(diff, [this]
|
||||||
{
|
{
|
||||||
DoCast(me, SPELL_BERSERK);
|
if (!IAmVeklor())
|
||||||
EnrageTimer = 60 * 60000;
|
DoMeleeAttackIfReady();
|
||||||
}
|
});
|
||||||
else EnrageTimer = 0;
|
|
||||||
}
|
|
||||||
else EnrageTimer -= diff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool IAmVeklor() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TaskScheduler _scheduler;
|
||||||
|
bool _introDone;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct boss_veknilash : public boss_twinemperorsAI
|
struct boss_veknilash : public boss_twinemperorsAI
|
||||||
@@ -385,192 +300,172 @@ struct boss_veknilash : public boss_twinemperorsAI
|
|||||||
|
|
||||||
bool IAmVeklor() override { return false; }
|
bool IAmVeklor() override { return false; }
|
||||||
|
|
||||||
uint32 UpperCut_Timer;
|
void EnterCombat(Unit* who) override
|
||||||
uint32 UnbalancingStrike_Timer;
|
|
||||||
uint32 Scarabs_Timer;
|
|
||||||
int Rand;
|
|
||||||
int RandX;
|
|
||||||
int RandY;
|
|
||||||
|
|
||||||
Creature* Summoned;
|
|
||||||
|
|
||||||
void Reset() override
|
|
||||||
{
|
{
|
||||||
TwinReset();
|
boss_twinemperorsAI::EnterCombat(who);
|
||||||
UpperCut_Timer = urand(14000, 29000);
|
|
||||||
UnbalancingStrike_Timer = urand(8000, 18000);
|
|
||||||
Scarabs_Timer = urand(7000, 14000);
|
|
||||||
|
|
||||||
//Added. Can be removed if its included in DB.
|
DoPlaySoundToSet(me, SOUND_VN_AGGRO);
|
||||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CastSpellOnBug(Creature* target) override
|
_scheduler
|
||||||
{
|
.Schedule(14s, [this](TaskContext context)
|
||||||
target->SetFaction(FACTION_MONSTER);
|
{
|
||||||
target->AI()->AttackStart(me->GetThreatMgr().getHostileTarget());
|
DoCastRandomTarget(SPELL_UPPERCUT, 0, me->GetMeleeReach(), true);
|
||||||
target->AddAura(SPELL_MUTATE_BUG, target);
|
context.Repeat(4s, 15s);
|
||||||
target->SetFullHealth();
|
})
|
||||||
}
|
.Schedule(12s, [this](TaskContext context)
|
||||||
|
{
|
||||||
void UpdateAI(uint32 diff) override
|
DoCastVictim(SPELL_UNBALANCING_STRIKE);
|
||||||
{
|
context.Repeat(8s, 20s);
|
||||||
//Return since we have no target
|
})
|
||||||
if (!UpdateVictim())
|
.Schedule(16s, [this](TaskContext context)
|
||||||
return;
|
{
|
||||||
|
DoCastAOE(SPELL_MUTATE_BUG);
|
||||||
if (!TryActivateAfterTTelep(diff))
|
context.Repeat(10s, 20s);
|
||||||
return;
|
});
|
||||||
|
|
||||||
//UnbalancingStrike_Timer
|
|
||||||
if (UnbalancingStrike_Timer <= diff)
|
|
||||||
{
|
|
||||||
DoCastVictim(SPELL_UNBALANCING_STRIKE);
|
|
||||||
UnbalancingStrike_Timer = 8000 + rand() % 12000;
|
|
||||||
}
|
|
||||||
else UnbalancingStrike_Timer -= diff;
|
|
||||||
|
|
||||||
if (UpperCut_Timer <= diff)
|
|
||||||
{
|
|
||||||
Unit* randomMelee = SelectTarget(SelectTargetMethod::Random, 0, NOMINAL_MELEE_RANGE, true);
|
|
||||||
if (randomMelee)
|
|
||||||
DoCast(randomMelee, SPELL_UPPERCUT);
|
|
||||||
UpperCut_Timer = 15000 + rand() % 15000;
|
|
||||||
}
|
|
||||||
else UpperCut_Timer -= diff;
|
|
||||||
|
|
||||||
HandleBugs(diff);
|
|
||||||
|
|
||||||
//Heal brother when 60yrds close
|
|
||||||
TryHealBrother(diff);
|
|
||||||
|
|
||||||
//Teleporting to brother
|
|
||||||
if (Teleport_Timer <= diff)
|
|
||||||
{
|
|
||||||
TeleportToMyBrother();
|
|
||||||
}
|
|
||||||
else Teleport_Timer -= diff;
|
|
||||||
|
|
||||||
CheckEnrage(diff);
|
|
||||||
|
|
||||||
DoMeleeAttackIfReady();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct boss_veklor : public boss_twinemperorsAI
|
struct boss_veklor : public boss_twinemperorsAI
|
||||||
{
|
{
|
||||||
boss_veklor(Creature* creature) : boss_twinemperorsAI(creature) { }
|
boss_veklor(Creature* creature) : boss_twinemperorsAI(creature)
|
||||||
|
{
|
||||||
|
me->SetFloatValue(UNIT_FIELD_COMBATREACH, 45.f);
|
||||||
|
}
|
||||||
|
|
||||||
bool IAmVeklor() override { return true; }
|
bool IAmVeklor() override { return true; }
|
||||||
|
|
||||||
uint32 ShadowBolt_Timer;
|
void EnterCombat(Unit* who) override
|
||||||
uint32 Blizzard_Timer;
|
|
||||||
uint32 ArcaneBurst_Timer;
|
|
||||||
uint32 Scorpions_Timer;
|
|
||||||
int Rand;
|
|
||||||
int RandX;
|
|
||||||
|
|
||||||
Creature* Summoned;
|
|
||||||
|
|
||||||
void Reset() override
|
|
||||||
{
|
{
|
||||||
TwinReset();
|
boss_twinemperorsAI::EnterCombat(who);
|
||||||
ShadowBolt_Timer = 0;
|
|
||||||
Blizzard_Timer = urand(15000, 20000);
|
|
||||||
ArcaneBurst_Timer = 1000;
|
|
||||||
Scorpions_Timer = urand(7000, 14000);
|
|
||||||
|
|
||||||
//Added. Can be removed if its included in DB.
|
DoPlaySoundToSet(me, SOUND_VK_AGGRO);
|
||||||
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
|
|
||||||
|
_scheduler
|
||||||
|
.Schedule(4s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||||
|
context.Repeat(2500ms);
|
||||||
|
})
|
||||||
|
.Schedule(10s, 15s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
DoCastRandomTarget(SPELL_BLIZZARD, 0, 45.f);
|
||||||
|
context.Repeat(5s, 12s);
|
||||||
|
})
|
||||||
|
.Schedule(1s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
if (me->SelectNearestPlayer(NOMINAL_MELEE_RANGE))
|
||||||
|
DoCastAOE(SPELL_ARCANE_BURST);
|
||||||
|
context.Repeat(7s, 12s);
|
||||||
|
})
|
||||||
|
.Schedule(30s, 40s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
DoCastSelf(SPELL_TWIN_TELEPORT_0);
|
||||||
|
context.Repeat();
|
||||||
|
})
|
||||||
|
.Schedule(5s, [this](TaskContext context)
|
||||||
|
{
|
||||||
|
DoCastAOE(SPELL_EXPLODE_BUG);
|
||||||
|
context.Repeat(4500ms, 10s);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastSpellOnBug(Creature* target) override
|
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
|
||||||
{
|
{
|
||||||
target->SetFaction(FACTION_MONSTER);
|
if (spellInfo->Id == SPELL_TWIN_TELEPORT_0)
|
||||||
target->AddAura(SPELL_EXPLODEBUG, target);
|
{
|
||||||
target->SetFullHealth();
|
if (Creature* veknilash = GetTwin())
|
||||||
|
{
|
||||||
|
DoCastSelf(SPELL_TWIN_TELEPORT_1, true);
|
||||||
|
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||||
|
|
||||||
|
Position veklorPos = me->GetPosition();
|
||||||
|
Position veknilashPos = veknilash->GetPosition();
|
||||||
|
me->NearTeleportTo(veknilashPos);
|
||||||
|
|
||||||
|
veknilash->CastSpell(veknilash, SPELL_TWIN_TELEPORT_1, true);
|
||||||
|
veknilash->SetControlled(true, UNIT_STATE_ROOT);
|
||||||
|
veknilash->NearTeleportTo(veklorPos);
|
||||||
|
|
||||||
|
veknilash->AI()->DoAction(ACTION_AFTER_TELEPORT);
|
||||||
|
DoAction(ACTION_AFTER_TELEPORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class at_twin_emperors : public OnlyOnceAreaTriggerScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
at_twin_emperors() : OnlyOnceAreaTriggerScript("at_twin_emperors") { }
|
||||||
|
|
||||||
|
bool _OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
||||||
|
{
|
||||||
|
if (InstanceScript* instance = player->GetInstanceScript())
|
||||||
|
{
|
||||||
|
if (instance->GetBossState(DATA_TWIN_EMPERORS) != DONE)
|
||||||
|
{
|
||||||
|
if (Creature* mastersEye = instance->GetCreature(DATA_MASTERS_EYE))
|
||||||
|
{
|
||||||
|
mastersEye->AI()->Talk(EMOTE_MASTERS_EYE_AT, player);
|
||||||
|
mastersEye->DespawnOrUnsummon(11000);
|
||||||
|
mastersEye->m_Events.AddEventAtOffset([mastersEye, player]()
|
||||||
|
{
|
||||||
|
mastersEye->SetFacingToObject(player);
|
||||||
|
}, 3s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Creature* veklor = instance->GetCreature(DATA_VEKLOR))
|
||||||
|
veklor->AI()->DoAction(ACTION_START_INTRO);
|
||||||
|
|
||||||
|
if (Creature* veknilash = instance->GetCreature(DATA_VEKNILASH))
|
||||||
|
veknilash->AI()->DoAction(ACTION_START_INTRO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_mutate_explode_bug : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_mutate_explode_bug);
|
||||||
|
|
||||||
|
void FilterTargets(std::list<WorldObject*>& targets)
|
||||||
|
{
|
||||||
|
targets.remove_if([&](WorldObject const* target) -> bool
|
||||||
|
{
|
||||||
|
if (target->GetEntry() != NPC_QIRAJI_SCARAB && target->GetEntry() != NPC_QIRAJI_SCORPION)
|
||||||
|
return true;
|
||||||
|
if (Creature const* creature = target->ToCreature())
|
||||||
|
if (creature->HasAura(SPELL_EXPLODE_BUG) || creature->HasAura(SPELL_MUTATE_BUG))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
Acore::Containers::RandomResize(targets, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAI(uint32 diff) override
|
void HandleOnHit()
|
||||||
{
|
{
|
||||||
//Return since we have no target
|
if (!GetHitUnit())
|
||||||
if (!UpdateVictim())
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// reset arcane burst after teleport - we need to do this because
|
Creature* target = GetHitUnit()->ToCreature();
|
||||||
// when VL jumps to VN's location there will be a warrior who will get only 2s to run away
|
|
||||||
// which is almost impossible
|
if (!target)
|
||||||
if (AfterTeleport)
|
|
||||||
ArcaneBurst_Timer = 5000;
|
|
||||||
if (!TryActivateAfterTTelep(diff))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//ShadowBolt_Timer
|
if (m_scriptSpellId == SPELL_MUTATE_BUG)
|
||||||
if (ShadowBolt_Timer <= diff)
|
target->CastSpell(target, SPELL_VIRULENT_POISON_PROC, true);
|
||||||
{
|
target->SetFaction(FACTION_HOSTILE);
|
||||||
if (!me->IsWithinDist(me->GetVictim(), 45.0f))
|
target->SetReactState(REACT_AGGRESSIVE);
|
||||||
me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0);
|
target->SetInCombatWithZone();
|
||||||
else
|
|
||||||
DoCastVictim(SPELL_SHADOWBOLT);
|
|
||||||
ShadowBolt_Timer = 2000;
|
|
||||||
}
|
|
||||||
else ShadowBolt_Timer -= diff;
|
|
||||||
|
|
||||||
//Blizzard_Timer
|
|
||||||
if (Blizzard_Timer <= diff)
|
|
||||||
{
|
|
||||||
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true);
|
|
||||||
if (target)
|
|
||||||
{
|
|
||||||
DoCast(target, SPELL_BLIZZARD);
|
|
||||||
}
|
|
||||||
Blizzard_Timer = 15000 + rand() % 15000;
|
|
||||||
}
|
|
||||||
else Blizzard_Timer -= diff;
|
|
||||||
|
|
||||||
if (ArcaneBurst_Timer <= diff)
|
|
||||||
{
|
|
||||||
Unit* mvic;
|
|
||||||
if ((mvic = SelectTarget(SelectTargetMethod::MaxDistance, 0, NOMINAL_MELEE_RANGE, true)) != nullptr)
|
|
||||||
{
|
|
||||||
DoCast(mvic, SPELL_ARCANEBURST);
|
|
||||||
ArcaneBurst_Timer = 5000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else ArcaneBurst_Timer -= diff;
|
|
||||||
|
|
||||||
HandleBugs(diff);
|
|
||||||
|
|
||||||
//Heal brother when 60yrds close
|
|
||||||
TryHealBrother(diff);
|
|
||||||
|
|
||||||
//Teleporting to brother
|
|
||||||
if (Teleport_Timer <= diff)
|
|
||||||
{
|
|
||||||
TeleportToMyBrother();
|
|
||||||
}
|
|
||||||
else Teleport_Timer -= diff;
|
|
||||||
|
|
||||||
CheckEnrage(diff);
|
|
||||||
|
|
||||||
//VL doesn't melee
|
|
||||||
//DoMeleeAttackIfReady();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttackStart(Unit* who) override
|
void Register() override
|
||||||
{
|
{
|
||||||
if (!who)
|
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mutate_explode_bug::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||||
return;
|
OnHit += SpellHitFn(spell_mutate_explode_bug::HandleOnHit);
|
||||||
|
|
||||||
if (who->isTargetableForAttack())
|
|
||||||
{
|
|
||||||
// VL doesn't melee
|
|
||||||
if (me->Attack(who, false))
|
|
||||||
{
|
|
||||||
me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0);
|
|
||||||
me->AddThreat(who, 0.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -578,4 +473,6 @@ void AddSC_boss_twinemperors()
|
|||||||
{
|
{
|
||||||
RegisterTempleOfAhnQirajCreatureAI(boss_veknilash);
|
RegisterTempleOfAhnQirajCreatureAI(boss_veknilash);
|
||||||
RegisterTempleOfAhnQirajCreatureAI(boss_veklor);
|
RegisterTempleOfAhnQirajCreatureAI(boss_veklor);
|
||||||
|
new at_twin_emperors();
|
||||||
|
RegisterSpellScript(spell_mutate_explode_bug);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ ObjectData const creatureData[] =
|
|||||||
{
|
{
|
||||||
{ NPC_SARTURA, DATA_SARTURA },
|
{ NPC_SARTURA, DATA_SARTURA },
|
||||||
{ NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN },
|
{ NPC_EYE_OF_CTHUN, DATA_EYE_OF_CTHUN },
|
||||||
{ NPC_OURO_SPAWNER, DATA_OURO_SPAWNER }
|
{ NPC_OURO_SPAWNER, DATA_OURO_SPAWNER },
|
||||||
|
{ NPC_MASTERS_EYE, DATA_MASTERS_EYE },
|
||||||
|
{ NPC_VEKLOR, DATA_VEKLOR },
|
||||||
|
{ NPC_VEKNILASH, DATA_VEKNILASH }
|
||||||
};
|
};
|
||||||
|
|
||||||
class instance_temple_of_ahnqiraj : public InstanceMapScript
|
class instance_temple_of_ahnqiraj : public InstanceMapScript
|
||||||
@@ -46,15 +49,10 @@ public:
|
|||||||
SetBossNumber(MAX_BOSS_NUMBER);
|
SetBossNumber(MAX_BOSS_NUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If Vem is dead...
|
|
||||||
bool IsBossDied[3];
|
|
||||||
|
|
||||||
ObjectGuid SkeramGUID;
|
ObjectGuid SkeramGUID;
|
||||||
ObjectGuid VemGUID;
|
ObjectGuid VemGUID;
|
||||||
ObjectGuid KriGUID;
|
ObjectGuid KriGUID;
|
||||||
ObjectGuid YaujGUID;
|
ObjectGuid YaujGUID;
|
||||||
ObjectGuid VeklorGUID;
|
|
||||||
ObjectGuid VeknilashGUID;
|
|
||||||
ObjectGuid ViscidusGUID;
|
ObjectGuid ViscidusGUID;
|
||||||
ObjectGuid CThunGUID;
|
ObjectGuid CThunGUID;
|
||||||
GuidVector CThunGraspGUIDs;
|
GuidVector CThunGraspGUIDs;
|
||||||
@@ -65,9 +63,6 @@ public:
|
|||||||
|
|
||||||
void Initialize() override
|
void Initialize() override
|
||||||
{
|
{
|
||||||
IsBossDied[0] = false;
|
|
||||||
IsBossDied[1] = false;
|
|
||||||
IsBossDied[2] = false;
|
|
||||||
BugTrioDeathCount = 0;
|
BugTrioDeathCount = 0;
|
||||||
CthunPhase = 0;
|
CthunPhase = 0;
|
||||||
}
|
}
|
||||||
@@ -92,16 +87,6 @@ public:
|
|||||||
case NPC_YAUJ:
|
case NPC_YAUJ:
|
||||||
YaujGUID = creature->GetGUID();
|
YaujGUID = creature->GetGUID();
|
||||||
break;
|
break;
|
||||||
case NPC_VEKLOR:
|
|
||||||
VeklorGUID = creature->GetGUID();
|
|
||||||
if (!creature->IsAlive())
|
|
||||||
{
|
|
||||||
HandleGameObject(doorGUIDs[1], true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NPC_VEKNILASH:
|
|
||||||
VeknilashGUID = creature->GetGUID();
|
|
||||||
break;
|
|
||||||
case NPC_VISCIDUS:
|
case NPC_VISCIDUS:
|
||||||
ViscidusGUID = creature->GetGUID();
|
ViscidusGUID = creature->GetGUID();
|
||||||
break;
|
break;
|
||||||
@@ -109,6 +94,10 @@ public:
|
|||||||
if (GetBossState(DATA_OURO) != DONE)
|
if (GetBossState(DATA_OURO) != DONE)
|
||||||
creature->Respawn();
|
creature->Respawn();
|
||||||
break;
|
break;
|
||||||
|
case NPC_MASTERS_EYE:
|
||||||
|
if (GetBossState(DATA_TWIN_EMPERORS) != DONE)
|
||||||
|
creature->Respawn(true);
|
||||||
|
break;
|
||||||
case NPC_CTHUN:
|
case NPC_CTHUN:
|
||||||
CThunGUID = creature->GetGUID();
|
CThunGUID = creature->GetGUID();
|
||||||
if (!creature->IsAlive())
|
if (!creature->IsAlive())
|
||||||
@@ -138,7 +127,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
case AQ40_DOOR_2:
|
case AQ40_DOOR_2:
|
||||||
doorGUIDs[1] = go->GetGUID();
|
doorGUIDs[1] = go->GetGUID();
|
||||||
if (Creature* veklor = instance->GetCreature(VeklorGUID))
|
if (Creature* veklor = GetCreature(DATA_VEKLOR))
|
||||||
{
|
{
|
||||||
if (!veklor->IsAlive())
|
if (!veklor->IsAlive())
|
||||||
{
|
{
|
||||||
@@ -177,16 +166,6 @@ public:
|
|||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case DATA_VEKLORISDEAD:
|
|
||||||
if (IsBossDied[1])
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATA_VEKNILASHISDEAD:
|
|
||||||
if (IsBossDied[2])
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATA_BUG_TRIO_DEATH:
|
case DATA_BUG_TRIO_DEATH:
|
||||||
return BugTrioDeathCount;
|
return BugTrioDeathCount;
|
||||||
|
|
||||||
@@ -208,10 +187,6 @@ public:
|
|||||||
return KriGUID;
|
return KriGUID;
|
||||||
case DATA_YAUJ:
|
case DATA_YAUJ:
|
||||||
return YaujGUID;
|
return YaujGUID;
|
||||||
case DATA_VEKLOR:
|
|
||||||
return VeklorGUID;
|
|
||||||
case DATA_VEKNILASH:
|
|
||||||
return VeknilashGUID;
|
|
||||||
case DATA_VISCIDUS:
|
case DATA_VISCIDUS:
|
||||||
return ViscidusGUID;
|
return ViscidusGUID;
|
||||||
case AQ40_DOOR_1:
|
case AQ40_DOOR_1:
|
||||||
@@ -234,12 +209,6 @@ public:
|
|||||||
else
|
else
|
||||||
BugTrioDeathCount = 0;
|
BugTrioDeathCount = 0;
|
||||||
break;
|
break;
|
||||||
case DATA_VEKLOR_DEATH:
|
|
||||||
IsBossDied[1] = true;
|
|
||||||
break;
|
|
||||||
case DATA_VEKNILASH_DEATH:
|
|
||||||
IsBossDied[2] = true;
|
|
||||||
break;
|
|
||||||
case DATA_CTHUN_PHASE:
|
case DATA_CTHUN_PHASE:
|
||||||
CthunPhase = data;
|
CthunPhase = data;
|
||||||
if (data == PHASE_CTHUN_DONE)
|
if (data == PHASE_CTHUN_DONE)
|
||||||
@@ -253,6 +222,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,17 +42,15 @@ enum DataTypes
|
|||||||
DATA_BUG_TRIO_DEATH = 13,
|
DATA_BUG_TRIO_DEATH = 13,
|
||||||
DATA_OURO_SPAWNER = 14,
|
DATA_OURO_SPAWNER = 14,
|
||||||
DATA_VEKLOR = 15,
|
DATA_VEKLOR = 15,
|
||||||
DATA_VEKLORISDEAD = 16,
|
DATA_VEKNILASH = 16,
|
||||||
DATA_VEKLOR_DEATH = 17,
|
DATA_CTHUN_PHASE = 17,
|
||||||
DATA_VEKNILASH = 18,
|
DATA_EYE_OF_CTHUN = 18,
|
||||||
DATA_VEKNILASHISDEAD = 19,
|
DATA_MASTERS_EYE = 19
|
||||||
DATA_VEKNILASH_DEATH = 20,
|
|
||||||
DATA_CTHUN_PHASE = 21,
|
|
||||||
DATA_EYE_OF_CTHUN = 22
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Creatures
|
enum Creatures
|
||||||
{
|
{
|
||||||
|
NPC_MASTERS_EYE = 15963,
|
||||||
NPC_CTHUN = 15727,
|
NPC_CTHUN = 15727,
|
||||||
NPC_EYE_OF_CTHUN = 15589,
|
NPC_EYE_OF_CTHUN = 15589,
|
||||||
NPC_CTHUN_PORTAL = 15896,
|
NPC_CTHUN_PORTAL = 15896,
|
||||||
|
|||||||
Reference in New Issue
Block a user