Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-06-16 10:04:30 -06:00
committed by GitHub
53 changed files with 1362 additions and 693 deletions

View File

@@ -339,7 +339,7 @@ struct boss_priestess_lackey_commonAI : public ScriptedAI
void EnterCombat(Unit* who) override
{
if (Creature* delrissa = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_DELRISSA)))
if (delrissa->IsAlive() && !delrissa->IsInCombat())
if (delrissa->IsAlive() && !delrissa->IsEngaged())
delrissa->AI()->AttackStart(who);
events.ScheduleEvent(EVENT_SPELL_HELPER_HEALING_POTION, 1000);

View File

@@ -783,37 +783,9 @@ public:
}
};
class spell_banging_the_gong : public SpellScriptLoader
{
public:
spell_banging_the_gong() : SpellScriptLoader("spell_banging_the_gong") { }
class spell_banging_the_gong_SpellScript : public SpellScript
{
PrepareSpellScript(spell_banging_the_gong_SpellScript);
void Activate(SpellEffIndex index)
{
PreventHitDefaultEffect(index);
GetHitGObj()->SendCustomAnim(0);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_banging_the_gong_SpellScript::Activate, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_banging_the_gong_SpellScript();
}
};
void AddSC_zulaman()
{
new npc_forest_frog();
new npc_zulaman_hostage();
new npc_harrison_jones();
new spell_banging_the_gong();
}

View File

@@ -32,7 +32,8 @@ enum Spells
SPELL_FROSTBREATH = 16099,
SPELL_MASSIVEGEYSER = 22421,
SPELL_SLAM = 24326,
SPELL_THRASH = 3417 // Triggers 3391
SPELL_THRASH = 3417, // Triggers 3391
SPELL_SPLASH = 24593
};
enum Events
@@ -42,6 +43,11 @@ enum Events
EVENT_SLAM = 3
};
enum Misc
{
GAMEOBJECT_MUDSKUNK_LURE = 180346
};
class boss_gahzranka : public CreatureScript
{
public:
@@ -51,6 +57,11 @@ public:
{
boss_gahzrankaAI(Creature* creature) : BossAI(creature, DATA_GAHZRANKA) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}
void Reset() override
{
_Reset();
@@ -147,8 +158,45 @@ private:
bool _wipeThreat = false;
};
class spell_pagles_point_cast : public SpellScript
{
PrepareSpellScript(spell_pagles_point_cast);
void OnEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
if (InstanceScript* instanceScript = caster->GetInstanceScript())
{
if (!instanceScript->GetData(DATA_GAHZRANKA))
{
caster->m_Events.AddEventAtOffset([caster]()
{
if (GameObject* lure = caster->SummonGameObject(GAMEOBJECT_MUDSKUNK_LURE, -11688.5f, -1737.74f, 10.409842f, 1.f, 0.f, 0.f, 0.f, 0.f, 30 * IN_MILLISECONDS))
{
caster->m_Events.AddEventAtOffset([caster, lure]()
{
if (lure)
lure->DespawnOrUnsummon();
caster->CastSpell(caster, SPELL_SPLASH, true);
caster->SummonCreature(NPC_GAHZRANKA, -11688.5f, -1723.74f, -5.78f, 0.f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5 * DAY * IN_MILLISECONDS);
}, 5s);
}
}, 2s);
}
}
}
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_pagles_point_cast::OnEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT);
}
};
void AddSC_boss_gahzranka()
{
new boss_gahzranka();
RegisterSpellScript(spell_gahzranka_slam);
RegisterSpellScript(spell_pagles_point_cast);
}

View File

