mirror of
https://github.com/ZhengPeiRu21/mod-individual-progression
synced 2025-11-29 23:44:51 +08:00
Naxx40 Progress
This commit is contained in:
@@ -5,6 +5,8 @@ DELETE FROM `areatrigger_teleport` WHERE `ID` IN (5196, 5197, 5198, 5199);
|
|||||||
UPDATE `creature` SET `spawnMask` = 3 WHERE `spawnMask` = 7 AND `map` = 533;
|
UPDATE `creature` SET `spawnMask` = 3 WHERE `spawnMask` = 7 AND `map` = 533;
|
||||||
UPDATE `gameobject` SET `spawnMask` = 7 WHERE `spawnMask` = 3 AND `map` = 533;
|
UPDATE `gameobject` SET `spawnMask` = 7 WHERE `spawnMask` = 3 AND `map` = 533;
|
||||||
|
|
||||||
|
UPDATE `gameobject` SET `spawnMask` = 3 WHERE `id` IN (202278, 202277); # Orb of Naxxramas does not exist in classic
|
||||||
|
|
||||||
DELETE FROM `dungeon_access_template` WHERE `id`=122;
|
DELETE FROM `dungeon_access_template` WHERE `id`=122;
|
||||||
INSERT INTO `dungeon_access_template` (`id`, `map_id`, `difficulty`, `min_level`, `max_level`, `min_avg_item_level`, `comment`) VALUES (122, 533, 2, 60, 0, 0, 'Naxxramas - 40man');
|
INSERT INTO `dungeon_access_template` (`id`, `map_id`, `difficulty`, `min_level`, `max_level`, `min_avg_item_level`, `comment`) VALUES (122, 533, 2, 60, 0, 0, 'Naxxramas - 40man');
|
||||||
|
|
||||||
@@ -16,6 +18,25 @@ DELETE FROM `creature` WHERE `guid` = 352042;
|
|||||||
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
|
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
|
||||||
(352042, 351097, 0, 0, 329, 0, 0, 1, 1, 0, 3929.06, -3372.12, 119.653, 4.71395, 300, 0, 0, 6986, 0, 0, 0, 0, 0, '', 0);
|
(352042, 351097, 0, 0, 329, 0, 0, 1, 1, 0, 3929.06, -3372.12, 119.653, 4.71395, 300, 0, 0, 6986, 0, 0, 0, 0, 0, '', 0);
|
||||||
|
|
||||||
|
# Four horseman chest
|
||||||
|
DELETE FROM `gameobject_template` WHERE `entry`=361000;
|
||||||
|
INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES
|
||||||
|
(361000, 3, 1387, 'Four Horsemen Chest', '', '', '', 1, 1634, 361000, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, '', '', 1);
|
||||||
|
|
||||||
|
REPLACE INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `GroupId`, `MinCount`, `MaxCount`) VALUES
|
||||||
|
(314800, 22349, 0, 0.0, 0, 1, 1, 1),
|
||||||
|
(314800, 22350, 0, 0.0, 0, 1, 1, 1),
|
||||||
|
(314800, 22351, 0, 0.0, 0, 1, 1, 1);
|
||||||
|
REPLACE INTO `gameobject_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `GroupId`, `MinCount`, `MaxCount`) VALUES
|
||||||
|
(361000, 314800, 314800, 100, 0, 0, 2, 2),
|
||||||
|
(361000, 22691, 0, 0, 0, 2, 1, 1),
|
||||||
|
(361000, 22726, 0, 30, 0, 0, 1, 1),
|
||||||
|
(361000, 22809, 0, 0, 0, 2, 1, 1),
|
||||||
|
(361000, 22811, 0, 0, 0, 2, 1, 1),
|
||||||
|
(361000, 23025, 0, 0, 0, 2, 1, 1),
|
||||||
|
(361000, 23027, 0, 0, 0, 2, 1, 1),
|
||||||
|
(361000, 23071, 0, 0, 0, 2, 1, 1);
|
||||||
|
|
||||||
DELETE FROM gameobject WHERE guid BETWEEN 351000 AND 351139;
|
DELETE FROM gameobject WHERE guid BETWEEN 351000 AND 351139;
|
||||||
SET @GUID := 351000;
|
SET @GUID := 351000;
|
||||||
INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES
|
INSERT INTO `gameobject` (`guid`, `id`, `map`, `spawnMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`) VALUES
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -137,66 +137,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class npc_naxx40_area_trigger : public CreatureScript
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
static bool isAttuned(Player* player)
|
|
||||||
{
|
|
||||||
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_1) == QUEST_STATUS_REWARDED)
|
|
||||||
return true;
|
|
||||||
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_2) == QUEST_STATUS_REWARDED)
|
|
||||||
return true;
|
|
||||||
if (player->GetQuestStatus(NAXX40_ATTUNEMENT_3) == QUEST_STATUS_REWARDED)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
npc_naxx40_area_trigger() : CreatureScript("npc_naxx40_area_trigger") {}
|
|
||||||
|
|
||||||
struct npc_naxx40_area_triggerAI: public ScriptedAI
|
|
||||||
{
|
|
||||||
npc_naxx40_area_triggerAI(Creature* creature) : ScriptedAI(creature)
|
|
||||||
{
|
|
||||||
me->SetDisplayId(11686); // Invisible
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveInLineOfSight(Unit* who) override
|
|
||||||
{
|
|
||||||
if (who && me->GetDistance2d(who) < 5.0f)
|
|
||||||
{
|
|
||||||
if (Player* player = who->ToPlayer())
|
|
||||||
{
|
|
||||||
if (isAttuned(player))
|
|
||||||
{
|
|
||||||
player->SetRaidDifficulty(RAID_DIFFICULTY_10MAN_HEROIC);
|
|
||||||
player->TeleportTo(533, 3005.68f, -3447.77f, 293.93f, 4.65f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else if (who && me->GetDistance2d(who) < 20.0f)
|
|
||||||
{
|
|
||||||
if (Player* player = who->ToPlayer())
|
|
||||||
{
|
|
||||||
if (isAttuned(player))
|
|
||||||
{
|
|
||||||
GameObject* door = me->FindNearestGameObject(NAXX_STRATH_GATE, 100.0f);
|
|
||||||
if (door)
|
|
||||||
{
|
|
||||||
door->SetGoState(GO_STATE_ACTIVE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CreatureAI* GetAI(Creature* creature) const override
|
|
||||||
{
|
|
||||||
return new npc_naxx40_area_triggerAI(creature);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class IndividualPlayerProgression_WorldScript : public WorldScript
|
class IndividualPlayerProgression_WorldScript : public WorldScript
|
||||||
{
|
{
|
||||||
@@ -658,13 +598,8 @@ public:
|
|||||||
// NOTE: Because NAXX40 is not currently implemented, defeating C'Thun ends Vanilla content
|
// NOTE: Because NAXX40 is not currently implemented, defeating C'Thun ends Vanilla content
|
||||||
UpdateProgressionState(killer, PROGRESSION_NAXX40);
|
UpdateProgressionState(killer, PROGRESSION_NAXX40);
|
||||||
break;
|
break;
|
||||||
case KELTHUZAD:
|
case KELTHUZAD_40:
|
||||||
if (killed->getLevel() == 80) {
|
UpdateProgressionState(killer, PROGRESSION_NAXX40);
|
||||||
UpdateProgressionState(killer, PROGRESSION_WOTLK_TIER_1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
UpdateProgressionState(killer, PROGRESSION_NAXX40);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case MALCHEZAAR:
|
case MALCHEZAAR:
|
||||||
UpdateProgressionState(killer, PROGRESSION_TBC_TIER_1);
|
UpdateProgressionState(killer, PROGRESSION_TBC_TIER_1);
|
||||||
@@ -681,6 +616,9 @@ public:
|
|||||||
case KILJAEDEN:
|
case KILJAEDEN:
|
||||||
UpdateProgressionState(killer, PROGRESSION_TBC_TIER_5);
|
UpdateProgressionState(killer, PROGRESSION_TBC_TIER_5);
|
||||||
break;
|
break;
|
||||||
|
case KELTHUZAD:
|
||||||
|
UpdateProgressionState(killer, PROGRESSION_WOTLK_TIER_1);
|
||||||
|
break;
|
||||||
case YOGGSARON:
|
case YOGGSARON:
|
||||||
UpdateProgressionState(killer, PROGRESSION_WOTLK_TIER_2);
|
UpdateProgressionState(killer, PROGRESSION_WOTLK_TIER_2);
|
||||||
break;
|
break;
|
||||||
@@ -695,18 +633,6 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Used in Naxx40, waiting for this AC PR to merge before can be used: https://github.com/azerothcore/azerothcore-wotlk/pull/12860
|
|
||||||
//
|
|
||||||
// void OnBeforeChooseGraveyard(Player* player, TeamId /*teamId*/, bool /*nearCorpse*/, uint32& graveyardOverride) override
|
|
||||||
// {
|
|
||||||
// if (player->GetMapId() == MAP_NAXX && player->GetMap()->GetSpawnMode() == RAID_DIFFICULTY_10MAN_HEROIC)
|
|
||||||
// {
|
|
||||||
// graveyardOverride = NAXX40_GRAVEYARD;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add all scripts in one
|
// Add all scripts in one
|
||||||
@@ -718,7 +644,6 @@ void AddSC_mod_individual_progression()
|
|||||||
new npc_ipp_aq();
|
new npc_ipp_aq();
|
||||||
new npc_ipp_tbc();
|
new npc_ipp_tbc();
|
||||||
new npc_ipp_wotlk();
|
new npc_ipp_wotlk();
|
||||||
new npc_naxx40_area_trigger();
|
|
||||||
new gobject_ipp_tbc();
|
new gobject_ipp_tbc();
|
||||||
new gobject_ipp_wotlk();
|
new gobject_ipp_wotlk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ enum ProgressionBossIDs
|
|||||||
NEFARIAN = 11583,
|
NEFARIAN = 11583,
|
||||||
CTHUN = 15727,
|
CTHUN = 15727,
|
||||||
KELTHUZAD = 15990,
|
KELTHUZAD = 15990,
|
||||||
|
KELTHUZAD_40 = 351019,
|
||||||
MALCHEZAAR = 15690,
|
MALCHEZAAR = 15690,
|
||||||
KAELTHAS = 19622,
|
KAELTHAS = 19622,
|
||||||
ILLIDAN = 22917,
|
ILLIDAN = 22917,
|
||||||
@@ -48,15 +49,7 @@ enum BuffSpells
|
|||||||
|
|
||||||
enum ProgressionQuestIDs
|
enum ProgressionQuestIDs
|
||||||
{
|
{
|
||||||
MIGHT_OF_KALIMDOR = 8742,
|
MIGHT_OF_KALIMDOR = 8742
|
||||||
NAXX40_ATTUNEMENT_1 = 9121,
|
|
||||||
NAXX40_ATTUNEMENT_2 = 9122,
|
|
||||||
NAXX40_ATTUNEMENT_3 = 9123,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum NaxxGraveyards
|
|
||||||
{
|
|
||||||
NAXX40_GRAVEYARD = 1449
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ProgressionMaps
|
enum ProgressionMaps
|
||||||
@@ -65,7 +58,6 @@ enum ProgressionMaps
|
|||||||
MAP_AQ_20 = 509,
|
MAP_AQ_20 = 509,
|
||||||
MAP_AQ_40 = 531,
|
MAP_AQ_40 = 531,
|
||||||
MAP_OUTLANDS = 530,
|
MAP_OUTLANDS = 530,
|
||||||
MAP_NAXX = 533,
|
|
||||||
MAP_ZUL_AMAN = 568,
|
MAP_ZUL_AMAN = 568,
|
||||||
MAP_NORTHREND = 571,
|
MAP_NORTHREND = 571,
|
||||||
MAP_ULDUAR = 603,
|
MAP_ULDUAR = 603,
|
||||||
@@ -113,9 +105,5 @@ enum ProgressionState : uint8
|
|||||||
PROGRESSION_WOTLK_TIER_5 = 16 // Ruby Sanctum
|
PROGRESSION_WOTLK_TIER_5 = 16 // Ruby Sanctum
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ProgressionObjects
|
|
||||||
{
|
|
||||||
NAXX_STRATH_GATE = 176424
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //AZEROTHCORE_INDIVIDUALPROGRESSION_H
|
#endif //AZEROTHCORE_INDIVIDUALPROGRESSION_H
|
||||||
|
|||||||
@@ -13,6 +13,22 @@ void AddSC_quest_the_masquerade_60_2();
|
|||||||
void AddSC_boss_lord_kazzak_60_2();
|
void AddSC_boss_lord_kazzak_60_2();
|
||||||
void AddSC_boss_chromaggus_60_2_A();
|
void AddSC_boss_chromaggus_60_2_A();
|
||||||
void AddSC_boss_drakkisath_50_59_B();
|
void AddSC_boss_drakkisath_50_59_B();
|
||||||
|
void AddSC_instance_naxxramas_combined();
|
||||||
|
void AddSC_boss_anubrekhan_40();
|
||||||
|
void AddSC_boss_faerlina_40();
|
||||||
|
void AddSC_boss_four_horsemen_40();
|
||||||
|
void AddSC_boss_gluth_40();
|
||||||
|
void AddSC_boss_gothik_40();
|
||||||
|
void AddSC_boss_grobbulus_40();
|
||||||
|
void AddSC_boss_heigan_40();
|
||||||
|
void AddSC_boss_kelthuzad_40();
|
||||||
|
void AddSC_boss_loatheb_40();
|
||||||
|
void AddSC_boss_maexxna_40();
|
||||||
|
void AddSC_boss_noth_40();
|
||||||
|
void AddSC_boss_patchwerk_40();
|
||||||
|
void AddSC_boss_razuvious_40();
|
||||||
|
void AddSC_boss_sapphiron_40();
|
||||||
|
void AddSC_boss_thaddius_40();
|
||||||
|
|
||||||
|
|
||||||
void Addmod_individual_progressionScripts()
|
void Addmod_individual_progressionScripts()
|
||||||
@@ -27,5 +43,21 @@ void Addmod_individual_progressionScripts()
|
|||||||
AddSC_boss_lord_kazzak_60_2();
|
AddSC_boss_lord_kazzak_60_2();
|
||||||
AddSC_boss_chromaggus_60_2_A();
|
AddSC_boss_chromaggus_60_2_A();
|
||||||
AddSC_boss_drakkisath_50_59_B();
|
AddSC_boss_drakkisath_50_59_B();
|
||||||
|
AddSC_instance_naxxramas_combined();
|
||||||
|
AddSC_boss_anubrekhan_40();
|
||||||
|
AddSC_boss_faerlina_40();
|
||||||
|
AddSC_boss_four_horsemen_40();
|
||||||
|
AddSC_boss_gluth_40();
|
||||||
|
AddSC_boss_gothik_40();
|
||||||
|
AddSC_boss_grobbulus_40();
|
||||||
|
AddSC_boss_heigan_40();
|
||||||
|
AddSC_boss_kelthuzad_40();
|
||||||
|
AddSC_boss_loatheb_40();
|
||||||
|
AddSC_boss_maexxna_40();
|
||||||
|
AddSC_boss_noth_40();
|
||||||
|
AddSC_boss_patchwerk_40();
|
||||||
|
AddSC_boss_razuvious_40();
|
||||||
|
AddSC_boss_sapphiron_40();
|
||||||
|
AddSC_boss_thaddius_40();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
247
src/naxx40Scripts/boss_anubrekhan_40.cpp
Normal file
247
src/naxx40Scripts/boss_anubrekhan_40.cpp
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Says
|
||||||
|
{
|
||||||
|
SAY_AGGRO = 0,
|
||||||
|
SAY_GREET = 1,
|
||||||
|
SAY_SLAY = 2,
|
||||||
|
EMOTE_LOCUST = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum GuardSays
|
||||||
|
{
|
||||||
|
EMOTE_SPAWN = 1,
|
||||||
|
EMOTE_SCARAB = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_IMPALE_10 = 28783,
|
||||||
|
SPELL_LOCUST_SWARM_10 = 28785,
|
||||||
|
SPELL_SUMMON_CORPSE_SCRABS_5 = 29105,
|
||||||
|
SPELL_SUMMON_CORPSE_SCRABS_10 = 28864,
|
||||||
|
SPELL_BERSERK = 26662
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_IMPALE = 1,
|
||||||
|
EVENT_LOCUST_SWARM = 2,
|
||||||
|
EVENT_BERSERK = 3,
|
||||||
|
EVENT_SPAWN_GUARD = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_CORPSE_SCARAB = 351083,
|
||||||
|
NPC_CRYPT_GUARD = 351082,
|
||||||
|
|
||||||
|
ACHIEV_TIMED_START_EVENT = 9891
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_anubrekhan_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_anubrekhan_40() : CreatureScript("boss_anubrekhan_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_anubrekhan_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_anubrekhan_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_anubrekhan_40AI(Creature* c) : BossAI(c, BOSS_ANUB), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = c->GetInstanceScript();
|
||||||
|
sayGreet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
bool sayGreet;
|
||||||
|
|
||||||
|
void SummonCryptGuards()
|
||||||
|
{
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_CRYPT_GUARD, 3299.732f, -3502.489f, 287.077f, 2.378f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
|
||||||
|
me->SummonCreature(NPC_CRYPT_GUARD, 3299.086f, -3450.929f, 287.077f, 3.999f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
SummonCryptGuards();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_ANUB_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
if (me->IsInCombat())
|
||||||
|
{
|
||||||
|
cr->SetInCombatWithZone();
|
||||||
|
if (cr->GetEntry() == NPC_CRYPT_GUARD)
|
||||||
|
{
|
||||||
|
cr->AI()->Talk(EMOTE_SPAWN, me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonedCreatureDies(Creature* cr, Unit*) override
|
||||||
|
{
|
||||||
|
if (cr->GetEntry() == NPC_CRYPT_GUARD)
|
||||||
|
{
|
||||||
|
cr->CastSpell(cr, SPELL_SUMMON_CORPSE_SCRABS_10, true, nullptr, nullptr, me->GetGUID());
|
||||||
|
cr->AI()->Talk(EMOTE_SCARAB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonedCreatureDespawn(Creature* cr) override
|
||||||
|
{
|
||||||
|
summons.Despawn(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
summons.DespawnAll();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* victim) override
|
||||||
|
{
|
||||||
|
if (victim->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, nullptr, nullptr, me->GetGUID());
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->CallForHelp(30.0f);
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_ANUB_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.ScheduleEvent(EVENT_IMPALE, 15000);
|
||||||
|
events.ScheduleEvent(EVENT_LOCUST_SWARM, urand(70000, 120000));
|
||||||
|
events.ScheduleEvent(EVENT_BERSERK, 600000);
|
||||||
|
if (!summons.HasEntry(NPC_CRYPT_GUARD))
|
||||||
|
{
|
||||||
|
SummonCryptGuards();
|
||||||
|
}
|
||||||
|
if (!Is25ManRaid())
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_SPAWN_GUARD, urand(15000, 20000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveInLineOfSight(Unit* who) override
|
||||||
|
{
|
||||||
|
if (!sayGreet && who->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
Talk(SAY_GREET);
|
||||||
|
sayGreet = true;
|
||||||
|
}
|
||||||
|
ScriptedAI::MoveInLineOfSight(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!me->IsInCombat() && sayGreet)
|
||||||
|
{
|
||||||
|
for (SummonList::iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (Creature* cr = pInstance->instance->GetCreature(*itr))
|
||||||
|
{
|
||||||
|
if (cr->IsInCombat())
|
||||||
|
DoZoneInCombat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_IMPALE:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_IMPALE_10, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(20000);
|
||||||
|
break;
|
||||||
|
case EVENT_LOCUST_SWARM:
|
||||||
|
Talk(EMOTE_LOCUST);
|
||||||
|
me->CastSpell(me, SPELL_LOCUST_SWARM_10, false);
|
||||||
|
events.ScheduleEvent(EVENT_SPAWN_GUARD, 3000);
|
||||||
|
events.RepeatEvent(90000);
|
||||||
|
break;
|
||||||
|
case EVENT_SPAWN_GUARD:
|
||||||
|
me->SummonCreature(NPC_CRYPT_GUARD, 3331.217f, -3476.607f, 287.074f, 3.269f, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 60000);
|
||||||
|
break;
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_anubrekhan_40()
|
||||||
|
{
|
||||||
|
new boss_anubrekhan_40();
|
||||||
|
}
|
||||||
248
src/naxx40Scripts/boss_faerlina_40.cpp
Normal file
248
src/naxx40Scripts/boss_faerlina_40.cpp
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellInfo.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Yells
|
||||||
|
{
|
||||||
|
SAY_GREET = 0,
|
||||||
|
SAY_AGGRO = 1,
|
||||||
|
SAY_SLAY = 2,
|
||||||
|
SAY_DEATH = 3,
|
||||||
|
EMOTE_WIDOWS_EMBRACE = 4,
|
||||||
|
EMOTE_FRENZY = 5,
|
||||||
|
SAY_FRENZY = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_POISON_BOLT_VOLLEY_10 = 28796,
|
||||||
|
SPELL_RAIN_OF_FIRE_10 = 28794,
|
||||||
|
SPELL_FRENZY_10 = 28798,
|
||||||
|
SPELL_WIDOWS_EMBRACE = 28732
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_POISON_BOLT = 1,
|
||||||
|
EVENT_RAIN_OF_FIRE = 2,
|
||||||
|
EVENT_FRENZY = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_NAXXRAMAS_WORSHIPPER = 351081,
|
||||||
|
NPC_NAXXRAMAS_FOLLOWER = 351080
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_faerlina_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_faerlina_40() : CreatureScript("boss_faerlina_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_faerlina_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_faerlina_40AI : public BossAI
|
||||||
|
{
|
||||||
|
boss_faerlina_40AI(Creature* c) : BossAI(c, BOSS_FAERLINA), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
sayGreet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
bool sayGreet;
|
||||||
|
|
||||||
|
void SummonHelpers()
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3362.66f, -3620.97f, 261.08f, 4.57276f);
|
||||||
|
me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3344.3f, -3618.31f, 261.08f, 4.69494f);
|
||||||
|
me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3356.71f, -3620.05f, 261.08f, 4.57276f);
|
||||||
|
me->SummonCreature(NPC_NAXXRAMAS_WORSHIPPER, 3350.26f, -3619.11f, 261.08f, 4.67748f);
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_NAXXRAMAS_FOLLOWER, 3347.49f, -3617.59f, 261.0f, 4.49f);
|
||||||
|
me->SummonCreature(NPC_NAXXRAMAS_FOLLOWER, 3359.64f, -3619.16f, 261.0f, 4.56f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
SummonHelpers();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_FAERLINA_WEB)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->CallForHelp(VISIBLE_RANGE);
|
||||||
|
summons.DoZoneInCombat();
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
events.ScheduleEvent(EVENT_POISON_BOLT, urand(7000, 12000));
|
||||||
|
events.ScheduleEvent(EVENT_RAIN_OF_FIRE, urand(8000, 12000));
|
||||||
|
events.ScheduleEvent(EVENT_FRENZY, urand(60000, 80000), 1);
|
||||||
|
events.SetPhase(1);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_FAERLINA_WEB)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveInLineOfSight(Unit* who) override
|
||||||
|
{
|
||||||
|
if (!sayGreet && who->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
Talk(SAY_GREET);
|
||||||
|
sayGreet = true;
|
||||||
|
}
|
||||||
|
ScriptedAI::MoveInLineOfSight(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!urand(0, 3))
|
||||||
|
{
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
}
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_FAERLINA_WEB)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!me->IsInCombat() && sayGreet)
|
||||||
|
{
|
||||||
|
for (SummonList::iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (Creature* cr = pInstance->instance->GetCreature(*itr))
|
||||||
|
{
|
||||||
|
if (cr->IsInCombat())
|
||||||
|
DoZoneInCombat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_POISON_BOLT:
|
||||||
|
if (!me->HasAura(SPELL_WIDOWS_EMBRACE))
|
||||||
|
{
|
||||||
|
me->CastCustomSpell(SPELL_POISON_BOLT_VOLLEY_10, SPELLVALUE_MAX_TARGETS, 10, me, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(urand(7000, 12000));
|
||||||
|
break;
|
||||||
|
case EVENT_RAIN_OF_FIRE:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_RAIN_OF_FIRE_10, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(urand(8000, 12000));
|
||||||
|
break;
|
||||||
|
case EVENT_FRENZY:
|
||||||
|
if (!me->HasAura(SPELL_FRENZY_10))
|
||||||
|
{
|
||||||
|
Talk(SAY_FRENZY);
|
||||||
|
Talk(EMOTE_FRENZY);
|
||||||
|
me->CastSpell(me, SPELL_FRENZY_10, true);
|
||||||
|
events.RepeatEvent(60000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||||
|
{
|
||||||
|
if (spell->Id == SPELL_WIDOWS_EMBRACE)
|
||||||
|
{
|
||||||
|
Talk(EMOTE_WIDOWS_EMBRACE);
|
||||||
|
if (me->HasAura(SPELL_FRENZY_10))
|
||||||
|
{
|
||||||
|
me->RemoveAurasDueToSpell(SPELL_FRENZY_10);
|
||||||
|
events.RescheduleEvent(EVENT_FRENZY, 60000);
|
||||||
|
}
|
||||||
|
pInstance->SetData(DATA_FRENZY_REMOVED, 0);
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
Unit::Kill(caster, caster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_faerlina_40()
|
||||||
|
{
|
||||||
|
new boss_faerlina_40();
|
||||||
|
}
|
||||||
458
src/naxx40Scripts/boss_four_horsemen_40.cpp
Normal file
458
src/naxx40Scripts/boss_four_horsemen_40.cpp
Normal file
@@ -0,0 +1,458 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellAuraEffects.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_BERSERK = 26662,
|
||||||
|
// Marks
|
||||||
|
SPELL_MARK_OF_KORTHAZZ = 28832,
|
||||||
|
SPELL_MARK_OF_BLAUMEUX = 28833,
|
||||||
|
SPELL_MARK_OF_MOGRAINE = 28834, // TODO: Requires Spell DBC Edit
|
||||||
|
SPELL_MARK_OF_ZELIEK = 28835,
|
||||||
|
SPELL_MARK_DAMAGE = 28836,
|
||||||
|
// Korth'azz
|
||||||
|
SPELL_KORTHAZZ_METEOR_10 = 28884,
|
||||||
|
SPELL_KORTHAZZ_METEOR_25 = 57467,
|
||||||
|
// Blaumeux
|
||||||
|
SPELL_BLAUMEUX_SHADOW_BOLT_10 = 57374,
|
||||||
|
SPELL_BLAUMEUX_SHADOW_BOLT_25 = 57464,
|
||||||
|
SPELL_BLAUMEUX_VOID_ZONE_10 = 28863,
|
||||||
|
SPELL_BLAUMEUX_VOID_ZONE_25 = 57463,
|
||||||
|
SPELL_BLAUMEUX_UNYIELDING_PAIN = 57381,
|
||||||
|
// Zeliek
|
||||||
|
SPELL_ZELIEK_HOLY_WRATH_10 = 28883,
|
||||||
|
SPELL_ZELIEK_HOLY_WRATH_25 = 57466,
|
||||||
|
SPELL_ZELIEK_HOLY_BOLT_10 = 57376,
|
||||||
|
SPELL_ZELIEK_HOLY_BOLT_25 = 57465,
|
||||||
|
SPELL_ZELIEK_CONDEMNATION = 57377,
|
||||||
|
// Mograine
|
||||||
|
SPELL_RIVENDARE_UNHOLY_SHADOW_10 = 28882,
|
||||||
|
SPELL_RIVENDARE_UNHOLY_SHADOW_25 = 57369
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_MARK_CAST = 1,
|
||||||
|
EVENT_PRIMARY_SPELL = 2,
|
||||||
|
EVENT_SECONDARY_SPELL = 3,
|
||||||
|
EVENT_PUNISH = 4,
|
||||||
|
EVENT_BERSERK = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
// Movement
|
||||||
|
MOVE_PHASE_NONE = 0,
|
||||||
|
MOVE_PHASE_STARTED = 1,
|
||||||
|
MOVE_PHASE_FINISHED = 2,
|
||||||
|
// Horseman
|
||||||
|
HORSEMAN_ZELIEK = 0,
|
||||||
|
HORSEMAN_BLAUMEUX = 1,
|
||||||
|
HORSEMAN_MOGRAINE = 2,
|
||||||
|
HORSEMAN_KORTHAZZ = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FourHorsemen
|
||||||
|
{
|
||||||
|
SAY_AGGRO = 0,
|
||||||
|
SAY_TAUNT = 1,
|
||||||
|
SAY_SPECIAL = 2,
|
||||||
|
SAY_SLAY = 3,
|
||||||
|
SAY_DEATH = 4,
|
||||||
|
EMOTE_RAGECAST = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
// MARKS
|
||||||
|
const uint32 TABLE_SPELL_MARK[4] = {SPELL_MARK_OF_ZELIEK, SPELL_MARK_OF_BLAUMEUX, SPELL_MARK_OF_MOGRAINE, SPELL_MARK_OF_KORTHAZZ};
|
||||||
|
|
||||||
|
// PRIMARY SPELL
|
||||||
|
const uint32 TABLE_SPELL_PRIMARY_10[4] = {SPELL_ZELIEK_HOLY_BOLT_10, SPELL_BLAUMEUX_SHADOW_BOLT_10, SPELL_RIVENDARE_UNHOLY_SHADOW_10, SPELL_KORTHAZZ_METEOR_10};
|
||||||
|
const uint32 TABLE_SPELL_PRIMARY_25[4] = {SPELL_ZELIEK_HOLY_BOLT_25, SPELL_BLAUMEUX_SHADOW_BOLT_25, SPELL_RIVENDARE_UNHOLY_SHADOW_25, SPELL_KORTHAZZ_METEOR_25};
|
||||||
|
|
||||||
|
// PUNISH
|
||||||
|
const uint32 TABLE_SPELL_PUNISH[4] = {SPELL_ZELIEK_CONDEMNATION, SPELL_BLAUMEUX_UNYIELDING_PAIN, 0, 0};
|
||||||
|
|
||||||
|
// SECONDARY SPELL
|
||||||
|
const uint32 TABLE_SPELL_SECONDARY_10[4] = {SPELL_ZELIEK_HOLY_WRATH_10, SPELL_BLAUMEUX_VOID_ZONE_10, 0, 0};
|
||||||
|
const uint32 TABLE_SPELL_SECONDARY_25[4] = {SPELL_ZELIEK_HOLY_WRATH_25, SPELL_BLAUMEUX_VOID_ZONE_25, 0, 0};
|
||||||
|
|
||||||
|
const Position WaypointPositions[12] =
|
||||||
|
{
|
||||||
|
// Thane waypoints
|
||||||
|
{2542.3f, -2984.1f, 241.49f, 5.362f},
|
||||||
|
{2547.6f, -2999.4f, 241.34f, 5.049f},
|
||||||
|
{2542.9f, -3015.0f, 241.35f, 4.654f},
|
||||||
|
// Lady waypoints
|
||||||
|
{2498.3f, -2961.8f, 241.28f, 3.267f},
|
||||||
|
{2487.7f, -2959.2f, 241.28f, 2.890f},
|
||||||
|
{2469.4f, -2947.6f, 241.28f, 2.576f},
|
||||||
|
// Mograine waypoints
|
||||||
|
{2553.8f, -2968.4f, 241.33f, 5.757f},
|
||||||
|
{2564.3f, -2972.5f, 241.33f, 5.890f},
|
||||||
|
{2583.9f, -2971.6f, 241.35f, 0.008f},
|
||||||
|
// Sir waypoints
|
||||||
|
{2534.5f, -2921.7f, 241.53f, 1.363f},
|
||||||
|
{2523.5f, -2902.8f, 241.28f, 2.095f},
|
||||||
|
{2517.8f, -2896.6f, 241.28f, 2.315f}
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_four_horsemen_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_four_horsemen_40() : CreatureScript("boss_four_horsemen_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_four_horsemen_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_four_horsemen_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_four_horsemen_40AI(Creature* c) : BossAI(c, BOSS_HORSEMAN)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
switch (me->GetEntry())
|
||||||
|
{
|
||||||
|
case NPC_SIR_ZELIEK_40:
|
||||||
|
horsemanId = HORSEMAN_ZELIEK;
|
||||||
|
break;
|
||||||
|
case NPC_LADY_BLAUMEUX_40:
|
||||||
|
horsemanId = HORSEMAN_BLAUMEUX;
|
||||||
|
break;
|
||||||
|
case NPC_HIGHLORD_MOGRAINE_40:
|
||||||
|
horsemanId = HORSEMAN_MOGRAINE;
|
||||||
|
break;
|
||||||
|
case NPC_THANE_KORTHAZZ_40:
|
||||||
|
horsemanId = HORSEMAN_KORTHAZZ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
uint8 currentWaypoint{};
|
||||||
|
uint8 movementPhase{};
|
||||||
|
uint8 horsemanId;
|
||||||
|
|
||||||
|
void MoveToCorner()
|
||||||
|
{
|
||||||
|
switch(me->GetEntry())
|
||||||
|
{
|
||||||
|
case NPC_THANE_KORTHAZZ_40:
|
||||||
|
currentWaypoint = 0;
|
||||||
|
break;
|
||||||
|
case NPC_LADY_BLAUMEUX_40:
|
||||||
|
currentWaypoint = 3;
|
||||||
|
break;
|
||||||
|
case NPC_HIGHLORD_MOGRAINE_40:
|
||||||
|
currentWaypoint = 6;
|
||||||
|
break;
|
||||||
|
case NPC_SIR_ZELIEK_40:
|
||||||
|
currentWaypoint = 9;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInRoom()
|
||||||
|
{
|
||||||
|
if (me->GetExactDist(2535.1f, -2968.7f, 241.3f) > 100.0f)
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
me->SetPosition(me->GetHomePosition());
|
||||||
|
movementPhase = MOVE_PHASE_NONE;
|
||||||
|
currentWaypoint = 0;
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
events.Reset();
|
||||||
|
events.RescheduleEvent(EVENT_MARK_CAST, 24000);
|
||||||
|
events.RescheduleEvent(EVENT_BERSERK, 600000);
|
||||||
|
if ((me->GetEntry() != NPC_LADY_BLAUMEUX_40 && me->GetEntry() != NPC_SIR_ZELIEK_40))
|
||||||
|
{
|
||||||
|
events.RescheduleEvent(EVENT_PRIMARY_SPELL, 10000 + rand() % 5000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.RescheduleEvent(EVENT_PUNISH, 5000);
|
||||||
|
events.RescheduleEvent(EVENT_SECONDARY_SPELL, 15000);
|
||||||
|
}
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE)))
|
||||||
|
{
|
||||||
|
if (pInstance->GetBossState(BOSS_GOTHIK) == DONE)
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MovementInform(uint32 type, uint32 id) override
|
||||||
|
{
|
||||||
|
if (type != POINT_MOTION_TYPE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// final waypoint
|
||||||
|
if (id % 3 == 2)
|
||||||
|
{
|
||||||
|
movementPhase = MOVE_PHASE_FINISHED;
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
if (!UpdateVictim())
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40)
|
||||||
|
{
|
||||||
|
me->GetMotionMaster()->Clear(false);
|
||||||
|
me->GetMotionMaster()->MoveIdle();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentWaypoint = id + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttackStart(Unit* who) override
|
||||||
|
{
|
||||||
|
if (movementPhase == MOVE_PHASE_FINISHED)
|
||||||
|
{
|
||||||
|
if (me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40)
|
||||||
|
{
|
||||||
|
me->Attack(who, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptedAI::AttackStart(who);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (pInstance->GetBossState(BOSS_HORSEMAN) == DONE)
|
||||||
|
{
|
||||||
|
if (!me->GetMap()->GetPlayers().IsEmpty())
|
||||||
|
{
|
||||||
|
if (Player* player = me->GetMap()->GetPlayers().getFirst()->GetSource())
|
||||||
|
{
|
||||||
|
if (GameObject* chest = player->SummonGameObject(GO_HORSEMEN_CHEST_40, 2514.8f, -2944.9f, 245.55f, 5.51f, 0, 0, 0, 0, 0))
|
||||||
|
{
|
||||||
|
chest->SetLootRecipient(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
if (movementPhase == MOVE_PHASE_NONE)
|
||||||
|
{
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
movementPhase = MOVE_PHASE_STARTED;
|
||||||
|
me->SetSpeed(MOVE_RUN, me->GetSpeedRate(MOVE_RUN), true);
|
||||||
|
MoveToCorner();
|
||||||
|
}
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HORSEMEN_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (movementPhase == MOVE_PHASE_STARTED && currentWaypoint)
|
||||||
|
{
|
||||||
|
me->GetMotionMaster()->MovePoint(currentWaypoint, WaypointPositions[currentWaypoint]);
|
||||||
|
currentWaypoint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (movementPhase < MOVE_PHASE_FINISHED || !UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_MARK_CAST:
|
||||||
|
me->CastSpell(me, TABLE_SPELL_MARK[horsemanId], false);
|
||||||
|
events.RepeatEvent((me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40) ? 15000 : 12000);
|
||||||
|
return;
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
Talk(SAY_SPECIAL);
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
return;
|
||||||
|
case EVENT_PRIMARY_SPELL:
|
||||||
|
Talk(SAY_TAUNT);
|
||||||
|
me->CastSpell(me->GetVictim(), RAID_MODE(TABLE_SPELL_PRIMARY_10[horsemanId], TABLE_SPELL_PRIMARY_25[horsemanId]), false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
return;
|
||||||
|
case EVENT_PUNISH:
|
||||||
|
if (!SelectTarget(SelectTargetMethod::MaxDistance, 0, 45.0f, true))
|
||||||
|
{
|
||||||
|
me->CastSpell(me, TABLE_SPELL_PUNISH[horsemanId], false);
|
||||||
|
Talk(EMOTE_RAGECAST);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(2010);
|
||||||
|
return;
|
||||||
|
case EVENT_SECONDARY_SPELL:
|
||||||
|
me->CastSpell(me->GetVictim(), RAID_MODE(TABLE_SPELL_SECONDARY_10[horsemanId], TABLE_SPELL_SECONDARY_25[horsemanId]), false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((me->GetEntry() == NPC_LADY_BLAUMEUX_40 || me->GetEntry() == NPC_SIR_ZELIEK_40))
|
||||||
|
{
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::MaxDistance, 0, 45.0f, true))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, RAID_MODE(TABLE_SPELL_PRIMARY_10[horsemanId], TABLE_SPELL_PRIMARY_25[horsemanId]), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_four_horsemen_mark : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_four_horsemen_mark() : SpellScriptLoader("spell_four_horsemen_mark") { }
|
||||||
|
|
||||||
|
class spell_four_horsemen_mark_AuraScript : public AuraScript
|
||||||
|
{
|
||||||
|
PrepareAuraScript(spell_four_horsemen_mark_AuraScript);
|
||||||
|
|
||||||
|
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||||
|
{
|
||||||
|
if (Unit* caster = GetCaster())
|
||||||
|
{
|
||||||
|
int32 damage;
|
||||||
|
switch (GetStackAmount())
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
damage = 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
damage = 500;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
damage = 1500;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
damage = 4000;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
damage = 12000;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
damage = 20000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
damage = 20000 + 1000 * (GetStackAmount() - 7);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (damage)
|
||||||
|
{
|
||||||
|
caster->CastCustomSpell(SPELL_MARK_DAMAGE, SPELLVALUE_BASE_POINT0, damage, GetTarget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
AfterEffectApply += AuraEffectApplyFn(spell_four_horsemen_mark_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AuraScript* GetAuraScript() const override
|
||||||
|
{
|
||||||
|
return new spell_four_horsemen_mark_AuraScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_four_horsemen_consumption : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_four_horsemen_consumption);
|
||||||
|
|
||||||
|
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
|
||||||
|
{
|
||||||
|
uint32 damage = GetCaster()->GetMap()->ToInstanceMap()->GetDifficulty() == REGULAR_DIFFICULTY ? 2750 : 4250;
|
||||||
|
SetHitDamage(damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnEffectHitTarget += SpellEffectFn(spell_four_horsemen_consumption::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_four_horsemen_40()
|
||||||
|
{
|
||||||
|
new boss_four_horsemen_40();
|
||||||
|
// new spell_four_horsemen_mark();
|
||||||
|
// RegisterSpellScript(spell_four_horsemen_consumption);
|
||||||
|
}
|
||||||
273
src/naxx40Scripts/boss_gluth_40.cpp
Normal file
273
src/naxx40Scripts/boss_gluth_40.cpp
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_MORTAL_WOUND = 25646,
|
||||||
|
SPELL_ENRAGE = 28371,
|
||||||
|
SPELL_DECIMATE = 28374,
|
||||||
|
SPELL_BERSERK = 26662,
|
||||||
|
SPELL_INFECTED_WOUND = 29306,
|
||||||
|
SPELL_CHOW_SEARCHER = 28404
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_MORTAL_WOUND = 1,
|
||||||
|
EVENT_ENRAGE = 2,
|
||||||
|
EVENT_DECIMATE = 3,
|
||||||
|
EVENT_BERSERK = 4,
|
||||||
|
EVENT_SUMMON_ZOMBIE = 5,
|
||||||
|
EVENT_CAN_EAT_ZOMBIE = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_ZOMBIE_CHOW = 351069
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Emotes
|
||||||
|
{
|
||||||
|
EMOTE_SPOTS_ONE = 0,
|
||||||
|
EMOTE_DECIMATE = 1,
|
||||||
|
EMOTE_ENRAGE = 2,
|
||||||
|
EMOTE_DEVOURS_ALL = 3,
|
||||||
|
EMOTE_BERSERK = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position zombiePos[3] =
|
||||||
|
{
|
||||||
|
{3267.9f, -3172.1f, 297.42f, 0.94f},
|
||||||
|
{3253.2f, -3132.3f, 297.42f, 0},
|
||||||
|
{3308.3f, -3185.8f, 297.42f, 1.58f}
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_gluth_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_gluth_40() : CreatureScript("boss_gluth_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_gluth_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_gluth_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_gluth_40AI(Creature* c) : BossAI(c, BOSS_GLUTH), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
me->ApplySpellImmune(SPELL_INFECTED_WOUND, IMMUNITY_ID, SPELL_INFECTED_WOUND, true);
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveInLineOfSight(Unit* who) override
|
||||||
|
{
|
||||||
|
if (!me->GetVictim() || me->GetVictim()->GetEntry() != NPC_ZOMBIE_CHOW)
|
||||||
|
{
|
||||||
|
if (who->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinDistInMap(who, 6.5f))
|
||||||
|
{
|
||||||
|
SetGazeOn(who);
|
||||||
|
Talk(EMOTE_SPOTS_ONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptedAI::MoveInLineOfSight(who);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
events.ScheduleEvent(EVENT_MORTAL_WOUND, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_ENRAGE, 22000);
|
||||||
|
events.ScheduleEvent(EVENT_DECIMATE, 105000);
|
||||||
|
events.ScheduleEvent(EVENT_BERSERK, 360000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_ZOMBIE, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* summon) override
|
||||||
|
{
|
||||||
|
if (summon->GetEntry() == NPC_ZOMBIE_CHOW)
|
||||||
|
{
|
||||||
|
summon->AI()->AttackStart(me);
|
||||||
|
}
|
||||||
|
summons.Summon(summon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonedCreatureDies(Creature* cr, Unit*) override { summons.Despawn(cr); }
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW)
|
||||||
|
{
|
||||||
|
me->ModifyHealth(int32(me->GetMaxHealth() * 0.05f));
|
||||||
|
}
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
summons.DespawnAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectPlayerInRoom()
|
||||||
|
{
|
||||||
|
if (me->IsInCombat())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
|
||||||
|
for (const auto& itr : pList)
|
||||||
|
{
|
||||||
|
Player* player = itr.GetSource();
|
||||||
|
if (!player || !player->IsAlive())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (player->GetPositionZ() > 300.0f || me->GetExactDist(player) > 50.0f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AttackStart(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictimWithGaze() && !SelectPlayerInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
break;
|
||||||
|
case EVENT_ENRAGE:
|
||||||
|
Talk(EMOTE_ENRAGE);
|
||||||
|
me->CastSpell(me, SPELL_ENRAGE, true);
|
||||||
|
events.RepeatEvent(22000);
|
||||||
|
break;
|
||||||
|
case EVENT_MORTAL_WOUND:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
break;
|
||||||
|
case EVENT_DECIMATE:
|
||||||
|
Talk(EMOTE_DECIMATE);
|
||||||
|
me->CastSpell(me, SPELL_DECIMATE, false);
|
||||||
|
events.RepeatEvent(105000);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_ZOMBIE:
|
||||||
|
{
|
||||||
|
uint8 rand = urand(0, 2);
|
||||||
|
for (int32 i = 0; i < 1; ++i)
|
||||||
|
{
|
||||||
|
// In 40 man raid, use all gates
|
||||||
|
me->SummonCreature(NPC_ZOMBIE_CHOW, zombiePos[urand(0, 2)]);
|
||||||
|
(rand == 2 ? rand = 0 : rand++);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_CAN_EAT_ZOMBIE:
|
||||||
|
events.RepeatEvent(1000);
|
||||||
|
if (me->GetVictim()->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinMeleeRange(me->GetVictim()))
|
||||||
|
{
|
||||||
|
me->CastCustomSpell(SPELL_CHOW_SEARCHER, SPELLVALUE_RADIUS_MOD, 20000, me, true);
|
||||||
|
Talk(EMOTE_DEVOURS_ALL);
|
||||||
|
return; // leave it to skip DoMeleeAttackIfReady
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_gluth_decimate : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_gluth_decimate() : SpellScriptLoader("spell_gluth_decimate") { }
|
||||||
|
|
||||||
|
class spell_gluth_decimate_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_gluth_decimate_SpellScript);
|
||||||
|
|
||||||
|
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||||
|
{
|
||||||
|
if (Unit* unitTarget = GetHitUnit())
|
||||||
|
{
|
||||||
|
int32 damage = int32(unitTarget->GetHealth()) - int32(unitTarget->CountPctFromMaxHealth(5));
|
||||||
|
if (damage <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Creature* cTarget = unitTarget->ToCreature())
|
||||||
|
{
|
||||||
|
cTarget->SetWalk(true);
|
||||||
|
cTarget->GetMotionMaster()->MoveFollow(GetCaster(), 0.0f, 0.0f, MOTION_SLOT_CONTROLLED);
|
||||||
|
cTarget->SetReactState(REACT_PASSIVE);
|
||||||
|
Unit::DealDamage(GetCaster(), cTarget, damage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GetCaster()->CastCustomSpell(28375, SPELLVALUE_BASE_POINT0, damage, unitTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_gluth_decimate_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_gluth_40()
|
||||||
|
{
|
||||||
|
new boss_gluth_40();
|
||||||
|
// new spell_gluth_decimate();
|
||||||
|
}
|
||||||
718
src/naxx40Scripts/boss_gothik_40.cpp
Normal file
718
src/naxx40Scripts/boss_gothik_40.cpp
Normal file
@@ -0,0 +1,718 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CombatAI.h"
|
||||||
|
#include "GridNotifiers.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Yells
|
||||||
|
{
|
||||||
|
SAY_INTRO_1 = 0,
|
||||||
|
SAY_INTRO_2 = 1,
|
||||||
|
SAY_INTRO_3 = 2,
|
||||||
|
SAY_INTRO_4 = 3,
|
||||||
|
SAY_PHASE_TWO = 4,
|
||||||
|
SAY_DEATH = 5,
|
||||||
|
SAY_KILL = 6,
|
||||||
|
|
||||||
|
EMOTE_PHASE_TWO = 7,
|
||||||
|
EMOTE_GATE_OPENED = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
// Gothik
|
||||||
|
SPELL_HARVEST_SOUL = 28679,
|
||||||
|
SPELL_SHADOW_BOLT = 29317,
|
||||||
|
// Teleport spells
|
||||||
|
SPELL_TELEPORT_DEAD = 28025,
|
||||||
|
SPELL_TELEPORT_LIVE = 28026,
|
||||||
|
// Visual spells
|
||||||
|
SPELL_INFORM_LIVING_TRAINEE = 27892,
|
||||||
|
SPELL_INFORM_LIVING_KNIGHT = 27928,
|
||||||
|
SPELL_INFORM_LIVING_RIDER = 27935,
|
||||||
|
SPELL_INFORM_DEAD_TRAINEE = 27915,
|
||||||
|
SPELL_INFORM_DEAD_KNIGHT = 27931,
|
||||||
|
SPELL_INFORM_DEAD_RIDER = 27937,
|
||||||
|
/*SPELL_ANCHOR_2_TRAINEE = 27893,
|
||||||
|
SPELL_ANCHOR_2_DK = 27929,
|
||||||
|
SPELL_ANCHOR_2_RIDER = 27936, fix me */
|
||||||
|
// Living trainee
|
||||||
|
SPELL_DEATH_PLAGUE = 55604,
|
||||||
|
// Dead trainee
|
||||||
|
SPELL_ARCANE_EXPLOSION = 27989,
|
||||||
|
// Living knight
|
||||||
|
SPELL_SHADOW_MARK = 27825,
|
||||||
|
// Dead knight
|
||||||
|
SPELL_WHIRLWIND = 56408,
|
||||||
|
// Living rider
|
||||||
|
SPELL_SHADOW_BOLT_VOLLEY = 27831,
|
||||||
|
// Dead rider
|
||||||
|
SPELL_DRAIN_LIFE = 27994,
|
||||||
|
SPELL_UNHOLY_FRENZY = 55648,
|
||||||
|
// Horse
|
||||||
|
SPELL_STOMP = 27993
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_LIVING_TRAINEE = 351043,
|
||||||
|
NPC_LIVING_KNIGHT = 351044,
|
||||||
|
NPC_LIVING_RIDER = 351045,
|
||||||
|
NPC_DEAD_TRAINEE = 351046,
|
||||||
|
NPC_DEAD_KNIGHT = 351050,
|
||||||
|
NPC_DEAD_HORSE = 351051,
|
||||||
|
NPC_DEAD_RIDER = 351052,
|
||||||
|
//NPC_TRIGGER = 16137, fix me
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
// Gothik
|
||||||
|
EVENT_SUMMON_ADDS = 1,
|
||||||
|
EVENT_HARVEST_SOUL = 2,
|
||||||
|
EVENT_SHADOW_BOLT = 3,
|
||||||
|
EVENT_TELEPORT = 4,
|
||||||
|
EVENT_CHECK_HEALTH = 5,
|
||||||
|
EVENT_CHECK_PLAYERS = 6,
|
||||||
|
// Living trainee
|
||||||
|
EVENT_DEATH_PLAGUE = 7,
|
||||||
|
// Dead trainee
|
||||||
|
EVENT_ARCANE_EXPLOSION = 8,
|
||||||
|
// Living knight
|
||||||
|
EVENT_SHADOW_MARK = 9,
|
||||||
|
// Dead knight
|
||||||
|
EVENT_WHIRLWIND = 10,
|
||||||
|
// Living rider
|
||||||
|
EVENT_SHADOW_BOLT_VOLLEY = 11,
|
||||||
|
// Dead rider
|
||||||
|
EVENT_DRAIN_LIFE = 12,
|
||||||
|
EVENT_UNHOLY_FRENZY = 13,
|
||||||
|
// HORSE
|
||||||
|
EVENT_STOMP = 14,
|
||||||
|
// Intro
|
||||||
|
EVENT_INTRO_2 = 15,
|
||||||
|
EVENT_INTRO_3 = 16,
|
||||||
|
EVENT_INTRO_4 = 17
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32 gothikWaves[24][2] =
|
||||||
|
{
|
||||||
|
{NPC_LIVING_TRAINEE, 20000},
|
||||||
|
{NPC_LIVING_TRAINEE, 20000},
|
||||||
|
{NPC_LIVING_TRAINEE, 10000},
|
||||||
|
{NPC_LIVING_KNIGHT, 10000},
|
||||||
|
{NPC_LIVING_TRAINEE, 15000},
|
||||||
|
{NPC_LIVING_KNIGHT, 10000},
|
||||||
|
{NPC_LIVING_TRAINEE, 15000},
|
||||||
|
{NPC_LIVING_TRAINEE, 0},
|
||||||
|
{NPC_LIVING_KNIGHT, 10000},
|
||||||
|
{NPC_LIVING_RIDER, 10000},
|
||||||
|
{NPC_LIVING_TRAINEE, 5000},
|
||||||
|
{NPC_LIVING_KNIGHT, 15000},
|
||||||
|
{NPC_LIVING_RIDER, 0},
|
||||||
|
{NPC_LIVING_TRAINEE, 10000},
|
||||||
|
{NPC_LIVING_KNIGHT, 10000},
|
||||||
|
{NPC_LIVING_TRAINEE, 10000},
|
||||||
|
{NPC_LIVING_RIDER, 5000},
|
||||||
|
{NPC_LIVING_KNIGHT, 5000},
|
||||||
|
{NPC_LIVING_TRAINEE, 20000},
|
||||||
|
{NPC_LIVING_RIDER, 0},
|
||||||
|
{NPC_LIVING_KNIGHT, 0},
|
||||||
|
{NPC_LIVING_TRAINEE, 15000},
|
||||||
|
{NPC_LIVING_TRAINEE, 29000},
|
||||||
|
{0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position PosSummonLiving[6] =
|
||||||
|
{
|
||||||
|
{2669.7f, -3428.76f, 268.56f, 1.6f},
|
||||||
|
{2692.1f, -3428.76f, 268.56f, 1.6f},
|
||||||
|
{2714.4f, -3428.76f, 268.56f, 1.6f},
|
||||||
|
{2669.7f, -3431.67f, 268.56f, 1.6f},
|
||||||
|
{2692.1f, -3431.67f, 268.56f, 1.6f},
|
||||||
|
{2714.4f, -3431.67f, 268.56f, 1.6f}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position PosSummonDead[5] =
|
||||||
|
{
|
||||||
|
{2725.1f, -3310.0f, 268.85f, 3.4f},
|
||||||
|
{2699.3f, -3322.8f, 268.60f, 3.3f},
|
||||||
|
{2733.1f, -3348.5f, 268.84f, 3.1f},
|
||||||
|
{2682.8f, -3304.2f, 268.85f, 3.9f},
|
||||||
|
{2664.8f, -3340.7f, 268.23f, 3.7f}
|
||||||
|
};
|
||||||
|
|
||||||
|
//const Position PosGroundLivingSide = {2691.2f, -3387.0f, 267.68f, 1.52f};
|
||||||
|
//const Position PosGroundDeadSide = {2693.5f, -3334.6f, 267.68f, 4.67f};
|
||||||
|
//const Position PosPlatform = {2640.5f, -3360.6f, 285.26f, 0.0f};
|
||||||
|
|
||||||
|
#define POS_Y_GATE -3360.78f
|
||||||
|
#define POS_Y_WEST -3285.0f
|
||||||
|
#define POS_Y_EAST -3434.0f
|
||||||
|
#define POS_X_NORTH 2750.49f
|
||||||
|
#define POS_X_SOUTH 2633.84f
|
||||||
|
#define IN_LIVE_SIDE(who) (who->GetPositionY() < POS_Y_GATE)
|
||||||
|
|
||||||
|
// Predicate function to check that the r efzr unit is NOT on the same side as the source.
|
||||||
|
struct NotOnSameSide
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit NotOnSameSide(Unit* pSource) : m_inLiveSide(IN_LIVE_SIDE(pSource)) { }
|
||||||
|
|
||||||
|
bool operator() (Unit const* pTarget)
|
||||||
|
{
|
||||||
|
return (m_inLiveSide != IN_LIVE_SIDE(pTarget));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_inLiveSide;
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_gothik_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_gothik_40() : CreatureScript("boss_gothik_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_gothik_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_gothik_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_gothik_40AI(Creature* c) : BossAI(c, BOSS_GOTHIK), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
bool secondPhase{};
|
||||||
|
bool gateOpened{};
|
||||||
|
uint8 waveCount{};
|
||||||
|
|
||||||
|
bool IsInRoom()
|
||||||
|
{
|
||||||
|
if (me->GetPositionX() > 2767 || me->GetPositionX() < 2618 || me->GetPositionY() > -3285 || me->GetPositionY() < -3435)
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->SetImmuneToPC(false);
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
secondPhase = false;
|
||||||
|
gateOpened = false;
|
||||||
|
waveCount = 0;
|
||||||
|
me->NearTeleportTo(2642.139f, -3386.959f, 285.492f, 6.265f);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_ENTER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_EXIT_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
Talk(SAY_INTRO_1);
|
||||||
|
events.ScheduleEvent(EVENT_INTRO_2, 4000);
|
||||||
|
events.ScheduleEvent(EVENT_INTRO_3, 9000);
|
||||||
|
events.ScheduleEvent(EVENT_INTRO_4, 14000);
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000);
|
||||||
|
events.ScheduleEvent(EVENT_CHECK_PLAYERS, 120000);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_ENTER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* summon) override
|
||||||
|
{
|
||||||
|
summons.Summon(summon);
|
||||||
|
if (gateOpened)
|
||||||
|
{
|
||||||
|
summons.DoZoneInCombat();
|
||||||
|
}
|
||||||
|
else if (Unit* target = me->SelectNearestTarget(50.0f))
|
||||||
|
{
|
||||||
|
AttackStart(target);
|
||||||
|
DoZoneInCombat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonedCreatureDespawn(Creature* cr) override
|
||||||
|
{
|
||||||
|
summons.Despawn(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_KILL);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
summons.DespawnAll();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_ENTER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_EXIT_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonHelpers(uint32 entry)
|
||||||
|
{
|
||||||
|
switch(entry)
|
||||||
|
{
|
||||||
|
case NPC_LIVING_TRAINEE:
|
||||||
|
me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[0].GetPositionX(), PosSummonLiving[0].GetPositionY(), PosSummonLiving[0].GetPositionZ(), PosSummonLiving[0].GetOrientation());
|
||||||
|
me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[1].GetPositionX(), PosSummonLiving[1].GetPositionY(), PosSummonLiving[1].GetPositionZ(), PosSummonLiving[1].GetOrientation());
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_LIVING_TRAINEE, PosSummonLiving[2].GetPositionX(), PosSummonLiving[2].GetPositionY(), PosSummonLiving[2].GetPositionZ(), PosSummonLiving[2].GetOrientation());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NPC_LIVING_KNIGHT:
|
||||||
|
me->SummonCreature(NPC_LIVING_KNIGHT, PosSummonLiving[3].GetPositionX(), PosSummonLiving[3].GetPositionY(), PosSummonLiving[3].GetPositionZ(), PosSummonLiving[3].GetOrientation());
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_LIVING_KNIGHT, PosSummonLiving[5].GetPositionX(), PosSummonLiving[5].GetPositionY(), PosSummonLiving[5].GetPositionZ(), PosSummonLiving[5].GetOrientation());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NPC_LIVING_RIDER:
|
||||||
|
me->SummonCreature(NPC_LIVING_RIDER, PosSummonLiving[4].GetPositionX(), PosSummonLiving[4].GetPositionY(), PosSummonLiving[4].GetPositionZ(), PosSummonLiving[4].GetOrientation());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckGroupSplitted()
|
||||||
|
{
|
||||||
|
Map::PlayerList const& PlayerList = me->GetMap()->GetPlayers();
|
||||||
|
if (!PlayerList.IsEmpty())
|
||||||
|
{
|
||||||
|
bool checklife = false;
|
||||||
|
bool checkdead = false;
|
||||||
|
for (const auto& i : PlayerList)
|
||||||
|
{
|
||||||
|
Player* player = i.GetSource();
|
||||||
|
if (player->IsAlive() &&
|
||||||
|
player->GetPositionX() <= POS_X_NORTH &&
|
||||||
|
player->GetPositionX() >= POS_X_SOUTH &&
|
||||||
|
player->GetPositionY() <= POS_Y_GATE &&
|
||||||
|
player->GetPositionY() >= POS_Y_EAST)
|
||||||
|
{
|
||||||
|
checklife = true;
|
||||||
|
}
|
||||||
|
else if (player->IsAlive() &&
|
||||||
|
player->GetPositionX() <= POS_X_NORTH &&
|
||||||
|
player->GetPositionX() >= POS_X_SOUTH &&
|
||||||
|
player->GetPositionY() >= POS_Y_GATE &&
|
||||||
|
player->GetPositionY() <= POS_Y_WEST)
|
||||||
|
{
|
||||||
|
checkdead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checklife && checkdead)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
|
||||||
|
{
|
||||||
|
uint8 pos = urand(0, 4);
|
||||||
|
switch (spellInfo->Id)
|
||||||
|
{
|
||||||
|
case SPELL_INFORM_LIVING_TRAINEE:
|
||||||
|
me->SummonCreature(NPC_DEAD_TRAINEE, PosSummonDead[pos].GetPositionX(), PosSummonDead[pos].GetPositionY(), PosSummonDead[pos].GetPositionZ(), PosSummonDead[pos].GetOrientation());
|
||||||
|
break;
|
||||||
|
case SPELL_INFORM_LIVING_KNIGHT:
|
||||||
|
me->SummonCreature(NPC_DEAD_KNIGHT, PosSummonDead[pos].GetPositionX(), PosSummonDead[pos].GetPositionY(), PosSummonDead[pos].GetPositionZ(), PosSummonDead[pos].GetOrientation());
|
||||||
|
break;
|
||||||
|
case SPELL_INFORM_LIVING_RIDER:
|
||||||
|
me->SummonCreature(NPC_DEAD_RIDER, PosSummonDead[pos].GetPositionX(), PosSummonDead[pos].GetPositionY(), PosSummonDead[pos].GetPositionZ(), PosSummonDead[pos].GetOrientation());
|
||||||
|
me->SummonCreature(NPC_DEAD_HORSE, PosSummonDead[pos].GetPositionX(), PosSummonDead[pos].GetPositionY(), PosSummonDead[pos].GetPositionZ(), PosSummonDead[pos].GetOrientation());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||||
|
{
|
||||||
|
if (!secondPhase)
|
||||||
|
{
|
||||||
|
damage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!IsInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_INTRO_2:
|
||||||
|
Talk(SAY_INTRO_2);
|
||||||
|
break;
|
||||||
|
case EVENT_INTRO_3:
|
||||||
|
Talk(SAY_INTRO_3);
|
||||||
|
break;
|
||||||
|
case EVENT_INTRO_4:
|
||||||
|
Talk(SAY_INTRO_4);
|
||||||
|
break;
|
||||||
|
case EVENT_SHADOW_BOLT:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||||
|
events.RepeatEvent(1010);
|
||||||
|
break;
|
||||||
|
case EVENT_HARVEST_SOUL:
|
||||||
|
me->CastSpell(me, SPELL_HARVEST_SOUL, false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
break;
|
||||||
|
case EVENT_TELEPORT:
|
||||||
|
me->AttackStop();
|
||||||
|
if (IN_LIVE_SIDE(me))
|
||||||
|
{
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT_DEAD, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
|
||||||
|
}
|
||||||
|
me->GetThreatMgr().resetAggro(NotOnSameSide(me));
|
||||||
|
if (Unit* pTarget = SelectTarget(SelectTargetMethod::MaxDistance, 0))
|
||||||
|
{
|
||||||
|
me->GetThreatMgr().addThreat(pTarget, 100.0f);
|
||||||
|
AttackStart(pTarget);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(20000);
|
||||||
|
break;
|
||||||
|
case EVENT_CHECK_HEALTH:
|
||||||
|
if (me->HealthBelowPct(30) && pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
events.CancelEvent(EVENT_TELEPORT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1000);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_ADDS:
|
||||||
|
if (gothikWaves[waveCount][0])
|
||||||
|
{
|
||||||
|
SummonHelpers(gothikWaves[waveCount][0]);
|
||||||
|
events.RepeatEvent(gothikWaves[waveCount][1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
secondPhase = true;
|
||||||
|
Talk(SAY_PHASE_TWO);
|
||||||
|
Talk(EMOTE_PHASE_TWO);
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT_LIVE, false);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->SetImmuneToPC(false);
|
||||||
|
me->RemoveAllAuras();
|
||||||
|
summons.DoZoneInCombat();
|
||||||
|
events.ScheduleEvent(EVENT_SHADOW_BOLT, 1000);
|
||||||
|
events.ScheduleEvent(EVENT_HARVEST_SOUL, urand(5000, 15000));
|
||||||
|
events.ScheduleEvent(EVENT_TELEPORT, 20000);
|
||||||
|
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||||
|
}
|
||||||
|
waveCount++;
|
||||||
|
break;
|
||||||
|
case EVENT_CHECK_PLAYERS:
|
||||||
|
if (!CheckGroupSplitted())
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_GOTHIK_INNER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
summons.DoZoneInCombat();
|
||||||
|
gateOpened = true;
|
||||||
|
Talk(EMOTE_GATE_OPENED);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class npc_boss_gothik_minion_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
npc_boss_gothik_minion_40() : CreatureScript("npc_boss_gothik_minion_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<npc_boss_gothik_minion_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct npc_boss_gothik_minion_40AI : public CombatAI
|
||||||
|
{
|
||||||
|
explicit npc_boss_gothik_minion_40AI(Creature* c) : CombatAI(c)
|
||||||
|
{
|
||||||
|
livingSide = IN_LIVE_SIDE(me);
|
||||||
|
}
|
||||||
|
EventMap events;
|
||||||
|
bool livingSide;
|
||||||
|
bool IsOnSameSide(Unit const* who) const { return livingSide == IN_LIVE_SIDE(who); }
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->SetNoCallAssistance(false);
|
||||||
|
events.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* /*who*/) override
|
||||||
|
{
|
||||||
|
switch (me->GetEntry())
|
||||||
|
{
|
||||||
|
case NPC_LIVING_TRAINEE:
|
||||||
|
events.ScheduleEvent(EVENT_DEATH_PLAGUE, 3000);
|
||||||
|
break;
|
||||||
|
case NPC_DEAD_TRAINEE:
|
||||||
|
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 2500);
|
||||||
|
break;
|
||||||
|
case NPC_LIVING_KNIGHT:
|
||||||
|
events.ScheduleEvent(EVENT_SHADOW_MARK, 3000);
|
||||||
|
break;
|
||||||
|
case NPC_DEAD_KNIGHT:
|
||||||
|
events.ScheduleEvent(EVENT_WHIRLWIND, 2000);
|
||||||
|
break;
|
||||||
|
case NPC_LIVING_RIDER:
|
||||||
|
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 3000);
|
||||||
|
break;
|
||||||
|
case NPC_DEAD_RIDER:
|
||||||
|
events.ScheduleEvent(EVENT_DRAIN_LIFE, urand(2000, 3500));
|
||||||
|
events.ScheduleEvent(EVENT_UNHOLY_FRENZY, urand(5000, 9000));
|
||||||
|
break;
|
||||||
|
case NPC_DEAD_HORSE:
|
||||||
|
events.ScheduleEvent(EVENT_STOMP, urand(2000, 5000));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||||
|
{
|
||||||
|
if (!attacker || !IsOnSameSide(attacker))
|
||||||
|
{
|
||||||
|
damage = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!me->IsInCombat())
|
||||||
|
{
|
||||||
|
me->CallForHelp(25.0f);
|
||||||
|
AttackStart(attacker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit*) override
|
||||||
|
{
|
||||||
|
switch (me->GetEntry())
|
||||||
|
{
|
||||||
|
case NPC_LIVING_TRAINEE:
|
||||||
|
me->CastSpell(me, SPELL_INFORM_LIVING_TRAINEE, true);
|
||||||
|
break;
|
||||||
|
case NPC_LIVING_KNIGHT:
|
||||||
|
me->CastSpell(me, SPELL_INFORM_LIVING_KNIGHT, true);
|
||||||
|
break;
|
||||||
|
case NPC_LIVING_RIDER:
|
||||||
|
me->CastSpell(me, SPELL_INFORM_LIVING_RIDER, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript())
|
||||||
|
{
|
||||||
|
me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->GetUnitState() == UNIT_STATE_CASTING)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_DEATH_PLAGUE:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_DEATH_PLAGUE, false);
|
||||||
|
events.RepeatEvent(urand(4000, 7000));
|
||||||
|
break;
|
||||||
|
case EVENT_ARCANE_EXPLOSION:
|
||||||
|
if (Unit* victim = me->GetVictim())
|
||||||
|
{
|
||||||
|
if (victim->IsWithinDist(me, 20))
|
||||||
|
{
|
||||||
|
me->CastSpell(victim, SPELL_ARCANE_EXPLOSION, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(2500);
|
||||||
|
break;
|
||||||
|
case EVENT_SHADOW_MARK:
|
||||||
|
if (Unit* victim = me->GetVictim())
|
||||||
|
{
|
||||||
|
if (!victim->HasAura(SPELL_SHADOW_MARK))
|
||||||
|
{
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_SHADOW_MARK, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(urand(5000, 7000));
|
||||||
|
break;
|
||||||
|
case EVENT_WHIRLWIND:
|
||||||
|
if (Unit* victim = me->GetVictim())
|
||||||
|
{
|
||||||
|
if (victim->IsWithinDist(me, 10))
|
||||||
|
{
|
||||||
|
me->CastSpell(victim, SPELL_WHIRLWIND, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(urand(4000, 6000));
|
||||||
|
break;
|
||||||
|
case EVENT_SHADOW_BOLT_VOLLEY:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT_VOLLEY, false);
|
||||||
|
events.RepeatEvent(5000);
|
||||||
|
break;
|
||||||
|
case EVENT_DRAIN_LIFE:
|
||||||
|
if (Unit* victim = me->GetVictim())
|
||||||
|
{
|
||||||
|
if (victim->IsWithinDist(me, 20))
|
||||||
|
{
|
||||||
|
me->CastSpell(victim, SPELL_DRAIN_LIFE, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(urand(8000, 12000));
|
||||||
|
break;
|
||||||
|
case EVENT_UNHOLY_FRENZY:
|
||||||
|
me->AddAura(SPELL_UNHOLY_FRENZY, me);
|
||||||
|
events.RepeatEvent(urand(15000, 17000));
|
||||||
|
break;
|
||||||
|
case EVENT_STOMP:
|
||||||
|
if (Unit* victim = me->GetVictim())
|
||||||
|
{
|
||||||
|
if (victim->IsWithinDist(me, 10))
|
||||||
|
{
|
||||||
|
me->CastSpell(victim, SPELL_STOMP, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(urand(4000, 9000));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_gothik_shadow_bolt_volley : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_gothik_shadow_bolt_volley() : SpellScriptLoader("spell_gothik_shadow_bolt_volley") { }
|
||||||
|
|
||||||
|
class spell_gothik_shadow_bolt_volley_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_gothik_shadow_bolt_volley_SpellScript);
|
||||||
|
|
||||||
|
void FilterTargets(std::list<WorldObject*>& targets)
|
||||||
|
{
|
||||||
|
targets.remove_if(Acore::UnitAuraCheck(false, SPELL_SHADOW_MARK));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gothik_shadow_bolt_volley_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_gothik_shadow_bolt_volley_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_gothik_40()
|
||||||
|
{
|
||||||
|
new boss_gothik_40();
|
||||||
|
new npc_boss_gothik_minion_40();
|
||||||
|
// new spell_gothik_shadow_bolt_volley();
|
||||||
|
}
|
||||||
326
src/naxx40Scripts/boss_grobbulus_40.cpp
Normal file
326
src/naxx40Scripts/boss_grobbulus_40.cpp
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PassiveAI.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellAuraEffects.h"
|
||||||
|
#include "SpellAuras.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_POISON_CLOUD = 28240,
|
||||||
|
SPELL_MUTATING_INJECTION = 28169,
|
||||||
|
SPELL_MUTATING_EXPLOSION = 28206,
|
||||||
|
SPELL_SLIME_SPRAY = 28157,
|
||||||
|
SPELL_POISON_CLOUD_DAMAGE_AURA = 28158,
|
||||||
|
SPELL_BERSERK = 26662,
|
||||||
|
SPELL_BOMBARD_SLIME = 28280
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Emotes
|
||||||
|
{
|
||||||
|
EMOTE_SLIME = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_BERSERK = 1,
|
||||||
|
EVENT_POISON_CLOUD = 2,
|
||||||
|
EVENT_SLIME_SPRAY = 3,
|
||||||
|
EVENT_MUTATING_INJECTION = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_FALLOUT_SLIME = 351067,
|
||||||
|
NPC_SEWAGE_SLIME = 351071,
|
||||||
|
NPC_STICHED_GIANT = 351027
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_grobbulus_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_grobbulus_40() : CreatureScript("boss_grobbulus_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_grobbulus_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_grobbulus_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_grobbulus_40AI(Creature* c) : BossAI(c, BOSS_GROBBULUS), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
uint32 dropSludgeTimer{};
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
dropSludgeTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PullChamberAdds()
|
||||||
|
{
|
||||||
|
std::list<Creature*> StichedGiants;
|
||||||
|
me->GetCreaturesWithEntryInRange(StichedGiants, 300.0f, NPC_STICHED_GIANT);
|
||||||
|
for (std::list<Creature*>::const_iterator itr = StichedGiants.begin(); itr != StichedGiants.end(); ++itr)
|
||||||
|
{
|
||||||
|
(*itr)->ToCreature()->AI()->AttackStart(me->GetVictim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
PullChamberAdds();
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
events.ScheduleEvent(EVENT_POISON_CLOUD, 15000);
|
||||||
|
events.ScheduleEvent(EVENT_MUTATING_INJECTION, 12000);
|
||||||
|
events.ScheduleEvent(EVENT_SLIME_SPRAY, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_BERSERK, 12 * 60 * 1000); // 12 minute enrage
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||||
|
{
|
||||||
|
if (spellInfo->Id == SPELL_SLIME_SPRAY && target->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_FALLOUT_SLIME, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
if (cr->GetEntry() == NPC_FALLOUT_SLIME)
|
||||||
|
{
|
||||||
|
cr->SetInCombatWithZone();
|
||||||
|
}
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonedCreatureDespawn(Creature* summon) override
|
||||||
|
{
|
||||||
|
summons.Despawn(summon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
summons.DespawnAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
dropSludgeTimer += diff;
|
||||||
|
if (!me->IsInCombat() && dropSludgeTimer >= 5000)
|
||||||
|
{
|
||||||
|
if (me->IsWithinDist3d(3178, -3305, 319, 5.0f) && !summons.HasEntry(NPC_SEWAGE_SLIME))
|
||||||
|
{
|
||||||
|
me->CastSpell(3128.96f + irand(-20, 20), -3312.96f + irand(-20, 20), 293.25f, SPELL_BOMBARD_SLIME, false);
|
||||||
|
}
|
||||||
|
dropSludgeTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_POISON_CLOUD:
|
||||||
|
me->CastSpell(me, SPELL_POISON_CLOUD, true);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
break;
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
break;
|
||||||
|
case EVENT_SLIME_SPRAY:
|
||||||
|
Talk(EMOTE_SLIME);
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_SLIME_SPRAY, false);
|
||||||
|
events.RepeatEvent(20000);
|
||||||
|
break;
|
||||||
|
case EVENT_MUTATING_INJECTION:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true, -SPELL_MUTATING_INJECTION))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_MUTATING_INJECTION, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(6000 + uint32(120 * me->GetHealthPct()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_grobbulus_poison_cloud_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_grobbulus_poison_cloud_40() : CreatureScript("boss_grobbulus_poison_cloud_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_grobbulus_40_poison_cloudAI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_grobbulus_40_poison_cloudAI : public NullCreatureAI
|
||||||
|
{
|
||||||
|
explicit boss_grobbulus_40_poison_cloudAI(Creature* pCreature) : NullCreatureAI(pCreature) { }
|
||||||
|
|
||||||
|
uint32 sizeTimer{};
|
||||||
|
uint32 auraVisualTimer{};
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
sizeTimer = 0;
|
||||||
|
auraVisualTimer = 1;
|
||||||
|
me->SetFloatValue(UNIT_FIELD_COMBATREACH, 2.0f);
|
||||||
|
me->SetFaction(FACTION_BOOTY_BAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript())
|
||||||
|
{
|
||||||
|
me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (auraVisualTimer) // this has to be delayed to be visible
|
||||||
|
{
|
||||||
|
auraVisualTimer += diff;
|
||||||
|
if (auraVisualTimer >= 1000)
|
||||||
|
{
|
||||||
|
me->CastSpell(me, SPELL_POISON_CLOUD_DAMAGE_AURA, true);
|
||||||
|
auraVisualTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sizeTimer += diff; // increase size to 15yd in 60 seconds, 0.00025 is the growth of size in 1ms
|
||||||
|
me->SetFloatValue(UNIT_FIELD_COMBATREACH, 2.0f + (0.00025f * sizeTimer));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_grobbulus_poison : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_grobbulus_poison() : SpellScriptLoader("spell_grobbulus_poison") { }
|
||||||
|
|
||||||
|
class spell_grobbulus_poison_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_grobbulus_poison_SpellScript);
|
||||||
|
|
||||||
|
void FilterTargets(std::list<WorldObject*>& targets)
|
||||||
|
{
|
||||||
|
std::list<WorldObject*> tmplist;
|
||||||
|
for (auto& target : targets)
|
||||||
|
{
|
||||||
|
if (GetCaster()->IsWithinDist3d(target, 0.0f))
|
||||||
|
{
|
||||||
|
tmplist.push_back(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targets.clear();
|
||||||
|
for (auto& itr : tmplist)
|
||||||
|
{
|
||||||
|
targets.push_back(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grobbulus_poison_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_grobbulus_poison_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_grobbulus_mutating_injection : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_grobbulus_mutating_injection() : SpellScriptLoader("spell_grobbulus_mutating_injection") { }
|
||||||
|
|
||||||
|
class spell_grobbulus_mutating_injection_AuraScript : public AuraScript
|
||||||
|
{
|
||||||
|
PrepareAuraScript(spell_grobbulus_mutating_injection_AuraScript);
|
||||||
|
|
||||||
|
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||||
|
{
|
||||||
|
return ValidateSpellInfo({ SPELL_MUTATING_EXPLOSION });
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||||
|
{
|
||||||
|
switch (GetTargetApplication()->GetRemoveMode())
|
||||||
|
{
|
||||||
|
case AURA_REMOVE_BY_ENEMY_SPELL:
|
||||||
|
case AURA_REMOVE_BY_EXPIRE:
|
||||||
|
if (auto caster = GetCaster())
|
||||||
|
{
|
||||||
|
caster->CastSpell(GetTarget(), SPELL_MUTATING_EXPLOSION, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
AfterEffectRemove += AuraEffectRemoveFn(spell_grobbulus_mutating_injection_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AuraScript* GetAuraScript() const override
|
||||||
|
{
|
||||||
|
return new spell_grobbulus_mutating_injection_AuraScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_grobbulus_40()
|
||||||
|
{
|
||||||
|
new boss_grobbulus_40();
|
||||||
|
new boss_grobbulus_poison_cloud_40();
|
||||||
|
// new spell_grobbulus_mutating_injection();
|
||||||
|
// new spell_grobbulus_poison();
|
||||||
|
}
|
||||||
251
src/naxx40Scripts/boss_heigan_40.cpp
Normal file
251
src/naxx40Scripts/boss_heigan_40.cpp
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Says
|
||||||
|
{
|
||||||
|
SAY_AGGRO = 0,
|
||||||
|
SAY_SLAY = 1,
|
||||||
|
SAY_TAUNT = 2,
|
||||||
|
EMOTE_DEATH = 3,
|
||||||
|
EMOTE_DANCE = 4,
|
||||||
|
EMOTE_DANCE_END = 5,
|
||||||
|
SAY_DANCE = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_SPELL_DISRUPTION = 29310,
|
||||||
|
SPELL_DECREPIT_FEVER = 29998,
|
||||||
|
SPELL_PLAGUE_CLOUD = 29350,
|
||||||
|
SPELL_TELEPORT_SELF = 30211
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_DISRUPTION = 1,
|
||||||
|
EVENT_DECEPIT_FEVER = 2,
|
||||||
|
EVENT_ERUPT_SECTION = 3,
|
||||||
|
EVENT_SWITCH_PHASE = 4,
|
||||||
|
EVENT_SAFETY_DANCE = 5,
|
||||||
|
EVENT_PLAGUE_CLOUD = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
PHASE_SLOW_DANCE = 0,
|
||||||
|
PHASE_FAST_DANCE = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_heigan_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_heigan_40() : CreatureScript("boss_heigan_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_heigan_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_heigan_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_heigan_40AI(Creature* c) : BossAI(c, BOSS_HEIGAN)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
EventMap events;
|
||||||
|
uint8 currentPhase{};
|
||||||
|
uint8 currentSection{};
|
||||||
|
bool moveRight{};
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
currentPhase = 0;
|
||||||
|
currentSection = 3;
|
||||||
|
moveRight = true;
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_ENTER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(EMOTE_DEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_HEIGAN_ENTER_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StartFightPhase(PHASE_SLOW_DANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartFightPhase(uint8 phase)
|
||||||
|
{
|
||||||
|
currentSection = 3;
|
||||||
|
currentPhase = phase;
|
||||||
|
events.Reset();
|
||||||
|
if (phase == PHASE_SLOW_DANCE)
|
||||||
|
{
|
||||||
|
me->CastStop();
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
DoZoneInCombat();
|
||||||
|
events.ScheduleEvent(EVENT_DISRUPTION, urand(12000, 15000));
|
||||||
|
events.ScheduleEvent(EVENT_DECEPIT_FEVER, 17000);
|
||||||
|
events.ScheduleEvent(EVENT_ERUPT_SECTION, 15000);
|
||||||
|
events.ScheduleEvent(EVENT_SWITCH_PHASE, 90000);
|
||||||
|
}
|
||||||
|
else // if (phase == PHASE_FAST_DANCE)
|
||||||
|
{
|
||||||
|
Talk(EMOTE_DANCE);
|
||||||
|
Talk(SAY_DANCE);
|
||||||
|
me->AttackStop();
|
||||||
|
me->StopMoving();
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT_SELF, false);
|
||||||
|
me->SetFacingTo(2.40f);
|
||||||
|
events.ScheduleEvent(EVENT_PLAGUE_CLOUD, 1000);
|
||||||
|
events.ScheduleEvent(EVENT_ERUPT_SECTION, 7000);
|
||||||
|
events.ScheduleEvent(EVENT_SWITCH_PHASE, 45000);
|
||||||
|
}
|
||||||
|
events.ScheduleEvent(EVENT_SAFETY_DANCE, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInRoom(Unit* who)
|
||||||
|
{
|
||||||
|
if (who->GetPositionX() > 2826 || who->GetPositionX() < 2723 || who->GetPositionY() > -3641 || who->GetPositionY() < -3736)
|
||||||
|
{
|
||||||
|
if (who->GetGUID() == me->GetGUID())
|
||||||
|
EnterEvadeMode();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!IsInRoom(me))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_DISRUPTION:
|
||||||
|
me->CastSpell(me, SPELL_SPELL_DISRUPTION, false);
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
break;
|
||||||
|
case EVENT_DECEPIT_FEVER:
|
||||||
|
me->CastSpell(me, SPELL_DECREPIT_FEVER, false);
|
||||||
|
events.RepeatEvent(urand(22000, 25000));
|
||||||
|
break;
|
||||||
|
case EVENT_PLAGUE_CLOUD:
|
||||||
|
me->CastSpell(me, SPELL_PLAGUE_CLOUD, false);
|
||||||
|
break;
|
||||||
|
case EVENT_SWITCH_PHASE:
|
||||||
|
if (currentPhase == PHASE_SLOW_DANCE)
|
||||||
|
{
|
||||||
|
StartFightPhase(PHASE_FAST_DANCE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StartFightPhase(PHASE_SLOW_DANCE);
|
||||||
|
Talk(EMOTE_DANCE_END); // avoid play the emote on aggro
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_ERUPT_SECTION:
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_HEIGAN_ERUPTION, currentSection);
|
||||||
|
if (currentSection == 3)
|
||||||
|
{
|
||||||
|
moveRight = false;
|
||||||
|
}
|
||||||
|
else if (currentSection == 0)
|
||||||
|
{
|
||||||
|
moveRight = true;
|
||||||
|
}
|
||||||
|
moveRight ? currentSection++ : currentSection--;
|
||||||
|
}
|
||||||
|
if (currentPhase == PHASE_SLOW_DANCE)
|
||||||
|
{
|
||||||
|
Talk(SAY_TAUNT);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(currentPhase == PHASE_SLOW_DANCE ? 10000 : 4000);
|
||||||
|
break;
|
||||||
|
case EVENT_SAFETY_DANCE:
|
||||||
|
{
|
||||||
|
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
|
||||||
|
for (const auto& itr : pList)
|
||||||
|
{
|
||||||
|
if (IsInRoom(itr.GetSource()) && !itr.GetSource()->IsAlive())
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_DANCE_FAIL, 0);
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_heigan_40()
|
||||||
|
{
|
||||||
|
new boss_heigan_40();
|
||||||
|
}
|
||||||
750
src/naxx40Scripts/boss_kelthuzad_40.cpp
Normal file
750
src/naxx40Scripts/boss_kelthuzad_40.cpp
Normal file
@@ -0,0 +1,750 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Yells
|
||||||
|
{
|
||||||
|
SAY_ANSWER_REQUEST = 3,
|
||||||
|
SAY_TAUNT = 6,
|
||||||
|
SAY_AGGRO = 7,
|
||||||
|
SAY_SLAY = 8,
|
||||||
|
SAY_DEATH = 9,
|
||||||
|
SAY_CHAIN = 10,
|
||||||
|
SAY_FROST_BLAST = 11,
|
||||||
|
SAY_REQUEST_AID = 12,
|
||||||
|
EMOTE_PHASE_TWO = 13,
|
||||||
|
SAY_SUMMON_MINIONS = 14,
|
||||||
|
SAY_SPECIAL = 15,
|
||||||
|
|
||||||
|
EMOTE_GUARDIAN_FLEE = 0,
|
||||||
|
EMOTE_GUARDIAN_APPEAR = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
// Kel'Thzuad
|
||||||
|
SPELL_FROST_BOLT_SINGLE = 28478,
|
||||||
|
SPELL_FROST_BOLT_MULTI = 28479,
|
||||||
|
SPELL_SHADOW_FISURE = 27810,
|
||||||
|
SPELL_VOID_BLAST = 27812,
|
||||||
|
SPELL_DETONATE_MANA = 27819,
|
||||||
|
SPELL_MANA_DETONATION_DAMAGE = 27820,
|
||||||
|
SPELL_FROST_BLAST = 27808,
|
||||||
|
SPELL_CHAINS_OF_KELTHUZAD = 28410, // 28408 script effect
|
||||||
|
SPELL_BERSERK = 28498,
|
||||||
|
SPELL_KELTHUZAD_CHANNEL = 29423,
|
||||||
|
|
||||||
|
// Minions
|
||||||
|
SPELL_FRENZY = 28468,
|
||||||
|
SPELL_MORTAL_WOUND = 28467,
|
||||||
|
SPELL_BLOOD_TAP = 28470
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_SOLDIER_OF_THE_FROZEN_WASTES = 351073,
|
||||||
|
NPC_UNSTOPPABLE_ABOMINATION = 351074,
|
||||||
|
NPC_SOUL_WEAVER = 351075,
|
||||||
|
NPC_GUARDIAN_OF_ICECROWN = 351076,
|
||||||
|
|
||||||
|
ACTION_CALL_HELP_ON = 1,
|
||||||
|
ACTION_CALL_HELP_OFF = 2,
|
||||||
|
ACTION_SECOND_PHASE = 3,
|
||||||
|
ACTION_GUARDIANS_OFF = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Event
|
||||||
|
{
|
||||||
|
// Kel'Thuzad
|
||||||
|
EVENT_SUMMON_SOLDIER = 1,
|
||||||
|
EVENT_SUMMON_UNSTOPPABLE_ABOMINATION = 2,
|
||||||
|
EVENT_SUMMON_SOUL_WEAVER = 3,
|
||||||
|
EVENT_PHASE_2 = 4,
|
||||||
|
EVENT_FROST_BOLT_SINGLE = 5,
|
||||||
|
EVENT_FROST_BOLT_MULTI = 6,
|
||||||
|
EVENT_DETONATE_MANA = 7,
|
||||||
|
EVENT_PHASE_3 = 8,
|
||||||
|
EVENT_P3_LICH_KING_SAY = 9,
|
||||||
|
EVENT_SHADOW_FISSURE = 10,
|
||||||
|
EVENT_FROST_BLAST = 11,
|
||||||
|
EVENT_CHAINS = 12,
|
||||||
|
EVENT_SUMMON_GUARDIAN_OF_ICECROWN = 13,
|
||||||
|
EVENT_FLOOR_CHANGE = 14,
|
||||||
|
EVENT_ENRAGE = 15,
|
||||||
|
EVENT_SPAWN_POOL = 16,
|
||||||
|
|
||||||
|
// Minions
|
||||||
|
EVENT_MINION_FRENZY = 17,
|
||||||
|
EVENT_MINION_MORTAL_WOUND = 18,
|
||||||
|
EVENT_MINION_BLOOD_TAP = 19
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position SummonGroups[12] =
|
||||||
|
{
|
||||||
|
// Portals
|
||||||
|
{3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, // LEFT_FAR
|
||||||
|
{3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, // LEFT_MIDDLE
|
||||||
|
{3683.868652f, -5057.281250f, 143.183884f, 5.237086f}, // LEFT_NEAR
|
||||||
|
{3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, // RIGHT_FAR
|
||||||
|
{3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, // RIGHT_MIDDLE
|
||||||
|
{3665.121094f, -5138.679199f, 143.183212f, 0.604023f}, // RIGHT_NEAR
|
||||||
|
|
||||||
|
// Middle
|
||||||
|
{3769.34f, -5071.80f, 143.2082f, 3.658f},
|
||||||
|
{3729.78f, -5043.56f, 143.3867f, 4.475f},
|
||||||
|
{3682.75f, -5055.26f, 143.1848f, 5.295f},
|
||||||
|
{3752.58f, -5161.82f, 143.2944f, 2.126f},
|
||||||
|
{3702.83f, -5171.70f, 143.4356f, 1.305f},
|
||||||
|
{3665.30f, -5141.55f, 143.1846f, 0.566f}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position SpawnPool[7] =
|
||||||
|
{
|
||||||
|
// Portals
|
||||||
|
{3783.272705f, -5062.697266f, 143.711203f, 3.617599f}, // LEFT_FAR
|
||||||
|
{3730.291260f, -5027.239258f, 143.956909f, 4.461900f}, // LEFT_MIDDLE
|
||||||
|
{3683.868652f, -5057.281250f, 143.183884f, 5.237086f}, // LEFT_NEAR
|
||||||
|
{3759.355225f, -5174.128418f, 143.802383f, 2.170104f}, // RIGHT_FAR
|
||||||
|
{3700.724365f, -5185.123047f, 143.928024f, 1.309310f}, // RIGHT_MIDDLE
|
||||||
|
{3665.121094f, -5138.679199f, 143.183212f, 0.604023f}, // RIGHT_NEAR
|
||||||
|
{3651.729980f, -5092.620117f, 143.380005f, 6.050000f} // GATE
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_kelthuzad_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_kelthuzad_40() : CreatureScript("boss_kelthuzad_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_kelthuzad_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_kelthuzad_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_kelthuzad_40AI(Creature* c) : BossAI(c, BOSS_KELTHUZAD), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
_justSpawned = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
bool _justSpawned;
|
||||||
|
|
||||||
|
float NormalizeOrientation(float o)
|
||||||
|
{
|
||||||
|
return std::fmod(o, 2.0f * static_cast<float>(M_PI)); // Only positive values will be passed
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpawnHelpers()
|
||||||
|
{
|
||||||
|
// spawn at gate
|
||||||
|
me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3656.19f, -5093.78f, 143.33f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo center
|
||||||
|
me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3657.94f, -5087.68f, 143.60f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo left
|
||||||
|
me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, 3655.48f, -5100.05f, 143.53f, 6.08, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000);// abo right
|
||||||
|
me->SummonCreature(NPC_SOUL_WEAVER, 3651.73f, -5092.62f, 143.38f, 6.05, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // soul behind
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3660.17f, -5092.45f, 143.37f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske front left
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3659.39f, -5096.21f, 143.29f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske front right
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3659.29f, -5090.19f, 143.48f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske left left
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3657.43f, -5098.03f, 143.41f, 6.07, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske right right
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3654.36f, -5090.51f, 143.48f, 6.09, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske behind left
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 3653.35f, -5095.91f, 143.41f, 6.09, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2000); // ske right right
|
||||||
|
|
||||||
|
// 6 rooms, 8 soldiers, 3 abominations and 1 weaver in each room | middle positions in table starts from 6
|
||||||
|
for (uint8 i = 6; i < 12; ++i)
|
||||||
|
{
|
||||||
|
for (uint8 j = 0; j < 8; ++j)
|
||||||
|
{
|
||||||
|
float angle = M_PI * 2 / 8 * j;
|
||||||
|
me->SummonCreature(NPC_SOLDIER_OF_THE_FROZEN_WASTES, SummonGroups[i].GetPositionX() + 6 * cos(angle), SummonGroups[i].GetPositionY() + 6 * std::sin(angle), SummonGroups[i].GetPositionZ(), SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (uint8 i = 6; i < 12; ++i)
|
||||||
|
{
|
||||||
|
for (uint8 j = 1; j < 4; ++j)
|
||||||
|
{
|
||||||
|
float dist = j == 2 ? 0.0f : 8.0f; // second in middle
|
||||||
|
float angle = SummonGroups[i].GetOrientation() + M_PI * 2 / 4 * j;
|
||||||
|
me->SummonCreature(NPC_UNSTOPPABLE_ABOMINATION, SummonGroups[i].GetPositionX() + dist * cos(angle), SummonGroups[i].GetPositionY() + dist * std::sin(angle), SummonGroups[i].GetPositionZ(), SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (uint8 i = 6; i < 12; ++i)
|
||||||
|
{
|
||||||
|
for (uint8 j = 0; j < 1; ++j)
|
||||||
|
{
|
||||||
|
float angle = SummonGroups[i].GetOrientation() + M_PI;
|
||||||
|
me->SummonCreature(NPC_SOUL_WEAVER, SummonGroups[i].GetPositionX() + 6 * cos(angle), SummonGroups[i].GetPositionY() + 6 * std::sin(angle), SummonGroups[i].GetPositionZ() + 0.5f, SummonGroups[i].GetOrientation(), TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonHelper(uint32 entry, uint32 count)
|
||||||
|
{
|
||||||
|
for (uint8 i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (Creature* cr = me->SummonCreature(entry, SpawnPool[urand(0, 6)], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20000))
|
||||||
|
{
|
||||||
|
if (Unit* target = SelectTargetFromPlayerList(100.0f))
|
||||||
|
{
|
||||||
|
cr->AI()->DoAction(ACTION_CALL_HELP_OFF);
|
||||||
|
cr->AI()->AttackStart(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_FLOOR)))
|
||||||
|
{
|
||||||
|
go->SetPhaseMask(1, true);
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_GATE)))
|
||||||
|
{
|
||||||
|
if(!_justSpawned) // Don't open the door if we just spawned and are still doing the conversation
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_justSpawned = false;
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_1)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_2)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_3)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_4)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterEvadeMode(EvadeReason why) override
|
||||||
|
{
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
ScriptedAI::EnterEvadeMode(why);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
summons.DoAction(ACTION_GUARDIANS_OFF);
|
||||||
|
if (Creature* guardian = summons.GetCreatureWithEntry(NPC_GUARDIAN_OF_ICECROWN))
|
||||||
|
{
|
||||||
|
guardian->AI()->Talk(EMOTE_GUARDIAN_FLEE);
|
||||||
|
}
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveInLineOfSight(Unit* who) override
|
||||||
|
{
|
||||||
|
if (!me->IsInCombat() && who->GetTypeId() == TYPEID_PLAYER && who->IsAlive() && me->GetDistance(who) <= 50.0f)
|
||||||
|
AttackStart(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
Talk(SAY_SUMMON_MINIONS);
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->RemoveAllAttackers();
|
||||||
|
me->SetTarget();
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
me->CastSpell(me, SPELL_KELTHUZAD_CHANNEL, false);
|
||||||
|
events.ScheduleEvent(EVENT_SPAWN_POOL, 5000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_SOLDIER, 6400);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_UNSTOPPABLE_ABOMINATION, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_SOUL_WEAVER, 12000);
|
||||||
|
events.ScheduleEvent(EVENT_PHASE_2, 228000);
|
||||||
|
events.ScheduleEvent(EVENT_ENRAGE, 900000);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_FLOOR)))
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15000);
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
summons.Summon(cr);
|
||||||
|
if (!cr->IsInCombat())
|
||||||
|
{
|
||||||
|
cr->GetMotionMaster()->MoveRandom(5);
|
||||||
|
}
|
||||||
|
if (cr->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
|
||||||
|
{
|
||||||
|
cr->SetHomePosition(cr->GetPositionX(), cr->GetPositionY(), cr->GetPositionZ(), cr->GetOrientation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (!me->HasAura(SPELL_KELTHUZAD_CHANNEL))
|
||||||
|
{
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_FLOOR_CHANGE:
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_FLOOR)))
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_FLOOR_CHANGE, 15000);
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
go->SetPhaseMask(2, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_SPAWN_POOL:
|
||||||
|
SpawnHelpers();
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_SOLDIER:
|
||||||
|
SummonHelper(NPC_SOLDIER_OF_THE_FROZEN_WASTES, 1);
|
||||||
|
events.RepeatEvent(3100);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_UNSTOPPABLE_ABOMINATION:
|
||||||
|
SummonHelper(NPC_UNSTOPPABLE_ABOMINATION, 1);
|
||||||
|
events.RepeatEvent(18500);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_SOUL_WEAVER:
|
||||||
|
SummonHelper(NPC_SOUL_WEAVER, 1);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
break;
|
||||||
|
case EVENT_PHASE_2:
|
||||||
|
Talk(EMOTE_PHASE_TWO);
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
events.Reset();
|
||||||
|
summons.DoAction(ACTION_SECOND_PHASE);
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||||
|
me->RemoveAura(SPELL_KELTHUZAD_CHANNEL);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
events.ScheduleEvent(EVENT_FROST_BOLT_SINGLE, urand(2000, 10000));
|
||||||
|
events.ScheduleEvent(EVENT_FROST_BOLT_MULTI, urand(15000, 30000));
|
||||||
|
events.ScheduleEvent(EVENT_DETONATE_MANA, 30000);
|
||||||
|
events.ScheduleEvent(EVENT_PHASE_3, 1000);
|
||||||
|
events.ScheduleEvent(EVENT_SHADOW_FISSURE, 25000);
|
||||||
|
events.ScheduleEvent(EVENT_FROST_BLAST, 45000);
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_CHAINS, 90000);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_ENRAGE:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
break;
|
||||||
|
case EVENT_FROST_BOLT_SINGLE:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_FROST_BOLT_SINGLE, false);
|
||||||
|
events.RepeatEvent(urand(2000, 10000));
|
||||||
|
break;
|
||||||
|
case EVENT_FROST_BOLT_MULTI:
|
||||||
|
me->CastSpell(me, SPELL_FROST_BOLT_MULTI, false);
|
||||||
|
events.RepeatEvent(urand(15000, 30000));
|
||||||
|
break;
|
||||||
|
case EVENT_SHADOW_FISSURE:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_SHADOW_FISURE, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(25000);
|
||||||
|
break;
|
||||||
|
case EVENT_FROST_BLAST:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0, true))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_FROST_BLAST, false);
|
||||||
|
}
|
||||||
|
Talk(SAY_FROST_BLAST);
|
||||||
|
events.RepeatEvent(45000);
|
||||||
|
break;
|
||||||
|
case EVENT_CHAINS:
|
||||||
|
for (uint8 i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 200, true, -SPELL_CHAINS_OF_KELTHUZAD))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_CHAINS_OF_KELTHUZAD, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Talk(SAY_CHAIN);
|
||||||
|
events.RepeatEvent(90000);
|
||||||
|
break;
|
||||||
|
case EVENT_DETONATE_MANA:
|
||||||
|
{
|
||||||
|
std::vector<Unit*> unitList;
|
||||||
|
ThreatContainer::StorageType const& threatList = me->GetThreatMgr().getThreatList();
|
||||||
|
for (auto itr : threatList)
|
||||||
|
{
|
||||||
|
if (itr->getTarget()->GetTypeId() == TYPEID_PLAYER
|
||||||
|
&& itr->getTarget()->getPowerType() == POWER_MANA
|
||||||
|
&& itr->getTarget()->GetPower(POWER_MANA))
|
||||||
|
{
|
||||||
|
unitList.push_back(itr->getTarget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!unitList.empty())
|
||||||
|
{
|
||||||
|
auto itr = unitList.begin();
|
||||||
|
advance(itr, urand(0, unitList.size() - 1));
|
||||||
|
me->CastSpell(*itr, SPELL_DETONATE_MANA, false);
|
||||||
|
Talk(SAY_SPECIAL);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_PHASE_3:
|
||||||
|
if (me->HealthBelowPct(45))
|
||||||
|
{
|
||||||
|
Talk(SAY_REQUEST_AID);
|
||||||
|
events.DelayEvents(5500);
|
||||||
|
events.ScheduleEvent(EVENT_P3_LICH_KING_SAY, 5000);
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_1)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_2)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_3)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_KELTHUZAD_PORTAL_4)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1000);
|
||||||
|
break;
|
||||||
|
case EVENT_P3_LICH_KING_SAY:
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_LICH_KING_BOSS)))
|
||||||
|
{
|
||||||
|
cr->AI()->Talk(SAY_ANSWER_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (uint8 i = 0 ; i < 5; ++i)
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_GUARDIAN_OF_ICECROWN, 10000 + (i * 5000));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_GUARDIAN_OF_ICECROWN:
|
||||||
|
if (Creature* cr = me->SummonCreature(NPC_GUARDIAN_OF_ICECROWN, SpawnPool[RAND(0, 1, 3, 4)]))
|
||||||
|
{
|
||||||
|
cr->AI()->Talk(EMOTE_GUARDIAN_APPEAR);
|
||||||
|
cr->AI()->AttackStart(me->GetVictim());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!me->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_kelthuzad_minion_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_kelthuzad_minion_40() : CreatureScript("boss_kelthuzad_minion_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_kelthuzad_minion_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_kelthuzad_minion_40AI : public ScriptedAI
|
||||||
|
{
|
||||||
|
explicit boss_kelthuzad_minion_40AI(Creature* c) : ScriptedAI(c) { }
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
bool callHelp{};
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
me->SetNoCallAssistance(true);
|
||||||
|
callHelp = true;
|
||||||
|
events.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoAction(int32 param) override
|
||||||
|
{
|
||||||
|
if (param == ACTION_CALL_HELP_ON)
|
||||||
|
{
|
||||||
|
callHelp = true;
|
||||||
|
}
|
||||||
|
else if (param == ACTION_CALL_HELP_OFF)
|
||||||
|
{
|
||||||
|
callHelp = false;
|
||||||
|
}
|
||||||
|
else if (param == ACTION_SECOND_PHASE)
|
||||||
|
{
|
||||||
|
if (!me->IsInCombat())
|
||||||
|
{
|
||||||
|
me->DespawnOrUnsummon(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param == ACTION_GUARDIANS_OFF)
|
||||||
|
{
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||||
|
me->RemoveAllAuras();
|
||||||
|
EnterEvadeMode();
|
||||||
|
me->SetPosition(me->GetHomePosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveInLineOfSight(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER && !who->IsPet())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ScriptedAI::MoveInLineOfSight(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* /*killer*/) override
|
||||||
|
{
|
||||||
|
if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION && me->GetInstanceScript())
|
||||||
|
{
|
||||||
|
me->GetInstanceScript()->SetData(DATA_ABOMINATION_KILLED, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttackStart(Unit* who) override
|
||||||
|
{
|
||||||
|
ScriptedAI::AttackStart(who);
|
||||||
|
if (callHelp)
|
||||||
|
{
|
||||||
|
std::list<Creature*> targets;
|
||||||
|
me->GetCreaturesWithEntryInRange(targets, 15.0f, me->GetEntry());
|
||||||
|
for (std::list<Creature*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((*itr)->GetGUID() != me->GetGUID())
|
||||||
|
{
|
||||||
|
(*itr)->ToCreature()->AI()->DoAction(ACTION_CALL_HELP_OFF);
|
||||||
|
(*itr)->ToCreature()->AI()->AttackStart(who);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me->GetEntry() != NPC_UNSTOPPABLE_ABOMINATION && me->GetEntry() != NPC_GUARDIAN_OF_ICECROWN)
|
||||||
|
{
|
||||||
|
me->AddThreat(who, 1000000.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* /*who*/) override
|
||||||
|
{
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION)
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_MINION_FRENZY, 1000);
|
||||||
|
events.ScheduleEvent(EVENT_MINION_MORTAL_WOUND, 5000);
|
||||||
|
}
|
||||||
|
else if (me->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_MINION_BLOOD_TAP, 15000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript())
|
||||||
|
{
|
||||||
|
me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustReachedHome() override
|
||||||
|
{
|
||||||
|
if (me->GetEntry() == NPC_GUARDIAN_OF_ICECROWN)
|
||||||
|
{
|
||||||
|
me->DespawnOrUnsummon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_MINION_MORTAL_WOUND:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
break;
|
||||||
|
case EVENT_MINION_FRENZY:
|
||||||
|
if (me->HealthBelowPct(35))
|
||||||
|
{
|
||||||
|
me->CastSpell(me, SPELL_FRENZY, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1000);
|
||||||
|
break;
|
||||||
|
case EVENT_MINION_BLOOD_TAP:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_BLOOD_TAP, false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_kelthuzad_frost_blast : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_kelthuzad_frost_blast() : SpellScriptLoader("spell_kelthuzad_frost_blast") { }
|
||||||
|
|
||||||
|
class spell_kelthuzad_frost_blast_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_kelthuzad_frost_blast_SpellScript);
|
||||||
|
|
||||||
|
void FilterTargets(std::list<WorldObject*>& targets)
|
||||||
|
{
|
||||||
|
Unit* caster = GetCaster();
|
||||||
|
if (!caster || !caster->ToCreature())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::list<WorldObject*> tmplist;
|
||||||
|
for (auto& target : targets)
|
||||||
|
{
|
||||||
|
if (!target->ToUnit()->HasAura(SPELL_FROST_BLAST))
|
||||||
|
{
|
||||||
|
tmplist.push_back(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targets.clear();
|
||||||
|
for (auto& itr : tmplist)
|
||||||
|
{
|
||||||
|
targets.push_back(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kelthuzad_frost_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_kelthuzad_frost_blast_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_kelthuzad_detonate_mana : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_kelthuzad_detonate_mana() : SpellScriptLoader("spell_kelthuzad_detonate_mana") { }
|
||||||
|
|
||||||
|
class spell_kelthuzad_detonate_mana_AuraScript : public AuraScript
|
||||||
|
{
|
||||||
|
PrepareAuraScript(spell_kelthuzad_detonate_mana_AuraScript);
|
||||||
|
|
||||||
|
bool Validate(SpellInfo const* /*spell*/) override
|
||||||
|
{
|
||||||
|
return ValidateSpellInfo({ SPELL_MANA_DETONATION_DAMAGE });
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleScript(AuraEffect const* aurEff)
|
||||||
|
{
|
||||||
|
PreventDefaultAction();
|
||||||
|
Unit* target = GetTarget();
|
||||||
|
if (auto mana = int32(target->GetMaxPower(POWER_MANA) / 10))
|
||||||
|
{
|
||||||
|
mana = target->ModifyPower(POWER_MANA, -mana);
|
||||||
|
target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, nullptr, aurEff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_AuraScript::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AuraScript* GetAuraScript() const override
|
||||||
|
{
|
||||||
|
return new spell_kelthuzad_detonate_mana_AuraScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_kelthuzad_40()
|
||||||
|
{
|
||||||
|
new boss_kelthuzad_40();
|
||||||
|
new boss_kelthuzad_minion_40();
|
||||||
|
// new spell_kelthuzad_frost_blast();
|
||||||
|
// new spell_kelthuzad_detonate_mana();
|
||||||
|
}
|
||||||
201
src/naxx40Scripts/boss_loatheb_40.cpp
Normal file
201
src/naxx40Scripts/boss_loatheb_40.cpp
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_NECROTIC_AURA = 55593,
|
||||||
|
SPELL_SUMMON_SPORE = 29234,
|
||||||
|
SPELL_DEATHBLOOM = 29865,
|
||||||
|
SPELL_INEVITABLE_DOOM = 29204,
|
||||||
|
SPELL_BERSERK = 26662
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_NECROTIC_AURA = 1,
|
||||||
|
EVENT_DEATHBLOOM = 2,
|
||||||
|
EVENT_INEVITABLE_DOOM = 3,
|
||||||
|
EVENT_BERSERK = 4,
|
||||||
|
EVENT_SUMMON_SPORE = 5,
|
||||||
|
EVENT_NECROTIC_AURA_FADING = 6,
|
||||||
|
EVENT_NECROTIC_AURA_REMOVED = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Texts
|
||||||
|
{
|
||||||
|
SAY_NECROTIC_AURA_APPLIED = 0,
|
||||||
|
SAY_NECROTIC_AURA_REMOVED = 1,
|
||||||
|
SAY_NECROTIC_AURA_FADING = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_loatheb_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_loatheb_40() : CreatureScript("boss_loatheb_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_loatheb_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_loatheb_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_loatheb_40AI(Creature* c) : BossAI(c, BOSS_LOATHEB), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
uint8 doomCounter;
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
doomCounter = 0;
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(BOSS_LOATHEB, NOT_STARTED);
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_LOATHEB_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
cr->SetInCombatWithZone();
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonedCreatureDies(Creature* /*cr*/, Unit*) override
|
||||||
|
{
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_SPORE_KILLED, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
events.ScheduleEvent(EVENT_NECROTIC_AURA, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_DEATHBLOOM, 5000);
|
||||||
|
events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 120000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_SPORE, 15000);
|
||||||
|
events.ScheduleEvent(EVENT_BERSERK, 720000);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(BOSS_LOATHEB, IN_PROGRESS);
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_LOATHEB_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
summons.DespawnAll();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(BOSS_LOATHEB, DONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictim() || !IsInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_SUMMON_SPORE:
|
||||||
|
me->CastSpell(me, SPELL_SUMMON_SPORE, true);
|
||||||
|
events.RepeatEvent(35000);
|
||||||
|
break;
|
||||||
|
case EVENT_NECROTIC_AURA:
|
||||||
|
me->CastSpell(me, SPELL_NECROTIC_AURA, true);
|
||||||
|
Talk(SAY_NECROTIC_AURA_APPLIED);
|
||||||
|
events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14000);
|
||||||
|
events.ScheduleEvent(EVENT_NECROTIC_AURA_REMOVED, 17000);
|
||||||
|
events.RepeatEvent(20000);
|
||||||
|
break;
|
||||||
|
case EVENT_DEATHBLOOM:
|
||||||
|
me->CastSpell(me, SPELL_DEATHBLOOM, false);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
break;
|
||||||
|
case EVENT_INEVITABLE_DOOM:
|
||||||
|
me->CastSpell(me, SPELL_INEVITABLE_DOOM, false);
|
||||||
|
doomCounter++;
|
||||||
|
events.RepeatEvent(doomCounter < 6 ? 30000 : 15000);
|
||||||
|
break;
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
break;
|
||||||
|
case EVENT_NECROTIC_AURA_FADING:
|
||||||
|
Talk(SAY_NECROTIC_AURA_FADING);
|
||||||
|
break;
|
||||||
|
case EVENT_NECROTIC_AURA_REMOVED:
|
||||||
|
Talk(SAY_NECROTIC_AURA_REMOVED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInRoom()
|
||||||
|
{
|
||||||
|
// Calculate the distance between his home position to the gate
|
||||||
|
if (me->GetExactDist(me->GetHomePosition().GetPositionX(),
|
||||||
|
me->GetHomePosition().GetPositionY(),
|
||||||
|
me->GetHomePosition().GetPositionZ()) > 50.0f)
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_loatheb_40()
|
||||||
|
{
|
||||||
|
new boss_loatheb_40();
|
||||||
|
}
|
||||||
265
src/naxx40Scripts/boss_maexxna_40.cpp
Normal file
265
src/naxx40Scripts/boss_maexxna_40.cpp
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PassiveAI.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_WEB_WRAP = 28622,
|
||||||
|
SPELL_WEB_SPRAY = 29484,
|
||||||
|
SPELL_POISON_SHOCK = 28741,
|
||||||
|
SPELL_NECROTIC_POISON = 54121,
|
||||||
|
SPELL_FRENZY = 54123,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_WEB_SPRAY = 1,
|
||||||
|
EVENT_POISON_SHOCK = 2,
|
||||||
|
EVENT_NECROTIC_POISON = 3,
|
||||||
|
EVENT_WEB_WRAP = 4,
|
||||||
|
EVENT_HEALTH_CHECK = 5,
|
||||||
|
EVENT_SUMMON_SPIDERLINGS = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Emotes
|
||||||
|
{
|
||||||
|
EMOTE_SPIDERS = 0,
|
||||||
|
EMOTE_WEB_WRAP = 1,
|
||||||
|
EMOTE_WEB_SPRAY = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_WEB_WRAP = 351079,
|
||||||
|
NPC_MAEXXNA_SPIDERLING = 351088
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position PosWrap[3] =
|
||||||
|
{
|
||||||
|
{3546.796f, -3869.082f, 296.450f, 0.0f},
|
||||||
|
{3531.271f, -3847.424f, 299.450f, 0.0f},
|
||||||
|
{3497.067f, -3843.384f, 302.384f, 0.0f}
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_maexxna_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_maexxna_40() : CreatureScript("boss_maexxna_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_maexxna_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_maexxna_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_maexxna_40AI(Creature* c) : BossAI(c, BOSS_MAEXXNA), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
|
||||||
|
bool IsInRoom()
|
||||||
|
{
|
||||||
|
if (me->GetExactDist(3486.6f, -3890.6f, 291.8f) > 100.0f)
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
events.ScheduleEvent(EVENT_WEB_WRAP, 20000);
|
||||||
|
events.ScheduleEvent(EVENT_WEB_SPRAY, 40000);
|
||||||
|
events.ScheduleEvent(EVENT_POISON_SHOCK, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_NECROTIC_POISON, 5000);
|
||||||
|
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_SPIDERLINGS, 30000);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_MAEXXNA_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
if (cr->GetEntry() == NPC_MAEXXNA_SPIDERLING)
|
||||||
|
{
|
||||||
|
cr->SetInCombatWithZone();
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||||
|
{
|
||||||
|
cr->AI()->AttackStart(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
summons.DespawnAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!IsInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_WEB_SPRAY:
|
||||||
|
Talk(EMOTE_WEB_SPRAY);
|
||||||
|
me->CastSpell(me, SPELL_WEB_SPRAY, true);
|
||||||
|
events.RepeatEvent(40000);
|
||||||
|
break;
|
||||||
|
case EVENT_POISON_SHOCK:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_POISON_SHOCK, false);
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
break;
|
||||||
|
case EVENT_NECROTIC_POISON:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_NECROTIC_POISON, false);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_SPIDERLINGS:
|
||||||
|
Talk(EMOTE_SPIDERS);
|
||||||
|
for (uint8 i = 0; i < 8; ++i)
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_MAEXXNA_SPIDERLING, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||||
|
}
|
||||||
|
events.RepeatEvent(40000);
|
||||||
|
break;
|
||||||
|
case EVENT_HEALTH_CHECK:
|
||||||
|
if (me->GetHealthPct() < 30)
|
||||||
|
{
|
||||||
|
me->CastSpell(me, SPELL_FRENZY, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1000);
|
||||||
|
break;
|
||||||
|
case EVENT_WEB_WRAP:
|
||||||
|
Talk(EMOTE_WEB_WRAP);
|
||||||
|
for (uint8 i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 0, true, -SPELL_WEB_WRAP))
|
||||||
|
{
|
||||||
|
target->RemoveAura(SPELL_WEB_SPRAY);
|
||||||
|
uint8 pos = urand(0, 2);
|
||||||
|
if (Creature* wrap = me->SummonCreature(NPC_WEB_WRAP, PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 60000))
|
||||||
|
{
|
||||||
|
wrap->AI()->SetGUID(target->GetGUID());
|
||||||
|
target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(40000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_maexxna_webwrap : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_maexxna_webwrap() : CreatureScript("boss_maexxna_webwrap") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_maexxna_webwrapAI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_maexxna_webwrapAI : public NullCreatureAI
|
||||||
|
{
|
||||||
|
explicit boss_maexxna_webwrapAI(Creature* c) : NullCreatureAI(c) {}
|
||||||
|
|
||||||
|
ObjectGuid victimGUID;
|
||||||
|
|
||||||
|
void SetGUID(ObjectGuid guid, int32 /*param*/) override
|
||||||
|
{
|
||||||
|
victimGUID = guid;
|
||||||
|
|
||||||
|
if (me->m_spells[0] && victimGUID)
|
||||||
|
{
|
||||||
|
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
|
||||||
|
{
|
||||||
|
victim->CastSpell(victim, me->m_spells[0], true, nullptr, nullptr, me->GetGUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* /*killer*/) override
|
||||||
|
{
|
||||||
|
if (me->m_spells[0] && victimGUID)
|
||||||
|
{
|
||||||
|
if (Unit* victim = ObjectAccessor::GetUnit(*me, victimGUID))
|
||||||
|
{
|
||||||
|
victim->RemoveAurasDueToSpell(me->m_spells[0], me->GetGUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_maexxna_40()
|
||||||
|
{
|
||||||
|
new boss_maexxna_40();
|
||||||
|
// new boss_maexxna_webwrap();
|
||||||
|
}
|
||||||
303
src/naxx40Scripts/boss_noth_40.cpp
Normal file
303
src/naxx40Scripts/boss_noth_40.cpp
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Says
|
||||||
|
{
|
||||||
|
SAY_AGGRO = 0,
|
||||||
|
SAY_SUMMON = 1,
|
||||||
|
SAY_SLAY = 2,
|
||||||
|
SAY_DEATH = 3,
|
||||||
|
EMOTE_SUMMON = 4,
|
||||||
|
EMOTE_SUMMON_WAVE = 5,
|
||||||
|
EMOTE_TELEPORT_BALCONY = 6,
|
||||||
|
EMOTE_TELEPORT_BACK = 7,
|
||||||
|
EMOTE_BLINK = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_CURSE_OF_THE_PLAGUEBRINGER = 29213,
|
||||||
|
SPELL_CRIPPLE = 29212,
|
||||||
|
SPELL_SUMMON_PLAGUED_WARRIORS = 29237,
|
||||||
|
SPELL_TELEPORT = 29216,
|
||||||
|
SPELL_TELEPORT_BACK = 29231,
|
||||||
|
SPELL_BERSERK = 68378,
|
||||||
|
SPELL_BLINK = 29208
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_CURSE = 1,
|
||||||
|
EVENT_CRIPPLE = 2,
|
||||||
|
EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE = 3,
|
||||||
|
EVENT_MOVE_TO_BALCONY = 4,
|
||||||
|
EVENT_BLINK = 5,
|
||||||
|
EVENT_MOVE_TO_GROUND = 6,
|
||||||
|
EVENT_SUMMON_PLAGUED_WARRIOR_REAL = 7,
|
||||||
|
EVENT_BALCONY_SUMMON_ANNOUNCE = 8,
|
||||||
|
EVENT_BALCONY_SUMMON_REAL = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_PLAGUED_WARRIOR = 351088,
|
||||||
|
NPC_PLAGUED_CHAMPION = 351087,
|
||||||
|
NPC_PLAGUED_GUARDIAN = 351086
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position summoningPosition[5] =
|
||||||
|
{
|
||||||
|
{2728.06f, -3535.38f, 263.21f, 2.75f},
|
||||||
|
{2725.71f, -3514.80f, 263.23f, 2.86f},
|
||||||
|
{2728.24f, -3465.08f, 264.20f, 3.56f},
|
||||||
|
{2704.79f, -3459.17f, 263.74f, 4.25f},
|
||||||
|
{2652.02f, -3459.13f, 262.50f, 5.39f}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Position nothPosition = {2684.94f, -3502.53f, 261.31f, 4.7f};
|
||||||
|
|
||||||
|
class boss_noth_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_noth_40() : CreatureScript("boss_noth_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_noth_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_noth_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_noth_40AI(Creature* c) : BossAI(c, BOSS_NOTH), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
uint8 timesInBalcony;
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
|
||||||
|
void StartGroundPhase()
|
||||||
|
{
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->SetControlled(false, UNIT_STATE_ROOT);
|
||||||
|
events.Reset();
|
||||||
|
events.ScheduleEvent(EVENT_MOVE_TO_BALCONY, 110000);
|
||||||
|
events.ScheduleEvent(EVENT_CURSE, 15000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE, 10000);
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_BLINK, 26000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartBalconyPhase()
|
||||||
|
{
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
me->AttackStop();
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||||
|
events.Reset();
|
||||||
|
events.ScheduleEvent(EVENT_BALCONY_SUMMON_ANNOUNCE, 4000);
|
||||||
|
events.ScheduleEvent(EVENT_MOVE_TO_GROUND, 70000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SummonHelper(uint32 entry, uint32 count)
|
||||||
|
{
|
||||||
|
for (uint8 i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
me->SummonCreature(entry, summoningPosition[urand(0, 4)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInRoom()
|
||||||
|
{
|
||||||
|
if (me->GetExactDist(2684.8f, -3502.5f, 261.3f) > 80.0f)
|
||||||
|
{
|
||||||
|
EnterEvadeMode(EVADE_REASON_OTHER);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT_BACK, true);
|
||||||
|
me->SetControlled(false, UNIT_STATE_ROOT);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
timesInBalcony = 0;
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_NOTH_ENTRY_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterEvadeMode(EvadeReason why) override
|
||||||
|
{
|
||||||
|
me->SetControlled(false, UNIT_STATE_ROOT);
|
||||||
|
ScriptedAI::EnterEvadeMode(why);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
StartGroundPhase();
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_NOTH_ENTRY_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* summon) override
|
||||||
|
{
|
||||||
|
summons.Summon(summon);
|
||||||
|
summon->SetInCombatWithZone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
if (me->GetPositionZ() > 270.27f)
|
||||||
|
{
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_DISABLE_MOVE);
|
||||||
|
me->NearTeleportTo(nothPosition.GetPositionX(), nothPosition.GetPositionY(), nothPosition.GetPositionZ(), nothPosition.GetOrientation(), true);
|
||||||
|
}
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_NOTH_ENTRY_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!IsInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
// GROUND
|
||||||
|
case EVENT_CURSE:
|
||||||
|
if (events.GetPhaseMask() == 0)
|
||||||
|
{
|
||||||
|
me->CastCustomSpell(SPELL_CURSE_OF_THE_PLAGUEBRINGER, SPELLVALUE_MAX_TARGETS, 10, me, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(25000);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE:
|
||||||
|
Talk(SAY_SUMMON);
|
||||||
|
Talk(EMOTE_SUMMON);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_REAL, 4000);
|
||||||
|
break;
|
||||||
|
case EVENT_SUMMON_PLAGUED_WARRIOR_REAL:
|
||||||
|
me->CastSpell(me, SPELL_SUMMON_PLAGUED_WARRIORS, true);
|
||||||
|
SummonHelper(NPC_PLAGUED_WARRIOR, 3);
|
||||||
|
break;
|
||||||
|
case EVENT_MOVE_TO_BALCONY:
|
||||||
|
Talk(EMOTE_TELEPORT_BALCONY);
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT, true);
|
||||||
|
StartBalconyPhase();
|
||||||
|
break;
|
||||||
|
case EVENT_BLINK:
|
||||||
|
DoResetThreat();
|
||||||
|
me->CastSpell(me, SPELL_CRIPPLE, false);
|
||||||
|
me->CastSpell(me, SPELL_BLINK, true);
|
||||||
|
Talk(EMOTE_BLINK);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
break;
|
||||||
|
// BALCONY
|
||||||
|
case EVENT_BALCONY_SUMMON_ANNOUNCE:
|
||||||
|
Talk(EMOTE_SUMMON_WAVE);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
events.ScheduleEvent(EVENT_BALCONY_SUMMON_REAL, 4000);
|
||||||
|
break;
|
||||||
|
case EVENT_BALCONY_SUMMON_REAL:
|
||||||
|
me->CastSpell(me, SPELL_SUMMON_PLAGUED_WARRIORS, true); // visual
|
||||||
|
switch (timesInBalcony)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
SummonHelper(NPC_PLAGUED_CHAMPION, 4);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
SummonHelper(NPC_PLAGUED_CHAMPION, 2);
|
||||||
|
SummonHelper(NPC_PLAGUED_GUARDIAN, 2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
SummonHelper(NPC_PLAGUED_GUARDIAN, 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_MOVE_TO_GROUND:
|
||||||
|
Talk(EMOTE_TELEPORT_BACK);
|
||||||
|
me->CastSpell(me, SPELL_TELEPORT_BACK, true);
|
||||||
|
timesInBalcony++;
|
||||||
|
if (timesInBalcony == 3)
|
||||||
|
{
|
||||||
|
DoCastSelf(SPELL_BERSERK);
|
||||||
|
}
|
||||||
|
StartGroundPhase();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (me->HasReactState(REACT_AGGRESSIVE))
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_noth_40()
|
||||||
|
{
|
||||||
|
new boss_noth_40();
|
||||||
|
}
|
||||||
190
src/naxx40Scripts/boss_patchwerk_40.cpp
Normal file
190
src/naxx40Scripts/boss_patchwerk_40.cpp
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Yells
|
||||||
|
{
|
||||||
|
SAY_AGGRO = 0,
|
||||||
|
SAY_SLAY = 1,
|
||||||
|
SAY_DEATH = 2,
|
||||||
|
EMOTE_BERSERK = 3,
|
||||||
|
EMOTE_ENRAGE = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_HATEFUL_STRIKE = 28308,
|
||||||
|
SPELL_FRENZY = 28131,
|
||||||
|
SPELL_BERSERK = 26662,
|
||||||
|
SPELL_SLIME_BOLT = 32309
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_HEALTH_CHECK = 1,
|
||||||
|
EVENT_HATEFUL_STRIKE = 2,
|
||||||
|
EVENT_SLIME_BOLT = 3,
|
||||||
|
EVENT_BERSERK = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_patchwerk_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_patchwerk_40() : CreatureScript("boss_patchwerk_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_patchwerk_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_patchwerk_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_patchwerk_40AI(Creature* c) : BossAI(c, BOSS_PATCHWERK)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!urand(0, 3))
|
||||||
|
{
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
}
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 1200);
|
||||||
|
events.ScheduleEvent(EVENT_BERSERK, 7 * 60 * 1000); // 7 minutes enrange
|
||||||
|
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_HATEFUL_STRIKE:
|
||||||
|
{
|
||||||
|
// Cast Hateful strike on the player with the highest amount of HP within melee distance, and second threat amount
|
||||||
|
std::list<Unit*> meleeRangeTargets;
|
||||||
|
Unit* finalTarget = nullptr;
|
||||||
|
uint8 counter = 0;
|
||||||
|
auto i = me->GetThreatMgr().getThreatList().begin();
|
||||||
|
for (; i != me->GetThreatMgr().getThreatList().end(); ++i, ++counter)
|
||||||
|
{
|
||||||
|
// Gather all units with melee range
|
||||||
|
Unit* target = (*i)->getTarget();
|
||||||
|
if (me->IsWithinMeleeRange(target))
|
||||||
|
{
|
||||||
|
meleeRangeTargets.push_back(target);
|
||||||
|
}
|
||||||
|
// and add threat to most hated
|
||||||
|
if (counter < 3)
|
||||||
|
{
|
||||||
|
me->AddThreat(target, 500.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
counter = 0;
|
||||||
|
std::list<Unit*, std::allocator<Unit*>>::iterator itr;
|
||||||
|
for (itr = meleeRangeTargets.begin(); itr != meleeRangeTargets.end(); ++itr, ++counter)
|
||||||
|
{
|
||||||
|
// if there is only one target available
|
||||||
|
if (meleeRangeTargets.size() == 1)
|
||||||
|
{
|
||||||
|
finalTarget = (*itr);
|
||||||
|
}
|
||||||
|
else if (counter > 0) // skip first target
|
||||||
|
{
|
||||||
|
if (!finalTarget || (*itr)->GetHealth() > finalTarget->GetHealth())
|
||||||
|
{
|
||||||
|
finalTarget = (*itr);
|
||||||
|
}
|
||||||
|
// third loop
|
||||||
|
if (counter >= 2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (finalTarget)
|
||||||
|
{
|
||||||
|
me->CastSpell(finalTarget, SPELL_HATEFUL_STRIKE, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1200);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
Talk(EMOTE_BERSERK);
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
events.ScheduleEvent(EVENT_SLIME_BOLT, 3000);
|
||||||
|
break;
|
||||||
|
case EVENT_SLIME_BOLT:
|
||||||
|
me->CastSpell(me, SPELL_SLIME_BOLT, false);
|
||||||
|
events.RepeatEvent(3000);
|
||||||
|
break;
|
||||||
|
case EVENT_HEALTH_CHECK:
|
||||||
|
if (me->GetHealthPct() <= 5)
|
||||||
|
{
|
||||||
|
Talk(EMOTE_ENRAGE);
|
||||||
|
me->CastSpell(me, SPELL_FRENZY, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_patchwerk_40()
|
||||||
|
{
|
||||||
|
new boss_patchwerk_40();
|
||||||
|
}
|
||||||
232
src/naxx40Scripts/boss_razuvious_40.cpp
Normal file
232
src/naxx40Scripts/boss_razuvious_40.cpp
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Says
|
||||||
|
{
|
||||||
|
SAY_AGGRO = 0,
|
||||||
|
SAY_SLAY = 1,
|
||||||
|
SAY_TAUNTED = 2,
|
||||||
|
SAY_DEATH = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_UNBALANCING_STRIKE = 26613,
|
||||||
|
SPELL_DISRUPTING_SHOUT = 29107,
|
||||||
|
SPELL_JAGGED_KNIFE = 55550,
|
||||||
|
SPELL_HOPELESS = 29125,
|
||||||
|
|
||||||
|
SPELL_TAUNT = 29060
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_UNBALANCING_STRIKE = 1,
|
||||||
|
EVENT_DISRUPTING_SHOUT = 2,
|
||||||
|
EVENT_JAGGED_KNIFE = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
NPC_DEATH_KNIGHT_UNDERSTUDY = 351084,
|
||||||
|
NPC_RAZUVIOUS = 351036
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_razuvious_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_razuvious_40() : CreatureScript("boss_razuvious_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_razuvious_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_razuvious_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_razuvious_40AI(Creature* c) : BossAI(c, BOSS_RAZUVIOUS), summons(me)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
|
||||||
|
void SpawnHelpers()
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2762.23f, -3085.07f, 267.685f, 1.95f);
|
||||||
|
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2758.24f, -3110.97f, 267.685f, 3.94f);
|
||||||
|
if (Is25ManRaid())
|
||||||
|
{
|
||||||
|
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2782.45f, -3088.03f, 267.685f, 0.75f);
|
||||||
|
me->SummonCreature(NPC_DEATH_KNIGHT_UNDERSTUDY, 2778.56f, -3113.74f, 267.685f, 5.28f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
events.Reset();
|
||||||
|
SpawnHelpers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (roll_chance_i(30))
|
||||||
|
{
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
}
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||||
|
{
|
||||||
|
// Damage done by the controlled Death Knight understudies should also count toward damage done by players
|
||||||
|
if(who && who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_DEATH_KNIGHT_UNDERSTUDY)
|
||||||
|
{
|
||||||
|
me->LowerPlayerDamageReq(damage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
me->CastSpell(me, SPELL_HOPELESS, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||||
|
{
|
||||||
|
if (spell->Id == SPELL_TAUNT)
|
||||||
|
{
|
||||||
|
Talk(SAY_TAUNTED, caster);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
events.ScheduleEvent(EVENT_UNBALANCING_STRIKE, 20000);
|
||||||
|
events.ScheduleEvent(EVENT_DISRUPTING_SHOUT, 15000);
|
||||||
|
events.ScheduleEvent(EVENT_JAGGED_KNIFE, 10000);
|
||||||
|
summons.DoZoneInCombat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_UNBALANCING_STRIKE:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_UNBALANCING_STRIKE, false);
|
||||||
|
events.RepeatEvent(20000);
|
||||||
|
break;
|
||||||
|
case EVENT_DISRUPTING_SHOUT:
|
||||||
|
me->CastSpell(me, SPELL_DISRUPTING_SHOUT, false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
break;
|
||||||
|
case EVENT_JAGGED_KNIFE:
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45.0f))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_JAGGED_KNIFE, false);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_razuvious_minion_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_razuvious_minion_40() : CreatureScript("boss_razuvious_minion_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_razuvious_minion_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_razuvious_minion_40AI : public ScriptedAI
|
||||||
|
{
|
||||||
|
explicit boss_razuvious_minion_40AI(Creature* c) : ScriptedAI(c) { }
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
events.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript())
|
||||||
|
{
|
||||||
|
me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
if (Creature* cr = me->FindNearestCreature(NPC_RAZUVIOUS, 100.0f))
|
||||||
|
{
|
||||||
|
cr->SetInCombatWithZone();
|
||||||
|
cr->AI()->AttackStart(who);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (UpdateVictim())
|
||||||
|
{
|
||||||
|
events.Update(diff);
|
||||||
|
if (!me->HasUnitState(UNIT_STATE_CASTING) || !me->IsCharmed())
|
||||||
|
{
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_razuvious_40()
|
||||||
|
{
|
||||||
|
new boss_razuvious_40();
|
||||||
|
new boss_razuvious_minion_40();
|
||||||
|
}
|
||||||
462
src/naxx40Scripts/boss_sapphiron_40.cpp
Normal file
462
src/naxx40Scripts/boss_sapphiron_40.cpp
Normal file
@@ -0,0 +1,462 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Yells
|
||||||
|
{
|
||||||
|
EMOTE_AIR_PHASE = 0,
|
||||||
|
EMOTE_GROUND_PHASE = 1,
|
||||||
|
EMOTE_BREATH = 2,
|
||||||
|
EMOTE_ENRAGE = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
// Fight
|
||||||
|
SPELL_FROST_AURA = 28531,
|
||||||
|
SPELL_CLEAVE = 19983,
|
||||||
|
SPELL_TAIL_SWEEP = 15847,
|
||||||
|
SPELL_SUMMON_BLIZZARD = 28560,
|
||||||
|
SPELL_LIFE_DRAIN = 28542,
|
||||||
|
SPELL_BERSERK = 26662,
|
||||||
|
|
||||||
|
// Ice block
|
||||||
|
SPELL_ICEBOLT_CAST = 28526,
|
||||||
|
SPELL_ICEBOLT_TRIGGER = 28522,
|
||||||
|
SPELL_FROST_MISSILE = 30101,
|
||||||
|
SPELL_FROST_EXPLOSION = 28524,
|
||||||
|
|
||||||
|
// Visuals
|
||||||
|
SPELL_SAPPHIRON_DIES = 29357
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
GO_ICE_BLOCK = 181247,
|
||||||
|
NPC_BLIZZARD = 16474,
|
||||||
|
|
||||||
|
POINT_CENTER = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_BERSERK = 1,
|
||||||
|
EVENT_CLEAVE = 2,
|
||||||
|
EVENT_TAIL_SWEEP = 3,
|
||||||
|
EVENT_LIFE_DRAIN = 4,
|
||||||
|
EVENT_BLIZZARD = 5,
|
||||||
|
EVENT_FLIGHT_START = 6,
|
||||||
|
EVENT_FLIGHT_LIFTOFF = 7,
|
||||||
|
EVENT_FLIGHT_ICEBOLT = 8,
|
||||||
|
EVENT_FLIGHT_BREATH = 9,
|
||||||
|
EVENT_FLIGHT_SPELL_EXPLOSION = 10,
|
||||||
|
EVENT_FLIGHT_START_LAND = 11,
|
||||||
|
EVENT_LAND = 12,
|
||||||
|
EVENT_GROUND = 13,
|
||||||
|
EVENT_HUNDRED_CLUB = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_sapphiron_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_sapphiron_40() : CreatureScript("boss_sapphiron_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_sapphiron_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_sapphiron_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_sapphiron_40AI(Creature* c) : BossAI(c, BOSS_SAPPHIRON)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
EventMap events;
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
uint8 iceboltCount{};
|
||||||
|
uint32 spawnTimer{};
|
||||||
|
GuidList blockList;
|
||||||
|
ObjectGuid currentTarget;
|
||||||
|
|
||||||
|
void InitializeAI() override
|
||||||
|
{
|
||||||
|
me->SummonGameObject(GO_SAPPHIRON_BIRTH, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0);
|
||||||
|
me->SetVisible(false);
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
ScriptedAI::InitializeAI();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInRoom()
|
||||||
|
{
|
||||||
|
if (me->GetExactDist(3523.5f, -5235.3f, 137.6f) > 100.0f)
|
||||||
|
{
|
||||||
|
EnterEvadeMode();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
if (me->IsVisible())
|
||||||
|
{
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
}
|
||||||
|
events.Reset();
|
||||||
|
iceboltCount = 0;
|
||||||
|
spawnTimer = 0;
|
||||||
|
currentTarget.Clear();
|
||||||
|
blockList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombatSelfFunction()
|
||||||
|
{
|
||||||
|
Map::PlayerList const& PlList = me->GetMap()->GetPlayers();
|
||||||
|
if (PlList.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const auto& i : PlList)
|
||||||
|
{
|
||||||
|
if (Player* player = i.GetSource())
|
||||||
|
{
|
||||||
|
if (player->IsGameMaster())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (player->IsAlive() && me->GetDistance(player) < 80.0f)
|
||||||
|
{
|
||||||
|
me->SetInCombatWith(player);
|
||||||
|
player->SetInCombatWith(me);
|
||||||
|
me->AddThreat(player, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
EnterCombatSelfFunction();
|
||||||
|
me->CastSpell(me, SPELL_FROST_AURA, true);
|
||||||
|
events.ScheduleEvent(EVENT_BERSERK, 900000);
|
||||||
|
events.ScheduleEvent(EVENT_CLEAVE, 5000);
|
||||||
|
events.ScheduleEvent(EVENT_TAIL_SWEEP, 10000);
|
||||||
|
events.ScheduleEvent(EVENT_LIFE_DRAIN, 17000);
|
||||||
|
events.ScheduleEvent(EVENT_BLIZZARD, 17000);
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_START, 45000);
|
||||||
|
events.ScheduleEvent(EVENT_HUNDRED_CLUB, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
me->CastSpell(me, SPELL_SAPPHIRON_DIES, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoAction(int32 param) override
|
||||||
|
{
|
||||||
|
if (param == ACTION_SAPPHIRON_BIRTH)
|
||||||
|
{
|
||||||
|
spawnTimer = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MovementInform(uint32 type, uint32 id) override
|
||||||
|
{
|
||||||
|
if (type == POINT_MOTION_TYPE && id == POINT_CENTER)
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_LIFTOFF, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpellHitTarget(Unit* target, SpellInfo const* spellInfo) override
|
||||||
|
{
|
||||||
|
if (spellInfo->Id == SPELL_ICEBOLT_CAST)
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_ICEBOLT_TRIGGER, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidExplosionTarget(WorldObject* target)
|
||||||
|
{
|
||||||
|
for (ObjectGuid const& guid : blockList)
|
||||||
|
{
|
||||||
|
if (target->GetGUID() == guid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Unit* block = ObjectAccessor::GetUnit(*me, guid))
|
||||||
|
{
|
||||||
|
if (block->IsInBetween(me, target, 2.0f) && block->IsWithinDist(target, 10.0f))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() == TYPEID_PLAYER && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (spawnTimer)
|
||||||
|
{
|
||||||
|
spawnTimer += diff;
|
||||||
|
if (spawnTimer >= 21500)
|
||||||
|
{
|
||||||
|
me->SetVisible(true);
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
spawnTimer = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsInRoom())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_BERSERK:
|
||||||
|
Talk(EMOTE_ENRAGE);
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
return;
|
||||||
|
case EVENT_CLEAVE:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_CLEAVE, false);
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
return;
|
||||||
|
case EVENT_TAIL_SWEEP:
|
||||||
|
me->CastSpell(me, SPELL_TAIL_SWEEP, false);
|
||||||
|
events.RepeatEvent(10000);
|
||||||
|
return;
|
||||||
|
case EVENT_LIFE_DRAIN:
|
||||||
|
me->CastCustomSpell(SPELL_LIFE_DRAIN, SPELLVALUE_MAX_TARGETS, 5, me, false);
|
||||||
|
events.RepeatEvent(24000);
|
||||||
|
return;
|
||||||
|
case EVENT_BLIZZARD:
|
||||||
|
{
|
||||||
|
Creature* cr;
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||||
|
{
|
||||||
|
cr = me->SummonCreature(NPC_BLIZZARD, *target, TEMPSUMMON_TIMED_DESPAWN, 16000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cr = me->SummonCreature(NPC_BLIZZARD, *me, TEMPSUMMON_TIMED_DESPAWN, 16000);
|
||||||
|
}
|
||||||
|
if (cr)
|
||||||
|
{
|
||||||
|
cr->GetMotionMaster()->MoveRandom(40);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(6500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case EVENT_FLIGHT_START:
|
||||||
|
if (me->HealthBelowPct(11))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
events.RepeatEvent(45000);
|
||||||
|
events.DelayEvents(35000);
|
||||||
|
me->SetReactState(REACT_PASSIVE);
|
||||||
|
me->AttackStop();
|
||||||
|
float x, y, z, o;
|
||||||
|
me->GetHomePosition(x, y, z, o);
|
||||||
|
me->GetMotionMaster()->MovePoint(POINT_CENTER, x, y, z);
|
||||||
|
return;
|
||||||
|
case EVENT_FLIGHT_LIFTOFF:
|
||||||
|
Talk(EMOTE_AIR_PHASE);
|
||||||
|
me->GetMotionMaster()->MoveIdle();
|
||||||
|
me->SendMeleeAttackStop(me->GetVictim());
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||||
|
me->SetDisableGravity(true);
|
||||||
|
currentTarget.Clear();
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_ICEBOLT, 3000);
|
||||||
|
iceboltCount = 3;
|
||||||
|
return;
|
||||||
|
case EVENT_FLIGHT_ICEBOLT:
|
||||||
|
{
|
||||||
|
if (currentTarget)
|
||||||
|
{
|
||||||
|
if (Unit* target = ObjectAccessor::GetUnit(*me, currentTarget))
|
||||||
|
{
|
||||||
|
me->SummonGameObject(GO_ICE_BLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Unit*> targets;
|
||||||
|
auto i = me->GetThreatMgr().getThreatList().begin();
|
||||||
|
for (; i != me->GetThreatMgr().getThreatList().end(); ++i)
|
||||||
|
{
|
||||||
|
if ((*i)->getTarget()->GetTypeId() == TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
bool inList = false;
|
||||||
|
if (!blockList.empty())
|
||||||
|
{
|
||||||
|
for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((*i)->getTarget()->GetGUID() == *itr)
|
||||||
|
{
|
||||||
|
inList = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inList)
|
||||||
|
{
|
||||||
|
targets.push_back((*i)->getTarget());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targets.empty() && iceboltCount)
|
||||||
|
{
|
||||||
|
auto itr = targets.begin();
|
||||||
|
advance(itr, urand(0, targets.size() - 1));
|
||||||
|
me->CastSpell(*itr, SPELL_ICEBOLT_CAST, false);
|
||||||
|
blockList.push_back((*itr)->GetGUID());
|
||||||
|
currentTarget = (*itr)->GetGUID();
|
||||||
|
--iceboltCount;
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_ICEBOLT, (me->GetExactDist(*itr) / 13.0f)*IN_MILLISECONDS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_BREATH, 1000);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case EVENT_FLIGHT_BREATH:
|
||||||
|
currentTarget.Clear();
|
||||||
|
Talk(EMOTE_BREATH);
|
||||||
|
me->CastSpell(me, SPELL_FROST_MISSILE, false);
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_SPELL_EXPLOSION, 8500);
|
||||||
|
return;
|
||||||
|
case EVENT_FLIGHT_SPELL_EXPLOSION:
|
||||||
|
me->CastSpell(me, SPELL_FROST_EXPLOSION, true);
|
||||||
|
events.ScheduleEvent(EVENT_FLIGHT_START_LAND, 3000);
|
||||||
|
return;
|
||||||
|
case EVENT_FLIGHT_START_LAND:
|
||||||
|
if (!blockList.empty())
|
||||||
|
{
|
||||||
|
for (GuidList::const_iterator itr = blockList.begin(); itr != blockList.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (Unit* block = ObjectAccessor::GetUnit(*me, *itr))
|
||||||
|
{
|
||||||
|
block->RemoveAurasDueToSpell(SPELL_ICEBOLT_TRIGGER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockList.clear();
|
||||||
|
me->RemoveAllGameObjects();
|
||||||
|
events.ScheduleEvent(EVENT_LAND, 1000);
|
||||||
|
return;
|
||||||
|
case EVENT_LAND:
|
||||||
|
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||||
|
me->SetDisableGravity(false);
|
||||||
|
events.ScheduleEvent(EVENT_GROUND, 1500);
|
||||||
|
return;
|
||||||
|
case EVENT_GROUND:
|
||||||
|
Talk(EMOTE_GROUND_PHASE);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
return;
|
||||||
|
case EVENT_HUNDRED_CLUB:
|
||||||
|
{
|
||||||
|
Map::PlayerList const& pList = me->GetMap()->GetPlayers();
|
||||||
|
for (const auto& itr : pList)
|
||||||
|
{
|
||||||
|
if (itr.GetSource()->GetResistance(SPELL_SCHOOL_FROST) > 100 && pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_HUNDRED_CLUB, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(5000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_sapphiron_frost_explosion : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_sapphiron_frost_explosion() : SpellScriptLoader("spell_sapphiron_frost_explosion") { }
|
||||||
|
|
||||||
|
class spell_sapphiron_frost_explosion_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_sapphiron_frost_explosion_SpellScript);
|
||||||
|
|
||||||
|
void FilterTargets(std::list<WorldObject*>& targets)
|
||||||
|
{
|
||||||
|
Unit* caster = GetCaster();
|
||||||
|
if (!caster || !caster->ToCreature())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::list<WorldObject*> tmplist;
|
||||||
|
for (auto& target : targets)
|
||||||
|
{
|
||||||
|
if (CAST_AI(boss_sapphiron_40::boss_sapphiron_40AI, caster->ToCreature()->AI())->IsValidExplosionTarget(target))
|
||||||
|
{
|
||||||
|
tmplist.push_back(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targets.clear();
|
||||||
|
for (auto& itr : tmplist)
|
||||||
|
{
|
||||||
|
targets.push_back(itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_explosion_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_sapphiron_frost_explosion_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_sapphiron_40()
|
||||||
|
{
|
||||||
|
new boss_sapphiron_40();
|
||||||
|
// new spell_sapphiron_frost_explosion();
|
||||||
|
}
|
||||||
772
src/naxx40Scripts/boss_thaddius_40.cpp
Normal file
772
src/naxx40Scripts/boss_thaddius_40.cpp
Normal file
@@ -0,0 +1,772 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ScriptMgr.h"
|
||||||
|
#include "ScriptedCreature.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
#include "naxxramas.h"
|
||||||
|
|
||||||
|
enum Says
|
||||||
|
{
|
||||||
|
// Stalagg
|
||||||
|
SAY_STAL_AGGRO = 0,
|
||||||
|
SAY_STAL_SLAY = 1,
|
||||||
|
SAY_STAL_DEATH = 2,
|
||||||
|
EMOTE_STAL_DEATH = 3,
|
||||||
|
EMOTE_STAL_REVIVE = 4,
|
||||||
|
|
||||||
|
// Feugen
|
||||||
|
SAY_FEUG_AGGRO = 0,
|
||||||
|
SAY_FEUG_SLAY = 1,
|
||||||
|
SAY_FEUG_DEATH = 2,
|
||||||
|
EMOTE_FEUG_DEATH = 3,
|
||||||
|
EMOTE_FEUG_REVIVE = 4,
|
||||||
|
|
||||||
|
// Thaddius
|
||||||
|
SAY_GREET = 0,
|
||||||
|
SAY_AGGRO = 1,
|
||||||
|
SAY_SLAY = 2,
|
||||||
|
SAY_ELECT = 3,
|
||||||
|
SAY_DEATH = 4,
|
||||||
|
EMOTE_POLARITY_SHIFTED = 6,
|
||||||
|
|
||||||
|
// Tesla Coil
|
||||||
|
EMOTE_TESLA_LINK_BREAKS = 0,
|
||||||
|
EMOTE_TESLA_OVERLOAD = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Spells
|
||||||
|
{
|
||||||
|
SPELL_MAGNETIC_PULL = 28337,
|
||||||
|
SPELL_TESLA_SHOCK = 28099,
|
||||||
|
SPELL_SHOCK_VISUAL = 28159,
|
||||||
|
|
||||||
|
// Stalagg
|
||||||
|
SPELL_POWER_SURGE = 28134,
|
||||||
|
SPELL_STALAGG_CHAIN = 28096,
|
||||||
|
|
||||||
|
// Feugen
|
||||||
|
SPELL_STATIC_FIELD = 28135,
|
||||||
|
SPELL_FEUGEN_CHAIN = 28111,
|
||||||
|
|
||||||
|
// Thaddius
|
||||||
|
SPELL_POLARITY_SHIFT = 28089,
|
||||||
|
SPELL_BALL_LIGHTNING = 28299,
|
||||||
|
SPELL_CHAIN_LIGHTNING = 28167,
|
||||||
|
SPELL_BERSERK = 27680,
|
||||||
|
SPELL_THADDIUS_VISUAL_LIGHTNING = 28136,
|
||||||
|
SPELL_THADDIUS_SPAWN_STUN = 28160,
|
||||||
|
|
||||||
|
SPELL_POSITIVE_CHARGE = 28062,
|
||||||
|
SPELL_POSITIVE_CHARGE_STACK = 29659,
|
||||||
|
SPELL_NEGATIVE_CHARGE = 28085,
|
||||||
|
SPELL_NEGATIVE_CHARGE_STACK = 29660,
|
||||||
|
SPELL_POSITIVE_POLARITY = 28059,
|
||||||
|
SPELL_NEGATIVE_POLARITY = 28084
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Events
|
||||||
|
{
|
||||||
|
EVENT_MINION_POWER_SURGE = 1,
|
||||||
|
EVENT_MINION_MAGNETIC_PULL = 2,
|
||||||
|
EVENT_MINION_CHECK_DISTANCE = 3,
|
||||||
|
EVENT_MINION_STATIC_FIELD = 4,
|
||||||
|
|
||||||
|
EVENT_THADDIUS_INIT = 5,
|
||||||
|
EVENT_THADDIUS_ENTER_COMBAT = 6,
|
||||||
|
EVENT_THADDIUS_CHAIN_LIGHTNING = 7,
|
||||||
|
EVENT_THADDIUS_BERSERK = 8,
|
||||||
|
EVENT_THADDIUS_POLARITY_SHIFT = 9,
|
||||||
|
EVENT_ALLOW_BALL_LIGHTNING = 10
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Misc
|
||||||
|
{
|
||||||
|
ACTION_MAGNETIC_PULL = 1,
|
||||||
|
ACTION_SUMMON_DIED = 2,
|
||||||
|
ACTION_RESTORE = 3,
|
||||||
|
GO_TESLA_COIL_LEFT = 181478,
|
||||||
|
GO_TESLA_COIL_RIGHT = 181477,
|
||||||
|
NPC_TESLA_COIL = 16218
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_thaddius_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_thaddius_40() : CreatureScript("boss_thaddius_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_thaddius_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_thaddius_40AI : public BossAI
|
||||||
|
{
|
||||||
|
explicit boss_thaddius_40AI(Creature* c) : BossAI(c, BOSS_THADDIUS), summons(me), ballLightningEnabled(false)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
EventMap events;
|
||||||
|
SummonList summons;
|
||||||
|
uint32 summonTimer{};
|
||||||
|
uint32 reviveTimer{};
|
||||||
|
uint32 resetTimer{};
|
||||||
|
bool ballLightningEnabled;
|
||||||
|
|
||||||
|
void DoAction(int32 param) override
|
||||||
|
{
|
||||||
|
if (param == ACTION_SUMMON_DIED)
|
||||||
|
{
|
||||||
|
if (summonTimer)
|
||||||
|
{
|
||||||
|
summonTimer = 0;
|
||||||
|
reviveTimer = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
summonTimer = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
BossAI::Reset();
|
||||||
|
events.Reset();
|
||||||
|
summons.DespawnAll();
|
||||||
|
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||||
|
me->SetControlled(true, UNIT_STATE_ROOT);
|
||||||
|
summonTimer = 0;
|
||||||
|
reviveTimer = 0;
|
||||||
|
resetTimer = 1;
|
||||||
|
me->SetPosition(me->GetHomePosition());
|
||||||
|
ballLightningEnabled = false;
|
||||||
|
|
||||||
|
me->SummonCreature(NPC_STALAGG_40, 3450.45f, -2931.42f, 312.091f, 5.49779f);
|
||||||
|
me->SummonCreature(NPC_FEUGEN_40, 3508.14f, -2988.65f, 312.092f, 2.37365f);
|
||||||
|
if (Creature* cr = me->SummonCreature(NPC_TESLA_COIL, 3527.34f, -2951.56f, 318.75f, 0.0f))
|
||||||
|
{
|
||||||
|
cr->RemoveAllAuras();
|
||||||
|
cr->InterruptNonMeleeSpells(true);
|
||||||
|
cr->CastSpell(cr, SPELL_FEUGEN_CHAIN, false);
|
||||||
|
cr->SetDisableGravity(true);
|
||||||
|
cr->SetImmuneToPC(false);
|
||||||
|
cr->SetControlled(true, UNIT_STATE_ROOT);
|
||||||
|
}
|
||||||
|
if (Creature* cr = me->SummonCreature(NPC_TESLA_COIL, 3487.04f, -2911.68f, 318.75f, 0.0f))
|
||||||
|
{
|
||||||
|
cr->RemoveAllAuras();
|
||||||
|
cr->InterruptNonMeleeSpells(true);
|
||||||
|
cr->CastSpell(cr, SPELL_STALAGG_CHAIN, false);
|
||||||
|
cr->SetDisableGravity(true);
|
||||||
|
cr->SetImmuneToPC(false);
|
||||||
|
cr->SetControlled(true, UNIT_STATE_ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_LEFT, 100.0f))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_RIGHT, 100.0f))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_THADDIUS_GATE)))
|
||||||
|
{
|
||||||
|
if (pInstance->GetBossState(BOSS_GLUTH) == DONE)
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY);
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK);
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY);
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Talk(SAY_SLAY);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* killer) override
|
||||||
|
{
|
||||||
|
BossAI::JustDied(killer);
|
||||||
|
Talk(SAY_DEATH);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_POLARITY);
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_STACK);
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_POLARITY);
|
||||||
|
pInstance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_STACK);
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_THADDIUS_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustSummoned(Creature* cr) override
|
||||||
|
{
|
||||||
|
summons.Summon(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* who) override
|
||||||
|
{
|
||||||
|
BossAI::EnterCombat(who);
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
summons.DoZoneInCombat(NPC_FEUGEN_40);
|
||||||
|
summons.DoZoneInCombat(NPC_STALAGG_40);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (resetTimer)
|
||||||
|
{
|
||||||
|
resetTimer += diff;
|
||||||
|
if (resetTimer > 1000)
|
||||||
|
{
|
||||||
|
resetTimer = 0;
|
||||||
|
me->CastSpell(me, SPELL_THADDIUS_SPAWN_STUN, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reviveTimer)
|
||||||
|
{
|
||||||
|
reviveTimer += diff;
|
||||||
|
if (reviveTimer >= 12000)
|
||||||
|
{
|
||||||
|
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, (*itr)))
|
||||||
|
{
|
||||||
|
if (cr->GetEntry() == NPC_TESLA_COIL)
|
||||||
|
{
|
||||||
|
cr->AI()->Talk(EMOTE_TESLA_OVERLOAD);
|
||||||
|
cr->CastSpell(me, SPELL_SHOCK_VISUAL, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reviveTimer = 0;
|
||||||
|
events.ScheduleEvent(EVENT_THADDIUS_INIT, 750);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (summonTimer) // Revive
|
||||||
|
{
|
||||||
|
summonTimer += diff;
|
||||||
|
if (summonTimer >= 5000)
|
||||||
|
{
|
||||||
|
summons.DoAction(ACTION_RESTORE);
|
||||||
|
summonTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_THADDIUS_INIT:
|
||||||
|
{
|
||||||
|
me->RemoveAllAuras();
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||||
|
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, (*itr)))
|
||||||
|
{
|
||||||
|
if (cr->GetEntry() == NPC_TESLA_COIL)
|
||||||
|
{
|
||||||
|
Unit::Kill(cr, cr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_LEFT, 100.0f))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (GameObject* go = me->FindNearestGameObject(GO_TESLA_COIL_RIGHT, 100.0f))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
me->CastSpell(me, SPELL_THADDIUS_VISUAL_LIGHTNING, true);
|
||||||
|
events.ScheduleEvent(EVENT_THADDIUS_ENTER_COMBAT, 1000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EVENT_THADDIUS_ENTER_COMBAT:
|
||||||
|
Talk(SAY_AGGRO);
|
||||||
|
me->SetReactState(REACT_AGGRESSIVE);
|
||||||
|
me->SetControlled(false, UNIT_STATE_STUNNED);
|
||||||
|
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||||
|
events.ScheduleEvent(EVENT_THADDIUS_CHAIN_LIGHTNING, 14000);
|
||||||
|
events.ScheduleEvent(EVENT_THADDIUS_BERSERK, 360000);
|
||||||
|
events.ScheduleEvent(EVENT_THADDIUS_POLARITY_SHIFT, 30000);
|
||||||
|
events.ScheduleEvent(EVENT_ALLOW_BALL_LIGHTNING, 5000);
|
||||||
|
return;
|
||||||
|
case EVENT_THADDIUS_BERSERK:
|
||||||
|
me->CastSpell(me, SPELL_BERSERK, true);
|
||||||
|
break;
|
||||||
|
case EVENT_THADDIUS_CHAIN_LIGHTNING:
|
||||||
|
me->CastSpell(me->GetVictim(), SPELL_CHAIN_LIGHTNING, false);
|
||||||
|
events.RepeatEvent(15000);
|
||||||
|
break;
|
||||||
|
case EVENT_THADDIUS_POLARITY_SHIFT:
|
||||||
|
me->CastSpell(me, SPELL_POLARITY_SHIFT, false);
|
||||||
|
events.RepeatEvent(30000);
|
||||||
|
break;
|
||||||
|
case EVENT_ALLOW_BALL_LIGHTNING:
|
||||||
|
ballLightningEnabled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||||
|
{
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
else if (ballLightningEnabled)
|
||||||
|
{
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat))
|
||||||
|
{
|
||||||
|
me->CastSpell(target, SPELL_BALL_LIGHTNING, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class boss_thaddius_summon_40 : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
boss_thaddius_summon_40() : CreatureScript("boss_thaddius_summon_40") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* pCreature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<boss_thaddius_summon_40AI>(pCreature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct boss_thaddius_summon_40AI : public ScriptedAI
|
||||||
|
{
|
||||||
|
explicit boss_thaddius_summon_40AI(Creature* c) : ScriptedAI(c)
|
||||||
|
{
|
||||||
|
pInstance = me->GetInstanceScript();
|
||||||
|
overload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceScript* pInstance;
|
||||||
|
EventMap events;
|
||||||
|
uint32 pullTimer{};
|
||||||
|
uint32 visualTimer{};
|
||||||
|
bool overload;
|
||||||
|
ObjectGuid myCoil;
|
||||||
|
|
||||||
|
void Reset() override
|
||||||
|
{
|
||||||
|
pullTimer = 0;
|
||||||
|
visualTimer = 1;
|
||||||
|
overload = false;
|
||||||
|
events.Reset();
|
||||||
|
me->SetControlled(false, UNIT_STATE_STUNNED);
|
||||||
|
if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.0f))
|
||||||
|
{
|
||||||
|
cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG_40 ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false);
|
||||||
|
cr->SetImmuneToPC(false);
|
||||||
|
myCoil = cr->GetGUID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterEvadeMode(EvadeReason why) override
|
||||||
|
{
|
||||||
|
me->SetControlled(false, UNIT_STATE_STUNNED);
|
||||||
|
ScriptedAI::EnterEvadeMode(why);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnterCombat(Unit* pWho) override
|
||||||
|
{
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.f, true))
|
||||||
|
{
|
||||||
|
myCoil = cr->GetGUID();
|
||||||
|
}
|
||||||
|
if (me->GetEntry() == NPC_STALAGG_40)
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_MINION_POWER_SURGE, 10000);
|
||||||
|
Talk(SAY_STAL_AGGRO);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_MINION_STATIC_FIELD, 5000);
|
||||||
|
Talk(SAY_FEUG_AGGRO);
|
||||||
|
}
|
||||||
|
events.ScheduleEvent(EVENT_MINION_CHECK_DISTANCE, 5000);
|
||||||
|
|
||||||
|
if (me->GetEntry() == NPC_STALAGG_40) // This event needs synchronisation, called for stalagg only
|
||||||
|
{
|
||||||
|
events.ScheduleEvent(EVENT_MINION_MAGNETIC_PULL, 20000);
|
||||||
|
}
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetGuidData(DATA_THADDIUS_GATE)))
|
||||||
|
{
|
||||||
|
go->SetGoState(GO_STATE_READY);
|
||||||
|
}
|
||||||
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_THADDIUS_BOSS)))
|
||||||
|
{
|
||||||
|
cr->AI()->AttackStart(pWho);
|
||||||
|
cr->AddThreat(pWho, 10.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoAction(int32 param) override
|
||||||
|
{
|
||||||
|
if (param == ACTION_MAGNETIC_PULL)
|
||||||
|
{
|
||||||
|
pullTimer = 1;
|
||||||
|
me->SetControlled(true, UNIT_STATE_STUNNED);
|
||||||
|
}
|
||||||
|
else if (param == ACTION_RESTORE)
|
||||||
|
{
|
||||||
|
if (!me->IsAlive())
|
||||||
|
{
|
||||||
|
me->Respawn();
|
||||||
|
me->SetInCombatWithZone();
|
||||||
|
Talk(me->GetEntry() == NPC_STALAGG_40 ? EMOTE_STAL_REVIVE : EMOTE_FEUG_REVIVE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
me->SetHealth(me->GetMaxHealth());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JustDied(Unit* /*killer*/) override
|
||||||
|
{
|
||||||
|
Talk(me->GetEntry() == NPC_STALAGG_40 ? SAY_STAL_DEATH : SAY_FEUG_DEATH);
|
||||||
|
Talk(me->GetEntry() == NPC_STALAGG_40 ? EMOTE_STAL_DEATH : EMOTE_FEUG_DEATH);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_THADDIUS_BOSS)))
|
||||||
|
{
|
||||||
|
cr->AI()->DoAction(ACTION_SUMMON_DIED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KilledUnit(Unit* who) override
|
||||||
|
{
|
||||||
|
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
pInstance->SetData(DATA_IMMORTAL_FAIL, 0);
|
||||||
|
}
|
||||||
|
if (!urand(0, 2))
|
||||||
|
{
|
||||||
|
Talk(me->GetEntry() == NPC_STALAGG_40 ? SAY_STAL_SLAY : SAY_FEUG_SLAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateAI(uint32 diff) override
|
||||||
|
{
|
||||||
|
if (visualTimer)
|
||||||
|
{
|
||||||
|
visualTimer += diff;
|
||||||
|
if (visualTimer >= 3000)
|
||||||
|
{
|
||||||
|
visualTimer = 0;
|
||||||
|
if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.0f))
|
||||||
|
{
|
||||||
|
cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG_40 ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UpdateVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pullTimer) // Disable AI during pull
|
||||||
|
{
|
||||||
|
pullTimer += diff;
|
||||||
|
if (pullTimer >= 3000)
|
||||||
|
{
|
||||||
|
me->SetControlled(false, UNIT_STATE_STUNNED);
|
||||||
|
pullTimer = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.Update(diff);
|
||||||
|
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (events.ExecuteEvent())
|
||||||
|
{
|
||||||
|
case EVENT_MINION_POWER_SURGE:
|
||||||
|
me->CastSpell(me, SPELL_POWER_SURGE, false);
|
||||||
|
events.RepeatEvent(19000);
|
||||||
|
break;
|
||||||
|
case EVENT_MINION_STATIC_FIELD:
|
||||||
|
me->CastSpell(me, SPELL_STATIC_FIELD, false);
|
||||||
|
events.RepeatEvent(3000);
|
||||||
|
break;
|
||||||
|
case EVENT_MINION_MAGNETIC_PULL:
|
||||||
|
events.RepeatEvent(20000);
|
||||||
|
if (pInstance)
|
||||||
|
{
|
||||||
|
if (Creature* feugen = ObjectAccessor::GetCreature(*me, pInstance->GetGuidData(DATA_FEUGEN_BOSS)))
|
||||||
|
{
|
||||||
|
if (!feugen->IsAlive() || !feugen->GetVictim() || !me->GetVictim())
|
||||||
|
return;
|
||||||
|
|
||||||
|
float threatFeugen = feugen->GetThreatMgr().getThreat(feugen->GetVictim());
|
||||||
|
float threatStalagg = me->GetThreatMgr().getThreat(me->GetVictim());
|
||||||
|
Unit* tankFeugen = feugen->GetVictim();
|
||||||
|
Unit* tankStalagg = me->GetVictim();
|
||||||
|
|
||||||
|
feugen->GetThreatMgr().modifyThreatPercent(tankFeugen, -100);
|
||||||
|
feugen->AddThreat(tankStalagg, threatFeugen);
|
||||||
|
feugen->CastSpell(tankStalagg, SPELL_MAGNETIC_PULL, true);
|
||||||
|
feugen->AI()->DoAction(ACTION_MAGNETIC_PULL);
|
||||||
|
|
||||||
|
me->GetThreatMgr().modifyThreatPercent(tankStalagg, -100);
|
||||||
|
me->AddThreat(tankFeugen, threatStalagg);
|
||||||
|
me->CastSpell(tankFeugen, SPELL_MAGNETIC_PULL, true);
|
||||||
|
DoAction(ACTION_MAGNETIC_PULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EVENT_MINION_CHECK_DISTANCE:
|
||||||
|
if (Creature* cr = ObjectAccessor::GetCreature(*me, myCoil))
|
||||||
|
{
|
||||||
|
if (!me->GetHomePosition().IsInDist(me, 28) && me->IsInCombat())
|
||||||
|
{
|
||||||
|
if (!overload)
|
||||||
|
{
|
||||||
|
overload = true;
|
||||||
|
cr->AI()->Talk(EMOTE_TESLA_LINK_BREAKS);
|
||||||
|
me->RemoveAurasDueToSpell(me->GetEntry() == NPC_STALAGG_40 ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN);
|
||||||
|
cr->InterruptNonMeleeSpells(true);
|
||||||
|
}
|
||||||
|
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 1000.f, true))
|
||||||
|
{
|
||||||
|
cr->CastStop(SPELL_TESLA_SHOCK);
|
||||||
|
cr->CastSpell(target, SPELL_TESLA_SHOCK, true);
|
||||||
|
}
|
||||||
|
events.RepeatEvent(1500);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
overload = false;
|
||||||
|
cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG_40 ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
events.RepeatEvent(5000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DoMeleeAttackIfReady();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_thaddius_pos_neg_charge : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_thaddius_pos_neg_charge() : SpellScriptLoader("spell_thaddius_pos_neg_charge") { }
|
||||||
|
|
||||||
|
class spell_thaddius_pos_neg_charge_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_thaddius_pos_neg_charge_SpellScript);
|
||||||
|
|
||||||
|
void HandleTargets(std::list<WorldObject*>& targets)
|
||||||
|
{
|
||||||
|
uint8 count = 0;
|
||||||
|
for (auto& ihit : targets)
|
||||||
|
{
|
||||||
|
if (ihit->GetGUID() != GetCaster()->GetGUID())
|
||||||
|
{
|
||||||
|
if (Player* target = ihit->ToPlayer())
|
||||||
|
{
|
||||||
|
if (target->HasAura(GetTriggeringSpell()->Id))
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
{
|
||||||
|
uint32 spellId = GetSpellInfo()->Id == SPELL_POSITIVE_CHARGE ? SPELL_POSITIVE_CHARGE_STACK : SPELL_NEGATIVE_CHARGE_STACK;
|
||||||
|
GetCaster()->SetAuraStack(spellId, GetCaster(), count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleDamage(SpellEffIndex /*effIndex*/)
|
||||||
|
{
|
||||||
|
if (!GetTriggeringSpell())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Unit* target = GetHitUnit();
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (target->HasAura(GetTriggeringSpell()->Id) || target->GetTypeId() != TYPEID_PLAYER)
|
||||||
|
{
|
||||||
|
SetHitDamage(0);
|
||||||
|
}
|
||||||
|
else if (target->GetInstanceScript())
|
||||||
|
{
|
||||||
|
target->GetInstanceScript()->SetData(DATA_CHARGES_CROSSED, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
|
||||||
|
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_thaddius_pos_neg_charge_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class spell_thaddius_polarity_shift : public SpellScriptLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
spell_thaddius_polarity_shift() : SpellScriptLoader("spell_thaddius_polarity_shift") { }
|
||||||
|
|
||||||
|
class spell_thaddius_polarity_shift_SpellScript : public SpellScript
|
||||||
|
{
|
||||||
|
PrepareSpellScript(spell_thaddius_polarity_shift_SpellScript);
|
||||||
|
|
||||||
|
bool Validate(SpellInfo const* /*spell*/) override
|
||||||
|
{
|
||||||
|
return ValidateSpellInfo({ SPELL_POSITIVE_POLARITY, SPELL_NEGATIVE_POLARITY });
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleDummy(SpellEffIndex /* effIndex */)
|
||||||
|
{
|
||||||
|
Unit* caster = GetCaster();
|
||||||
|
if (Unit* target = GetHitUnit())
|
||||||
|
{
|
||||||
|
target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK);
|
||||||
|
target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK);
|
||||||
|
target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, caster->GetGUID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleAfterCast()
|
||||||
|
{
|
||||||
|
if (GetCaster())
|
||||||
|
{
|
||||||
|
if (Creature* caster = GetCaster()->ToCreature())
|
||||||
|
{
|
||||||
|
if (caster->GetEntry() == NPC_THADDIUS_40)
|
||||||
|
{
|
||||||
|
caster->AI()->Talk(SAY_ELECT);
|
||||||
|
caster->AI()->Talk(EMOTE_POLARITY_SHIFTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Register() override
|
||||||
|
{
|
||||||
|
OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||||
|
AfterCast += SpellCastFn(spell_thaddius_polarity_shift_SpellScript::HandleAfterCast);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SpellScript* GetSpellScript() const override
|
||||||
|
{
|
||||||
|
return new spell_thaddius_polarity_shift_SpellScript();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class npc_tesla : public CreatureScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
npc_tesla() : CreatureScript("npc_tesla") { }
|
||||||
|
|
||||||
|
CreatureAI* GetAI(Creature* creature) const override
|
||||||
|
{
|
||||||
|
return GetNaxxramasAI<npc_teslaAI>(creature);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct npc_teslaAI : public ScriptedAI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
npc_teslaAI(Creature* creature) : ScriptedAI(creature) { }
|
||||||
|
void EnterEvadeMode(EvadeReason /*why*/) override { } // never stop casting due to evade
|
||||||
|
void UpdateAI(uint32 /*diff*/) override { } // never do anything unless told
|
||||||
|
void EnterCombat(Unit* /*who*/) override { }
|
||||||
|
void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType, SpellSchoolMask) override { damage = 0; } // no, you can't kill it
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class at_thaddius_entrance : public AreaTriggerScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
at_thaddius_entrance() : AreaTriggerScript("at_thaddius_entrance") { }
|
||||||
|
|
||||||
|
bool OnTrigger(Player* player, AreaTrigger const* /*areaTrigger*/) override
|
||||||
|
{
|
||||||
|
InstanceScript* instance = player->GetInstanceScript();
|
||||||
|
if (!instance || instance->GetData(DATA_HAD_THADDIUS_GREET) || instance->GetBossState(BOSS_THADDIUS) == DONE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (Creature* thaddius = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_THADDIUS_BOSS)))
|
||||||
|
{
|
||||||
|
thaddius->AI()->Talk(SAY_GREET);
|
||||||
|
}
|
||||||
|
instance->SetData(DATA_HAD_THADDIUS_GREET, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddSC_boss_thaddius_40()
|
||||||
|
{
|
||||||
|
new boss_thaddius_40();
|
||||||
|
new boss_thaddius_summon_40();
|
||||||
|
// new npc_tesla();
|
||||||
|
// new spell_thaddius_pos_neg_charge();
|
||||||
|
// new spell_thaddius_polarity_shift();
|
||||||
|
// new at_thaddius_entrance();
|
||||||
|
}
|
||||||
1364
src/naxx40Scripts/instance_naxxramas.cpp
Normal file
1364
src/naxx40Scripts/instance_naxxramas.cpp
Normal file
File diff suppressed because it is too large
Load Diff
257
src/naxx40Scripts/naxxramas.h
Normal file
257
src/naxx40Scripts/naxxramas.h
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEF_NAXXRAMAS_H
|
||||||
|
#define DEF_NAXXRAMAS_H
|
||||||
|
|
||||||
|
#include "CreatureAIImpl.h"
|
||||||
|
#include "SpellScript.h"
|
||||||
|
|
||||||
|
#define NaxxramasScriptName "instance_naxxramas"
|
||||||
|
|
||||||
|
enum Encouters
|
||||||
|
{
|
||||||
|
BOSS_PATCHWERK = 0,
|
||||||
|
BOSS_GROBBULUS = 1,
|
||||||
|
BOSS_GLUTH = 2,
|
||||||
|
BOSS_NOTH = 3,
|
||||||
|
BOSS_HEIGAN = 4,
|
||||||
|
BOSS_LOATHEB = 5,
|
||||||
|
BOSS_ANUB = 6,
|
||||||
|
BOSS_FAERLINA = 7,
|
||||||
|
BOSS_MAEXXNA = 8,
|
||||||
|
BOSS_THADDIUS = 9,
|
||||||
|
BOSS_RAZUVIOUS = 10,
|
||||||
|
BOSS_GOTHIK = 11,
|
||||||
|
BOSS_HORSEMAN = 12,
|
||||||
|
BOSS_SAPPHIRON = 13,
|
||||||
|
BOSS_KELTHUZAD = 14,
|
||||||
|
MAX_ENCOUNTERS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXData
|
||||||
|
{
|
||||||
|
DATA_NOTH_ENTRY_GATE = 100,
|
||||||
|
DATA_HEIGAN_ERUPTION = 101,
|
||||||
|
DATA_HEIGAN_ENTER_GATE = 102,
|
||||||
|
DATA_LOATHEB_GATE = 103,
|
||||||
|
DATA_ANUB_GATE = 104,
|
||||||
|
DATA_FAERLINA_WEB = 105,
|
||||||
|
DATA_MAEXXNA_GATE = 106,
|
||||||
|
DATA_THADDIUS_BOSS = 107,
|
||||||
|
DATA_STALAGG_BOSS = 108,
|
||||||
|
DATA_FEUGEN_BOSS = 109,
|
||||||
|
DATA_THADDIUS_GATE = 110,
|
||||||
|
DATA_GOTHIK_ENTER_GATE = 111,
|
||||||
|
DATA_GOTHIK_INNER_GATE = 112,
|
||||||
|
DATA_GOTHIK_EXIT_GATE = 113,
|
||||||
|
DATA_HORSEMEN_GATE = 114,
|
||||||
|
DATA_LICH_KING_BOSS = 115,
|
||||||
|
DATA_KELTHUZAD_FLOOR = 116,
|
||||||
|
DATA_ABOMINATION_KILLED = 117,
|
||||||
|
DATA_FRENZY_REMOVED = 118,
|
||||||
|
DATA_CHARGES_CROSSED = 119,
|
||||||
|
DATA_SPORE_KILLED = 120,
|
||||||
|
DATA_HUNDRED_CLUB = 121,
|
||||||
|
DATA_DANCE_FAIL = 122,
|
||||||
|
DATA_IMMORTAL_FAIL = 123,
|
||||||
|
DATA_KELTHUZAD_GATE = 124,
|
||||||
|
DATA_HAD_THADDIUS_GREET = 125,
|
||||||
|
DATA_KELTHUZAD_PORTAL_1 = 126,
|
||||||
|
DATA_KELTHUZAD_PORTAL_2 = 127,
|
||||||
|
DATA_KELTHUZAD_PORTAL_3 = 128,
|
||||||
|
DATA_KELTHUZAD_PORTAL_4 = 129
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXGOs
|
||||||
|
{
|
||||||
|
GO_PATCHWERK_GATE = 181123,
|
||||||
|
GO_GLUTH_GATE = 181120,
|
||||||
|
GO_NOTH_ENTRY_GATE = 181200,
|
||||||
|
GO_NOTH_EXIT_GATE = 181201,
|
||||||
|
GO_HEIGAN_ENTRY_GATE = 181202,
|
||||||
|
GO_HEIGAN_EXIT_GATE = 181203,
|
||||||
|
GO_LOATHEB_GATE = 181241,
|
||||||
|
GO_ANUB_GATE = 181126,
|
||||||
|
GO_ANUB_NEXT_GATE = 181195,
|
||||||
|
GO_FAERLINA_WEB = 181235,
|
||||||
|
GO_FAERLINA_GATE = 194022,
|
||||||
|
GO_MAEXXNA_GATE = 181209,
|
||||||
|
GO_THADDIUS_GATE = 181121,
|
||||||
|
GO_GOTHIK_ENTER_GATE = 181124,
|
||||||
|
GO_GOTHIK_INNER_GATE = 181170,
|
||||||
|
GO_GOTHIK_EXIT_GATE = 181125,
|
||||||
|
GO_HORSEMEN_GATE = 181119,
|
||||||
|
GO_SAPPHIRON_GATE = 181225,
|
||||||
|
|
||||||
|
GO_HORSEMEN_CHEST_10 = 181366,
|
||||||
|
GO_HORSEMEN_CHEST_25 = 193426,
|
||||||
|
GO_HORSEMEN_CHEST_40 = 361000,
|
||||||
|
|
||||||
|
GO_SAPPHIRON_BIRTH = 181356,
|
||||||
|
GO_KELTHUZAD_FLOOR = 181444,
|
||||||
|
GO_KELTHUZAD_GATE = 181228,
|
||||||
|
GO_KELTHUZAD_PORTAL_1 = 181402,
|
||||||
|
GO_KELTHUZAD_PORTAL_2 = 181403,
|
||||||
|
GO_KELTHUZAD_PORTAL_3 = 181404,
|
||||||
|
GO_KELTHUZAD_PORTAL_4 = 181405,
|
||||||
|
|
||||||
|
GO_LOATHEB_PORTAL = 181577,
|
||||||
|
GO_THADDIUS_PORTAL = 181576,
|
||||||
|
GO_MAEXXNA_PORTAL = 181575,
|
||||||
|
GO_HORSEMAN_PORTAL = 181578,
|
||||||
|
|
||||||
|
// "Glow" effect on center-side portal
|
||||||
|
GO_DEATHKNIGHT_EYE_PORTAL = 181210,
|
||||||
|
GO_PLAGUE_EYE_PORTAL = 181211,
|
||||||
|
GO_SPIDER_EYE_PORTAL = 181212,
|
||||||
|
GO_ABOM_EYE_PORTAL = 181213,
|
||||||
|
|
||||||
|
// "Glow" effect on boss-side portal
|
||||||
|
GO_ARAC_EYE_RAMP_BOSS = 181233,
|
||||||
|
GO_PLAG_EYE_RAMP_BOSS = 181231,
|
||||||
|
GO_MILI_EYE_RAMP_BOSS = 181230,
|
||||||
|
GO_CONS_EYE_RAMP_BOSS = 181232,
|
||||||
|
|
||||||
|
// Gate to enter Naxx 40 from Strath
|
||||||
|
NAXX_STRATH_GATE = 176424
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXNPCs
|
||||||
|
{
|
||||||
|
// Thaddius
|
||||||
|
NPC_THADDIUS = 15928,
|
||||||
|
NPC_STALAGG = 15929,
|
||||||
|
NPC_FEUGEN = 15930,
|
||||||
|
|
||||||
|
// Four horseman
|
||||||
|
NPC_BARON_RIVENDARE = 30549,
|
||||||
|
NPC_SIR_ZELIEK = 16063,
|
||||||
|
NPC_LADY_BLAUMEUX = 16065,
|
||||||
|
NPC_THANE_KORTHAZZ = 16064,
|
||||||
|
|
||||||
|
// Sapphiron
|
||||||
|
NPC_SAPPHIRON = 15989,
|
||||||
|
|
||||||
|
// Kel'Thuzad
|
||||||
|
NPC_KELTHUZAD = 15990,
|
||||||
|
NPC_LICH_KING = 16980,
|
||||||
|
|
||||||
|
// Frogger
|
||||||
|
NPC_LIVING_POISON = 16027,
|
||||||
|
NPC_NAXXRAMAS_TRIGGER = 16082,
|
||||||
|
NPC_MR_BIGGLESWORTH = 16998,
|
||||||
|
|
||||||
|
// Patchwerk
|
||||||
|
NPC_PATCHWERK = 16028,
|
||||||
|
NPC_PATCHWORK_GOLEM = 16017,
|
||||||
|
NPC_BILE_RETCHER = 16018,
|
||||||
|
NPC_MAD_SCIENTIST = 16020,
|
||||||
|
NPC_LIVING_MONSTROSITY = 16021,
|
||||||
|
NPC_SURGICAL_ASSIST = 16022,
|
||||||
|
NPC_SLUDGE_BELCHER = 16029,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NX40NPCs
|
||||||
|
{
|
||||||
|
// Thaddius
|
||||||
|
NPC_THADDIUS_40 = 351000,
|
||||||
|
NPC_STALAGG_40 = 351001,
|
||||||
|
NPC_FEUGEN_40 = 351002,
|
||||||
|
|
||||||
|
// Four horseman
|
||||||
|
NPC_HIGHLORD_MOGRAINE_40 = 351037,
|
||||||
|
NPC_SIR_ZELIEK_40 = 351038,
|
||||||
|
NPC_LADY_BLAUMEUX_40 = 351040,
|
||||||
|
NPC_THANE_KORTHAZZ_40 = 351039,
|
||||||
|
|
||||||
|
// Sapphiron
|
||||||
|
NPC_SAPPHIRON_40 = 351018,
|
||||||
|
|
||||||
|
// Kel'Thuzad
|
||||||
|
NPC_KELTHUZAD_40 = 351019,
|
||||||
|
NPC_LICH_KING_40 = 16980,
|
||||||
|
|
||||||
|
// Frogger
|
||||||
|
NPC_LIVING_POISON_40 = 16027,
|
||||||
|
NPC_NAXXRAMAS_TRIGGER_40 = 16082,
|
||||||
|
NPC_MR_BIGGLESWORTH_40 = 16998,
|
||||||
|
|
||||||
|
// Patchwerk
|
||||||
|
NPC_PATCHWERK_40 = 351028,
|
||||||
|
NPC_PATCHWORK_GOLEM_40 = 351021,
|
||||||
|
NPC_BILE_RETCHER_40 = 351022,
|
||||||
|
NPC_MAD_SCIENTIST_40 = 351023,
|
||||||
|
NPC_LIVING_MONSTROSITY_40 = 351024,
|
||||||
|
NPC_SURGICAL_ASSIST_40 = 351025,
|
||||||
|
NPC_SLUDGE_BELCHER_40 = 351029,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXMisc
|
||||||
|
{
|
||||||
|
SPELL_ERUPTION = 29371,
|
||||||
|
SPELL_FROGGER_EXPLODE = 28433,
|
||||||
|
|
||||||
|
ACTION_SAPPHIRON_BIRTH = 1,
|
||||||
|
|
||||||
|
// Background screams in instance if Thaddius still alive, four of them from 8873 to 8876
|
||||||
|
SOUND_SCREAM = 8873
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXSays
|
||||||
|
{
|
||||||
|
SAY_SAPP_DIALOG1 = 0,
|
||||||
|
SAY_SAPP_DIALOG2_LICH = 1,
|
||||||
|
SAY_SAPP_DIALOG3 = 2,
|
||||||
|
SAY_SAPP_DIALOG4_LICH = 2,
|
||||||
|
SAY_SAPP_DIALOG5 = 4,
|
||||||
|
SAY_SAPP_DIALOG6 = 20,
|
||||||
|
SAY_CAT_DIED = 5,
|
||||||
|
SAY_FIRST_WING_TAUNT = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXEvents
|
||||||
|
{
|
||||||
|
EVENT_THADDIUS_SCREAMS = 0,
|
||||||
|
EVENT_KELTHUZAD_WING_TAUNT = 1,
|
||||||
|
EVENT_FROSTWYRM_WATERFALL_DOOR = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXMaps
|
||||||
|
{
|
||||||
|
MAP_NAXX = 533,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXGraveyards
|
||||||
|
{
|
||||||
|
NAXX40_GRAVEYARD = 1449
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NXAttunementQuests
|
||||||
|
{
|
||||||
|
NAXX40_ATTUNEMENT_1 = 9121,
|
||||||
|
NAXX40_ATTUNEMENT_2 = 9122,
|
||||||
|
NAXX40_ATTUNEMENT_3 = 9123
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class AI, class T>
|
||||||
|
inline AI* GetNaxxramasAI(T* obj)
|
||||||
|
{
|
||||||
|
return GetInstanceAI<AI>(obj, NaxxramasScriptName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user