diff --git a/src/server/scripts/EasternKingdoms/Deadmines/boss_helix_gearbreaker.cpp b/src/server/scripts/EasternKingdoms/Deadmines/boss_helix_gearbreaker.cpp index 18fb46baefe..4eb5feb4512 100644 --- a/src/server/scripts/EasternKingdoms/Deadmines/boss_helix_gearbreaker.cpp +++ b/src/server/scripts/EasternKingdoms/Deadmines/boss_helix_gearbreaker.cpp @@ -75,55 +75,44 @@ enum Spells SPELL_ARMING_VISUAL_RED = 88317, SPELL_STICKY_BOMB_ARMED_STATE = 88319, SPELL_STICKY_BOMB_PERIODIC_TRIGGER = 88329, - SPELL_EXPLODE = 88974 -}; - -uint32 const BombArmingVisualSpells[] = -{ - SPELL_ARMING_VISUAL_YELLOW, - SPELL_ARMING_VISUAL_ORANGE, - SPELL_ARMING_VISUAL_RED + SPELL_EXPLODE = 88974, }; enum DisplayIds { - DISPLAY_ID_BOMB_INVISIBLE = 11686 + DISPLAY_ID_BOMB_INVISIBLE = 11686, }; enum Events { // Helix Gearbreaker - EVENT_SUMMON_HELIX_CREW = 1, - EVENT_STICKY_BOMB, + EVENT_STICKY_BOMB = 1, EVENT_OAF_SMASH, EVENT_THROW_HELIX, EVENT_RIDE_FACE, // Lumbering Oaf - EVENT_PREPARE_OAF_SMASH, - EVENT_OAF_SMASH_CHARGE, + EVENT_MOVE_TO_PREPARE_POSITION, + EVENT_CHARGE_DEST, // Sticky Bomb - EVENT_ARM_BOMB, + EVENT_ARMING_VISUAL_YELLOW, + EVENT_ARMING_VISUAL_ORANGE, + EVENT_ARMING_VISUAL_RED, + EVENT_PREPARED_STATE, EVENT_PERIODIC_TRIGGER, EVENT_EXPLOSION_COUNTDOWN, + EVENT_COUNTDOWN, // Helix' Crew - EVENT_THROW_BOMB, - EVENT_TALK_READY + EVENT_TALK_READY, }; enum Actions { - // Lumbering Oaf ACTION_OAF_SMASH = 1, ACTION_OAF_DEAD, - - // Helix' Crw ACTION_TALK_CREW, - - // Sticky Bomb - ACTION_BOMB_DETONATED, }; enum Points @@ -137,12 +126,10 @@ enum Phases PHASE_2 = 2 }; -Position const LumberingOafSummonPosition = { -302.3611f, -516.3455f, 52.03153f, 0.1745329f }; -Position const OafSmashStartigPosition = { -289.8343f, -526.2162f, 49.83808f }; -Position const ChargePos = { -289.5868f, -489.5746f, 49.91263f }; +Position const ChargePreparationPos = { -289.8343f, -526.2162f, 49.83808f }; +Position const ChargePos = { -289.5868f, -489.5746f, 49.91263f }; -static constexpr uint8 const HelixCrewPositionCount = 4; -Position const HelixFirstCrewPositions[HelixCrewPositionCount] = +Position const HelixCrewPositions[] = { { -283.8438f, -503.3698f, 60.512f, 1.902409f }, { -285.8681f, -503.8264f, 60.55348f, 5.009095f }, @@ -150,459 +137,576 @@ Position const HelixFirstCrewPositions[HelixCrewPositionCount] = { -289.8316f, -503.4063f, 60.36356f, 1.815142f } }; -struct boss_helix_gearbreaker : public BossAI +class boss_helix_gearbreaker : public CreatureScript { - boss_helix_gearbreaker(Creature* creature) : BossAI(creature, DATA_HELIX_GEARBREAKER) - { - me->SetReactState(REACT_PASSIVE); - } + public: + boss_helix_gearbreaker() : CreatureScript("boss_helix_gearbreaker") { } - void JustEngagedWith(Unit* /*who*/) override - { - _JustEngagedWith(); - Talk(SAY_AGGRO); - instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 2); - - events.SetPhase(PHASE_1); - if (IsHeroic()) - events.ScheduleEvent(EVENT_SUMMON_HELIX_CREW, 5s, 0, PHASE_1); - - events.ScheduleEvent(EVENT_STICKY_BOMB, 6s, 0, PHASE_1); - events.ScheduleEvent(EVENT_OAF_SMASH, 17s, 0, PHASE_1); - - /* - events.ScheduleEvent(EVENT_THROW_HELIX, Seconds(34), 0, PHASE_1); - */ - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - Talk(SAY_DEATH); - summons.DespawnAll(); - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - } - - void JustAppeared() override - { - DoCastSelf(SPELL_OAFGUARD); - DoSummon(NPC_LUMBERING_OAF, LumberingOafSummonPosition, 2 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN); - } - - void KilledUnit(Unit* who) override - { - if (who->GetTypeId() == TYPEID_PLAYER) - Talk(SAY_SLAY); - } - - void EnterEvadeMode(EvadeReason /*why*/) override - { - _EnterEvadeMode(); - - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - if (Creature* lumberingOaf = instance->GetCreature(DATA_LUMBERING_OAF)) - if (lumberingOaf->IsAlive()) - instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, lumberingOaf); - - summons.DespawnAll(); - _DespawnAtEvade(); - } - - void DoAction(int32 action) override - { - switch (action) + struct boss_helix_gearbreakerAI : public BossAI { - case ACTION_OAF_DEAD: - Talk(SAY_OAF_DEAD); - DoCastSelf(SPELL_EMOTE_TALK); - me->SetReactState(REACT_AGGRESSIVE); - me->RemoveAurasDueToSpell(SPELL_OAFGUARD); - events.SetPhase(PHASE_2); - if (!me->GetVehicleBase()) - events.ScheduleEvent(EVENT_RIDE_FACE, Seconds(2) + Milliseconds(500), 0, PHASE_2); - break; - default: - break; - } - } - - void DamageTaken(Unit* /*attacker*/, uint32& damage) override - { - // Helix cannot die while he is protected by his Lumbering Oaf - if (damage >= me->GetHealth() && me->HasAura(SPELL_OAFGUARD)) - damage = me->GetHealth() - 1; - } - - 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) + boss_helix_gearbreakerAI(Creature* creature) : BossAI(creature, DATA_HELIX_GEARBREAKER) { - - case EVENT_SUMMON_HELIX_CREW: - for (uint8 i = 0; i < HelixCrewPositionCount; i++) - { - if (Creature* crew = DoSummon(NPC_HELIX_CREW, HelixFirstCrewPositions[i], 0, TEMPSUMMON_MANUAL_DESPAWN)) - if (!i && crew->IsAIEnabled) - crew->AI()->DoAction(ACTION_TALK_CREW); - } - break; - case EVENT_STICKY_BOMB: - DoCastAOE(SPELL_THROW_BOMB_TARGETING); - events.Repeat(3s + 500ms); - break; - case EVENT_OAF_SMASH: - if (Creature* oaf = instance->GetCreature(DATA_LUMBERING_OAF)) - if (oaf->IsAIEnabled) - oaf->AI()->DoAction(ACTION_OAF_SMASH); - - events.RescheduleEvent(EVENT_STICKY_BOMB, 11s, 0, PHASE_1); - events.Repeat(52s); - break; - - case EVENT_THROW_HELIX: - Talk(SAY_THROW_HELIX); - events.ScheduleEvent(EVENT_RIDE_FACE, Seconds(2)); - events.Repeat(Seconds(52)); - break; - case EVENT_RIDE_FACE: - DoCastAOE(SPELL_RIDE_FACE_TARGETING, true); - events.RescheduleEvent(EVENT_STICKY_BOMB, Seconds(20), 0, PHASE_1); - break; - default: - break; + Initialize(); } - } - DoMeleeAttackIfReady(); - } -}; - -struct npc_helix_lumbering_oaf : public ScriptedAI -{ - npc_helix_lumbering_oaf(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - - void JustEngagedWith(Unit* /*who*/) override - { - _instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1); - - if (Creature* helix = _instance->GetCreature(DATA_HELIX_GEARBREAKER)) - if (helix->IsAIEnabled) - helix->AI()->DoZoneInCombat(); - } - - void JustAppeared() override - { - if (Creature* helix = _instance->GetCreature(DATA_HELIX_GEARBREAKER)) - helix->EnterVehicle(me); - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_OAF_SMASH: - DoCastAOE(SPELL_OAF_GRAB_TARGETING); - break; - default: - break; - } - } - - void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override - { - if (!passenger) - return; - - if (apply && passenger->GetTypeId() == TYPEID_PLAYER) - { - Talk(SAY_OAF_SMASH_1); - me->AttackStop(); - me->SetReactState(REACT_PASSIVE); - _events.ScheduleEvent(EVENT_PREPARE_OAF_SMASH, 1s); - } - - /* - if (!apply && passenger->GetEntry() == BOSS_HELIX_GEARBREAKER && me->IsInCombat()) - _instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, passenger); - else if (apply && passenger->GetEntry() == BOSS_HELIX_GEARBREAKER && me->IsInCombat()) - _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, passenger); - */ - } - - void MovementInform(uint32 type, uint32 point) override - { - if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) - return; - - switch (point) - { - case POINT_CHARGE_PREP: - me->SetFacingTo(1.570796f); - _events.ScheduleEvent(EVENT_OAF_SMASH_CHARGE, 1s); - break; - default: - break; - } - } - - void JustDied(Unit* /*killer*/) override - { - _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); - if (Creature* helix = _instance->GetCreature(DATA_HELIX_GEARBREAKER)) - helix->AI()->DoAction(ACTION_OAF_DEAD); - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) + void Initialize() { - case EVENT_PREPARE_OAF_SMASH: - Talk(SAY_OAF_SMASH_2); - me->GetMotionMaster()->MovePoint(POINT_CHARGE_PREP, OafSmashStartigPosition, true); - break; - case EVENT_OAF_SMASH_CHARGE: - DoCastAOE(SPELL_CHARGE); - break; - default: - break; + _crewSummoned = false; } - } - DoMeleeAttackIfReady(); - } -private: - EventMap _events; - InstanceScript* _instance; -}; -struct npc_helix_sticky_bomb : public NullCreatureAI -{ - npc_helix_sticky_bomb(Creature* creature) : NullCreatureAI(creature), _countdown(0) { } - - void Reset() override - { - _events.ScheduleEvent(EVENT_ARM_BOMB, 2s); - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_BOMB_DETONATED: - me->SetDisplayId(DISPLAY_ID_BOMB_INVISIBLE); - me->RemoveAllAuras(); - me->DespawnOrUnsummon(2s + 500ms); - _events.Reset(); - break; - default: - break; - } - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) + void Reset() override { - case EVENT_ARM_BOMB: - if (_countdown < 3) - { - DoCastSelf(BombArmingVisualSpells[_countdown]); - _events.Repeat(1s); - _countdown++; - } - else - { - DoCastSelf(SPELL_STICKY_BOMB_ARMED_STATE); - _events.ScheduleEvent(EVENT_PERIODIC_TRIGGER, 1s); - } - break; - case EVENT_PERIODIC_TRIGGER: - DoCastSelf(SPELL_STICKY_BOMB_PERIODIC_TRIGGER); - _events.ScheduleEvent(EVENT_EXPLOSION_COUNTDOWN, 15s + 500ms); - break; - case EVENT_EXPLOSION_COUNTDOWN: - if (_countdown) + _Reset(); + Initialize(); + } + + void JustEngagedWith(Unit* /*who*/) override + { + _JustEngagedWith(); + Talk(SAY_AGGRO); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + + if (Creature* lumberingOaf = instance->GetCreature(DATA_LUMBERING_OAF)) + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, lumberingOaf); + + events.SetPhase(PHASE_1); + events.ScheduleEvent(EVENT_STICKY_BOMB, Seconds(5), 0, PHASE_1); + events.ScheduleEvent(EVENT_OAF_SMASH, Seconds(16), 0, PHASE_1); + events.ScheduleEvent(EVENT_THROW_HELIX, Seconds(34), 0, PHASE_1); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + Talk(SAY_DEATH); + summons.DespawnAll(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + summons.DespawnAll(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (Creature* lumberingOaf = instance->GetCreature(DATA_LUMBERING_OAF)) { - DoCastSelf(SPELL_ARMING_VISUAL_RED); - _events.Repeat(1s); - _countdown--; + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, lumberingOaf); + lumberingOaf->DespawnOrUnsummon(0, Seconds(30)); } - else + me->DespawnOrUnsummon(); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + } + + void DoAction(int32 action) override + { + switch (action) { - DoCastSelf(SPELL_EXPLODE); - DoAction(ACTION_BOMB_DETONATED); + case ACTION_OAF_DEAD: + Talk(SAY_OAF_DEAD); + DoCastSelf(SPELL_EMOTE_TALK); + me->SetReactState(REACT_AGGRESSIVE); + me->RemoveAurasDueToSpell(SPELL_OAFGUARD); + events.SetPhase(PHASE_2); + if (!me->GetVehicleBase()) + events.ScheduleEvent(EVENT_RIDE_FACE, Seconds(2) + Milliseconds(500), 0, PHASE_2); + break; + default: + break; } - break; - default: - break; } - } - } -private: - EventMap _events; - uint8 _countdown; -}; -struct npc_helix_crew : public PassiveAI -{ - npc_helix_crew(Creature* creature) : PassiveAI(creature) { } - - void IsSummonedBy(Unit* /*summoner*/) override - { - _events.ScheduleEvent(EVENT_THROW_BOMB, 1s); - } - - void DoAction(int32 action) override - { - switch (action) - { - case ACTION_TALK_CREW: - _events.ScheduleEvent(EVENT_TALK_READY, 1s); - break; - default: - break; - } - } - - void UpdateAI(uint32 diff) override - { - _events.Update(diff); - - while (uint32 eventId = _events.ExecuteEvent()) - { - switch (eventId) + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - case EVENT_THROW_BOMB: - DoCastAOE(SPELL_THROW_BOMB_TARGETING); - _events.Repeat(5s); - break; - case EVENT_TALK_READY: - Talk(SAY_CREW_JOIN_FIGHT); - break; - default: - break; + if (damage >= me->GetHealth() && me->HasAura(SPELL_OAFGUARD)) + damage = me->GetHealth() - 1; } - } - } -private: - EventMap _events; -}; -class spell_helix_throw_bomb_targeting : public SpellScript -{ - PrepareSpellScript(spell_helix_throw_bomb_targeting); - - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; - - Trinity::Containers::RandomResize(targets, 1); - } - - void HandleHit(SpellEffIndex effIndex) - { - if (Unit* caster = GetCaster()) - caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_helix_throw_bomb_targeting::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_helix_throw_bomb_targeting::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); - } -}; - -class spell_helix_sticky_bomb_periodic_trigger : public AuraScript -{ - PrepareAuraScript(spell_helix_sticky_bomb_periodic_trigger); - - void HandleTick(AuraEffect const* /*aurEff*/) - { - PreventDefaultAction(); - Creature* target = GetTarget()->ToCreature(); - if (!target || !target->IsAIEnabled) - return; - - SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell); - if (!spell) - return; - - if (Player* player = target->SelectNearestPlayer(spell->Effects[EFFECT_0].CalcRadius())) - { - if (!player->GetVehicleBase() && player->GetExactDist(target) <= 1.0f) + void UpdateAI(uint32 diff) override { - target->CastSpell(target, spell->Id, true); - target->AI()->DoAction(ACTION_BOMB_DETONATED); + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STICKY_BOMB: + if (!_crewSummoned && IsHeroic()) + { + for (uint8 i = 0; i < 4; i++) + { + if (Creature* crew = DoSummon(NPC_HELIX_CREW, HelixCrewPositions[i], 0, TEMPSUMMON_MANUAL_DESPAWN)) + if (i == 1) + crew->AI()->DoAction(ACTION_TALK_CREW); + } + _crewSummoned = true; + } + + DoCastAOE(SPELL_THROW_BOMB_TARGETING, true); + events.Repeat(Seconds(3) + Milliseconds(500)); + break; + case EVENT_OAF_SMASH: + if (Creature* lumberingOaf = me->GetVehicleCreatureBase()) + { + lumberingOaf->AI()->DoAction(ACTION_OAF_SMASH); + events.RescheduleEvent(EVENT_STICKY_BOMB, Seconds(10), 0, PHASE_1); + events.Repeat(Seconds(52)); + } + break; + case EVENT_THROW_HELIX: + Talk(SAY_THROW_HELIX); + events.ScheduleEvent(EVENT_RIDE_FACE, Seconds(2)); + events.Repeat(Seconds(52)); + break; + case EVENT_RIDE_FACE: + DoCastAOE(SPELL_RIDE_FACE_TARGETING, true); + events.RescheduleEvent(EVENT_STICKY_BOMB, Seconds(20), 0, PHASE_1); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); } + private: + bool _crewSummoned; + }; + + CreatureAI* GetAI(Creature *creature) const override + { + return GetDeadminesAI(creature); } - } - - void Register() override - { - OnEffectPeriodic += AuraEffectPeriodicFn(spell_helix_sticky_bomb_periodic_trigger::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); - } }; -class spell_helix_oaf_grab_targeting : public SpellScript +class npc_helix_lumbering_oaf : public CreatureScript { - PrepareSpellScript(spell_helix_oaf_grab_targeting); + public: + npc_helix_lumbering_oaf() : CreatureScript("npc_helix_lumbering_oaf") { } - void FilterTargets(std::list& targets) - { - if (targets.empty()) - return; + struct npc_helix_lumbering_oafAI : public ScriptedAI + { + npc_helix_lumbering_oafAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()) { } - Trinity::Containers::RandomResize(targets, 1); - } + void JustEngagedWith(Unit* who) override + { + if (Creature* helix = _instance->GetCreature(DATA_HELIX_GEARBREAKER)) + if (!helix->IsInCombat()) + helix->AI()->AttackStart(who); + } - void HandleHit(SpellEffIndex effIndex) - { - if (Unit* caster = GetCaster()) - caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); - } + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_OAF_SMASH: + Talk(SAY_OAF_SMASH_1); + DoCastAOE(SPELL_OAF_GRAB_TARGETING, true); + break; + default: + break; + } + } - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_helix_oaf_grab_targeting::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); - OnEffectHitTarget += SpellEffectFn(spell_helix_oaf_grab_targeting::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); - } + void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override + { + if (!passenger) + return; + + if (apply && passenger->GetTypeId() == TYPEID_PLAYER) + { + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + _events.ScheduleEvent(EVENT_MOVE_TO_PREPARE_POSITION, Milliseconds(500)); + } + + if (!apply && passenger->GetEntry() == BOSS_HELIX_GEARBREAKER && me->IsInCombat()) + _instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, passenger); + else if (apply && passenger->GetEntry() == BOSS_HELIX_GEARBREAKER && me->IsInCombat()) + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, passenger); + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (point) + { + case POINT_CHARGE_PREP: + me->SetFacingTo(1.570796f); + _events.ScheduleEvent(EVENT_CHARGE_DEST, Seconds(1)); + break; + default: + break; + } + } + + void JustDied(Unit* /*killer*/) override + { + _instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + if (Creature* helix = _instance->GetCreature(DATA_HELIX_GEARBREAKER)) + helix->AI()->DoAction(ACTION_OAF_DEAD); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MOVE_TO_PREPARE_POSITION: + Talk(SAY_OAF_SMASH_2); + me->GetMotionMaster()->MovePoint(POINT_CHARGE_PREP, ChargePreparationPos, true); + break; + case EVENT_CHARGE_DEST: + DoCastAOE(SPELL_CHARGE); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetDeadminesAI(creature); + } }; -class spell_helix_force_player_to_ride_oaf : public SpellScript +class npc_helix_sticky_bomb : public CreatureScript { - PrepareSpellScript(spell_helix_force_player_to_ride_oaf); + public: + npc_helix_sticky_bomb() : CreatureScript("npc_helix_sticky_bomb") { } - void HandleHit(SpellEffIndex effIndex) - { - if (Unit* caster = GetCaster()) - GetHitUnit()->CastSpell(caster, GetSpellInfo()->Effects[effIndex].BasePoints, false); - } + struct npc_helix_sticky_bombAI : public PassiveAI + { + npc_helix_sticky_bombAI(Creature* creature) : PassiveAI(creature) + { + Initialize(); + } - void Register() override - { - OnEffectHitTarget += SpellEffectFn(spell_helix_force_player_to_ride_oaf::HandleHit, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); - } + void Initialize() + { + _countdown = 0; + } + + void IsSummonedBy(Unit* /*summoner*/) override + { + _events.ScheduleEvent(EVENT_ARMING_VISUAL_YELLOW, Seconds(2) + Milliseconds(500)); + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARMING_VISUAL_YELLOW: + DoCastSelf(SPELL_ARMING_VISUAL_YELLOW); + _events.ScheduleEvent(EVENT_ARMING_VISUAL_ORANGE, Seconds(1)); + break; + case EVENT_ARMING_VISUAL_ORANGE: + DoCastSelf(SPELL_ARMING_VISUAL_ORANGE); + _events.ScheduleEvent(EVENT_ARMING_VISUAL_RED, Seconds(2)); + break; + case EVENT_ARMING_VISUAL_RED: + DoCastSelf(SPELL_ARMING_VISUAL_RED); + _events.ScheduleEvent(EVENT_PREPARED_STATE, Seconds(1)); + break; + case EVENT_PREPARED_STATE: + DoCastSelf(SPELL_STICKY_BOMB_ARMED_STATE); + _events.ScheduleEvent(EVENT_PERIODIC_TRIGGER, Seconds(1)); + break; + case EVENT_PERIODIC_TRIGGER: + DoCastSelf(SPELL_STICKY_BOMB_PERIODIC_TRIGGER); + _events.ScheduleEvent(EVENT_EXPLOSION_COUNTDOWN, Seconds(15) + Milliseconds(500)); + break; + case EVENT_EXPLOSION_COUNTDOWN: + DoCastSelf(SPELL_ARMING_VISUAL_RED); + _events.ScheduleEvent(EVENT_COUNTDOWN, Seconds(1)); + break; + case EVENT_COUNTDOWN: + if (_countdown != 3) + { + DoCastSelf(SPELL_ARMING_VISUAL_RED); + _countdown++; + _events.Repeat(Seconds(1)); + } + else + { + me->RemoveAllAuras(); + DoCastSelf(SPELL_EXPLODE, true); + } + break; + default: + break; + } + } + } + private: + EventMap _events; + uint8 _countdown; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetDeadminesAI(creature); + } +}; + +class npc_helix_crew : public CreatureScript +{ + public: + npc_helix_crew() : CreatureScript("npc_helix_crew") { } + + struct npc_helix_crewAI : public PassiveAI + { + npc_helix_crewAI(Creature* creature) : PassiveAI(creature) { } + + void IsSummonedBy(Unit* /*summoner*/) override + { + _events.ScheduleEvent(EVENT_STICKY_BOMB, Seconds(1)); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_TALK_CREW: + _events.ScheduleEvent(EVENT_TALK_READY, Seconds(1)); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STICKY_BOMB: + DoCastAOE(SPELL_THROW_BOMB_TARGETING, true); + _events.Repeat(Seconds(5)); + break; + case EVENT_TALK_READY: + Talk(SAY_CREW_JOIN_FIGHT); + break; + default: + break; + } + } + } + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetDeadminesAI(creature); + } +}; + +class spell_helix_throw_bomb_targeting : public SpellScriptLoader +{ + public: + spell_helix_throw_bomb_targeting() : SpellScriptLoader("spell_helix_throw_bomb_targeting") { } + + class spell_helix_throw_bomb_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_helix_throw_bomb_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleHit(SpellEffIndex effIndex) + { + GetCaster()->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_helix_throw_bomb_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_helix_throw_bomb_targeting_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_helix_throw_bomb_targeting_SpellScript(); + } +}; + +class spell_helix_sticky_bomb_periodic_trigger : public SpellScriptLoader +{ + public: + spell_helix_sticky_bomb_periodic_trigger() : SpellScriptLoader("spell_helix_sticky_bomb_periodic_trigger") { } + + class spell_helix_sticky_bomb_periodic_trigger_AuraScript : public AuraScript + { + PrepareAuraScript(spell_helix_sticky_bomb_periodic_trigger_AuraScript); + + void HandleTick(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (Unit* caster = GetCaster()) + if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell)) + if (Player* player = caster->SelectNearestPlayer(spell->Effects[EFFECT_0].CalcRadius())) + if (!player->GetVehicleBase()) + caster->CastSpell(GetCaster()->GetVictim(), GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_helix_sticky_bomb_periodic_trigger_AuraScript::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_helix_sticky_bomb_periodic_trigger_AuraScript(); + } +}; + +class spell_helix_explode : public SpellScriptLoader +{ + public: + spell_helix_explode() : SpellScriptLoader("spell_helix_explode") { } + + class spell_helix_explode_SpellScript : public SpellScript + { + PrepareSpellScript(spell_helix_explode_SpellScript); + + void HandleLaunch(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()) + { + if (caster->GetTypeId() == TYPEID_UNIT) + { + caster->RemoveAllAuras(); + caster->SetDisplayId(DISPLAY_ID_BOMB_INVISIBLE); + caster->ToCreature()->DespawnOrUnsummon(Seconds(2) + Milliseconds(400)); + } + } + } + + void Register() override + { + OnEffectLaunch += SpellEffectFn(spell_helix_explode_SpellScript::HandleLaunch, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + private: + uint8 _targetsCounter; + }; + + SpellScript* GetSpellScript() const override + { + return new spell_helix_explode_SpellScript(); + } +}; + +class spell_helix_oaf_grab_targeting : public SpellScriptLoader +{ + public: + spell_helix_oaf_grab_targeting() : SpellScriptLoader("spell_helix_oaf_grab_targeting") { } + + class spell_helix_oaf_grab_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_helix_oaf_grab_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleHit(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_helix_oaf_grab_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_helix_oaf_grab_targeting_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_helix_oaf_grab_targeting_SpellScript(); + } +}; + +class spell_helix_force_player_to_ride_oaf : public SpellScriptLoader +{ + public: + spell_helix_force_player_to_ride_oaf() : SpellScriptLoader("spell_helix_force_player_to_ride_oaf") { } + + class spell_helix_force_player_to_ride_oaf_SpellScript : public SpellScript + { + PrepareSpellScript(spell_helix_force_player_to_ride_oaf_SpellScript); + + void HandleHit(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + if (Unit* target = GetHitUnit()) + if (caster->GetVehicleKit()) + { + target->CastStop(); + target->CastSpell(caster, GetSpellInfo()->Effects[effIndex].BasePoints, false); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_helix_force_player_to_ride_oaf_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_helix_force_player_to_ride_oaf_SpellScript(); + } }; class spell_helix_oaf_smash : public SpellScriptLoader @@ -905,14 +1009,15 @@ class spell_helix_chest_bomb : public SpellScriptLoader void AddSC_boss_helix_gearbreaker() { - RegisterDeadminesCreatureAI(boss_helix_gearbreaker); - RegisterDeadminesCreatureAI(npc_helix_lumbering_oaf); - RegisterDeadminesCreatureAI(npc_helix_sticky_bomb); - RegisterDeadminesCreatureAI(npc_helix_crew); - RegisterSpellScript(spell_helix_throw_bomb_targeting); - RegisterAuraScript(spell_helix_sticky_bomb_periodic_trigger); - RegisterSpellScript(spell_helix_oaf_grab_targeting); - RegisterSpellScript(spell_helix_force_player_to_ride_oaf); + new boss_helix_gearbreaker(); + new npc_helix_lumbering_oaf(); + new npc_helix_sticky_bomb(); + new npc_helix_crew(); + new spell_helix_throw_bomb_targeting(); + new spell_helix_sticky_bomb_periodic_trigger(); + new spell_helix_explode(); + new spell_helix_oaf_grab_targeting(); + new spell_helix_force_player_to_ride_oaf(); new spell_helix_oaf_smash(); new spell_helix_ride_face_targeting(); new spell_helix_ride_vehicle();