@@ -24,19 +24,25 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "zulgurub.h"
enum Spells
{
SPELL_MANABURN = 26046,
SPELL_SLEEP = 24664
SPELL_SLEEP = 24664,
SPELL_EARTH_SHOCK = 24685,
SPELL_CHAIN_BURN = 24684,
SPELL_SUMMON_NIGHTMARE_ILLUSION_LEFT = 24681,
SPELL_SUMMON_NIGHTMARE_ILLUSION_BACK = 24728,
SPELL_SUMMON_NIGHTMARE_ILLUSION_RIGHT = 24729
};
enum Events
{
EVENT_MANABURN = 1,
EVENT_SLEEP = 2,
EVENT_ILLUSIONS = 3
EVENT_SLEEP = 1,
EVENT_EARTH_SHOCK = 2,
EVENT_CHAIN_BURN = 3,
EVENT_ILLUSIONS = 4
};
class boss_hazzarah : public CreatureScript
@@ -48,22 +54,42 @@ public:
{
boss_hazzarahAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
void Reset() override
void JustSummoned(Creature* summon) override
{
_Reset();
}
summons.Summon(summon);
void JustDied(Unit* /*killer*/) override
{
_JustDied();
summon->SetCorpseDelay(10);
summon->SetReactState(REACT_PASSIVE);
summon->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
summon->SetVisible(false);
summon->m_Events.AddEventAtOffset([summon]()
{
summon->SetVisible(true);
}, 2s);
summon->m_Events.AddEventAtOffset([summon]()
{
summon->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
summon->SetReactState(REACT_AGGRESSIVE);
summon->SetInCombatWithZone();
}, 3500ms);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_MANABURN, urand(4000, 10000));
events.ScheduleEvent(EVENT_SLEEP, urand(10000, 18000));
events.ScheduleEvent(EVENT_ILLUSIONS, urand(10000, 18000));
events.ScheduleEvent(EVENT_SLEEP, 12s, 15s);
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
}
bool CanAIAttack(Unit const* target) const override
{
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
return !target->HasAura(SPELL_SLEEP);
return true;
}
void UpdateAI(uint32 diff) override
@@ -80,27 +106,26 @@ public:
{
switch (eventId)
{
case EVENT_MANABURN:
DoCastVictim(SPELL_MANABURN, true);
events.ScheduleEvent(EVENT_MANABURN, urand(8000, 16000));
break;
case EVENT_SLEEP:
DoCastVictim(SPELL_SLEEP, true);
events.ScheduleEvent(EVENT_SLEEP, urand(12000, 20000));
events.ScheduleEvent(EVENT_SLEEP, 24s, 32s);
return;
case EVENT_EARTH_SHOCK:
DoCastVictim(SPELL_EARTH_SHOCK);
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
break;
case EVENT_CHAIN_BURN:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA; }))
{
DoCast(target, SPELL_CHAIN_BURN, false);
}
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
break;
case EVENT_ILLUSIONS:
// We will summon 3 illusions that will spawn on a random gamer and attack this gamer
// We will just use one model for the beginning
for (uint8 i = 0; i < 3; ++i)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
Creature* Illusion = me->SummonCreature(NPC_NIGHTMARE_ILLUSION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
if (Illusion)
Illusion->AI()->AttackStart(target);
}
}
events.ScheduleEvent(EVENT_ILLUSIONS, urand(15000, 25000));
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_LEFT, true);
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_BACK, true);
DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_RIGHT, true);
events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
break;
default:
break;
@@ -117,7 +142,28 @@ public:
}
};
class spell_chain_burn : public SpellScript
{
PrepareSpellScript(spell_chain_burn);
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject* target) -> bool
{
Unit* unit = target->ToUnit();
return !unit || unit->getPowerType() != POWER_MANA || caster->GetVictim() == unit;
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_chain_burn::FilterTargets, EFFECT_0, TARGET_UNIT_TARGET_ENEMY);
}
};
void AddSC_boss_hazzarah()
{
new boss_hazzarah();
RegisterSpellScript(spell_chain_burn);
}

View File

@@ -86,6 +86,23 @@ public:
Talk(SAY_AGGRO);
}
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
switch (summon->GetEntry())
{
case NPC_BRAIN_WASH_TOTEM:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
{
summon->CastSpell(target, summon->m_spells[0], true);
}
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())

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

