aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/3.3.5/2025_09_22_00_world.sql44
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp838
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp9
-rw-r--r--src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h11
4 files changed, 667 insertions, 235 deletions
diff --git a/sql/updates/world/3.3.5/2025_09_22_00_world.sql b/sql/updates/world/3.3.5/2025_09_22_00_world.sql
new file mode 100644
index 00000000000..81cbd82d6e1
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_09_22_00_world.sql
@@ -0,0 +1,44 @@
+-- Intro
+DELETE FROM `areatrigger_scripts` WHERE `entry` = 4853;
+INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES
+(4853, 'at_the_dead_scar');
+
+DELETE FROM `spawn_group` WHERE `spawnType` = 0 AND `spawnId` IN (SELECT `guid` FROM `creature` WHERE `id` = 24895);
+DELETE FROM `creature` WHERE `id` = 24895;
+
+UPDATE `creature_template_movement` SET `Flight` = 1 WHERE `CreatureId` = 24895;
+
+UPDATE `creature_template` SET `ScriptName` = 'npc_madrigosa' WHERE `entry` = 24895;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (46609,46610,44872,44844,44883,44884,46637,46638);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(13,1,46609,0,0,31,0,3,19871,0,0,0,0,"","Group 0: Spell 'Freeze' (Effect 0) targets creature 'World Trigger (Not Immune NPC)'"),
+(13,1,46610,0,0,31,0,5,188119,0,0,0,0,"","Group 0: Spell 'Freeze' (Effect 0) targets object 'Doodad_Sunwell_Ice_Barrier01'"),
+(13,1,44872,0,0,31,0,3,24882,0,0,0,0,"","Group 0: Spell 'Frost Blast' (Effect 0) targets creature 'Brutallus'"),
+(13,3,44844,0,0,31,0,3,24895,0,0,0,0,"","Group 0: Spell 'Fel Fireball' (Effect 0, 1) targets creature 'Madrigosa'"),
+(13,1,44883,0,0,31,0,3,24882,0,0,0,0,"","Group 0: Spell 'Encapsulate' (Effect 0) targets creature 'Brutallus'"),
+(13,1,44884,0,0,31,0,3,24895,0,0,0,0,"","Group 0: Spell 'Charge' (Effect 0) targets creature 'Madrigosa'"),
+(13,1,46637,0,0,31,0,3,19871,0,0,0,0,"","Group 0: Spell 'Break Ice' (Effect 0) targets creature 'World Trigger (Not Immune NPC)'"),
+(13,1,46638,0,0,31,0,5,188119,0,0,0,0,"","Group 0: Spell 'Break Ice' (Effect 0) targets object 'Doodad_Sunwell_Ice_Barrier01'");
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN (
+'spell_brutallus_freeze',
+'spell_brutallus_break_ice',
+'spell_brutallus_burn_primer',
+'spell_brutallus_burn_ally');
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(46609, 'spell_brutallus_freeze'),
+(46637, 'spell_brutallus_break_ice'),
+(45141, 'spell_brutallus_burn_primer'),
+(45151, 'spell_brutallus_burn_ally');
+
+UPDATE `creature_text` SET `Emote` = 1 WHERE `CreatureID` = 24882 AND `GroupID` = 0;
+UPDATE `creature_text` SET `BroadcastTextId` = 25224 WHERE `CreatureID` = 24882 AND `GroupID` = 2;
+UPDATE `creature_text` SET `Text` = "That was fun, but I still await a true challenge!", `Language` = 0, `BroadcastTextId` = 25225 WHERE `CreatureID` = 24882 AND `GroupID` = 3;
+
+-- Outro
+UPDATE `creature_template` SET `AIName` = 'SmartAI', `flags_extra` = `flags_extra` |128 WHERE `entry` = 25703;
+
+DELETE FROM `smart_scripts` WHERE `entryorguid` = 25703 AND `source_type` = 0;
+INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`event_param5`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_param4`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES
+(25703,0,0,0,60,0,100,1,7000,7000,0,0,0,11,45212,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Brutallus Death Cloud - On Update - Cast 'Brutallus Death Cloud' (No Repeat)");
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp
index 33a133b37cf..b1536cbc077 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_brutallus.cpp
@@ -15,317 +15,604 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: Boss_Brutallus
-SD%Complete: 80
-SDComment: Find a way to start the intro, best code for the intro
-EndScriptData */
+/*
+ * Intro requires additional re-checks, something may be missing or implemented wrongly.
+ Visually it doesn't look good because of several core bugs \ wrong implementation
+ * Everything related to Burn requires additional re-checks since something may be implemented wrongly
+ * Effect of SPELL_CLEAR_RETURN_STATE is NYI
+ * SPELL_TAUNT_HIT_CHANCE has no effect currently
+ */
#include "ScriptMgr.h"
+#include "GameObject.h"
#include "InstanceScript.h"
-#include "Log.h"
+#include "MotionMaster.h"
+#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellAuraEffects.h"
+#include "SpellInfo.h"
#include "SpellScript.h"
#include "sunwell_plateau.h"
-enum Quotes
+enum BrutallusTexts
{
- YELL_INTRO = 0,
- YELL_INTRO_BREAK_ICE = 1,
- YELL_INTRO_CHARGE = 2,
- YELL_INTRO_KILL_MADRIGOSA = 3,
- YELL_INTRO_TAUNT = 4,
-
- YELL_AGGRO = 5,
- YELL_KILL = 6,
- YELL_LOVE = 7,
- YELL_BERSERK = 8,
- YELL_DEATH = 9,
-
- YELL_MADR_ICE_BARRIER = 0,
- YELL_MADR_INTRO = 1,
- YELL_MADR_ICE_BLOCK = 2,
- YELL_MADR_TRAP = 3,
- YELL_MADR_DEATH = 4
+ SAY_INTRO = 0,
+ SAY_INTRO_BREAK_ICE = 1,
+ SAY_INTRO_CHARGE = 2,
+ SAY_INTRO_KILL_MADRIGOSA = 3,
+ SAY_INTRO_TAUNT = 4,
+
+ SAY_AGGRO = 5,
+ SAY_SLAY = 6,
+ SAY_LOVE = 7,
+ SAY_BERSERK = 8,
+ SAY_DEATH = 9,
+
+ SAY_MADR_ICE_BARRIER = 0,
+ SAY_MADR_INTRO = 1,
+ SAY_MADR_ICE_BLOCK = 2,
+ SAY_MADR_TRAP = 3,
+ SAY_MADR_DEATH = 4
};
-enum Spells
+enum BrutallusSpells
{
+ // Passive
+ SPELL_DUAL_WIELD_PASSIVE = 42459,
+ SPELL_TAUNT_HIT_CHANCE = 45210,
+
+ // Combat
SPELL_METEOR_SLASH = 45150,
- SPELL_BURN = 46394,
SPELL_STOMP = 45185,
+ SPELL_BURN_PRIMER = 45141,
SPELL_BERSERK = 26662,
- SPELL_DUAL_WIELD = 42459,
- SPELL_INTRO_FROST_BLAST = 45203,
- SPELL_INTRO_FROSTBOLT = 44843,
- SPELL_INTRO_ENCAPSULATE = 45665,
- SPELL_INTRO_ENCAPSULATE_CHANELLING = 45661
+ // Intro - Madrigosa
+ SPELL_FREEZE = 46609,
+ SPELL_FROST_BREATH = 45065,
+ SPELL_FROST_BLAST = 44872,
+ SPELL_FROSTBOLT = 44843,
+ SPELL_ENCAPSULATE = 44883,
+ SPELL_SELF_STUN = 45066,
+ SPELL_PERMANENT_FEIGN_DEATH = 29266,
+
+ // Intro - Brutallus
+ SPELL_FLAME_RING_1 = 44873,
+ SPELL_FLAME_RING_2 = 44874,
+ SPELL_FEL_FIREBALL = 44844,
+ SPELL_ARCANE_EXPLOSION_VISUAL = 35426,
+ SPELL_CHARGE = 44884,
+ SPELL_CLEAR_RETURN_STATE = 38289,
+ SPELL_FULL_HEAL = 17683,
+ SPELL_BREAK_ICE = 46637,
+
+ // Intro - Shared
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+
+ // Outro - Brutallus
+ SPELL_SUMMON_DEATH_CLOUD = 45884,
+
+ // Outro - Madrigosa
+ SPELL_SUMMON_FELBLAZE_PRE_VISUAL = 44885,
+ SPELL_SUMMON_FELBLAZE = 45069,
+
+ // Scripts
+ SPELL_BURN_DAMAGE = 46394,
+ SPELL_FREEZE_OBJECT = 46610,
+ SPELL_BREAK_ICE_OBJECT = 46638,
+ SPELL_BREAK_ICE_KNOCK_BACK = 47030
};
-struct boss_brutallus : public BossAI
+enum BrutallusEvents
{
- boss_brutallus(Creature* creature) : BossAI(creature, DATA_BRUTALLUS)
- {
- Initialize();
- Intro = true;
- }
-
- void Initialize()
- {
- SlashTimer = 11000;
- StompTimer = 30000;
- BurnTimer = 60000;
- BerserkTimer = 360000;
-
- IntroPhase = 0;
- IntroPhaseTimer = 0;
- IntroFrostBoltTimer = 0;
+ EVENT_METEOR_SLASH = 1,
+ EVENT_STOMP,
+ EVENT_BURN,
+ EVENT_BERSERK,
+
+ EVENT_INTRO_1,
+ EVENT_INTRO_2,
+ EVENT_INTRO_3,
+ EVENT_INTRO_4,
+ EVENT_INTRO_5,
+ EVENT_INTRO_6,
+ EVENT_INTRO_7,
+ EVENT_INTRO_8,
+ EVENT_INTRO_9,
+ EVENT_INTRO_10,
+ EVENT_INTRO_11,
+ EVENT_INTRO_12,
+ EVENT_INTRO_13,
+ EVENT_INTRO_14,
+ EVENT_INTRO_15,
+ EVENT_INTRO_16,
+ EVENT_INTRO_17,
+ EVENT_INTRO_18,
+ EVENT_INTRO_19,
+ EVENT_INTRO_20,
+ EVENT_INTRO_21,
+ EVENT_INTRO_22,
+ EVENT_INTRO_23,
+ EVENT_INTRO_24,
+ EVENT_INTRO_25,
+ EVENT_INTRO_26,
+
+ EVENT_FROSTBOLT,
+
+ EVENT_OUTRO_1,
+ EVENT_OUTRO_2,
+ EVENT_OUTRO_3
+};
- IsIntro = false;
- Enraged = false;
- }
+enum BrutallusActions
+{
+ ACTION_START_OUTRO = 0
+};
- uint32 SlashTimer;
- uint32 BurnTimer;
- uint32 StompTimer;
- uint32 BerserkTimer;
+enum BrutallusPoints
+{
+ POINT_MADRIGOSA_LAND_1 = 0,
+ POINT_MADRIGOSA_LIFTOFF = 1,
+ POINT_MADRIGOSA_LAND_2 = 2,
+ POINT_MADRIGOSA_LAND_3 = 3,
+ POINT_BRUTALLUS_OFFSET = 4,
+ POINT_BRUTALLUS_COMBAT = 5
+};
- uint32 IntroPhase;
- uint32 IntroPhaseTimer;
- uint32 IntroFrostBoltTimer;
+Position const MadrigosaSpawnPos = { 1470.3624f, 738.1818f, 64.166770f, 4.625122547149658203f };
+Position const MadrigosaMoveLandPos1 = { 1463.8200f, 661.2120f, 19.797100f, 0.0f };
+Position const MadrigosaMoveLiftoffPos = { 1464.6943f, 652.1426f, 39.277885f, 0.0f };
+Position const MadrigosaMoveLandPos2 = { 1464.6943f, 652.1426f, 20.819180f, 0.0f };
+Position const MadrigosaMoveLandPos3 = { 1464.6943f, 652.1426f, 19.819180f, 0.0f };
+Position const BrutallusMoveOffsetPos = { 1464.4820f, 583.9001f, 44.392480f, 0.0f };
+Position const BrutallusMoveCombatPos = { 1478.7400f, 621.8980f, 22.654501f, 0.0f };
- bool Intro;
- bool IsIntro;
- bool Enraged;
+// 24882 - Brutallus
+struct boss_brutallus : public BossAI
+{
+ boss_brutallus(Creature* creature) : BossAI(creature, DATA_BRUTALLUS) { }
void Reset() override
{
- Initialize();
-
- DoCast(me, SPELL_DUAL_WIELD, true);
+ _Reset();
- BossAI::Reset();
+ /// @todo: Dual Wield doesn't get apply after evade for unknown reason. Investigate this
+ DoCastSelf(SPELL_DUAL_WIELD_PASSIVE);
+ DoCastSelf(SPELL_TAUNT_HIT_CHANCE);
}
void JustEngagedWith(Unit* who) override
{
- Talk(YELL_AGGRO);
+ if (who->GetEntry() == NPC_MADRIGOSA)
+ return;
BossAI::JustEngagedWith(who);
+
+ Talk(SAY_AGGRO);
+
+ events.ScheduleEvent(EVENT_METEOR_SLASH, 10s);
+ events.ScheduleEvent(EVENT_STOMP, 30s);
+ events.ScheduleEvent(EVENT_BURN, 20s);
+ events.ScheduleEvent(EVENT_BERSERK, 6min);
}
- void KilledUnit(Unit* /*victim*/) override
+ void OnSpellCast(SpellInfo const* spell) override
{
- Talk(YELL_KILL);
+ switch (spell->Id)
+ {
+ case SPELL_STOMP:
+ Talk(SAY_LOVE);
+ break;
+ case SPELL_BERSERK:
+ Talk(SAY_BERSERK);
+ break;
+ default:
+ break;
+ }
}
- void JustDied(Unit* killer) override
+ void KilledUnit(Unit* /*victim*/) override
{
- Talk(YELL_DEATH);
-
- instance->SetBossState(DATA_FELMYST, SPECIAL);
- BossAI::JustDied(killer);
+ Talk(SAY_SLAY);
}
- void EnterEvadeMode(EvadeReason why) override
+ void JustDied(Unit* /*killer*/) override
{
- if (!Intro)
- BossAI::EnterEvadeMode(why);
+ _JustDied();
+
+ Talk(SAY_DEATH);
+
+ DoCastSelf(SPELL_SUMMON_DEATH_CLOUD, true);
+
+ if (Creature* madrigosa = instance->GetCreature(DATA_MADRIGOSA))
+ madrigosa->AI()->DoAction(ACTION_START_OUTRO);
}
- void StartIntro()
+ void UpdateAI(uint32 diff) override
{
- if (!Intro || IsIntro)
+ if (!UpdateVictim())
return;
- if (Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA))
- {
- Madrigosa->Respawn();
- Madrigosa->setActive(true);
- Madrigosa->SetFarVisible(true);
- IsIntro = true;
- Madrigosa->SetMaxHealth(me->GetMaxHealth());
- Madrigosa->SetHealth(me->GetMaxHealth());
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->Attack(Madrigosa, true);
- Madrigosa->Attack(me, true);
- }
- else
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
{
- // Madrigosa not found, end intro
- TC_LOG_ERROR("scripts", "Madrigosa was not found");
- EndIntro();
+ switch (eventId)
+ {
+ case EVENT_METEOR_SLASH:
+ DoCastSelf(SPELL_METEOR_SLASH);
+ events.Repeat(12s);
+ break;
+ case EVENT_STOMP:
+ DoCastVictim(SPELL_STOMP);
+ events.Repeat(32s);
+ break;
+ case EVENT_BURN:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, 100.0f, true, true, -SPELL_BURN_DAMAGE))
+ DoCast(target, SPELL_BURN_PRIMER);
+ events.Repeat(20s);
+ break;
+ case EVENT_BERSERK:
+ DoCastSelf(SPELL_BERSERK);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
}
- }
- void EndIntro()
- {
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- Intro = false;
- IsIntro = false;
+ DoMeleeAttackIfReady();
}
+};
- void AttackStart(Unit* who) override
+// 24895 - Madrigosa
+struct npc_madrigosa : public ScriptedAI
+{
+ npc_madrigosa(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { }
+
+ void JustAppeared() override
{
- if (!who || Intro || IsIntro)
- return;
- BossAI::AttackStart(who);
+ _events.ScheduleEvent(EVENT_INTRO_1, 2500ms);
}
- void DoIntro()
+ void MovementInform(uint32 type, uint32 id) override
{
- Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA);
- if (!Madrigosa)
- return;
-
- switch (IntroPhase)
+ if (type == POINT_MOTION_TYPE)
{
- case 0:
- Madrigosa->AI()->Talk(YELL_MADR_ICE_BARRIER);
- IntroPhaseTimer = 7000;
- ++IntroPhase;
- break;
- case 1:
- me->SetFacingToObject(Madrigosa);
- Madrigosa->SetFacingToObject(me);
- Madrigosa->AI()->Talk(YELL_MADR_INTRO, me);
- IntroPhaseTimer = 9000;
- ++IntroPhase;
- break;
- case 2:
- Talk(YELL_INTRO, Madrigosa);
- IntroPhaseTimer = 13000;
- ++IntroPhase;
- break;
- case 3:
- DoCast(me, SPELL_INTRO_FROST_BLAST);
- Madrigosa->SetDisableGravity(true);
- me->AttackStop();
- Madrigosa->AttackStop();
- IntroFrostBoltTimer = 3000;
- IntroPhaseTimer = 28000;
- ++IntroPhase;
- break;
- case 4:
- Talk(YELL_INTRO_BREAK_ICE);
- IntroPhaseTimer = 6000;
- ++IntroPhase;
- break;
- case 5:
- Madrigosa->CastSpell(me, SPELL_INTRO_ENCAPSULATE_CHANELLING, false);
- Madrigosa->AI()->Talk(YELL_MADR_TRAP);
- DoCast(me, SPELL_INTRO_ENCAPSULATE);
- IntroPhaseTimer = 11000;
- ++IntroPhase;
- break;
- case 6:
- Talk(YELL_INTRO_CHARGE);
- IntroPhaseTimer = 5000;
- ++IntroPhase;
- break;
- case 7:
- Unit::Kill(me, Madrigosa);
- Madrigosa->AI()->Talk(YELL_MADR_DEATH);
- me->SetFullHealth();
- me->AttackStop();
- IntroPhaseTimer = 4000;
- ++IntroPhase;
- break;
- case 8:
- Talk(YELL_INTRO_KILL_MADRIGOSA);
- me->SetOrientation(0.14f);
- me->StopMoving();
- Madrigosa->setDeathState(CORPSE);
- IntroPhaseTimer = 8000;
- ++IntroPhase;
- break;
- case 9:
- Talk(YELL_INTRO_TAUNT);
- IntroPhaseTimer = 5000;
- ++IntroPhase;
- break;
- case 10:
- EndIntro();
- break;
+ switch (id)
+ {
+ case POINT_MADRIGOSA_LAND_1:
+ _events.ScheduleEvent(EVENT_INTRO_2, 0s);
+ break;
+ case POINT_MADRIGOSA_LIFTOFF:
+ _events.ScheduleEvent(EVENT_INTRO_9, 0s);
+ break;
+ case POINT_MADRIGOSA_LAND_2:
+ _events.ScheduleEvent(EVENT_INTRO_13, 0s);
+ break;
+ case POINT_MADRIGOSA_LAND_3:
+ _events.ScheduleEvent(EVENT_INTRO_14, 1s);
+ break;
+ default:
+ break;
+ }
}
}
- void MoveInLineOfSight(Unit* who) override
+ void DoAction(int32 action) override
{
- if (!me->IsValidAttackTarget(who))
- return;
-
- if (Intro)
- instance->SetBossState(DATA_BRUTALLUS, SPECIAL);
-
- if (Intro && !IsIntro)
- StartIntro();
+ if (action == ACTION_START_OUTRO)
+ _events.ScheduleEvent(EVENT_OUTRO_1, 1min);
+ }
- if (!Intro)
- BossAI::MoveInLineOfSight(who);
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
+ {
+ if (damage >= me->GetHealth())
+ damage = me->GetHealth() - 1;
}
+ /// @temporary: Find a better solution to end combat without breaking visuals (Feign Death)
+ void EnterEvadeMode(EvadeReason /*why*/) override { }
+
void UpdateAI(uint32 diff) override
{
- if (IsIntro)
- {
- if (IntroPhaseTimer <= diff)
- DoIntro();
- else IntroPhaseTimer -= diff;
+ _events.Update(diff);
- if (IntroPhase == 3 + 1)
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
{
- if (IntroFrostBoltTimer <= diff)
+ case EVENT_INTRO_1:
+ me->GetMotionMaster()->MovePoint(POINT_MADRIGOSA_LAND_1, MadrigosaMoveLandPos1);
+ break;
+ case EVENT_INTRO_2:
+ Talk(SAY_MADR_ICE_BARRIER);
+ if (Creature* trigger = _instance->GetCreature(DATA_WORLD_TRIGGER))
+ me->SetFacingToObject(trigger);
+ DoCastSelf(SPELL_FREEZE);
+ _events.ScheduleEvent(EVENT_INTRO_3, 7s);
+ break;
+ case EVENT_INTRO_3:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ me->SetFacingToObject(brutallus);
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ Talk(SAY_MADR_INTRO);
+ _events.ScheduleEvent(EVENT_INTRO_4, 6s);
+ break;
+ case EVENT_INTRO_4:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ brutallus->AI()->Talk(SAY_INTRO);
+ _events.ScheduleEvent(EVENT_INTRO_5, 4s);
+ break;
+ case EVENT_INTRO_5:
+ me->SetImmuneToNPC(false);
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ AttackStart(brutallus);
+ _events.ScheduleEvent(EVENT_INTRO_6, 5s);
+ break;
+ case EVENT_INTRO_6:
+ DoCastSelf(SPELL_FROST_BREATH);
+ _events.ScheduleEvent(EVENT_INTRO_7, 5s);
+ break;
+ case EVENT_INTRO_7:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
+ me->SetReactState(REACT_PASSIVE);
+ _events.ScheduleEvent(EVENT_INTRO_8, 2500ms);
+ break;
+ case EVENT_INTRO_8:
{
- if (Creature* Madrigosa = instance->GetCreature(DATA_MADRIGOSA))
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+ me->GetMotionMaster()->MovePoint(POINT_MADRIGOSA_LIFTOFF, MadrigosaMoveLiftoffPos);
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
{
- Madrigosa->CastSpell(me, SPELL_INTRO_FROSTBOLT, true);
- IntroFrostBoltTimer = 2000;
+ brutallus->SetDisableGravity(true);
+ brutallus->SetControlled(true, UNIT_STATE_ROOT);
}
+ break;
}
- else
- IntroFrostBoltTimer -= diff;
- }
+ case EVENT_INTRO_9:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ me->SetFacingToObject(brutallus);
+ Talk(SAY_MADR_ICE_BLOCK);
+ DoCastSelf(SPELL_FROST_BLAST);
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ brutallus->SetReactState(REACT_PASSIVE);
+ _events.ScheduleEvent(EVENT_FROSTBOLT, RAND(1200ms, 2400ms, 3600ms));
+ _events.ScheduleEvent(EVENT_INTRO_10, 8500ms);
+ break;
+ case EVENT_INTRO_10:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ brutallus->CastSpell(brutallus, SPELL_FLAME_RING_1);
+ _events.ScheduleEvent(EVENT_INTRO_11, 6s);
+ break;
+ case EVENT_INTRO_11:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->AI()->Talk(SAY_INTRO_BREAK_ICE);
+ /// @temporary: SPELL_CLEAR_ALL_DEBUFFS doesn't remove that aura
+ brutallus->RemoveAurasDueToSpell(SPELL_FROST_BLAST);
+ brutallus->CastSpell(brutallus, SPELL_CLEAR_ALL_DEBUFFS);
+ brutallus->CastSpell(brutallus, SPELL_FLAME_RING_2);
+ brutallus->SetFacingTo(1.383456826210021972f);
+ brutallus->CastSpell(brutallus, SPELL_FEL_FIREBALL);
+ brutallus->SetImmuneToNPC(true);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_12, 6s);
+ break;
+ }
+ case EVENT_INTRO_12:
+ me->GetMotionMaster()->MovePoint(POINT_MADRIGOSA_LAND_2, MadrigosaMoveLandPos2);
+ _events.CancelEvent(EVENT_FROSTBOLT);
+ break;
+ case EVENT_INTRO_13:
+ me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
+ me->GetMotionMaster()->MovePoint(POINT_MADRIGOSA_LAND_3, MadrigosaMoveLandPos3);
+ me->SetAnimTier(AnimTier::Ground);
+ break;
+ case EVENT_INTRO_14:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ me->SetFacingToObject(brutallus);
+ _events.ScheduleEvent(EVENT_INTRO_15, 2500ms);
+ break;
+ case EVENT_INTRO_15:
+ {
+ DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS);
+ DoCastSelf(SPELL_ENCAPSULATE);
+ Talk(SAY_MADR_TRAP);
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->SetDisableGravity(false);
+ brutallus->SetControlled(false, UNIT_STATE_ROOT);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_16, 1500ms);
+ break;
+ }
+ case EVENT_INTRO_16:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->SetDisableGravity(true);
+ brutallus->SetHover(true);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_17, 2s);
+ break;
+ }
+ case EVENT_INTRO_17:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ brutallus->GetMotionMaster()->MovePoint(POINT_BRUTALLUS_OFFSET, BrutallusMoveOffsetPos);
+ _events.ScheduleEvent(EVENT_INTRO_18, 9s);
+ break;
+ case EVENT_INTRO_18:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->CastSpell(brutallus, SPELL_ARCANE_EXPLOSION_VISUAL);
+ brutallus->CastSpell(brutallus, SPELL_CLEAR_ALL_DEBUFFS);
+ brutallus->AI()->Talk(SAY_INTRO_CHARGE);
+ brutallus->GetMotionMaster()->MoveFall();
+ }
+ me->InterruptNonMeleeSpells(false);
+ _events.ScheduleEvent(EVENT_INTRO_19, 1s);
+ break;
+ }
+ case EVENT_INTRO_19:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ me->SetFacingToObject(brutallus);
+ DoCastSelf(SPELL_SELF_STUN);
+ me->SetImmuneToNPC(true);
+ _events.ScheduleEvent(EVENT_INTRO_20, 1500ms);
+ break;
+ case EVENT_INTRO_20:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->SetDisableGravity(false);
+ brutallus->SetHover(false);
+ brutallus->CastSpell(brutallus, SPELL_CHARGE);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_21, 1s);
+ break;
+ }
+ case EVENT_INTRO_21:
+ me->RemoveAurasDueToSpell(SPELL_SELF_STUN);
+ DoCastSelf(SPELL_PERMANENT_FEIGN_DEATH);
+ Talk(SAY_MADR_DEATH);
+ _events.ScheduleEvent(EVENT_INTRO_22, 2s);
+ break;
+ case EVENT_INTRO_22:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ brutallus->CastSpell(brutallus, SPELL_CLEAR_RETURN_STATE);
+ _events.ScheduleEvent(EVENT_INTRO_23, 1s);
+ break;
+ case EVENT_INTRO_23:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->CastSpell(brutallus, SPELL_FULL_HEAL);
+ brutallus->GetMotionMaster()->MovePoint(POINT_BRUTALLUS_COMBAT, BrutallusMoveCombatPos);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_24, 3500ms);
+ break;
+ }
+ case EVENT_INTRO_24:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->AI()->Talk(SAY_INTRO_KILL_MADRIGOSA);
+ brutallus->SetFacingTo(0.069813169538974761f);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_25, 7s);
+ break;
+ }
+ case EVENT_INTRO_25:
+ {
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->AI()->Talk(SAY_INTRO_TAUNT);
+ brutallus->CastSpell(brutallus, SPELL_BREAK_ICE);
+ }
+ _events.ScheduleEvent(EVENT_INTRO_26, 2500ms);
+ break;
+ }
+ case EVENT_INTRO_26:
+ {
+ me->SetHomePosition(me->GetPosition());
- if (!UpdateVictim())
- return;
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ {
+ brutallus->SetImmuneToNPC(false);
+ brutallus->SetHomePosition(brutallus->GetPosition());
+ brutallus->SetReactState(REACT_AGGRESSIVE);
+ /// @temporary: Should not be called, find a better solution to end combat
+ brutallus->AI()->EnterEvadeMode();
+ }
+ break;
+ }
- DoMeleeAttackIfReady();
+ case EVENT_FROSTBOLT:
+ if (Creature* brutallus = _instance->GetCreature(DATA_BRUTALLUS))
+ DoCast(brutallus, SPELL_FROSTBOLT);
+ _events.Repeat(RAND(1200ms, 2400ms, 3600ms));
+ break;
+
+ case EVENT_OUTRO_1:
+ DoCastSelf(SPELL_SUMMON_FELBLAZE_PRE_VISUAL);
+ _events.ScheduleEvent(EVENT_OUTRO_2, 3s);
+ break;
+ case EVENT_OUTRO_2:
+ // We are not ready to summon Felmyst (currently it creates double spawn)
+ // DoCastSelf(SPELL_SUMMON_FELBLAZE);
+ _events.ScheduleEvent(EVENT_OUTRO_3, 9s);
+ break;
+ case EVENT_OUTRO_3:
+ me->DespawnOrUnsummon();
+ break;
+ default:
+ break;
+ }
}
- if (!UpdateVictim() || IsIntro)
- return;
+ if (UpdateVictim())
+ DoMeleeAttackIfReady();
+ }
- if (SlashTimer <= diff)
- {
- DoCastVictim(SPELL_METEOR_SLASH);
- SlashTimer = 11000;
- } else SlashTimer -= diff;
+private:
+ EventMap _events;
+ InstanceScript* _instance;
+};
- if (StompTimer <= diff)
- {
- Talk(YELL_LOVE);
- DoCastVictim(SPELL_STOMP);
- StompTimer = 30000;
- } else StompTimer -= diff;
+// 45141 - Burn
+class spell_brutallus_burn_primer : public SpellScript
+{
+ PrepareSpellScript(spell_brutallus_burn_primer);
- if (BurnTimer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true, true, -SPELL_BURN))
- target->CastSpell(target, SPELL_BURN, true);
- BurnTimer = urand(60000, 180000);
- } else BurnTimer -= diff;
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_BURN_DAMAGE });
+ }
- if (BerserkTimer < diff && !Enraged)
- {
- Talk(YELL_BERSERK);
- DoCast(me, SPELL_BERSERK);
- Enraged = true;
- } else BerserkTimer -= diff;
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ if (!target->HasAura(SPELL_BURN_DAMAGE))
+ target->CastSpell(target, SPELL_BURN_DAMAGE, true);
+ }
- DoMeleeAttackIfReady();
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_brutallus_burn_primer::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 45151 - Burn
+class spell_brutallus_burn_ally : public SpellScript
+{
+ PrepareSpellScript(spell_brutallus_burn_ally);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_BURN_DAMAGE });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ if (!target->HasAura(SPELL_BURN_DAMAGE))
+ target->CastSpell(target, SPELL_BURN_DAMAGE, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_brutallus_burn_ally::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
@@ -353,12 +640,12 @@ class spell_brutallus_stomp : public SpellScript
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- return ValidateSpellInfo({ SPELL_BURN });
+ return ValidateSpellInfo({ SPELL_BURN_DAMAGE });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
- GetHitUnit()->RemoveAurasDueToSpell(SPELL_BURN);
+ GetHitUnit()->RemoveAurasDueToSpell(SPELL_BURN_DAMAGE);
}
void Register() override
@@ -367,9 +654,96 @@ class spell_brutallus_stomp : public SpellScript
}
};
+// 46609 - Freeze
+class spell_brutallus_freeze : public SpellScript
+{
+ PrepareSpellScript(spell_brutallus_freeze);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_FREEZE_OBJECT });
+ }
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_FREEZE_OBJECT);
+
+ /// @temporary: ActivateObject from the spell above doesn't work
+ if (InstanceScript* instance = GetHitUnit()->GetInstanceScript())
+ {
+ if (GameObject* iceBarrier = instance->GetGameObject(DATA_ICE_BARRIER))
+ {
+ iceBarrier->SetLootState(GO_READY);
+ iceBarrier->UseDoorOrButton();
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_brutallus_freeze::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+// 46637 - Break Ice
+class spell_brutallus_break_ice : public AuraScript
+{
+ PrepareAuraScript(spell_brutallus_break_ice);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_BREAK_ICE_OBJECT, SPELL_BREAK_ICE_KNOCK_BACK });
+ }
+
+ void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->CastSpell(GetTarget(), SPELL_BREAK_ICE_OBJECT);
+
+ /// @temporary: ActivateObject from the spell above doesn't work
+ if (InstanceScript* instance = GetTarget()->GetInstanceScript())
+ {
+ if (GameObject* iceBarrier = instance->GetGameObject(DATA_ICE_BARRIER))
+ {
+ iceBarrier->SetLootState(GO_READY);
+ iceBarrier->UseDoorOrButton();
+ }
+ }
+ }
+
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->CastSpell(GetTarget(), SPELL_BREAK_ICE_KNOCK_BACK);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_brutallus_break_ice::AfterApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_brutallus_break_ice::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 4853
+class at_the_dead_scar : public OnlyOnceAreaTriggerScript
+{
+public:
+ at_the_dead_scar() : OnlyOnceAreaTriggerScript("at_the_dead_scar") { }
+
+ bool TryHandleOnce(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override
+ {
+ player->SummonCreature(NPC_MADRIGOSA, MadrigosaSpawnPos, TEMPSUMMON_MANUAL_DESPAWN);
+ return true;
+ }
+};
+
void AddSC_boss_brutallus()
{
RegisterSunwellPlateauCreatureAI(boss_brutallus);
+ RegisterSunwellPlateauCreatureAI(npc_madrigosa);
+ RegisterSpellScript(spell_brutallus_burn_primer);
+ RegisterSpellScript(spell_brutallus_burn_ally);
RegisterSpellScript(spell_brutallus_burn);
RegisterSpellScript(spell_brutallus_stomp);
+ RegisterSpellScript(spell_brutallus_freeze);
+ RegisterSpellScript(spell_brutallus_break_ice);
+ new at_the_dead_scar();
}
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
index c2960845be9..baad3460be8 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
@@ -50,6 +50,7 @@ ObjectData const creatureData[] =
{ NPC_SATHROVARR, DATA_SATHROVARR },
{ NPC_BRUTALLUS, DATA_BRUTALLUS },
{ NPC_MADRIGOSA, DATA_MADRIGOSA },
+ { NPC_WORLD_TRIGGER, DATA_WORLD_TRIGGER },
{ NPC_FELMYST, DATA_FELMYST },
{ NPC_GRAND_WARLOCK_ALYTHESS, DATA_ALYTHESS },
{ NPC_LADY_SACROLASH, DATA_SACROLASH },
@@ -61,6 +62,12 @@ ObjectData const creatureData[] =
{ 0, 0 } // END
};
+ObjectData const gameObjectData[] =
+{
+ { GO_ICE_BARRIER, DATA_ICE_BARRIER },
+ { 0, 0 } //END
+};
+
BossBoundaryData const boundaries =
{
{ DATA_KALECGOS, new BoundaryUnionBoundary(new CircleBoundary(Position(1704.9f, 928.4f), 34.0), new RectangleBoundary(1689.2f, 1713.3f, 762.2f, 1074.8f)) }
@@ -78,7 +85,7 @@ class instance_sunwell_plateau : public InstanceMapScript
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadDoorData(doorData);
- LoadObjectData(creatureData, nullptr);
+ LoadObjectData(creatureData, gameObjectData);
LoadBossBoundaries(boundaries);
}
diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h b/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h
index 2ddb4233a18..7dfc6e55329 100644
--- a/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h
+++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/sunwell_plateau.h
@@ -39,6 +39,7 @@ enum SWPDataTypes
DATA_KALECGOS_HUMAN,
DATA_SATHROVARR,
DATA_MADRIGOSA,
+ DATA_WORLD_TRIGGER,
DATA_ALYTHESS,
DATA_SACROLASH,
DATA_KILJAEDEN_CONTROLLER,
@@ -51,6 +52,8 @@ enum SWPDataTypes
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4,
+ DATA_ICE_BARRIER,
+
// Misc
DATA_PLAYER_GUID
};
@@ -63,9 +66,12 @@ enum SWPCreatureIds
NPC_KALECGOS_HUMAN = 24891,
NPC_SATHROVARR = 24892,
NPC_BRUTALLUS = 24882,
- NPC_MADRIGOSA = 24895,
NPC_FELMYST = 25038,
+ // Brutallus
+ NPC_MADRIGOSA = 24895,
+ NPC_WORLD_TRIGGER = 19871,
+
NPC_DEAD = 25268,
NPC_FLIGHT_LEFT = 25357,
NPC_FLIGHT_RIGHT = 25358,
@@ -112,7 +118,8 @@ enum SWPGameObjectIds
GO_FIRE_BARRIER = 188075,
GO_MURUS_GATE_1 = 187990,
GO_MURUS_GATE_2 = 188118,
- GO_SPECTRAL_RIFT = 187055
+ GO_SPECTRAL_RIFT = 187055,
+ GO_ICE_BARRIER = 188119
};
template <class AI, class T>