fix(Scripts/MoltenCore): rewrite (#8741)

This commit is contained in:
Andrius Peleckas
2021-11-02 11:59:01 +00:00
committed by GitHub
parent 2f25323456
commit 2da923e761
15 changed files with 2441 additions and 1127 deletions

View File

@@ -15,36 +15,31 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Baron_Geddon
SD%Complete: 100
SDComment:
SDCategory: Molten Core
EndScriptData */
#include "molten_core.h"
#include "ObjectMgr.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
enum Emotes
{
EMOTE_SERVICE = 0
EMOTE_SERVICE = 0
};
enum Spells
{
SPELL_INFERNO = 19695,
SPELL_IGNITE_MANA = 19659,
SPELL_LIVING_BOMB = 20475,
SPELL_ARMAGEDDON = 20479,
SPELL_INFERNO = 19695,
SPELL_INFERNO_DUMMY_EFFECT = 19698, // Server side spell which inflicts damage
SPELL_IGNITE_MANA = 19659,
SPELL_LIVING_BOMB = 20475,
SPELL_ARMAGEDDON = 20478,
};
enum Events
{
EVENT_INFERNO = 1,
EVENT_IGNITE_MANA = 2,
EVENT_LIVING_BOMB = 3,
EVENT_INFERNO = 1,
EVENT_IGNITE_MANA,
EVENT_LIVING_BOMB,
};
class boss_baron_geddon : public CreatureScript
@@ -54,62 +49,75 @@ public:
struct boss_baron_geddonAI : public BossAI
{
boss_baron_geddonAI(Creature* creature) : BossAI(creature, BOSS_BARON_GEDDON)
boss_baron_geddonAI(Creature* creature) : BossAI(creature, DATA_GEDDON),
armageddonCasted(false)
{
}
void EnterCombat(Unit* victim) override
void Reset() override
{
BossAI::EnterCombat(victim);
events.ScheduleEvent(EVENT_INFERNO, 45000);
events.ScheduleEvent(EVENT_IGNITE_MANA, 30000);
events.ScheduleEvent(EVENT_LIVING_BOMB, 35000);
_Reset();
armageddonCasted = false;
}
void UpdateAI(uint32 diff) override
void EnterCombat(Unit* /*attacker*/) override
{
if (!UpdateVictim())
return;
_EnterCombat();
events.ScheduleEvent(EVENT_INFERNO, urand(13000, 15000));
events.ScheduleEvent(EVENT_IGNITE_MANA, urand(7000, 19000));
events.ScheduleEvent(EVENT_LIVING_BOMB, urand(11000, 16000));
}
events.Update(diff);
// If we are <2% hp cast Armageddon
if (!HealthAbovePct(2))
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
// If boss is below 2% hp - cast Armageddon
if (!armageddonCasted && damage < me->GetHealth() && me->HealthBelowPctDamaged(2, damage))
{
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_ARMAGEDDON);
Talk(EMOTE_SERVICE);
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
if (me->CastSpell(me, SPELL_ARMAGEDDON) == SPELL_CAST_OK)
{
case EVENT_INFERNO:
DoCast(me, SPELL_INFERNO);
events.ScheduleEvent(EVENT_INFERNO, 45000);
break;
case EVENT_IGNITE_MANA:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_IGNITE_MANA))
DoCast(target, SPELL_IGNITE_MANA);
events.ScheduleEvent(EVENT_IGNITE_MANA, 30000);
break;
case EVENT_LIVING_BOMB:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_LIVING_BOMB);
events.ScheduleEvent(EVENT_LIVING_BOMB, 35000);
break;
default:
break;
Talk(EMOTE_SERVICE);
}
armageddonCasted = true;
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_INFERNO:
{
DoCastSelf(SPELL_INFERNO);
events.RepeatEvent(urand(21000, 26000));
break;
}
case EVENT_IGNITE_MANA:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_IGNITE_MANA))
{
DoCast(target, SPELL_IGNITE_MANA);
}
events.RepeatEvent(urand(27000, 32000));
break;
}
case EVENT_LIVING_BOMB:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
DoCast(target, SPELL_LIVING_BOMB);
}
events.RepeatEvent(urand(11000, 16000));
break;
}
}
DoMeleeAttackIfReady();
}
private:
bool armageddonCasted;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -118,7 +126,68 @@ public:
}
};
// 19695 Inferno
class spell_geddon_inferno : public SpellScriptLoader
{
public:
spell_geddon_inferno() : SpellScriptLoader("spell_geddon_inferno") { }
class spell_geddon_inferno_AuraScript : public AuraScript
{
PrepareAuraScript(spell_geddon_inferno_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_INFERNO_DUMMY_EFFECT });
}
void PeriodicTick(AuraEffect const* aurEff)
{
PreventDefaultAction();
if (Unit* caster = GetUnitOwner())
{
//The pulses come about 1 second apart and last for 10 seconds. Damage starts at 500 damage per pulse and increases by 500 every other pulse (500, 500, 1000, 1000, 1500, etc.). (Source: Wowwiki)
int32 multiplier = 1;
switch (aurEff->GetTickNumber())
{
case 2:
case 3:
multiplier = 2;
break;
case 4:
case 5:
multiplier = 3;
break;
case 6:
case 7:
multiplier = 4;
break;
case 8:
multiplier = 5;
break;
}
caster->CastCustomSpell(SPELL_INFERNO_DUMMY_EFFECT, SPELLVALUE_BASE_POINT0, 500 * multiplier, caster, TRIGGERED_NONE, nullptr, aurEff);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_geddon_inferno_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_geddon_inferno_AuraScript();
}
};
void AddSC_boss_baron_geddon()
{
new boss_baron_geddon();
// Spells
new spell_geddon_inferno();
}

View File

@@ -15,83 +15,124 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Garr
SD%Complete: 50
SDComment: Adds NYI
SDCategory: Molten Core
EndScriptData */
#include "molten_core.h"
#include "ObjectMgr.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "Containers.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "molten_core.h"
enum Texts
{
EMOTE_MASS_ERRUPTION = 0,
};
enum Spells
{
// Garr
SPELL_ANTIMAGIC_PULSE = 19492,
SPELL_MAGMA_SHACKLES = 19496,
SPELL_ENRAGE = 19516,
SPELL_ANTIMAGIC_PULSE = 19492, // Dispels magic on nearby enemies, removing 1 beneficial spell
SPELL_MAGMA_SHACKLES = 19496, // Reduces the movement speed of nearby enemies by 60%
SPELL_SEPARATION_ANXIETY = 23487, // Aura cast on himself by Garr, if adds move out of range, they will cast spell 23492 on themselves (server side)
SPELL_FRENZY = 19516, // Increases the caster's attack speed by 9 + scale. Stacks up to 10 times
// Adds
SPELL_ERUPTION = 19497,
SPELL_IMMOLATE = 20294,
// Fireworn
SPELL_SEPARATION_ANXIETY_MINION = 23492, // Increases damage done by 300% and applied banish immunity
SPELL_ERUPTION = 19497, // Deals fire aoe damage and knockbacks nearby enemies
SPELL_MASSIVE_ERUPTION = 20483, // Deals fire aoe damage, knockbacks nearby enemies and kills caster
SPELL_ERUPTION_TRIGGER = 20482, // Removes banish auras and applied immunity to banish (server side)
SPELL_ENRAGE_TRIGGER = 19515, // Server side. Triggers 19516 on hit
};
enum Events
{
EVENT_ANTIMAGIC_PULSE = 1,
EVENT_MAGMA_SHACKLES = 2,
EVENT_ANTIMAGIC_PULSE = 1,
EVENT_MAGMA_SHACKLES,
};
class boss_garr : public CreatureScript
{
public:
boss_garr() : CreatureScript("boss_garr") { }
boss_garr() : CreatureScript("boss_garr") {}
struct boss_garrAI : public BossAI
{
boss_garrAI(Creature* creature) : BossAI(creature, BOSS_GARR)
boss_garrAI(Creature* creature) : BossAI(creature, DATA_GARR),
massEruptionTimer(600000) // 10 mins
{
}
void EnterCombat(Unit* victim) override
void Reset() override
{
BossAI::EnterCombat(victim);
_Reset();
massEruptionTimer = 600000;
}
void EnterCombat(Unit* /*attacker*/) override
{
_EnterCombat();
DoCastSelf(SPELL_SEPARATION_ANXIETY, true);
events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 15000);
events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 10000);
massEruptionTimer = 600000; // 10 mins
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
// This should always process
if (massEruptionTimer <= diff)
{
Talk(EMOTE_MASS_ERRUPTION, me);
DoCastAOE(SPELL_ERUPTION_TRIGGER, true);
massEruptionTimer = 20000;
}
else
{
massEruptionTimer -= diff;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ANTIMAGIC_PULSE:
DoCast(me, SPELL_ANTIMAGIC_PULSE);
events.ScheduleEvent(EVENT_ANTIMAGIC_PULSE, 20000);
{
DoCastSelf(SPELL_ANTIMAGIC_PULSE);
events.RepeatEvent(20000);
break;
}
case EVENT_MAGMA_SHACKLES:
DoCast(me, SPELL_MAGMA_SHACKLES);
events.ScheduleEvent(EVENT_MAGMA_SHACKLES, 15000);
break;
default:
{
DoCastSelf(SPELL_MAGMA_SHACKLES);
events.RepeatEvent(15000);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
}
private:
uint32 massEruptionTimer;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -100,60 +141,115 @@ public:
}
};
class npc_firesworn : public CreatureScript
class npc_garr_firesworn : public CreatureScript
{
public:
npc_firesworn() : CreatureScript("npc_firesworn") { }
npc_garr_firesworn() : CreatureScript("npc_garr_firesworn") {}
struct npc_fireswornAI : public ScriptedAI
struct npc_garr_fireswornAI : public ScriptedAI
{
npc_fireswornAI(Creature* creature) : ScriptedAI(creature) { }
npc_garr_fireswornAI(Creature* creature) : ScriptedAI(creature) {}
uint32 immolateTimer;
void Reset() override
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/ ) override
{
immolateTimer = 4000; //These times are probably wrong
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
uint32 const health10pct = me->CountPctFromMaxHealth(10);
uint32 health = me->GetHealth();
if (int32(health) - int32(damage) < int32(health10pct))
if (damage >= me->GetHealth())
{
damage = 0;
DoCastVictim(SPELL_ERUPTION);
me->DespawnOrUnsummon();
// Prevent double damage because Firesworn can kill himself with Massive Erruption
if (me != attacker)
{
DoCastSelf(SPELL_ERUPTION, true);
}
DoCastAOE(SPELL_ENRAGE_TRIGGER);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (immolateTimer <= diff)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_IMMOLATE);
immolateTimer = urand(5000, 10000);
}
else
immolateTimer -= diff;
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_fireswornAI>(creature);
return GetMoltenCoreAI<npc_garr_fireswornAI>(creature);
}
};
// 23487 Separation Anxiety (server side)
class spell_garr_separation_nexiety : public SpellScriptLoader
{
public:
spell_garr_separation_nexiety() : SpellScriptLoader("spell_garr_separation_nexiety") {}
class spell_garr_separation_nexiety_AuraScript : public AuraScript
{
PrepareAuraScript(spell_garr_separation_nexiety_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_SEPARATION_ANXIETY_MINION });
}
void HandlePeriodic(AuraEffect const* aurEff)
{
Unit const* caster = GetCaster();
Unit* target = GetTarget();
if (caster && target && target->GetDistance(caster) > 40.0f && !target->HasAura(SPELL_SEPARATION_ANXIETY_MINION))
{
target->CastSpell(target, SPELL_SEPARATION_ANXIETY_MINION, true, nullptr, aurEff);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_garr_separation_nexiety_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// Should return a fully valid AuraScript pointer.
AuraScript* GetAuraScript() const override
{
return new spell_garr_separation_nexiety_AuraScript();
}
};
//19515 Frenzy (SERVERSIDE)
class spell_garr_frenzy : public SpellScriptLoader
{
public:
spell_garr_frenzy() : SpellScriptLoader("spell_garr_frenzy") {}
class spell_garr_frenzy_SpellScript : public SpellScript
{
PrepareSpellScript(spell_garr_frenzy_SpellScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_FRENZY });
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
target->CastSpell(target, SPELL_FRENZY);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_garr_frenzy_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_garr_frenzy_SpellScript();
}
};
void AddSC_boss_garr()
{
new boss_garr();
new npc_firesworn();
new npc_garr_firesworn();
// Spells
new spell_garr_separation_nexiety();
new spell_garr_frenzy();
}

View File

