Scripts/UB: Rework The Black Stalker (#28040)

This commit is contained in:
offl
2022-06-20 20:02:48 +03:00
committed by GitHub
parent 74ed066aa3
commit c025fcef74
2 changed files with 241 additions and 154 deletions

View File

@@ -0,0 +1,17 @@
--
DELETE FROM `spell_script_names` WHERE `ScriptName` IN (
'spell_the_black_stalker_levitate',
'spell_the_black_stalker_levitation_pulse',
'spell_the_black_stalker_someone_grab_me',
'spell_the_black_stalker_magnetic_pull',
'spell_the_black_stalker_summon_spore_strider');
INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
(31704,'spell_the_black_stalker_levitate'),
(31701,'spell_the_black_stalker_levitation_pulse'),
(31702,'spell_the_black_stalker_someone_grab_me'),
(31703,'spell_the_black_stalker_magnetic_pull'),
(38756,'spell_the_black_stalker_summon_spore_strider');
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` = 31702;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
(13,1,31702,0,0,31,0,3,17992,0,0,0,0,"","Group 0: Spell 'Someone Grab Me' (Effect 0) targets creature 'Coilfang Invisible Vacuum Dummy'");

View File

@@ -15,187 +15,257 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Boss_the_black_stalker
SD%Complete: 95
SDComment: Timers may be incorrect
SDCategory: Coilfang Resevoir, Underbog
EndScriptData */
#include "ScriptMgr.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "the_underbog.h"
/*
How levitation sequence works: boss casts Levitate and it triggers a chain of spells, target(any target, player or pet, any position in
threat list) eventually gets pulled towards by randomly selected trigger. Then target becomes protected from Pull Towards by Suspension
aura which is triggered every 1 sec up to 4 times. Since it has stun mechanic, diminishing returns cuts off its duration every cast in
half (20 > 10 > 5 > 0). Eventually player becomes immune to Suspension and vulnerable to another pull towards.
Whole levitate sequence is designed to pull player towards up to 3 times. Usually it works like this: player gets pulled towards,
gets protected by Suspension from Pull Towards next 2 times. If player is unlucky, boss can cast Levitate on same player again, in that case
player can be pulled towards 2 times in a row without any protection from fall damage by Suspension(case from sniffs).
However currently diminishing returns affects Suspension after first cast, its duration is 10 instead of 20 seconds and player will be
immune to 4th cast. That allows to pull player towards when levitation sequence ends. Levitation sequence has sensetive design and looks
like lack of delays between packets makes it work differently too.
Of course as was said above player can be pulled towards 2 times in a row but that looks like a rare case.
*/
enum Spells
{
SPELL_LEVITATE = 31704,
SPELL_SUSPENSION = 31719,
SPELL_LEVITATION_PULSE = 31701,
SPELL_MAGNETIC_PULL = 31705,
SPELL_CHAIN_LIGHTNING = 31717,
SPELL_STATIC_CHARGE = 31715,
SPELL_SUMMON_SPORE_STRIDER = 38755
SPELL_LEVITATE = 31704,
SPELL_CHAIN_LIGHTNING = 31717,
SPELL_STATIC_CHARGE = 31715, // Never seen any cast on retail, probably because of shared cooldown with Chain Lightning
SPELL_SUMMON_PLAYER = 20279, // NYI, may be 20311 or any other
SPELL_SUMMON_SPORE_STRIDER_SCRIPT = 38756,
SPELL_LEVITATION_PULSE = 31701,
SPELL_SOMEONE_GRAB_ME = 31702,
SPELL_MAGNETIC_PULL = 31703,
SPELL_SUSPENSION_PRIMER = 31720,
SPELL_SUSPENSION = 31719,
SPELL_SUMMON_SPORE_STRIDER = 38755
};
enum CreatureIdS
enum Events
{
ENTRY_SPORE_STRIDER = 22299
EVENT_LEASH_CHECK = 1,
EVENT_LEVITATE,
EVENT_CHAIN_LIGHTNING,
EVENT_STATIC_CHARGE,
EVENT_SUMMON_SPORE_STRIDER
};
class boss_the_black_stalker : public CreatureScript
struct boss_the_black_stalker : public ScriptedAI
{
public:
boss_the_black_stalker() : CreatureScript("boss_the_black_stalker") { }
boss_the_black_stalker(Creature* creature) : ScriptedAI(creature), _summons(creature) { }
CreatureAI* GetAI(Creature* creature) const override
void Reset() override
{
return GetTheUnderbogAI<boss_the_black_stalkerAI>(creature);
_events.Reset();
_summons.DespawnAll();
}
struct boss_the_black_stalkerAI : public ScriptedAI
void JustEngagedWith(Unit* /*who*/) override
{
boss_the_black_stalkerAI(Creature* creature) : ScriptedAI(creature), Striders(creature)
_events.ScheduleEvent(EVENT_LEASH_CHECK, 5s);
_events.ScheduleEvent(EVENT_LEVITATE, 8s, 18s);
_events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 0s, 3s);
_events.ScheduleEvent(EVENT_STATIC_CHARGE, 10s);
if (IsHeroic())
_events.ScheduleEvent(EVENT_SUMMON_SPORE_STRIDER, 20s, 30s);
}
void JustSummoned(Creature* summon) override
{
_summons.Summon(summon);
if (me->IsEngaged())
DoZoneInCombat(summon);
}
void JustDied(Unit* /*killer*/) override
{
_summons.DespawnAll();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = _events.ExecuteEvent())
{
Initialize();
InAir = false;
}
void Initialize()
{
Levitate_Timer = 12000;
ChainLightning_Timer = 6000;
StaticCharge_Timer = 10000;
SporeStriders_Timer = 10000 + rand32() % 5000;
check_Timer = 5000;
LevitatedTarget.Clear();
LevitatedTarget_Timer = 0;
}
uint32 SporeStriders_Timer;
uint32 Levitate_Timer;
uint32 ChainLightning_Timer;
uint32 StaticCharge_Timer;
ObjectGuid LevitatedTarget;
uint32 LevitatedTarget_Timer;
bool InAir;
uint32 check_Timer;
SummonList Striders;
void Reset() override
{
Initialize();
Striders.DespawnAll();
}
void JustEngagedWith(Unit* /*who*/) override { }
void JustSummoned(Creature* summon) override
{
if (summon && summon->GetEntry() == ENTRY_SPORE_STRIDER)
switch (eventId)
{
Striders.Summon(summon);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
summon->AI()->AttackStart(target);
else
if (me->GetVictim())
summon->AI()->AttackStart(me->GetVictim());
}
}
void JustDied(Unit* /*killer*/) override
{
Striders.DespawnAll();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
// Evade if too far
if (check_Timer <= diff)
{
float x, y, z, o;
me->GetHomePosition(x, y, z, o);
if (!me->IsWithinDist3d(x, y, z, 60))
case EVENT_LEASH_CHECK:
{
EnterEvadeMode();
return;
}
check_Timer = 1000;
} else check_Timer -= diff;
// Spore Striders
if (IsHeroic() && SporeStriders_Timer <= diff)
{
DoCast(me, SPELL_SUMMON_SPORE_STRIDER);
SporeStriders_Timer = 10000 + rand32() % 5000;
} else SporeStriders_Timer -= diff;
// Levitate
if (LevitatedTarget)
{
if (LevitatedTarget_Timer <= diff)
{
if (Unit* target = ObjectAccessor::GetUnit(*me, LevitatedTarget))
float x, y, z, o;
me->GetHomePosition(x, y, z, o);
if (!me->IsWithinDist3d(x, y, z, 60))
{
if (!target->HasAura(SPELL_LEVITATE))
{
LevitatedTarget.Clear();
return;
}
if (InAir)
{
target->AddAura(SPELL_SUSPENSION, target);
LevitatedTarget.Clear();
}
else
{
target->CastSpell(target, SPELL_MAGNETIC_PULL, true);
InAir = true;
LevitatedTarget_Timer = 1500;
}
EnterEvadeMode();
return;
}
else
LevitatedTarget.Clear();
} else LevitatedTarget_Timer -= diff;
}
if (Levitate_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
{
DoCast(target, SPELL_LEVITATE);
LevitatedTarget = target->GetGUID();
LevitatedTarget_Timer = 2000;
InAir = false;
_events.Repeat(1s);
break;
}
Levitate_Timer = 12000 + rand32() % 3000;
} else Levitate_Timer -= diff;
case EVENT_LEVITATE:
DoCastSelf(SPELL_LEVITATE);
_events.Repeat(18s, 24s);
break;
case EVENT_CHAIN_LIGHTNING:
DoCastVictim(SPELL_CHAIN_LIGHTNING);
_events.Repeat(6s, 12s);
break;
case EVENT_STATIC_CHARGE:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30, true))
DoCast(target, SPELL_STATIC_CHARGE);
_events.Repeat(10s);
break;
case EVENT_SUMMON_SPORE_STRIDER:
DoCastSelf(SPELL_SUMMON_SPORE_STRIDER_SCRIPT);
_events.Repeat(15s, 25s);
break;
default:
break;
}
// Chain Lightning
if (ChainLightning_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
DoCast(target, SPELL_CHAIN_LIGHTNING);
ChainLightning_Timer = 7000;
} else ChainLightning_Timer -= diff;
// Static Charge
if (StaticCharge_Timer <= diff)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30, true))
DoCast(target, SPELL_STATIC_CHARGE);
StaticCharge_Timer = 10000;
} else StaticCharge_Timer -= diff;
DoMeleeAttackIfReady();
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
};
DoMeleeAttackIfReady();
}
private:
EventMap _events;
SummonList _summons;
};
// 31704 - Levitate
class spell_the_black_stalker_levitate : public SpellScript
{
PrepareSpellScript(spell_the_black_stalker_levitate);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_LEVITATION_PULSE });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_LEVITATION_PULSE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_the_black_stalker_levitate::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 31701 - Levitation Pulse
class spell_the_black_stalker_levitation_pulse : public SpellScript
{
PrepareSpellScript(spell_the_black_stalker_levitation_pulse);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SOMEONE_GRAB_ME });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetCaster()->CastSpell(GetCaster(), SPELL_SOMEONE_GRAB_ME, true);
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_the_black_stalker_levitation_pulse::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 31702 - Someone Grab Me
class spell_the_black_stalker_someone_grab_me : public SpellScript
{
PrepareSpellScript(spell_the_black_stalker_someone_grab_me);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_MAGNETIC_PULL, SPELL_SUSPENSION });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (!GetCaster()->HasAura(SPELL_SUSPENSION))
GetHitUnit()->CastSpell(GetCaster(), SPELL_MAGNETIC_PULL);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_the_black_stalker_someone_grab_me::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 31703 - Magnetic Pull
class spell_the_black_stalker_magnetic_pull : public SpellScript
{
PrepareSpellScript(spell_the_black_stalker_magnetic_pull);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SUSPENSION_PRIMER });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUSPENSION_PRIMER, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_the_black_stalker_magnetic_pull::HandleScript, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 38756 - Summon Spore Strider
class spell_the_black_stalker_summon_spore_strider : public SpellScript
{
PrepareSpellScript(spell_the_black_stalker_summon_spore_strider);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SUMMON_SPORE_STRIDER });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
for (uint8 i = 0; i < 3; i++)
GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_SPORE_STRIDER, true);
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_the_black_stalker_summon_spore_strider::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_boss_the_black_stalker()
{
new boss_the_black_stalker();
RegisterTheUnderbogCreatureAI(boss_the_black_stalker);
RegisterSpellScript(spell_the_black_stalker_levitate);
RegisterSpellScript(spell_the_black_stalker_levitation_pulse);
RegisterSpellScript(spell_the_black_stalker_someone_grab_me);
RegisterSpellScript(spell_the_black_stalker_magnetic_pull);
RegisterSpellScript(spell_the_black_stalker_summon_spore_strider);
}