/*
* 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 General Public License as published by
* the Free Software Foundation; either version 2 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 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 .
*/
#include "CreatureScript.h"
#include "GameObjectAI.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.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_TRANSFORM_BACK = 4,
// Spawn of Mar'li
EMOTE_FULL_GROWN = 0
};
enum Spells
{
// Spider Form
SPELL_CHARGE = 22911,
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,
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 Phases
{
PHASE_TROLL = 1,
PHASE_SPIDER = 2
};
enum Misc
{
GO_SPIDER_EGGS = 179985,
};
// hack
float const DamageIncrease = 35.0f;
float const DamageDecrease = 100.f / (1.f + DamageIncrease / 100.f) - 100.f;
// High Priestess Mar'li (14510)
struct boss_marli : public BossAI
{
public:
boss_marli(Creature* creature) : BossAI(creature, DATA_MARLI) { }
void Reset() override
{
if (_phase == PHASE_SPIDER)
{
me->RemoveAura(SPELL_SPIDER_FORM);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
_phase = PHASE_TROLL;
}
std::list eggs;
me->GetGameObjectListWithEntryInGrid(eggs, GO_SPIDER_EGGS, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& egg : eggs)
{
egg->Respawn();
egg->UpdateObjectVisibility();
}
BossAI::Reset();
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO);
scheduler.Schedule(1s, [this](TaskContext)
{
DoCastAOE(SPELL_HATCH_EGGS);
scheduler.Schedule(500ms, [this](TaskContext)
{
Talk(SAY_SPIDER_SPAWN);
});
// Both Forms
scheduler.Schedule(4s, 6s, [this](TaskContext context)
{
DoCastVictim(SPELL_THRASH);
context.Repeat(10s, 20s);
});
_schedulePhaseTroll();
});
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
private:
Phases _phase = PHASE_TROLL;
void _schedulePhaseTroll()
{
// only if switching back from spider form
if (_phase == PHASE_SPIDER)
{
me->RemoveAura(SPELL_SPIDER_FORM);
DoCastSelf(SPELL_TRANSFORM_BACK, true);
Talk(SAY_TRANSFORM_BACK);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageDecrease);
scheduler.CancelGroup(PHASE_SPIDER);
}
_phase = PHASE_TROLL;
scheduler.Schedule(15s, PHASE_TROLL, [this](TaskContext context)
{
DoCastVictim(SPELL_POISON_VOLLEY, true);
context.Repeat(10s, 20s);
}).Schedule(30s, PHASE_TROLL, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_DRAIN_LIFE);
context.Repeat(20s, 50s);
}).Schedule(30s, PHASE_TROLL, [this](TaskContext context)
{
DoCastSelf(SPELL_HATCH_SPIDER_EGG, true);
context.Repeat(20s);
}).Schedule(10s, 20s, PHASE_TROLL, [this](TaskContext context)
{
std::list targets = DoFindFriendlyMissingBuff(100.f, SPELL_ENLARGE);
for (auto const& target : targets)
{
DoCast(target, SPELL_ENLARGE);
}
context.Repeat(20s, 40s);
});
// Transition to PHASE_SPIDER
scheduler.Schedule(1min, PHASE_TROLL, [this](TaskContext)
{
_schedulePhaseSpider();
});
}
void _schedulePhaseSpider()
{
scheduler.CancelGroup(PHASE_TROLL);
_phase = PHASE_SPIDER;
Talk(SAY_TRANSFORM);
DoCastSelf(SPELL_SPIDER_FORM, true);
me->ApplyStatPctModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, DamageIncrease);
scheduler.Schedule(5s, PHASE_SPIDER, [this](TaskContext context)
{
DoCastAOE(SPELL_ENVELOPING_WEB);
scheduler.Schedule(500ms, PHASE_SPIDER, [this](TaskContext)
{
_chargePlayer();
});
context.Repeat(15s, 20s);
}).Schedule(1s, PHASE_SPIDER, [this](TaskContext context)
{
DoCastVictim(SPELL_CORROSIVE_POISON);
context.Repeat(25s, 35s);
}).Schedule(5s, 10s, PHASE_SPIDER, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_POISON_SHOCK);
context.Repeat(10s);
});
// Transition to PHASE_TROLL
scheduler.Schedule(1min, PHASE_SPIDER, [this](TaskContext)
{
_schedulePhaseTroll();
});
}
void _chargePlayer()
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [this](Unit* target) -> bool
{
if (!target->IsPlayer() || 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);
}
}
};
// Spawn of Mar'li (15041)
struct npc_spawn_of_marli : public ScriptedAI
{
npc_spawn_of_marli(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
_scheduler.CancelAll();
}
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(4s, [this](TaskContext context)
{
if (context.GetRepeatCounter() < 5)
{
DoCastSelf(SPELL_GROWTH);
context.Repeat(4s);
}
else
{
Talk(EMOTE_FULL_GROWN);
DoCastSelf(SPELL_FULL_GROWN);
}
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
};
// Hatch Eggs (24083)
class spell_hatch_eggs : public SpellScript
{
PrepareSpellScript(spell_hatch_eggs);
void HandleObjectAreaTargetSelect(std::list& 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);
}
};
// Enveloping Webs (24110)
class spell_enveloping_webs : public SpellScript
{
PrepareSpellScript(spell_enveloping_webs);
void HandleOnHit()
{
Unit* caster = GetCaster();
Unit* hitUnit = GetHitUnit();
if (caster && hitUnit && hitUnit->IsPlayer())
{
caster->GetThreatMgr().ModifyThreatByPercent(hitUnit, -100);
}
}
void Register() override
{
OnHit += SpellHitFn(spell_enveloping_webs::HandleOnHit);
}
};
// Mar'li Transform (24084)
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()
{
RegisterCreatureAI(boss_marli);
RegisterCreatureAI(npc_spawn_of_marli);
RegisterSpellScript(spell_hatch_eggs);
RegisterSpellScript(spell_enveloping_webs);
RegisterSpellScript(spell_marli_transform);
}