diff --git a/sql/updates/world/master/2026_02_15_01_world.sql b/sql/updates/world/master/2026_02_15_01_world.sql new file mode 100644 index 0000000000..832edad417 --- /dev/null +++ b/sql/updates/world/master/2026_02_15_01_world.sql @@ -0,0 +1,23 @@ +-- GameObject Visibility +DELETE FROM `gameobject_addon` WHERE `guid`=300137; +INSERT INTO `gameobject_addon` (`guid`, `parent_rotation0`, `parent_rotation1`, `parent_rotation2`, `parent_rotation3`, `invisibilityType`, `invisibilityValue`, `WorldEffectID`, `AIAnimKitID`) VALUES +(300137, 0, 0, 0, 1, 20, 1000, 0, 0); + +UPDATE `gameobject` SET `PhaseId`=504 WHERE `guid`=300148; + +-- Talks +DELETE FROM `creature_text` WHERE `CreatureID` IN (54135) AND `GroupID` = 0; +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(54135, 0, 0, 'You have earned the right to proceed. Huo lies beyond.', 12, 0, 100, 0, 0, 0, 55251, 0, 'Master Li Fei to Player'); + +-- ScriptNames +UPDATE `creature_template` SET `ScriptName`= 'npc_li_fei' WHERE `entry`=54135; +UPDATE `creature_template` SET `unit_flags`=`unit_flags` & ~0x100, `ScriptName`= 'npc_li_fei_combat' WHERE `entry`=54734; + +UPDATE `creature_template_difficulty` SET `StaticFlags1`=`StaticFlags1`|0x00000008 WHERE `entry`=54734; + +DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_fire_crash', 'spell_feet_of_fury', 'spell_flying_shadow_kick'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(102499, 'spell_fire_crash'), +(108958, 'spell_feet_of_fury'), +(108936, 'spell_flying_shadow_kick'); diff --git a/src/server/scripts/Pandaria/zone_the_wandering_isle.cpp b/src/server/scripts/Pandaria/zone_the_wandering_isle.cpp index f253a19845..ba10c5c130 100644 --- a/src/server/scripts/Pandaria/zone_the_wandering_isle.cpp +++ b/src/server/scripts/Pandaria/zone_the_wandering_isle.cpp @@ -46,6 +46,31 @@ namespace Spells static constexpr uint32 CurseOfTheCrocodile = 102942; static constexpr uint32 RideVehiclePole = 102717; static constexpr uint32 TrainingBellPoleExitExclusion = 133381; + + // Only the Worthy Shall Pass + static constexpr uint32 FireCrashCover = 108149; + static constexpr uint32 FireCrashInvis = 108150; + static constexpr uint32 FireCrashPhaseShift = 102515; + static constexpr uint32 FlyingShadowKick = 108936; + static constexpr uint32 FlyingShadowKickJump = 108943; + static constexpr uint32 FeetOfFury = 108958; + static constexpr uint32 FeetOfFuryDamage = 108957; +} + +namespace Quests +{ + static constexpr uint32 OnlyTheWorthyShallPass = 29421; +} + +namespace Creatures +{ + static constexpr uint32 MasterLiFei = 54135; + static constexpr uint32 MasterLiFeiCombat = 54734; +} + +namespace Talks +{ + static constexpr uint32 LiFeiDefeat = 0; } enum TraineeMisc @@ -1298,6 +1323,175 @@ public: return true; } }; + +// 54135 - Master Li Fei +struct npc_li_fei : public ScriptedAI +{ + npc_li_fei(Creature* creature) : ScriptedAI(creature) {} + + void OnQuestAccept(Player* player, Quest const* quest) override + { + if (quest->GetQuestId() == Quests::OnlyTheWorthyShallPass) + player->CastSpell(player, Spells::FireCrashCover); + } +}; + +// 102499 - Fire Crash +class spell_fire_crash : public SpellScript +{ + static constexpr Position PlayerJumpPos = { 1351.3334f, 3939.0347f, 109.32395f, 6.00115f }; + + void SetDest(SpellDestination& dest) const + { + dest.Relocate(PlayerJumpPos); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_fire_crash::SetDest, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); + } +}; + +// 54734 - Master Li Fei (combat) +struct npc_li_fei_combat : public ScriptedAI +{ + npc_li_fei_combat(Creature* creature) : ScriptedAI(creature), _defeatTriggered(false) {} + + enum Events + { + EVENT_FEET_OF_FURY = 1, + EVENT_SHADOW_KICK, + }; + + void Reset() override + { + _defeatTriggered = false; + } + + void JustEngagedWith(Unit* /*attacker*/) override + { + _events.ScheduleEvent(EVENT_FEET_OF_FURY, 6s); + _events.ScheduleEvent(EVENT_SHADOW_KICK, 10s); + } + + void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo*/) override + { + if (!_defeatTriggered && me->HealthBelowPctDamaged(50, damage)) + { + _defeatTriggered = true; + me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE); + + Creature* liFei = me->FindNearestCreatureWithOptions(15.0f, { .CreatureId = Creatures::MasterLiFei, .IgnorePhases = true }); + if (!liFei) + return; + + for (ObjectGuid const& guid : me->GetTapList()) + { + Player* player = ObjectAccessor::GetPlayer(*me, guid); + if (!player) + continue; + + player->KilledMonsterCredit(Creatures::MasterLiFeiCombat, ObjectGuid::Empty); + player->RemoveAurasDueToSpell(Spells::FireCrashCover); + player->RemoveAurasDueToSpell(Spells::FireCrashInvis); + player->RemoveAurasDueToSpell(Spells::FireCrashPhaseShift); + } + + liFei->AI()->Talk(Talks::LiFeiDefeat, attacker); + + EnterEvadeMode(); + } + } + + void KilledUnit(Unit* victim) override + { + Player* player = victim->ToPlayer(); + if (!player) + return; + + player->SetQuestStatus(Quests::OnlyTheWorthyShallPass, QUEST_STATUS_FAILED); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + if (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FEET_OF_FURY: + DoCastVictim(Spells::FeetOfFury); + + _events.ScheduleEvent(EVENT_FEET_OF_FURY, 12s); + break; + case EVENT_SHADOW_KICK: + DoCastVictim(Spells::FlyingShadowKick); + + _events.ScheduleEvent(EVENT_SHADOW_KICK, 15s); + break; + default: + break; + } + } + } + +private: + EventMap _events; + bool _defeatTriggered; +}; + +// 108958 - Feet of Fury +class spell_feet_of_fury : public AuraScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ Spells::FeetOfFuryDamage }); + } + + void PeriodicTick(AuraEffect const* aurEff) + { + PreventDefaultAction(); + + Unit* target = GetTarget(); + target->CastSpell(target->GetVictim(), Spells::FeetOfFuryDamage, CastSpellExtraArgsInit{ + .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR, + .TriggeringAura = aurEff + }); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_feet_of_fury::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } +}; + +// 108936 - Flying Shadow Kick +class spell_flying_shadow_kick : public SpellScript +{ + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ Spells::FlyingShadowKickJump }); + } + + void HandleHitTarget(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), Spells::FlyingShadowKickJump, CastSpellExtraArgsInit{ + .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR, + }); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_flying_shadow_kick::HandleHitTarget, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; }; void AddSC_zone_the_wandering_isle() @@ -1331,4 +1525,10 @@ void AddSC_zone_the_wandering_isle() new at_singing_pools_transform_base("at_singing_pools_transform_crocodile"); new at_singing_pools_transform_base("at_singing_pools_transform_crane"); new at_singing_pools_transform_base("at_singing_pools_transform_turtle"); + + RegisterCreatureAI(npc_li_fei); + RegisterSpellScript(spell_fire_crash); + RegisterCreatureAI(npc_li_fei_combat); + RegisterSpellScript(spell_feet_of_fury); + RegisterSpellScript(spell_flying_shadow_kick); }