@@ -15,13 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Gehennas
SD%Complete: 90
SDComment: Adds MC NYI
SDCategory: Molten Core
EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
@@ -48,9 +41,7 @@ public:
struct boss_gehennasAI : public BossAI
{
boss_gehennasAI(Creature* creature) : BossAI(creature, BOSS_GEHENNAS)
{
}
boss_gehennasAI(Creature* creature) : BossAI(creature, DATA_GEHENNAS) {}
void EnterCombat(Unit* /*attacker*/) override
{
@@ -60,69 +51,47 @@ public:
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 5000));
}
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
{
if (!UpdateVictim())
switch (eventId)
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
case EVENT_GEHENNAS_CURSE:
{
case EVENT_GEHENNAS_CURSE:
DoCastVictim(SPELL_GEHENNAS_CURSE);
events.RepeatEvent(urand(25000, 30000));
break;
}
case EVENT_RAIN_OF_FIRE:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
DoCastVictim(SPELL_GEHENNAS_CURSE);
events.RepeatEvent(urand(25000, 30000));
break;
DoCast(target, SPELL_RAIN_OF_FIRE, true);
}
case EVENT_RAIN_OF_FIRE:
events.RepeatEvent(6000);
break;
}
case EVENT_SHADOW_BOLT:
{
if (urand(0, 1))
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
{
DoCast(target, SPELL_RAIN_OF_FIRE);
}
events.RepeatEvent(6000);
break;
}
case EVENT_SHADOW_BOLT:
{
if (urand(0, 1))
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
{
DoCast(target, SPELL_SHADOW_BOLT_RANDOM);
}
else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
DoCast(target, SPELL_SHADOW_BOLT_RANDOM);
}
else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
events.RepeatEvent(5000);
break;
}
}
else
{
DoCastVictim(SPELL_SHADOW_BOLT_VICTIM);
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
events.RepeatEvent(5000);
break;
}
}
DoMeleeAttackIfReady();
}
};

View File

@@ -15,40 +15,28 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Golemagg
SD%Complete: 90
SDComment: Timers need to be confirmed, Golemagg's Trust need to be checked
SDCategory: Molten Core
EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
#include "ObjectMgr.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ObjectAccessor.h"
enum Texts
{
EMOTE_LOWHP = 0,
EMOTE_LOWHP = 0,
};
enum Spells
{
// Golemagg
SPELL_MAGMASPLASH = 13879,
SPELL_PYROBLAST = 20228,
SPELL_EARTHQUAKE = 19798,
SPELL_ENRAGE = 19953,
SPELL_GOLEMAGG_TRUST = 20553,
SPELL_PYROBLAST = 20228,
SPELL_EARTHQUAKE = 19798,
SPELL_ENRAGE = 19953,
SPELL_ATTRACK_RAGER = 20544,
// Core Rager
SPELL_MANGLE = 19820
};
enum Events
{
EVENT_PYROBLAST = 1,
EVENT_EARTHQUAKE = 2,
SPELL_MANGLE = 19820,
SPELL_FULL_HEAL = 17683,
};
class boss_golemagg : public CreatureScript
@@ -58,72 +46,79 @@ public:
struct boss_golemaggAI : public BossAI
{
boss_golemaggAI(Creature* creature) : BossAI(creature, BOSS_GOLEMAGG_THE_INCINERATOR)
{
}
boss_golemaggAI(Creature* creature) : BossAI(creature, DATA_GOLEMAGG),
earthquakeTimer(0),
pyroblastTimer(0),
enraged(false)
{}
void Reset() override
{
BossAI::Reset();
DoCast(me, SPELL_MAGMASPLASH, true);
_Reset();
earthquakeTimer = 0;
pyroblastTimer = urand(3000, 7000);
enraged = false;
}
void EnterCombat(Unit* victim) override
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
BossAI::EnterCombat(victim);
events.ScheduleEvent(EVENT_PYROBLAST, 7000);
// The two ragers should join the fight alongside me against my foes.
std::list<Creature*> ragers;
me->GetCreaturesWithEntryInRange(ragers, 100, NPC_CORE_RAGER);
for (Creature* i : ragers)
if (!enraged && me->HealthBelowPctDamaged(10, damage))
{
if (i && i->IsAlive() && !i->IsInCombat())
{
i->AI()->AttackStart(victim);
}
DoCastSelf(SPELL_ENRAGE, true);
DoCastSelf(SPELL_ATTRACK_RAGER, true);
DoCastAOE(SPELL_EARTHQUAKE, true);
earthquakeTimer = 5000;
enraged = true;
}
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (!HealthBelowPct(10) || me->HasAura(SPELL_ENRAGE))
return;
DoCast(me, SPELL_ENRAGE, true);
events.ScheduleEvent(EVENT_EARTHQUAKE, 3000);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
// Should not get impact by cast state (cast should always happen)
if (earthquakeTimer)
{
if (earthquakeTimer <= diff)
{
DoCastAOE(SPELL_EARTHQUAKE, true);
earthquakeTimer = 5000;
}
else
{
earthquakeTimer -= diff;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
return;
}
if (pyroblastTimer <= diff)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
case EVENT_PYROBLAST:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
DoCast(target, SPELL_PYROBLAST);
events.ScheduleEvent(EVENT_PYROBLAST, 7000);
break;
case EVENT_EARTHQUAKE:
DoCastVictim(SPELL_EARTHQUAKE);
events.ScheduleEvent(EVENT_EARTHQUAKE, 3000);
break;
default:
break;
DoCast(target, SPELL_PYROBLAST);
}
pyroblastTimer = 7000;
}
else
{
pyroblastTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
uint32 earthquakeTimer;
uint32 pyroblastTimer;
bool enraged;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -139,45 +134,79 @@ public:
struct npc_core_ragerAI : public ScriptedAI
{
npc_core_ragerAI(Creature* creature) : ScriptedAI(creature)
npc_core_ragerAI(Creature* creature) : ScriptedAI(creature),
instance(creature->GetInstanceScript()),
mangleTimer(7000),
rangeCheckTimer(1000)
{
instance = creature->GetInstanceScript();
}
void Reset() override
{
mangleTimer = 7 * IN_MILLISECONDS; // These times are probably wrong
mangleTimer = 7000; // These times are probably wrong
rangeCheckTimer = 1000;
if (instance->GetBossState(DATA_GOLEMAGG) == DONE)
{
DoCastSelf(SPELL_CORE_RAGER_QUIET_SUICIDE, true);
}
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
if (HealthAbovePct(50) || !instance)
return;
if (Creature* pGolemagg = instance->instance->GetCreature(instance->GetGuidData(BOSS_GOLEMAGG_THE_INCINERATOR)))
// Just in case if something will go bad, let players to kill this creature
if (instance->GetBossState(DATA_GOLEMAGG) == DONE)
{
if (pGolemagg->IsAlive())
{
me->AddAura(SPELL_GOLEMAGG_TRUST, me);
Talk(EMOTE_LOWHP);
me->SetFullHealth();
}
return;
}
if (me->HealthBelowPctDamaged(50, damage))
{
damage = 0;
DoCastSelf(SPELL_FULL_HEAL, true);
Talk(EMOTE_LOWHP);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
// Should have no impact from unit state
if (rangeCheckTimer <= diff)
{
Creature const* golemagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_GEDDON));
if (golemagg && me->GetDistance(golemagg) > 100.0f)
{
instance->DoAction(ACTION_RESET_MAGMADAR_ENCOUNTER);
return;
}
rangeCheckTimer = 1000;
}
else
{
rangeCheckTimer -= diff;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
// Mangle
if (mangleTimer <= diff)
{
DoCastVictim(SPELL_MANGLE);
mangleTimer = 10 * IN_MILLISECONDS;
mangleTimer = 10000;
}
else
{
mangleTimer -= diff;
}
DoMeleeAttackIfReady();
}
@@ -185,6 +214,7 @@ public:
private:
InstanceScript* instance;
uint32 mangleTimer;
uint32 rangeCheckTimer;
};
CreatureAI* GetAI(Creature* creature) const override

View File

@@ -15,13 +15,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Lucifron
SD%Complete: 100
SDComment:
SDCategory: Molten Core
EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
@@ -47,9 +40,7 @@ public:
struct boss_lucifronAI : public BossAI
{
boss_lucifronAI(Creature* creature) : BossAI(creature, BOSS_LUCIFRON)
{
}
boss_lucifronAI(Creature* creature) : BossAI(creature, DATA_LUCIFRON) {}
void EnterCombat(Unit* /*victim*/) override
{
@@ -59,46 +50,29 @@ public:
events.ScheduleEvent(EVENT_SHADOW_SHOCK, 5000);
}
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
{
if (!UpdateVictim())
switch (eventId)
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
case EVENT_IMPENDING_DOOM:
{
case EVENT_IMPENDING_DOOM:
{
DoCastVictim(SPELL_IMPENDING_DOOM);
events.RepeatEvent(20000);
break;
}
case EVENT_LUCIFRON_CURSE:
{
DoCastVictim(SPELL_LUCIFRON_CURSE);
events.RepeatEvent(20000);
break;
}
case EVENT_SHADOW_SHOCK:
{
DoCastVictim(SPELL_SHADOW_SHOCK);
events.RepeatEvent(5000);
break;
}
DoCastVictim(SPELL_IMPENDING_DOOM);
events.RepeatEvent(20000);
break;
}
case EVENT_LUCIFRON_CURSE:
{
DoCastVictim(SPELL_LUCIFRON_CURSE);
events.RepeatEvent(20000);
break;
}
case EVENT_SHADOW_SHOCK:
{
DoCastVictim(SPELL_SHADOW_SHOCK);
events.RepeatEvent(5000);
break;
}
}
DoMeleeAttackIfReady();
}
};

View File

