From fd7689781828cbdf453cab357c550a2a93224bef Mon Sep 17 00:00:00 2001 From: insunaa Date: Wed, 22 Feb 2023 12:07:22 +0100 Subject: [PATCH] Ulduar: Convert Auriaya to BossAI Closes https://github.com/cmangos/mangos-wotlk/pull/440 --- sql/scriptdev2/spell.sql | 2 + .../northrend/ulduar/ulduar/boss_auriaya.cpp | 409 +++++++----------- src/game/Spells/SpellEffects.cpp | 9 - 3 files changed, 158 insertions(+), 262 deletions(-) diff --git a/sql/scriptdev2/spell.sql b/sql/scriptdev2/spell.sql index 939045428b0..8e68ef58525 100644 --- a/sql/scriptdev2/spell.sql +++ b/sql/scriptdev2/spell.sql @@ -992,8 +992,10 @@ INSERT INTO spell_scripts(Id, ScriptName) VALUES (64235,'spell_void_zone_xt'), (64411,'spell_blessing_of_ancient_kings'), (64415,'spell_valanyr_equip_effect'), +(64456,'spell_feral_essence_removal'), (64475,'spell_ignis_remove_strength'), (64503,'spell_ignis_water'), +(64386,'spell_terrifying_screech'), (64568,'spell_blood_reserve_enchant'), (65121,'spell_searing_light'), (65272,'spell_shatter_chest'), diff --git a/src/game/AI/ScriptDevAI/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp b/src/game/AI/ScriptDevAI/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp index ea032bb0593..d4c5d750ac2 100644 --- a/src/game/AI/ScriptDevAI/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp +++ b/src/game/AI/ScriptDevAI/scripts/northrend/ulduar/ulduar/boss_auriaya.cpp @@ -23,16 +23,15 @@ EndScriptData */ #include "AI/ScriptDevAI/include/sc_common.h" #include "ulduar.h" +#include "AI/ScriptDevAI/base/BossAI.h" enum { - SAY_AGGRO = -1603079, - SAY_SLAY_1 = -1603080, - SAY_SLAY_2 = -1603081, - SAY_BERSERK = -1603082, - SAY_DEATH = -1603083, - EMOTE_SCREECH = -1603084, - EMOTE_DEFENDER = -1603085, + SAY_AGGRO = 34341, + SAY_SLAY_1 = 34355, + SAY_SLAY_2 = 34354, + SAY_BERSERK = 34358, + EMOTE_DEFENDER = 34162, // Auriaya SPELL_BERSERK = 47008, @@ -63,329 +62,233 @@ enum NPC_SEEPING_FERAL_ESSENCE = 34098, // summoned by the feral defender on feign death // NPC_GUARDIAN_SWARN = 34034, // summoned by spell NPC_FERAL_DEFENDER_STALKER = 34096, + + SOUND_DEATH = 15476, }; /*###### ## boss_auriaya ######*/ -struct boss_auriayaAI : public ScriptedAI +enum AuriayaActions { - boss_auriayaAI(Creature* pCreature) : ScriptedAI(pCreature) - { - m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - Reset(); - } - - instance_ulduar* m_pInstance; - bool m_bIsRegularMode; - - uint32 m_uiEnrageTimer; - uint32 m_uiSwarmTimer; - uint32 m_uiSonicScreechTimer; - uint32 m_uiSentinelBlastTimer; - uint32 m_uiTerrifyingScreechTimer; - uint32 m_uiDefenderTimer; - - void Reset() override - { - m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; - m_uiSwarmTimer = 50000; - m_uiSonicScreechTimer = 58000; - m_uiSentinelBlastTimer = 40000; - m_uiTerrifyingScreechTimer = 38000; - m_uiDefenderTimer = 1 * MINUTE * IN_MILLISECONDS; - } - - void JustDied(Unit* /*pKiller*/) override - { - DoScriptText(SAY_DEATH, m_creature); - - if (m_pInstance) - m_pInstance->SetData(TYPE_AURIAYA, DONE); - } + AURIAYA_DEFENDER, + AURIAYA_ACTIONS_MAX, +}; - void Aggro(Unit* /*pWho*/) override +struct boss_auriayaAI : public BossAI +{ + boss_auriayaAI(Creature* creature) : BossAI(creature, AURIAYA_ACTIONS_MAX), + m_instance(dynamic_cast(creature->GetInstanceData())), + m_isRegularMode(creature->GetMap()->IsRegularDifficulty()) { - if (m_pInstance) - m_pInstance->SetData(TYPE_AURIAYA, IN_PROGRESS); - - DoScriptText(SAY_AGGRO, m_creature); + SetDataType(TYPE_AURIAYA); + AddOnAggroText(SAY_AGGRO); + AddOnKillText(SAY_SLAY_1, SAY_SLAY_2); + AddCombatAction(AURIAYA_DEFENDER, 1min); } - void KilledUnit(Unit* /*pVictim*/) override - { - DoScriptText(urand(0, 1) ? SAY_SLAY_1 : SAY_SLAY_2, m_creature); - } + instance_ulduar* m_instance; + bool m_isRegularMode; - void JustReachedHome() override + void JustDied(Unit* killer) override { - if (m_pInstance) - m_pInstance->SetData(TYPE_AURIAYA, FAIL); + BossAI::JustDied(killer); + m_creature->PlayDirectSound(SOUND_DEATH); } - void JustSummoned(Creature* pSummoned) override + void JustSummoned(Creature* summoned) override { // Summon the feral defender - if (pSummoned->GetEntry() == NPC_FERAL_DEFENDER_STALKER) - DoCastSpellIfCan(pSummoned, SPELL_ACTIVATE_FERAL_DEFENDER, CAST_INTERRUPT_PREVIOUS); + if (summoned->GetEntry() == NPC_FERAL_DEFENDER_STALKER) + DoCastSpellIfCan(summoned, SPELL_ACTIVATE_FERAL_DEFENDER, CAST_INTERRUPT_PREVIOUS); } - void UpdateAI(const uint32 uiDiff) override + void ExecuteAction(uint32 action) override { - if (!m_creature->SelectHostileTarget() || !m_creature->GetVictim()) - return; - - if (m_uiTerrifyingScreechTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_TERRIFYING_SCREECH) == CAST_OK) - { - DoScriptText(EMOTE_SCREECH, m_creature); - m_uiTerrifyingScreechTimer = 35000; - m_uiSentinelBlastTimer = 2000; - } - } - else - m_uiTerrifyingScreechTimer -= uiDiff; - - if (m_uiSentinelBlastTimer < uiDiff) - { - // Cast Sentinel blast right after terrifying screech - if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SENTINEL_BLAST : SPELL_SENTINEL_BLAST_H) == CAST_OK) - m_uiSentinelBlastTimer = 35000; - } - else - m_uiSentinelBlastTimer -= uiDiff; - - if (m_uiDefenderTimer) + switch (action) { - if (m_uiDefenderTimer <= uiDiff) + case AURIAYA_DEFENDER: { - // Summon the feral defender trigger if (DoCastSpellIfCan(m_creature, SPELL_ACTIVATE_FERAL_DEFENDER_TRIGG) == CAST_OK) - m_uiDefenderTimer = 0; - } - else - m_uiDefenderTimer -= uiDiff; - } - - if (m_uiSonicScreechTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_SONIC_SCREECH : SPELL_SONIC_SCREECH_H) == CAST_OK) - m_uiSonicScreechTimer = 27000; - } - else - m_uiSonicScreechTimer -= uiDiff; - - if (m_uiSwarmTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(pTarget, SPELL_GUARDIAN_SWARM) == CAST_OK) - m_uiSwarmTimer = 37000; - } - } - else - m_uiSwarmTimer -= uiDiff; - - if (m_uiEnrageTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, SPELL_BERSERK) == CAST_OK) - { - DoScriptText(SAY_BERSERK, m_creature); - m_uiEnrageTimer = 10 * MINUTE * IN_MILLISECONDS; + DisableCombatAction(action); + return; } + default: + return; } - else - m_uiEnrageTimer -= uiDiff; - - DoMeleeAttackIfReady(); } }; -UnitAI* GetAI_boss_auriaya(Creature* pCreature) -{ - return new boss_auriayaAI(pCreature); -} - /*###### ## boss_feral_defender ######*/ -struct boss_feral_defenderAI : public ScriptedAI +enum FeralDefenderActions +{ + FERAL_DEFENDER_FERAL_RUSH, + FERAL_DEFENDER_ACTIONS_MAX, + FERAL_DEFENDER_REVIVE, + FERAL_DEFENDER_RESTART_COMBAT, +}; + +struct boss_feral_defenderAI : public BossAI { - boss_feral_defenderAI(Creature* pCreature) : ScriptedAI(pCreature) + boss_feral_defenderAI(Creature* creature) : BossAI(creature, FERAL_DEFENDER_ACTIONS_MAX), + m_instance(dynamic_cast(creature->GetInstanceData())), + m_isRegularMode(creature->GetMap()->IsRegularDifficulty()), + m_feralRushCount(m_isRegularMode ? 6 :10) { - m_pInstance = (instance_ulduar*)pCreature->GetInstanceData(); - m_bIsRegularMode = pCreature->GetMap()->IsRegularDifficulty(); - m_uiMaxFeralRush = m_bIsRegularMode ? 6 : 10; - Reset(); + AddCombatAction(FERAL_DEFENDER_FERAL_RUSH, 3s, 5s); + AddCustomAction(FERAL_DEFENDER_REVIVE, true, [&]() + { + DoCastSpellIfCan(m_creature, SPELL_FULL_HEAL, CAST_TRIGGERED); + ResetTimer(FERAL_DEFENDER_RESTART_COMBAT, 3s); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + }); + AddCustomAction(FERAL_DEFENDER_RESTART_COMBAT, true, [&]() + { + DoResetThreat(); + m_creature->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); + m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNINTERACTIBLE); + m_creature->SetImmobilizedState(false, true); + SetCombatScriptStatus(false); + if (Creature* seepingFeralStalker = m_creature->GetMap()->GetCreature(m_seepingGuid)) + seepingFeralStalker->ForcedDespawn(); + + AddInitialCooldowns(); + ResetTimer(FERAL_DEFENDER_FERAL_RUSH, 1s); + }); + SetDeathPrevention(true); } - instance_ulduar* m_pInstance; - bool m_bIsRegularMode; + instance_ulduar* m_instance; + bool m_isRegularMode; - uint8 m_uiFeralRushCount; - uint8 m_uiMaxFeralRush; - uint32 m_uiPounceTimer; - uint32 m_uiFeralRushTimer; - uint32 m_uiReviveDelayTimer; - uint32 m_uiAttackDelayTimer; - uint32 m_uiKilledCount; + uint8 m_feralRushCount; + uint8 m_maxFeralRush; + uint8 m_deathCount; + + ObjectGuid m_seepingGuid; void Reset() override { - m_uiFeralRushCount = 0; - m_uiReviveDelayTimer = 0; - m_uiAttackDelayTimer = 0; - m_uiPounceTimer = urand(9000, 12000); - m_uiFeralRushTimer = urand(3000, 5000); - m_uiKilledCount = 0; + m_feralRushCount = 0; + m_deathCount = 0; DoCastSpellIfCan(m_creature, SPELL_FERAL_ESSENCE); } + void JustPreventedDeath(Unit* attacker) override + { + if (m_deathCount >= 7) + SetDeathPrevention(false); + DoCastSpellIfCan(m_creature, SPELL_FERAL_ESSENCE_REMOVAL, CAST_TRIGGERED); + DoCastSpellIfCan(m_creature, SPELL_SEEPING_FERAL_ESSENCE_SUMMON, CAST_TRIGGERED); + DoLimitedFakeDeath(SPELL_FEIGN_DEATH); + ++m_deathCount; + ResetTimer(FERAL_DEFENDER_REVIVE, 30s); + SetCombatScriptStatus(true); + } + void JustDied(Unit* /*pKiller*/) override { // Set achiev criteria to true - if (m_pInstance) - m_pInstance->SetSpecialAchievementCriteria(TYPE_ACHIEV_NINE_LIVES, true); + if (m_instance) + m_instance->SetSpecialAchievementCriteria(TYPE_ACHIEV_NINE_LIVES, true); } - void DamageTaken(Unit* /*pDealer*/, uint32& uiDamage, DamageEffectType /*damagetype*/, SpellEntry const* spellInfo) override + void JustSummoned(Creature* summoned) override { - // If we don't have the feral essence anymore then ignore this - if (m_uiKilledCount >= 8) // 9-1 == 8 - return; - - if (m_uiReviveDelayTimer) // Already faking - { - uiDamage = 0; - return; - } - - if (uiDamage >= m_creature->GetHealth()) + // Cast seeping feral essence on the summoned + if (summoned->GetEntry() == NPC_SEEPING_FERAL_ESSENCE) { - uiDamage = 0; - - // Set Feign death, remove one aura stack and summon a feral essence - DoCastSpellIfCan(m_creature, SPELL_FEIGN_DEATH, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_FERAL_ESSENCE_REMOVAL, CAST_TRIGGERED); - DoCastSpellIfCan(m_creature, SPELL_SEEPING_FERAL_ESSENCE_SUMMON, CAST_TRIGGERED); - - // the feign death aura doesn't do everything, so keep the following here as well - m_creature->SetHealth(0); - m_creature->ClearComboPointHolders(); - m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); - m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); - m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNINTERACTIBLE); - m_creature->ClearAllReactives(); - m_creature->GetMotionMaster()->Clear(); - m_creature->GetMotionMaster()->MoveIdle(); - m_creature->SetStandState(UNIT_STAND_STATE_DEAD); - - m_uiReviveDelayTimer = 30000; - ++m_uiKilledCount; + m_seepingGuid = summoned->GetObjectGuid(); + summoned->SetImmobilizedState(true); + summoned->CastSpell(summoned, m_isRegularMode ? SPELL_SEEPING_FERAL_ESSENCE : SPELL_SEEPING_FERAL_ESSENCE_H, TRIGGERED_OLD_TRIGGERED, nullptr, nullptr, m_creature->GetObjectGuid()); } } - void JustSummoned(Creature* pSummoned) override + void DoLimitedFakeDeath(uint32 spellId) { - // Cast seeping feral essence on the summoned - if (pSummoned->GetEntry() == NPC_SEEPING_FERAL_ESSENCE) - pSummoned->CastSpell(pSummoned, m_bIsRegularMode ? SPELL_SEEPING_FERAL_ESSENCE : SPELL_SEEPING_FERAL_ESSENCE_H, TRIGGERED_OLD_TRIGGERED, nullptr, nullptr, m_creature->GetObjectGuid()); + m_creature->InterruptNonMeleeSpells(false); + m_creature->InterruptMoving(); + m_creature->ClearComboPointHolders(); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_20_PERCENT, false); + m_creature->ModifyAuraState(AURA_STATE_HEALTHLESS_35_PERCENT, false); + m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNINTERACTIBLE); + m_creature->ClearAllReactives(); + m_creature->SetTarget(nullptr); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + m_creature->SetImmobilizedState(true, true); + + if (spellId) + DoCastSpellIfCan(nullptr, spellId, CAST_INTERRUPT_PREVIOUS); + ResetDeathPrevented(); } - void UpdateAI(const uint32 uiDiff) override + void ExecuteAction(uint32 action) override { - if (!m_creature->SelectHostileTarget() || !m_creature->GetVictim()) - return; - - if (m_uiReviveDelayTimer) - { - if (m_uiReviveDelayTimer <= uiDiff) - { - // ToDo: figure out how to enable the ressurrect animation - DoCastSpellIfCan(m_creature, SPELL_FULL_HEAL, CAST_TRIGGERED); - m_uiReviveDelayTimer = 0; - m_uiAttackDelayTimer = 3000; - } - else - m_uiReviveDelayTimer -= uiDiff; - - // No Further action while faking - return; - } - - if (m_uiAttackDelayTimer) + switch (action) { - if (m_uiAttackDelayTimer <= uiDiff) + case FERAL_DEFENDER_FERAL_RUSH: { - DoResetThreat(); - m_creature->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH); - m_creature->SetStandState(UNIT_STAND_STATE_STAND); - m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNINTERACTIBLE); - - m_uiPounceTimer = urand(9000, 10000); - m_uiFeralRushCount = 0; - m_uiFeralRushTimer = 1000; - m_uiAttackDelayTimer = 0; - } - else - m_uiAttackDelayTimer -= uiDiff; - - // No Further action while faking - return; - } - - if (m_uiPounceTimer < uiDiff) - { - if (Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0)) - { - if (DoCastSpellIfCan(pTarget, m_bIsRegularMode ? SPELL_FERAL_POUNCE : SPELL_FERAL_POUNCE_H) == CAST_OK) - m_uiPounceTimer = urand(13000, 16000); - } - } - else - m_uiPounceTimer -= uiDiff; - - if (m_uiFeralRushTimer < uiDiff) - { - if (DoCastSpellIfCan(m_creature, m_bIsRegularMode ? SPELL_FERAL_RUSH : SPELL_FERAL_RUSH_H) == CAST_OK) - { - ++m_uiFeralRushCount; - - if (m_uiFeralRushCount == m_uiMaxFeralRush) + if (DoCastSpellIfCan(nullptr, m_isRegularMode ? SPELL_FERAL_RUSH : SPELL_FERAL_RUSH_H) == CAST_OK) { - m_uiFeralRushCount = 0; - m_uiFeralRushTimer = 12000; + ++m_feralRushCount; + if (m_feralRushCount < m_maxFeralRush) + ResetCombatAction(action, 400ms); + else + { + m_feralRushCount = 0; + ResetCombatAction(action, 12s); + } } - else - m_uiFeralRushTimer = 400; + return; } } - else - m_uiFeralRushTimer -= uiDiff; + }; +}; - DoMeleeAttackIfReady(); +// 64386 - Terrifying Screech +struct TerrifyingScreech : public SpellScript +{ + void OnSuccessfulFinish(Spell* spell) const override + { + Unit* caster = spell->GetCaster(); + if (!caster || !caster->AI() || !caster->IsCreature()) + return; + caster->AI()->DoCastSpellIfCan(nullptr, caster->GetMap()->IsRegularDifficulty() ? SPELL_SENTINEL_BLAST : SPELL_SENTINEL_BLAST_H); } }; -UnitAI* GetAI_boss_feral_defender(Creature* pCreature) +// 64456 - Feral Essence Application Removal +struct FeralEssanceRemoval : public SpellScript { - return new boss_feral_defenderAI(pCreature); -} + void OnEffectExecute(Spell* spell, SpellEffectIndex /*effIdx*/) const override + { + Unit* unitTarget = spell->GetUnitTarget(); + if (!unitTarget) + return; + + uint32 spellId = spell->m_spellInfo->CalculateSimpleValue(EFFECT_INDEX_0); + unitTarget->RemoveAuraHolderFromStack(spellId); + } +}; void AddSC_boss_auriaya() { Script* pNewScript = new Script; pNewScript->Name = "boss_auriaya"; - pNewScript->GetAI = GetAI_boss_auriaya; + pNewScript->GetAI = &GetNewAIInstance; pNewScript->RegisterSelf(); pNewScript = new Script; pNewScript->Name = "boss_feral_defender"; - pNewScript->GetAI = &GetAI_boss_feral_defender; + pNewScript->GetAI = &GetNewAIInstance; pNewScript->RegisterSelf(); + + RegisterSpellScript("spell_terrifying_screech"); + RegisterSpellScript("spell_feral_essence_removal"); } diff --git a/src/game/Spells/SpellEffects.cpp b/src/game/Spells/SpellEffects.cpp index d1dc7e239ec..5e47043f552 100644 --- a/src/game/Spells/SpellEffects.cpp +++ b/src/game/Spells/SpellEffects.cpp @@ -10207,15 +10207,6 @@ void Spell::EffectScriptEffect(SpellEffectIndex eff_idx) unitTarget->CastSpell(m_caster, m_spellInfo->CalculateSimpleValue(eff_idx), TRIGGERED_OLD_TRIGGERED); return; } - case 64456: // Feral Essence Application Removal - { - if (!unitTarget) - return; - - uint32 spellId = m_spellInfo->CalculateSimpleValue(eff_idx); - unitTarget->RemoveAuraHolderFromStack(spellId); - return; - } case 64466: // Empowering Shadows { if (!unitTarget)