diff --git a/Source/Framework/Constants/Spells/SpellAuraConst.cs b/Source/Framework/Constants/Spells/SpellAuraConst.cs index 69acacb20..7ddc82d22 100644 --- a/Source/Framework/Constants/Spells/SpellAuraConst.cs +++ b/Source/Framework/Constants/Spells/SpellAuraConst.cs @@ -413,7 +413,7 @@ namespace Framework.Constants OverrideSpellVisual = 403, OverrideAttackPowerBySpPct = 404, ModRatingPct = 405, - KeyboundOverride = 406, // NYI + KeyboundOverride = 406, ModFear2 = 407, SetActionButtonSpellCount = 408, CanTurnWhileFalling = 409, diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index ca9a34f1e..2c5059c14 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -1190,6 +1190,10 @@ namespace Framework.Database "RtOperandType1, RtOperandType2, RtOperandType3, RtOperandType4, RtOperandType5, RtOperand1, RtOperand2, RtOperand3, RtOperand4, RtOperand5, " + "Logic1, Logic2, Logic3, Logic4, Logic5 FROM spell_item_enchantment_condition WHERE (`VerifiedBuild` > 0) = ?"); + // SpellKeyboundOverride.db2 + PrepareStatement(HotfixStatements.SEL_SPELL_KEYBOUND_OVERRIDE, "SELECT ID, `Function`, Type, Data, Flags FROM spell_keybound_override" + + " WHERE (`VerifiedBuild` > 0) = ?"); + // SpellLabel.db2 PrepareStatement(HotfixStatements.SEL_SPELL_LABEL, "SELECT ID, LabelID, SpellID FROM spell_label WHERE (`VerifiedBuild` > 0) = ?"); @@ -2102,6 +2106,8 @@ namespace Framework.Database SEL_SPELL_ITEM_ENCHANTMENT_CONDITION, + SEL_SPELL_KEYBOUND_OVERRIDE, + SEL_SPELL_LABEL, SEL_SPELL_LEARN_SPELL, diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index 2a972941c..55d0e8b6a 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -289,6 +289,7 @@ namespace Game.DataStorage SpellInterruptsStorage = ReadDB2("SpellInterrupts.db2", HotfixStatements.SEL_SPELL_INTERRUPTS); SpellItemEnchantmentStorage = ReadDB2("SpellItemEnchantment.db2", HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT, HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT_LOCALE); SpellItemEnchantmentConditionStorage = ReadDB2("SpellItemEnchantmentCondition.db2", HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT_CONDITION); + SpellKeyboundOverrideStorage = ReadDB2("SpellKeyboundOverride.db2", HotfixStatements.SEL_SPELL_KEYBOUND_OVERRIDE); SpellLabelStorage = ReadDB2("SpellLabel.db2", HotfixStatements.SEL_SPELL_LABEL); SpellLearnSpellStorage = ReadDB2("SpellLearnSpell.db2", HotfixStatements.SEL_SPELL_LEARN_SPELL); SpellLevelsStorage = ReadDB2("SpellLevels.db2", HotfixStatements.SEL_SPELL_LEVELS); @@ -711,6 +712,7 @@ namespace Game.DataStorage public static DB6Storage SpellInterruptsStorage; public static DB6Storage SpellItemEnchantmentStorage; public static DB6Storage SpellItemEnchantmentConditionStorage; + public static DB6Storage SpellKeyboundOverrideStorage; public static DB6Storage SpellLabelStorage; public static DB6Storage SpellLearnSpellStorage; public static DB6Storage SpellLevelsStorage; diff --git a/Source/Game/DataStorage/Structs/S_Records.cs b/Source/Game/DataStorage/Structs/S_Records.cs index 9e3378c64..a12de8dd8 100644 --- a/Source/Game/DataStorage/Structs/S_Records.cs +++ b/Source/Game/DataStorage/Structs/S_Records.cs @@ -380,6 +380,15 @@ namespace Game.DataStorage public byte[] Logic = new byte[5]; } + public sealed class SpellKeyboundOverrideRecord + { + public uint Id; + public string Function; + public sbyte Type; + public uint Data; + public int Flags; + } + public sealed class SpellLabelRecord { public uint Id; diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index d969fb339..7b1852e00 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -701,5 +701,19 @@ namespace Game { GetPlayer().SendSpellCategoryCooldowns(); } + + [WorldPacketHandler(ClientOpcodes.KeyboundOverride, Processing = PacketProcessing.ThreadSafe)] + void HandleKeyboundOverride(KeyboundOverride keyboundOverride) + { + Player player = GetPlayer(); + if (!player.HasAuraTypeWithMiscvalue(AuraType.KeyboundOverride, keyboundOverride.OverrideID)) + return; + + SpellKeyboundOverrideRecord spellKeyboundOverride = CliDB.SpellKeyboundOverrideStorage.LookupByKey(keyboundOverride.OverrideID); + if (spellKeyboundOverride == null) + return; + + player.CastSpell(player, spellKeyboundOverride.Data); + } } } diff --git a/Source/Game/Networking/Packets/SpellPackets.cs b/Source/Game/Networking/Packets/SpellPackets.cs index 500c73814..330839bad 100644 --- a/Source/Game/Networking/Packets/SpellPackets.cs +++ b/Source/Game/Networking/Packets/SpellPackets.cs @@ -1158,6 +1158,18 @@ namespace Game.Networking.Packets IsFavorite = _worldPacket.HasBit(); } } + + class KeyboundOverride : ClientPacket + { + public KeyboundOverride(WorldPacket packet) : base(packet) { } + + public override void Read() + { + OverrideID = _worldPacket.ReadUInt16(); + } + + public ushort OverrideID; + } //Structs public struct SpellLogPowerData