@@ -15,102 +15,98 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Magmadar
SD%Complete: 75
SDComment: Conflag on ground nyi
SDCategory: Molten Core
EndScriptData */
#include "molten_core.h"
#include "ObjectMgr.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
enum Texts
{
EMOTE_FRENZY = 0,
EMOTE_SMOLDERING = 0,
EMOTE_IGNITE = 1,
EMOTE_FRENZY = 0,
};
enum Spells
{
SPELL_FRENZY = 19451,
SPELL_MAGMA_SPIT = 19449,
SPELL_PANIC = 19408,
SPELL_LAVA_BOMB = 19428,
SPELL_SERRATED_BITE = 19771,
SPELL_FRENZY = 19451,
SPELL_MAGMA_SPIT = 19449,
SPELL_PANIC = 19408,
SPELL_LAVA_BOMB = 19411, // This calls a dummy server side effect that cast spell 20494 to spawn GO 177704 for 30s
SPELL_LAVA_BOMB_EFFECT = 20494, // Spawns trap GO 177704 which triggers 19428
SPELL_LAVA_BOMB_RANGED = 20474, // This calls a dummy server side effect that cast spell 20495 to spawn GO 177704 for 60s
SPELL_LAVA_BOMB_RANGED_EFFECT = 20495, // Spawns trap GO 177704 which triggers 19428
};
enum Events
{
EVENT_FRENZY = 1,
EVENT_PANIC = 2,
EVENT_LAVA_BOMB = 3,
EVENT_SERRATED_BITE = 1,
EVENT_IGNITE = 2,
EVENT_FRENZY = 1,
EVENT_PANIC,
EVENT_LAVA_BOMB,
EVENT_LAVA_BOMB_RANGED,
};
constexpr float MELEE_TARGET_LOOKUP_DIST = 10.0f;
class boss_magmadar : public CreatureScript
{
public:
boss_magmadar() : CreatureScript("boss_magmadar") { }
boss_magmadar() : CreatureScript("boss_magmadar") {}
struct boss_magmadarAI : public BossAI
{
boss_magmadarAI(Creature* creature) : BossAI(creature, BOSS_MAGMADAR)
{
}
boss_magmadarAI(Creature* creature) : BossAI(creature, DATA_MAGMADAR) {}
void Reset() override
void EnterCombat(Unit* /*victim*/) override
{
BossAI::Reset();
DoCast(me, SPELL_MAGMA_SPIT, true);
}
void EnterCombat(Unit* victim) override
{
BossAI::EnterCombat(victim);
events.ScheduleEvent(EVENT_FRENZY, 30000);
events.ScheduleEvent(EVENT_PANIC, 20000);
_EnterCombat();
events.ScheduleEvent(EVENT_FRENZY, 8500);
events.ScheduleEvent(EVENT_PANIC, 9500);
events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
events.ScheduleEvent(EVENT_LAVA_BOMB_RANGED, 15000);
}
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
switch (eventId)
{
switch (eventId)
case EVENT_FRENZY:
{
case EVENT_FRENZY:
Talk(EMOTE_FRENZY);
DoCast(me, SPELL_FRENZY);
events.ScheduleEvent(EVENT_FRENZY, 15000);
break;
case EVENT_PANIC:
DoCastVictim(SPELL_PANIC);
events.ScheduleEvent(EVENT_PANIC, 35000);
break;
case EVENT_LAVA_BOMB:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_LAVA_BOMB))
DoCast(target, SPELL_LAVA_BOMB);
events.ScheduleEvent(EVENT_LAVA_BOMB, 12000);
break;
default:
break;
Talk(EMOTE_FRENZY);
DoCastSelf(SPELL_FRENZY);
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_PANIC:
{
DoCastVictim(SPELL_PANIC);
events.RepeatEvent(urand(31000, 38000));
break;
}
case EVENT_LAVA_BOMB:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, MELEE_TARGET_LOOKUP_DIST, true))
{
DoCast(target, SPELL_LAVA_BOMB);
}
events.RepeatEvent(urand(12000, 15000));
break;
}
case EVENT_LAVA_BOMB_RANGED:
{
std::list<Unit*> targets;
SelectTargetList(targets, [this](Unit* target)
{
return target && target->IsPlayer() && target->GetDistance(me) > MELEE_TARGET_LOOKUP_DIST && target->GetDistance(me) < 100.0f;
}, 1, SELECT_TARGET_RANDOM);
if (!targets.empty())
{
DoCast(targets.front() , SPELL_LAVA_BOMB_RANGED);
}
events.RepeatEvent(urand(12000, 15000));
break;
}
}
DoMeleeAttackIfReady();
}
};
@@ -120,142 +116,64 @@ public:
}
};
// Serrated Bites timer may be wrong
class npc_magmadar_core_hound : public CreatureScript
// 19411 Lava Bomb
// 20474 Lava Bomb
class spell_magmadar_lava_bomb : public SpellScriptLoader
{
public:
npc_magmadar_core_hound() : CreatureScript("npc_magmadar_core_hound") { }
spell_magmadar_lava_bomb() : SpellScriptLoader("spell_magmadar_lava_bomb") {}
struct npc_magmadar_core_houndAI : public CreatureAI
class spell_magmadar_lava_bomb_SpellScript : public SpellScript
{
npc_magmadar_core_houndAI(Creature* creature) : CreatureAI(creature)
PrepareSpellScript(spell_magmadar_lava_bomb_SpellScript);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_LAVA_BOMB_EFFECT, SPELL_LAVA_BOMB_RANGED_EFFECT });
}
EventMap events;
std::list<Creature*> hounds;
bool smoldering = false;
Unit* killer;
void removeFeignDeath()
void HandleDummy(SpellEffIndex /*effIndex*/)
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT);
me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
me->RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT);
me->ClearUnitState(UNIT_STATE_DIED);
me->ClearUnitState(UNIT_STATE_CANNOT_AUTOATTACK);
me->DisableRotate(false);
}
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
if (me->HealthBelowPctDamaged(0, damage))
if (Unit* target = GetHitUnit())
{
if (!smoldering)
uint32 spellId = 0;
switch (m_scriptSpellId)
{
killer = attacker;
events.ScheduleEvent(EVENT_IGNITE, 10000);
me->SetHealth(1);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT);
me->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
me->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
me->AddUnitMovementFlag(MOVEMENTFLAG_ROOT);
me->AddUnitState(UNIT_STATE_DIED);
me->AddUnitState(UNIT_STATE_CANNOT_AUTOATTACK);
me->DisableRotate(true);
Talk(EMOTE_SMOLDERING);
}
damage = 0;
smoldering = true;
}
}
void Reset() override
{
removeFeignDeath();
}
void JustDied(Unit* /*killer*/) override
{
removeFeignDeath();
}
void EnterCombat(Unit* /*victim*/) override
{
events.ScheduleEvent(EVENT_SERRATED_BITE, 10000); // timer may be wrong
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && !smoldering)
return;
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_SERRATED_BITE:
if (UpdateVictim() && !smoldering)
{
DoCast(me->GetVictim(), SPELL_SERRATED_BITE);
events.ScheduleEvent(EVENT_SERRATED_BITE, 10000); // again, timer may be wrong
}
case SPELL_LAVA_BOMB:
{
spellId = SPELL_LAVA_BOMB_EFFECT;
break;
case EVENT_IGNITE:
smoldering = false;
me->GetCreaturesWithEntryInRange(hounds, 80, NPC_CORE_HOUND);
for (Creature* i : hounds)
{
if (i && i->IsAlive() && i->IsInCombat() && !i->HasUnitState(UNIT_STATE_DIED))
{
Talk(EMOTE_IGNITE);
me->SetFullHealth();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PREVENT_EMOTES_FROM_CHAT_TEXT);
me->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
me->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
me->RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT);
me->ClearUnitState(UNIT_STATE_DIED);
me->ClearUnitState(UNIT_STATE_CANNOT_AUTOATTACK);
me->DisableRotate(false);
me->AI()->AttackStart(i->GetVictim());
return;
}
}
if (me->HasUnitState(UNIT_STATE_DIED))
{
if (killer)
{
me->Kill(killer, me);
}
else
{
me->Kill(me, me);
}
}
}
case SPELL_LAVA_BOMB_RANGED:
{
spellId = SPELL_LAVA_BOMB_RANGED_EFFECT;
break;
}
default:
break;
{
return;
}
}
target->CastSpell(target, spellId, true, nullptr, nullptr, GetCaster()->GetGUID());
}
}
DoMeleeAttackIfReady();
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_magmadar_lava_bomb_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
CreatureAI* GetAI(Creature* creature) const override
SpellScript* GetSpellScript() const override
{
return GetMoltenCoreAI<npc_magmadar_core_houndAI>(creature);
return new spell_magmadar_lava_bomb_SpellScript();
}
};
void AddSC_boss_magmadar()
{
new boss_magmadar();
new npc_magmadar_core_hound();
// Spells
new spell_magmadar_lava_bomb();
}

View File

