fix(Core/ZG): Multiple improvements to High Priestess Mar'li (#11647)

This commit is contained in:
Nefertumm
2022-06-13 19:44:20 -03:00
committed by GitHub
parent 32334f5f14
commit 7e703393d2
4 changed files with 314 additions and 193 deletions

View File

@@ -15,45 +15,72 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_Marli
SD%Complete: 80
SDComment: Charging healers and casters not working. Perhaps wrong Spell Timers.
SDCategory: Zul'Gurub
EndScriptData */
#include "GameObjectAI.h"
#include "SpellScript.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "zulgurub.h"
enum Says
{
// Mar'li
SAY_AGGRO = 0,
SAY_TRANSFORM = 1,
SAY_SPIDER_SPAWN = 2,
SAY_DEATH = 3
SAY_DEATH = 3,
SAY_TRANSFORM_BACK = 4,
// Spawn of Mar'li
EMOTE_FULL_GROWN = 0
};
enum Spells
{
// Spider form
SPELL_CHARGE = 22911,
SPELL_ASPECT_OF_MARLI = 24686, // A stun spell
SPELL_ENVOLWINGWEB = 24110,
SPELL_ENVELOPING_WEB = 24110,
SPELL_CORROSIVE_POISON = 24111,
SPELL_POISON_SHOCK = 24112,
//Troll form
SPELL_POISON_VOLLEY = 24099,
SPELL_DRAIN_LIFE = 24300,
SPELL_ENLARGE = 24109,
SPELL_SPIDER_EGGS = 24082,
// All
SPELL_SPIDER_FORM = 24084,
// The Spider Spell
SPELL_LEVELUP = 24312 // Not right Spell.
SPELL_TRANSFORM_BACK = 24085,
SPELL_THRASH = 3391,
SPELL_HATCH_SPIDER_EGG = 24082,
SPELL_HATCH_EGGS = 24083,
// Spawn of Mar'li
SPELL_GROWTH = 24086,
SPELL_FULL_GROWN = 24088
};
enum Events
{
EVENT_SPAWN_START_SPIDERS = 1, // Phase 1
EVENT_POISON_VOLLEY = 2, // Phase All
EVENT_SPAWN_SPIDER = 3, // Phase All
EVENT_CHARGE_PLAYER = 4, // Phase 3
EVENT_ASPECT_OF_MARLI = 5, // Phase 2
EVENT_TRANSFORM = 6, // Phase 2
EVENT_TRANSFORM_BACK = 7 // Phase 3
// Spider form
EVENT_CHARGE_PLAYER = 7,
EVENT_ENVELOPING_WEB = 8,
EVENT_CORROSIVE_POISON = 9,
EVENT_POISON_SHOCK = 10,
// Troll form
EVENT_POISON_VOLLEY = 11,
EVENT_DRAIN_LIFE = 12,
EVENT_ENLARGE = 13,
// All
EVENT_SPAWN_START_SPIDERS = 1,
EVENT_TRANSFORM = 2,
EVENT_TRANSFORM_BACK = 3,
EVENT_HATCH_SPIDER_EGG = 4,
EVENT_THRASH = 5,
EVENT_TALK_FIRST_SPIDERS = 6,
};
enum Phases
@@ -63,208 +90,269 @@ enum Phases
PHASE_THREE = 3
};
class boss_marli : public CreatureScript
enum Misc
{
public:
boss_marli() : CreatureScript("boss_marli") { }
GO_SPIDER_EGGS = 179985,
};
struct boss_marliAI : public BossAI
struct boss_marli : public BossAI
{
boss_marli(Creature* creature) : BossAI(creature, DATA_MARLI) { }
void Reset() override
{
boss_marliAI(Creature* creature) : BossAI(creature, DATA_MARLI) { }
if (events.IsInPhase(PHASE_THREE))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
void Reset() override
std::list<GameObject*> eggs;
me->GetGameObjectListWithEntryInGrid(eggs, GO_SPIDER_EGGS, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& egg : eggs)
{
if (events.IsInPhase(PHASE_THREE))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
_Reset();
egg->Respawn();
egg->UpdateObjectVisibility();
}
void JustDied(Unit* /*killer*/) override
BossAI::Reset();
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
events.ScheduleEvent(EVENT_SPAWN_START_SPIDERS, 1000, 0, PHASE_ONE);
Talk(SAY_AGGRO);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
_JustDied();
Talk(SAY_DEATH);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_SPAWN_START_SPIDERS, 1000, 0, PHASE_ONE);
Talk(SAY_AGGRO);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
switch (eventId)
{
switch (eventId)
case EVENT_SPAWN_START_SPIDERS:
events.ScheduleEvent(EVENT_TALK_FIRST_SPIDERS, 500, 0, PHASE_TWO);
DoCastAOE(SPELL_HATCH_EGGS);
events.ScheduleEvent(EVENT_TRANSFORM, 60000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_HATCH_SPIDER_EGG, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_DRAIN_LIFE, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_THRASH, urand(4000, 6000)); // all phases
events.ScheduleEvent(EVENT_ENLARGE, urand(10000, 20000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
case EVENT_TALK_FIRST_SPIDERS:
Talk(SAY_SPIDER_SPAWN);
break;
case EVENT_POISON_VOLLEY:
DoCastVictim(SPELL_POISON_VOLLEY, true);
events.ScheduleEvent(EVENT_POISON_VOLLEY, urand(10000, 20000), 0, PHASE_TWO);
break;
case EVENT_HATCH_SPIDER_EGG:
DoCastSelf(SPELL_HATCH_SPIDER_EGG, true);
events.ScheduleEvent(EVENT_HATCH_SPIDER_EGG, 20000, 0, PHASE_TWO);
break;
case EVENT_DRAIN_LIFE:
DoCastRandomTarget(SPELL_DRAIN_LIFE);
events.ScheduleEvent(EVENT_DRAIN_LIFE, urand(20000, 50000), 0, PHASE_TWO);
break;
case EVENT_ENLARGE:
{
case EVENT_SPAWN_START_SPIDERS:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
Talk(SAY_SPIDER_SPAWN);
Creature* Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
}
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000);
events.ScheduleEvent(EVENT_SPAWN_SPIDER, 30000);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
case EVENT_POISON_VOLLEY:
DoCastVictim(SPELL_POISON_VOLLEY, true);
events.ScheduleEvent(EVENT_POISON_VOLLEY, urand(10000, 20000));
break;
case EVENT_ASPECT_OF_MARLI:
DoCastVictim(SPELL_ASPECT_OF_MARLI, true);
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, urand(13000, 18000), 0, PHASE_TWO);
break;
case EVENT_SPAWN_SPIDER:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
Creature* Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
}
events.ScheduleEvent(EVENT_SPAWN_SPIDER, urand(12000, 17000));
break;
case EVENT_TRANSFORM:
{
Talk(SAY_TRANSFORM);
DoCast(me, SPELL_SPIDER_FORM); // SPELL_AURA_TRANSFORM
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
DoCastVictim(SPELL_ENVOLWINGWEB);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatPercent(me->GetVictim(), -100);
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 1500, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 25000, 0, PHASE_THREE);
events.SetPhase(PHASE_THREE);
break;
}
case EVENT_CHARGE_PLAYER:
{
Unit* target = nullptr;
int i = 0;
while (i++ < 3) // max 3 tries to get a random target with power_mana
{
target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); // not aggro leader
if (target && target->getPowerType() == POWER_MANA)
break;
}
if (target)
{
DoCast(target, SPELL_CHARGE);
AttackStart(target);
}
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 8000, 0, PHASE_THREE);
break;
}
case EVENT_TRANSFORM_BACK:
{
me->RemoveAura(SPELL_SPIDER_FORM);
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 1)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 1)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000);
events.ScheduleEvent(EVENT_SPAWN_SPIDER, 30000);
events.ScheduleEvent(EVENT_TRANSFORM, urand(35000, 60000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
}
default:
break;
std::list<Creature*> targets = DoFindFriendlyMissingBuff(100.f, SPELL_ENLARGE);
if (targets.size() > 0)
DoCast(*(targets.begin()), SPELL_ENLARGE);
events.ScheduleEvent(EVENT_ENLARGE, urand(20000, 40000), 0, PHASE_TWO);
break;
}
case EVENT_TRANSFORM:
Talk(SAY_TRANSFORM);
DoCastSelf(SPELL_SPIDER_FORM, true);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
events.ScheduleEvent(EVENT_ENVELOPING_WEB, 5000, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 6000, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_CORROSIVE_POISON, 1000, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_POISON_SHOCK, urand(5000, 10000), 0, PHASE_THREE);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 60000, 0, PHASE_THREE);
events.SetPhase(PHASE_THREE);
break;
case EVENT_ENVELOPING_WEB:
DoCastAOE(SPELL_ENVELOPING_WEB);
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 500, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_ENVELOPING_WEB, urand(15000, 20000), 0, PHASE_THREE);
break;
case EVENT_CHARGE_PLAYER:
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [this](Unit* target) -> bool
{
if (target->GetTypeId() != TYPEID_PLAYER || target->getPowerType() != Powers::POWER_MANA)
return false;
if (me->IsWithinMeleeRange(target) || me->GetVictim() == target)
return false;
return true;
});
if (target)
{
DoCast(target, SPELL_CHARGE);
AttackStart(target);
}
break;
}
case EVENT_CORROSIVE_POISON:
DoCastVictim(SPELL_CORROSIVE_POISON);
events.ScheduleEvent(EVENT_CORROSIVE_POISON, urand(25000, 35000), 0, PHASE_THREE);
break;
case EVENT_POISON_SHOCK:
DoCastRandomTarget(SPELL_POISON_SHOCK);
events.ScheduleEvent(EVENT_POISON_SHOCK, 10000, 0, PHASE_THREE);
break;
case EVENT_TRANSFORM_BACK:
me->RemoveAura(SPELL_SPIDER_FORM);
DoCastSelf(SPELL_TRANSFORM_BACK, true);
Talk(SAY_TRANSFORM_BACK);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_TRANSFORM, 60000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_HATCH_SPIDER_EGG, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_DRAIN_LIFE, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_ENLARGE, urand(10000, 20000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
case EVENT_THRASH:
DoCastVictim(SPELL_THRASH);
events.ScheduleEvent(EVENT_THRASH, urand(10000, 20000));
break;
default:
break;
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetZulGurubAI<boss_marliAI>(creature);
DoMeleeAttackIfReady();
}
};
// Spawn of Marli
class npc_spawn_of_marli : public CreatureScript
// Spawn of Mar'li
struct npc_spawn_of_marli : public ScriptedAI
{
public:
npc_spawn_of_marli() : CreatureScript("npc_spawn_of_marli") { }
npc_spawn_of_marli(Creature* creature) : ScriptedAI(creature) { }
struct npc_spawn_of_marliAI : public ScriptedAI
void Reset() override
{
npc_spawn_of_marliAI(Creature* creature) : ScriptedAI(creature) { }
_scheduler.CancelAll();
}
uint32 LevelUp_Timer;
void Reset() override
void EnterCombat(Unit* /*who*/) override
{
_scheduler.Schedule(4s, [this](TaskContext context)
{
LevelUp_Timer = 3000;
}
void EnterCombat(Unit* /*who*/) override
{
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
//LevelUp_Timer
if (LevelUp_Timer <= diff)
if (context.GetRepeatCounter() < 5)
{
DoCast(me, SPELL_LEVELUP);
LevelUp_Timer = 3000;
DoCastSelf(SPELL_GROWTH);
context.Repeat(4s);
}
else LevelUp_Timer -= diff;
else
{
Talk(EMOTE_FULL_GROWN);
DoCastSelf(SPELL_FULL_GROWN);
}
});
}
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
void UpdateAI(uint32 diff) override
{
return GetZulGurubAI<npc_spawn_of_marliAI>(creature);
//Return since we have no target
if (!UpdateVictim())
return;
_scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
private:
TaskScheduler _scheduler;
};
// 24083 - Hatch Eggs
class spell_hatch_eggs : public SpellScript
{
PrepareSpellScript(spell_hatch_eggs);
void HandleObjectAreaTargetSelect(std::list<WorldObject*>& targets)
{
targets.sort(Acore::ObjectDistanceOrderPred(GetCaster()));
targets.resize(GetSpellInfo()->MaxAffectedTargets);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hatch_eggs::HandleObjectAreaTargetSelect, EFFECT_0, TARGET_GAMEOBJECT_DEST_AREA);
}
};
// 24110 - Enveloping Webs
class spell_enveloping_webs : public SpellScript
{
PrepareSpellScript(spell_enveloping_webs);
void HandleOnHit()
{
Unit* caster = GetCaster();
Unit* hitUnit = GetHitUnit();
if (caster && hitUnit && hitUnit->GetTypeId() == TYPEID_PLAYER)
{
caster->GetThreatMgr().modifyThreatPercent(hitUnit, -100);
}
}
void Register() override
{
OnHit += SpellHitFn(spell_enveloping_webs::HandleOnHit);
}
};
// 24084 - Mar'li Transform
class spell_marli_transform : public AuraScript
{
PrepareAuraScript(spell_marli_transform);
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetCaster() && GetCaster()->ToCreature())
GetCaster()->ToCreature()->LoadEquipment(0, true);
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetCaster() && GetCaster()->ToCreature())
GetCaster()->ToCreature()->LoadEquipment(1, true);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_marli_transform::HandleApply, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_marli_transform::HandleRemove, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_marli()
{
new boss_marli();
new npc_spawn_of_marli();
RegisterCreatureAI(boss_marli);
RegisterCreatureAI(npc_spawn_of_marli);
RegisterSpellScript(spell_hatch_eggs);
RegisterSpellScript(spell_enveloping_webs);
RegisterSpellScript(spell_marli_transform);
}

