Scripts/AQ20: Rewrite Moam (#31216)

* New register model
* Repeat events instead of scheduling them
* Added unique names for enums
* Added comments for script names
* Added AI for Mana Fiend
* Added missing emote
* Use all emotes
* Create master-script to summon Mana Fiends
* Implement & use Zero Mana/Full Health spell
* Implement Energize script to end stoned phase
* Implement Drain Mana master spell script with correct amount of targets and checks to ensure only players and mana-users will be targeted
* Implement Drain Mana visual effect
* Now, once all Mana Fiends are dead, stone phase is finished
* Rework the way stone phase is started and finished
* Moam now drops obsidian mineral once dead
* Added a check to ensure all combat spells will be used
* Added event to handle Arcane Eruption instead of trying to cast it every update tick

Credit for a lot of things goes to CMaNGOS
This commit is contained in:
offl
2025-09-14 01:19:03 +03:00
committed by GitHub
parent 5c6bf61066
commit de6a77c535
3 changed files with 287 additions and 148 deletions

View File

@@ -0,0 +1,26 @@
--
DELETE FROM `spell_script_names` WHERE `ScriptName` IN (
'spell_moam_summon_mana_fiends',
'spell_moam_energize',
'spell_moam_drain_mana',
'spell_moam_drain_mana_effect',
'spell_gen_zero_mana_full_health');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(25684, 'spell_moam_summon_mana_fiends'),
(25685, 'spell_moam_energize'),
(25676, 'spell_moam_drain_mana'),
(25671, 'spell_moam_drain_mana_effect'),
(25755, 'spell_moam_drain_mana_effect'),
(23777, 'spell_gen_zero_mana_full_health');
DELETE FROM `creature_text` WHERE `CreatureID` = 15340 AND `GroupID` = 2;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(15340,2,0,"%s drains your mana and turns to stone.",16,0,100,0,0,0,11474,0,"moam EMOTE_ENERGIZE");
UPDATE `creature_template` SET `AIName` = 'SmartAI', `flags_extra` = `flags_extra`&~2 WHERE `entry` = 15527;
DELETE FROM `smart_scripts` WHERE `entryorguid` = 15527 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
(15527,0,0,0,37,0,100,0,0,0,0,0,0,116,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Mana Fiend - On AI Initialize - Set Corpse Delay"),
(15527,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,"Mana Fiend - On Spawn - Set In Combat With Zone"),
(15527,0,2,0,0,0,100,0,5000,7000,5000,7000,0,11,25679,0,0,0,0,0,1,0,0,0,0,0,0,0,0,"Mana Fiend - In Combat - Cast 'Arcane Explosion'"),
(15527,0,3,0,13,0,100,0,10000,20000,0,0,0,11,15122,0,0,0,0,0,2,0,0,0,0,0,0,0,0,"Mana Fiend - Target Casting - Cast 'Counterspell'");

View File

@@ -17,177 +17,272 @@
#include "ScriptMgr.h"
#include "Containers.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "ruins_of_ahnqiraj.h"
enum Texts
enum MoamTexts
{
EMOTE_AGGRO = 0,
EMOTE_MANA_FULL = 1
EMOTE_AGGRO = 0,
EMOTE_MANA_FULL = 1,
EMOTE_ENERGIZE = 2
};
enum Spells
enum MoamSpells
{
// Combat
SPELL_TRAMPLE = 15550,
SPELL_DRAIN_MANA = 25671,
SPELL_DRAIN_MANA = 25676,
SPELL_ARCANE_ERUPTION = 25672,
SPELL_SUMMON_MANA_FIEND_1 = 25681, // TARGET_DEST_CASTER_FRONT
SPELL_SUMMON_MANA_FIEND_2 = 25682, // TARGET_DEST_CASTER_LEFT
SPELL_SUMMON_MANA_FIEND_3 = 25683, // TARGET_DEST_CASTER_RIGHT
SPELL_ENERGIZE = 25685
SPELL_SUMMON_MANA_FIENDS = 25684,
SPELL_ENERGIZE = 25685,
// Misc
SPELL_ZERO_MANA_FULL_HEALTH = 23777,
SPELL_DROP_OBSIDIAN = 27630,
// Scripts
SPELL_SUMMON_MANA_FIEND_1 = 25681,
SPELL_SUMMON_MANA_FIEND_2 = 25682,
SPELL_SUMMON_MANA_FIEND_3 = 25683,
SPELL_DRAIN_MANA_EFFECT = 25671,
SPELL_DRAIN_MANA_VISUAL = 26639
};
enum Events
enum MoamEvents
{
EVENT_TRAMPLE = 1,
EVENT_DRAIN_MANA = 2,
EVENT_STONE_PHASE = 3,
EVENT_STONE_PHASE_END = 4,
EVENT_WIDE_SLASH = 5,
EVENT_TRAMPLE = 1,
EVENT_DRAIN_MANA,
EVENT_STONE_PHASE,
EVENT_ARCANE_ERUPTION
};
enum Actions
enum MoamMisc
{
ACTION_STONE_PHASE_START = 1,
ACTION_STONE_PHASE_END = 2,
MAX_MANA_FIENDS = 3
};
class boss_moam : public CreatureScript
// 15340 - Moam
struct boss_moam : public BossAI
{
public:
boss_moam() : CreatureScript("boss_moam") { }
boss_moam(Creature* creature) : BossAI(creature, DATA_MOAM), _deadManaFiendCount(0) { }
struct boss_moamAI : public BossAI
void JustAppeared() override
{
DoCastSelf(SPELL_ZERO_MANA_FULL_HEALTH);
}
void Reset() override
{
_Reset();
_deadManaFiendCount = 0;
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(EMOTE_AGGRO);
events.ScheduleEvent(EVENT_TRAMPLE, 10s, 25s);
events.ScheduleEvent(EVENT_DRAIN_MANA, 6s);
events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
events.ScheduleEvent(EVENT_ARCANE_ERUPTION, 1s);
}
void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) override
{
_deadManaFiendCount++;
if (_deadManaFiendCount == MAX_MANA_FIENDS)
{
boss_moamAI(Creature* creature) : BossAI(creature, DATA_MOAM)
{
Initialize();
}
void Initialize()
{
_isStonePhase = false;
}
void Reset() override
{
_Reset();
me->SetPower(POWER_MANA, 0);
Initialize();
events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
//events.ScheduleEvent(EVENT_WIDE_SLASH, 11s);
}
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
{
if (!_isStonePhase && HealthBelowPct(45))
{
_isStonePhase = true;
DoAction(ACTION_STONE_PHASE_START);
}
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_STONE_PHASE_END:
{
me->RemoveAurasDueToSpell(SPELL_ENERGIZE);
events.ScheduleEvent(EVENT_STONE_PHASE, 90s);
_isStonePhase = false;
break;
}
case ACTION_STONE_PHASE_START:
{
DoCast(me, SPELL_SUMMON_MANA_FIEND_1);
DoCast(me, SPELL_SUMMON_MANA_FIEND_2);
DoCast(me, SPELL_SUMMON_MANA_FIEND_3);
DoCast(me, SPELL_ENERGIZE);
events.ScheduleEvent(EVENT_STONE_PHASE_END, 90s);
break;
}
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA))
{
if (_isStonePhase)
DoAction(ACTION_STONE_PHASE_END);
DoCastAOE(SPELL_ARCANE_ERUPTION);
me->SetPower(POWER_MANA, 0);
}
if (_isStonePhase)
{
if (events.ExecuteEvent() == EVENT_STONE_PHASE_END)
DoAction(ACTION_STONE_PHASE_END);
return;
}
// Messing up mana-drain channel
//if (me->HasUnitState(UNIT_STATE_CASTING))
// return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_STONE_PHASE:
DoAction(ACTION_STONE_PHASE_START);
break;
case EVENT_DRAIN_MANA:
{
std::list<Unit*> targetList;
{
for (ThreatReference const* ref : me->GetThreatManager().GetUnsortedThreatList())
if (ref->GetVictim()->GetTypeId() == TYPEID_PLAYER && ref->GetVictim()->GetPowerType() == POWER_MANA)
targetList.push_back(ref->GetVictim());
}
Trinity::Containers::RandomResize(targetList, 5);
for (std::list<Unit*>::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
DoCast(*itr, SPELL_DRAIN_MANA);
events.ScheduleEvent(EVENT_DRAIN_MANA, 5s, 15s);
break;
}/*
case EVENT_WIDE_SLASH:
DoCast(me, SPELL_WIDE_SLASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 11s);
break;
case EVENT_TRASH:
DoCast(me, SPELL_TRASH);
events.ScheduleEvent(EVENT_WIDE_SLASH, 15s);
break;*/
default:
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool _isStonePhase;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetAQ20AI<boss_moamAI>(creature);
me->RemoveAurasDueToSpell(SPELL_ENERGIZE);
_deadManaFiendCount = 0;
}
}
void OnSpellCast(SpellInfo const* spell) override
{
switch (spell->Id)
{
case SPELL_ARCANE_ERUPTION:
// Is there a spell for that? Maybe Zero Mana/Full Health but with a check to prevent setting full health if creature is in combat?
me->SetPower(POWER_MANA, 0);
Talk(EMOTE_MANA_FULL);
break;
case SPELL_SUMMON_MANA_FIENDS:
DoCastSelf(SPELL_ENERGIZE);
Talk(EMOTE_ENERGIZE);
break;
default:
break;
}
}
void JustReachedHome() override
{
_JustReachedHome();
DoCastSelf(SPELL_ZERO_MANA_FULL_HEALTH);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
DoCastSelf(SPELL_DROP_OBSIDIAN, true);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_TRAMPLE:
DoCastSelf(SPELL_TRAMPLE);
events.Repeat(10s, 15s);
break;
case EVENT_DRAIN_MANA:
DoCastSelf(SPELL_DRAIN_MANA);
events.Repeat(6s);
break;
case EVENT_STONE_PHASE:
_deadManaFiendCount = 0;
DoCastSelf(SPELL_SUMMON_MANA_FIENDS);
events.Repeat(130s);
break;
case EVENT_ARCANE_ERUPTION:
if (me->GetPower(POWER_MANA) == me->GetMaxPower(POWER_MANA))
DoCastSelf(SPELL_ARCANE_ERUPTION);
events.Repeat(1s);
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
}
private:
uint8 _deadManaFiendCount;
};
// 25684 - Summon Mana Fiends
class spell_moam_summon_mana_fiends : public SpellScript
{
PrepareSpellScript(spell_moam_summon_mana_fiends);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_SUMMON_MANA_FIEND_1,
SPELL_SUMMON_MANA_FIEND_2,
SPELL_SUMMON_MANA_FIEND_3
});
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
caster->CastSpell(caster, SPELL_SUMMON_MANA_FIEND_1, true);
caster->CastSpell(caster, SPELL_SUMMON_MANA_FIEND_2, true);
caster->CastSpell(caster, SPELL_SUMMON_MANA_FIEND_3, true);
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_moam_summon_mana_fiends::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 25685 - Energize
class spell_moam_energize : public AuraScript
{
PrepareAuraScript(spell_moam_energize);
void OnPeriodic(AuraEffect const* /*aurEff*/)
{
if (GetTarget()->GetPower(POWER_MANA) == GetTarget()->GetMaxPower(POWER_MANA))
Remove();
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_moam_energize::OnPeriodic, EFFECT_1, SPELL_AURA_PERIODIC_ENERGIZE);
}
};
// 25676 - Drain Mana
class spell_moam_drain_mana : public SpellScript
{
PrepareSpellScript(spell_moam_drain_mana);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRAIN_MANA_EFFECT });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
Trinity::Containers::RandomResize(targets, [](WorldObject* target)
{
return target->IsPlayer() && target->ToPlayer()->GetPowerType() == POWER_MANA;
}, 6);
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetHitUnit(), SPELL_DRAIN_MANA_EFFECT, true);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_moam_drain_mana::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_moam_drain_mana::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 25671 - Drain Mana
// 25755 - Drain Mana
class spell_moam_drain_mana_effect : public SpellScript
{
PrepareSpellScript(spell_moam_drain_mana_effect);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DRAIN_MANA_VISUAL });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetCaster(), SPELL_DRAIN_MANA_VISUAL, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_moam_drain_mana_effect::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_moam()
{
new boss_moam();
RegisterAQ20CreatureAI(boss_moam);
RegisterSpellScript(spell_moam_summon_mana_fiends);
RegisterSpellScript(spell_moam_energize);
RegisterSpellScript(spell_moam_drain_mana);
RegisterSpellScript(spell_moam_drain_mana_effect);
}

