/* * 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); }