diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs index d33d4d0de..83e1553b8 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs @@ -56,22 +56,6 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory] - [InlineData(0, true)] - [InlineData(0, false)] - [InlineData(100, true)] - [InlineData(1000, false)] - public void TestSpecialAbility(int abilityId, bool active) - { - var expected = new ToggleSpecialAbility(abilityId, active).Compile(); - - var ns = PacketTestUtilities.CreateTestNetState(); - ns.SendToggleSpecialAbility(abilityId, active); - - var result = ns.SendPipe.Reader.TryRead(); - AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); - } - [Theory] [InlineData(0x1000u, "This is a header", "This is a body", "This is a footer")] [InlineData(0x1000u, null, null, null)] @@ -338,18 +322,6 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestClearAbility() - { - var expected = new ClearWeaponAbility().Compile(); - - var ns = PacketTestUtilities.CreateTestNetState(); - ns.SendClearWeaponAbility(); - - var result = ns.SendPipe.Reader.TryRead(); - AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); - } - [Theory] [InlineData(0xFF01)] public void TestDisplayHuePicker(int itemID) diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs index f304c3b69..f8cb355e1 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPackets.cs @@ -57,19 +57,6 @@ namespace Server.Network public static Packet Instantiate(bool dead) => dead ? Dead : Alive; } - public sealed class ToggleSpecialAbility : Packet - { - public ToggleSpecialAbility(int abilityID, bool active) : base(0xBF) - { - EnsureCapacity(7); - - Stream.Write((short)0x25); - - Stream.Write((short)abilityID); - Stream.Write(active); - } - } - public sealed class DisplayProfile : Packet { public DisplayProfile(Serial m, string header, string body, string footer) : base(0xB8) @@ -374,18 +361,6 @@ namespace Server.Network } } - public sealed class ClearWeaponAbility : Packet - { - public static readonly Packet Instance = SetStatic(new ClearWeaponAbility()); - - public ClearWeaponAbility() : base(0xBF) - { - EnsureCapacity(5); - - Stream.Write((short)0x21); - } - } - public sealed class DisplayHuePicker : Packet { public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9) diff --git a/Projects/Server/Events/EventSink.cs b/Projects/Server/Events/EventSink.cs index 797750fc1..9e168c742 100644 --- a/Projects/Server/Events/EventSink.cs +++ b/Projects/Server/Events/EventSink.cs @@ -106,9 +106,6 @@ namespace Server public static event Action DeleteRequest; public static void InvokeDeleteRequest(NetState state, int index) => DeleteRequest?.Invoke(state, index); - public static event Action SetAbility; - public static void InvokeSetAbility(Mobile mobile, int index) => SetAbility?.Invoke(mobile, index); - public static event Action ServerStarted; public static void InvokeServerStarted() => ServerStarted?.Invoke(); diff --git a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs index 51b9161b6..00371638d 100644 --- a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs @@ -48,7 +48,6 @@ namespace Server.Network IncomingPackets.Register(0xD7, 0, true, EncodedCommand); IncomingPackets.Register(0xF4, 0, false, CrashReport); - IncomingPackets.RegisterEncoded(0x19, true, SetAbility); IncomingPackets.RegisterEncoded(0x28, true, GuildGumpRequest); IncomingPackets.RegisterEncoded(0x32, true, QuestGumpRequest); } @@ -584,17 +583,12 @@ namespace Server.Network } } - public static void SetAbility(this NetState state, IEntity e, EncodedReader reader) - { - EventSink.InvokeSetAbility(state.Mobile, reader.ReadInt32()); - } - - public static void GuildGumpRequest(this NetState state, IEntity e, EncodedReader reader) + public static void GuildGumpRequest(NetState state, IEntity e, EncodedReader reader) { EventSink.InvokeGuildGumpRequest(state.Mobile); } - public static void QuestGumpRequest(this NetState state, IEntity e, EncodedReader reader) + public static void QuestGumpRequest(NetState state, IEntity e, EncodedReader reader) { EventSink.InvokeQuestGumpRequest(state.Mobile); } diff --git a/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs b/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs index 5c76326f4..051ac8f7e 100644 --- a/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingPlayerPackets.cs @@ -63,23 +63,6 @@ namespace Server.Network public static void SendDeathStatus(this NetState ns, bool dead) => ns?.Send(stackalloc byte[] { 0x2C, dead ? (byte)0 : (byte)2 }); - public static void SendToggleSpecialAbility(this NetState ns, int abilityId, bool active) - { - if (ns == null) - { - return; - } - - var writer = new SpanWriter(stackalloc byte[8]); - writer.Write((byte)0xBF); // Packet ID - writer.Write((ushort)8); - writer.Write((short)0x25); - writer.Write((short)abilityId); - writer.Write(active); - - ns.Send(writer.Span); - } - public static void SendDisplayProfile(this NetState ns, Serial m, string header, string body, string footer) { if (ns == null) @@ -352,10 +335,6 @@ namespace Server.Network [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void SendPingAck(this NetState ns, byte ping) => ns?.Send(stackalloc byte[] { 0x73, ping }); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SendClearWeaponAbility(this NetState ns) => - ns?.Send(stackalloc byte[] { 0xBF, 0x00, 0x5, 0x00, 0x21 }); - public static void SendDisplayHuePicker(this NetState ns, Serial huePickerSerial, int huePickerItemID) { if (ns == null) diff --git a/Projects/UOContent.Tests/Tests/Items/Weapons/Abilities/WeaponAbilityPacketTests.cs b/Projects/UOContent.Tests/Tests/Items/Weapons/Abilities/WeaponAbilityPacketTests.cs new file mode 100644 index 000000000..c5ee471c1 --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Items/Weapons/Abilities/WeaponAbilityPacketTests.cs @@ -0,0 +1,39 @@ +using System; +using Server.Items; +using Server.Tests; +using Server.Tests.Network; +using Xunit; + +namespace UOContent.Tests +{ + public class WeaponAbilityPacketTests + { + [Theory] + [InlineData(0, true)] + [InlineData(0, false)] + [InlineData(100, true)] + [InlineData(1000, false)] + public void TestSpecialAbility(int abilityId, bool active) + { + var expected = new ToggleSpecialAbility(abilityId, active).Compile(); + + var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendToggleSpecialAbility(abilityId, active); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + + [Fact] + public void TestClearAbility() + { + var expected = new ClearWeaponAbility().Compile(); + + var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendClearWeaponAbility(); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + } +} diff --git a/Projects/UOContent.Tests/Tests/Items/Weapons/Abilities/WeaponAbilityPackets.cs b/Projects/UOContent.Tests/Tests/Items/Weapons/Abilities/WeaponAbilityPackets.cs new file mode 100644 index 000000000..f44593af0 --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Items/Weapons/Abilities/WeaponAbilityPackets.cs @@ -0,0 +1,29 @@ +using Server.Network; + +namespace UOContent.Tests +{ + public sealed class ToggleSpecialAbility : Packet + { + public ToggleSpecialAbility(int abilityID, bool active) : base(0xBF) + { + EnsureCapacity(7); + + Stream.Write((short)0x25); + + Stream.Write((short)abilityID); + Stream.Write(active); + } + } + + public sealed class ClearWeaponAbility : Packet + { + public static readonly Packet Instance = SetStatic(new ClearWeaponAbility()); + + public ClearWeaponAbility() : base(0xBF) + { + EnsureCapacity(5); + + Stream.Write((short)0x21); + } + } +} diff --git a/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs b/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs index 192c6d847..fb4e4a5d0 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/ConcussionBlow.cs @@ -3,9 +3,8 @@ using System; namespace Server.Items { /// - /// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or - /// vice - /// versa. + /// This devastating strike is most effective against those who are in good health and whose reserves + /// of mana are low, or vice versa. /// public class ConcussionBlow : WeaponAbility { diff --git a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs index 4a66f0907..560a6673f 100644 --- a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs +++ b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbility.cs @@ -132,15 +132,17 @@ namespace Server.Items { var mana = BaseMana; - var skillTotal = GetSkill(from, SkillName.Swords) + GetSkill(from, SkillName.Macing) - + GetSkill(from, SkillName.Fencing) + - GetSkill(from, SkillName.Archery) + - GetSkill(from, SkillName.Parry) - + GetSkill(from, SkillName.Lumberjacking) + - GetSkill(from, SkillName.Stealth) - + GetSkill(from, SkillName.Poisoning) + - GetSkill(from, SkillName.Bushido) + - GetSkill(from, SkillName.Ninjitsu); + var skillTotal = + GetSkill(from, SkillName.Swords) + + GetSkill(from, SkillName.Macing) + + GetSkill(from, SkillName.Fencing) + + GetSkill(from, SkillName.Archery) + + GetSkill(from, SkillName.Parry) + + GetSkill(from, SkillName.Lumberjacking) + + GetSkill(from, SkillName.Stealth) + + GetSkill(from, SkillName.Poisoning) + + GetSkill(from, SkillName.Bushido) + + GetSkill(from, SkillName.Ninjitsu); if (skillTotal >= 300.0) { @@ -196,9 +198,11 @@ namespace Server.Items } /* */ - if (weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills.Swords.Base >= reqSkill || - from.Skills.Macing.Base >= reqSkill || - from.Skills.Fencing.Base >= reqSkill)) + if (weapon.WeaponAttributes.UseBestSkill > 0 && + (from.Skills.Swords.Base >= reqSkill || + from.Skills.Macing.Base >= reqSkill || + from.Skills.Fencing.Base >= reqSkill) + ) { return true; } @@ -394,23 +398,6 @@ namespace Server.Items } } - public static void Initialize() - { - EventSink.SetAbility += EventSink_SetAbility; - } - - private static void EventSink_SetAbility(Mobile m, int index) - { - if (index == 0) - { - ClearCurrentAbility(m); - } - else if (index >= 1 && index < Abilities.Length) - { - SetCurrentAbility(m, Abilities[index]); - } - } - private static void AddContext(Mobile m, WeaponAbilityContext context) { m_PlayersTable[m] = context; @@ -418,21 +405,12 @@ namespace Server.Items private static void RemoveContext(Mobile m) { - var context = GetContext(m); - - if (context != null) + if (m_PlayersTable.Remove(m, out var context)) { - RemoveContext(m, context); + context.Timer?.Stop(); } } - private static void RemoveContext(Mobile m, WeaponAbilityContext context) - { - m_PlayersTable.Remove(m); - - context.Timer.Stop(); - } - private static WeaponAbilityContext GetContext(Mobile m) { m_PlayersTable.TryGetValue(m, out var context); diff --git a/Projects/UOContent/Items/Weapons/Abilities/WeaponAbilityPackets.cs b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbilityPackets.cs new file mode 100644 index 000000000..8165628bf --- /dev/null +++ b/Projects/UOContent/Items/Weapons/Abilities/WeaponAbilityPackets.cs @@ -0,0 +1,50 @@ +using System.Buffers; +using System.Runtime.CompilerServices; +using Server.Network; + +namespace Server.Items +{ + public static class WeaponAbilityPackets + { + public static void Configure() + { + IncomingPackets.RegisterEncoded(0x19, true, SetAbility); + } + + public static void SetAbility(NetState state, IEntity e, EncodedReader reader) + { + var m = state.Mobile; + var index = reader.ReadInt32(); + + if (index >= 1 && index < WeaponAbility.Abilities.Length) + { + WeaponAbility.SetCurrentAbility(m, WeaponAbility.Abilities[index]); + } + else + { + WeaponAbility.ClearCurrentAbility(m); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void SendClearWeaponAbility(this NetState ns) => + ns?.Send(stackalloc byte[] { 0xBF, 0x00, 0x5, 0x00, 0x21 }); + + public static void SendToggleSpecialAbility(this NetState ns, int abilityId, bool active) + { + if (ns == null) + { + return; + } + + var writer = new SpanWriter(stackalloc byte[8]); + writer.Write((byte)0xBF); // Packet ID + writer.Write((ushort)8); + writer.Write((short)0x25); + writer.Write((short)abilityId); + writer.Write(active); + + ns.Send(writer.Span); + } + } +} diff --git a/Projects/UOContent/Multis/Boats/BaseBoat.cs b/Projects/UOContent/Multis/Boats/BaseBoat.cs index 3bc792753..ff86aa515 100644 --- a/Projects/UOContent/Multis/Boats/BaseBoat.cs +++ b/Projects/UOContent/Multis/Boats/BaseBoat.cs @@ -1342,7 +1342,7 @@ namespace Server.Multis Order = BoatOrder.Move; _moveTimerToken.Cancel(); - Timer.StartTimer(interval, StopBoat, out _moveTimerToken); + Timer.StartTimer(interval, single ? 1 : 0, StopBoat, out _moveTimerToken); return true; } diff --git a/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs b/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs index e0fd4a198..4fd9d4927 100644 --- a/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs +++ b/Projects/UOContent/Spells/Bushido/SamuraiSpell.cs @@ -1,6 +1,6 @@ using System; +using Server.Items; using Server.Mobiles; -using Server.Network; namespace Server.Spells.Bushido {