mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-15 23:20:36 +01:00
Scripts/UB: Rework The Black Stalker (#28040)
This commit is contained in:
17
sql/updates/world/3.3.5/2022_06_20_01_world.sql
Normal file
17
sql/updates/world/3.3.5/2022_06_20_01_world.sql
Normal 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'");
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user