@@ -15,192 +15,561 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Majordomo_Executus
SD%Complete: 30
SDComment: Correct spawning and Event NYI
SDCategory: Molten Core
EndScriptData */
#include "molten_core.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
#include "Player.h"
#include "ScriptedGossip.h"
#include "ObjectAccessor.h"
#include "SpellScript.h"
enum Texts
{
SAY_AGGRO = 0,
SAY_SPAWN = 1,
SAY_SLAY = 2,
SAY_SPECIAL = 3,
SAY_DEFEAT = 4,
SAY_AGGRO = 0,
SAY_SPAWN = 1,
SAY_SLAY = 2,
SAY_DEFEAT = 3,
SAY_SUMMON_MAJ = 4,
SAY_ARRIVAL2_MAJ = 5,
SAY_LAST_ADD = 6,
SAY_SUMMON_MAJ = 5,
SAY_ARRIVAL2_MAJ = 6
SAY_DEFEAT_2 = 7,
SAY_DEFEAT_3 = 8,
// Ragnaros event
// Majordomo
SAY_RAG_SUM_1 = 9,
SAY_RAG_SUM_2 = 10,
// Ragnaros
SAY_ARRIVAL1_RAG = 1,
SAY_ARRIVAL3_RAG = 3,
};
enum Spells
{
SPELL_MAGIC_REFLECTION = 20619,
SPELL_DAMAGE_REFLECTION = 21075,
SPELL_BLAST_WAVE = 20229,
SPELL_AEGIS_OF_RAGNAROS = 20620,
SPELL_TELEPORT = 20618,
SPELL_SUMMON_RAGNAROS = 19774,
};
SPELL_MAGIC_REFLECTION = 20619,
SPELL_DAMAGE_REFLECTION = 21075,
SPELL_BLAST_WAVE = 20229,
SPELL_AEGIS_OF_RAGNAROS = 20620,
SPELL_TELEPORT_RANDOM = 20618, // Teleport random target
SPELL_TELEPORT_TARGET = 20534, // Teleport Victim
SPELL_ENCOURAGEMENT = 21086,
SPELL_CHAMPION = 21090, // Server side
SPELL_IMMUNE_POLY = 21087, // Server side
SPELL_HATE_TO_ZERO = 20538, // Threat reset after each teleport. Server side
SPELL_SEPARATION_ANXIETY = 21094, // Aura cast on himself by Majordomo Executus, if adds move out of range, they will cast spell 21095 on themselves
SPELL_SEPARATION_ANXIETY_MINION = 21095,
#define GOSSIP_HELLO 4995
// Outro & Ragnaros intro
SPELL_TELEPORT_SELF = 19484,
SPELL_SUMMON_RAGNAROS = 19774,
SPELL_ELEMENTAL_FIRE = 19773,
SPELL_RAGNA_EMERGE = 20568,
SPELL_RAGNAROS_FADE = 21107,
SPELL_RAGNAROS_SUBMERGE_EFFECT = 21859, // Applies pacify state and applies all schools immunity
};
enum Events
{
EVENT_MAGIC_REFLECTION = 1,
EVENT_DAMAGE_REFLECTION = 2,
EVENT_BLAST_WAVE = 3,
EVENT_TELEPORT = 4,
EVENT_MAGIC_REFLECTION = 1,
EVENT_DAMAGE_REFLECTION,
EVENT_BLAST_WAVE,
EVENT_TELEPORT_RANDOM,
EVENT_TELEPORT_TARGET,
EVENT_AEGIS_OF_RAGNAROS,
EVENT_OUTRO_1 = 5,
EVENT_OUTRO_2 = 6,
EVENT_OUTRO_3 = 7,
EVENT_DEFEAT_OUTRO_1 = 1,
EVENT_DEFEAT_OUTRO_2,
EVENT_DEFEAT_OUTRO_3,
EVENT_RAGNAROS_SUMMON_1 = 1,
EVENT_RAGNAROS_SUMMON_2,
EVENT_RAGNAROS_SUMMON_3,
EVENT_RAGNAROS_SUMMON_4,
EVENT_RAGNAROS_SUMMON_5,
EVENT_RAGNAROS_SUMMON_6,
EVENT_RAGNAROS_SUMMON_7,
EVENT_RAGNAROS_EMERGE,
};
enum Misc
{
TEXT_ID_SUMMON_1 = 4995,
TEXT_ID_SUMMON_2 = 5011,
TEXT_ID_SUMMON_3 = 5012,
GOSSIP_ITEM_SUMMON_1 = 4093,
GOSSIP_ITEM_SUMMON_2 = 4109,
GOSSIP_ITEM_SUMMON_3 = 4108,
FACTION_MAJORDOMO_FRIENDLY = 1080,
SUMMON_GROUP_ADDS = 1,
// Points
POINT_RAGNAROS_SUMMON = 1,
// Event phases
PHASE_NONE = 1,
PHASE_COMBAT = 2,
PHASE_DEFEAT_OUTRO = 3,
PHASE_RAGNAROS_SUMMONING = 4,
};
Position const MajordomoRagnaros = { 848.933f, -812.875f, -229.601f, 4.046f };
Position const MajordomoSummonPos = {759.542f, -1173.43f, -118.974f, 3.3048f };
Position const MajordomoMoveRagPos = { 830.9636f, -814.7055f, -228.9733f, 0.0f }; // Position used at Ragnaros summoning event
Position const RagnarosSummonPos = { 838.3082f, -831.4665f, -232.1853f, 2.199115f };
class boss_majordomo : public CreatureScript
{
public:
boss_majordomo() : CreatureScript("boss_majordomo") { }
boss_majordomo() : CreatureScript("boss_majordomo") {}
struct boss_majordomoAI : public BossAI
{
boss_majordomoAI(Creature* creature) : BossAI(creature, BOSS_MAJORDOMO_EXECUTUS)
boss_majordomoAI(Creature* creature) : BossAI(creature, DATA_MAJORDOMO_EXECUTUS), spawnInTextTimer(0) {}
// Disabled events
void JustDied(Unit* /*killer*/) override {}
void JustSummoned(Creature* summon) override
{
if (summon->GetEntry() == NPC_RAGNAROS)
{
summon->CastSpell(summon, SPELL_RAGNAROS_FADE);
summon->CastSpell(summon, SPELL_RAGNAROS_SUBMERGE_EFFECT, true);
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NON_ATTACKABLE);
summon->SetReactState(REACT_PASSIVE);
}
}
void KilledUnit(Unit* /*victim*/) override
void InitializeAI() override
{
if (urand(0, 99) < 25)
BossAI::InitializeAI();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
events.SetPhase(PHASE_COMBAT);
std::list<TempSummon*> p_summons;
me->SummonCreatureGroup(SUMMON_GROUP_ADDS, &p_summons);
if (!p_summons.empty())
{
for (TempSummon const* summon : p_summons)
{
if (summon)
{
static_minionsGUIDS.insert(summon->GetGUID());
}
}
}
spawnInTextTimer = 10000;
}
else
{
events.SetPhase(PHASE_NONE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->SetFaction(FACTION_MAJORDOMO_FRIENDLY);
}
}
void Reset() override
{
me->ResetLootMode();
events.Reset();
aliveMinionsGUIDS.clear();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE)
{
events.SetPhase(PHASE_COMBAT);
instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, NOT_STARTED);
}
else
{
static_minionsGUIDS.clear();
summons.DespawnAll();
}
}
bool CanAIAttack(Unit const* /*target*/) const override
{
return instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE;
}
void KilledUnit(Unit* victim) override
{
if (roll_chance_i(25) && victim->IsPlayer())
{
Talk(SAY_SLAY);
}
}
void EnterCombat(Unit* who) override
void EnterCombat(Unit* /*attacker*/) override
{
BossAI::EnterCombat(who);
if (!events.IsInPhase(PHASE_COMBAT))
{
return;
}
_EnterCombat();
DoCastAOE(SPELL_SEPARATION_ANXIETY);
spawnInTextTimer = 0;
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_MAGIC_REFLECTION, 30000);
events.ScheduleEvent(EVENT_DAMAGE_REFLECTION, 15000);
events.ScheduleEvent(EVENT_BLAST_WAVE, 10000);
events.ScheduleEvent(EVENT_TELEPORT, 20000);
// Call every flamewaker around him
me->CallForHelp(30);
DoCastSelf(SPELL_AEGIS_OF_RAGNAROS, true);
events.ScheduleEvent(EVENT_MAGIC_REFLECTION, 30000, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_DAMAGE_REFLECTION, 15000, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_BLAST_WAVE, 10000, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_TELEPORT_RANDOM, 15000, PHASE_COMBAT, PHASE_COMBAT);
events.ScheduleEvent(EVENT_TELEPORT_TARGET, 30000, PHASE_COMBAT, PHASE_COMBAT);
aliveMinionsGUIDS.clear();
aliveMinionsGUIDS = static_minionsGUIDS;
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
aliveMinionsGUIDS.erase(summon->GetGUID());
if (summon->GetEntry() == NPC_FLAMEWAKER_HEALER || summon->GetEntry() == NPC_FLAMEWAKER_ELITE)
{
uint32 const remainingAdds = std::count_if(aliveMinionsGUIDS.begin(), aliveMinionsGUIDS.end(), [](ObjectGuid const& summonGuid)
{
return summonGuid.GetEntry() == NPC_FLAMEWAKER_HEALER || summonGuid.GetEntry() == NPC_FLAMEWAKER_ELITE;
});
// Last remaining add
if (remainingAdds == 1)
{
Talk(SAY_LAST_ADD);
DoCastAOE(SPELL_CHAMPION);
}
// 50% of adds
else if (remainingAdds == 4)
{
DoCastAOE(SPELL_IMMUNE_POLY);
}
else if (!remainingAdds)
{
if (!static_minionsGUIDS.empty())
{
for (ObjectGuid const& guid : static_minionsGUIDS)
{
if (Creature* minion = ObjectAccessor::GetCreature(*me, guid))
{
minion->DespawnOrUnsummon();
}
}
static_minionsGUIDS.clear();
}
instance->SetBossState(DATA_MAJORDOMO_EXECUTUS, DONE);
events.CancelEventGroup(PHASE_COMBAT);
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
me->SetFaction(FACTION_MAJORDOMO_FRIENDLY);
EnterEvadeMode();
Talk(SAY_DEFEAT);
return;
}
DoCastAOE(SPELL_ENCOURAGEMENT);
}
}
void JustReachedHome() override
{
_JustReachedHome();
if (instance->GetBossState(DATA_MAJORDOMO_EXECUTUS) == DONE)
{
events.Reset();
events.SetPhase(PHASE_DEFEAT_OUTRO);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_1, 7500, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*dmgType*/, SpellSchoolMask /*school*/) override
{
if (events.IsInPhase(PHASE_COMBAT) && me->GetHealth() <= damage)
{
damage = 0;
}
}
void UpdateAI(uint32 diff) override
{
if (instance->GetBossState(BOSS_MAJORDOMO_EXECUTUS) != DONE)
if (spawnInTextTimer)
{
if (!UpdateVictim())
return;
events.Update(diff);
if (!me->FindNearestCreature(NPC_FLAMEWAKER_HEALER, 100.0f) && !me->FindNearestCreature(NPC_FLAMEWAKER_ELITE, 100.0f))
if (spawnInTextTimer <= diff)
{
me->GetMap()->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, me->GetEntry(), me);
me->SetFaction(FACTION_FRIENDLY);
EnterEvadeMode();
Talk(SAY_DEFEAT);
_JustDied();
events.ScheduleEvent(EVENT_OUTRO_1, 32000);
return;
spawnInTextTimer = 0;
Talk(SAY_SPAWN);
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (HealthBelowPct(50))
DoCast(me, SPELL_AEGIS_OF_RAGNAROS, true);
while (uint32 eventId = events.ExecuteEvent())
else
{
switch (eventId)
{
case EVENT_MAGIC_REFLECTION:
DoCast(me, SPELL_MAGIC_REFLECTION);
events.ScheduleEvent(EVENT_MAGIC_REFLECTION, 30000);
break;
case EVENT_DAMAGE_REFLECTION:
DoCast(me, SPELL_DAMAGE_REFLECTION);
events.ScheduleEvent(EVENT_DAMAGE_REFLECTION, 30000);
break;
case EVENT_BLAST_WAVE:
DoCastVictim(SPELL_BLAST_WAVE);
events.ScheduleEvent(EVENT_BLAST_WAVE, 10000);
break;
case EVENT_TELEPORT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
DoCast(target, SPELL_TELEPORT);
events.ScheduleEvent(EVENT_TELEPORT, 20000);
break;
default:
break;
}
spawnInTextTimer -= diff;
}
DoMeleeAttackIfReady();
}
else
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
switch (events.GetPhaseMask())
{
case (1 << (PHASE_COMBAT - 1)):
{
switch (eventId)
if (!UpdateVictim())
{
case EVENT_OUTRO_1:
me->NearTeleportTo(RagnarosTelePos.GetPositionX(), RagnarosTelePos.GetPositionY(), RagnarosTelePos.GetPositionZ(), RagnarosTelePos.GetOrientation());
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
break;
case EVENT_OUTRO_2:
instance->instance->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos);
break;
case EVENT_OUTRO_3:
Talk(SAY_ARRIVAL2_MAJ);
break;
default:
break;
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MAGIC_REFLECTION:
{
DoCastSelf(SPELL_MAGIC_REFLECTION);
events.RepeatEvent(30000);
break;
}
case EVENT_DAMAGE_REFLECTION:
{
DoCastSelf(SPELL_DAMAGE_REFLECTION);
events.RepeatEvent(30000);
break;
}
case EVENT_BLAST_WAVE:
{
DoCastVictim(SPELL_BLAST_WAVE);
events.RepeatEvent(10000);
break;
}
case EVENT_TELEPORT_RANDOM:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
{
DoCastSelf(SPELL_HATE_TO_ZERO, true);
DoCast(target, SPELL_TELEPORT_RANDOM);
}
events.RepeatEvent(15000);
break;
}
case EVENT_TELEPORT_TARGET:
{
DoCastSelf(SPELL_HATE_TO_ZERO, true);
DoCastAOE(SPELL_TELEPORT_TARGET);
events.RepeatEvent(30000);
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
break;
}
case (1 << (PHASE_DEFEAT_OUTRO - 1)):
{
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DEFEAT_OUTRO_1:
{
Talk(SAY_DEFEAT_2);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_2, 8000, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
break;
}
case EVENT_DEFEAT_OUTRO_2:
{
Talk(SAY_DEFEAT_3);
events.ScheduleEvent(EVENT_DEFEAT_OUTRO_3, 21500, PHASE_DEFEAT_OUTRO, PHASE_DEFEAT_OUTRO);
break;
}
case EVENT_DEFEAT_OUTRO_3:
{
DoCastSelf(SPELL_TELEPORT_SELF);
break;
}
}
}
break;
}
case (1 << (PHASE_RAGNAROS_SUMMONING - 1)):
{
events.Update(diff);
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_RAGNAROS_SUMMON_1:
{
if (GameObject* lavaSplash = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_SPLASH)))
{
lavaSplash->SetRespawnTime(900);
lavaSplash->Refresh();
}
if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM)))
{
lavaSteam->SetRespawnTime(900);
lavaSteam->Refresh();
}
Talk(SAY_RAG_SUM_2);
// Next event will get triggered in MovementInform
me->SetWalk(true);
me->GetMotionMaster()->MovePoint(POINT_RAGNAROS_SUMMON, MajordomoMoveRagPos, true, false);
break;
}
case EVENT_RAGNAROS_SUMMON_2:
{
if (GameObject* lavaSteam = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_LAVA_STEAM)))
{
me->SetFacingToObject(lavaSteam);
}
Talk(SAY_SUMMON_MAJ);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_3, 16700, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
events.ScheduleEvent(EVENT_RAGNAROS_EMERGE, 15000, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_3:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->AI()->Talk(SAY_ARRIVAL1_RAG);
}
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_4, 11700, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_4:
{
Talk(SAY_ARRIVAL2_MAJ);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_5, 8700, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_5:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->AI()->Talk(SAY_ARRIVAL3_RAG);
}
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_6, 16500, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
break;
}
case EVENT_RAGNAROS_SUMMON_6:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->CastSpell(me, SPELL_ELEMENTAL_FIRE, true);
ragnaros->AI()->DoAction(ACTION_FINISH_RAGNAROS_INTRO);
}
break;
}
// Additional events
case EVENT_RAGNAROS_EMERGE:
{
if (Creature* ragnaros = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_RAGNAROS)))
{
ragnaros->RemoveAurasDueToSpell(SPELL_RAGNAROS_FADE);
ragnaros->CastSpell(ragnaros, SPELL_RAGNA_EMERGE);
}
}break;
}
}
break;
}
}
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type == POINT_MOTION_TYPE && pointId == POINT_RAGNAROS_SUMMON)
{
DoCastAOE(SPELL_SUMMON_RAGNAROS);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_2, 11500, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
}
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
{
if (events.IsInPhase(PHASE_DEFEAT_OUTRO) && spellInfo->Id == SPELL_TELEPORT_SELF)
{
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->SetHomePosition(MajordomoRagnaros);
me->NearTeleportTo(MajordomoRagnaros.GetPositionX(), MajordomoRagnaros.GetPositionY(), MajordomoRagnaros.GetPositionZ(), MajordomoRagnaros.GetOrientation());
events.SetPhase(PHASE_NONE);
}
}
void DoAction(int32 action) override
{
if (action == ACTION_START_RAGNAROS && events.GetNextEventTime(EVENT_OUTRO_2) == 0)
if (action == ACTION_START_RAGNAROS_INTRO && !events.IsInPhase(PHASE_RAGNAROS_SUMMONING))
{
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
Talk(SAY_SUMMON_MAJ);
events.ScheduleEvent(EVENT_OUTRO_2, 8000);
events.ScheduleEvent(EVENT_OUTRO_3, 24000);
}
else if (action == ACTION_START_RAGNAROS_ALT)
{
me->SetFaction(FACTION_FRIENDLY);
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
events.SetPhase(PHASE_RAGNAROS_SUMMONING);
events.ScheduleEvent(EVENT_RAGNAROS_SUMMON_1, 5000, PHASE_RAGNAROS_SUMMONING, PHASE_RAGNAROS_SUMMONING);
}
}
private:
GuidSet static_minionsGUIDS; // contained data should be changed on encounter completion
GuidSet aliveMinionsGUIDS; // used for calculations
uint32 spawnInTextTimer;
};
bool OnGossipHello(Player* player, Creature* creature) override
{
AddGossipItemFor(player, 4093, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, GOSSIP_HELLO, creature->GetGUID());
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_1, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
SendGossipMenuFor(player, TEXT_ID_SUMMON_1, creature->GetGUID());
return true;
}
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 /*action*/) override
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
{
CloseGossipMenuFor(player);
creature->AI()->DoAction(ACTION_START_RAGNAROS);
ClearGossipMenuFor(player);
switch (action)
{
case GOSSIP_ACTION_INFO_DEF:
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, TEXT_ID_SUMMON_2, creature->GetGUID());
break;
}
case GOSSIP_ACTION_INFO_DEF+1:
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_2, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, TEXT_ID_SUMMON_2, creature->GetGUID());
break;
}
case GOSSIP_ACTION_INFO_DEF+2:
{
AddGossipItemFor(player, GOSSIP_ITEM_SUMMON_3, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
SendGossipMenuFor(player, TEXT_ID_SUMMON_3, creature->GetGUID());
break;
}
case GOSSIP_ACTION_INFO_DEF+3:
{
CloseGossipMenuFor(player);
creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
creature->AI()->Talk(SAY_RAG_SUM_1, player);
creature->AI()->DoAction(ACTION_START_RAGNAROS_INTRO);
break;
}
default:
CloseGossipMenuFor(player);
break;
}
return true;
}
@@ -210,7 +579,118 @@ public:
}
};
// 20538 Hate to Zero (SERVERSIDE)
class spell_hate_to_zero : public SpellScriptLoader
{
public:
spell_hate_to_zero() : SpellScriptLoader("spell_hate_to_zero") {}
class spell_hate_to_zero_SpellScript : public SpellScript
{
PrepareSpellScript(spell_hate_to_zero_SpellScript);
bool Load() override
{
return GetCaster()->GetTypeId() == TYPEID_UNIT;
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
if (Creature* creatureCaster = caster->ToCreature())
{
creatureCaster->getThreatMgr().resetAllAggro();
}
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_hate_to_zero_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_hate_to_zero_SpellScript();
}
};
// 21094 Separation Anxiety (server side)
class spell_majordomo_separation_nexiety : public SpellScriptLoader
{
public:
spell_majordomo_separation_nexiety() : SpellScriptLoader("spell_majordomo_separation_nexiety") {}
class spell_majordomo_separation_nexiety_AuraScript : public AuraScript
{
PrepareAuraScript(spell_majordomo_separation_nexiety_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_SEPARATION_ANXIETY_MINION });
}
void HandlePeriodic(AuraEffect const* aurEff)
{
Unit const* caster = GetCaster();
Unit* target = GetTarget();
if (caster && target && target->GetDistance(caster) > 40.0f && !target->HasAura(SPELL_SEPARATION_ANXIETY_MINION))
{
target->CastSpell(target, SPELL_SEPARATION_ANXIETY_MINION, true, nullptr, aurEff);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_majordomo_separation_nexiety_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
// Should return a fully valid AuraScript pointer.
AuraScript* GetAuraScript() const override
{
return new spell_majordomo_separation_nexiety_AuraScript();
}
};
// 19774 Summon Ragnaros
class spell_summon_ragnaros : public SpellScriptLoader
{
public:
spell_summon_ragnaros() : SpellScriptLoader("spell_summon_ragnaros") {}
class spell_summon_ragnaros_SpellScript : public SpellScript
{
PrepareSpellScript(spell_summon_ragnaros_SpellScript);
void HandleHit()
{
if (Unit* caster = GetCaster())
{
caster->SummonCreature(NPC_RAGNAROS, RagnarosSummonPos, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 2 * HOUR * IN_MILLISECONDS);
}
}
void Register() override
{
AfterCast += SpellCastFn(spell_summon_ragnaros_SpellScript::HandleHit);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_summon_ragnaros_SpellScript();
}
};
void AddSC_boss_majordomo()
{
new boss_majordomo();
// Spells
new spell_hate_to_zero();
new spell_majordomo_separation_nexiety();
new spell_summon_ragnaros();
}

View File

@@ -15,289 +15,304 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Ragnaros
SD%Complete: 95
SDComment: some spells doesnt work correctly
SDCategory: Molten Core
EndScriptData */
#include "molten_core.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
enum Texts
{
SAY_SUMMON_MAJ = 0,
SAY_ARRIVAL1_RAG = 1,
SAY_ARRIVAL2_MAJ = 2,
SAY_ARRIVAL3_RAG = 3,
SAY_ARRIVAL5_RAG = 4,
SAY_REINFORCEMENTS1 = 5,
SAY_REINFORCEMENTS2 = 6,
SAY_HAND = 7,
SAY_WRATH = 8,
SAY_KILL = 9,
SAY_MAGMABURST = 10
SAY_SUMMON_MAJ = 0,
SAY_ARRIVAL1_RAG = 1,
SAY_ARRIVAL2_MAJ = 2,
SAY_ARRIVAL3_RAG = 3,
SAY_ARRIVAL5_RAG = 4,
SAY_REINFORCEMENTS1 = 5,
SAY_REINFORCEMENTS2 = 6,
SAY_HAND = 7,
SAY_WRATH = 8,
SAY_KILL = 9,
SAY_MAGMABURST = 10
};
enum Spells
{
SPELL_HAND_OF_RAGNAROS = 19780,
SPELL_WRATH_OF_RAGNAROS = 20566,
SPELL_LAVA_BURST = 21158,
SPELL_MAGMA_BLAST = 20565, // Ranged attack
SPELL_SONS_OF_FLAME_DUMMY = 21108, // Server side effect
SPELL_RAGSUBMERGE = 21107, // Stealth aura
SPELL_RAGEMERGE = 20568,
SPELL_MELT_WEAPON = 21388,
SPELL_ELEMENTAL_FIRE = 20564,
SPELL_ERRUPTION = 17731
SPELL_HAND_OF_RAGNAROS = 19780,
SPELL_WRATH_OF_RAGNAROS = 20566,
SPELL_LAVA_BURST = 21158,
SPELL_MAGMA_BLAST = 20565, // Ranged attack
SPELL_SONS_OF_FLAME_DUMMY = 21108, // Server side effect
SPELL_RAGSUBMERGE = 21107, // Stealth aura
SPELL_RAGNA_SUBMERGE_VISUAL = 20567, // Visual for submerging into lava
SPELL_RAGEMERGE = 20568,
SPELL_MELT_WEAPON = 21387,
SPELL_ELEMENTAL_FIRE = 20563,
SPELL_ERRUPTION = 17731,
SPELL_RAGNAROS_SUBMERGE_EFFECT = 21859, // Applies pacify state and applies all schools immunity
};
enum Events
{
EVENT_ERUPTION = 1,
EVENT_WRATH_OF_RAGNAROS = 2,
EVENT_HAND_OF_RAGNAROS = 3,
EVENT_LAVA_BURST = 4,
EVENT_ELEMENTAL_FIRE = 5,
EVENT_MAGMA_BLAST = 6,
EVENT_SUBMERGE = 7,
EVENT_WRATH_OF_RAGNAROS,
EVENT_HAND_OF_RAGNAROS,
EVENT_LAVA_BURST,
EVENT_MAGMA_BLAST,
EVENT_SUBMERGE,
EVENT_INTRO_1 = 8,
EVENT_INTRO_2 = 9,
EVENT_INTRO_3 = 10,
EVENT_INTRO_4 = 11,
EVENT_INTRO_5 = 12
EVENT_INTRO_1,
EVENT_INTRO_2,
EVENT_INTRO_3,
EVENT_INTRO_4,
EVENT_INTRO_5,
};
enum Creatures
{
NPC_SON_OF_FLAME = 12143,
};
enum Misc
{
MAX_SON_OF_FLAME_COUNT = 8,
};
constexpr float DEATH_ORIENTATION = 4.0f;
class boss_ragnaros : public CreatureScript
{
public:
boss_ragnaros() : CreatureScript("boss_ragnaros") { }
boss_ragnaros() : CreatureScript("boss_ragnaros") {}
struct boss_ragnarosAI : public BossAI
{
boss_ragnarosAI(Creature* creature) : BossAI(creature, BOSS_RAGNAROS)
boss_ragnarosAI(Creature* creature) : BossAI(creature, DATA_RAGNAROS),
attackableTImer(0),
_emergeTimer(90000),
_hasYelledMagmaBurst(false),
_hasSubmergedOnce(false),
_isBanished(false)
{
_introState = 0;
me->SetReactState(REACT_PASSIVE);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
creature->SetReactState(REACT_PASSIVE);
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
}
void Reset() override
{
BossAI::Reset();
_Reset();
_emergeTimer = 90000;
_hasYelledMagmaBurst = false;
_hasSubmergedOnce = false;
_isBanished = false;
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
DoCastSelf(SPELL_MELT_WEAPON, true);
DoCastSelf(SPELL_ELEMENTAL_FIRE, true);
}
void EnterCombat(Unit* victim) override
void DoAction(int32 action) override
{
BossAI::EnterCombat(victim);
if (action == ACTION_FINISH_RAGNAROS_INTRO)
{
attackableTImer = 10000;
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
summons.Despawn(summon);
}
void EnterCombat(Unit* /*victim*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_ERUPTION, 15000);
events.ScheduleEvent(EVENT_WRATH_OF_RAGNAROS, 30000);
events.ScheduleEvent(EVENT_HAND_OF_RAGNAROS, 25000);
events.ScheduleEvent(EVENT_LAVA_BURST, 10000);
events.ScheduleEvent(EVENT_ELEMENTAL_FIRE, 3000);
events.ScheduleEvent(EVENT_MAGMA_BLAST, 2000);
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
}
void JustDied(Unit* killer) override
void JustDied(Unit* /*killer*/) override
{
BossAI::JustDied(killer);
_JustDied();
me->SetFacingTo(DEATH_ORIENTATION);
}
void KilledUnit(Unit* /*victim*/) override
void KilledUnit(Unit* victim) override
{
if (urand(0, 99) < 25)
if (roll_chance_i(25) && victim->GetTypeId() == TYPEID_PLAYER)
{
Talk(SAY_KILL);
}
}
void AttackStart(Unit* target) override
{
if (target && me->Attack(target, true))
{
DoStartNoMovement(target);
}
}
void UpdateAI(uint32 diff) override
{
if (_introState != 2)
if (attackableTImer)
{
if (!_introState)
if (attackableTImer <= diff)
{
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
events.ScheduleEvent(EVENT_INTRO_1, 4000);
events.ScheduleEvent(EVENT_INTRO_2, 23000);
events.ScheduleEvent(EVENT_INTRO_3, 42000);
events.ScheduleEvent(EVENT_INTRO_4, 43000);
events.ScheduleEvent(EVENT_INTRO_5, 53000);
_introState = 1;
}
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_INTRO_1:
Talk(SAY_ARRIVAL1_RAG);
break;
case EVENT_INTRO_2:
Talk(SAY_ARRIVAL3_RAG);
break;
case EVENT_INTRO_3:
me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK1H);
break;
case EVENT_INTRO_4:
Talk(SAY_ARRIVAL5_RAG);
if (Creature* executus = ObjectAccessor::GetCreature(*me, instance->GetGuidData(BOSS_MAJORDOMO_EXECUTUS)))
Unit::Kill(me, executus);
break;
case EVENT_INTRO_5:
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
_introState = 2;
break;
default:
break;
}
}
}
else
{
if (_isBanished && ((_emergeTimer <= diff) || (instance->GetData(DATA_RAGNAROS_ADDS)) > 8))
{
//Become unbanished again
me->RemoveAurasDueToSpell(SPELL_RAGNAROS_SUBMERGE_EFFECT);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC | UNIT_FLAG_NON_ATTACKABLE);
me->SetReactState(REACT_AGGRESSIVE);
me->SetFaction(FACTION_MONSTER);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
AttackStart(target);
instance->SetData(DATA_RAGNAROS_ADDS, 0);
_isBanished = false;
DoZoneInCombat();
attackableTImer = 0;
}
else if (_isBanished)
else
{
_emergeTimer -= diff;
return;
attackableTImer -= diff;
}
}
if (_isBanished && (_emergeTimer <= diff || !summons.HasEntry(NPC_SON_OF_FLAME)))
{
//Become unbanished again
me->SetReactState(REACT_AGGRESSIVE);
me->SetFaction(14);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
me->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
AttackStart(target);
}
if (!UpdateVictim())
return;
_isBanished = false;
}
else if (_isBanished)
{
_emergeTimer -= diff;
return;
}
events.Update(diff);
if (!UpdateVictim())
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
switch (eventId)
case EVENT_ERUPTION:
{
case EVENT_ERUPTION:
DoCastVictim(SPELL_ERRUPTION);
events.ScheduleEvent(EVENT_ERUPTION, urand(20000, 45000));
break;
case EVENT_WRATH_OF_RAGNAROS:
DoCastVictim(SPELL_WRATH_OF_RAGNAROS);
if (urand(0, 1))
Talk(SAY_WRATH);
events.ScheduleEvent(EVENT_WRATH_OF_RAGNAROS, 25000);
break;
case EVENT_HAND_OF_RAGNAROS:
DoCast(me, SPELL_HAND_OF_RAGNAROS);
if (urand(0, 1))
Talk(SAY_HAND);
events.ScheduleEvent(EVENT_HAND_OF_RAGNAROS, 20000);
break;
case EVENT_LAVA_BURST:
DoCastVictim(SPELL_LAVA_BURST);
events.ScheduleEvent(EVENT_LAVA_BURST, 10000);
break;
case EVENT_ELEMENTAL_FIRE:
DoCastVictim(SPELL_ELEMENTAL_FIRE);
events.ScheduleEvent(EVENT_ELEMENTAL_FIRE, urand(10000, 14000));
break;
case EVENT_MAGMA_BLAST:
if (!me->IsWithinMeleeRange(me->GetVictim()))
DoCastVictim(SPELL_ERRUPTION);
events.RepeatEvent(urand(20000, 45000));
break;
}
case EVENT_WRATH_OF_RAGNAROS:
{
DoCastVictim(SPELL_WRATH_OF_RAGNAROS);
if (urand(0, 1))
{
Talk(SAY_WRATH);
}
events.RepeatEvent(25000);
break;
}
case EVENT_HAND_OF_RAGNAROS:
{
DoCastSelf(SPELL_HAND_OF_RAGNAROS);
if (urand(0, 1))
{
Talk(SAY_HAND);
}
events.RepeatEvent(20000);
break;
}
case EVENT_LAVA_BURST:
{
DoCastVictim(SPELL_LAVA_BURST);
events.RepeatEvent(10000);
break;
}
case EVENT_MAGMA_BLAST:
{
Unit* victim = me->GetVictim();
if (victim && !me->IsWithinMeleeRange(victim))
{
DoCast(victim, SPELL_MAGMA_BLAST);
if (!_hasYelledMagmaBurst)
{
DoCastVictim(SPELL_MAGMA_BLAST);
if (!_hasYelledMagmaBurst)
{
Talk(SAY_MAGMABURST);
_hasYelledMagmaBurst = true;
}
Talk(SAY_MAGMABURST);
_hasYelledMagmaBurst = true;
}
events.ScheduleEvent(EVENT_MAGMA_BLAST, 2500);
break;
case EVENT_SUBMERGE:
{
if (!_isBanished)
{
// TODO: There is a spell to summon him
me->AttackStop();
DoResetThreat();
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(false);
me->SetFaction(FACTION_FRIENDLY);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
instance->SetData(DATA_RAGNAROS_ADDS, 0);
if (!_hasSubmergedOnce)
{
Talk(SAY_REINFORCEMENTS1);
// summon 8 elementals
for (uint8 i = 0; i < 8; ++i)
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
if (Creature* summoned = me->SummonCreature(12143, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
summoned->AI()->AttackStart(target);
_hasSubmergedOnce = true;
_isBanished = true;
_emergeTimer = 90000;
}
else
{
Talk(SAY_REINFORCEMENTS2);
for (uint8 i = 0; i < 8; ++i)
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
if (Creature* summoned = me->SummonCreature(12143, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
summoned->AI()->AttackStart(target);
_isBanished = true;
_emergeTimer = 90000;
}
}
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
break;
}
default:
break;
}
events.RepeatEvent(2500);
break;
}
case EVENT_SUBMERGE:
{
if (!_isBanished)
{
me->InterruptNonMeleeSpells(false);
me->AttackStop();
DoResetThreat();
me->SetReactState(REACT_PASSIVE);
me->SetFaction(35);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SUBMERGED);
DoCastSelf(SPELL_RAGNA_SUBMERGE_VISUAL, true);
//me->HandleEmoteCommand(EMOTE_ONESHOT_SUBMERGE);
SummonMinions();
}
events.ScheduleEvent(EVENT_SUBMERGE, 180000);
break;
}
}
DoMeleeAttackIfReady();
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}
DoMeleeAttackIfReady();
}
private:
float const DEATH_ORIENTATION = 4.0f;
uint32 attackableTImer; // used after intro
uint32 _emergeTimer;
uint8 _introState;
bool _hasYelledMagmaBurst;
bool _hasSubmergedOnce;
bool _isBanished;
void SummonMinions()
{
Talk(_hasSubmergedOnce ? SAY_REINFORCEMENTS2 : SAY_REINFORCEMENTS1);
for (uint8 i = 0; i < MAX_SON_OF_FLAME_COUNT; ++i)
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
if (Creature* summoned = me->SummonCreature(NPC_SON_OF_FLAME, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 900000))
{
summoned->AI()->AttackStart(target);
}
}
}
_isBanished = true;
_emergeTimer = 90000;
if (!_hasSubmergedOnce)
{
_hasSubmergedOnce = true;
}
}
};
CreatureAI* GetAI(Creature* creature) const override
@@ -306,40 +321,7 @@ public:
}
};
class npc_son_of_flame : public CreatureScript
{
public:
npc_son_of_flame() : CreatureScript("npc_SonOfFlame") { }
struct npc_son_of_flameAI : public ScriptedAI
{
npc_son_of_flameAI(Creature* creature) : ScriptedAI(creature)
{
instance = me->GetInstanceScript();
}
void JustDied(Unit* /*killer*/) override { instance->SetData(DATA_RAGNAROS_ADDS, 1); }
void UpdateAI(uint32 /*diff*/) override
{
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_son_of_flameAI>(creature);
}
};
void AddSC_boss_ragnaros()
{
new boss_ragnaros();
new npc_son_of_flame();
}

View File

@@ -15,29 +15,29 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "molten_core.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "molten_core.h"
#include "Player.h"
enum Spells
{
SPELL_ARCANE_EXPLOSION = 19712,
SPELL_SHAZZRAH_CURSE = 19713,
SPELL_MAGIC_GROUNDING = 19714,
SPELL_COUNTERSPELL = 19715,
SPELL_SHAZZRAH_GATE_DUMMY = 23138, // Teleports to and attacks a random target.
SPELL_SHAZZRAH_GATE = 23139,
SPELL_ARCANE_EXPLOSION = 19712,
SPELL_SHAZZRAH_CURSE = 19713,
SPELL_MAGIC_GROUNDING = 19714,
SPELL_COUNTERSPELL = 19715,
SPELL_SHAZZRAH_GATE_DUMMY = 23138, // Teleports to and attacks a random target. About every 45 seconds Shazzrah will blink to random target causing a wipe of the threat list (source: wowwwiki)
SPELL_SHAZZRAH_GATE = 23139,
};
enum Events
{
EVENT_ARCANE_EXPLOSION = 1,
EVENT_ARCANE_EXPLOSION_TRIGGERED = 2,
EVENT_SHAZZRAH_CURSE = 3,
EVENT_MAGIC_GROUNDING = 4,
EVENT_COUNTERSPELL = 5,
EVENT_SHAZZRAH_GATE = 6,
EVENT_SHAZZRAH_CURSE,
EVENT_MAGIC_GROUNDING,
EVENT_COUNTERSPELL,
EVENT_SHAZZRAH_GATE,
};
class boss_shazzrah : public CreatureScript
@@ -47,66 +47,57 @@ public:
struct boss_shazzrahAI : public BossAI
{
boss_shazzrahAI(Creature* creature) : BossAI(creature, BOSS_SHAZZRAH) { }
boss_shazzrahAI(Creature* creature) : BossAI(creature, DATA_SHAZZRAH) {}
void EnterCombat(Unit* target) override
void EnterCombat(Unit* /*target*/) override
{
BossAI::EnterCombat(target);
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 6000);
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, 10000);
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 24000);
events.ScheduleEvent(EVENT_COUNTERSPELL, 15000);
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 45000);
_EnterCombat();
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(2000, 4000));
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, urand(7000, 11000));
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, urand(14000, 19000));
events.ScheduleEvent(EVENT_COUNTERSPELL, urand(9000, 10000));
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 30000);
}
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
switch (eventId)
{
switch (eventId)
case EVENT_ARCANE_EXPLOSION:
{
case EVENT_ARCANE_EXPLOSION:
DoCastVictim(SPELL_ARCANE_EXPLOSION);
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, urand(4000, 7000));
break;
// Triggered subsequent to using "Gate of Shazzrah".
case EVENT_ARCANE_EXPLOSION_TRIGGERED:
DoCastVictim(SPELL_ARCANE_EXPLOSION);
break;
case EVENT_SHAZZRAH_CURSE:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_SHAZZRAH_CURSE))
DoCast(target, SPELL_SHAZZRAH_CURSE);
events.ScheduleEvent(EVENT_SHAZZRAH_CURSE, urand(25000, 30000));
break;
case EVENT_MAGIC_GROUNDING:
DoCast(me, SPELL_MAGIC_GROUNDING);
events.ScheduleEvent(EVENT_MAGIC_GROUNDING, 35000);
break;
case EVENT_COUNTERSPELL:
DoCastVictim(SPELL_COUNTERSPELL);
events.ScheduleEvent(EVENT_COUNTERSPELL, urand(16000, 20000));
break;
case EVENT_SHAZZRAH_GATE:
DoResetThreat();
DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY);
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION_TRIGGERED, 2000);
events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, urand(3000, 6000));
events.ScheduleEvent(EVENT_SHAZZRAH_GATE, 45000);
break;
default:
break;
DoCastVictim(SPELL_ARCANE_EXPLOSION);
events.RepeatEvent(urand(4000, 5000));
break;
}
case EVENT_SHAZZRAH_CURSE:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_SHAZZRAH_CURSE))
{
DoCast(target, SPELL_SHAZZRAH_CURSE);
}
events.RepeatEvent(urand(23000, 26000));
break;
}
case EVENT_MAGIC_GROUNDING:
{
DoCastSelf(SPELL_MAGIC_GROUNDING);
events.RepeatEvent(urand(7000, 9000));
break;
}
case EVENT_COUNTERSPELL:
{
DoCastAOE(SPELL_COUNTERSPELL);
events.RepeatEvent(urand(15000, 18000));
break;
}
case EVENT_SHAZZRAH_GATE:
{
DoCastAOE(SPELL_SHAZZRAH_GATE_DUMMY);
events.RescheduleEvent(EVENT_ARCANE_EXPLOSION, urand(3000, 6000));
events.RepeatEvent(45000);
break;
}
}
DoMeleeAttackIfReady();
}
};
@@ -120,7 +111,7 @@ public:
class spell_shazzrah_gate_dummy : public SpellScriptLoader
{
public:
spell_shazzrah_gate_dummy() : SpellScriptLoader("spell_shazzrah_gate_dummy") { }
spell_shazzrah_gate_dummy() : SpellScriptLoader("spell_shazzrah_gate_dummy") {}
class spell_shazzrah_gate_dummy_SpellScript : public SpellScript
{
@@ -133,21 +124,55 @@ public:
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
return;
Unit* caster = GetCaster();
if (!targets.empty())
{
targets.remove_if([caster](WorldObject const* target) -> bool
{
Player const* plrTarget = target->ToPlayer();
// Should not target non player targets
if (!plrTarget)
{
return true;
}
WorldObject* target = Acore::Containers::SelectRandomContainerElement(targets);
targets.clear();
targets.push_back(target);
// Should skip current victim
if (caster->GetVictim() == plrTarget)
{
return true;
}
// Should not target enemies within melee range
if (plrTarget->IsWithinDistInMap(caster, caster->GetMeleeRange(plrTarget)))
{
return true;
}
return false;
});
}
if (!targets.empty())
{
Acore::Containers::RandomResize(targets, 1);
}
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
Unit* caster = GetCaster();
Unit* target = GetHitUnit();
if (!caster || !target)
{
target->CastSpell(GetCaster(), SPELL_SHAZZRAH_GATE, true);
if (Creature* creature = GetCaster()->ToCreature())
creature->AI()->AttackStart(target); // Attack the target which caster will teleport to.
target->CastSpell(caster, SPELL_SHAZZRAH_GATE, true, nullptr, nullptr, caster->GetGUID());
caster->CastSpell(caster, SPELL_ARCANE_EXPLOSION);
if (Creature* creatureCaster = caster->ToCreature())
{
creatureCaster->getThreatMgr().resetAllAggro();
creatureCaster->AI()->AttackStart(target); // Attack the target which caster will teleport to.
}
}
}
@@ -167,5 +192,7 @@ public:
void AddSC_boss_shazzrah()
{
new boss_shazzrah();
// Spells
new spell_shazzrah_gate_dummy();
}

View File

@@ -15,17 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Sulfuron_Harbringer
SD%Complete: 80
SDComment: Adds NYI
SDCategory: Molten Core
EndScriptData */
#include "molten_core.h"
#include "ObjectMgr.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "molten_core.h"
enum Spells
{
@@ -45,84 +37,79 @@ enum Spells
enum Events
{
EVENT_DARK_STRIKE = 1,
EVENT_DEMORALIZING_SHOUT = 2,
EVENT_INSPIRE = 3,
EVENT_KNOCKDOWN = 4,
EVENT_FLAMESPEAR = 5,
EVENT_DEMORALIZING_SHOUT,
EVENT_INSPIRE,
EVENT_KNOCKDOWN,
EVENT_FLAMESPEAR,
EVENT_HEAL = 6,
EVENT_SHADOW_WORD_PAIN = 7,
EVENT_IMMOLATE = 8,
EVENT_HEAL,
EVENT_SHADOW_WORD_PAIN,
EVENT_IMMOLATE,
};
class boss_sulfuron : public CreatureScript
{
public:
boss_sulfuron() : CreatureScript("boss_sulfuron") { }
boss_sulfuron() : CreatureScript("boss_sulfuron") {}
struct boss_sulfuronAI : public BossAI
{
boss_sulfuronAI(Creature* creature) : BossAI(creature, BOSS_SULFURON_HARBINGER)
{
}
boss_sulfuronAI(Creature* creature) : BossAI(creature, DATA_SULFURON) {}
void EnterCombat(Unit* victim) override
void EnterCombat(Unit* /*victim*/) override
{
BossAI::EnterCombat(victim);
events.ScheduleEvent(EVENT_DARK_STRIKE, 10000);
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, 15000);
events.ScheduleEvent(EVENT_INSPIRE, 13000);
_EnterCombat();
events.ScheduleEvent(EVENT_DARK_STRIKE, urand(4000, 7000));
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, urand(6000, 20000));
events.ScheduleEvent(EVENT_INSPIRE, urand(7000, 10000));
events.ScheduleEvent(EVENT_KNOCKDOWN, 6000);
events.ScheduleEvent(EVENT_FLAMESPEAR, 2000);
}
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
switch (eventId)
{
switch (eventId)
case EVENT_DARK_STRIKE:
{
case EVENT_DARK_STRIKE:
DoCast(me, SPELL_DARK_STRIKE);
events.ScheduleEvent(EVENT_DARK_STRIKE, urand(15000, 18000));
break;
case EVENT_DEMORALIZING_SHOUT:
DoCastVictim(SPELL_DEMORALIZING_SHOUT);
events.ScheduleEvent(EVENT_DEMORALIZING_SHOUT, urand(15000, 20000));
break;
case EVENT_INSPIRE:
{
std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE);
if (!healers.empty())
DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
DoCastSelf(SPELL_DARK_STRIKE);
events.RepeatEvent(urand(4000, 7000));
break;
}
case EVENT_DEMORALIZING_SHOUT:
{
DoCastVictim(SPELL_DEMORALIZING_SHOUT);
events.RepeatEvent(urand(12000, 18000));
break;
}
case EVENT_INSPIRE:
{
std::list<Creature*> healers = DoFindFriendlyMissingBuff(45.0f, SPELL_INSPIRE);
if (!healers.empty())
{
DoCast(Acore::Containers::SelectRandomContainerElement(healers), SPELL_INSPIRE);
}
DoCast(me, SPELL_INSPIRE);
events.ScheduleEvent(EVENT_INSPIRE, urand(20000, 26000));
break;
}
case EVENT_KNOCKDOWN:
DoCastVictim(SPELL_KNOCKDOWN);
events.ScheduleEvent(EVENT_KNOCKDOWN, urand(12000, 15000));
break;
case EVENT_FLAMESPEAR:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
DoCast(target, SPELL_FLAMESPEAR);
events.ScheduleEvent(EVENT_FLAMESPEAR, urand(12000, 16000));
break;
default:
break;
DoCastSelf(SPELL_INSPIRE);
events.RepeatEvent(urand(13000, 20000));
break;
}
case EVENT_KNOCKDOWN:
{
DoCastVictim(SPELL_KNOCKDOWN);
events.RepeatEvent(urand(10000, 20000));
break;
}
case EVENT_FLAMESPEAR:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
{
DoCast(target, SPELL_FLAMESPEAR);
}
events.RepeatEvent(urand(12000, 16000));
break;
}
}
DoMeleeAttackIfReady();
}
};
@@ -135,13 +122,11 @@ public:
class npc_flamewaker_priest : public CreatureScript
{
public:
npc_flamewaker_priest() : CreatureScript("npc_flamewaker_priest") { }
npc_flamewaker_priest() : CreatureScript("npc_flamewaker_priest") {}
struct npc_flamewaker_priestAI : public ScriptedAI
{
npc_flamewaker_priestAI(Creature* creature) : ScriptedAI(creature)
{
}
npc_flamewaker_priestAI(Creature* creature) : ScriptedAI(creature) {}
void Reset() override
{
@@ -153,45 +138,63 @@ public:
events.Reset();
}
void EnterCombat(Unit* victim) override
void EnterCombat(Unit* /*victim*/) override
{
ScriptedAI::EnterCombat(victim);
events.ScheduleEvent(EVENT_HEAL, urand(15000, 30000));
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 2000);
events.ScheduleEvent(EVENT_IMMOLATE, 8000);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(2000, 4000));
events.ScheduleEvent(EVENT_IMMOLATE, urand(3500, 6000));
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
while (uint32 eventId = events.ExecuteEvent())
while (uint32 const eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_HEAL:
{
if (Unit* target = DoSelectLowestHpFriendly(60.0f, 1))
{
DoCast(target, SPELL_HEAL);
events.ScheduleEvent(EVENT_HEAL, urand(15000, 20000));
}
events.RepeatEvent(urand(15000, 20000));
break;
}
case EVENT_SHADOW_WORD_PAIN:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_SHADOWWORDPAIN))
{
DoCast(target, SPELL_SHADOWWORDPAIN);
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(18000, 26000));
}
events.RepeatEvent(urand(2500, 5000));
break;
}
case EVENT_IMMOLATE:
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true, -SPELL_IMMOLATE))
{
DoCast(target, SPELL_IMMOLATE);
events.ScheduleEvent(EVENT_IMMOLATE, urand(15000, 25000));
break;
default:
}
events.RepeatEvent(urand(5000, 7000));
break;
}
}
if (me->HasUnitState(UNIT_STATE_CASTING))
{
return;
}
}

