mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-24 10:56:38 +01:00
47
sql/updates/world/3.3.5/2025_11_09_00_world.sql
Normal file
47
sql/updates/world/3.3.5/2025_11_09_00_world.sql
Normal file
@@ -0,0 +1,47 @@
|
||||
-- Ingvar
|
||||
UPDATE `creature_template` SET `unit_flags` = 33555200, `AIName` = 'SmartAI' WHERE `entry` = 24012;
|
||||
DELETE FROM `smart_scripts` WHERE `entryorguid` = 24012 AND `source_type` = 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
|
||||
(24012,0,0,0,11,0,100,0,0,0,0,0,0,11,42862,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Ingvar Res Ground Visual - On Spawn - Cast 'Scourge Resurrection'"),
|
||||
(24012,0,1,0,11,0,100,0,0,0,0,0,0,41,10000,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Ingvar Res Ground Visual - On Spawn - Delayed Despawn");
|
||||
|
||||
DELETE FROM `creature_text` WHERE `CreatureID` IN (23954,23980) AND `GroupID` = 3;
|
||||
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(23954,3,0,"%s roars!",41,0,100,0,0,0,14029,0,"Ingvar the Plunderer - EMOTE_ROAR"),
|
||||
(23980,3,0,"%s roars!",41,0,100,0,0,0,14029,0,"Ingvar the Plunderer - EMOTE_ROAR");
|
||||
|
||||
DELETE FROM `creature_equip_template` WHERE `CreatureID` = 23954 AND `ID` = 2;
|
||||
UPDATE `creature_equip_template` SET `ItemID1` = 33177 WHERE `CreatureID` = 23954 AND `ID` = 1;
|
||||
UPDATE `creature` SET `equipment_id` = 1 WHERE `id` = 23954;
|
||||
|
||||
-- Keleseth
|
||||
DELETE FROM `creature_summon_groups` WHERE `summonerId` = 23953 AND `summonerType` = 0;
|
||||
INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`,`summonTime`,`Comment`) VALUES
|
||||
(23953,0,0,23970,153.91295,260.99866,42.953950,5.777040004730224609,8,0,"Prince Keleseth - Group 0 - Vrykul Skeleton"),
|
||||
(23953,0,0,23970,148.90604,260.21863,42.953945,5.899212837219238281,8,0,"Prince Keleseth - Group 0 - Vrykul Skeleton"),
|
||||
(23953,0,0,23970,147.77333,266.23520,42.953945,5.759586334228515625,8,0,"Prince Keleseth - Group 0 - Vrykul Skeleton"),
|
||||
(23953,0,0,23970,153.47198,266.16130,42.953945,5.619960308074951171,8,0,"Prince Keleseth - Group 0 - Vrykul Skeleton");
|
||||
|
||||
DELETE FROM `creature_text` WHERE `CreatureID` = 23953;
|
||||
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(23953,0,0,"Your blood is mine!",14,0,0,0,0,13221,22736,0,"Prince Keleseth - SAY_AGGRO"),
|
||||
(23953,1,0,"Not so fast.",14,0,0,0,0,13222,22734,0,"Prince Keleseth - SAY_FROST_TOMB"),
|
||||
(23953,2,0,"Darkness waits.",14,0,0,0,0,13223,29591,0,"Prince Keleseth - SAY_SLAY"),
|
||||
(23953,3,0,"Aranal, ledel! Their fate shall be yours!",14,0,0,0,0,13224,22729,0,"Prince Keleseth - SAY_SUMMON_SKELETONS"),
|
||||
(23953,4,0,"I join... the night.",14,0,0,0,0,13225,29592,0,"Prince Keleseth - SAY_DEATH"),
|
||||
(23953,5,0,"%s casts Frost Tomb on $n.",41,0,0,0,0,0,27152,0,"Prince Keleseth - EMOTE_FROST_TOMB");
|
||||
|
||||
UPDATE `spell_script_names` SET `ScriptName` = 'spell_keleseth_frost_tomb_channel' WHERE `ScriptName` = 'spell_frost_tomb';
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_keleseth_frost_tomb_periodic';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(42672, 'spell_keleseth_frost_tomb_periodic');
|
||||
|
||||
DELETE FROM `creature_text` WHERE `CreatureID` = 23970;
|
||||
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
|
||||
(23970,0,0,"%s rises from the floor!",16,0,100,0,0,0,26607,0,"Vrykul Skeleton - EMOTE_RISES");
|
||||
|
||||
-- Skarvald
|
||||
DELETE FROM `creature_loot_template` WHERE `Entry` = 24201 AND `Reference` = 35045;
|
||||
DELETE FROM `creature_loot_template` WHERE `Entry` = 31656 AND `Item` = 47241;
|
||||
DELETE FROM `creature_loot_template` WHERE `Entry` = 31656 AND `Reference` = 35049;
|
||||
@@ -15,12 +15,12 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Ingvar_The_Plunderer
|
||||
SD%Complete: 95
|
||||
SDComment: Blizzlike Timers (just shadow axe summon needs a new timer)
|
||||
SDCategory: Utgarde Keep
|
||||
EndScriptData */
|
||||
/*
|
||||
* Combat timers requires to be revisited
|
||||
* Everything related to Ingvar Throw Dummy requires additional research and checks
|
||||
since it may be handled wrongly or something may be missing
|
||||
* Out of Combat events are NYI, should be handled from Proto-Drake Rider's script (DB issue)
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
@@ -28,146 +28,197 @@ EndScriptData */
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellScript.h"
|
||||
#include "utgarde_keep.h"
|
||||
|
||||
enum Yells
|
||||
enum IngvarTexts
|
||||
{
|
||||
// Ingvar (Human/Undead)
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2,
|
||||
// Ingvar (Human / Undead)
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2,
|
||||
EMOTE_ROAR = 3,
|
||||
|
||||
// Annhylde The Caller
|
||||
YELL_RESURRECT = 0
|
||||
SAY_RESURRECT = 0
|
||||
};
|
||||
|
||||
enum Events
|
||||
enum IngvarSpells
|
||||
{
|
||||
EVENT_CLEAVE = 1,
|
||||
// Human Form
|
||||
SPELL_CLEAVE = 42724,
|
||||
SPELL_SMASH = 42669,
|
||||
SPELL_STAGGERING_ROAR = 42708,
|
||||
SPELL_ENRAGE = 42705,
|
||||
|
||||
// Undead Form
|
||||
SPELL_DARK_SMASH = 42723,
|
||||
SPELL_DREADFUL_ROAR = 42729,
|
||||
SPELL_WOE_STRIKE = 42730,
|
||||
SPELL_SHADOW_AXE = 42748,
|
||||
|
||||
// Feign Death & Resurrection
|
||||
SPELL_CLEAR_ALL_DEBUFFS = 34098,
|
||||
SPELL_INGVAR_FEIGN_DEATH = 42795,
|
||||
SPELL_SUMMON_BANSHEE = 42912,
|
||||
SPELL_ETHEREAL_TELEPORT = 34427,
|
||||
SPELL_SCOURGE_RESURRECTION_CHANNEL = 42857,
|
||||
SPELL_SCOURGE_RESURRECTION_VISUAL = 42863,
|
||||
SPELL_SCOURGE_RESURRECTION_HEAL = 42704,
|
||||
|
||||
// Ingvar Throw Dummy
|
||||
SPELL_THROW_AXE = 42750,
|
||||
|
||||
// Scripts
|
||||
SPELL_WOE_STRIKE_EFFECT = 42739
|
||||
};
|
||||
|
||||
enum IngvarEvents
|
||||
{
|
||||
EVENT_CLEAVE = 1,
|
||||
EVENT_SMASH,
|
||||
EVENT_STAGGERING_ROAR,
|
||||
EVENT_ENRAGE,
|
||||
|
||||
EVENT_SUMMON_BANSHEE,
|
||||
|
||||
EVENT_DARK_SMASH,
|
||||
EVENT_DREADFUL_ROAR,
|
||||
EVENT_WOE_STRIKE,
|
||||
EVENT_SHADOW_AXE,
|
||||
EVENT_JUST_TRANSFORMED,
|
||||
EVENT_SUMMON_BANSHEE,
|
||||
|
||||
EVENT_RESURRECT_1,
|
||||
EVENT_RESURRECT_2
|
||||
EVENT_RESURRECTION_1,
|
||||
EVENT_RESURRECTION_2,
|
||||
EVENT_RESURRECTION_3,
|
||||
EVENT_RESURRECTION_4,
|
||||
EVENT_RESURRECTION_5,
|
||||
EVENT_RESURRECTION_6,
|
||||
EVENT_RESURRECTION_7,
|
||||
EVENT_RESURRECTION_8,
|
||||
EVENT_RESURRECTION_9,
|
||||
EVENT_RESURRECTION_10
|
||||
};
|
||||
|
||||
enum Phases
|
||||
enum IngvarActions
|
||||
{
|
||||
PHASE_HUMAN = 1,
|
||||
PHASE_UNDEAD,
|
||||
PHASE_EVENT
|
||||
ACTION_START_UNDEAD_PHASE = 0,
|
||||
ACTION_AXE_RETURNS = 1
|
||||
};
|
||||
|
||||
enum Spells
|
||||
enum IngvarPoints
|
||||
{
|
||||
// Ingvar Spells human form
|
||||
SPELL_CLEAVE = 42724,
|
||||
SPELL_SMASH = 42669,
|
||||
SPELL_STAGGERING_ROAR = 42708,
|
||||
SPELL_ENRAGE = 42705,
|
||||
|
||||
SPELL_INGVAR_FEIGN_DEATH = 42795,
|
||||
SPELL_SUMMON_BANSHEE = 42912,
|
||||
SPELL_SCOURG_RESURRECTION = 42863, // Spawn resurrect effect around Ingvar
|
||||
|
||||
// Ingvar Spells undead form
|
||||
SPELL_DARK_SMASH = 42723,
|
||||
SPELL_DREADFUL_ROAR = 42729,
|
||||
SPELL_WOE_STRIKE = 42730,
|
||||
SPELL_WOE_STRIKE_EFFECT = 42739,
|
||||
|
||||
SPELL_SHADOW_AXE_SUMMON = 42748,
|
||||
SPELL_SHADOW_AXE_PERIODIC_DAMAGE = 42750,
|
||||
|
||||
// Spells for Annhylde
|
||||
SPELL_SCOURG_RESURRECTION_HEAL = 42704, // Heal Max + DummyAura
|
||||
SPELL_SCOURG_RESURRECTION_BEAM = 42857, // Channeling Beam of Annhylde
|
||||
SPELL_SCOURG_RESURRECTION_DUMMY = 42862, // Some Emote Dummy?
|
||||
SPELL_INGVAR_TRANSFORM = 42796
|
||||
POINT_CALLER_DOWN = 0,
|
||||
POINT_CALLER_UP = 1,
|
||||
POINT_AXE_TO_TARGET = 2,
|
||||
POINT_AXE_TO_OWNER = 3
|
||||
};
|
||||
|
||||
enum Misc
|
||||
enum IngvarCreatures
|
||||
{
|
||||
ACTION_START_PHASE_2
|
||||
NPC_INGVAR_UNDEAD = 23980,
|
||||
NPC_THROW_TARGET = 23996
|
||||
};
|
||||
|
||||
// 23954 - Ingvar the Plunderer
|
||||
struct boss_ingvar_the_plunderer : public BossAI
|
||||
{
|
||||
boss_ingvar_the_plunderer(Creature* creature) : BossAI(creature, DATA_INGVAR) { }
|
||||
boss_ingvar_the_plunderer(Creature* creature) : BossAI(creature, DATA_INGVAR), _isUnkillable(true), _isInTransition(false) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
if (me->GetEntry() != NPC_INGVAR)
|
||||
me->UpdateEntry(NPC_INGVAR);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetImmuneToPC(false);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth() && events.IsInPhase(PHASE_HUMAN))
|
||||
{
|
||||
events.SetPhase(PHASE_EVENT);
|
||||
events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 3s, 0, PHASE_EVENT);
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->StopMoving();
|
||||
DoCast(me, SPELL_INGVAR_FEIGN_DEATH, true);
|
||||
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetImmuneToPC(true, true);
|
||||
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
if (events.IsInPhase(PHASE_EVENT))
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
void DoAction(int32 actionId) override
|
||||
{
|
||||
if (actionId == ACTION_START_PHASE_2)
|
||||
StartZombiePhase();
|
||||
}
|
||||
|
||||
void StartZombiePhase()
|
||||
{
|
||||
me->RemoveAura(SPELL_INGVAR_FEIGN_DEATH);
|
||||
DoCast(me, SPELL_INGVAR_TRANSFORM, true);
|
||||
me->UpdateEntry(NPC_INGVAR_UNDEAD);
|
||||
events.ScheduleEvent(EVENT_JUST_TRANSFORMED, 500ms, 0, PHASE_EVENT);
|
||||
_isUnkillable = true;
|
||||
_isInTransition = false;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
if (events.IsInPhase(PHASE_EVENT) || events.IsInPhase(PHASE_UNDEAD)) // ingvar gets multiple JustEngagedWith calls
|
||||
return;
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
events.SetPhase(PHASE_HUMAN);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 6s, 12s, 0, PHASE_HUMAN);
|
||||
events.ScheduleEvent(EVENT_STAGGERING_ROAR, 18s, 21s, 0, PHASE_HUMAN);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 7s, 14s, 0, PHASE_HUMAN);
|
||||
events.ScheduleEvent(EVENT_SMASH, 12s, 17s, 0, PHASE_HUMAN);
|
||||
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 6s, 12s);
|
||||
events.ScheduleEvent(EVENT_SMASH, 12s, 17s);
|
||||
events.ScheduleEvent(EVENT_STAGGERING_ROAR, 18s, 21s);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 7s, 14s);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (events.IsInPhase(PHASE_EVENT)) // prevent ingvar from beginning to attack/chase during transition
|
||||
return;
|
||||
BossAI::AttackStart(who);
|
||||
if (damage >= me->GetHealth() && _isUnkillable)
|
||||
{
|
||||
damage = me->GetHealth() - 1;
|
||||
|
||||
if (_isInTransition)
|
||||
return;
|
||||
|
||||
_isInTransition = true;
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
Talk(SAY_DEATH);
|
||||
/// @todo: This should not be called. Clear All Debuffs should remove all debuffs. Does it work? Remove this
|
||||
me->RemoveAllAuras();
|
||||
DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS);
|
||||
DoCastSelf(SPELL_INGVAR_FEIGN_DEATH);
|
||||
/// This one is removed manually
|
||||
me->RemoveAurasDueToSpell(SPELL_ENRAGE);
|
||||
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 2400ms);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSpellStart(SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_STAGGERING_ROAR, me) ||
|
||||
spell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_DREADFUL_ROAR, me))
|
||||
Talk(EMOTE_ROAR);
|
||||
}
|
||||
|
||||
void OnSpellCast(SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id == SPELL_SHADOW_AXE)
|
||||
SetEquipmentSlots(false, EQUIP_UNEQUIP);
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_START_UNDEAD_PHASE:
|
||||
me->UpdateEntry(NPC_INGVAR_UNDEAD);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
Talk(SAY_AGGRO);
|
||||
DoZoneInCombat();
|
||||
|
||||
_isUnkillable = false;
|
||||
|
||||
events.ScheduleEvent(EVENT_DARK_SMASH, 14s, 18s);
|
||||
events.ScheduleEvent(EVENT_DREADFUL_ROAR, 0s);
|
||||
events.ScheduleEvent(EVENT_WOE_STRIKE, 10s, 14s);
|
||||
events.ScheduleEvent(EVENT_SHADOW_AXE, 30s);
|
||||
break;
|
||||
case ACTION_AXE_RETURNS:
|
||||
me->LoadEquipment(1, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -176,24 +227,9 @@ struct boss_ingvar_the_plunderer : public BossAI
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void ScheduleSecondPhase()
|
||||
{
|
||||
events.SetPhase(PHASE_UNDEAD);
|
||||
events.ScheduleEvent(EVENT_DARK_SMASH, 14s, 18s, 0, PHASE_UNDEAD);
|
||||
events.ScheduleEvent(EVENT_DREADFUL_ROAR, 0ms, 0, PHASE_UNDEAD);
|
||||
events.ScheduleEvent(EVENT_WOE_STRIKE, 10s, 14s, 0, PHASE_UNDEAD);
|
||||
events.ScheduleEvent(EVENT_SHADOW_AXE, 30s, 0, PHASE_UNDEAD);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!events.IsInPhase(PHASE_EVENT) && !UpdateVictim())
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
@@ -205,50 +241,46 @@ struct boss_ingvar_the_plunderer : public BossAI
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
// PHASE ONE
|
||||
// Human Phase
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 6s, 12s, 0, PHASE_HUMAN);
|
||||
break;
|
||||
case EVENT_STAGGERING_ROAR:
|
||||
DoCast(me, SPELL_STAGGERING_ROAR);
|
||||
events.ScheduleEvent(EVENT_STAGGERING_ROAR, 18s, 22s, 0, PHASE_HUMAN);
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 7s, 14s, 0, PHASE_HUMAN);
|
||||
events.Repeat(6s, 12s);
|
||||
break;
|
||||
case EVENT_SMASH:
|
||||
DoCastAOE(SPELL_SMASH);
|
||||
events.ScheduleEvent(EVENT_SMASH, 12s, 16s, 0, PHASE_HUMAN);
|
||||
DoCastSelf(SPELL_SMASH);
|
||||
events.Repeat(12s, 16s);
|
||||
break;
|
||||
case EVENT_JUST_TRANSFORMED:
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetImmuneToPC(false);
|
||||
ScheduleSecondPhase();
|
||||
Talk(SAY_AGGRO);
|
||||
DoZoneInCombat();
|
||||
return;
|
||||
case EVENT_STAGGERING_ROAR:
|
||||
DoCastSelf(SPELL_STAGGERING_ROAR);
|
||||
events.Repeat(18s, 22s);
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
events.Repeat(7s, 14s);
|
||||
break;
|
||||
|
||||
// Transition Phase
|
||||
case EVENT_SUMMON_BANSHEE:
|
||||
DoCast(me, SPELL_SUMMON_BANSHEE);
|
||||
return;
|
||||
// PHASE TWO
|
||||
DoCastSelf(SPELL_SUMMON_BANSHEE);
|
||||
break;
|
||||
|
||||
// Undead Phase
|
||||
case EVENT_DARK_SMASH:
|
||||
DoCastVictim(SPELL_DARK_SMASH);
|
||||
events.ScheduleEvent(EVENT_DARK_SMASH, 12s, 16s, 0, PHASE_UNDEAD);
|
||||
DoCastSelf(SPELL_DARK_SMASH);
|
||||
events.Repeat(12s, 16s);
|
||||
break;
|
||||
case EVENT_DREADFUL_ROAR:
|
||||
DoCast(me, SPELL_DREADFUL_ROAR);
|
||||
events.ScheduleEvent(EVENT_DREADFUL_ROAR, 18s, 22s, 0, PHASE_UNDEAD);
|
||||
DoCastSelf(SPELL_DREADFUL_ROAR);
|
||||
events.Repeat(18s, 22s);
|
||||
break;
|
||||
case EVENT_WOE_STRIKE:
|
||||
DoCastVictim(SPELL_WOE_STRIKE);
|
||||
events.ScheduleEvent(EVENT_WOE_STRIKE, 10s, 14s, 0, PHASE_UNDEAD);
|
||||
events.Repeat(10s, 14s);
|
||||
break;
|
||||
case EVENT_SHADOW_AXE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0.0f, true))
|
||||
DoCast(target, SPELL_SHADOW_AXE_SUMMON);
|
||||
events.ScheduleEvent(EVENT_SHADOW_AXE, 30s, 0, PHASE_UNDEAD);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
|
||||
DoCast(target, SPELL_SHADOW_AXE);
|
||||
events.Repeat(30s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -258,27 +290,22 @@ struct boss_ingvar_the_plunderer : public BossAI
|
||||
return;
|
||||
}
|
||||
|
||||
if (!events.IsInPhase(PHASE_EVENT))
|
||||
DoMeleeAttackIfReady();
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isUnkillable;
|
||||
bool _isInTransition;
|
||||
};
|
||||
|
||||
// 24068 - Annhylde the Caller
|
||||
struct npc_annhylde_the_caller : public ScriptedAI
|
||||
{
|
||||
npc_annhylde_the_caller(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
x = 0.f;
|
||||
y = 0.f;
|
||||
z = 0.f;
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
npc_annhylde_the_caller(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
|
||||
|
||||
void Reset() override
|
||||
void JustAppeared() override
|
||||
{
|
||||
_events.Reset();
|
||||
|
||||
me->GetPosition(x, y, z);
|
||||
me->GetMotionMaster()->MovePoint(1, x, y, z - 15.0f);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_1, 0s);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
@@ -288,28 +315,17 @@ struct npc_annhylde_the_caller : public ScriptedAI
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 1:
|
||||
Talk(YELL_RESURRECT);
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
{
|
||||
ingvar->RemoveAura(SPELL_SUMMON_BANSHEE);
|
||||
ingvar->CastSpell(ingvar, SPELL_SCOURG_RESURRECTION_DUMMY, true);
|
||||
DoCast(ingvar, SPELL_SCOURG_RESURRECTION_BEAM);
|
||||
}
|
||||
_events.ScheduleEvent(EVENT_RESURRECT_1, 8s);
|
||||
case POINT_CALLER_DOWN:
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_3, 1s);
|
||||
break;
|
||||
case 2:
|
||||
me->DespawnOrUnsummon();
|
||||
case POINT_CALLER_UP:
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_10, 1s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* /*who*/) override { }
|
||||
void MoveInLineOfSight(Unit* /*who*/) override { }
|
||||
void JustEngagedWith(Unit* /*who*/) override { }
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_events.Update(diff);
|
||||
@@ -318,22 +334,51 @@ struct npc_annhylde_the_caller : public ScriptedAI
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RESURRECT_1:
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
{
|
||||
ingvar->RemoveAura(SPELL_INGVAR_FEIGN_DEATH);
|
||||
ingvar->CastSpell(ingvar, SPELL_SCOURG_RESURRECTION_HEAL, false);
|
||||
}
|
||||
_events.ScheduleEvent(EVENT_RESURRECT_2, 3s);
|
||||
case EVENT_RESURRECTION_1:
|
||||
DoCastSelf(SPELL_ETHEREAL_TELEPORT);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_2, 2400ms);
|
||||
break;
|
||||
case EVENT_RESURRECT_2:
|
||||
case EVENT_RESURRECTION_2:
|
||||
me->GetMotionMaster()->MovePoint(POINT_CALLER_DOWN, me->GetPositionWithOffset({ 0.0f, 0.0f, -15.0f }));
|
||||
break;
|
||||
case EVENT_RESURRECTION_3:
|
||||
Talk(SAY_RESURRECT);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_4, 2400ms);
|
||||
break;
|
||||
case EVENT_RESURRECTION_4:
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
ingvar->RemoveAurasDueToSpell(SPELL_SUMMON_BANSHEE);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_5, 1200ms);
|
||||
break;
|
||||
case EVENT_RESURRECTION_5:
|
||||
DoCastSelf(SPELL_SCOURGE_RESURRECTION_CHANNEL);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_6, 2400ms);
|
||||
break;
|
||||
case EVENT_RESURRECTION_6:
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
ingvar->CastSpell(ingvar, SPELL_SCOURGE_RESURRECTION_VISUAL);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_7, 6s);
|
||||
break;
|
||||
case EVENT_RESURRECTION_7:
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
{
|
||||
ingvar->RemoveAurasDueToSpell(SPELL_SCOURG_RESURRECTION_DUMMY);
|
||||
ingvar->AI()->DoAction(ACTION_START_PHASE_2);
|
||||
ingvar->RemoveAurasDueToSpell(SPELL_INGVAR_FEIGN_DEATH);
|
||||
///! HACK: Removing Feign Death changes react state to default
|
||||
ingvar->SetReactState(REACT_PASSIVE);
|
||||
ingvar->CastSpell(ingvar, SPELL_SCOURGE_RESURRECTION_HEAL);
|
||||
}
|
||||
|
||||
me->GetMotionMaster()->MovePoint(2, x, y, z + 15.0f);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_8, 3600ms);
|
||||
break;
|
||||
case EVENT_RESURRECTION_8:
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
ingvar->AI()->DoAction(ACTION_START_UNDEAD_PHASE);
|
||||
_events.ScheduleEvent(EVENT_RESURRECTION_9, 1200ms);
|
||||
break;
|
||||
case EVENT_RESURRECTION_9:
|
||||
me->GetMotionMaster()->MovePoint(POINT_CALLER_UP, me->GetPositionWithOffset({ 0.0f, 0.0f, 15.0f }));
|
||||
break;
|
||||
case EVENT_RESURRECTION_10:
|
||||
me->DespawnOrUnsummon();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -344,34 +389,53 @@ struct npc_annhylde_the_caller : public ScriptedAI
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
EventMap _events;
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
// 23997 - Ingvar Throw Dummy
|
||||
struct npc_ingvar_throw_dummy : public ScriptedAI
|
||||
{
|
||||
npc_ingvar_throw_dummy(Creature* creature) : ScriptedAI(creature) { }
|
||||
npc_ingvar_throw_dummy(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
|
||||
|
||||
void Reset() override
|
||||
void JustAppeared() override
|
||||
{
|
||||
if (Creature* target = me->FindNearestCreature(NPC_THROW_TARGET, 200.0f))
|
||||
DoCastSelf(SPELL_THROW_AXE);
|
||||
|
||||
_scheduler.Schedule(1s, [this](TaskContext /*task*/)
|
||||
{
|
||||
float x, y, z;
|
||||
target->GetPosition(x, y, z);
|
||||
me->GetMotionMaster()->MoveCharge(x, y, z);
|
||||
target->DespawnOrUnsummon();
|
||||
}
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
if (Creature* target = me->FindNearestCreature(NPC_THROW_TARGET, 200.0f))
|
||||
me->GetMotionMaster()->MovePoint(POINT_AXE_TO_TARGET, target->GetPosition());
|
||||
});
|
||||
|
||||
_scheduler.Schedule(6s, 10s, [this](TaskContext /*task*/)
|
||||
{
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
me->GetMotionMaster()->MovePoint(POINT_AXE_TO_OWNER, ingvar->GetPosition());
|
||||
});
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == EFFECT_MOTION_TYPE && id == EVENT_CHARGE)
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_AXE_TO_OWNER)
|
||||
{
|
||||
me->CastSpell(me, SPELL_SHADOW_AXE_PERIODIC_DAMAGE, true);
|
||||
me->DespawnOrUnsummon(10s);
|
||||
if (Creature* ingvar = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_INGVAR)))
|
||||
ingvar->AI()->DoAction(ACTION_AXE_RETURNS);
|
||||
|
||||
_scheduler.Schedule(1s, [this](TaskContext /*task*/)
|
||||
{
|
||||
SetEquipmentSlots(false, EQUIP_UNEQUIP);
|
||||
me->DespawnOrUnsummon();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
// 42912 - Summon Banshee
|
||||
|
||||
@@ -15,157 +15,145 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Prince_Keleseth
|
||||
SD%Complete: 100
|
||||
SDComment:
|
||||
SDCategory: Utgarde Keep
|
||||
EndScriptData */
|
||||
/*
|
||||
* Combat timers requires to be revisited
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
#include "MotionMaster.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TemporarySummon.h"
|
||||
#include "utgarde_keep.h"
|
||||
|
||||
enum KelsethEncounter
|
||||
enum KelesethTexts
|
||||
{
|
||||
SPELL_SHADOWBOLT = 43667,
|
||||
SPELL_FROST_TOMB = 48400,
|
||||
SPELL_FROST_TOMB_STUN = 42672,
|
||||
SPELL_FROST_TOMB_SUMMON = 42714,
|
||||
// Prince Keleseth
|
||||
SAY_AGGRO = 0,
|
||||
SAY_FROST_TOMB = 1,
|
||||
SAY_SLAY = 2,
|
||||
SAY_SUMMON_SKELETONS = 3,
|
||||
SAY_DEATH = 4,
|
||||
EMOTE_FROST_TOMB = 5,
|
||||
|
||||
SPELL_SHADOW_FISSURE = 50657,
|
||||
SPELL_FULL_HEAL = 17683,
|
||||
SPELL_DECREPIFY = 42702,
|
||||
SPELL_BONE_ARMOR = 59386,
|
||||
// Vrykul Skeleton
|
||||
EMOTE_RISES = 0
|
||||
};
|
||||
|
||||
NPC_FROSTTOMB = 23965,
|
||||
NPC_SKELETON = 23970,
|
||||
enum KelesethSpells
|
||||
{
|
||||
// Prince Keleseth
|
||||
SPELL_SHADOW_BOLT = 43667,
|
||||
SPELL_FROST_TOMB = 42672,
|
||||
|
||||
NPC_RUNEMAGE = 23960,
|
||||
NPC_STRATEGIST = 23956,
|
||||
// Vrykul Skeleton
|
||||
SPELL_DECREPIFY = 42702,
|
||||
SPELL_BONE_ARMOR = 59386,
|
||||
SPELL_SHADOW_FISSURE = 50657,
|
||||
SPELL_FULL_HEAL = 17683,
|
||||
SPELL_INSTAKILL_SELF = 29878,
|
||||
|
||||
SAY_START_COMBAT = 1,
|
||||
SAY_SUMMON_SKELETONS,
|
||||
SAY_FROST_TOMB,
|
||||
SAY_FROST_TOMB_EMOTE,
|
||||
SAY_DEATH,
|
||||
// Frost Tomb
|
||||
SPELL_FROST_TOMB_CHANNEL = 48400,
|
||||
|
||||
EVENT_SHADOWBOLT = 1,
|
||||
// Scripts
|
||||
SPELL_FROST_TOMB_SUMMON = 42714
|
||||
};
|
||||
|
||||
enum KelesethEvents
|
||||
{
|
||||
// Prince Keleseth
|
||||
EVENT_SHADOW_BOLT = 1,
|
||||
EVENT_FROST_TOMB,
|
||||
EVENT_SUMMON_SKELETONS,
|
||||
|
||||
// Vrykul Skeleton
|
||||
EVENT_ATTACK,
|
||||
EVENT_DECREPIFY,
|
||||
EVENT_FULL_HEAL,
|
||||
EVENT_SHADOW_FISSURE,
|
||||
EVENT_RESURRECT,
|
||||
|
||||
DATA_ON_THE_ROCKS
|
||||
EVENT_BONE_ARMOR,
|
||||
EVENT_RESURRECT_1,
|
||||
EVENT_RESURRECT_2
|
||||
};
|
||||
|
||||
#define SKELETONSPAWN_Z 42.8668f
|
||||
|
||||
float const SkeletonSpawnPoint[1][2] =
|
||||
enum KelesethMisc
|
||||
{
|
||||
{156.2559f, 259.2093f},
|
||||
};
|
||||
|
||||
float AttackLoc[3]= {197.636f, 194.046f, 40.8164f};
|
||||
|
||||
struct npc_frost_tomb : public ScriptedAI
|
||||
{
|
||||
npc_frost_tomb(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
_instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
void IsSummonedBy(WorldObject* summonerWO) override
|
||||
{
|
||||
Unit* summoner = summonerWO->ToUnit();
|
||||
if (!summoner)
|
||||
return;
|
||||
DoCast(summoner, SPELL_FROST_TOMB, true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override { }
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* keleseth = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_PRINCE_KELESETH)))
|
||||
keleseth->AI()->SetData(DATA_ON_THE_ROCKS, false);
|
||||
}
|
||||
|
||||
private:
|
||||
InstanceScript* _instance;
|
||||
SUMMON_GROUP_SKELETONS = 0,
|
||||
DATA_ON_THE_ROCKS = 1,
|
||||
ACTION_INSTAKILL_SELF = 0,
|
||||
NPC_SKELETON = 23970
|
||||
};
|
||||
|
||||
// 23953 - Prince Keleseth
|
||||
struct boss_keleseth : public BossAI
|
||||
{
|
||||
boss_keleseth(Creature* creature) : BossAI(creature, DATA_PRINCE_KELESETH)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
onTheRocks = true;
|
||||
}
|
||||
boss_keleseth(Creature* creature) : BossAI(creature, DATA_PRINCE_KELESETH), _onTheRocks(true) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
events.ScheduleEvent(EVENT_SHADOWBOLT, 2s, 3s);
|
||||
events.ScheduleEvent(EVENT_FROST_TOMB, 14s, 19s);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SKELETONS, 6s);
|
||||
|
||||
Initialize();
|
||||
_onTheRocks = true;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
Talk(SAY_START_COMBAT);
|
||||
|
||||
if (!who)
|
||||
return;
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
std::list<Creature*> guards;
|
||||
me->GetCreatureListWithEntryInGrid(guards, NPC_RUNEMAGE, 60.0f);
|
||||
me->GetCreatureListWithEntryInGrid(guards, NPC_STRATEGIST, 60.0f);
|
||||
if (!guards.empty())
|
||||
{
|
||||
for (std::list<Creature*>::iterator itr = guards.begin(); itr != guards.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->IsAlive() && (*itr)->IsWithinLOSInMap(me))
|
||||
(*itr)->AI()->AttackStart(who);
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 0s);
|
||||
events.ScheduleEvent(EVENT_FROST_TOMB, 14s, 19s);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SKELETONS, 5s);
|
||||
|
||||
/// @todo: Should he really call for help? Check this
|
||||
me->CallForHelp(50.0f);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
void KillSkeletons()
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_DEATH);
|
||||
std::vector<Creature*> skeletons;
|
||||
GetCreatureListWithEntryInGrid(skeletons, me, NPC_SKELETON, 200.0f);
|
||||
for (Creature* skeleton : skeletons)
|
||||
skeleton->AI()->DoAction(ACTION_INSTAKILL_SELF);
|
||||
}
|
||||
|
||||
// Do not engage or despawn summons, killed by spells
|
||||
void JustSummoned(Creature* /*summon*/) override { }
|
||||
|
||||
void SetData(uint32 data, uint32 value) override
|
||||
{
|
||||
if (data == DATA_ON_THE_ROCKS)
|
||||
onTheRocks = value != 0;
|
||||
_onTheRocks = value != 0;
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 data) const override
|
||||
{
|
||||
if (data == DATA_ON_THE_ROCKS)
|
||||
return onTheRocks;
|
||||
return _onTheRocks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
KillSkeletons();
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
KillSkeletons();
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
@@ -180,25 +168,22 @@ struct boss_keleseth : public BossAI
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SUMMON_SKELETONS:
|
||||
Talk(SAY_SUMMON_SKELETONS);
|
||||
SummonSkeletons();
|
||||
break;
|
||||
case EVENT_SHADOWBOLT:
|
||||
DoCastVictim(SPELL_SHADOWBOLT);
|
||||
events.ScheduleEvent(EVENT_SHADOWBOLT, 2s, 3s);
|
||||
case EVENT_SHADOW_BOLT:
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
events.Repeat(2s, 3s);
|
||||
break;
|
||||
case EVENT_FROST_TOMB:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_FROST_TOMB))
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_FROST_TOMB_CHANNEL))
|
||||
{
|
||||
Talk(SAY_FROST_TOMB);
|
||||
Talk(SAY_FROST_TOMB_EMOTE, target);
|
||||
|
||||
DoCast(target, SPELL_FROST_TOMB_STUN, true);
|
||||
// checked from sniffs - the player casts the spell
|
||||
target->CastSpell(target, SPELL_FROST_TOMB_SUMMON, true);
|
||||
Talk(SAY_FROST_TOMB, target);
|
||||
Talk(EMOTE_FROST_TOMB, target);
|
||||
DoCast(target, SPELL_FROST_TOMB);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_FROST_TOMB, 14s, 19s);
|
||||
events.Repeat(14s, 19s);
|
||||
break;
|
||||
case EVENT_SUMMON_SKELETONS:
|
||||
Talk(SAY_SUMMON_SKELETONS);
|
||||
me->SummonCreatureGroup(SUMMON_GROUP_SKELETONS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -211,83 +196,115 @@ struct boss_keleseth : public BossAI
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
void SummonSkeletons()
|
||||
{
|
||||
// I could not found any spell cast for this
|
||||
for (uint8 i = 0; i < 4; ++i)
|
||||
me->SummonCreature(NPC_SKELETON, SkeletonSpawnPoint[0][0], SkeletonSpawnPoint[0][1], SKELETONSPAWN_Z, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
bool onTheRocks;
|
||||
bool _onTheRocks;
|
||||
};
|
||||
|
||||
// 23970 - Vrykul Skeleton
|
||||
struct npc_vrykul_skeleton : public ScriptedAI
|
||||
{
|
||||
npc_vrykul_skeleton(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
void InitializeAI() override
|
||||
{
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_DECREPIFY, 4s, 6s);
|
||||
me->SetCorpseDelay(15, true);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
void JustAppeared() override
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
_events.ScheduleEvent(EVENT_ATTACK, 7s);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_DECREPIFY, 4s, 6s);
|
||||
if (IsHeroic())
|
||||
_events.ScheduleEvent(EVENT_BONE_ARMOR, 10s, 15s);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
// Creature is unkillable by default. But allow to kill self with spell
|
||||
if (damage >= me->GetHealth() && attacker != me)
|
||||
{
|
||||
damage = 0;
|
||||
damage = me->GetHealth() - 1;
|
||||
|
||||
// There are some issues with pets
|
||||
// they will still attack. I would say it is a PetAI bug
|
||||
if (!me->HasUnitFlag(UNIT_FLAG_UNINTERACTIBLE))
|
||||
{
|
||||
// from sniffs
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_RESURRECT, 18s, 22s);
|
||||
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
_events.Reset();
|
||||
_events.ScheduleEvent(EVENT_RESURRECT_1, 18s, 22s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_INSTAKILL_SELF)
|
||||
{
|
||||
/// @todo: Spell doesn't work if creature is in evade mode
|
||||
DoCastSelf(SPELL_INSTAKILL_SELF, true);
|
||||
me->KillSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
{
|
||||
_events.Update(diff);
|
||||
|
||||
events.Update(diff);
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ATTACK:
|
||||
DoZoneInCombat();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_events.Update(diff);
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_DECREPIFY:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, true, -SPELL_DECREPIFY))
|
||||
DoCast(target, SPELL_DECREPIFY);
|
||||
events.ScheduleEvent(EVENT_DECREPIFY, 1s, 5s);
|
||||
DoCastVictim(SPELL_DECREPIFY);
|
||||
_events.Repeat(1s, 5s);
|
||||
break;
|
||||
case EVENT_RESURRECT:
|
||||
events.ScheduleEvent(EVENT_FULL_HEAL, 1s);
|
||||
events.ScheduleEvent(EVENT_SHADOW_FISSURE, 1s);
|
||||
case EVENT_BONE_ARMOR:
|
||||
/// It is unclear how exactly this ability is used
|
||||
if (roll_chance_i(50))
|
||||
DoCastSelf(SPELL_BONE_ARMOR);
|
||||
_events.Repeat(20s, 30s);
|
||||
break;
|
||||
case EVENT_FULL_HEAL:
|
||||
DoCast(me, SPELL_FULL_HEAL, true);
|
||||
break;
|
||||
case EVENT_SHADOW_FISSURE:
|
||||
DoCast(me, SPELL_SHADOW_FISSURE, true);
|
||||
DoCastAOE(SPELL_BONE_ARMOR, true);
|
||||
case EVENT_RESURRECT_1:
|
||||
DoCastSelf(SPELL_SHADOW_FISSURE);
|
||||
DoCastSelf(SPELL_FULL_HEAL);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
events.ScheduleEvent(EVENT_DECREPIFY, 4s, 6s);
|
||||
Talk(EMOTE_RISES);
|
||||
_events.ScheduleEvent(EVENT_RESURRECT_2, 1s);
|
||||
break;
|
||||
case EVENT_RESURRECT_2:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
_events.ScheduleEvent(EVENT_DECREPIFY, 4s, 6s);
|
||||
if (IsHeroic())
|
||||
_events.ScheduleEvent(EVENT_BONE_ARMOR, 10s, 15s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -297,20 +314,104 @@ struct npc_vrykul_skeleton : public ScriptedAI
|
||||
return;
|
||||
}
|
||||
|
||||
if (!me->HasUnitFlag(UNIT_FLAG_UNINTERACTIBLE))
|
||||
DoMeleeAttackIfReady();
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
// 23965 - Frost Tomb
|
||||
struct npc_frost_tomb : public ScriptedAI
|
||||
{
|
||||
npc_frost_tomb(Creature* creature) : ScriptedAI(creature), _isKilled(false), _instance(creature->GetInstanceScript()) { }
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
void JustAppeared() override
|
||||
{
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
if (Unit* summoner = summon->GetSummonerUnit())
|
||||
DoCast(summoner, SPELL_FROST_TOMB_CHANNEL);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
damage = me->GetHealth() -1;
|
||||
|
||||
if (_isKilled)
|
||||
return;
|
||||
|
||||
_isKilled = true;
|
||||
|
||||
_scheduler.Schedule(0s, [this](TaskContext task)
|
||||
{
|
||||
switch (task.GetRepeatCounter())
|
||||
{
|
||||
case 0:
|
||||
if (Creature* keleseth = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_PRINCE_KELESETH)))
|
||||
keleseth->AI()->SetData(DATA_ON_THE_ROCKS, false);
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
task.Repeat(1s);
|
||||
break;
|
||||
case 1:
|
||||
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
task.Repeat(1s);
|
||||
break;
|
||||
case 2:
|
||||
me->DespawnOrUnsummon();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
bool _isKilled;
|
||||
TaskScheduler _scheduler;
|
||||
InstanceScript* _instance;
|
||||
};
|
||||
|
||||
// 42672 - Frost Tomb
|
||||
class spell_keleseth_frost_tomb_periodic : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_keleseth_frost_tomb_periodic);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_FROST_TOMB_SUMMON });
|
||||
}
|
||||
|
||||
void OnPeriodic(AuraEffect const* aurEff)
|
||||
{
|
||||
if (aurEff->GetTickNumber() == 1)
|
||||
GetTarget()->CastSpell(GetTarget(), SPELL_FROST_TOMB_SUMMON, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_keleseth_frost_tomb_periodic::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
// 48400 - Frost Tomb
|
||||
class spell_frost_tomb : public AuraScript
|
||||
class spell_keleseth_frost_tomb_channel : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_frost_tomb);
|
||||
PrepareAuraScript(spell_keleseth_frost_tomb_channel);
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
|
||||
if (Unit* caster = GetCaster())
|
||||
@@ -321,7 +422,7 @@ class spell_frost_tomb : public AuraScript
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_frost_tomb::OnRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_keleseth_frost_tomb_channel::AfterRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -332,6 +433,7 @@ class achievement_on_the_rocks : public AchievementCriteriaScript
|
||||
|
||||
bool OnCheck(Player* /*source*/, Unit* target) override
|
||||
{
|
||||
// todo: migrate to worldstate 3895 (worldstateexpression 6312)
|
||||
return target && target->GetAI() && target->GetAI()->GetData(DATA_ON_THE_ROCKS);
|
||||
}
|
||||
};
|
||||
@@ -341,6 +443,7 @@ void AddSC_boss_keleseth()
|
||||
RegisterUtgardeKeepCreatureAI(boss_keleseth);
|
||||
RegisterUtgardeKeepCreatureAI(npc_frost_tomb);
|
||||
RegisterUtgardeKeepCreatureAI(npc_vrykul_skeleton);
|
||||
RegisterSpellScript(spell_frost_tomb);
|
||||
RegisterSpellScript(spell_keleseth_frost_tomb_periodic);
|
||||
RegisterSpellScript(spell_keleseth_frost_tomb_channel);
|
||||
new achievement_on_the_rocks();
|
||||
}
|
||||
|
||||
@@ -15,12 +15,9 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Skarvald_Dalronn
|
||||
SD%Complete: 95
|
||||
SDComment: Needs adjustments to blizzlike timers
|
||||
SDCategory: Utgarde Keep
|
||||
EndScriptData */
|
||||
/*
|
||||
* Combat timers requires to be revisited
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "InstanceScript.h"
|
||||
@@ -28,53 +25,67 @@ EndScriptData */
|
||||
#include "ScriptedCreature.h"
|
||||
#include "utgarde_keep.h"
|
||||
|
||||
enum Texts
|
||||
enum SkarvaldTexts
|
||||
{
|
||||
// Texts are common for both bosses and their ghosts.
|
||||
SAY_AGGRO = 0,
|
||||
SAY_DEATH = 1, // Said once both bosses are dead.
|
||||
SAY_DIED_FIRST = 2, // Said by the first boss that dies.
|
||||
SAY_KILL = 3,
|
||||
SAY_DEATH_RESPONSE = 4 // Said by the boss alive after the first one dies.
|
||||
|
||||
// Texts are common for both bosses.
|
||||
SAY_AGGRO = 0,
|
||||
SAY_DEATH = 1, // Said once both bosses are dead.
|
||||
SAY_DIED_FIRST = 2, // Said by the first boss that dies.
|
||||
SAY_SLAY = 3,
|
||||
SAY_DEATH_RESPONSE = 4 // Said by the boss alive after the first one dies.
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
// Spells of Skarvald and his Ghost
|
||||
SPELL_CHARGE = 43651,
|
||||
SPELL_STONE_STRIKE = 48583,
|
||||
SPELL_ENRAGE = 48193,
|
||||
SPELL_SUMMON_SKARVALD_GHOST = 48613,
|
||||
|
||||
// Spells of Dalronn and his Ghost
|
||||
SPELL_SHADOW_BOLT = 43649,
|
||||
SPELL_SUMMON_SKELETONS = 52611,
|
||||
SPELL_DEBILITATE = 43650,
|
||||
SPELL_SUMMON_DALRONN_GHOST = 48612,
|
||||
};
|
||||
|
||||
enum Events
|
||||
enum SkarvaldSpells
|
||||
{
|
||||
// Skarvald the Constructor
|
||||
EVENT_SKARVALD_CHARGE = 1,
|
||||
SPELL_CHARGE = 43651,
|
||||
SPELL_STONE_STRIKE = 48583,
|
||||
SPELL_ENRAGE = 48193,
|
||||
SPELL_SUMMON_SKARVALD_GHOST = 48613,
|
||||
|
||||
// Dalronn the Controller
|
||||
SPELL_SHADOW_BOLT = 43649,
|
||||
SPELL_SUMMON_SKELETONS = 52611,
|
||||
SPELL_DEBILITATE = 43650,
|
||||
SPELL_SUMMON_DALRONN_GHOST = 48612,
|
||||
|
||||
// Ghosts
|
||||
SPELL_GHOST_VISUAL = 22650,
|
||||
SPELL_PERIODIC_HEAL = 48591,
|
||||
|
||||
// Shared
|
||||
SPELL_PERMANENT_FEIGN_DEATH = 29266,
|
||||
SPELL_QUIET_SUICIDE = 3617
|
||||
};
|
||||
|
||||
enum SkarvaldEvents
|
||||
{
|
||||
// Skarvald the Constructor
|
||||
EVENT_SKARVALD_CHARGE = 1,
|
||||
EVENT_STONE_STRIKE,
|
||||
EVENT_ENRAGE,
|
||||
|
||||
// Dalronn the Controller
|
||||
EVENT_SHADOW_BOLT,
|
||||
EVENT_DEBILITATE,
|
||||
EVENT_SUMMON_SKELETONS,
|
||||
EVENT_DELAYED_AGGRO_SAY, // Dalronn's SAY_AGGRO is delayed so it doesn't overlap Skarvald's one.
|
||||
EVENT_DELAYED_AGGRO_SAY,
|
||||
|
||||
// Common event to both bosses.
|
||||
// Delays SAY_DEATH_RESPONSE so it doesn't overlap with the SAY_DIED_FIRST from the boss that has just died.
|
||||
EVENT_DEATH_RESPONSE
|
||||
// Common
|
||||
EVENT_DEATH_RESPONSE,
|
||||
EVENT_FEIGN_DEATH
|
||||
};
|
||||
|
||||
enum Actions
|
||||
enum SkarvaldActions
|
||||
{
|
||||
ACTION_OTHER_JUST_DIED = 1,
|
||||
ACTION_DESPAWN_SUMMONS = 2 // Only needed to clear off the ghosts when the second boss dies.
|
||||
ACTION_OTHER_FEIGNS_DEATH = 1,
|
||||
ACTION_CLEANUP_AND_DIE = 2
|
||||
};
|
||||
|
||||
enum SkarvaldCreatures
|
||||
{
|
||||
NPC_DALRONN_GHOST = 27389,
|
||||
NPC_SKARVALD_GHOST = 27390
|
||||
};
|
||||
|
||||
class SkarvaldChargePredicate
|
||||
@@ -91,23 +102,37 @@ class SkarvaldChargePredicate
|
||||
Unit* _me;
|
||||
};
|
||||
|
||||
struct generic_boss_controllerAI : public BossAI
|
||||
struct ControllerBaseAI : public BossAI
|
||||
{
|
||||
generic_boss_controllerAI(Creature* creature) : BossAI(creature, DATA_SKARVALD_DALRONN)
|
||||
ControllerBaseAI(Creature* creature) : BossAI(creature, DATA_SKARVALD_DALRONN)
|
||||
{
|
||||
OtherBossData = 0;
|
||||
IsInGhostForm = me->GetEntry() == NPC_SKARVALD_GHOST || me->GetEntry() == NPC_DALRONN_GHOST;
|
||||
OtherFeignsDeath = false;
|
||||
IsAboutToFeignDeath = false;
|
||||
}
|
||||
|
||||
void JustAppeared() override
|
||||
{
|
||||
if (!IsInGhostForm)
|
||||
return;
|
||||
|
||||
DoCastSelf(SPELL_GHOST_VISUAL);
|
||||
DoCastSelf(SPELL_PERIODIC_HEAL);
|
||||
|
||||
DoZoneInCombat();
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
if (IsInGhostForm)
|
||||
if (!IsInGhostForm)
|
||||
{
|
||||
// Call this here since ghosts aren't set in combat as they spawn.
|
||||
DoZoneInCombat(me);
|
||||
}
|
||||
else
|
||||
_Reset();
|
||||
OtherFeignsDeath = false;
|
||||
IsAboutToFeignDeath = false;
|
||||
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
@@ -116,81 +141,108 @@ struct generic_boss_controllerAI : public BossAI
|
||||
BossAI::JustEngagedWith(who);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
void DamageTaken(Unit* who, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (Creature* otherBoss = ObjectAccessor::GetCreature(*me, instance->GetGuidData(OtherBossData)))
|
||||
if (OtherFeignsDeath)
|
||||
return;
|
||||
|
||||
if (damage >= me->GetHealth() && who != me)
|
||||
{
|
||||
if (otherBoss->IsAlive())
|
||||
damage = me->GetHealth() -1;
|
||||
|
||||
if (!IsAboutToFeignDeath)
|
||||
{
|
||||
Talk(SAY_DIED_FIRST);
|
||||
me->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
otherBoss->AI()->DoAction(ACTION_OTHER_JUST_DIED);
|
||||
DoCast(me, OtherBossData == DATA_DALRONN ? SPELL_SUMMON_SKARVALD_GHOST : SPELL_SUMMON_DALRONN_GHOST, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
otherBoss->AI()->DoAction(ACTION_DESPAWN_SUMMONS);
|
||||
_JustDied();
|
||||
IsAboutToFeignDeath = true;
|
||||
|
||||
if (Creature* otherBoss = ObjectAccessor::GetCreature(*me, instance->GetGuidData(OtherBossData)))
|
||||
otherBoss->AI()->DoAction(ACTION_OTHER_FEIGNS_DEATH);
|
||||
|
||||
events.Reset();
|
||||
events.ScheduleEvent(EVENT_FEIGN_DEATH, 0s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 actionId) override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
switch (actionId)
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_OTHER_JUST_DIED:
|
||||
events.ScheduleEvent(EVENT_DEATH_RESPONSE, 2s);
|
||||
case ACTION_OTHER_FEIGNS_DEATH:
|
||||
events.ScheduleEvent(EVENT_DEATH_RESPONSE, 4s);
|
||||
OtherFeignsDeath = true;
|
||||
break;
|
||||
case ACTION_DESPAWN_SUMMONS:
|
||||
case ACTION_CLEANUP_AND_DIE:
|
||||
summons.DespawnAll();
|
||||
DoCastSelf(SPELL_QUIET_SUICIDE, true);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
if (eventId == EVENT_DEATH_RESPONSE)
|
||||
Talk(SAY_DEATH_RESPONSE);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (!IsInGhostForm && who->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_KILL);
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32 OtherBossData;
|
||||
bool IsInGhostForm;
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (OtherFeignsDeath)
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
|
||||
if (Creature* otherBoss = ObjectAccessor::GetCreature(*me, instance->GetGuidData(OtherBossData)))
|
||||
otherBoss->AI()->DoAction(ACTION_CLEANUP_AND_DIE);
|
||||
}
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_DEATH_RESPONSE:
|
||||
Talk(SAY_DEATH_RESPONSE);
|
||||
break;
|
||||
case EVENT_FEIGN_DEATH:
|
||||
Talk(SAY_DIED_FIRST);
|
||||
DoCastSelf(OtherBossData == DATA_DALRONN ? SPELL_SUMMON_SKARVALD_GHOST : SPELL_SUMMON_DALRONN_GHOST, true);
|
||||
DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH);
|
||||
me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32 OtherBossData;
|
||||
bool IsInGhostForm;
|
||||
bool OtherFeignsDeath;
|
||||
bool IsAboutToFeignDeath;
|
||||
};
|
||||
|
||||
struct boss_skarvald_the_constructor : public generic_boss_controllerAI
|
||||
// 24200, 27390 - Skarvald the Constructor
|
||||
struct boss_skarvald_the_constructor : public ControllerBaseAI
|
||||
{
|
||||
boss_skarvald_the_constructor(Creature* creature) : generic_boss_controllerAI(creature)
|
||||
boss_skarvald_the_constructor(Creature* creature) : ControllerBaseAI(creature)
|
||||
{
|
||||
OtherBossData = DATA_DALRONN;
|
||||
Enraged = false;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Enraged = false;
|
||||
generic_boss_controllerAI::Reset();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
generic_boss_controllerAI::JustEngagedWith(who);
|
||||
ControllerBaseAI::JustEngagedWith(who);
|
||||
|
||||
if (!IsInGhostForm)
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_SKARVALD_CHARGE, 5s);
|
||||
events.ScheduleEvent(EVENT_STONE_STRIKE, 10s);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 10s, 15s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
@@ -200,49 +252,42 @@ struct boss_skarvald_the_constructor : public generic_boss_controllerAI
|
||||
case EVENT_SKARVALD_CHARGE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, SkarvaldChargePredicate(me)))
|
||||
DoCast(target, SPELL_CHARGE);
|
||||
events.ScheduleEvent(EVENT_CHARGE, 5s, 10s);
|
||||
events.Repeat(5s, 10s);
|
||||
break;
|
||||
case EVENT_STONE_STRIKE:
|
||||
DoCastVictim(SPELL_STONE_STRIKE);
|
||||
events.ScheduleEvent(EVENT_STONE_STRIKE, 5s, 10s);
|
||||
events.Repeat(5s, 10s);
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
events.Repeat(20s, 30s);
|
||||
break;
|
||||
default:
|
||||
generic_boss_controllerAI::ExecuteEvent(eventId);
|
||||
ControllerBaseAI::ExecuteEvent(eventId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (!Enraged && !IsInGhostForm && me->HealthBelowPctDamaged(15, damage))
|
||||
{
|
||||
Enraged = true;
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool Enraged;
|
||||
};
|
||||
|
||||
struct boss_dalronn_the_controller : public generic_boss_controllerAI
|
||||
// 24201, 27389 - Dalronn the Controller
|
||||
struct boss_dalronn_the_controller : public ControllerBaseAI
|
||||
{
|
||||
boss_dalronn_the_controller(Creature* creature) : generic_boss_controllerAI(creature)
|
||||
boss_dalronn_the_controller(Creature* creature) : ControllerBaseAI(creature)
|
||||
{
|
||||
OtherBossData = DATA_SKARVALD;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
generic_boss_controllerAI::JustEngagedWith(who);
|
||||
ControllerBaseAI::JustEngagedWith(who);
|
||||
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 1s);
|
||||
events.ScheduleEvent(EVENT_DEBILITATE, 5s);
|
||||
|
||||
if (!IsInGhostForm)
|
||||
events.ScheduleEvent(EVENT_DELAYED_AGGRO_SAY, 5s);
|
||||
|
||||
if (IsHeroic())
|
||||
events.ScheduleEvent(EVENT_SUMMON_SKELETONS, 10s);
|
||||
|
||||
if (!IsInGhostForm)
|
||||
events.ScheduleEvent(EVENT_DELAYED_AGGRO_SAY, 6s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
@@ -252,22 +297,22 @@ struct boss_dalronn_the_controller : public generic_boss_controllerAI
|
||||
case EVENT_SHADOW_BOLT:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f, true))
|
||||
DoCast(target, SPELL_SHADOW_BOLT);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 2100ms); //give a 100ms pause to try cast other spells
|
||||
events.Repeat(2s, 4s);
|
||||
break;
|
||||
case EVENT_DEBILITATE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 50.0f, true))
|
||||
DoCast(target, SPELL_DEBILITATE);
|
||||
events.ScheduleEvent(EVENT_DEBILITATE, 5s, 10s);
|
||||
events.Repeat(5s, 10s);
|
||||
break;
|
||||
case EVENT_SUMMON_SKELETONS:
|
||||
DoCast(me, SPELL_SUMMON_SKELETONS);
|
||||
events.ScheduleEvent(EVENT_SUMMON_SKELETONS, 10s, 30s);
|
||||
DoCastSelf(SPELL_SUMMON_SKELETONS);
|
||||
events.Repeat(10s, 30s);
|
||||
break;
|
||||
case EVENT_DELAYED_AGGRO_SAY:
|
||||
Talk(SAY_AGGRO);
|
||||
break;
|
||||
default:
|
||||
generic_boss_controllerAI::ExecuteEvent(eventId);
|
||||
ControllerBaseAI::ExecuteEvent(eventId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,6 @@ DoorData const doorData[] =
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
MinionData const minionData[] =
|
||||
{
|
||||
{ NPC_SKARVALD, DATA_SKARVALD_DALRONN },
|
||||
{ NPC_DALRONN, DATA_SKARVALD_DALRONN },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
class instance_utgarde_keep : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -47,7 +40,6 @@ class instance_utgarde_keep : public InstanceMapScript
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadDoorData(doorData);
|
||||
LoadMinionData(minionData);
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
@@ -59,11 +51,9 @@ class instance_utgarde_keep : public InstanceMapScript
|
||||
break;
|
||||
case NPC_SKARVALD:
|
||||
SkarvaldGUID = creature->GetGUID();
|
||||
AddMinion(creature, true);
|
||||
break;
|
||||
case NPC_DALRONN:
|
||||
DalronnGUID = creature->GetGUID();
|
||||
AddMinion(creature, true);
|
||||
break;
|
||||
case NPC_INGVAR:
|
||||
IngvarGUID = creature->GetGUID();
|
||||
@@ -73,19 +63,6 @@ class instance_utgarde_keep : public InstanceMapScript
|
||||
}
|
||||
}
|
||||
|
||||
void OnCreatureRemove(Creature* creature) override
|
||||
{
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_SKARVALD:
|
||||
case NPC_DALRONN:
|
||||
AddMinion(creature, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
|
||||
@@ -46,16 +46,7 @@ enum UKCreatureIds
|
||||
NPC_PRINCE_KELESETH = 23953,
|
||||
NPC_SKARVALD = 24200,
|
||||
NPC_DALRONN = 24201,
|
||||
NPC_INGVAR = 23954,
|
||||
|
||||
// Skarvald - Dalronn
|
||||
NPC_DALRONN_GHOST = 27389,
|
||||
NPC_SKARVALD_GHOST = 27390,
|
||||
|
||||
// Ingvar the Plunderer
|
||||
NPC_INGVAR_UNDEAD = 23980,
|
||||
NPC_THROW_TARGET = 23996,
|
||||
NPC_ANNHYLDE_THE_CALLER = 24068
|
||||
NPC_INGVAR = 23954
|
||||
};
|
||||
|
||||
enum UKGameObjectIds
|
||||
|
||||
Reference in New Issue
Block a user