@@ -28,13 +28,20 @@ EndScriptData */
enum Spells
{
SPELL_AMBUSH = 34794,
SPELL_THOUSANDBLADES = 34799
SPELL_VANISH = 24699,
SPELL_AMBUSH = 24337,
SPELL_GOUGE = 24698,
SPELL_THOUSAND_BLADES = 24649,
SPELL_THRASH = 3417,
SPELL_ENRAGE = 8269
};
enum Misc
enum Events
{
EQUIP_ID_MAIN_HAND = 0 //was item display id 31818, but this id does not exist
EVENT_VANISH = 1,
EVENT_AMBUSH = 2,
EVENT_GOUGE = 3,
EVENT_THOUSAND_BLADES = 4
};
class boss_renataki : public CreatureScript
@@ -46,36 +53,67 @@ public:
{
boss_renatakiAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
uint32 Invisible_Timer;
uint32 Ambush_Timer;
uint32 Visible_Timer;
uint32 Aggro_Timer;
uint32 ThousandBlades_Timer;
bool Invisible;
bool Ambushed;
void Reset() override
{
_Reset();
Invisible_Timer = urand(8000, 18000);
Ambush_Timer = 3000;
Visible_Timer = 4000;
Aggro_Timer = urand(15000, 25000);
ThousandBlades_Timer = urand(4000, 8000);
Invisible = false;
Ambushed = false;
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
me->SetReactState(REACT_AGGRESSIVE);
_enraged = false;
_thousandBladesCount = urand(2, 5);
_thousandBladesTargets.clear();
_dynamicFlags = me->GetDynamicFlags();
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_VANISH, 23s, 25s);
events.ScheduleEvent(EVENT_GOUGE, 5s, 10s);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 20s);
DoCastSelf(SPELL_THRASH, true);
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (!_enraged && HealthBelowPct(30))
{
me->TextEmote("%s becomes enraged", me, false);
DoCast(me, SPELL_ENRAGE);
_enraged = true;
}
}
bool CanAIAttack(Unit const* target) const override
{
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
return !target->HasAura(SPELL_GOUGE);
return true;
}
bool CanBeSeen(Player const* /*player*/) override
{
return me->GetReactState() == REACT_AGGRESSIVE;
}
bool CanSeeAlways(WorldObject const* obj) override
{
if (me->GetReactState() == REACT_PASSIVE)
{
return obj->ToCreature() && obj->ToCreature()->IsPet();
}
return false;
}
bool CanAlwaysBeDetectable(WorldObject const* seer) override
{
if (me->GetReactState() == REACT_PASSIVE)
{
return seer->ToCreature() && seer->ToCreature()->IsPet();
}
return false;
}
void UpdateAI(uint32 diff) override
@@ -83,86 +121,122 @@ public:
if (!UpdateVictim())
return;
//Invisible_Timer
if (Invisible_Timer <= diff)
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
me->InterruptSpell(CURRENT_GENERIC_SPELL);
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
me->SetDisplayId(11686);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
Invisible = true;
Invisible_Timer = urand(15000, 30000);
}
else Invisible_Timer -= diff;
if (Invisible)
{
if (Ambush_Timer <= diff)
switch (eventId)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (target)
case EVENT_VANISH:
me->SetReactState(REACT_PASSIVE);
_dynamicFlags = me->GetDynamicFlags();
me->RemoveDynamicFlag(UNIT_DYNFLAG_TRACK_UNIT);
DoCastSelf(SPELL_VANISH);
events.DelayEvents(5s);
events.ScheduleEvent(EVENT_AMBUSH, 5s);
events.ScheduleEvent(EVENT_VANISH, 38s, 45s);
return;
case EVENT_AMBUSH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
{
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
DoCast(target, SPELL_AMBUSH, true);
}
me->SetDynamicFlag(_dynamicFlags);
me->RemoveAurasDueToSpell(SPELL_VANISH);
me->SetReactState(REACT_AGGRESSIVE);
break;
case EVENT_GOUGE:
DoCastAOE(SPELL_GOUGE);
events.ScheduleEvent(EVENT_GOUGE, 10s, 15s);
return;
case EVENT_THOUSAND_BLADES:
{
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
DoCast(target, SPELL_AMBUSH);
}
if (_thousandBladesTargets.empty())
{
std::vector<Unit*> targetList;
ThreatContainer::StorageType const& threatlist = me->GetThreatMgr().getThreatList();
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
{
if (Unit* target = (*itr)->getTarget())
{
if (target->IsAlive() && target->IsWithinDist2d(me, 100.f))
{
targetList.push_back(target);
}
}
}
Ambushed = true;
Ambush_Timer = 3000;
if (!targetList.empty())
{
Acore::Containers::RandomShuffle(targetList);
// First get ranged targets
for (Unit* target : targetList)
{
if (!target->IsWithinMeleeRange(me))
{
_thousandBladesTargets.push_back(target);
}
}
if (_thousandBladesTargets.size() < _thousandBladesCount)
{
// if still not enough, get melee targets
for (Unit* target : targetList)
{
if (target->IsWithinMeleeRange(me))
{
_thousandBladesTargets.push_back(target);
}
}
}
if (!_thousandBladesTargets.empty())
{
Acore::Containers::RandomResize(_thousandBladesTargets, _thousandBladesCount);
}
}
}
if (!_thousandBladesTargets.empty())
{
std::vector<Unit*>::iterator itr = _thousandBladesTargets.begin();
std::advance(itr, urand(0, _thousandBladesTargets.size() - 1));
if (Unit* target = *itr)
{
DoCast(target, SPELL_THOUSAND_BLADES, false);
}
_thousandBladesTargets.erase(itr);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
}
else
{
_thousandBladesCount = urand(2, 5);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 22s);
}
break;
}
default:
break;
}
else Ambush_Timer -= diff;
}
if (Ambushed)
{
if (Visible_Timer <= diff)
{
me->InterruptSpell(CURRENT_GENERIC_SPELL);
me->SetDisplayId(15268);
SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
Invisible = false;
Visible_Timer = 4000;
}
else Visible_Timer -= diff;
}
//Resetting some aggro so he attacks other gamers
if (!Invisible)
{
if (Aggro_Timer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
if (DoGetThreat(me->GetVictim()))
{
DoModifyThreatPercent(me->GetVictim(), -50);
}
if (target)
{
AttackStart(target);
}
Aggro_Timer = urand(7000, 20000);
}
else Aggro_Timer -= diff;
if (ThousandBlades_Timer <= diff)
{
DoCastVictim(SPELL_THOUSANDBLADES);
ThousandBlades_Timer = urand(7000, 12000);
}
else ThousandBlades_Timer -= diff;
}
DoMeleeAttackIfReady();
if (me->GetReactState() == REACT_AGGRESSIVE)
DoMeleeAttackIfReady();
}
private:
bool _enraged;
uint32 _dynamicFlags;
uint8 _thousandBladesCount;
std::vector<Unit*> _thousandBladesTargets;
};
CreatureAI* GetAI(Creature* creature) const override

