Core/Scripts: Implemented right Snobold Vassal behavior on Gormok fight. (#17934)

This commit is contained in:
Keader
2016-10-14 19:01:58 -03:00
committed by SnapperRy
parent 6dc0a9f04a
commit 8fb2dce017
2 changed files with 308 additions and 140 deletions

View File

@@ -0,0 +1,20 @@
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_gormok_ride_player','spell_gormok_jump_to_hand','spell_gormok_snobolled');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(66245,'spell_gormok_ride_player'),
(66342,'spell_gormok_jump_to_hand'),
(66406,'spell_gormok_snobolled');
DELETE FROM `disables` WHERE `sourceType`=0 AND `entry`=66636;
INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `params_0`, `params_1`, `comment`) VALUES
(0, 66636, 64, 0, 0, 'Disable LoS for Spell Rising Anger');
DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`=34796;
INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES
(34796, 46598, 0, 0);
DELETE FROM `vehicle_template_accessory` WHERE `entry`=34796 AND `accessory_entry`=34800;
INSERT INTO `vehicle_template_accessory` (`entry`, `accessory_entry`, `seat_id`, `minion`, `description`, `summontype`, `summontimer`) VALUES
(34796,34800,0,0,'Snobold Vassal', 5,0),
(34796,34800,1,0,'Snobold Vassal', 5,0),
(34796,34800,2,0,'Snobold Vassal', 5,0),
(34796,34800,3,0,'Snobold Vassal', 5,0);

View File

@@ -16,9 +16,6 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Known bugs:
// Gormok - Snobolled (creature at back)
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "trial_of_the_crusader.h"
@@ -71,14 +68,16 @@ enum BossSpells
//Gormok
SPELL_IMPALE = 66331,
SPELL_STAGGERING_STOMP = 67648,
SPELL_RISING_ANGER = 66636,
//Snobold
SPELL_RISING_ANGER = 66636,
SPELL_SNOBOLLED = 66406,
SPELL_BATTER = 66408,
SPELL_FIRE_BOMB = 66313,
SPELL_FIRE_BOMB_1 = 66317,
SPELL_FIRE_BOMB_DOT = 66318,
SPELL_HEAD_CRACK = 66407,
SPELL_JUMP_TO_HAND = 66342,
SPELL_RIDE_PLAYER = 66245,
//Acidmaw & Dreadscale Generic
SPELL_SWEEP = 66794,
@@ -117,38 +116,41 @@ enum BossSpells
enum MyActions
{
ACTION_ENABLE_FIRE_BOMB = 1,
ACTION_DISABLE_FIRE_BOMB = 2
ACTION_DISABLE_FIRE_BOMB = 2,
ACTION_ACTIVE_SNOBOLD = 3
};
enum Events
{
// Gormok
EVENT_IMPALE = 1,
EVENT_STAGGERING_STOMP = 2,
EVENT_THROW = 3,
EVENT_STAGGERING_STOMP,
EVENT_THROW,
// Snobold
EVENT_FIRE_BOMB = 4,
EVENT_BATTER = 5,
EVENT_HEAD_CRACK = 6,
EVENT_FIRE_BOMB,
EVENT_BATTER,
EVENT_HEAD_CRACK,
EVENT_SNOBOLLED,
EVENT_CHECK_MOUNT,
// Acidmaw & Dreadscale
EVENT_BITE = 7,
EVENT_SPEW = 8,
EVENT_SLIME_POOL = 9,
EVENT_SPIT = 10,
EVENT_SPRAY = 11,
EVENT_SWEEP = 12,
EVENT_SUBMERGE = 13,
EVENT_EMERGE = 14,
EVENT_SUMMON_ACIDMAW = 15,
EVENT_BITE,
EVENT_SPEW,
EVENT_SLIME_POOL,
EVENT_SPIT,
EVENT_SPRAY,
EVENT_SWEEP,
EVENT_SUBMERGE,
EVENT_EMERGE,
EVENT_SUMMON_ACIDMAW,
// Icehowl
EVENT_FEROCIOUS_BUTT = 16,
EVENT_MASSIVE_CRASH = 17,
EVENT_WHIRL = 18,
EVENT_ARCTIC_BREATH = 19,
EVENT_TRAMPLE = 20
EVENT_FEROCIOUS_BUTT,
EVENT_MASSIVE_CRASH,
EVENT_WHIRL,
EVENT_ARCTIC_BREATH,
EVENT_TRAMPLE
};
enum Phases
@@ -158,6 +160,13 @@ enum Phases
PHASE_SUBMERGED = 3
};
enum GormokMisc
{
DATA_NEW_TARGET = 1,
GORMOK_HAND_SEAT = 4,
PLAYER_VEHICLE_ID = 444,
};
class boss_gormok : public CreatureScript
{
public:
@@ -169,9 +178,9 @@ class boss_gormok : public CreatureScript
void Reset() override
{
events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS));
events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS);
events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS));
events.ScheduleEvent(EVENT_IMPALE, Seconds(8), Seconds(10));
events.ScheduleEvent(EVENT_STAGGERING_STOMP, Seconds(15));
events.ScheduleEvent(EVENT_THROW, Seconds(15), Seconds(30));
summons.DespawnAll();
}
@@ -216,18 +225,7 @@ class boss_gormok : public CreatureScript
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
me->SetInCombatWithZone();
instance->SetData(TYPE_NORTHREND_BEASTS, GORMOK_IN_PROGRESS);
for (uint8 i = 0; i < MAX_SNOBOLDS; i++)
{
if (Creature* pSnobold = DoSpawnCreature(NPC_SNOBOLD_VASSAL, 0, 0, 0, 0, TEMPSUMMON_CORPSE_DESPAWN, 0))
{
pSnobold->EnterVehicle(me, i);
pSnobold->SetInCombatWithZone();
pSnobold->AI()->DoAction(ACTION_ENABLE_FIRE_BOMB);
}
}
}
void DamageTaken(Unit* /*who*/, uint32& damage) override
@@ -235,8 +233,14 @@ class boss_gormok : public CreatureScript
// despawn the remaining passengers on death
if (damage >= me->GetHealth())
for (uint8 i = 0; i < MAX_SNOBOLDS; ++i)
if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i))
pSnobold->ToCreature()->DespawnOrUnsummon();
if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i))
snobold->ToCreature()->DespawnOrUnsummon();
}
void PassengerBoarded(Unit* who, int8 seatId, bool apply) override
{
if (apply && seatId == GORMOK_HAND_SEAT)
who->CastSpell(me, SPELL_RISING_ANGER, true);
}
void UpdateAI(uint32 diff) override
@@ -255,30 +259,28 @@ class boss_gormok : public CreatureScript
{
case EVENT_IMPALE:
DoCastVictim(SPELL_IMPALE);
events.ScheduleEvent(EVENT_IMPALE, urand(8*IN_MILLISECONDS, 10*IN_MILLISECONDS));
return;
events.Repeat(Seconds(8), Seconds(10));
break;
case EVENT_STAGGERING_STOMP:
DoCastVictim(SPELL_STAGGERING_STOMP);
events.ScheduleEvent(EVENT_STAGGERING_STOMP, 15*IN_MILLISECONDS);
return;
events.Repeat(Seconds(15));
break;
case EVENT_THROW:
for (uint8 i = 0; i < MAX_SNOBOLDS; ++i)
{
if (Unit* pSnobold = me->GetVehicleKit()->GetPassenger(i))
if (Unit* snobold = me->GetVehicleKit()->GetPassenger(i))
{
pSnobold->ExitVehicle();
pSnobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
pSnobold->ToCreature()->SetReactState(REACT_AGGRESSIVE);
pSnobold->ToCreature()->AI()->DoAction(ACTION_DISABLE_FIRE_BOMB);
pSnobold->CastSpell(me, SPELL_RISING_ANGER, true);
Talk(EMOTE_SNOBOLLED);
snobold->ExitVehicle();
snobold->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
snobold->GetAI()->DoAction(ACTION_DISABLE_FIRE_BOMB);
snobold->CastSpell(me, SPELL_JUMP_TO_HAND, true);
break;
}
}
events.ScheduleEvent(EVENT_THROW, urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS));
return;
events.Repeat(Seconds(15), Seconds(30));
break;
default:
return;
break;
}
}
@@ -292,6 +294,23 @@ class boss_gormok : public CreatureScript
}
};
class SnobolledTargetSelector : public std::unary_function<Unit*, bool>
{
public:
SnobolledTargetSelector(Unit const* /*unit*/) { }
bool operator()(Unit* unit) const
{
if (unit->GetTypeId() != TYPEID_PLAYER)
return false;
if (unit->HasAura(SPELL_RIDE_PLAYER) || unit->HasAura(SPELL_SNOBOLLED))
return false;
return true;
}
};
class npc_snobold_vassal : public CreatureScript
{
public:
@@ -299,59 +318,24 @@ class npc_snobold_vassal : public CreatureScript
struct npc_snobold_vassalAI : public ScriptedAI
{
npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature)
npc_snobold_vassalAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), _isActive(false)
{
_targetDied = false;
_instance = creature->GetInstanceScript();
_instance->SetData(DATA_SNOBOLD_COUNT, INCREASE);
SetCombatMovement(false);
}
void Reset() override
{
_events.ScheduleEvent(EVENT_BATTER, 5*IN_MILLISECONDS);
_events.ScheduleEvent(EVENT_HEAD_CRACK, 25*IN_MILLISECONDS);
_targetGUID.Clear();
_targetDied = false;
//Workaround for Snobold
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
}
void EnterCombat(Unit* who) override
{
_targetGUID = who->GetGUID();
me->TauntApply(who);
DoCast(who, SPELL_SNOBOLLED);
}
void DamageTaken(Unit* pDoneBy, uint32 &uiDamage) override
{
if (pDoneBy->GetGUID() == _targetGUID)
uiDamage = 0;
}
void MovementInform(uint32 type, uint32 pointId) override
{
if (type != POINT_MOTION_TYPE)
return;
switch (pointId)
{
case 0:
if (_targetDied)
me->DespawnOrUnsummon();
break;
default:
break;
}
me->SetInCombatWithZone();
_events.ScheduleEvent(EVENT_CHECK_MOUNT, Seconds(1));
_events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30));
}
void JustDied(Unit* /*killer*/) override
{
if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID))
if (target->IsAlive())
target->RemoveAurasDueToSpell(SPELL_SNOBOLLED);
target->RemoveAurasDueToSpell(SPELL_SNOBOLLED);
_instance->SetData(DATA_SNOBOLD_COUNT, DECREASE);
}
@@ -360,50 +344,69 @@ class npc_snobold_vassal : public CreatureScript
switch (action)
{
case ACTION_ENABLE_FIRE_BOMB:
_events.ScheduleEvent(EVENT_FIRE_BOMB, urand(5*IN_MILLISECONDS, 30*IN_MILLISECONDS));
_events.ScheduleEvent(EVENT_FIRE_BOMB, Seconds(5), Seconds(30));
break;
case ACTION_DISABLE_FIRE_BOMB:
_events.CancelEvent(EVENT_FIRE_BOMB);
break;
case ACTION_ACTIVE_SNOBOLD:
_isActive = true;
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
void SetGUID(ObjectGuid guid, int32 id) override
{
if (!UpdateVictim() || _targetDied)
if (id == DATA_NEW_TARGET)
if (Unit* target = ObjectAccessor::GetPlayer(*me, guid))
{
_targetGUID = guid;
AttackStart(target);
_events.ScheduleEvent(EVENT_BATTER, Seconds(5));
_events.ScheduleEvent(EVENT_HEAD_CRACK, Seconds(25));
_events.ScheduleEvent(EVENT_SNOBOLLED, Milliseconds(500));
}
}
void AttackStart(Unit* who) override
{
//Snobold only melee attack players that is your vehicle
if (!_isActive || who->GetGUID() != _targetGUID)
return;
if (Unit* target = ObjectAccessor::GetPlayer(*me, _targetGUID))
{
if (!target->IsAlive())
{
Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_GORMOK));
if (gormok && gormok->IsAlive())
{
SetCombatMovement(false);
_targetDied = true;
ScriptedAI::AttackStart(who);
}
// looping through Gormoks seats
for (uint8 i = 0; i < MAX_SNOBOLDS; i++)
{
if (!gormok->GetVehicleKit()->GetPassenger(i))
{
me->EnterVehicle(gormok, i);
DoAction(ACTION_ENABLE_FIRE_BOMB);
break;
}
}
}
else if (Unit* target2 = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true))
void MountOnBoss()
{
Unit* gormok = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(NPC_GORMOK));
if (gormok && gormok->IsAlive())
{
me->AttackStop();
_targetGUID.Clear();
_isActive = false;
_events.CancelEvent(EVENT_BATTER);
_events.CancelEvent(EVENT_HEAD_CRACK);
for (uint8 i = 0; i < MAX_SNOBOLDS; i++)
{
if (!gormok->GetVehicleKit()->GetPassenger(i))
{
_targetGUID = target2->GetGUID();
me->GetMotionMaster()->MoveJump(*target2, 15.0f, 15.0f);
me->EnterVehicle(gormok, i);
DoAction(ACTION_ENABLE_FIRE_BOMB);
break;
}
}
}
//Without Boss, snobolds should jump in another players
else if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(me)))
me->CastSpell(target, SPELL_RIDE_PLAYER, true);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
@@ -414,37 +417,47 @@ class npc_snobold_vassal : public CreatureScript
switch (eventId)
{
case EVENT_FIRE_BOMB:
if (me->GetVehicleBase())
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true))
me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_FIRE_BOMB, true);
_events.ScheduleEvent(EVENT_FIRE_BOMB, 20*IN_MILLISECONDS);
return;
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, -me->GetVehicleBase()->GetCombatReach(), true))
me->CastSpell(target, SPELL_FIRE_BOMB);
_events.Repeat(Seconds(20));
break;
case EVENT_HEAD_CRACK:
// commented out while SPELL_SNOBOLLED gets fixed
//if (Unit* target = ObjectAccessor::GetPlayer(*me, m_uiTargetGUID))
DoCastVictim(SPELL_HEAD_CRACK);
_events.ScheduleEvent(EVENT_HEAD_CRACK, 30*IN_MILLISECONDS);
return;
DoCast(me->GetVehicleBase(), SPELL_HEAD_CRACK);
_events.Repeat(Seconds(30));
break;
case EVENT_BATTER:
// commented out while SPELL_SNOBOLLED gets fixed
//if (Unit* target = ObjectAccessor::GetPlayer(*me, m_uiTargetGUID))
DoCastVictim(SPELL_BATTER);
_events.ScheduleEvent(EVENT_BATTER, 10*IN_MILLISECONDS);
return;
DoCast(me->GetVehicleBase(), SPELL_BATTER);
_events.Repeat(Seconds(10));
break;
case EVENT_SNOBOLLED:
DoCastAOE(SPELL_SNOBOLLED);
break;
case EVENT_CHECK_MOUNT:
if (!me->GetVehicleBase())
MountOnBoss();
_events.Repeat(Seconds(1));
break;
default:
return;
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
// do melee attack only when not on Gormoks back
if (!me->GetVehicleBase())
if (!UpdateVictim())
return;
// do melee attack only if is in player back.
if (_isActive)
DoMeleeAttackIfReady();
}
private:
EventMap _events;
InstanceScript* _instance;
ObjectGuid _targetGUID;
bool _targetDied;
bool _isActive;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -1145,6 +1158,138 @@ class boss_icehowl : public CreatureScript
}
};
class spell_gormok_jump_to_hand : public SpellScriptLoader
{
public:
spell_gormok_jump_to_hand() : SpellScriptLoader("spell_gormok_jump_to_hand") { }
class spell_gormok_jump_to_hand_AuraScript : public AuraScript
{
PrepareAuraScript(spell_gormok_jump_to_hand_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_RIDE_PLAYER))
return false;
return true;
}
bool Load() override
{
if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL)
return true;
return false;
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (Unit* caster = GetCaster())
{
if (CreatureAI* gormokAI = GetTarget()->ToCreature()->AI())
{
if (Unit* target = gormokAI->SelectTarget(SELECT_TARGET_RANDOM, 0, SnobolledTargetSelector(GetTarget())))
{
gormokAI->Talk(EMOTE_SNOBOLLED);
caster->GetAI()->DoAction(ACTION_ACTIVE_SNOBOLD);
caster->CastSpell(target, SPELL_RIDE_PLAYER, true);
}
}
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_jump_to_hand_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_gormok_jump_to_hand_AuraScript();
}
};
class spell_gormok_ride_player : public SpellScriptLoader
{
public:
spell_gormok_ride_player() : SpellScriptLoader("spell_gormok_ride_player") { }
class spell_gormok_ride_player_AuraScript : public AuraScript
{
PrepareAuraScript(spell_gormok_ride_player_AuraScript);
bool Load() override
{
if (GetCaster() && GetCaster()->GetEntry() == NPC_SNOBOLD_VASSAL)
return true;
return false;
}
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* target = GetTarget();
if (target->GetTypeId() != TYPEID_PLAYER || !target->IsInWorld())
return;
if (!target->CreateVehicleKit(PLAYER_VEHICLE_ID, 0))
return;
if (Unit *caster = GetCaster())
caster->GetAI()->SetGUID(target->GetGUID(), DATA_NEW_TARGET);
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetTarget()->RemoveVehicleKit();
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_gormok_ride_player_AuraScript::OnApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectRemoveFn(spell_gormok_ride_player_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_gormok_ride_player_AuraScript();
}
};
class spell_gormok_snobolled : public SpellScriptLoader
{
public:
spell_gormok_snobolled() : SpellScriptLoader("spell_gormok_snobolled") { }
class spell_gormok_snobolled_AuraScript : public AuraScript
{
PrepareAuraScript(spell_gormok_snobolled_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
if (!sSpellMgr->GetSpellInfo(SPELL_RIDE_PLAYER))
return false;
return true;
}
void OnPeriodic(AuraEffect const* /*aurEff*/)
{
if (!GetTarget()->HasAura(SPELL_RIDE_PLAYER))
Remove();
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_gormok_snobolled_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_gormok_snobolled_AuraScript();
}
};
class spell_jormungars_paralytic_toxin : public SpellScriptLoader
{
public:
@@ -1293,6 +1438,9 @@ void AddSC_boss_northrend_beasts()
new npc_snobold_vassal();
new npc_firebomb();
new spell_gormok_fire_bomb();
new spell_gormok_jump_to_hand();
new spell_gormok_ride_player();
new spell_gormok_snobolled();
new boss_acidmaw();
new boss_dreadscale();