From 9c09857b190c36f587db11ab18c87d79ceef5b99 Mon Sep 17 00:00:00 2001 From: Nefertumm Date: Sat, 9 Jul 2022 18:36:51 -0300 Subject: [PATCH] fix(Core/ZulGurub): Jin'do the Hexxer rewrite (#12233) Co-authored-by: UltraNix --- .../rev_1656469500232857400.sql | 36 ++ .../EasternKingdoms/ZulGurub/boss_jindo.cpp | 425 +++++++++--------- 2 files changed, 244 insertions(+), 217 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1656469500232857400.sql diff --git a/data/sql/updates/pending_db_world/rev_1656469500232857400.sql b/data/sql/updates/pending_db_world/rev_1656469500232857400.sql new file mode 100644 index 000000000..d5e671a32 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1656469500232857400.sql @@ -0,0 +1,36 @@ +-- +DELETE FROM `spell_target_position` WHERE `id` = 24466; +INSERT INTO `spell_target_position` (`ID`, `EffectIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`) VALUES +(24466, 0, 309, -11582.9, -1251.15, 90, 5.04179); + +UPDATE `creature` SET `spawntimesecs` = 20 WHERE `id1` = 14826; + +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 14826; + +DELETE FROM `smart_scripts` WHERE (`entryorguid` = 14826) AND (`source_type` = 0) AND (`id` IN (0, 1)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(14826, 0, 0, 0, 6, 0, 100, 0, 0, 0, 0, 0, 0, 41, 5000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Sacrificed Troll - On Just Died - Despawn In 5000 ms'), +(14826, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 9, 14826, 0, 100, 2, 0, 0, 0, 0, 'Sacrificed Troll - On Respawn - Respawn Closest Creature \'Sacrificed Troll\''); + +SET @LEADERGUID := 49081; +DELETE FROM `creature_formations` WHERE `memberGUID` IN (@LEADERGUID, 49078, 49079, 49080, 49082, 49083, 49084, 49085, 49086, 49087); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`) VALUES +(@LEADERGUID, @LEADERGUID, 0, 0, 3), +(@LEADERGUID, 49078, 0, 0, 3), +(@LEADERGUID, 49079, 0, 0, 3), +(@LEADERGUID, 49080, 0, 0, 3), +(@LEADERGUID, 49082, 0, 0, 3), +(@LEADERGUID, 49083, 0, 0, 3), +(@LEADERGUID, 49084, 0, 0, 3), +(@LEADERGUID, 49085, 0, 0, 3), +(@LEADERGUID, 49086, 0, 0, 3), +(@LEADERGUID, 49087, 0, 0, 3); + +UPDATE `creature_template_spell` SET `Spell` = 24261 WHERE `CreatureID` = 15112 AND `Index` = 0; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_random_aggro', 'spell_delusions_of_jindo'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(23878, 'spell_random_aggro'), +(24306, 'spell_delusions_of_jindo'); + +UPDATE `creature_template` SET `speed_run` = 1.14286, `speed_walk` = 1.32 WHERE `entry` = 11380; diff --git a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp index 0b912aef1..d4aa84a18 100644 --- a/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp +++ b/src/server/scripts/EasternKingdoms/ZulGurub/boss_jindo.cpp @@ -15,15 +15,10 @@ * with this program. If not, see . */ -/* ScriptData -SDName: Boss_Jin'do the Hexxer -SD%Complete: 85 -SDComment: Mind Control not working because of core bug. Shades visible for all. -SDCategory: Zul'Gurub -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "SpellScript.h" +#include "TaskScheduler.h" #include "zulgurub.h" enum Say @@ -33,269 +28,265 @@ enum Say enum Spells { - SPELL_BRAINWASHTOTEM = 24262, - SPELL_POWERFULLHEALINGWARD = 24309, + SPELL_BRAIN_WASH_TOTEM = 24262, + SPELL_POWERFULL_HEALING_WARD = 24309, SPELL_HEX = 24053, - SPELL_DELUSIONSOFJINDO = 24306, + SPELL_DELUSIONS_OF_JINDO = 24306, + SPELL_SUMMON_SHADE_OF_JINDO = 24308, + SPELL_BANISH = 24466, + //Healing Ward Spell SPELL_HEAL = 24311, + //Shade of Jindo Spell - SPELL_SHADEOFJINDO_PASSIVE = 24307, - SPELL_SHADEOFJINDO_VISUAL = 24313, - SPELL_SHADOWSHOCK = 19460 + SPELL_SHADE_OF_JINDO_PASSIVE = 24307, + SPELL_SHADE_OF_JINDO_VISUAL = 24313, + SPELL_SHADOW_SHOCK = 19460, + SPELL_RANDOM_AGGRO = 23878 }; enum Events { - EVENT_BRAINWASHTOTEM = 1, - EVENT_POWERFULLHEALINGWARD = 2, + EVENT_BRAIN_WASH_TOTEM = 1, + EVENT_POWERFULL_HEALING_WARD = 2, EVENT_HEX = 3, - EVENT_DELUSIONSOFJINDO = 4, + EVENT_DELUSIONS_OF_JINDO = 4, EVENT_TELEPORT = 5 }; -Position const TeleportLoc = {-11583.7783f, -1249.4278f, 77.5471f, 4.745f}; - -class boss_jindo : public CreatureScript +struct boss_jindo : public BossAI { -public: - boss_jindo() : CreatureScript("boss_jindo") { } + boss_jindo(Creature* creature) : BossAI(creature, DATA_JINDO) { } - struct boss_jindoAI : public BossAI + void EnterCombat(Unit* who) override { - boss_jindoAI(Creature* creature) : BossAI(creature, DATA_JINDO) { } + BossAI::EnterCombat(who); + events.ScheduleEvent(EVENT_BRAIN_WASH_TOTEM, 20000); + events.ScheduleEvent(EVENT_POWERFULL_HEALING_WARD, 16000); + events.ScheduleEvent(EVENT_HEX, 8000); + events.ScheduleEvent(EVENT_DELUSIONS_OF_JINDO, 10000); + events.ScheduleEvent(EVENT_TELEPORT, 5000); - void Reset() override + Talk(SAY_AGGRO); + } + + void JustSummoned(Creature* summon) override + { + BossAI::JustSummoned(summon); + + switch (summon->GetEntry()) { - _Reset(); - } - - void JustDied(Unit* /*killer*/) override - { - _JustDied(); - } - - void EnterCombat(Unit* /*who*/) override - { - _EnterCombat(); - events.ScheduleEvent(EVENT_BRAINWASHTOTEM, 20000); - events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, 16000); - events.ScheduleEvent(EVENT_HEX, 8000); - events.ScheduleEvent(EVENT_DELUSIONSOFJINDO, 10000); - events.ScheduleEvent(EVENT_TELEPORT, 5000); - 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)) { - case NPC_BRAIN_WASH_TOTEM: - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1)) - { - summon->CastSpell(target, summon->m_spells[0], true); - } - break; - default: - break; + summon->CastSpell(target, summon->m_spells[0], true); + } + break; + default: + break; + } + } + + void EnterEvadeMode(EvadeReason evadeReason) override + { + if (_EnterEvadeMode(evadeReason)) + { + me->AddUnitState(UNIT_STATE_EVADE); + Reset(); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_DANCE); + + me->m_Events.AddEventAtOffset([&]() + { + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); + me->GetMotionMaster()->MoveTargetedHome(); + }, 4s); + } + } + + 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) + { + case EVENT_BRAIN_WASH_TOTEM: + DoCastSelf(SPELL_BRAIN_WASH_TOTEM); + events.ScheduleEvent(EVENT_BRAIN_WASH_TOTEM, urand(18000, 26000)); + break; + case EVENT_POWERFULL_HEALING_WARD: + DoCastSelf(SPELL_POWERFULL_HEALING_WARD, true); + events.ScheduleEvent(EVENT_POWERFULL_HEALING_WARD, urand(14000, 20000)); + break; + case EVENT_HEX: + if (me->GetThreatMgr().getThreatList().size() > 1) + DoCastVictim(SPELL_HEX, true); + events.ScheduleEvent(EVENT_HEX, urand(12000, 20000)); + break; + case EVENT_DELUSIONS_OF_JINDO: + DoCastRandomTarget(SPELL_DELUSIONS_OF_JINDO); + events.ScheduleEvent(EVENT_DELUSIONS_OF_JINDO, urand(4000, 12000)); + break; + case EVENT_TELEPORT: + DoCastRandomTarget(SPELL_BANISH); + events.ScheduleEvent(EVENT_TELEPORT, urand(15000, 23000)); + break; + default: + break; } } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + DoMeleeAttackIfReady(); + } - events.Update(diff); - - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - - while (uint32 eventId = events.ExecuteEvent()) - { - switch (eventId) - { - case EVENT_BRAINWASHTOTEM: - DoCast(me, SPELL_BRAINWASHTOTEM); - events.ScheduleEvent(EVENT_BRAINWASHTOTEM, urand(18000, 26000)); - break; - case EVENT_POWERFULLHEALINGWARD: - DoCastSelf(SPELL_POWERFULLHEALINGWARD, true); - events.ScheduleEvent(EVENT_POWERFULLHEALINGWARD, urand(14000, 20000)); - break; - case EVENT_HEX: - DoCastVictim(SPELL_HEX, true); - events.ScheduleEvent(EVENT_HEX, urand(12000, 20000)); - break; - case EVENT_DELUSIONSOFJINDO: // HACK - // Casting the delusion curse with a shade so shade will attack the same target with the curse. - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - { - DoCast(target, SPELL_DELUSIONSOFJINDO); - Creature* Shade = me->SummonCreature(NPC_SHADE_OF_JINDO, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (Shade) - Shade->AI()->AttackStart(target); - } - events.ScheduleEvent(EVENT_DELUSIONSOFJINDO, urand(4000, 12000)); - break; - case EVENT_TELEPORT: // Possible HACK - // Teleports a random player and spawns 9 Sacrificed Trolls to attack player - if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) - { - DoTeleportPlayer(target, TeleportLoc.m_positionX, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, TeleportLoc.GetOrientation()); - if (DoGetThreat(me->GetVictim())) - DoModifyThreatPercent(target, -100); - Creature* SacrificedTroll; - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX + 2, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX - 2, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX + 4, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX - 4, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY + 2, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY - 2, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY + 4, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX, TeleportLoc.m_positionY - 4, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - SacrificedTroll = me->SummonCreature(NPC_SACRIFICED_TROLL, TeleportLoc.m_positionX + 3, TeleportLoc.m_positionY, TeleportLoc.m_positionZ, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - if (SacrificedTroll) - SacrificedTroll->AI()->AttackStart(target); - } - events.ScheduleEvent(EVENT_TELEPORT, urand(15000, 23000)); - break; - default: - break; - } - } - - DoMeleeAttackIfReady(); - } - - bool CanAIAttack(Unit const* target) const override - { + bool CanAIAttack(Unit const* target) const override + { + if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target) return !target->HasAura(SPELL_HEX); - } - }; - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); + return true; } }; //Healing Ward -class npc_healing_ward : public CreatureScript +struct npc_healing_ward : public ScriptedAI { -public: - npc_healing_ward() - : CreatureScript("npc_healing_ward") + npc_healing_ward(Creature* creature) : ScriptedAI(creature) { + _instance = creature->GetInstanceScript(); } - struct npc_healing_wardAI : public ScriptedAI + void Reset() override { - npc_healing_wardAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } + _scheduler.CancelAll(); + } - uint32 Heal_Timer; - - InstanceScript* instance; - - void Reset() override - { - Heal_Timer = 2000; - } - - void EnterCombat(Unit* /*who*/) override - { - } - - void UpdateAI(uint32 diff) override - { - //Heal_Timer - if (Heal_Timer <= diff) + void EnterCombat(Unit* /*who*/) override + { + _scheduler. + Schedule(2s, [this](TaskContext context) { - Unit* pJindo = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_JINDO)); + Unit* pJindo = ObjectAccessor::GetUnit(*me, _instance->GetGuidData(DATA_JINDO)); if (pJindo) DoCast(pJindo, SPELL_HEAL); - Heal_Timer = 3000; - } - else Heal_Timer -= diff; - - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override - { - return GetZulGurubAI(creature); + context.Repeat(3s); + }); } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + +private: + InstanceScript* _instance; + TaskScheduler _scheduler; }; //Shade of Jindo -class npc_shade_of_jindo : public CreatureScript +struct npc_shade_of_jindo : public ScriptedAI { -public: - npc_shade_of_jindo() - : CreatureScript("npc_shade_of_jindo") + npc_shade_of_jindo(Creature* creature) : ScriptedAI(creature) { } + + void IsSummonedBy(Unit* /*summoner*/) override { + DoZoneInCombat(); + DoCastSelf(SPELL_SHADE_OF_JINDO_PASSIVE, true); + DoCastSelf(SPELL_SHADE_OF_JINDO_VISUAL, true); + DoCastAOE(SPELL_RANDOM_AGGRO, true); } - struct npc_shade_of_jindoAI : public ScriptedAI + void Reset() override { - npc_shade_of_jindoAI(Creature* creature) : ScriptedAI(creature) { } + _scheduler.CancelAll(); - uint32 ShadowShock_Timer; - - void Reset() override - { - ShadowShock_Timer = 1000; - DoCastSelf(SPELL_SHADEOFJINDO_PASSIVE, true); - DoCastSelf(SPELL_SHADEOFJINDO_VISUAL, true); - } - - void EnterCombat(Unit* /*who*/) override { } - - void UpdateAI(uint32 diff) override - { - //ShadowShock_Timer - if (ShadowShock_Timer <= diff) + _scheduler. + Schedule(1s, [this](TaskContext context) { - DoCastVictim(SPELL_SHADOWSHOCK); - ShadowShock_Timer = 2000; - } - else ShadowShock_Timer -= diff; + DoCastAOE(SPELL_RANDOM_AGGRO, true); + context.Repeat(); + }); + } - DoMeleeAttackIfReady(); - } - }; - - CreatureAI* GetAI(Creature* creature) const override + void EnterCombat(Unit* /*who*/) override { - return GetZulGurubAI(creature); + _scheduler. + Schedule(1s, [this](TaskContext context) + { + DoCastVictim(SPELL_SHADOW_SHOCK); + context.Repeat(2s); + }); + } + + void UpdateAI(uint32 diff) override + { + _scheduler.Update(diff, [this] + { + DoMeleeAttackIfReady(); + }); + } + +private: + TaskScheduler _scheduler; +}; + +class spell_random_aggro : public SpellScript +{ + PrepareSpellScript(spell_random_aggro); + + void HandleOnHit() + { + Unit* caster = GetCaster(); + Unit* target = GetHitUnit(); + if (!caster || !target || !caster->GetAI()) + return; + + caster->GetAI()->AttackStart(target); + } + + void Register() override + { + OnHit += SpellHitFn(spell_random_aggro::HandleOnHit); + } +}; + +class spell_delusions_of_jindo : public SpellScript +{ + PrepareSpellScript(spell_delusions_of_jindo); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SUMMON_SHADE_OF_JINDO }); + } + + void HandleOnHit() + { + Unit* caster = GetCaster(); + if (caster) + caster->CastSpell(caster, SPELL_SUMMON_SHADE_OF_JINDO, true); + } + + void Register() override + { + OnHit += SpellHitFn(spell_delusions_of_jindo::HandleOnHit); } }; void AddSC_boss_jindo() { - new boss_jindo(); - new npc_healing_ward(); - new npc_shade_of_jindo(); + RegisterZulGurubCreatureAI(boss_jindo); + RegisterZulGurubCreatureAI(npc_healing_ward); + RegisterZulGurubCreatureAI(npc_shade_of_jindo); + RegisterSpellScript(spell_random_aggro); + RegisterSpellScript(spell_delusions_of_jindo); }