View File

@@ -22,6 +22,7 @@ SDComment: Missing reset function after killing a boss for Ohgan, Thekal.
SDCategory: Zul'Gurub
EndScriptData */
#include "GameObjectAI.h"
#include "InstanceScript.h"
#include "ScriptMgr.h"
#include "zulgurub.h"
@@ -36,7 +37,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 +51,7 @@ public:
instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map)
{
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
LoadObjectData(creatureData, nullptr);
}
@@ -71,7 +74,20 @@ public:
case NPC_HAKKAR:
_hakkarGUID = creature->GetGUID();
break;
case NPC_SPAWN_OF_MARLI:
if (Creature* marli = GetCreature(DATA_MARLI))
{
marli->AI()->JustSummoned(creature);
}
break;
case NPC_GAHZRANKA:
_gahzrankaGUID = creature->GetGUID();
break;
default:
break;
}
InstanceScript::OnCreatureCreate(creature);
}
void OnGameObjectCreate(GameObject* go) override
@@ -109,6 +125,16 @@ public:
return ObjectGuid::Empty;
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_GAHZRANKA)
{
return _gahzrankaGUID || GetBossState(DATA_GAHZRANKA) == DONE;
}
return 0;
}
std::string GetSaveData() override
{
OUT_SAVE_INST_DATA;
@@ -160,6 +186,7 @@ public:
ObjectGuid _arlokkGUID;
ObjectGuid _goGongOfBethekkGUID;
ObjectGuid _hakkarGUID;
ObjectGuid _gahzrankaGUID;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -168,7 +195,56 @@ public:
}
};
enum EdgeOfMadnessEnum
{
EVENT_EDGE_OF_MADNESS_GRILEK = 27,
EVENT_EDGE_OF_MADNESS_HAZZARAH = 28,
EVENT_EDGE_OF_MADNESS_RENATAKI = 29,
EVENT_EDGE_OF_MADNESS_WUSHOOLAY = 30
};
std::vector<std::pair<uint32, uint32>> BrazierOfMadnessContainer =
{
{ EVENT_EDGE_OF_MADNESS_GRILEK, NPC_GRILEK },
{ EVENT_EDGE_OF_MADNESS_HAZZARAH, NPC_HAZZARAH },
{ EVENT_EDGE_OF_MADNESS_RENATAKI, NPC_RENATAKI },
{ EVENT_EDGE_OF_MADNESS_WUSHOOLAY, NPC_WUSHOOLAY }
};
Position const edgeOfMagnessSummonPos = { -11901.229f, -1906.366f, 65.358f, 0.942f };
struct go_brazier_of_madness : public GameObjectAI
{
go_brazier_of_madness(GameObject* go) : GameObjectAI(go) { }
bool GossipHello(Player* /*player*/, bool reportUse) override
{
if (reportUse)
{
return true;
}
uint32 bossEntry = 0;
for (uint8 i = 0; i < 4; ++i)
{
if (sGameEventMgr->IsActiveEvent(BrazierOfMadnessContainer[i].first))
{
bossEntry = BrazierOfMadnessContainer[i].second;
break;
}
}
if (bossEntry)
{
me->SummonCreature(bossEntry, edgeOfMagnessSummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2 * HOUR * IN_MILLISECONDS);
}
return false;
}
};
void AddSC_instance_zulgurub()
{
new instance_zulgurub();
RegisterGameObjectAI(go_brazier_of_madness);
}

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,
@@ -59,7 +61,13 @@ enum CreatureIds
NPC_VILEBRANCH_SPEAKER = 11391, // Mandokir Event
NPC_CHAINED_SPIRIT = 15117, // Mandokir Event
NPC_HAKKAR = 14834,
NPC_ZULGURUB_TIGER = 11361
NPC_ZULGURUB_TIGER = 11361,
NPC_BRAIN_WASH_TOTEM = 15112,
NPC_GAHZRANKA = 15114,
NPC_GRILEK = 15082,
NPC_HAZZARAH = 15083,
NPC_RENATAKI = 15084,
NPC_WUSHOOLAY = 15085
};
enum GameobjectIds

