From 4d2dbbcf169c17a0fe56b5d92b557a0cbfb8e18a Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Mon, 17 Feb 2025 15:06:19 -0500 Subject: [PATCH] Core/Auras: Implemented mount equipment Port From (https://github.com/TrinityCore/TrinityCore/commit/6dd5fb9d88e7a8b7da696bbe7b96947217b1ace2) --- Source/Framework/Constants/CliDBConst.cs | 18 +++++-- .../Database/Databases/HotfixDatabase.cs | 6 +++ Source/Game/DataStorage/CliDB.cs | 2 + Source/Game/DataStorage/Structs/M_Records.cs | 10 +++- .../Game/Networking/Packets/SpellPackets.cs | 23 +++++++++ Source/Game/Spells/Auras/AuraEffect.cs | 17 ++++++- Source/Game/Spells/SpellEffects.cs | 37 ++++++++++++++ Source/Scripts/Spells/Generic.cs | 48 +++++++++++++++++++ 8 files changed, 154 insertions(+), 7 deletions(-) diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 1e93dc592..13b046e21 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -1889,11 +1889,19 @@ namespace Framework.Constants public enum MountFlags : int { - SelfMount = 0x02, // Player becomes the mount himself - FactionSpecific = 0x04, - PreferredSwimming = 0x10, - PreferredWaterWalking = 0x20, - HideIfUnknown = 0x40 + ServerOnly = 0x01, + IsSelfMount = 0x02, + ExcludeFromJournalIfFactionDoesntMatch = 0x04, + AllowMountedCombat = 0x08, + SummonRandomFavorWhileUnderwater = 0x10, + SummonRandomFavorWhileAtWaterSurface = 0x20, + ExcludeFromJournalIfNotLearned = 0x40, + SummonRandomDoNotFavorWhenGrounded = 0x80, + ShowInSpellbook = 0x100, + AddToActionBarOnLearn = 0x200, + NotForUseAsATaxi = 0x400, + MountEquipmentEffectsSuppressed = 0x800, + DisablePlayerMountPreview = 0x1000, } public enum PathPropertyIndex diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index 664e854ac..69a93c6d9 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -962,6 +962,10 @@ namespace Framework.Database PrepareStatement(HotfixStatements.SEL_MOUNT_CAPABILITY, "SELECT ID, Flags, ReqRidingSkill, ReqAreaID, ReqSpellAuraID, ReqSpellKnownID, ModSpellAuraID, " + "ReqMapID, PlayerConditionID, FlightCapabilityID FROM mount_capability WHERE (`VerifiedBuild` > 0) = ?"); + // MountEquipment.db2 + PrepareStatement(HotfixStatements.SEL_MOUNT_EQUIPMENT, "SELECT ID, Item, BuffSpell, Unknown820, LearnedBySpell FROM mount_equipment" + + " WHERE (`VerifiedBuild` > 0) = ?"); + // MountTypeXCapability.db2 PrepareStatement(HotfixStatements.SEL_MOUNT_TYPE_X_CAPABILITY, "SELECT ID, MountTypeID, MountCapabilityID, OrderIndex FROM mount_type_x_capability" + " WHERE (`VerifiedBuild` > 0) = ?"); @@ -2095,6 +2099,8 @@ namespace Framework.Database SEL_MOUNT_CAPABILITY, + SEL_MOUNT_EQUIPMENT, + SEL_MOUNT_TYPE_X_CAPABILITY, SEL_MOUNT_X_DISPLAY, diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index d9a82087f..a9eb96670 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -244,6 +244,7 @@ namespace Game.DataStorage ModifierTreeStorage = ReadDB2("ModifierTree.db2", HotfixStatements.SEL_MODIFIER_TREE); MountCapabilityStorage = ReadDB2("MountCapability.db2", HotfixStatements.SEL_MOUNT_CAPABILITY); MountStorage = ReadDB2("Mount.db2", HotfixStatements.SEL_MOUNT, HotfixStatements.SEL_MOUNT_LOCALE); + MountEquipmentStorage = ReadDB2("MountEquipment.db2", HotfixStatements.SEL_MOUNT_EQUIPMENT); MountTypeXCapabilityStorage = ReadDB2("MountTypeXCapability.db2", HotfixStatements.SEL_MOUNT_TYPE_X_CAPABILITY); MountXDisplayStorage = ReadDB2("MountXDisplay.db2", HotfixStatements.SEL_MOUNT_X_DISPLAY); MovieStorage = ReadDB2("Movie.db2", HotfixStatements.SEL_MOVIE); @@ -693,6 +694,7 @@ namespace Game.DataStorage public static DB6Storage ModifierTreeStorage; public static DB6Storage MountCapabilityStorage; public static DB6Storage MountStorage; + public static DB6Storage MountEquipmentStorage; public static DB6Storage MountTypeXCapabilityStorage; public static DB6Storage MountXDisplayStorage; public static DB6Storage MovieStorage; diff --git a/Source/Game/DataStorage/Structs/M_Records.cs b/Source/Game/DataStorage/Structs/M_Records.cs index f7f65735b..1f7506170 100644 --- a/Source/Game/DataStorage/Structs/M_Records.cs +++ b/Source/Game/DataStorage/Structs/M_Records.cs @@ -197,7 +197,6 @@ namespace Game.DataStorage public int MountSpecialSpellVisualKitID; public bool HasFlag(MountFlags mountFlags) { return (Flags & (int)mountFlags) != 0; } - public bool IsSelfMount() { return HasFlag(MountFlags.SelfMount); } } public sealed class MountCapabilityRecord @@ -216,6 +215,15 @@ namespace Game.DataStorage public bool HasFlag(MountCapabilityFlags mountCapabilityFlags) { return (Flags & (int)mountCapabilityFlags) != 0; } } + public sealed class MountEquipmentRecord + { + public uint Id; + public int Item; + public int BuffSpell; + public int Unknown820; + public uint LearnedBySpell; + } + public sealed class MountTypeXCapabilityRecord { public uint Id; diff --git a/Source/Game/Networking/Packets/SpellPackets.cs b/Source/Game/Networking/Packets/SpellPackets.cs index fdfa99c40..f084f0104 100644 --- a/Source/Game/Networking/Packets/SpellPackets.cs +++ b/Source/Game/Networking/Packets/SpellPackets.cs @@ -1243,6 +1243,29 @@ namespace Game.Networking.Packets public uint Result; } + class ApplyMountEquipmentResult : ServerPacket + { + public ObjectGuid ItemGUID; + public uint ItemID; + public ApplyResult Result = ApplyResult.Success; + + public enum ApplyResult + { + Success = 0, + Failure = 1 + } + + public ApplyMountEquipmentResult() : base(ServerOpcodes.ApplyMountEquipmentResult, ConnectionType.Instance) { } + + public override void Write() + { + _worldPacket.WritePackedGuid(ItemGUID); + _worldPacket.WriteUInt32(ItemID); + _worldPacket.WriteBits(Result, 1); + _worldPacket.FlushBits(); + } + } + class MissileCancel : ServerPacket { public MissileCancel() : base(ServerOpcodes.MissileCancel) { } diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 62ac8f192..112d2e766 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -2169,7 +2169,7 @@ namespace Game.Spells var mountDisplays = Global.DB2Mgr.GetMountDisplays(mountEntry.Id); if (mountDisplays != null) { - if (mountEntry.IsSelfMount()) + if (mountEntry.HasFlag(MountFlags.IsSelfMount)) { displayId = SharedConst.DisplayIdHiddenMount; } @@ -2191,6 +2191,17 @@ namespace Game.Spells // TODO: CREATE TABLE mount_vehicle (mountId, vehicleCreatureId) for future mounts that are vehicles (new mounts no longer have proper data in MiscValue) //if (MountVehicle const* mountVehicle = sObjectMgr->GetMountVehicle(mountEntry->Id)) // creatureEntry = mountVehicle->VehicleCreatureId; + + if (mode.HasFlag(AuraEffectHandleModes.Real) && !mountEntry.HasFlag(MountFlags.MountEquipmentEffectsSuppressed)) + { + Player playerTarget = target.ToPlayer(); + if (playerTarget != null) + { + var mountEquipment = CliDB.MountEquipmentStorage.Values.FirstOrDefault(record => playerTarget.HasSpell(record.LearnedBySpell)); + if (mountEquipment != null) + playerTarget.CastSpell(playerTarget, (uint)mountEquipment.BuffSpell, this); + } + } } CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(creatureEntry); @@ -2234,7 +2245,11 @@ namespace Game.Spells // need to remove ALL arura related to mounts, this will stop client crash with broom stick // and never endless flying after using Headless Horseman's Mount if (mode.HasAnyFlag(AuraEffectHandleModes.Real)) + { target.RemoveAurasByType(AuraType.Mounted); + foreach (var (_, mountEquipmentStore) in CliDB.MountEquipmentStorage) + target.RemoveOwnedAura((uint)mountEquipmentStore.BuffSpell); + } if (mode.HasAnyFlag(AuraEffectHandleModes.ChangeAmountMask)) { diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index ee1c13148..702d3cb46 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5681,6 +5681,43 @@ namespace Game.Spells Conversation.CreateConversation((uint)effectInfo.MiscValue, unitTarget, destTarget.GetPosition(), unitTarget.GetGUID(), GetSpellInfo()); } + [SpellEffectHandler(SpellEffectName.ApplyMountEquipment)] + void EffectApplyMountEquipment() + { + if (effectHandleMode != SpellEffectHandleMode.LaunchTarget) + return; + + Player playerTarget = unitTarget.ToPlayer(); + if (playerTarget == null) + return; + + foreach (var (_, mountEquipment) in CliDB.MountEquipmentStorage) + { + if (mountEquipment.LearnedBySpell == effectInfo.TriggerSpell) + { + playerTarget.LearnSpell(mountEquipment.LearnedBySpell, false, 0, true); + var mountAuras = playerTarget.GetAuraEffectsByType(AuraType.Mounted); + if (!mountAuras.Empty()) + { + var mountEntry = Global.DB2Mgr.GetMount(mountAuras.FirstOrDefault().GetId()); + if (mountEntry != null && !mountEntry.HasFlag(MountFlags.MountEquipmentEffectsSuppressed)) + playerTarget.CastSpell(playerTarget, (uint)mountEquipment.BuffSpell, true); + } + } + else + { + playerTarget.RemoveOwnedAura((uint)mountEquipment.BuffSpell); + playerTarget.RemoveSpell(mountEquipment.LearnedBySpell, false, false, true); + } + } + + ApplyMountEquipmentResult applyMountEquipmentResult = new(); + applyMountEquipmentResult.ItemGUID = m_castItemGUID; + applyMountEquipmentResult.ItemID = m_castItemEntry; + applyMountEquipmentResult.Result = ApplyMountEquipmentResult.ApplyResult.Success; + playerTarget.SendPacket(applyMountEquipmentResult); + } + [SpellEffectHandler(SpellEffectName.SendChatMessage)] void EffectSendChatMessage() { diff --git a/Source/Scripts/Spells/Generic.cs b/Source/Scripts/Spells/Generic.cs index 5fc492d6e..3e7f53a48 100644 --- a/Source/Scripts/Spells/Generic.cs +++ b/Source/Scripts/Spells/Generic.cs @@ -5166,4 +5166,52 @@ namespace Scripts.Spells.Generic } } + [Script] // 296837 - Comfortable Rider's Barding + class spell_gen_comfortable_riders_barding : AuraScript + { + static uint SPELL_DAZED = 1604; + + bool _apply; + + public override bool Validate(SpellInfo spellInfo) + { + return ValidateSpellInfo(SPELL_DAZED); + } + + void HandleEffect(AuraEffect aurEff, AuraEffectHandleModes mode) + { + GetTarget().ApplySpellImmune(GetId(), SpellImmunity.Id, SPELL_DAZED, _apply); + } + + public override void Register() + { + _apply = true; + OnEffectApply.Add(new EffectApplyHandler(HandleEffect, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); + _apply = false; + OnEffectRemove.Add(new EffectApplyHandler(HandleEffect, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); + } + } + + [Script] // 297091 - Parachute + class spell_gen_saddlechute : AuraScript + { + static uint SPELL_PARACHUTE = 297092; + + public override bool Validate(SpellInfo spellInfo) + { + return ValidateSpellInfo(SPELL_PARACHUTE); + } + + void TriggerParachute(AuraEffect aurEff, AuraEffectHandleModes mode) + { + Unit target = GetTarget(); + if (target.IsFlying() || target.IsFalling()) + target.CastSpell(target, SPELL_PARACHUTE, new CastSpellExtraArgs(TriggerCastFlags.DontReportCastError)); + } + + public override void Register() + { + AfterEffectRemove.Add(new EffectApplyHandler(TriggerParachute, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); + } + } } \ No newline at end of file