Scripts/Underrot: Implement Elder Leaxa encounter (#28920)

This commit is contained in:
Naddley
2023-04-17 09:15:58 +02:00
committed by GitHub
parent 1b3f93aa0f
commit bda3320986
5 changed files with 593 additions and 0 deletions
@@ -0,0 +1,57 @@
-- Elder Leaxa
DELETE FROM `instance_template` WHERE `map` = 1841;
INSERT INTO `instance_template` (`map`, `parent`, `script`) VALUES
(1841, 0, 'instance_underrot');
DELETE FROM `instance_encounters` WHERE `entry` IN (2111, 2112, 2118, 2123);
INSERT INTO `instance_encounters` (`entry`, `creditType`, `creditEntry`, `lastEncounterDungeon`, `comment`) VALUES
(2111, 0, 131318, 0, 'Elder Leaxa'),
(2112, 0, 131817, 0, 'Cragmaw the Infested'),
(2118, 0, 131383, 0, 'Sporecaller Zancha'),
(2123, 0, 133007, 0, 'Unbound Abomination');
UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'boss_elder_leaxa' WHERE `entry` = 131318;
UPDATE `creature_template` SET `faction` = 14, `BaseAttackTime`=2000, `unit_flags`=33555200, `unit_flags2`=2099200, `unit_flags3`=17301505, `flags_extra` = 0x00000080 | 0x20000000 , `AIName` = '', `ScriptName` = 'npc_blood_wave_stalker' WHERE `entry`=132398; -- Blood Wave Stalker
UPDATE `creature_template` SET `faction`= 16, `BaseAttackTime`=2000, `unit_flags`=32832, `unit_flags2`=2099200, `unit_flags3`=524288, `AIName` = '', `ScriptName` = 'npc_blood_effigy' WHERE `entry`=134701; -- Blood Effigy
DELETE FROM `creature_template_addon` WHERE `entry` IN (134701, 132398);
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `StandState`, `AnimTier`, `VisFlags`, `SheathState`, `PvpFlags`, `emote`, `aiAnimKit`, `movementAnimKit`, `meleeAnimKit`, `visibilityDistanceType`, `auras`) VALUES
(134701, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, '272385'), -- 134701 (Blood Effigy) - Blood Mirror
(132398, 0, 0, 0, 0, 0, 1, 0, 0, 12224, 0, 0, 3, ''); -- 132398 (Blood Wave Stalker) - Creeping Rot
DELETE FROM `creature_template_movement` WHERE `CreatureID` = 132398;
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
(132398, 1, 0, 1, 0, 0, 0, NULL);
-- AreaTrigger
DELETE FROM `areatrigger_template` WHERE `IsServerSide`=0 AND `Id` = 17135;
INSERT INTO `areatrigger_template` (`Id`, `IsServerSide`, `Type`, `Flags`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `VerifiedBuild`) VALUES
(17135, 0, 4, 4, 2.5, 2.5, 20, 20, 0.300000011920928955, 0.300000011920928955, 0, 0, 28153);
DELETE FROM `areatrigger_create_properties` WHERE `Id` = 12454;
INSERT INTO `areatrigger_create_properties` (`Id`, `AreaTriggerId`, `MoveCurveId`, `ScaleCurveId`, `MorphCurveId`, `FacingCurveId`, `AnimId`, `AnimKitId`, `DecalPropertiesId`, `TimeToTarget`, `TimeToTargetScale`, `Shape`, `ShapeData0`, `ShapeData1`, `ShapeData2`, `ShapeData3`, `ShapeData4`, `ShapeData5`, `ShapeData6`, `ShapeData7`, `VerifiedBuild`) VALUES
(12454, 17135, 0, 0, 0, 0, 0, 0, 0, 0, 10000, 4, 2.5, 2.5, 20, 20, 0.300000011920928955, 0.300000011920928955, 0, 0, 28153); -- SpellId : 261496
DELETE FROM `areatrigger_template_actions` WHERE `AreaTriggerId` = 17135 AND `IsServerSide` = 0;
INSERT INTO `areatrigger_template_actions` (`AreaTriggerId`, `IsServerSide`, `ActionType`, `ActionParam`, `TargetType`) VALUES
(17135, 0, 1, 261498, 2);
DELETE FROM `creature_text` WHERE `CreatureID` = 131318;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(131318, 0, 0, 'For de glory of G\'huun!', 14, 0, 100, 0, 0, 101028, 148173, 0, 'Elder Leaxa to Player'),
(131318, 1, 0, 'G\'huun\'s power take you!', 14, 0, 100, 0, 0, 101027, 148180, 0, 'Elder Leaxa'),
(131318, 2, 0, 'Rot and wither!', 14, 0, 100, 0, 0, 101026, 148211, 0, 'Elder Leaxa to Player'),
(131318, 3, 0, 'G\'huun be everywhere!', 14, 0, 100, 0, 0, 101025, 148212, 0, 'Elder Leaxa'),
(131318, 4, 0, '|TINTERFACE\\ICONS\\INV_TikiMan2_Bloodtroll.blp:20|t Elder Leaxa begins to cast |cFFF00000|Hspell:264603|h[Blood Mirror]|h|r!', 41, 0, 100, 0, 0, 101025, 157334, 0, 'Elder Leaxa'),
(131318, 5, 0, 'My power grows!', 14, 0, 100, 0, 0, 101031, 95739, 0, 'Elder Leaxa to Player');
-- SpellScripts
DELETE FROM `spell_script_names` WHERE `spell_id` IN (260879, 264747, 264757, 260889, 261496, 261498, 264603);
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(260879, 'spell_taint_of_ghuun'),
(264747, 'spell_sanguine_feast_selector'),
(264757, 'spell_taint_of_ghuun'),
(260889, 'spell_creeping_rot_selector'),
(261496, 'spell_creeping_rot_aura'),
(261498, 'spell_taint_of_ghuun'),
(264603, 'spell_blood_mirror_selector');
@@ -0,0 +1,367 @@
/*
* This file is part of the TrinityCore 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 General Public License as published by the
* Free Software Foundation; either version 2 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 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 "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "Containers.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellAuras.h"
#include "underrot.h"
enum LeaxaSpells
{
SPELL_TAINT_OF_GHUUN = 260685,
SPELL_BLOOD_BOLT = 260879,
SPELL_SANGUINE_FEAST = 264747,
SPELL_CREEPING_ROT_SELECTOR = 260889,
SPELL_CREEPING_ROT_SUMMON = 260894,
SPELL_CREEPING_ROT_SPAWN_VISUAL = 260891,
SPELL_CREEPING_ROT_AURA = 261496,
SPELL_CREEPING_ROT_PERIODIC_DMG = 261498,
SPELL_BLOOD_MIRROR_SELECTOR = 264603,
SPELL_BLOOD_MIRROR_MISSILE = 264609
};
enum LeaxaEvents
{
EVENT_BLOOD_BOLT = 1,
EVENT_CREEPING_ROT,
EVENT_SANGUINE_FEAST,
EVENT_BLOOD_MIRROR
};
enum LeaxaTexts
{
SAY_AGGRO = 0,
SAY_SANGUINE_FEAST = 1,
SAY_ROT_AND_WITHER = 2,
SAY_BLOOD_MIRROR = 3,
SAY_ANNOUNCE_BLOOD_MIRROR = 4,
SAY_DEATH = 5
};
enum LeaxaAnimKits
{
ANIMKIT_BLOOD_EFFIGY_DEATH = 9798
};
// 131318 - Elder Leaxa
struct boss_elder_leaxa : public BossAI
{
boss_elder_leaxa(Creature* creature) : BossAI(creature, DATA_ELDER_LEAXA) { }
void JustDied(Unit* /*killer*/) override
{
_JustDied();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
Talk(SAY_DEATH);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_EnterEvadeMode();
_DespawnAtEvade();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
Talk(SAY_AGGRO);
me->SetAIAnimKitId(0);
events.ScheduleEvent(EVENT_BLOOD_BOLT, 1s);
events.ScheduleEvent(EVENT_SANGUINE_FEAST, 8s);
events.ScheduleEvent(EVENT_CREEPING_ROT, 12s);
events.ScheduleEvent(EVENT_BLOOD_MIRROR, 17s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
{
case EVENT_BLOOD_BOLT:
DoCastVictim(SPELL_BLOOD_BOLT);
events.ScheduleEvent(EVENT_BLOOD_BOLT, 6s);
break;
case EVENT_SANGUINE_FEAST:
Talk(SAY_SANGUINE_FEAST);
DoCastAOE(SPELL_SANGUINE_FEAST);
events.ScheduleEvent(EVENT_SANGUINE_FEAST, 30s);
break;
case EVENT_CREEPING_ROT:
Talk(SAY_ROT_AND_WITHER);
DoCastAOE(SPELL_CREEPING_ROT_SELECTOR);
events.ScheduleEvent(EVENT_CREEPING_ROT, 16s);
break;
case EVENT_BLOOD_MIRROR:
Talk(SAY_BLOOD_MIRROR);
Talk(SAY_ANNOUNCE_BLOOD_MIRROR);
DoCastSelf(SPELL_BLOOD_MIRROR_SELECTOR);
events.ScheduleEvent(EVENT_BLOOD_MIRROR, 47s);
break;
default:
break;
}
DoMeleeAttackIfReady();
}
};
// 134701 - Blood Effigy
struct npc_blood_effigy : public ScriptedAI
{
npc_blood_effigy(Creature* creature) : ScriptedAI(creature) { }
void JustEngagedWith(Unit* /*who*/) override
{
_events.ScheduleEvent(EVENT_BLOOD_BOLT, 1s);
_events.ScheduleEvent(EVENT_SANGUINE_FEAST, 8s);
_events.ScheduleEvent(EVENT_CREEPING_ROT, 12s);
}
void JustDied(Unit* /*killer*/) override
{
me->SetAIAnimKitId(ANIMKIT_BLOOD_EFFIGY_DEATH);
me->DespawnOrUnsummon(3s);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (_events.ExecuteEvent())
{
case EVENT_BLOOD_BOLT:
DoCastVictim(SPELL_BLOOD_BOLT);
_events.ScheduleEvent(EVENT_BLOOD_BOLT, 2s);
break;
case EVENT_SANGUINE_FEAST:
DoCastAOE(SPELL_SANGUINE_FEAST);
_events.ScheduleEvent(EVENT_SANGUINE_FEAST, 30s);
break;
case EVENT_CREEPING_ROT:
DoCastAOE(SPELL_CREEPING_ROT_SELECTOR);
_events.ScheduleEvent(EVENT_CREEPING_ROT, 16s);
break;
default:
break;
}
DoMeleeAttackIfReady();
}
private:
EventMap _events;
};
// 132398 - Blood Wave Stalker
struct npc_blood_wave_stalker : public ScriptedAI
{
npc_blood_wave_stalker(Creature* creature) : ScriptedAI(creature) { }
static constexpr float WALK_DISTANCE = 58.0f;
void JustAppeared() override
{
DoCast(SPELL_CREEPING_ROT_AURA);
float angle = me->GetOrientation();
float destX = me->GetPositionX() + WALK_DISTANCE * std::cos(angle);
float destY = me->GetPositionY() + WALK_DISTANCE * std::sin(angle);
float destZ = me->GetPositionZ();
Position walkDest(destX, destY, destZ);
me->GetMotionMaster()->MovePoint(0, walkDest);
}
};
// 264747 - Sanguine Feast
class spell_sanguine_feast_selector : public SpellScript
{
PrepareSpellScript(spell_sanguine_feast_selector);
bool Validate(SpellInfo const* spellInfo) override
{
return !spellInfo->GetEffects().empty() && ValidateSpellInfo({ uint32(spellInfo->GetEffect(EFFECT_0).CalcValue()) });
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
caster->CastSpell(GetHitUnit(), uint32(GetEffectInfo().CalcValue(caster)));
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_sanguine_feast_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 260889 - Creeping Rot
class spell_creeping_rot_selector : public SpellScript
{
PrepareSpellScript(spell_creeping_rot_selector);
static constexpr float SPAWN_DISTANCE = 5.0f;
void HandleHit(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
// make sure spell is cast towards target and caster looks towards target
caster->SetInFront(target);
caster->SetFacingToObject(target);
caster->CastSpell(target, SPELL_CREEPING_ROT_SUMMON);
float angle = caster->GetOrientation();
float destX = caster->GetPositionX() + SPAWN_DISTANCE * std::cos(angle);
float destY = caster->GetPositionY() + SPAWN_DISTANCE * std::sin(angle);
float destZ = caster->GetPositionZ();
Position spawnVisualDest(destX, destY, destZ);
caster->CastSpell(spawnVisualDest, SPELL_CREEPING_ROT_SPAWN_VISUAL, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_creeping_rot_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 261496 - Creeping Rot (Aura)
class spell_creeping_rot_aura : public AuraScript
{
PrepareAuraScript(spell_creeping_rot_aura);
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
return;
Creature* creature = GetTarget()->ToCreature();
if (!creature)
return;
creature->DespawnOrUnsummon();
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_creeping_rot_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
static Position const MirrorSpawnPositions[] =
{
{ 879.79865f, 1222.6233f, 56.47815f },
{ 856.184f, 1232.5435f, 56.52007f },
{ 859.34204f, 1238.0243f, 56.520065f },
{ 857.8333f, 1220.6545f, 56.468567f },
{ 876.17365f, 1240.2848f, 56.409615f },
{ 864.25867f, 1240.5903f, 56.520065f },
{ 863.1042f, 1218.0591f, 56.468765f }
};
// 264603 - Blood Mirror
class spell_blood_mirror_selector : public SpellScript
{
PrepareSpellScript(spell_blood_mirror_selector);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_BLOOD_MIRROR_MISSILE });
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
Position spawnPos = Trinity::Containers::SelectRandomContainerElement(MirrorSpawnPositions);
GetCaster()->CastSpell(spawnPos, SPELL_BLOOD_MIRROR_MISSILE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_blood_mirror_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
// 260879 - Blood Bolt
// 264757 - Sanguine Feast
// 261498 - Creeping Rot
class spell_taint_of_ghuun : public SpellScript
{
PrepareSpellScript(spell_taint_of_ghuun);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_TAINT_OF_GHUUN });
}
void HandleHit()
{
InstanceScript* instance = GetHitUnit()->GetInstanceScript();
if (!instance)
return;
Creature* leaxa = instance->GetCreature(DATA_ELDER_LEAXA);
if (!leaxa)
return;
leaxa->CastSpell(GetHitUnit(), SPELL_TAINT_OF_GHUUN, true);
}
void Register() override
{
AfterHit += SpellHitFn(spell_taint_of_ghuun::HandleHit);
}
};
void AddSC_boss_elder_leaxa()
{
// Creature
RegisterUnderrotCreatureAI(boss_elder_leaxa);
RegisterUnderrotCreatureAI(npc_blood_wave_stalker);
RegisterUnderrotCreatureAI(npc_blood_effigy);
// Spells
RegisterSpellScript(spell_sanguine_feast_selector);
RegisterSpellScript(spell_creeping_rot_selector);
RegisterSpellScript(spell_creeping_rot_aura);
RegisterSpellScript(spell_blood_mirror_selector);
RegisterSpellScript(spell_taint_of_ghuun);
}
@@ -0,0 +1,78 @@
/*
* This file is part of the TrinityCore 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 General Public License as published by the
* Free Software Foundation; either version 2 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 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 "AreaBoundary.h"
#include "InstanceScript.h"
#include "ScriptMgr.h"
#include "underrot.h"
BossBoundaryData const boundaries =
{
{ DATA_ELDER_LEAXA, new CircleBoundary(Position(869.502014f, 1230.199951f), 58.0f) }
};
ObjectData const creatureData[] =
{
{ BOSS_ELDER_LEAXA, DATA_ELDER_LEAXA },
{ BOSS_SPORECALLER_ZANCHA, DATA_SPORECALLER_ZANCHA },
{ BOSS_CRAGMAW_THE_INFESTED, DATA_CRAGMAW_THE_INFESTED },
{ BOSS_UNBOUND_ABOMINATION, DATA_UNBOUND_ABOMINATION },
{ 0, 0 } // END
};
DoorData const doorData[] =
{
{ GO_WALL_DOOR_SHORTCUT_ENTRANCE, DATA_SPORECALLER_ZANCHA, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
DungeonEncounterData const encounters[] =
{
{ DATA_ELDER_LEAXA, {{ 2111 }} },
{ DATA_CRAGMAW_THE_INFESTED, {{ 2112 }} },
{ DATA_SPORECALLER_ZANCHA, {{ 2118 }} },
{ DATA_UNBOUND_ABOMINATION, {{ 2123 }} },
};
class instance_underrot : public InstanceMapScript
{
public:
instance_underrot() : InstanceMapScript(UnderrotScriptName, 1841) { }
struct instance_underrot_InstanceMapScript : public InstanceScript
{
instance_underrot_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
LoadBossBoundaries(boundaries);
LoadDungeonEncounterData(encounters);
}
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{
return new instance_underrot_InstanceMapScript(map);
}
};
void AddSC_instance_underrot()
{
new instance_underrot();
}
@@ -0,0 +1,60 @@
/*
* This file is part of the TrinityCore 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 General Public License as published by the
* Free Software Foundation; either version 2 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 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_UNDERROT_H_
#define DEF_UNDERROT_H_
#include "CreatureAIImpl.h"
#define DataHeader "Underrot"
#define UnderrotScriptName "instance_underrot"
uint32 const EncounterCount = 4;
enum UnderrotDataTypes
{
// Encounters
DATA_ELDER_LEAXA = 0,
DATA_SPORECALLER_ZANCHA,
DATA_CRAGMAW_THE_INFESTED,
DATA_UNBOUND_ABOMINATION
};
enum UnderrotCreatureIds
{
// Bosses
BOSS_ELDER_LEAXA = 131318,
BOSS_SPORECALLER_ZANCHA = 131383,
BOSS_CRAGMAW_THE_INFESTED = 131817,
BOSS_UNBOUND_ABOMINATION = 133007
};
enum UnderrotGameObjectIds
{
GO_PYRAMID_DOOR_UNBOUND_ABOMINATION_ENTRANCE = 296385,
GO_WALL_DOOR_SHORTCUT_ENTRANCE = 295356
};
template <class AI, class T>
inline AI* GetUnderrotAI(T* obj)
{
return GetInstanceAI<AI>(obj, UnderrotScriptName);
}
#define RegisterUnderrotCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetUnderrotAI)
#endif
@@ -0,0 +1,31 @@
/*
* This file is part of the TrinityCore 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 General Public License as published by the
* Free Software Foundation; either version 2 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 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/>.
*/
// This is where scripts' loading functions should be declared:
// Underrot
void AddSC_instance_underrot();
void AddSC_boss_elder_leaxa();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddZandalarScripts()
{
// Underrot
AddSC_instance_underrot();
AddSC_boss_elder_leaxa();
}