View File

@@ -25,38 +25,9 @@ EndScriptData */
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "temple_of_ahnqiraj.h"
/*
* This is a 2 phases events. Here follows an explanation of the main events and transition between phases and sub-phases.
*
* The first phase is the EYE phase: the Eye of C'Thun is active and C'thun is not active.
* During this phase, the "Eye of C'Thun" alternates between 2 sub-phases:
* - PHASE_EYE_GREEN_BEAM:
* 50 sec phase during which the Eye mainly casts its Green Beam every 3 sec.
* - PHASE_EYE_RED_BEAM:
* 35 sec phase during which the Eye casts its red beam every sec.
* This EYE phase ends when the "Eye of C'Thun" is killed. Then starts the CTHUN phase.
*
* The second phase is the CTHUN phase. The Eye of C'Thun is not active and C'Thun is active.
* This phase starts with the transformation of the Eye into C'Thun (PHASE_CTHUN_TRANSITION).
* After the transformation, C'Thun alternates between 2 sub-phases:
* - PHASE_CTHUN_STOMACH:
* - C'Thun is almost insensible to all damage (99% damage reduction).
* - It spawns 2 tentacles in its stomach.
* - C'Thun swallows players.
* - This sub-phase ends when the 2 tentacles are killed. Swallowed players are regurgitate.
*
* - PHASE_CTHUN_WEAK:
* - weakened C'Thun takes normal damage.
* - This sub-phase ends after 45 secs.
*
* This CTHUN phase ends when C'Thun is killed
*
* Note:
* - the current phase is stored in the instance data to be easily shared between the eye and cthun.
*/
enum Phases
{
PHASE_NOT_STARTED = 0,
@@ -99,7 +70,7 @@ enum Spells
//SAME AS PHASE1
//Giant Claw Tentacles
SPELL_MASSIVE_GROUND_RUPTURE = 26100,
SPELL_MASSIVE_GROUND_RUPTURE = 26478,
//Also casts Hamstring
SPELL_THRASH = 3391,
@@ -111,6 +82,10 @@ enum Spells
SPELL_MOUTH_TENTACLE = 26332,
SPELL_EXIT_STOMACH_KNOCKBACK = 25383,
SPELL_DIGESTIVE_ACID = 26476,
// Tentacles
SPELL_SUBMERGE_VISUAL = 26234,
SPELL_BIRTH = 26262
};
enum Actions
@@ -142,6 +117,20 @@ const Position FleshTentaclePos[2] =
{ -8525.0f, 1994.0f, -98.0f, 2.12f},
};
class NotInStomachSelector
{
public:
NotInStomachSelector() { }
bool operator()(Unit* unit) const
{
if (unit->GetTypeId() != TYPEID_PLAYER || unit->HasAura(SPELL_DIGESTIVE_ACID))
return false;
return true;
}
};
//Kick out position
const Position KickPos = { -8545.0f, 1984.0f, -96.0f, 0.0f};
@@ -917,32 +906,40 @@ public:
{
eye_tentacleAI(Creature* creature) : ScriptedAI(creature)
{
if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
SetCombatMovement(false);
}
uint32 MindflayTimer;
uint32 KillSelfTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p);
}
}
void Reset() override
{
//Mind flay half a second after we spawn
MindflayTimer = 500;
_scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_GROUND_RUPTURE);
}).Schedule(5min, [this](TaskContext /*task*/)
{
me->DespawnOrUnsummon();
}).Schedule(1s, 5s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && u->GetTypeId() == TYPEID_PLAYER && !u->HasAura(SPELL_DIGESTIVE_ACID) && !u->HasAura(SPELL_MIND_FLAY); }))
{
DoCast(target, SPELL_MIND_FLAY);
}
//This prevents eyes from overlapping
KillSelfTimer = 35000;
context.Repeat(10s, 15s);
});
}
void EnterCombat(Unit* /*who*/) override
@@ -956,26 +953,12 @@ public:
if (!UpdateVictim())
return;
//KillSelfTimer
if (KillSelfTimer <= diff)
{
Unit::Kill(me, me);
return;
}
else KillSelfTimer -= diff;
//MindflayTimer
if (MindflayTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (target && !target->HasAura(SPELL_DIGESTIVE_ACID))
DoCast(target, SPELL_MIND_FLAY);
//Mindflay every 10 seconds
MindflayTimer = 10000;
}
else MindflayTimer -= diff;
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
};
};
@@ -995,35 +978,41 @@ public:
{
SetCombatMovement(false);
if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
}
uint32 GroundRuptureTimer;
uint32 HamstringTimer;
uint32 EvadeTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p);
}
}
void Reset() override
{
//First rupture should happen half a second after we spawn
GroundRuptureTimer = 500;
HamstringTimer = 2000;
EvadeTimer = 5000;
_scheduler.Schedule(Milliseconds(500), [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_GROUND_RUPTURE);
}).Schedule(Minutes(5), [this](TaskContext /*task*/)
{
me->DespawnOrUnsummon();
});
}
void EnterCombat(Unit* /*who*/) override
{
DoZoneInCombat();
_scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_HAMSTRING);
context.Repeat(5s);
});
}
void UpdateAI(uint32 diff) override
@@ -1032,62 +1021,14 @@ public:
if (!UpdateVictim())
return;
//EvadeTimer
if (!me->IsWithinMeleeRange(me->GetVictim()))
{
if (EvadeTimer <= diff)
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
Unit::Kill(p, p);
//Dissapear and reappear at new position
me->SetVisible(false);
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (!target)
{
Unit::Kill(me, me);
return;
}
if (!target->HasAura(SPELL_DIGESTIVE_ACID))
{
me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0);
if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
}
GroundRuptureTimer = 500;
HamstringTimer = 2000;
EvadeTimer = 5000;
AttackStart(target);
}
me->SetVisible(true);
}
else EvadeTimer -= diff;
}
//GroundRuptureTimer
if (GroundRuptureTimer <= diff)
{
DoCastVictim(SPELL_GROUND_RUPTURE);
GroundRuptureTimer = 30000;
}
else GroundRuptureTimer -= diff;
//HamstringTimer
if (HamstringTimer <= diff)
{
DoCastVictim(SPELL_HAMSTRING);
HamstringTimer = 5000;
}
else HamstringTimer -= diff;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
};
};
@@ -1107,37 +1048,112 @@ public:
{
SetCombatMovement(false);
if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
}
uint32 GroundRuptureTimer;
uint32 ThrashTimer;
uint32 HamstringTimer;
uint32 EvadeTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p);
}
}
void Reset() override
{
//First rupture should happen half a second after we spawn
GroundRuptureTimer = 500;
HamstringTimer = 2000;
ThrashTimer = 5000;
EvadeTimer = 5000;
_scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE);
});
}
void EnterCombat(Unit* /*who*/) override
{
DoZoneInCombat();
_scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_HAMSTRING);
context.Repeat(10s);
}).Schedule(5s, [this](TaskContext context) {
DoCastSelf(SPELL_THRASH);
context.Repeat(10s);
});
}
void ScheduleMeleeCheck()
{
// Check if a target is in melee range
_scheduler.Schedule(10s, [this](TaskContext task)
{
if (Unit* target = me->GetVictim())
{
if (!target->IsWithinMeleeRange(me))
{
// Main target not found within melee range, try to select a new one
if (Player* newTarget = me->SelectNearestPlayer(5.0f))
{
AttackStart(newTarget);
}
else // Main target not found, and failed to acquire a new target... Submerge
{
Submerge();
}
}
}
task.Repeat();
});
}
void Submerge()
{
if (me->SelectNearestPlayer(5.0f))
{
return;
}
// Despawn portal
if (Creature* p = ObjectAccessor::GetCreature(*me, _portalGUID))
{
p->DespawnOrUnsummon();
}
DoCastSelf(SPELL_SUBMERGE_VISUAL);
me->SetHealth(me->GetMaxHealth());
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
_scheduler.CancelAll();
_scheduler.Schedule(5s, [this](TaskContext /*task*/)
{
Emerge();
});
}
void Emerge()
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NotInStomachSelector()))
{
Position pos = target->GetPosition();
me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0);
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, pos, TEMPSUMMON_CORPSE_DESPAWN))
{
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL);
DoCastSelf(SPELL_BIRTH);
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE, true);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
ScheduleMeleeCheck();
}
}
void UpdateAI(uint32 diff) override
@@ -1146,70 +1162,14 @@ public:
if (!UpdateVictim())
return;
//EvadeTimer
if (!me->IsWithinMeleeRange(me->GetVictim()))
{
if (EvadeTimer <= diff)
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
Unit::Kill(p, p);
//Dissapear and reappear at new position
me->SetVisible(false);
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (!target)
{
Unit::Kill(me, me);
return;
}
if (!target->HasAura(SPELL_DIGESTIVE_ACID))
{
me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0);
if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
}
GroundRuptureTimer = 500;
HamstringTimer = 2000;
ThrashTimer = 5000;
EvadeTimer = 5000;
AttackStart(target);
}
me->SetVisible(true);
}
else EvadeTimer -= diff;
}
//GroundRuptureTimer
if (GroundRuptureTimer <= diff)
{
DoCastVictim(SPELL_GROUND_RUPTURE);
GroundRuptureTimer = 30000;
}
else GroundRuptureTimer -= diff;
//ThrashTimer
if (ThrashTimer <= diff)
{
DoCastVictim(SPELL_THRASH);
ThrashTimer = 10000;
}
else ThrashTimer -= diff;
//HamstringTimer
if (HamstringTimer <= diff)
{
DoCastVictim(SPELL_HAMSTRING);
HamstringTimer = 10000;
}
else HamstringTimer -= diff;
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
};
};
@@ -1229,26 +1189,34 @@ public:
{
SetCombatMovement(false);
if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
}
uint32 BeamTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p);
}
}
void Reset() override
{
//Green Beam half a second after we spawn
BeamTimer = 500;
_scheduler.Schedule(500ms, [this](TaskContext /*task*/)
{
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE);
}).Schedule(1s, 5s, [this](TaskContext context) {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
{
DoCast(target, SPELL_GREEN_BEAM);
}
context.Repeat(2100ms);
});
}
void EnterCombat(Unit* /*who*/) override
@@ -1262,18 +1230,12 @@ public:
if (!UpdateVictim())
return;
//BeamTimer
if (BeamTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (target && !target->HasAura(SPELL_DIGESTIVE_ACID))
DoCast(target, SPELL_GREEN_BEAM);
//Beam every 2 seconds
BeamTimer = 2100;
}
else BeamTimer -= diff;
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
};
};