View File

@@ -15,51 +15,64 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Instance_Molten_Core
SD%Complete: 0
SDComment: Place Holder
SDCategory: Molten Core
EndScriptData */
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "molten_core.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "InstanceScript.h"
#include "TemporarySummon.h"
#include "molten_core.h"
Position const SummonPositions[10] =
MinionData const minionData[] =
{
{759.542f, -1173.43f, -118.974f, 3.3048f},
{761.652f, -1164.30f, -119.533f, 3.3919f},
{747.323f, -1149.24f, -120.060f, 3.6629f},
{766.734f, -1183.16f, -119.292f, 2.9889f},
{757.364f, -1198.31f, -118.652f, 2.3095f},
{752.349f, -1159.19f, -119.261f, 3.6032f},
{738.015f, -1152.22f, -119.512f, 4.0792f},
{757.246f, -1189.79f, -118.633f, 2.5333f},
{745.916f, -1199.35f, -118.119f, 1.8932f},
{838.510f, -829.840f, -232.000f, 2.00000f},
{ NPC_FIRESWORN, DATA_GARR },
{ NPC_FLAMEWALKER, DATA_GEHENNAS },
{ NPC_FLAMEWALKER_PROTECTOR, DATA_LUCIFRON },
{ NPC_FLAMEWALKER_PRIEST, DATA_SULFURON },
{ NPC_FLAMEWALKER_HEALER, DATA_MAJORDOMO_EXECUTUS },
{ NPC_FLAMEWALKER_ELITE, DATA_MAJORDOMO_EXECUTUS },
{ 0, 0 } // END
};
struct MCBossObject
{
uint32 bossId;
uint32 runeId;
uint32 circleId;
};
constexpr uint8 MAX_MC_LINKED_BOSS_OBJ = 7;
MCBossObject const linkedBossObjData[MAX_MC_LINKED_BOSS_OBJ]=
{
{ DATA_MAGMADAR, GO_RUNE_KRESS, GO_CIRCLE_MAGMADAR },
{ DATA_GEHENNAS, GO_RUNE_MOHN, GO_CIRCLE_GEHENNAS },
{ DATA_GARR, GO_RUNE_BLAZ, GO_CIRCLE_GARR },
{ DATA_SHAZZRAH, GO_RUNE_MAZJ, GO_CIRCLE_SHAZZRAH },
{ DATA_GEDDON, GO_RUNE_ZETH, GO_CIRCLE_GEDDON },
{ DATA_GOLEMAGG, GO_RUNE_THERI, GO_CIRCLE_GOLEMAGG },
{ DATA_SULFURON, GO_RUNE_KORO, GO_CIRCLE_SULFURON },
};
class instance_molten_core : public InstanceMapScript
{
public:
instance_molten_core() : InstanceMapScript("instance_molten_core", 409) { }
instance_molten_core() : InstanceMapScript(MCScriptName, 409) {}
struct instance_molten_core_InstanceMapScript : public InstanceScript
{
instance_molten_core_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetBossNumber(MAX_ENCOUNTER);
_deadBossCount = 0;
_ragnarosAddDeaths = 0;
LoadMinionData(minionData);
}
void OnPlayerEnter(Player* /*player*/) override
{
if (CheckMajordomoExecutus())
{
SummonMajordomoExecutus();
}
}
void OnCreatureCreate(Creature* creature) override
@@ -67,13 +80,61 @@ public:
switch (creature->GetEntry())
{
case NPC_GOLEMAGG_THE_INCINERATOR:
_golemaggTheIncineratorGUID = creature->GetGUID();
{
_golemaggGUID = creature->GetGUID();
break;
}
case NPC_CORE_RAGER:
{
_golemaggMinionsGUIDS.insert(creature->GetGUID());
break;
}
case NPC_MAJORDOMO_EXECUTUS:
{
_majordomoExecutusGUID = creature->GetGUID();
break;
default:
}
case NPC_GARR:
{
_garrGUID = creature->GetGUID();
break;
}
case NPC_RAGNAROS:
{
_ragnarosGUID = creature->GetGUID();
break;
}
case NPC_FIRESWORN:
case NPC_FLAMEWALKER:
case NPC_FLAMEWALKER_PROTECTOR:
case NPC_FLAMEWALKER_PRIEST:
case NPC_FLAMEWALKER_HEALER:
case NPC_FLAMEWALKER_ELITE:
{
AddMinion(creature, true);
break;
}
}
}
void OnCreatureRemove(Creature* creature) override
{
switch (creature->GetEntry())
{
case NPC_FIRESWORN:
{
AddMinion(creature, false);
break;
}
case NPC_FLAMEWALKER:
case NPC_FLAMEWALKER_PROTECTOR:
case NPC_FLAMEWALKER_PRIEST:
case NPC_FLAMEWALKER_HEALER:
case NPC_FLAMEWALKER_ELITE:
{
AddMinion(creature, false);
break;
}
}
}
@@ -82,64 +143,92 @@ public:
switch (go->GetEntry())
{
case GO_CACHE_OF_THE_FIRELORD:
{
_cacheOfTheFirelordGUID = go->GetGUID();
break;
case GO_CIRCLE_BARON:
_circlesGUIDs[5] = go->GetGUID();
break;
}
case GO_CIRCLE_GEDDON:
case GO_CIRCLE_GARR:
_circlesGUIDs[3] = go->GetGUID();
break;
case GO_CIRCLE_GEHENNAS:
_circlesGUIDs[2] = go->GetGUID();
break;
case GO_CIRCLE_GOLEMAGG:
_circlesGUIDs[7] = go->GetGUID();
break;
case GO_CIRCLE_MAGMADAR:
_circlesGUIDs[1] = go->GetGUID();
break;
case GO_CIRCLE_SHAZZRAH:
_circlesGUIDs[4] = go->GetGUID();
break;
case GO_CIRCLE_SULFURON:
_circlesGUIDs[6] = go->GetGUID();
{
for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i)
{
if (linkedBossObjData[i].circleId != go->GetEntry())
{
continue;
}
if (GetBossState(linkedBossObjData[i].bossId) == DONE)
{
go->DespawnOrUnsummon();
}
else
{
_circlesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID();
}
}
break;
default:
}
case GO_RUNE_KRESS:
case GO_RUNE_MOHN:
case GO_RUNE_BLAZ:
case GO_RUNE_MAZJ:
case GO_RUNE_ZETH:
case GO_RUNE_THERI:
case GO_RUNE_KORO:
{
for (uint8 i = 0; i < MAX_MC_LINKED_BOSS_OBJ; ++i)
{
if (linkedBossObjData[i].runeId != go->GetEntry())
{
continue;
}
if (GetBossState(linkedBossObjData[i].bossId) == DONE)
{
go->SetGoState(GO_STATE_ACTIVE);
}
else
{
_runesGUIDs[linkedBossObjData[i].bossId] = go->GetGUID();
}
}
break;
}
case GO_LAVA_STEAM:
{
_lavaSteamGUID = go->GetGUID();
break;
}
case GO_LAVA_SPLASH:
{
_lavaSplashGUID = go->GetGUID();
break;
}
}
}
void SetData(uint32 type, uint32 data) override
{
if (type == DATA_RAGNAROS_ADDS)
{
if (data == 1)
++_ragnarosAddDeaths;
else if (data == 0)
_ragnarosAddDeaths = 0;
}
}
uint32 GetData(uint32 type) const override
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case DATA_RAGNAROS_ADDS:
return _ragnarosAddDeaths;
}
return 0;
}
ObjectGuid GetGuidData(uint32 type) const override
{
switch (type)
{
case BOSS_GOLEMAGG_THE_INCINERATOR:
return _golemaggTheIncineratorGUID;
case BOSS_MAJORDOMO_EXECUTUS:
case DATA_GOLEMAGG:
return _golemaggGUID;
case DATA_MAJORDOMO_EXECUTUS:
return _majordomoExecutusGUID;
case DATA_GARR:
return _garrGUID;
case DATA_LAVA_STEAM:
return _lavaSteamGUID;
case DATA_LAVA_SPLASH:
return _lavaSplashGUID;
case DATA_RAGNAROS:
return _ragnarosGUID;
}
return ObjectGuid::Empty;
@@ -148,54 +237,153 @@ public:
bool SetBossState(uint32 bossId, EncounterState state) override
{
if (!InstanceScript::SetBossState(bossId, state))
{
return false;
}
if (state == DONE && bossId < BOSS_MAJORDOMO_EXECUTUS)
if (CheckMajordomoExecutus())
SummonMajordomoExecutus();
if (bossId == BOSS_MAJORDOMO_EXECUTUS && state == DONE)
if (bossId == DATA_MAJORDOMO_EXECUTUS && state == DONE)
{
DoRespawnGameObject(_cacheOfTheFirelordGUID, 7 * DAY);
}
else if (bossId == DATA_GOLEMAGG)
{
switch (state)
{
case NOT_STARTED:
case FAIL:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
Creature* minion = instance->GetCreature(minionGuid);
if (minion && minion->isDead())
{
minion->Respawn();
}
}
}
break;
}
case IN_PROGRESS:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
{
minion->AI()->DoZoneInCombat(nullptr, 150.0f);
}
}
}
break;
}
case DONE:
{
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
{
minion->CastSpell(minion, SPELL_CORE_RAGER_QUIET_SUICIDE, true);
}
}
_golemaggMinionsGUIDS.clear();
}
break;
}
default:
break;
}
}
// Perform needed checks for Majordomu
if (bossId < DATA_MAJORDOMO_EXECUTUS && state == DONE)
{
if (GameObject* circle = instance->GetGameObject(_circlesGUIDs[bossId]))
{
circle->DespawnOrUnsummon();
_circlesGUIDs[bossId].Clear();
}
if (GameObject* rune = instance->GetGameObject(_runesGUIDs[bossId]))
{
rune->SetGoState(GO_STATE_ACTIVE);
_runesGUIDs[bossId].Clear();
}
if (CheckMajordomoExecutus())
{
SummonMajordomoExecutus();
}
}
return true;
}
void DoAction(int32 action) override
{
if (action == ACTION_RESET_MAGMADAR_ENCOUNTER)
{
if (Creature* golemagg = instance->GetCreature(_golemaggGUID))
{
golemagg->AI()->EnterEvadeMode();
}
if (!_golemaggMinionsGUIDS.empty())
{
for (ObjectGuid const& minionGuid : _golemaggMinionsGUIDS)
{
if (Creature* minion = instance->GetCreature(minionGuid))
{
minion->AI()->EnterEvadeMode();
}
}
}
}
}
void SummonMajordomoExecutus()
{
if (_majordomoExecutusGUID)
return;
if (GetBossState(BOSS_MAJORDOMO_EXECUTUS) != DONE)
if (instance->GetCreature(_majordomoExecutusGUID))
{
instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, SummonPositions[0]);
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[1]);
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[2]);
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[3]);
instance->SummonCreature(NPC_FLAMEWAKER_HEALER, SummonPositions[4]);
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[5]);
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[6]);
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[7]);
instance->SummonCreature(NPC_FLAMEWAKER_ELITE, SummonPositions[8]);
return;
}
else if (TempSummon* summon = instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, RagnarosTelePos))
summon->AI()->DoAction(ACTION_START_RAGNAROS_ALT);
instance->SummonCreature(NPC_MAJORDOMO_EXECUTUS, GetBossState(DATA_MAJORDOMO_EXECUTUS) != DONE ? MajordomoSummonPos : MajordomoRagnaros);
}
bool CheckMajordomoExecutus() const
{
if (GetBossState(BOSS_RAGNAROS) == DONE)
if (GetBossState(DATA_RAGNAROS) == DONE)
{
return false;
}
for (uint8 i = 0; i < DATA_MAJORDOMO_EXECUTUS; ++i)
{
if (i == DATA_LUCIFRON)
{
continue;
}
for (uint8 i = 0; i < BOSS_MAJORDOMO_EXECUTUS; ++i)
if (GetBossState(i) != DONE)
{
return false;
}
}
// Prevent spawning if Ragnaros is present
if (instance->GetCreature(_ragnarosGUID))
{
return false;
}
return true;
}
std::string GetSaveData() override
std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
@@ -206,7 +394,7 @@ public:
return saveStream.str();
}
void Load(char const* data) override
void Load(char const* data) override
{
if (!data)
{
@@ -228,27 +416,43 @@ public:
uint32 tmpState;
loadStream >> tmpState;
if (tmpState == IN_PROGRESS || tmpState > TO_BE_DECIDED)
{
tmpState = NOT_STARTED;
}
SetBossState(i, EncounterState(tmpState));
SetBossState(i, static_cast<EncounterState>(tmpState));
}
if (CheckMajordomoExecutus())
{
SummonMajordomoExecutus();
}
}
else
{
OUT_LOAD_INST_DATA_FAIL;
}
OUT_LOAD_INST_DATA_COMPLETE;
}
private:
ObjectGuid _golemaggTheIncineratorGUID;
std::unordered_map<uint32/*bossid*/, ObjectGuid/*circleGUID*/> _circlesGUIDs;
std::unordered_map<uint32/*bossid*/, ObjectGuid/*runeGUID*/> _runesGUIDs;
// Golemagg encounter related
ObjectGuid _golemaggGUID;
GuidSet _golemaggMinionsGUIDS;
// Ragnaros encounter related
ObjectGuid _ragnarosGUID;
ObjectGuid _lavaSteamGUID;
ObjectGuid _lavaSplashGUID;
ObjectGuid _majordomoExecutusGUID;
ObjectGuid _cacheOfTheFirelordGUID;
uint8 _deadBossCount;
uint8 _ragnarosAddDeaths;
std::unordered_map<uint8, ObjectGuid> _circlesGUIDs;
ObjectGuid _garrGUID;
ObjectGuid _magmadarGUID;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override

