diff options
-rw-r--r-- | sql/updates/world/3.3.5/2025_09_14_00_world.sql | 17 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp | 463 |
2 files changed, 268 insertions, 212 deletions
diff --git a/sql/updates/world/3.3.5/2025_09_14_00_world.sql b/sql/updates/world/3.3.5/2025_09_14_00_world.sql new file mode 100644 index 00000000000..7e6935f0cdc --- /dev/null +++ b/sql/updates/world/3.3.5/2025_09_14_00_world.sql @@ -0,0 +1,17 @@ +-- +UPDATE `creature_template` SET `flags_extra` = `flags_extra`&~2 WHERE `entry` = 15514; +UPDATE `creature` SET `spawntimesecs` = 120 WHERE `id` = 15514; + +UPDATE `spell_script_names` SET `ScriptName` = 'spell_buru_egg_explosion' WHERE `ScriptName` = 'spell_egg_explosion'; + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` IN (15521,15964); +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (15521,15964) 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 +(15521,0,0,0,37,0,100,0,0,0,0,0,0,116,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Hive'Zara Hatchling - On AI Initialize - Set Corpse Delay"), +(15521,0,1,0,11,0,100,0,0,0,0,0,0,38,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Hive'Zara Hatchling - On Spawn - Set In Combat With Zone"), + +(15964,0,0,0,11,0,100,0,0,0,0,0,0,11,26646,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Buru Egg Trigger - On Spawn - Cast 'Buru Egg Trigger Effect'"); + +DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_buru_cancel_creeping_plague'; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(27027, 'spell_buru_cancel_creeping_plague'); diff --git a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp index cfb19483d79..207566ce11a 100644 --- a/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp +++ b/src/server/scripts/Kalimdor/RuinsOfAhnQiraj/boss_buru.cpp @@ -20,266 +20,305 @@ #include "ObjectAccessor.h" #include "ruins_of_ahnqiraj.h" #include "ScriptedCreature.h" +#include "SpellInfo.h" #include "SpellScript.h" -enum Emotes +enum BuruTexts { - EMOTE_TARGET = 0 + EMOTE_TARGET = 0 }; -enum Spells +enum BuruSpells { - SPELL_CREEPING_PLAGUE = 20512, - SPELL_DISMEMBER = 96, - SPELL_GATHERING_SPEED = 1834, - SPELL_FULL_SPEED = 1557, - SPELL_THORNS = 25640, - SPELL_BURU_TRANSFORM = 24721, - SPELL_SUMMON_HATCHLING = 1881, - SPELL_EXPLODE = 19593, - SPELL_EXPLODE_2 = 5255, - SPELL_BURU_EGG_TRIGGER = 26646 + // Phase 1 + SPELL_DISMEMBER = 96, + SPELL_GATHERING_SPEED = 1834, + SPELL_FULL_SPEED = 1557, + + // Phase 2 + SPELL_CREEPING_PLAGUE = 20512, + + // Misc + SPELL_THORNS = 25640, + SPELL_CREATURE_SPECIAL = 7155, + SPELL_BURU_TRANSFORM = 24721, + SPELL_CANCEL_CREEPING_PLAGUE = 27027, + + // Buru Egg + SPELL_EGG_EXPLOSION = 19593, + SPELL_SUMMON_HATCHLING = 1881, + + // Scripts + SPELL_EXPLOSION = 5255 }; -enum Events +enum BuruEvents { - EVENT_DISMEMBER = 1, - EVENT_GATHERING_SPEED = 2, - EVENT_FULL_SPEED = 3, - EVENT_CREEPING_PLAGUE = 4, - EVENT_RESPAWN_EGG = 5 + EVENT_DISMEMBER = 1, + EVENT_GATHERING_SPEED, + EVENT_FULL_SPEED, + EVENT_CREEPING_PLAGUE, + + EVENT_TRANSFORM_1, + EVENT_TRANSFORM_2, + EVENT_TRANSFORM_3 }; -enum Phases +enum BuruPhases { - PHASE_EGG = 0, - PHASE_TRANSFORM = 1 + PHASE_EGG = 0, + PHASE_TRANSFORM = 1 }; -enum Actions +// 15370 - Buru the Gorger +struct boss_buru : public BossAI { - ACTION_EXPLODE = 0 -}; + boss_buru(Creature* creature) : BossAI(creature, DATA_BURU), _phase(PHASE_EGG) { } -class boss_buru : public CreatureScript -{ - public: - boss_buru() : CreatureScript("boss_buru") { } + void Reset() override + { + _Reset(); + _phase = PHASE_EGG; + me->SetReactState(REACT_AGGRESSIVE); + } - struct boss_buruAI : public BossAI - { - boss_buruAI(Creature* creature) : BossAI(creature, DATA_BURU) - { - _phase = 0; - } + void JustEngagedWith(Unit* who) override + { + BossAI::JustEngagedWith(who); - void EnterEvadeMode(EvadeReason why) override - { - BossAI::EnterEvadeMode(why); - - for (ObjectGuid eggGuid : Eggs) - if (Creature* egg = ObjectAccessor::GetCreature(*me, eggGuid)) - egg->Respawn(); - - Eggs.clear(); - } - - void JustEngagedWith(Unit* who) override - { - BossAI::JustEngagedWith(who); - Talk(EMOTE_TARGET, who); - DoCast(me, SPELL_THORNS); - - events.ScheduleEvent(EVENT_DISMEMBER, 5s); - events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s); - events.ScheduleEvent(EVENT_FULL_SPEED, 1min); - - _phase = PHASE_EGG; - } - - void DoAction(int32 action) override - { - if (action == ACTION_EXPLODE) - if (_phase == PHASE_EGG) - Unit::DealDamage(me, me, 45000); - } + DoCastSelf(SPELL_THORNS); - void KilledUnit(Unit* victim) override - { - if (victim->GetTypeId() == TYPEID_PLAYER) - ChaseNewVictim(); - } + ChaseNewVictim(); - void ChaseNewVictim() - { - if (_phase != PHASE_EGG) - return; + events.ScheduleEvent(EVENT_DISMEMBER, 10s, 15s); + events.ScheduleEvent(EVENT_GATHERING_SPEED, 2s); + events.ScheduleEvent(EVENT_FULL_SPEED, 1min); + } - me->RemoveAurasDueToSpell(SPELL_FULL_SPEED); + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + switch (spellInfo->Id) + { + case SPELL_EXPLOSION: me->RemoveAurasDueToSpell(SPELL_GATHERING_SPEED); - events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s); - events.ScheduleEvent(EVENT_FULL_SPEED, 1min); + me->RemoveAurasDueToSpell(SPELL_FULL_SPEED); + DoCastSelf(SPELL_CREATURE_SPECIAL); + break; + case SPELL_CREATURE_SPECIAL: + ChaseNewVictim(); + break; + default: + break; + } + } - if (Unit* victim = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) - { - ResetThreatList(); - AttackStart(victim); - Talk(EMOTE_TARGET, victim); - } - } + void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override + { + if (_phase == PHASE_EGG && me->HealthBelowPctDamaged(20, damage)) + { + _phase = PHASE_TRANSFORM; + events.ScheduleEvent(EVENT_TRANSFORM_1, 0s); + } + } - void ManageRespawn(ObjectGuid EggGUID) - { - ChaseNewVictim(); - Eggs.push_back(EggGUID); - events.ScheduleEvent(EVENT_RESPAWN_EGG, 100s); - } + void KilledUnit(Unit* /*victim*/) override + { + // Triggers even if victim is a creature. Victim can be a creature if it reaches first position in threat list + ChaseNewVictim(); + } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; - - events.Update(diff); - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_DISMEMBER: - DoCastVictim(SPELL_DISMEMBER); - events.ScheduleEvent(EVENT_DISMEMBER, 5s); - break; - case EVENT_GATHERING_SPEED: - DoCast(me, SPELL_GATHERING_SPEED); - events.ScheduleEvent(EVENT_GATHERING_SPEED, 9s); - break; - case EVENT_FULL_SPEED: - DoCast(me, SPELL_FULL_SPEED); - break; - case EVENT_CREEPING_PLAGUE: - DoCast(me, SPELL_CREEPING_PLAGUE); - events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 6s); - break; - case EVENT_RESPAWN_EGG: - if (Creature* egg = ObjectAccessor::GetCreature(*me, Eggs.front())) - { - egg->Respawn(); - Eggs.pop_front(); - } - break; - default: - break; - } - } - - if (me->GetHealthPct() < 20.0f && _phase == PHASE_EGG) - { - DoCast(me, SPELL_BURU_TRANSFORM); // Enrage - DoCast(me, SPELL_FULL_SPEED, true); - me->RemoveAurasDueToSpell(SPELL_THORNS); - _phase = PHASE_TRANSFORM; - } + void ChaseNewVictim() + { + if (_phase != PHASE_EGG) + return; - DoMeleeAttackIfReady(); - } - private: - GuidList Eggs; - uint8 _phase; - }; + events.RescheduleEvent(EVENT_GATHERING_SPEED, 9s); + events.RescheduleEvent(EVENT_FULL_SPEED, 1min); + + ResetThreatList(); - CreatureAI* GetAI(Creature* creature) const override + if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true)) { - return GetAQ20AI<boss_buruAI>(creature); + AddThreat(target, 1000000.0f); + AttackStart(target); + Talk(EMOTE_TARGET, target); } -}; + } -class npc_buru_egg : public CreatureScript -{ - public: - npc_buru_egg() : CreatureScript("npc_buru_egg") { } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + DoCastSelf(SPELL_CANCEL_CREEPING_PLAGUE); + } - struct npc_buru_eggAI : public ScriptedAI - { - npc_buru_eggAI(Creature* creature) : ScriptedAI(creature) - { - _instance = me->GetInstanceScript(); - SetCombatMovement(false); - } + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; - void JustEngagedWith(Unit* attacker) override - { - if (Creature* buru = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BURU))) - if (!buru->IsInCombat()) - buru->AI()->AttackStart(attacker); - } + events.Update(diff); - void JustSummoned(Creature* who) override - { - if (who->GetEntry() == NPC_HATCHLING) - if (Creature* buru = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BURU))) - if (Unit* target = buru->AI()->SelectTarget(SelectTargetMethod::Random)) - who->AI()->AttackStart(target); - } + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; - void JustDied(Unit* /*killer*/) override + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) { - DoCastAOE(SPELL_EXPLODE, true); - DoCastAOE(SPELL_EXPLODE_2, true); // Unknown purpose - DoCast(me, SPELL_SUMMON_HATCHLING, true); - - if (Creature* buru = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BURU))) - if (boss_buru::boss_buruAI* buruAI = dynamic_cast<boss_buru::boss_buruAI*>(buru->AI())) - buruAI->ManageRespawn(me->GetGUID()); + // Phase 1 + case EVENT_DISMEMBER: + DoCastVictim(SPELL_DISMEMBER); + events.Repeat(6s, 8s); + break; + case EVENT_GATHERING_SPEED: + DoCastSelf(SPELL_GATHERING_SPEED); + events.Repeat(9s); + break; + case EVENT_FULL_SPEED: + DoCastSelf(SPELL_FULL_SPEED); + break; + + // Phase 2 + case EVENT_CREEPING_PLAGUE: + DoCastSelf(SPELL_CREEPING_PLAGUE); + events.Repeat(6s); + break; + + // Transform + case EVENT_TRANSFORM_1: + me->ResetPlayerDamageReq(); + me->SetReactState(REACT_PASSIVE); + events.CancelEvent(EVENT_DISMEMBER); + events.CancelEvent(EVENT_GATHERING_SPEED); + events.CancelEvent(EVENT_FULL_SPEED); + ResetThreatList(); + events.ScheduleEvent(EVENT_TRANSFORM_2, 3s + 500ms); + break; + case EVENT_TRANSFORM_2: + me->RemoveAurasDueToSpell(SPELL_THORNS); + DoCastSelf(SPELL_BURU_TRANSFORM); + events.ScheduleEvent(EVENT_TRANSFORM_3, 6s); + break; + case EVENT_TRANSFORM_3: + me->SetReactState(REACT_AGGRESSIVE); + DoCastSelf(SPELL_FULL_SPEED); + events.ScheduleEvent(EVENT_CREEPING_PLAGUE, 2s); + break; + default: + break; } - private: - InstanceScript* _instance; - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetAQ20AI<npc_buru_eggAI>(creature); + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; } + + DoMeleeAttackIfReady(); + } + +private: + uint8 _phase; }; -// 19593 - Egg Explosion -class spell_egg_explosion : public SpellScriptLoader +// 15514 - Buru Egg +struct npc_buru_egg : public ScriptedAI { - public: - spell_egg_explosion() : SpellScriptLoader("spell_egg_explosion") { } - - class spell_egg_explosion_SpellScript : public SpellScript + npc_buru_egg(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } + + void InitializeAI() override + { + me->SetCorpseDelay(4, true); + me->SetReactState(REACT_PASSIVE); + } + + void JustEngagedWith(Unit* who) override + { + if (Creature* buru = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_BURU))) + if (!buru->IsInCombat()) + buru->AI()->AttackStart(who); + } + + void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override + { + if (spellInfo->Id == SPELL_BURU_TRANSFORM) { - PrepareSpellScript(spell_egg_explosion_SpellScript); + DoCastSelf(SPELL_SUMMON_HATCHLING); + me->DespawnOrUnsummon(); + } + } - void HandleAfterCast() - { - if (Creature* buru = GetCaster()->FindNearestCreature(NPC_BURU, 5.f)) - buru->AI()->DoAction(ACTION_EXPLODE); - } + void JustDied(Unit* /*killer*/) override + { + DoCastSelf(SPELL_EGG_EXPLOSION); + DoCastSelf(SPELL_SUMMON_HATCHLING, true); + } - void HandleDummyHitTarget(SpellEffIndex /*effIndex*/) - { - if (Unit* target = GetHitUnit()) - Unit::DealDamage(GetCaster(), target, -16 * GetCaster()->GetDistance(target) + 500); - } +private: + InstanceScript* _instance; +}; - void Register() override - { - AfterCast += SpellCastFn(spell_egg_explosion_SpellScript::HandleAfterCast); - OnEffectHitTarget += SpellEffectFn(spell_egg_explosion_SpellScript::HandleDummyHitTarget, EFFECT_0, SPELL_EFFECT_DUMMY); - } - }; +// 19593 - Egg Explosion +class spell_buru_egg_explosion : public SpellScript +{ + PrepareSpellScript(spell_buru_egg_explosion); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_EXPLOSION }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + + int32 damage = 0; + + if (target->IsPet() || target->IsPlayer()) + // Damage from 100 - 500 based on proximity - max range 25. Pets are valid targets here + damage = 100 + ((25 - std::min(caster->GetExactDist2d(target), 25.f)) / 25.f) * 400; + + // Buru has different formula + else if (target->GetEntry() == NPC_BURU) + if (target->GetHealthPct() > 20.0f) + /// @todo: This requires additional research as it doesn't seem right, doesn't it depend on proximity? + damage = target->GetMaxHealth() * 15 / 100; + + CastSpellExtraArgs args; + args.AddSpellBP0(damage); + caster->CastSpell(target, SPELL_EXPLOSION, args); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_buru_egg_explosion::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; - SpellScript* GetSpellScript() const override - { - return new spell_egg_explosion_SpellScript(); - } +// 27027 - Cancel Creeping Plague +class spell_buru_cancel_creeping_plague : public SpellScript +{ + PrepareSpellScript(spell_buru_cancel_creeping_plague); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_CREEPING_PLAGUE }); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->RemoveAurasDueToSpell(SPELL_CREEPING_PLAGUE); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_buru_cancel_creeping_plague::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } }; void AddSC_boss_buru() { - new boss_buru(); - new npc_buru_egg(); - new spell_egg_explosion(); + RegisterAQ20CreatureAI(boss_buru); + RegisterAQ20CreatureAI(npc_buru_egg); + RegisterSpellScript(spell_buru_egg_explosion); + RegisterSpellScript(spell_buru_cancel_creeping_plague); } |