View File

@@ -69,8 +69,6 @@ public:
{
if (p->GetZoneId() == me->GetZoneId())
{
p->RemoveAurasDueToSpell(SPELL_AURA_OF_FROST);
p->RemoveAurasDueToSpell(SPELL_CHILL);
p->RemoveAurasDueToSpell(SPELL_FROST_BREATH);
}

View File

@@ -738,48 +738,6 @@ class spell_gen_no_offhand_proc : public AuraScript
}
};
/* 71602 - Item - Icecrown 25 Normal Caster Trinket 1 Base
71645 - Item - Icecrown 25 Heroic Caster Trinket 1 Base
71845 - Item - Icecrown 25 Normal Caster Weapon Proc
71846 - Item - Icecrown 25 Heroic Caster Weapon Proc
72419 - Item - Icecrown Reputation Ring Healer Trigger
75465 - Item - Chamber of Aspects 25 Nuker Trinket
75474 - Item - Chamber of Aspects 25 Heroic Nuker Trinket */
class spell_gen_proc_once_per_cast : public AuraScript
{
PrepareAuraScript(spell_gen_proc_once_per_cast);
bool Load() override
{
_spellPointer = nullptr;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetActor())
{
if (Player* player = eventInfo.GetActor()->ToPlayer())
{
if (player->m_spellModTakingSpell == _spellPointer)
{
return false;
}
_spellPointer = player->m_spellModTakingSpell;
}
}
return true;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_gen_proc_once_per_cast::CheckProc);
}
private:
Spell* _spellPointer;
};
// 70805 - Item - Rogue T10 2P Bonus
class spell_gen_proc_on_self : public AuraScript
{
@@ -4545,7 +4503,6 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_use_spell_base_level_check);
RegisterSpellScript(spell_gen_proc_from_direct_damage);
RegisterSpellScript(spell_gen_no_offhand_proc);
RegisterSpellScript(spell_gen_proc_once_per_cast);
RegisterSpellScript(spell_gen_proc_on_self);
RegisterSpellScript(spell_gen_proc_not_self);
RegisterSpellScript(spell_gen_baby_murloc_passive);