View File

@@ -36,7 +36,8 @@ ObjectData const creatureData[] =
{
{ NPC_HIGH_PRIEST_THEKAL, DATA_THEKAL },
{ NPC_ZEALOT_LORKHAN, DATA_LORKHAN },
{ NPC_ZEALOT_ZATH, DATA_ZATH }
{ NPC_ZEALOT_ZATH, DATA_ZATH },
{ NPC_PRIESTESS_MARLI, DATA_MARLI }
};
class instance_zulgurub : public InstanceMapScript
@@ -49,6 +50,7 @@ public:
instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
LoadObjectData(creatureData, nullptr);
}
@@ -71,7 +73,15 @@ public:
case NPC_HAKKAR:
_hakkarGUID = creature->GetGUID();
break;
case NPC_SPAWN_OF_MARLI:
if (Creature* marli = GetCreature(DATA_MARLI))
{
marli->AI()->JustSummoned(creature);
}
break;
}
InstanceScript::OnCreatureCreate(creature);
}
void OnGameObjectCreate(GameObject* go) override

View File

@@ -49,6 +49,8 @@ enum CreatureIds
NPC_ZULIAN_PROWLER = 15101, // Arlokk Event
NPC_ZEALOT_LORKHAN = 11347,
NPC_ZEALOT_ZATH = 11348,
NPC_PRIESTESS_MARLI = 14510,
NPC_SPAWN_OF_MARLI = 15041,
NPC_HIGH_PRIEST_THEKAL = 14509,
NPC_JINDO_THE_HEXXER = 11380,
NPC_NIGHTMARE_ILLUSION = 15163,