View File

@@ -3922,6 +3922,23 @@ private:
uint32 _text;
};
// 23777 - Zero Mana/Full Health DND
class spell_gen_zero_mana_full_health : public SpellScript
{
PrepareSpellScript(spell_gen_zero_mana_full_health);
void HandleDummy(SpellEffIndex /*effIndex*/)
{
GetCaster()->SetFullHealth();
GetCaster()->SetPower(POWER_MANA, 0);
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_gen_zero_mana_full_health::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_gen_eject_all_passengers : public SpellScript
{
PrepareSpellScript(spell_gen_eject_all_passengers);
@@ -4828,6 +4845,7 @@ void AddSC_generic_spell_scripts()
RegisterSpellScriptWithArgs(spell_gen_whisper_to_controller_random, "spell_future_you_whisper_to_controller_random", WHISPER_FUTURE_YOU);
RegisterSpellScriptWithArgs(spell_gen_whisper_to_controller_random, "spell_wyrmrest_defender_whisper_to_controller_random", WHISPER_DEFENDER);
RegisterSpellScriptWithArgs(spell_gen_whisper_to_controller_random, "spell_past_you_whisper_to_controller_random", WHISPER_PAST_YOU);
RegisterSpellScript(spell_gen_zero_mana_full_health);
RegisterSpellScript(spell_gen_eject_all_passengers);
RegisterSpellScript(spell_gen_eject_passenger);
RegisterSpellScriptWithArgs(spell_gen_eject_passenger_with_seatId, "spell_gen_eject_passenger_1", 0);