View File

@@ -1208,6 +1208,27 @@ class spell_warl_drain_soul : public AuraScript
}
};
// 29341 - Shadowburn
class spell_warl_shadowburn : public AuraScript
{
PrepareAuraScript(spell_warl_shadowburn);
void RemoveEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
if (!(GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH && caster && target && caster->IsPlayer() && caster->ToPlayer()->isHonorOrXPTarget(target)))
{
PreventDefaultAction();
}
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_warl_shadowburn::RemoveEffect, EFFECT_0, SPELL_AURA_CHANNEL_DEATH_ITEM, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_warlock_spell_scripts()
{
RegisterSpellScript(spell_warl_eye_of_kilrogg);
@@ -1238,4 +1259,5 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_soulshatter);
RegisterSpellScript(spell_warl_unstable_affliction);
RegisterSpellScript(spell_warl_drain_soul);
RegisterSpellScript(spell_warl_shadowburn);
}

View File

@@ -302,9 +302,6 @@ public:
* ---
* --- Dragonspecific scripts and handling: LETHON
* ---
*
* @todo
* - Spell: Shadow bolt whirl casts needs custom handling (spellscript)
*/
enum LethonTexts
@@ -318,6 +315,14 @@ enum LethonSpells
SPELL_DRAW_SPIRIT = 24811,
SPELL_SHADOW_BOLT_WHIRL = 24834,
SPELL_DARK_OFFERING = 24804,
SPELL_SHADOW_BOLT_WHIRL1 = 24820,
SPELL_SHADOW_BOLT_WHIRL2 = 24821,
SPELL_SHADOW_BOLT_WHIRL3 = 24822,
SPELL_SHADOW_BOLT_WHIRL4 = 24823,
SPELL_SHADOW_BOLT_WHIRL5 = 24835,
SPELL_SHADOW_BOLT_WHIRL6 = 24836,
SPELL_SHADOW_BOLT_WHIRL7 = 24837,
SPELL_SHADOW_BOLT_WHIRL8 = 24838,
};
enum LethonCreatures
@@ -340,13 +345,14 @@ public:
{
_stage = 1;
emerald_dragonAI::Reset();
events.ScheduleEvent(EVENT_SHADOW_BOLT_WHIRL, 10000);
me->RemoveAurasDueToSpell(SPELL_SHADOW_BOLT_WHIRL);
}
void EnterCombat(Unit* who) override
{
Talk(SAY_LETHON_AGGRO);
WorldBossAI::EnterCombat(who);
DoCastSelf(SPELL_SHADOW_BOLT_WHIRL, true);
}
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
@@ -368,20 +374,6 @@ public:
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_SHADOW_BOLT_WHIRL:
me->CastSpell((Unit*)nullptr, SPELL_SHADOW_BOLT_WHIRL, false);
events.ScheduleEvent(EVENT_SHADOW_BOLT_WHIRL, urand(15000, 30000));
break;
default:
emerald_dragonAI::ExecuteEvent(eventId);
break;
}
}
private:
uint8 _stage;
};
@@ -712,6 +704,41 @@ public:
}
};
class spell_shadow_bolt_whirl : public AuraScript
{
PrepareAuraScript(spell_shadow_bolt_whirl);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHADOW_BOLT_WHIRL1, SPELL_SHADOW_BOLT_WHIRL2, SPELL_SHADOW_BOLT_WHIRL3, SPELL_SHADOW_BOLT_WHIRL4, SPELL_SHADOW_BOLT_WHIRL5, SPELL_SHADOW_BOLT_WHIRL6, SPELL_SHADOW_BOLT_WHIRL7, SPELL_SHADOW_BOLT_WHIRL8 });
}
void HandlePeriodic(AuraEffect const* aurEff)
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
if (!caster || !target)
return;
std::array<uint32, 8> spellForTick = { SPELL_SHADOW_BOLT_WHIRL1, SPELL_SHADOW_BOLT_WHIRL2, SPELL_SHADOW_BOLT_WHIRL3, SPELL_SHADOW_BOLT_WHIRL4, SPELL_SHADOW_BOLT_WHIRL5, SPELL_SHADOW_BOLT_WHIRL6, SPELL_SHADOW_BOLT_WHIRL7, SPELL_SHADOW_BOLT_WHIRL8 };
uint32 tick = (aurEff->GetTickNumber() + 7/*-1*/) % 8;
// casted in left/right (but triggered spell have wide forward cone)
float forward = target->GetOrientation();
if (tick <= 3)
target->SetOrientation(forward + 0.75f * M_PI - tick * M_PI / 8); // Left
else
target->SetOrientation(forward - 0.75f * M_PI + (8 - tick) * M_PI / 8); // Right
target->CastSpell(target, spellForTick[tick], true);
target->SetOrientation(forward);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadow_bolt_whirl::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_mark_of_nature : public SpellScriptLoader
{
public:
@@ -765,4 +792,5 @@ void AddSC_emerald_dragons()
// dragon spellscripts
new spell_dream_fog_sleep();
new spell_mark_of_nature();
RegisterSpellScript(spell_shadow_bolt_whirl);
};