View File

@@ -0,0 +1,216 @@
/*
* This file is part of the AzerothCore 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 Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "molten_core.h"
enum Texts
{
EMOTE_SMOLDERING = 0,
EMOTE_IGNITE = 1,
};
enum Spells
{
// Ancient Core Hound
SPELL_SERRATED_BITE = 19771,
SPELL_PLAY_DEAD = 19822,
SPELL_FULL_HEALTH = 17683,
SPELL_FIRE_NOVA_VISUAL = 19823,
SPELL_PLAY_DEAD_PACIFY = 19951, // Server side spell
};
// Serrated Bites timer may be wrong
class npc_mc_core_hound : public CreatureScript
{
public:
npc_mc_core_hound() : CreatureScript("npc_mc_core_hound") {}
struct npc_mc_core_houndAI : public CreatureAI
{
npc_mc_core_houndAI(Creature* creature) :
CreatureAI(creature),
instance(creature->GetInstanceScript()),
serratedBiteTimer(3000)
{
}
void Reset() override
{
serratedBiteTimer = 3000;
}
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damagetype*/, SpellSchoolMask /*damageSchoolMask*/) override
{
// Prevent receiving any extra damage if Hound is playing dead
if (me->HasAura(SPELL_PLAY_DEAD))
{
damage = 0;
return;
}
else if (me->GetHealth() <= damage)
{
damage = 0;
Talk(EMOTE_SMOLDERING);
DoCastSelf(SPELL_PLAY_DEAD);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_PLAY_DEAD))
{
return;
}
if (serratedBiteTimer <= diff)
{
DoCastVictim(SPELL_SERRATED_BITE);
serratedBiteTimer = urand(5000, 6000);
}
else
{
serratedBiteTimer -= diff;
}
DoMeleeAttackIfReady();
}
private:
InstanceScript* instance;
uint32 serratedBiteTimer;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetMoltenCoreAI<npc_mc_core_houndAI>(creature);
}
};
// 19822 Play Dead
class spell_mc_play_dead : public SpellScriptLoader
{
public:
spell_mc_play_dead() : SpellScriptLoader("spell_mc_play_dead") { }
class spell_mc_play_dead_AuraScript : public AuraScript
{
PrepareAuraScript(spell_mc_play_dead_AuraScript);
bool Load() override
{
return GetCaster()->GetTypeId() == TYPEID_UNIT;
}
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Creature* creatureTarget = GetTarget()->ToCreature();
if (!creatureTarget)
{
return;
}
creatureTarget->CastSpell(creatureTarget, SPELL_PLAY_DEAD_PACIFY, true);
creatureTarget->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
creatureTarget->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
//creatureTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
creatureTarget->SetReactState(REACT_PASSIVE);
creatureTarget->SetControlled(true, UNIT_STATE_ROOT);
creatureTarget->AttackStop();
}
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Creature* creatureTarget = GetTarget()->ToCreature();
if (!creatureTarget)
{
return;
}
creatureTarget->RemoveAurasDueToSpell(SPELL_PLAY_DEAD_PACIFY);
creatureTarget->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
creatureTarget->RemoveFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
//creatureTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
creatureTarget->SetControlled(false, UNIT_STATE_ROOT);
creatureTarget->SetReactState(REACT_AGGRESSIVE);
if (!creatureTarget->IsInCombat())
{
return;
}
bool shouldDie = true;
std::list<Creature*> hounds;
creatureTarget->GetCreaturesWithEntryInRange(hounds, 80.0f, NPC_CORE_HOUND);
// Perform lambda based check to find if there is any nearby
if (!hounds.empty())
{
// Alive hound been found within 80 yards -> cancel suicide
if (std::find_if(hounds.begin(), hounds.end(), [creatureTarget](Creature const* hound)
{
return creatureTarget != hound && creatureTarget->IsWithinLOSInMap(hound) && hound->IsAlive() && hound->IsInCombat() && !hound->HasAura(SPELL_PLAY_DEAD);
}) != hounds.end())
{
shouldDie = false;
}
}
if (!shouldDie)
{
if (CreatureAI* targetAI = creatureTarget->AI())
{
targetAI->DoCastSelf(SPELL_FIRE_NOVA_VISUAL, true);
targetAI->DoCastSelf(SPELL_FULL_HEALTH, true);
targetAI->Talk(EMOTE_IGNITE);
}
}
else
{
Unit::Kill(creatureTarget, creatureTarget);
}
}
void Register() override
{
AfterEffectApply += AuraEffectApplyFn(spell_mc_play_dead_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_FEIGN_DEATH, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectApplyFn(spell_mc_play_dead_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_FEIGN_DEATH, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_mc_play_dead_AuraScript();
}
};
void AddSC_molten_core()
{
// Creatures
new npc_mc_core_hound();
// Spells
new spell_mc_play_dead();
}

View File

@@ -15,74 +15,107 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#ifndef DEF_MOLTEN_CORE_H
#define DEF_MOLTEN_CORE_H
#include "CreatureAIImpl.h"
#define MCScriptName "instance_molten_core"
enum Encounters
constexpr uint32 MAX_ENCOUNTER = 10;
enum MCData
{
BOSS_LUCIFRON = 0,
BOSS_MAGMADAR = 1,
BOSS_GEHENNAS = 2,
BOSS_GARR = 3,
BOSS_SHAZZRAH = 4,
BOSS_BARON_GEDDON = 5,
BOSS_SULFURON_HARBINGER = 6,
BOSS_GOLEMAGG_THE_INCINERATOR = 7,
BOSS_MAJORDOMO_EXECUTUS = 8,
BOSS_RAGNAROS = 9,
MAX_ENCOUNTER,
DATA_LUCIFRON = 0,
DATA_MAGMADAR = 1,
DATA_GEHENNAS = 2,
DATA_GARR = 3,
DATA_SHAZZRAH = 4,
DATA_GEDDON = 5,
DATA_SULFURON = 6,
DATA_GOLEMAGG = 7,
DATA_MAJORDOMO_EXECUTUS = 8,
DATA_RAGNAROS = 9,
// Other data
DATA_LAVA_STEAM = 10,
DATA_LAVA_SPLASH = 11,
};
enum Actions
enum MCActions
{
ACTION_START_RAGNAROS = 0,
ACTION_START_RAGNAROS_ALT = 1,
ACTION_START_RAGNAROS_INTRO = -1,
ACTION_FINISH_RAGNAROS_INTRO = -2,
ACTION_RESET_MAGMADAR_ENCOUNTER = -3, // Used when ragers are pulled far away
ACTION_PREPARE_MAJORDOMO_RAGNA = -4,
};
Position const RagnarosTelePos = {829.159f, -815.773f, -228.972f, 5.30500f};
Position const RagnarosSummonPos = {838.510f, -829.840f, -232.000f, 2.00000f};
enum Creatures
enum MCCreatures
{
NPC_LUCIFRON = 12118,
NPC_MAGMADAR = 11982,
NPC_GEHENNAS = 12259,
NPC_GARR = 12057,
NPC_SHAZZRAH = 12264,
NPC_BARON_GEDDON = 12056,
NPC_SULFURON_HARBINGER = 12098,
NPC_GOLEMAGG_THE_INCINERATOR = 11988,
NPC_MAJORDOMO_EXECUTUS = 12018,
NPC_RAGNAROS = 11502,
NPC_FLAMEWAKER_HEALER = 11663,
NPC_FLAMEWAKER_ELITE = 11664,
NPC_CORE_RAGER = 11672,
NPC_CORE_HOUND = 11671,
// Garr
NPC_GARR = 12057,
NPC_FIRESWORN = 12099,
// Gehennas
NPC_GEHENNAS = 12259,
NPC_FLAMEWALKER = 11661,
// Golemagg
NPC_GOLEMAGG_THE_INCINERATOR = 11988,
NPC_CORE_RAGER = 11672,
// Lucifron
NPC_LUCIFRON = 12118,
NPC_FLAMEWALKER_PROTECTOR = 12119,
// Sulfuron
NPC_SULFURON_HARBINGER = 12098,
NPC_FLAMEWALKER_PRIEST = 11662,
// Majordomo
NPC_MAJORDOMO_EXECUTUS = 12018,
NPC_FLAMEWALKER_HEALER = 11663,
NPC_FLAMEWALKER_ELITE = 11664,
};
enum GameObjects
enum MCGameObjects
{
GO_CACHE_OF_THE_FIRELORD = 179703,
GO_CIRCLE_SULFURON = 178187,
GO_CIRCLE_BARON = 178188,
GO_CIRCLE_GEDDON = 178188,
GO_CIRCLE_SHAZZRAH = 178189,
GO_CIRCLE_GOLEMAGG = 178190,
GO_CIRCLE_GARR = 178191,
GO_CIRCLE_MAGMADAR = 178192,
GO_CIRCLE_GEHENNAS = 178193,
GO_RUNE_KRESS = 176956, // Magmadar
GO_RUNE_MOHN = 176957, // Gehennas
GO_RUNE_BLAZ = 176955, // Garr
GO_RUNE_MAZJ = 176953, // Shazzrah
GO_RUNE_ZETH = 176952, // Geddon
GO_RUNE_THERI = 176954, // Golemagg
GO_RUNE_KORO = 176951, // Sulfuron
// Ragnaros event related
GO_LAVA_STEAM = 178107,
GO_LAVA_SPLASH = 178108,
};
enum Data
enum MCSpells
{
DATA_RAGNAROS_ADDS = 0,
SPELL_CORE_RAGER_QUIET_SUICIDE = 3617, // Server side
};
extern Position const MajordomoRagnaros; // Teleport location to Ragnaros summons area
extern Position const MajordomoSummonPos; // Majordomo summon position (battle)
template <class AI, class T>
inline AI* GetMoltenCoreAI(T* obj)
{

View File

@@ -74,7 +74,8 @@ void AddSC_boss_selin_fireheart();
void AddSC_boss_vexallus();
void AddSC_boss_priestess_delrissa();
void AddSC_instance_magisters_terrace();
void AddSC_boss_lucifron(); //Molten core
void AddSC_molten_core(); //Molten core
void AddSC_boss_lucifron();
void AddSC_boss_magmadar();
void AddSC_boss_gehennas();
void AddSC_boss_garr();
@@ -210,7 +211,8 @@ void AddEasternKingdomsScripts()
AddSC_boss_vexallus();
AddSC_boss_priestess_delrissa();
AddSC_instance_magisters_terrace();
AddSC_boss_lucifron(); //Molten core
AddSC_molten_core(); // Molten core
AddSC_boss_lucifron();
AddSC_boss_magmadar();
AddSC_boss_gehennas();
AddSC_boss_garr();